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() { void MakeSelectionTexture() {
int size = (int)selBlockSize; int hSize = (int)selBlockSize;
int y = game.Height - size; 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 ); 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 ) ) if( !game.AcceptedUrls.HasAccepted( url ) )
game.AcceptedUrls.AddAccepted( 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 ); game.AsyncDownloader.DownloadData( url, true, "texturePack", lastModified );
else else
game.AsyncDownloader.DownloadImage( url, true, "terrain", lastModified ); game.AsyncDownloader.DownloadImage( url, true, "terrain", lastModified );

View File

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

View File

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

View File

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

View File

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

View File

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