Treat .zip as texture packs in EnvMapAppearance packets, use builds.json for determing latest builds.

This commit is contained in:
UnknownShadow200 2015-12-01 10:41:48 +11:00
parent 3a15ef9024
commit 59d0b2da74
7 changed files with 85 additions and 80 deletions

View file

@ -82,10 +82,11 @@ namespace ClassicalSharp {
}
void MakeSelectionTexture() {
int size = (int)selBlockSize;
int y = game.Height - size;
int hSize = (int)selBlockSize;
int vSize = (int)Math.Floor( 23 * 2 * game.GuiScale );
int y = game.Height - vSize;
TextureRec rec = new TextureRec( 0, 22/256f, 24/256f, 24/256f );
selTex = new Texture( game.GuiTexId, 0, y, size, size, rec );
selTex = new Texture( game.GuiTexId, 0, y, hSize, vSize, rec );
}
}
}

View file

@ -322,7 +322,9 @@ namespace ClassicalSharp {
if( !game.AcceptedUrls.HasAccepted( url ) )
game.AcceptedUrls.AddAccepted( url );
if( usingTexturePack )
// NOTE: This is entirely against the original CPE specification, but we
// do it here as a convenience until EnvMapAppearance v2 is more widely adopted.
if( usingTexturePack || url.EndsWith( ".zip" ) )
game.AsyncDownloader.DownloadData( url, true, "texturePack", lastModified );
else
game.AsyncDownloader.DownloadImage( url, true, "terrain", lastModified );

View file

@ -18,7 +18,7 @@ namespace Launcher2 {
titleFont = new Font( "Arial", 16, FontStyle.Bold );
infoFont = new Font( "Arial", 14, FontStyle.Regular );
buttonFont = titleFont;
widgets = new LauncherWidget[16];
widgets = new LauncherWidget[17];
}
UpdateCheckTask checkTask;
@ -28,18 +28,20 @@ namespace Launcher2 {
Resize();
}
Build dev, stable;
public override void Tick() {
if( checkTask != null && !checkTask.Working ) {
if( checkTask.Exception != null ) {
updateCheckFailed = true;
} else {
lastStable = DateTime.Parse( checkTask.LatestStableDate,
null, DateTimeStyles.AssumeUniversal );
lastDev = DateTime.Parse( checkTask.LatestDevDate,
null, DateTimeStyles.AssumeUniversal );
dev = checkTask.LatestDev;
lastDev = dev.TimeBuilt;
validDev = dev.DirectXSize > 50000 && dev.OpenGLSize > 50000;
validStable = Int32.Parse( checkTask.LatestStableSize ) > 50000;
validDev = Int32.Parse( checkTask.LatestDevSize ) > 50000;
stable = checkTask.LatestStable;
lastStable = stable.TimeBuilt;
validStable = stable.DirectXSize > 50000 && stable.OpenGLSize > 50000;
}
checkTask = null;
game.MakeBackground();
@ -64,22 +66,24 @@ namespace Launcher2 {
widgetIndex = 0;
MakeLabelAt( "Your build:", titleFont, Anchor.Centre, Anchor.Centre, -55, -120 );
string yourBuild = File.GetLastWriteTimeUtc( "ClassicalSharp.exe" ).ToString( dateFormat );
string yourBuild = File.GetLastWriteTime( "ClassicalSharp.exe" ).ToString( dateFormat );
MakeLabelAt( yourBuild, infoFont, Anchor.Centre, Anchor.Centre, 100, -120 );
MakeLabelAt( "Latest stable:", titleFont, Anchor.Centre, Anchor.Centre, -70, -80 );
string latestStable = GetDateString( lastStable, validStable );
MakeLabelAt( latestStable, infoFont, Anchor.Centre, Anchor.Centre, 100, -80 );
MakeButtonAt( "Update to stable", 180, 30, titleFont, Anchor.Centre, 0, -40,
(x, y) => UpdateBuild( lastStable, validStable, "latest.Release.zip" ) );
MakeButtonAt( "Update to D3D9 stable", 260, 30, titleFont, Anchor.Centre, 0, -40,
(x, y) => UpdateBuild( lastStable, validStable, true, true ) );
MakeButtonAt( "Update to OpenGL stable", 260, 30, titleFont, Anchor.Centre, 0, 0,
(x, y) => UpdateBuild( lastStable, validStable, true, false ) );
MakeLabelAt( "Latest dev:", titleFont, Anchor.Centre, Anchor.Centre, -60, 40 );
string latestDev = GetDateString( lastDev, validDev );
MakeLabelAt( latestDev, infoFont, Anchor.Centre, Anchor.Centre, 100, 40 );
MakeButtonAt( "Update to OpenGL dev", 240, 30, titleFont, Anchor.Centre, 0, 80,
(x, y) => UpdateBuild( lastDev, validDev, "latest.zip" ) );
MakeButtonAt( "Update to D3D9 dev", 240, 30, titleFont, Anchor.Centre, 0, 120,
(x, y) => UpdateBuild( lastDev, validDev, "latest.DirectX.zip" ) );
MakeButtonAt( "Update to D3D9 dev", 240, 30, titleFont, Anchor.Centre, 0, 80,
(x, y) => UpdateBuild( lastDev, validDev, false, true ) );
MakeButtonAt( "Update to OpenGL dev", 240, 30, titleFont, Anchor.Centre, 0, 120,
(x, y) => UpdateBuild( lastDev, validDev, false, false ) );
MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre,
0, 200, (x, y) => game.SetScreen( new MainScreen( game ) ) );
@ -90,11 +94,15 @@ namespace Launcher2 {
if( !valid ) return "Build corrupted";
if( last == DateTime.MinValue ) return "Checking..";
return last.ToUniversalTime().ToString( dateFormat );
return last.ToString( dateFormat );
}
void UpdateBuild( DateTime last, bool valid, string dir ) {
void UpdateBuild( DateTime last, bool valid, bool release, bool dx ) {
if( last == DateTime.MinValue || !valid ) return;
Build build = release ? stable : dev;
string dir = dx ? build.DirectXPath : build.OpenGLPath;
Console.WriteLine( "FETCH! " + dir );
Patcher.Update( dir );
}

View file

@ -43,6 +43,7 @@
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<StartAction>Project</StartAction>
</PropertyGroup>
<ItemGroup>
<Reference Include="SharpWave">

View file

@ -162,7 +162,7 @@ namespace Launcher2 {
static int GetLastIndexOfNumber( string json, int index ) {
int lastIndex = index;
for( ; lastIndex < json.Length; lastIndex++ ) {
if( "0123456789+-".IndexOf( json[lastIndex] ) == -1 )
if( "0123456789+-.".IndexOf( json[lastIndex] ) == -1 )
break;
}
return lastIndex - 1;

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net;
using System.Threading;
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
namespace Launcher2 {
@ -56,8 +57,7 @@ namespace Launcher2 {
var swGet = System.Diagnostics.Stopwatch.StartNew();
string getResponse = GetHtmlAll( loginUri, classicubeNetUri );
int index = 0; bool success = true;
Dictionary<string, object> data =
(Dictionary<string, object>)Json.ParseValue( getResponse, ref index, ref success );
JsonObject data = (JsonObject)Json.ParseValue( getResponse, ref index, ref success );
string token = (string)data["token"];
// Step 2: POST to login page with csrf token.
@ -72,7 +72,7 @@ namespace Launcher2 {
var sw = System.Diagnostics.Stopwatch.StartNew();
string response = PostHtmlAll( loginUri, loginUri, loginData );
index = 0; success = true;
data = (Dictionary<string, object>)Json.ParseValue( response, ref index, ref success );
data = (JsonObject)Json.ParseValue( response, ref index, ref success );
List<object> errors = (List<object>)data["errors"];
if( errors.Count > 0 || (data.ContainsKey( "username" ) && data["username"] == null) )
@ -88,13 +88,12 @@ namespace Launcher2 {
string response = GetHtmlAll( uri, classicubeNetUri );
int index = 0; bool success = true;
Dictionary<string, object> root =
(Dictionary<string, object>)Json.ParseValue( response, ref index, ref success );
JsonObject root = (JsonObject)Json.ParseValue( response, ref index, ref success );
List<object> list = (List<object>)root["servers"];
Dictionary<string, object> pairs = (Dictionary<string, object>)list[0];
return new ClientStartData( Username, (string)pairs["mppass"],
(string)pairs["ip"], (string)pairs["port"] );
JsonObject obj = (JsonObject)list[0];
return new ClientStartData( Username, (string)obj["mppass"],
(string)obj["ip"], (string)obj["port"] );
}
public List<ServerListEntry> GetPublicServers() {
@ -102,17 +101,16 @@ namespace Launcher2 {
List<ServerListEntry> servers = new List<ServerListEntry>();
string response = GetHtmlAll( publicServersUri, classicubeNetUri );
int index = 0; bool success = true;
Dictionary<string, object> root =
(Dictionary<string, object>)Json.ParseValue( response, ref index, ref success );
JsonObject root = (JsonObject)Json.ParseValue( response, ref index, ref success );
List<object> list = (List<object>)root["servers"];
foreach( object server in list ) {
Dictionary<string, object> pairs = (Dictionary<string, object>)server;
JsonObject obj = (JsonObject)server;
servers.Add( new ServerListEntry(
(string)pairs["hash"], (string)pairs["name"],
(string)pairs["players"], (string)pairs["maxplayers"],
(string)pairs["uptime"], (string)pairs["mppass"],
(string)pairs["ip"], (string)pairs["port"] ) );
(string)obj["hash"], (string)obj["name"],
(string)obj["players"], (string)obj["maxplayers"],
(string)obj["uptime"], (string)obj["mppass"],
(string)obj["ip"], (string)obj["port"] ) );
}
Log( "cc servers took " + sw.ElapsedMilliseconds );
sw.Stop();

View file

@ -1,22 +1,28 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using JsonObject = System.Collections.Generic.Dictionary<string, object>;
namespace Launcher2 {
public class Build {
public DateTime TimeBuilt;
public string DirectXPath, OpenGLPath;
public int DirectXSize, OpenGLSize;
}
public sealed class UpdateCheckTask : IWebTask {
public const string UpdatesUri = "http://cs.classicube.net/";
StringComparison ordinal = StringComparison.Ordinal;
public string LatestStableDate, LatestStableSize;
public string LatestDevDate, LatestDevSize;
public const string BuildsUri = "http://cs.classicube.net/builds.json";
public Build LatestDev, LatestStable;
public void CheckForUpdatesAsync() {
Working = true;
Exception = null;
LatestStableDate = null; LatestStableSize = null;
LatestDevDate = null; LatestDevSize = null;
LatestDev = null;
LatestStable = null;
Thread thread = new Thread( UpdateWorker, 256 * 1024 );
thread.Name = "Launcher.UpdateCheck";
@ -33,46 +39,35 @@ namespace Launcher2 {
}
void CheckUpdates() {
var response = GetHtml( UpdatesUri, UpdatesUri );
foreach( string line in response ) {
if( line.StartsWith( @"<a href=""latest.", ordinal ) ) {
int index = 0;
string text = line.Substring( @"<a href=""".Length );
string buildName = ReadToken( text, ref index );
string date = ReadToken( text, ref index );
string time = ReadToken( text, ref index );
string buildSize = ReadToken( text, ref index );
if( buildName.Contains( "latest.zip" ) ) {
LatestDevDate = date + " " + time;
LatestDevSize = buildSize;
} else if( buildName.Contains( "latest.Release.zip" ) ) {
LatestStableDate = date + " " + time;
LatestStableSize = buildSize;
}
}
}
string response = GetHtmlAll( BuildsUri, UpdatesUri );
int index = 0; bool success = true;
JsonObject data = (JsonObject)Json.ParseValue( response, ref index, ref success );
JsonObject devBuild = (JsonObject)data["latest"];
JsonObject releaseBuilds = (JsonObject)data["releases"];
LatestDev = MakeBuild( devBuild, false );
Build[] stableBuilds = new Build[releaseBuilds.Count];
int i = 0;
foreach( KeyValuePair<string, object> pair in releaseBuilds )
stableBuilds[i++] = MakeBuild( (JsonObject)pair.Value, true );
Array.Sort<Build>( stableBuilds,
(a, b) => b.TimeBuilt.CompareTo( a.TimeBuilt ) );
LatestStable = stableBuilds[0];
}
string ReadToken( string value, ref int index ) {
int start = index;
int wordEnd = -1;
for( ; index < value.Length; index++ ) {
if( value[index] == ' ' ) {
// found end of this word
if( wordEnd == -1 )
wordEnd = index;
} else {
// found start of next word
if( wordEnd != -1 )
break;
}
}
static readonly DateTime epoch = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc );
Build MakeBuild( JsonObject obj, bool release ) {
Build build = new Build();
string timeKey = release ? "release_ts" : "ts";
double rawTime = Double.Parse( (string)obj[timeKey] );
build.TimeBuilt = epoch.AddSeconds( rawTime ).ToLocalTime();
if( wordEnd == -1 )
wordEnd = value.Length;
return value.Substring( start, wordEnd - start );
}
build.DirectXSize = Int32.Parse( (string)obj["dx_size"] );
build.DirectXPath = (string)obj["dx_file"];
build.OpenGLSize = Int32.Parse( (string)obj["ogl_size"] );
build.OpenGLPath = (string)obj["ogl_file"];
return build;
}
}
}