Cleanup WeatherRenderer somewhat, add (non-working) update screen to new launcher.

This commit is contained in:
UnknownShadow200 2015-11-03 07:57:43 +11:00
parent 120c630c51
commit d1818f6e23
19 changed files with 390 additions and 231 deletions

View File

@ -46,7 +46,7 @@ namespace ClassicalSharp {
game.Drawer2D.MakeBitmappedTextTexture( ref args, 0, 0 ) : game.Drawer2D.MakeBitmappedTextTexture( ref args, 0, 0 ) :
game.Drawer2D.MakeTextTexture( ref args, 0, 0 ); game.Drawer2D.MakeTextTexture( ref args, 0, 0 );
chatInputText.WordWrap( ref parts, ref partLens, 64 ); chatInputText.WordWrap( ref parts, ref partLens, 64 );
maxWidth = 0; maxWidth = 0;
args = new DrawTextArgs( null, font, false ); args = new DrawTextArgs( null, font, false );
for( int i = 0; i < lines; i++ ) { for( int i = 0; i < lines; i++ ) {

View File

@ -15,13 +15,15 @@ namespace ClassicalSharp {
map = game.Map; map = game.Map;
graphics = game.Graphics; graphics = game.Graphics;
info = game.BlockInfo; info = game.BlockInfo;
weatherVb = graphics.CreateDynamicVb( VertexFormat.Pos3fTex2fCol4b, 12 * 9 * 9 ); weatherVb = graphics.CreateDynamicVb( VertexFormat.Pos3fTex2fCol4b, vertices.Length );
} }
int weatherVb; int weatherVb;
short[] heightmap; short[] heightmap;
float vOffset; float vOffset;
VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[8 * 9 * 9]; const int extent = 4;
VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[8 * (extent * 2 + 1) * (extent * 2 + 1)];
public void Render( double deltaTime ) { public void Render( double deltaTime ) {
Weather weather = map.Weather; Weather weather = map.Weather;
if( weather == Weather.Sunny ) return; if( weather == Weather.Sunny ) return;
@ -36,8 +38,8 @@ namespace ClassicalSharp {
graphics.AlphaBlending = true; graphics.AlphaBlending = true;
graphics.DepthWrite = false; graphics.DepthWrite = false;
FastColour col = FastColour.White; FastColour col = FastColour.White;
for( int dx = -4; dx <= 4; dx++ ) { for( int dx = -extent; dx <= extent; dx++ ) {
for( int dz = -4; dz <= 4; dz++ ) { for( int dz = -extent; dz <= extent; dz++ ) {
int rainY = Math.Max( pos.Y, GetRainHeight( pos.X + dx, pos.Z + dz ) + 1 ); int rainY = Math.Max( pos.Y, GetRainHeight( pos.X + dx, pos.Z + dz ) + 1 );
int height = Math.Min( 6 - ( rainY - pos.Y ), 6 ); int height = Math.Min( 6 - ( rainY - pos.Y ), 6 );
if( height <= 0 ) continue; if( height <= 0 ) continue;
@ -46,6 +48,7 @@ namespace ClassicalSharp {
MakeRainForSquare( pos.X + dx, rainY, height, pos.Z + dz, col, ref index ); MakeRainForSquare( pos.X + dx, rainY, height, pos.Z + dz, col, ref index );
} }
} }
// fixes crashing on nVidia cards in OpenGL builds. // fixes crashing on nVidia cards in OpenGL builds.
if( index > 0 ) { if( index > 0 ) {
graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b ); graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );

View File

@ -87,8 +87,8 @@ namespace Launcher2 {
void Draw() { void Draw() {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( "Username", titleFont, -180, -100 ); MakeLabelAt( "Username", titleFont, Anchor.Centre, Anchor.Centre, -180, -100 );
MakeTextAt( "Password", titleFont, -180, -50 ); MakeLabelAt( "Password", titleFont, Anchor.Centre, Anchor.Centre, -180, -50 );
MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 ); MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 );
MakeInput( Get(), 300, Anchor.Centre, true, 30, -50, 32 ); MakeInput( Get(), 300, Anchor.Centre, true, 30, -50, 32 );
@ -97,8 +97,8 @@ namespace Launcher2 {
-75, 0, StartClient ); -75, 0, StartClient );
MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre, MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre,
140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) ); 140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) );
string text = widgets[6] == null ? "" : ((LauncherLabelWidget)widgets[6]).Text; string text = widgets[6] == null ? "" : widgets[6].Text;
MakeTextAt( text, inputFont, 0, 50 ); MakeLabelAt( text, inputFont, Anchor.Centre, Anchor.Centre, 0, 50 );
if( HasServers && !signingIn ) if( HasServers && !signingIn )
MakeButtonAt( "Servers", 90, 35, titleFont, Anchor.Centre, MakeButtonAt( "Servers", 90, 35, titleFont, Anchor.Centre,
@ -117,12 +117,6 @@ namespace Launcher2 {
Dirty = true; Dirty = true;
} }
} }
void MakeTextAt( string text, Font font, int x, int y ) {
LauncherLabelWidget widget = new LauncherLabelWidget( game, text );
widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget;
}
bool HasServers { bool HasServers {
get { get {

View File

@ -69,10 +69,10 @@ namespace Launcher2 {
void Draw() { void Draw() {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( titleFont, "Search", -200, 10 ); MakeLabelAt( "Search", titleFont, Anchor.Centre, Anchor.Centre, -200, 10 );
MakeInput( Get(), 270, Anchor.LeftOrTop, false, -25, 5, 32 ); MakeInput( Get(), 270, Anchor.LeftOrTop, false, -25, 5, 32 );
MakeTextAt( inputFont, "../play/", -210, 55 ); MakeLabelAt( "../play/", inputFont, Anchor.Centre, Anchor.Centre, -210, 55 );
MakeInput( Get(), 320, Anchor.LeftOrTop, false, -20, 50, 32 ); MakeInput( Get(), 320, Anchor.LeftOrTop, false, -20, 50, 32 );
((LauncherInputWidget)widgets[3]).ClipboardFilter = HashFilter; ((LauncherInputWidget)widgets[3]).ClipboardFilter = HashFilter;
@ -82,12 +82,6 @@ namespace Launcher2 {
195, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) ); 195, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) );
MakeTableWidget(); MakeTableWidget();
} }
void MakeTextAt( Font font, string text, int x, int y ) {
LauncherLabelWidget widget = new LauncherLabelWidget( game, text );
widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.LeftOrTop, x, y );
widgets[widgetIndex++] = widget;
}
void MakeTableWidget() { void MakeTableWidget() {
if( widgets[tableIndex] != null ) { if( widgets[tableIndex] != null ) {

View File

@ -73,17 +73,18 @@ namespace Launcher2 {
void Draw() { void Draw() {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( "Username", -180, -100 ); MakeLabelAt( "Username", titleFont, Anchor.Centre, Anchor.Centre, -180, -100 );
MakeTextAt( "Address", -180, -50 ); MakeLabelAt( "Address", titleFont, Anchor.Centre, Anchor.Centre, -180, -50 );
MakeTextAt( "Mppass", -180, 0 ); MakeLabelAt( "Mppass", titleFont, Anchor.Centre, Anchor.Centre, -180, 0 );
MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 ); MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 );
MakeInput( Get(), 300, Anchor.Centre, false, 30, -50, 64 ); MakeInput( Get(), 300, Anchor.Centre, false, 30, -50, 64 );
MakeInput( Get(), 300, Anchor.Centre, false, 30, 0, 32 ); MakeInput( Get(), 300, Anchor.Centre, false, 30, 0, 32 );
MakeButtonAt( "Connect", 110, 35, -65, 50, StartClient ); MakeButtonAt( "Connect", 110, 35, titleFont, Anchor.Centre, -65, 50, StartClient );
MakeButtonAt( "Back", 80, 35, 140, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) ); MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre,
MakeTextAt( "", 0, 100 ); 140, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) );
MakeLabelAt( "", titleFont, Anchor.Centre, Anchor.Centre, 0, 100 );
} }
void SetStatus( string text ) { void SetStatus( string text ) {
@ -95,23 +96,6 @@ namespace Launcher2 {
Dirty = true; Dirty = true;
} }
} }
void MakeTextAt( string text, int x, int y ) {
LauncherLabelWidget widget = new LauncherLabelWidget( game, text );
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget;
}
void MakeButtonAt( string text, int width, int height,
int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text;
widget.OnClick = onClick;
widget.Active = false;
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y );
widgets[widgetIndex++] = widget;
}
void StartClient( int mouseX, int mouseY ) { void StartClient( int mouseX, int mouseY ) {
SetStatus( "" ); SetStatus( "" );

View File

@ -14,6 +14,7 @@ namespace Launcher2 {
} }
public override void Init() { public override void Init() {
buttonFont = titleFont;
game.Window.Mouse.Move += MouseMove; game.Window.Mouse.Move += MouseMove;
game.Window.Mouse.ButtonDown += MouseButtonDown; game.Window.Mouse.ButtonDown += MouseButtonDown;
@ -82,9 +83,9 @@ namespace Launcher2 {
protected string Get() { return Get( widgetIndex ); } protected string Get() { return Get( widgetIndex ); }
protected string Get( int index ) { protected string Get( int index ) {
LauncherWidget widget = widgets[index]; LauncherWidget widget = widgets[index];
return widget == null ? "" : ((LauncherInputWidget)widget).Text; return widget == null ? "" : widget.Text;
} }
protected void Set( int index, string text ) { protected void Set( int index, string text ) {
@ -92,24 +93,6 @@ namespace Launcher2 {
.Redraw( drawer, text, inputFont ); .Redraw( drawer, text, inputFont );
} }
protected override void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = false;
button.Redraw( drawer, button.Text, titleFont );
Dirty = true;
}
}
protected override void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = true;
button.Redraw( drawer, button.Text, titleFont );
Dirty = true;
}
}
protected LauncherInputWidget lastInput; protected LauncherInputWidget lastInput;
protected void InputClick( int mouseX, int mouseY ) { protected void InputClick( int mouseX, int mouseY ) {
LauncherInputWidget input = (LauncherInputWidget)selectedWidget; LauncherInputWidget input = (LauncherInputWidget)selectedWidget;

View File

@ -56,12 +56,26 @@ namespace Launcher2 {
selectedWidget = null; selectedWidget = null;
} }
protected Font buttonFont;
/// <summary> Called when the user has moved their mouse away from a previously selected widget. </summary> /// <summary> Called when the user has moved their mouse away from a previously selected widget. </summary>
protected virtual void UnselectWidget( LauncherWidget widget ) { protected virtual void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = false;
button.Redraw( drawer, button.Text, buttonFont );
Dirty = true;
}
} }
/// <summary> Called when user has moved their mouse over a given widget. </summary> /// <summary> Called when user has moved their mouse over a given widget. </summary>
protected virtual void SelectWidget( LauncherWidget widget ) { protected virtual void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = true;
button.Redraw( drawer, button.Text, buttonFont );
Dirty = true;
}
} }
protected LauncherWidget lastClicked; protected LauncherWidget lastClicked;
@ -126,5 +140,17 @@ namespace Launcher2 {
widget.DrawAt( drawer, text, font, Anchor.Centre, verAnchor, width, height, x, y ); widget.DrawAt( drawer, text, font, Anchor.Centre, verAnchor, width, height, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
protected void MakeLabelAt( string text, Font font, Anchor horAnchor, Anchor verAnchor, int x, int y) {
if( widgets[widgetIndex] != null ) {
LauncherLabelWidget input = (LauncherLabelWidget)widgets[widgetIndex];
input.DrawAt( drawer, text, font, horAnchor, verAnchor, x, y );
} else {
LauncherLabelWidget widget = new LauncherLabelWidget( game, text );
widget.DrawAt( drawer, text, font, horAnchor, verAnchor, x, y );
widgets[widgetIndex] = widget;
}
widgetIndex++;
}
} }
} }

View File

@ -70,6 +70,10 @@ namespace Launcher2 {
MakeButtonAt( "Singleplayer", Anchor.Centre, Anchor.Centre, MakeButtonAt( "Singleplayer", Anchor.Centre, Anchor.Centre,
buttonWidth, buttonHeight, 0, 0, buttonWidth, buttonHeight, 0, 0,
(x, y) => Client.Start( "default.zip" ) ); (x, y) => Client.Start( "default.zip" ) );
MakeButtonAt( "Check for updates", Anchor.Centre, Anchor.Centre,
buttonWidth, buttonHeight, 0, 100,
(x, y) => game.SetScreen( new UpdatesScreen( game ) ) );
} }
const int buttonWidth = 220, buttonHeight = 35, sideButtonWidth = 150; const int buttonWidth = 220, buttonHeight = 35, sideButtonWidth = 150;

View File

@ -15,6 +15,7 @@ namespace Launcher2 {
textFont = new Font( "Arial", 16, FontStyle.Bold ); textFont = new Font( "Arial", 16, FontStyle.Bold );
infoFont = new Font( "Arial", 14, FontStyle.Regular ); infoFont = new Font( "Arial", 14, FontStyle.Regular );
statusFont = new Font( "Arial", 13, FontStyle.Italic ); statusFont = new Font( "Arial", 13, FontStyle.Italic );
buttonFont = textFont;
widgets = new LauncherWidget[4]; widgets = new LauncherWidget[4];
} }
@ -41,24 +42,6 @@ namespace Launcher2 {
Dirty = true; Dirty = true;
} }
protected override void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = false;
button.Redraw( drawer, button.Text, textFont );
Dirty = true;
}
}
protected override void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) {
button.Active = true;
button.Redraw( drawer, button.Text, textFont );
Dirty = true;
}
}
ResourceFetcher fetcher; ResourceFetcher fetcher;
void DownloadResources( int mouseX, int mouseY ) { void DownloadResources( int mouseX, int mouseY ) {
if( game.Downloader == null ) if( game.Downloader == null )
@ -85,10 +68,9 @@ namespace Launcher2 {
drawer.DrawRect( backCol, game.Width / 2 - 175, drawer.DrawRect( backCol, game.Width / 2 - 175,
game.Height / 2 - 70, 175 * 2, 70 * 2 ); game.Height / 2 - 70, 175 * 2, 70 * 2 );
string text = widgets[0] == null ? string text = widgets[0] != null ? widgets[0].Text
String.Format( format, ResourceFetcher.EstimateDownloadSize().ToString( "F2" ) ) : String.Format( format, ResourceFetcher.EstimateDownloadSize() );
: ((LauncherLabelWidget)widgets[0]).Text; MakeLabelAt( text, statusFont, Anchor.Centre, Anchor.Centre, 0, 5 );
MakeTextAt( statusFont, text, 0, 5 );
// Clear the entire previous widgets state. // Clear the entire previous widgets state.
for( int i = 1; i < widgets.Length; i++ ) { for( int i = 1; i < widgets.Length; i++ ) {
@ -98,11 +80,11 @@ namespace Launcher2 {
} }
if( fetcher == null ) { if( fetcher == null ) {
MakeTextAt( infoFont, mainText, 0, -30 ); MakeLabelAt( mainText, infoFont, Anchor.Centre, Anchor.Centre, 0, -30 );
MakeButtonAt( "Yes", 60, 30, textFont, Anchor.Centre, MakeButtonAt( "Yes", 60, 30, textFont, Anchor.Centre,
-50, 40, DownloadResources ); -50, 40, DownloadResources );
MakeButtonAt( "No", 60, 30, textFont, Anchor.Centre, MakeButtonAt( "No", 60, 30, textFont, Anchor.Centre,
50, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) ); 50, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) );
} else { } else {
MakeButtonAt( "Cancel", 120, 30, textFont, Anchor.Centre, MakeButtonAt( "Cancel", 120, 30, textFont, Anchor.Centre,
@ -120,12 +102,6 @@ namespace Launcher2 {
} }
} }
void MakeTextAt( Font font, string text, int x, int y ) {
LauncherLabelWidget widget = new LauncherLabelWidget( game, text );
widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget;
}
public override void Dispose() { public override void Dispose() {
game.Window.Mouse.Move -= MouseMove; game.Window.Mouse.Move -= MouseMove;
game.Window.Mouse.ButtonDown -= MouseButtonDown; game.Window.Mouse.ButtonDown -= MouseButtonDown;

View File

@ -0,0 +1,113 @@
using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Net;
using ClassicalSharp;
namespace Launcher2 {
public sealed class UpdatesScreen : LauncherScreen {
Font titleFont, infoFont;
public UpdatesScreen( LauncherWindow game ) : base( game ) {
game.Window.Mouse.Move += MouseMove;
game.Window.Mouse.ButtonDown += MouseButtonDown;
titleFont = new Font( "Arial", 16, FontStyle.Bold );
infoFont = new Font( "Arial", 14, FontStyle.Regular );
buttonFont = titleFont;
widgets = new LauncherWidget[16];
}
UpdateCheckTask checkTask;
public override void Init() {
checkTask = new UpdateCheckTask();
checkTask.CheckForUpdatesAsync();
Resize();
}
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 );
validStable = Int32.Parse( checkTask.LatestStableSize ) > 50000;
validDev = Int32.Parse( checkTask.LatestDevSize ) > 50000;
}
checkTask = null;
game.MakeBackground();
Resize();
}
}
public override void Resize() {
using( drawer ) {
drawer.SetBitmap( game.Framebuffer );
Draw();
}
Dirty = true;
}
const string dateFormat = "dd-MM-yyyy HH:mm";
DateTime lastStable, lastDev;
bool validStable = true, validDev = true;
bool updateCheckFailed;
void Draw() {
widgetIndex = 0;
MakeLabelAt( "Your build:", titleFont, Anchor.Centre, Anchor.Centre, -55, -120 );
string yourBuild = File.GetLastWriteTimeUtc( "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( lastDev, validDev, "latest.Release.zip" ) );
MakeLabelAt( "Latest OpenGL dev:", titleFont, Anchor.Centre, Anchor.Centre, -100, 0 );
string latestDev = GetDateString( lastDev, validDev );
MakeLabelAt( latestDev, infoFont, Anchor.Centre, Anchor.Centre, 100, 0 );
MakeButtonAt( "Update to OpenGL dev", 240, 30, titleFont, Anchor.Centre, 0, 40,
(x, y) => UpdateBuild( lastDev, validDev, "latest.zip" ) );
MakeLabelAt( "Latest D3D9 dev:", titleFont, Anchor.Centre, Anchor.Centre, -85, 80 );
MakeLabelAt( latestDev, infoFont, Anchor.Centre, Anchor.Centre, 100, 80 );
MakeButtonAt( "Update to D3D9 dev", 230, 30, titleFont, Anchor.Centre, 0, 120,
(x, y) => UpdateBuild( lastDev, validDev, "latest.DirectX.zip" ) );
MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre,
0, 200, (x, y) => game.SetScreen( new MainScreen( game ) ) );
}
string GetDateString( DateTime last, bool valid ) {
if( updateCheckFailed ) return "Update check failed";
if( !valid ) return "Build corrupted";
if( last == DateTime.MinValue ) return "Checking..";
return last.ToString( dateFormat );
}
void UpdateBuild( DateTime last, bool valid, string dir ) {
if( last == DateTime.MinValue || !valid ) return;
using( WebClient client = new WebClient() ) {
client.DownloadFile( UpdateCheckTask.UpdatesUri + dir, "update.zip" );
}
}
public override void Dispose() {
game.Window.Mouse.Move -= MouseMove;
game.Window.Mouse.ButtonDown -= MouseButtonDown;
titleFont.Dispose();
infoFont.Dispose();
}
}
}

View File

@ -7,7 +7,6 @@ namespace Launcher2 {
public sealed class LauncherButtonWidget : LauncherWidget { public sealed class LauncherButtonWidget : LauncherWidget {
public int ButtonWidth, ButtonHeight; public int ButtonWidth, ButtonHeight;
public string Text;
public bool Shadow = true; public bool Shadow = true;
public bool Active = false; public bool Active = false;

View File

@ -9,7 +9,6 @@ namespace Launcher2 {
public sealed class LauncherInputWidget : LauncherWidget { public sealed class LauncherInputWidget : LauncherWidget {
public int ButtonWidth, ButtonHeight; public int ButtonWidth, ButtonHeight;
public string Text;
/// <summary> Whether the input widget currently is focused through a mouse click or tab. </summary> /// <summary> Whether the input widget currently is focused through a mouse click or tab. </summary>
public bool Active; public bool Active;

View File

@ -7,8 +7,6 @@ namespace Launcher2 {
/// <summary> Widget that represents text that cannot be modified by the user. </summary> /// <summary> Widget that represents text that cannot be modified by the user. </summary>
public sealed class LauncherLabelWidget : LauncherWidget { public sealed class LauncherLabelWidget : LauncherWidget {
public string Text;
public LauncherLabelWidget( LauncherWindow window, string text ) : base( window ) { public LauncherLabelWidget( LauncherWindow window, string text ) : base( window ) {
Text = text; Text = text;
} }

View File

@ -9,6 +9,8 @@ namespace Launcher2 {
public LauncherWindow Window; public LauncherWindow Window;
public Action<int, int> OnClick; public Action<int, int> OnClick;
public string Text;
public LauncherWidget( LauncherWindow window ) { public LauncherWidget( LauncherWindow window ) {
Window = window; Window = window;
} }

View File

@ -4,7 +4,7 @@
<ProjectGuid>{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}</ProjectGuid> <ProjectGuid>{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Launcher2</RootNamespace> <RootNamespace>Launcher2</RootNamespace>
<AssemblyName>Launcher2</AssemblyName> <AssemblyName>Launcher2</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion> <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
@ -58,6 +58,7 @@
<Compile Include="Gui\Screens\LauncherScreen.cs" /> <Compile Include="Gui\Screens\LauncherScreen.cs" />
<Compile Include="Gui\Screens\MainScreen.cs" /> <Compile Include="Gui\Screens\MainScreen.cs" />
<Compile Include="Gui\Screens\ResourcesScreen.cs" /> <Compile Include="Gui\Screens\ResourcesScreen.cs" />
<Compile Include="Gui\Screens\UpdatesScreen.cs" />
<Compile Include="Gui\TableWidget\LauncherTableWidget.cs" /> <Compile Include="Gui\TableWidget\LauncherTableWidget.cs" />
<Compile Include="Gui\TableWidget\LauncherTableWidget.Input.cs" /> <Compile Include="Gui\TableWidget\LauncherTableWidget.Input.cs" />
<Compile Include="Gui\Widgets\LauncherButtonWidget.cs" /> <Compile Include="Gui\Widgets\LauncherButtonWidget.cs" />
@ -76,8 +77,9 @@
<Compile Include="Utils\ClientStartData.cs" /> <Compile Include="Utils\ClientStartData.cs" />
<Compile Include="Utils\Secure.cs" /> <Compile Include="Utils\Secure.cs" />
<Compile Include="WebService\ClassiCubeSession.cs" /> <Compile Include="WebService\ClassiCubeSession.cs" />
<Compile Include="WebService\GameSession.cs" /> <Compile Include="WebService\IWebTask.cs" />
<Compile Include="WebService\ServerListEntry.cs" /> <Compile Include="WebService\ServerListEntry.cs" />
<Compile Include="WebService\UpdateCheckTask.cs" />
<Compile Include="WebService\WebUtility.cs" /> <Compile Include="WebService\WebUtility.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -55,9 +55,10 @@ namespace Launcher2 {
return File.Exists( "default.zip" ); return File.Exists( "default.zip" );
} }
public static float EstimateDownloadSize() { public static string EstimateDownloadSize() {
return (291 + 4621 + 7) / 1024f; float size = (291 + 4621 + 7) / 1024f;
// clasic.jar + 1.6.2.jar + terrain-patch.png // classic.jar + 1.6.2.jar + terrain-patch.png
return size.ToString( "F2" );
} }
} }
} }

View File

@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net;
using System.Threading;
namespace Launcher2 { namespace Launcher2 {
public class ClassicubeSession : GameSession { public sealed class ClassicubeSession : IWebTask {
const string classicubeNetUri = "https://www.classicube.net/", const string classicubeNetUri = "https://www.classicube.net/",
loginUri = "https://www.classicube.net/acc/login", loginUri = "https://www.classicube.net/acc/login",
@ -13,7 +15,43 @@ namespace Launcher2 {
const string loggedInAs = @"<a href=""/acc"" class=""button"">"; const string loggedInAs = @"<a href=""/acc"" class=""button"">";
StringComparison ordinal = StringComparison.Ordinal; StringComparison ordinal = StringComparison.Ordinal;
public override void Login( string user, string password ) { public List<ServerListEntry> Servers = new List<ServerListEntry>();
public void LoginAsync( string user, string password ) {
Username = user;
Working = true;
Exception = null;
Status = "&eSigning in..";
Servers = new List<ServerListEntry>();
Thread thread = new Thread( LoginWorker, 256 * 1024 );
thread.Name = "Launcher.CCLoginAsync";
thread.Start( password );
}
void LoginWorker( object password ) {
// Sign in to classicube.net
try {
Login( Username, (string)password );
} catch( WebException ex ) {
Finish( false, ex, "sign in" ); return;
} catch( InvalidOperationException ex ) {
Finish( false, null, "&eFailed to sign in: " +
Environment.NewLine + ex.Message ); return;
}
// Retrieve list of public servers
Status = "&eRetrieving public servers list..";
try {
Servers = GetPublicServers();
} catch( WebException ex ) {
Servers = new List<ServerListEntry>();
Finish( false, ex, "retrieving servers list" ); return;
}
Finish( true, null, "&eSigned in" );
}
void Login( string user, string password ) {
Username = user; Username = user;
// Step 1: GET csrf token from login page. // Step 1: GET csrf token from login page.
var swGet = System.Diagnostics.Stopwatch.StartNew(); var swGet = System.Diagnostics.Stopwatch.StartNew();
@ -52,7 +90,7 @@ namespace Launcher2 {
} }
} }
public override ClientStartData GetConnectInfo( string hash ) { public ClientStartData GetConnectInfo( string hash ) {
string uri = playUri + hash; string uri = playUri + hash;
var response = GetHtml( uri, classicubeNetUri ); var response = GetHtml( uri, classicubeNetUri );
ClientStartData data = new ClientStartData(); ClientStartData data = new ClientStartData();
@ -61,7 +99,7 @@ namespace Launcher2 {
foreach( string line in response ) { foreach( string line in response ) {
int index = 0; int index = 0;
// Look for <param name="x" value="x"> tags // Look for <param name="x" value="x"> tags
if( ( index = line.IndexOf( "<param", ordinal ) ) > 0 ) { if( (index = line.IndexOf( "<param", ordinal )) > 0 ) {
int nameStart = index + 13; int nameStart = index + 13;
int nameEnd = line.IndexOf( '"', nameStart ); int nameEnd = line.IndexOf( '"', nameStart );
string paramName = line.Substring( nameStart, nameEnd - nameStart ); string paramName = line.Substring( nameStart, nameEnd - nameStart );
@ -85,7 +123,7 @@ namespace Launcher2 {
return line.Substring( valueStart, valueEnd - valueStart ); return line.Substring( valueStart, valueEnd - valueStart );
} }
public override List<ServerListEntry> GetPublicServers() { public List<ServerListEntry> GetPublicServers() {
var sw = System.Diagnostics.Stopwatch.StartNew(); var sw = System.Diagnostics.Stopwatch.StartNew();
var response = GetHtml( publicServersUri, classicubeNetUri ); var response = GetHtml( publicServersUri, classicubeNetUri );
List<ServerListEntry> servers = new List<ServerListEntry>(); List<ServerListEntry> servers = new List<ServerListEntry>();

View File

@ -3,122 +3,87 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading;
namespace Launcher2 {
namespace Launcher2 {
/// <summary> Represents a task that performs a series of GET or POST requests asynchronously. </summary>
public abstract class GameSession { public abstract class IWebTask {
public string Username; public virtual void ResetSession() {
Username = null;
public virtual void ResetSession() { cookies = new CookieContainer();
Username = null; }
cookies = new CookieContainer();
} /// <summary> Whether this web task is still performing GET or POST requests asynchronously. </summary>
public bool Working;
public bool Working;
public WebException Exception; /// <summary> Handled exception that was generated by the last GET or POST request. </summary>
public string Status; public WebException Exception;
public List<ServerListEntry> Servers = new List<ServerListEntry>();
/// <summary> Current status of this web task (e.g. downloading page X) </summary>
public void LoginAsync( string user, string password ) { public string Status;
Username = user;
Working = true; /// <summary> Username used when performing GET or POST requests, can be left null. </summary>
Exception = null; public string Username;
Status = "&eSigning in..";
Servers = new List<ServerListEntry>(); protected void Finish( bool success, WebException ex, string status ) {
if( !success )
Thread thread = new Thread( LoginWorker, 256 * 1024 ); Username = null;
thread.Name = "Launcher.LoginAsync"; Working = false;
thread.Start( password );
} Exception = ex;
Status = status;
void LoginWorker( object password ) { }
// Sign in to classicube.net
try { protected CookieContainer cookies = new CookieContainer();
Login( Username, (string)password );
} catch( WebException ex ) { protected HttpWebResponse MakeRequest( string uri, string referer, string data ) {
Finish( false, ex, "sign in" ); return; HttpWebRequest request = (HttpWebRequest)WebRequest.Create( uri );
} catch( InvalidOperationException ex ) { request.UserAgent = Program.AppName;
Finish( false, null, "&eFailed to sign in: " + request.ReadWriteTimeout = 15 * 1000;
Environment.NewLine + ex.Message ); return; request.Timeout = 15 * 1000;
} request.Referer = referer;
request.KeepAlive = true;
// Retrieve list of public servers request.CookieContainer = cookies;
Status = "&eRetrieving public servers list..";
try { // On my machine, these reduce minecraft server list download time from 40 seconds to 4.
Servers = GetPublicServers(); request.Proxy = null;
} catch( WebException ex ) { request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
Servers = new List<ServerListEntry>(); if( data != null ) {
Finish( false, ex, "retrieving servers list" ); return; request.Method = "POST";
} request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8;";
Finish( true, null, "&eSigned in" ); byte[] encodedData = Encoding.UTF8.GetBytes( data );
} request.ContentLength = encodedData.Length;
using( Stream stream = request.GetRequestStream() ) {
void Finish( bool success, WebException ex, string status ) { stream.Write( encodedData, 0, encodedData.Length );
if( !success ) }
Username = null; }
Working = false; return (HttpWebResponse)request.GetResponse();
}
Exception = ex;
Status = status; protected IEnumerable<string> GetHtml( string uri, string referer ) {
} HttpWebResponse response = MakeRequest( uri, referer, null );
return GetResponseLines( response );
public abstract void Login( string user, string password ); }
public abstract ClientStartData GetConnectInfo( string hash ); protected IEnumerable<string> PostHtml( string uri, string referer, string data ) {
HttpWebResponse response = MakeRequest( uri, referer, data );
public abstract List<ServerListEntry> GetPublicServers(); return GetResponseLines( response );
}
CookieContainer cookies = new CookieContainer();
protected IEnumerable<string> GetResponseLines( HttpWebResponse response ) {
protected HttpWebResponse MakeRequest( string uri, string referer, string data ) { using( Stream stream = response.GetResponseStream() ) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create( uri ); using( StreamReader reader = new StreamReader( stream ) ) {
request.UserAgent = Program.AppName; string line;
request.ReadWriteTimeout = 15 * 1000; while( (line = reader.ReadLine()) != null ) {
request.Timeout = 15 * 1000; yield return line;
request.Referer = referer; }
request.KeepAlive = true; }
request.CookieContainer = cookies; }
}
// On my machine, these reduce minecraft server list download time from 40 seconds to 4.
request.Proxy = null; protected static void Log( string text ) {
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; System.Diagnostics.Debug.WriteLine( text );
if( data != null ) { }
request.Method = "POST"; }
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8;"; }
byte[] encodedData = Encoding.UTF8.GetBytes( data );
request.ContentLength = encodedData.Length;
using( Stream stream = request.GetRequestStream() ) {
stream.Write( encodedData, 0, encodedData.Length );
}
}
return (HttpWebResponse)request.GetResponse();
}
protected IEnumerable<string> GetHtml( string uri, string referer ) {
HttpWebResponse response = MakeRequest( uri, referer, null );
return GetResponseLines( response );
}
protected IEnumerable<string> PostHtml( string uri, string referer, string data ) {
HttpWebResponse response = MakeRequest( uri, referer, data );
return GetResponseLines( response );
}
protected IEnumerable<string> GetResponseLines( HttpWebResponse response ) {
using( Stream stream = response.GetResponseStream() ) {
using( StreamReader reader = new StreamReader( stream ) ) {
string line;
while( (line = reader.ReadLine()) != null ) {
yield return line;
}
}
}
}
protected static void Log( string text ) {
System.Diagnostics.Debug.WriteLine( text );
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Net;
using System.Threading;
namespace Launcher2 {
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 void CheckForUpdatesAsync() {
Working = true;
Exception = null;
LatestStableDate = null; LatestStableSize = null;
LatestDevDate = null; LatestDevSize = null;
Thread thread = new Thread( UpdateWorker, 256 * 1024 );
thread.Name = "Launcher.UpdateCheck";
thread.Start();
}
void UpdateWorker() {
try {
CheckUpdates();
} catch( WebException ex ) {
Finish( false, ex, null ); return;
}
Finish( true, null, null );
}
void CheckUpdates() {
var response = GetHtml( UpdatesUri, UpdatesUri );
foreach( string line in response ) {
Console.WriteLine( line );
if( line.StartsWith( "latest.", ordinal ) ) {
int index = 0;
string buildName = ReadToken( line, ref index );
string date = ReadToken( line, ref index );
string time = ReadToken( line, ref index );
string buildSize = ReadToken( line, ref index );
if( line.StartsWith( "latest.zip", ordinal ) ) {
LatestDevDate = date + " " + time;
LatestDevSize = buildSize;
} else if( line.StartsWith( "latest.Release.zip", ordinal ) ) {
LatestStableDate = date + " " + time;
LatestStableSize = buildSize;
}
}
}
}
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;
}
}
if( wordEnd == -1 )
wordEnd = value.Length;
return value.Substring( start, wordEnd - start );
}
}
}