Implement servers list and stuff.

This commit is contained in:
UnknownShadow200 2015-10-20 12:57:18 +11:00
parent c205b03726
commit e1a244e319
22 changed files with 582 additions and 375 deletions

View File

@ -55,6 +55,26 @@ namespace ClassicalSharp {
} }
} }
public override void DrawClippedText( ref DrawTextArgs args, float x, float y, float maxWidth, float maxHeight ) {
if( !args.SkipPartsCheck )
GetTextParts( args.Text );
Brush shadowBrush = GetOrCreateBrush( Color.Black );
format.Trimming = StringTrimming.EllipsisCharacter;
for( int i = 0; i < parts.Count; i++ ) {
TextPart part = parts[i];
Brush textBrush = GetOrCreateBrush( part.TextColour );
RectangleF rect = new RectangleF( x + Offset, y + Offset, maxWidth, maxHeight );
if( args.UseShadow )
g.DrawString( part.Text, args.Font, shadowBrush, rect, format );
rect = new RectangleF( x, y, maxWidth, maxHeight );
g.DrawString( part.Text, args.Font, textBrush, rect, format );
x += g.MeasureString( part.Text, args.Font, Int32.MaxValue, format ).Width;
}
format.Trimming = StringTrimming.None;
}
public override void DrawRect( Color colour, int x, int y, int width, int height ) { public override void DrawRect( Color colour, int x, int y, int width, int height ) {
Brush brush = GetOrCreateBrush( colour ); Brush brush = GetOrCreateBrush( colour );
g.FillRectangle( brush, x, y, width, height ); g.FillRectangle( brush, x, y, width, height );

View File

@ -20,6 +20,10 @@ namespace ClassicalSharp {
/// specified coordinates in the currently bound bitmap. </summary> /// specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawText( ref DrawTextArgs args, float x, float y ); public abstract void DrawText( ref DrawTextArgs args, float x, float y );
/// <summary> Draws a string using the specified arguments and fonts at the
/// specified coordinates in the currently bound bitmap, clipping if necessary. </summary>
public abstract void DrawClippedText( ref DrawTextArgs args, float x, float y, float maxWidth, float maxHeight );
/// <summary> Draws a 2D flat rectangle of the specified dimensions at the /// <summary> Draws a 2D flat rectangle of the specified dimensions at the
/// specified coordinates in the currently bound bitmap. </summary> /// specified coordinates in the currently bound bitmap. </summary>
public abstract void DrawRect( Color colour, int x, int y, int width, int height ); public abstract void DrawRect( Color colour, int x, int y, int width, int height );

View File

@ -105,13 +105,13 @@ namespace ClassicalSharp {
FastColour col = colXSide; FastColour col = colXSide;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight, cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight,
pos.Z - scale, rec.U1, rec.V2, colNormal ); pos.Z - scale, rec.U1, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight, cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight,
pos.Z - scale, rec.U1, rec.V1, colNormal ); pos.Z - scale, rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight, cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y - scale * blockHeight,
pos.Z + scale, rec.U2, rec.V1, colNormal ); pos.Z + scale, rec.U2, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight, cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + scale * blockHeight,
pos.Z + scale, rec.U2, rec.V2, colNormal ); pos.Z + scale, rec.U2, rec.V2, col );
} }
} }
} }

View File

@ -123,8 +123,6 @@ namespace ClassicalSharp {
} }
if( jumping ) { if( jumping ) {
Vector3I p = Vector3I.Floor( Position );
if( TouchesAnyWater() || TouchesAnyLava() ) { if( TouchesAnyWater() || TouchesAnyLava() ) {
BoundingBox bounds = CollisionBounds; BoundingBox bounds = CollisionBounds;
bounds.Min.Y += 1; bounds.Min.Y += 1;

View File

@ -13,7 +13,7 @@ namespace ClassicalSharp.Network {
EventWaitHandle handle = new EventWaitHandle( false, EventResetMode.AutoReset ); EventWaitHandle handle = new EventWaitHandle( false, EventResetMode.AutoReset );
Thread worker; Thread worker;
readonly object requestLocker = new object(); readonly object requestLocker = new object();
List<DownloadRequest> requests = new List<DownloadRequest>(); List<Request> requests = new List<Request>();
readonly object downloadedLocker = new object(); readonly object downloadedLocker = new object();
Dictionary<string, DownloadedItem> downloaded = new Dictionary<string, DownloadedItem>(); Dictionary<string, DownloadedItem> downloaded = new Dictionary<string, DownloadedItem>();
string skinServer = null; string skinServer = null;
@ -50,7 +50,7 @@ namespace ClassicalSharp.Network {
void AddRequest( string url, bool priority, string identifier, byte type ) { void AddRequest( string url, bool priority, string identifier, byte type ) {
lock( requestLocker ) { lock( requestLocker ) {
DownloadRequest request = new DownloadRequest( url, identifier, type ); Request request = new Request( url, identifier, type );
if( priority ) { if( priority ) {
requests.Insert( 0, request ); requests.Insert( 0, request );
} else { } else {
@ -109,7 +109,7 @@ namespace ClassicalSharp.Network {
WebClient client; WebClient client;
void DownloadThreadWorker() { void DownloadThreadWorker() {
while( true ) { while( true ) {
DownloadRequest request = null; Request request = null;
lock( requestLocker ) { lock( requestLocker ) {
if( requests.Count > 0 ) { if( requests.Count > 0 ) {
request = requests[0]; request = requests[0];
@ -126,7 +126,7 @@ namespace ClassicalSharp.Network {
} }
} }
void DownloadItem( DownloadRequest request ) { void DownloadItem( Request request ) {
string url = request.Url; string url = request.Url;
byte type = request.Type; byte type = request.Type;
string dataType = type == 0 ? "image" : (type == 1 ? "string" : "raw"); string dataType = type == 0 ? "image" : (type == 1 ? "string" : "raw");
@ -177,14 +177,14 @@ namespace ClassicalSharp.Network {
} }
} }
class DownloadRequest { class Request {
public string Url; public string Url;
public string Identifier; public string Identifier;
public byte Type; // 0 = bitmap, 1 = string, 2 = byte[] public byte Type; // 0 = bitmap, 1 = string, 2 = byte[]
public DateTime TimeAdded; public DateTime TimeAdded;
public DownloadRequest( string url, string identifier, byte type ) { public Request( string url, string identifier, byte type ) {
Url = url; Url = url;
Identifier = identifier; Identifier = identifier;
Type = type; Type = type;

View File

@ -43,6 +43,7 @@ namespace ClassicalSharp {
public void Render( double deltaTime ) { public void Render( double deltaTime ) {
if( sidesVb == -1 || edgesVb == -1 ) return; if( sidesVb == -1 || edgesVb == -1 ) return;
graphics.Texturing = true; graphics.Texturing = true;
graphics.AlphaTest = true;
graphics.BindTexture( sideTexId ); graphics.BindTexture( sideTexId );
graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b ); graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b );
graphics.BindVb( sidesVb ); graphics.BindVb( sidesVb );
@ -60,6 +61,7 @@ namespace ClassicalSharp {
} }
graphics.AlphaBlending = false; graphics.AlphaBlending = false;
graphics.Texturing = false; graphics.Texturing = false;
graphics.AlphaTest = false;
} }
public void Dispose() { public void Dispose() {

View File

@ -15,18 +15,34 @@ namespace Launcher2 {
titleFont = new Font( "Arial", 15, FontStyle.Bold ); titleFont = new Font( "Arial", 15, FontStyle.Bold );
inputFont = new Font( "Arial", 15, FontStyle.Regular ); inputFont = new Font( "Arial", 15, FontStyle.Regular );
enterIndex = 4; enterIndex = 4;
widgets = new LauncherWidget[7]; widgets = new LauncherWidget[8];
} }
public override void Init() { public override void Init() {
Resize(); Resize();
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
LoadSavedInfo( drawer ); LoadSavedInfo( drawer );
} }
} }
public override void Tick() { public override void Tick() {
if( !signingIn ) return;
ClassicubeSession session = game.Session;
string status = session.Status;
if( status != lastStatus )
SetStatus( status );
if( !session.Working ) {
if( session.Exception != null ) {
DisplayWebException( session.Exception, session.Status );
}
signingIn = false;
game.MakeBackground();
Resize();
}
} }
void LoadSavedInfo( IDrawer2D drawer ) { void LoadSavedInfo( IDrawer2D drawer ) {
@ -45,31 +61,36 @@ namespace Launcher2 {
} }
public override void Resize() { public override void Resize() {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
Draw( drawer ); Draw();
} }
Dirty = true; Dirty = true;
} }
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); void Draw() {
void Draw( IDrawer2D drawer ) {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( drawer, "Username", -180, -100 ); MakeTextAt( "Username", -180, -100 );
MakeTextAt( drawer, "Password", -180, -50 ); MakeTextAt( "Password", -180, -50 );
MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, -100 ); MakeTextInputAt( false, Get( widgetIndex ), 30, -100 );
MakeTextInputAt( drawer, true, Get( widgetIndex ), 30, -50 ); MakeTextInputAt( true, Get( widgetIndex ), 30, -50 );
MakeButtonAt( drawer, "Sign in", 90, 35, -75, 0, StartClient ); MakeButtonAt( "Sign in", 90, 35, -75, 0, StartClient );
MakeButtonAt( drawer, "Back", 80, 35, 140, 0, () => game.SetScreen( new MainScreen( game ) ) ); MakeButtonAt( "Back", 80, 35, 140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) );
MakeTextAt( drawer, "", 0, 50 ); MakeTextAt( "", 0, 50 );
if( HasServers && !signingIn )
MakeButtonAt( "Servers", 90, 35, 35, 0, ShowServers );
} }
string lastStatus;
void SetStatus( string text ) { void SetStatus( string text ) {
using( IDrawer2D drawer = game.Drawer ) { lastStatus = text;
using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
LauncherTextWidget widget = (LauncherTextWidget)widgets[6]; LauncherTextWidget widget = (LauncherTextWidget)widgets[6];
drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y, drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y,
widget.Width, widget.Height ); widget.Width, widget.Height );
widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 0, 50 ); widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 0, 50 );
@ -77,13 +98,13 @@ namespace Launcher2 {
} }
} }
void MakeTextAt( IDrawer2D drawer, string text, int x, int y ) { void MakeTextAt( string text, int x, int y ) {
LauncherTextWidget widget = new LauncherTextWidget( game, text ); LauncherTextWidget widget = new LauncherTextWidget( game, text );
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeTextInputAt( IDrawer2D drawer, bool password, string text, int x, int y ) { void MakeTextInputAt( bool password, string text, int x, int y ) {
LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); LauncherTextInputWidget widget = new LauncherTextInputWidget( game );
widget.OnClick = InputClick; widget.OnClick = InputClick;
widget.Password = password; widget.Password = password;
@ -92,52 +113,46 @@ namespace Launcher2 {
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, void MakeButtonAt( string text, int width, int height,
int x, int y, Action onClick ) { int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game ); LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text; widget.Text = text;
widget.OnClick = onClick; widget.OnClick = onClick;
widget.Active = false;
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y );
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void StartClient() { bool HasServers {
get {
return !(game.Session.Servers == null || game.Session.Servers.Count == 0 );
}
}
bool signingIn;
void StartClient( int mouseX, int mouseY ) {
if( String.IsNullOrEmpty( Get( 2 ) ) ) { if( String.IsNullOrEmpty( Get( 2 ) ) ) {
SetStatus( "&ePlease enter a username" ); return; SetStatus( "&ePlease enter a username" ); return;
} }
if( String.IsNullOrEmpty( Get( 3 ) ) ) { if( String.IsNullOrEmpty( Get( 3 ) ) ) {
SetStatus( "&ePlease enter a username" ); return; SetStatus( "&ePlease enter a username" ); return;
} }
System.Diagnostics.Debug.WriteLine( Get( 2 ) ); if( signingIn ) return;
System.Diagnostics.Debug.WriteLine( Get( 3 ) );
game.Session.LoginAsync( Get( 2 ), Get( 3 ) );
game.MakeBackground();
Resize();
SetStatus( "&eSigning in.." );
signingIn = true;
}
void ShowServers( int mouseX, int mouseY ) {
if( signingIn ) return;
SetStatus( "&eSigning in..." );
ClassicubeSession session = game.Session; ClassicubeSession session = game.Session;
try { if( !HasServers ) return;
session.Login( Get( 2 ), Get( 3 ) ); game.SetScreen( new ClassiCubeServersScreen( game ) );
} catch( WebException ex ) {
session.Username = null;
DisplayWebException( ex, "sign in" );
return;
} catch( InvalidOperationException ex ) {
session.Username = null;
string text = "&eFailed to sign in: " +
Environment.NewLine + ex.Message;
SetStatus( text );
return;
}
SetStatus( "&eRetrieving public servers list.." );
try {
game.Servers = session.GetPublicServers();
} catch( WebException ex ) {
game.Servers = new List<ServerListEntry>();
DisplayWebException( ex, "retrieve servers list" );
return;
}
SetStatus( "&eSigned in" );
} }
void DisplayWebException( WebException ex, string action ) { void DisplayWebException( WebException ex, string action ) {

View File

@ -1,230 +1,168 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Net; using System.Net;
using ClassicalSharp; using ClassicalSharp;
using OpenTK;
using OpenTK.Input; using OpenTK.Input;
namespace Launcher2 { namespace Launcher2 {
public sealed class ClassiCubeServersScreen : LauncherScreen { public sealed class ClassiCubeServersScreen : LauncherInputScreen {
const int tableIndex = 6;
public ClassiCubeServersScreen( LauncherWindow game ) : base( game ) { public ClassiCubeServersScreen( LauncherWindow game ) : base( game ) {
textFont = new Font( "Arial", 16, FontStyle.Bold ); titleFont = new Font( "Arial", 16, FontStyle.Bold );
widgets = new LauncherWidget[5]; inputFont = new Font( "Arial", 13, FontStyle.Regular );
game.Window.Mouse.Move += MouseMove; enterIndex = 4;
game.Window.Mouse.ButtonDown += MouseButtonDown;
game.Window.KeyPress += KeyPress; widgets = new LauncherWidget[7];
game.Window.Keyboard.KeyDown += KeyDown; game.Window.Mouse.WheelChanged += MouseWheelChanged;
game.Window.Keyboard.KeyRepeat = true; game.Window.Mouse.ButtonUp += MouseButtonUp;
} }
public override void Tick() { public override void Tick() {
} }
void KeyDown( object sender, KeyboardKeyEventArgs e ) { protected override void MouseMove( object sender, MouseMoveEventArgs e ) {
if( lastInput != null && e.Key == Key.BackSpace ) { base.MouseMove( sender, e );
using( IDrawer2D drawer = game.Drawer ) { if( selectedWidget != null && selectedWidget == widgets[tableIndex] ) {
drawer.SetBitmap( game.Framebuffer ); LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
lastInput.RemoveChar( textFont ); table.MouseMove( e.XDelta, e.YDelta );
Dirty = true;
}
} else if( e.Key == Key.Enter ) { // Click sign in button
LauncherWidget widget = widgets[4];
if( widget.OnClick != null )
widget.OnClick();
} }
} }
void KeyPress( object sender, KeyPressEventArgs e ) { void MouseButtonUp( object sender, MouseButtonEventArgs e ) {
if( lastInput != null ) { LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
using( IDrawer2D drawer = game.Drawer ) { table.DraggingWidth = false;
drawer.SetBitmap( game.Framebuffer ); }
lastInput.AddChar( e.KeyChar, textFont );
Dirty = true; protected override void OnAddedChar() { FilterList(); }
}
protected override void OnRemovedChar() { FilterList(); }
void FilterList() {
if( lastInput == widgets[1] ) {
LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
table.FilterEntries( lastInput.Text );
ClampIndex();
Resize();
} }
} }
public override void Init() { Resize(); } public override void Init() { Resize(); }
public override void Resize() { public override void Resize() {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
drawer.Clear( LauncherWindow.clearColour ); drawer.Clear( LauncherWindow.clearColour );
DrawButtons( drawer ); Draw();
} }
Dirty = true; Dirty = true;
} }
Font textFont; void Draw() {
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 );
void DrawButtons( IDrawer2D drawer ) {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( drawer, "Search", -180, 0 ); int lastIndex = GetLastInputIndex();
MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, 0 );
MakeTextAt( drawer, "classicube.net/server/play/", -320, 50 ); MakeTextAt( titleFont, "Search", -200, 10 );
MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, 50 ); MakeTextInputAt( Get( widgetIndex ), 270, -25, 5 );
MakeButtonAt( drawer, "Back", 80, 35, 180, 0, () => game.SetScreen( new MainScreen( game ) ) ); MakeTextAt( inputFont, "../play/", -210, 55 );
MakeTextInputAt( "61f27b1f0a3dcb546b650b87a3e17436"/*Get( 3 )*/, 320, -20, 50 );
MakeButtonAt( "Connect", 100, 30, 180, 5, ConnectToServer );
MakeButtonAt( "Back", 70, 30, 195, 50,
(x, y) => game.SetScreen( new MainScreen( game ) ) );
MakeTableWidget();
if( lastIndex >= 0 )
lastInput = widgets[lastIndex] as LauncherTextInputWidget;
} }
ClassicubeSession session = new ClassicubeSession(); int GetLastInputIndex() {
List<ServerListEntry> servers = new List<ServerListEntry>(); return lastInput == null ? -1 :
void StartClient() { Array.IndexOf<LauncherWidget>( widgets, lastInput );
if( String.IsNullOrEmpty( Get( 2 ) ) ) {
SetStatus( "&ePlease enter a username" ); return;
}
if( String.IsNullOrEmpty( Get( 3 ) ) ) {
SetStatus( "&ePlease enter a username" ); return;
}
System.Diagnostics.Debug.WriteLine( Get( 2 ) );
System.Diagnostics.Debug.WriteLine( Get( 3 ) );
SetStatus( "&eSigning in..." );
try {
session.Login( Get( 2 ), Get( 3 ) );
} catch( WebException ex ) {
session.Username = null;
DisplayWebException( ex, "sign in" );
return;
} catch( InvalidOperationException ex ) {
session.Username = null;
string text = "&eFailed to sign in: " +
Environment.NewLine + ex.Message;
SetStatus( text );
return;
}
SetStatus( "&eRetrieving public servers list.." );
try {
servers = session.GetPublicServers();
} catch( WebException ex ) {
servers = new List<ServerListEntry>();
DisplayWebException( ex, "retrieve servers list" );
return;
}
SetStatus( "&eSigned in" );
}
string Get( int index ) {
LauncherWidget widget = widgets[index];
return widget == null ? "" : ((widget as LauncherTextInputWidget)).Text;
}
void Set( int index, string text ) {
(widgets[index] as LauncherTextInputWidget)
.Redraw( game.Drawer, text, textFont );
}
void SetStatus( string text ) {
using( IDrawer2D drawer = game.Drawer ) {
drawer.SetBitmap( game.Framebuffer );
LauncherTextWidget widget = (LauncherTextWidget)widgets[6];
drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y,
widget.Width, widget.Height );
widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.Centre, 0, 50 );
Dirty = true;
}
} }
void MakeTextAt( IDrawer2D drawer, string text, int x, int y ) { void MakeTextAt( Font font, string text, int x, int y ) {
LauncherTextWidget widget = new LauncherTextWidget( game, text ); LauncherTextWidget widget = new LauncherTextWidget( game, text );
widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.LeftOrTop, x, y ); widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.LeftOrTop, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeTextInputAt( IDrawer2D drawer, bool password, string text, int x, int y ) { void MakeTextInputAt( string text, int width, int x, int y ) {
LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); LauncherTextInputWidget widget = new LauncherTextInputWidget( game );
widget.OnClick = InputClick; widget.OnClick = InputClick;
widget.Password = password;
widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.LeftOrTop, 300, 30, x, y ); widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.LeftOrTop, width, 30, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, void MakeButtonAt( string text, int width, int height,
int x, int y, Action onClick ) { int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game ); LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text; widget.Text = text;
widget.OnClick = onClick; widget.OnClick = onClick;
widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.LeftOrTop, width, height, x, y ); widget.Active = false;
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.LeftOrTop, width, height, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
protected override void UnselectWidget( LauncherWidget widget ) { void MakeTableWidget() {
LauncherButtonWidget button = widget as LauncherButtonWidget; if( widgets[tableIndex] != null ) {
if( button != null ) { LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
button.Redraw( game.Drawer, button.Text, textFont ); table.Redraw( drawer, inputFont, titleFont );
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); return;
Dirty = true;
} }
LauncherTableWidget widget = new LauncherTableWidget( game );
widget.CurrentIndex = 0;
widget.SetEntries( game.Session.Servers );
widget.DrawAt( drawer, inputFont, titleFont, Anchor.LeftOrTop, Anchor.LeftOrTop, 0, 100 );
widget.NeedRedraw = Resize;
widget.SelectedChanged = SelectedChanged;
widgets[widgetIndex++] = widget;
} }
protected override void SelectWidget( LauncherWidget widget ) { void SelectedChanged( string hash ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; using( drawer ) {
if( button != null ) {
button.Redraw( game.Drawer, button.Text, textFont );
Dirty = true;
}
}
LauncherTextInputWidget lastInput;
void InputClick() {
LauncherTextInputWidget input = selectedWidget as LauncherTextInputWidget;
using( IDrawer2D drawer = game.Drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
if( lastInput != null ) { Set( 3, hash );
lastInput.Active = false;
lastInput.Redraw( game.Drawer, lastInput.Text, textFont );
}
input.Active = true;
input.Redraw( game.Drawer, input.Text, textFont );
} }
lastInput = input;
Dirty = true; Dirty = true;
} }
public override void Dispose() { void ConnectToServer( int mouseX, int mouseY ) {
textFont.Dispose(); GameStartData data = null;
game.Window.Mouse.Move -= MouseMove; try {
game.Window.Mouse.ButtonDown -= MouseButtonDown; data = game.Session.GetConnectInfo( Get( 3 ) );
} catch( WebException ex ) {
game.Window.KeyPress -= KeyPress; Program.LogException( ex );
game.Window.Keyboard.KeyDown -= KeyDown; return;
game.Window.Keyboard.KeyRepeat = false; }
Client.Start( data, true );
} }
void DisplayWebException( WebException ex, string action ) { void MouseWheelChanged( object sender, MouseWheelEventArgs e ) {
Program.LogException( ex ); LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
if( ex.Status == WebExceptionStatus.Timeout ) { table.CurrentIndex -= e.Delta;
string text = "&eFailed to " + action + ":" + ClampIndex();
Environment.NewLine + "Timed out while connecting to classicube.net."; Resize();
SetStatus( text ); }
} else if( ex.Status == WebExceptionStatus.ProtocolError ) {
HttpWebResponse response = (HttpWebResponse)ex.Response; void ClampIndex() {
int errorCode = (int)response.StatusCode; LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget;
string description = response.StatusDescription; if( table.CurrentIndex >= table.Count )
string text = "&eFailed to " + action + ":" + table.CurrentIndex = table.Count - 1;
Environment.NewLine + " classicube.net returned: (" + errorCode + ") " + description; if( table.CurrentIndex < 0 )
SetStatus(text ); table.CurrentIndex = 0;
} else if( ex.Status == WebExceptionStatus.NameResolutionFailure ) { }
string text = "&eFailed to " + action + ":" +
Environment.NewLine + "Unable to resolve classicube.net" + public override void Dispose() {
Environment.NewLine + "you may not be connected to the internet."; base.Dispose();
SetStatus( text ); game.Window.Mouse.WheelChanged -= MouseWheelChanged;
} else {
string text = "&eFailed to " + action + ":" +
Environment.NewLine + ex.Status;
SetStatus( text );
}
} }
} }
} }

View File

@ -19,7 +19,7 @@ namespace Launcher2 {
public override void Init() { public override void Init() {
Resize(); Resize();
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
LoadSavedInfo( drawer ); LoadSavedInfo( drawer );
} }
@ -53,31 +53,30 @@ namespace Launcher2 {
} }
public override void Resize() { public override void Resize() {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
Draw( drawer ); Draw();
} }
Dirty = true; Dirty = true;
} }
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); void Draw() {
void Draw( IDrawer2D drawer ) {
widgetIndex = 0; widgetIndex = 0;
MakeTextAt( drawer, "Username", -180, -100 ); MakeTextAt( "Username", -180, -100 );
MakeTextAt( drawer, "Address", -180, -50 ); MakeTextAt( "Address", -180, -50 );
MakeTextAt( drawer, "Mppass", -180, 0 ); MakeTextAt( "Mppass", -180, 0 );
MakeTextInputAt( drawer, Get( widgetIndex ), 30, -100 ); MakeTextInputAt( Get( widgetIndex ), 30, -100 );
MakeTextInputAt( drawer, Get( widgetIndex ), 30, -50 ); MakeTextInputAt( Get( widgetIndex ), 30, -50 );
MakeTextInputAt( drawer, Get( widgetIndex ), 30, 0 ); MakeTextInputAt( Get( widgetIndex ), 30, 0 );
MakeButtonAt( drawer, "Connect", 110, 35, -65, 50, StartClient ); MakeButtonAt( "Connect", 110, 35, -65, 50, StartClient );
MakeButtonAt( drawer, "Back", 80, 35, 140, 50, () => game.SetScreen( new MainScreen( game ) ) ); MakeButtonAt( "Back", 80, 35, 140, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) );
MakeTextAt( drawer, "", 0, 100 ); MakeTextAt( "", 0, 100 );
} }
void SetStatus( string text ) { void SetStatus( string text ) {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
LauncherTextWidget widget = (LauncherTextWidget)widgets[8]; LauncherTextWidget widget = (LauncherTextWidget)widgets[8];
drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y, drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y,
@ -87,13 +86,13 @@ namespace Launcher2 {
} }
} }
void MakeTextAt( IDrawer2D drawer, string text, int x, int y ) { void MakeTextAt( string text, int x, int y ) {
LauncherTextWidget widget = new LauncherTextWidget( game, text ); LauncherTextWidget widget = new LauncherTextWidget( game, text );
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeTextInputAt( IDrawer2D drawer, string text, int x, int y ) { void MakeTextInputAt( string text, int x, int y ) {
LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); LauncherTextInputWidget widget = new LauncherTextInputWidget( game );
widget.OnClick = InputClick; widget.OnClick = InputClick;
@ -101,18 +100,18 @@ namespace Launcher2 {
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, void MakeButtonAt( string text, int width, int height,
int x, int y, Action onClick ) { int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game ); LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text; widget.Text = text;
widget.OnClick = onClick; widget.OnClick = onClick;
widget.Active = false;
widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y );
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void StartClient() { void StartClient( int mouseX, int mouseY ) {
SetStatus( "" ); SetStatus( "" );
if( String.IsNullOrEmpty( Get( 3 ) ) ) { if( String.IsNullOrEmpty( Get( 3 ) ) ) {

View File

@ -24,28 +24,34 @@ namespace Launcher2 {
protected void KeyDown( object sender, KeyboardKeyEventArgs e ) { protected void KeyDown( object sender, KeyboardKeyEventArgs e ) {
if( lastInput != null && e.Key == Key.BackSpace ) { if( lastInput != null && e.Key == Key.BackSpace ) {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
lastInput.RemoveChar( inputFont ); lastInput.RemoveChar( inputFont );
Dirty = true; Dirty = true;
} }
OnRemovedChar();
} else if( e.Key == Key.Enter && enterIndex >= 0 ) { } else if( e.Key == Key.Enter && enterIndex >= 0 ) {
LauncherWidget widget = widgets[enterIndex]; LauncherWidget widget = widgets[enterIndex];
if( widget.OnClick != null ) if( widget.OnClick != null )
widget.OnClick(); widget.OnClick( 0, 0 );
} }
} }
protected void KeyPress( object sender, KeyPressEventArgs e ) { protected void KeyPress( object sender, KeyPressEventArgs e ) {
if( lastInput != null ) { if( lastInput != null ) {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
lastInput.AddChar( e.KeyChar, inputFont ); lastInput.AddChar( e.KeyChar, inputFont );
Dirty = true; Dirty = true;
} }
OnAddedChar();
} }
} }
protected virtual void OnAddedChar() { }
protected virtual void OnRemovedChar() { }
protected string Get( int index ) { protected string Get( int index ) {
LauncherWidget widget = widgets[index]; LauncherWidget widget = widgets[index];
return widget == null ? "" : ((widget as LauncherTextInputWidget)).Text; return widget == null ? "" : ((widget as LauncherTextInputWidget)).Text;
@ -53,14 +59,14 @@ namespace Launcher2 {
protected void Set( int index, string text ) { protected void Set( int index, string text ) {
(widgets[index] as LauncherTextInputWidget) (widgets[index] as LauncherTextInputWidget)
.Redraw( game.Drawer, text, inputFont ); .Redraw( drawer, text, inputFont );
} }
protected override void UnselectWidget( LauncherWidget widget ) { protected override void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) { if( button != null ) {
button.Redraw( game.Drawer, button.Text, titleFont ); button.Active = false;
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); button.Redraw( drawer, button.Text, titleFont );
Dirty = true; Dirty = true;
} }
} }
@ -68,23 +74,24 @@ namespace Launcher2 {
protected override void SelectWidget( LauncherWidget widget ) { protected override void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) { if( button != null ) {
button.Redraw( game.Drawer, button.Text, titleFont ); button.Active = true;
button.Redraw( drawer, button.Text, titleFont );
Dirty = true; Dirty = true;
} }
} }
protected LauncherTextInputWidget lastInput; protected LauncherTextInputWidget lastInput;
protected void InputClick() { protected void InputClick( int mouseX, int mouseY ) {
LauncherTextInputWidget input = selectedWidget as LauncherTextInputWidget; LauncherTextInputWidget input = selectedWidget as LauncherTextInputWidget;
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
if( lastInput != null ) { if( lastInput != null ) {
lastInput.Active = false; lastInput.Active = false;
lastInput.Redraw( game.Drawer, lastInput.Text, inputFont ); lastInput.Redraw( drawer, lastInput.Text, inputFont );
} }
input.Active = true; input.Active = true;
input.Redraw( game.Drawer, input.Text, inputFont ); input.Redraw( drawer, input.Text, inputFont );
} }
lastInput = input; lastInput = input;
Dirty = true; Dirty = true;

View File

@ -7,12 +7,14 @@ namespace Launcher2 {
public abstract class LauncherScreen { public abstract class LauncherScreen {
protected LauncherWindow game; protected LauncherWindow game;
protected IDrawer2D drawer;
public bool Dirty; public bool Dirty;
protected int widgetIndex; protected int widgetIndex;
public LauncherScreen( LauncherWindow game ) { public LauncherScreen( LauncherWindow game ) {
this.game = game; this.game = game;
drawer = game.Drawer;
} }
public abstract void Init(); public abstract void Init();
@ -25,44 +27,9 @@ namespace Launcher2 {
/// <summary> Cleans up all native resources held by this screen. </summary> /// <summary> Cleans up all native resources held by this screen. </summary>
public abstract void Dispose(); public abstract void Dispose();
protected static uint clearColourBGRA = (uint)LauncherWindow.clearColour.ToArgb();
protected unsafe void FilterArea( int x, int y, int width, int height, byte scale ) {
FilterArea( x, y, width, height, scale, clearColourBGRA );
}
/// <summary> Scales the RGB components of the bitmap in the specified region by the given amount. </summary>
/// <remarks> Pixels with same value as clearColour are left untouched. </remarks>
protected unsafe void FilterArea( int x, int y, int width, int height,
byte scale, uint clearColour ) {
Bitmap buffer = game.Framebuffer;
if( x >= buffer.Width || y >= buffer.Height ) return;
width = Math.Min( x + width, buffer.Width ) - x;
height = Math.Min( y + height, buffer.Height ) - y;
using( FastBitmap bmp = new FastBitmap( buffer, true ) ) {
for( int yy = y; yy < y + height; yy++ ) {
int* row = bmp.GetRowPtr( yy ) + x;
for( int xx = 0; xx < width; xx++ ) {
uint pixel = (uint)row[xx];
if( pixel == clearColour ) continue;
uint a = pixel & 0xFF000000;
uint r = (pixel >> 16) & 0xFF;
uint g = (pixel >> 8) & 0xFF;
uint b = pixel & 0xFF;
r = (r * scale) / 255;
g = (g * scale) / 255;
b = (b * scale) / 255;
row[xx] = (int)(a | (r << 16) | (g << 8) | b);
}
}
}
}
protected LauncherWidget selectedWidget; protected LauncherWidget selectedWidget;
protected LauncherWidget[] widgets; protected LauncherWidget[] widgets;
protected void MouseMove( object sender, MouseMoveEventArgs e ) { protected virtual void MouseMove( object sender, MouseMoveEventArgs e ) {
for( int i = 0; i < widgets.Length; i++ ) { for( int i = 0; i < widgets.Length; i++ ) {
LauncherWidget widget = widgets[i]; LauncherWidget widget = widgets[i];
if( widget == null ) continue; if( widget == null ) continue;
@ -70,7 +37,7 @@ namespace Launcher2 {
e.X < widget.X + widget.Width && e.Y < widget.Y + widget.Height ) { e.X < widget.X + widget.Width && e.Y < widget.Y + widget.Height ) {
if( selectedWidget == widget ) return; if( selectedWidget == widget ) return;
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
if( selectedWidget != null ) if( selectedWidget != null )
UnselectWidget( selectedWidget ); UnselectWidget( selectedWidget );
@ -82,7 +49,7 @@ namespace Launcher2 {
} }
if( selectedWidget == null ) return; if( selectedWidget == null ) return;
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
UnselectWidget( selectedWidget ); UnselectWidget( selectedWidget );
} }
@ -101,7 +68,7 @@ namespace Launcher2 {
if( e.Button != MouseButton.Left || selectedWidget == null ) return; if( e.Button != MouseButton.Left || selectedWidget == null ) return;
if( selectedWidget.OnClick != null ) if( selectedWidget.OnClick != null )
selectedWidget.OnClick(); selectedWidget.OnClick( e.X, e.Y );
} }
} }
} }

View File

@ -16,14 +16,15 @@ namespace Launcher2 {
protected override void UnselectWidget( LauncherWidget widget ) { protected override void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
button.Redraw( game.Drawer, button.Text, textFont ); button.Active = false;
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); button.Redraw( drawer, button.Text, textFont );
Dirty = true; Dirty = true;
} }
protected override void SelectWidget( LauncherWidget widget ) { protected override void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
button.Redraw( game.Drawer, button.Text, textFont ); button.Active = true;
button.Redraw( drawer, button.Text, textFont );
Dirty = true; Dirty = true;
} }
@ -33,42 +34,41 @@ namespace Launcher2 {
} }
public override void Resize() { public override void Resize() {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
Draw( drawer ); Draw();
} }
Dirty = true; Dirty = true;
} }
Font textFont; Font textFont;
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); void Draw() {
void Draw( IDrawer2D drawer ) {
widgetIndex = 0; widgetIndex = 0;
MakeButtonAt( drawer, "Direct connect", Anchor.Centre, Anchor.Centre, MakeButtonAt( "Direct connect", Anchor.Centre, Anchor.Centre,
buttonWidth, buttonHeight, 0, -100, buttonWidth, buttonHeight, 0, -100,
() => game.SetScreen( new DirectConnectScreen( game ) ) ); (x, y) => game.SetScreen( new DirectConnectScreen( game ) ) );
MakeButtonAt( drawer, "ClassiCube.net", Anchor.Centre, Anchor.Centre, MakeButtonAt( "ClassiCube.net", Anchor.Centre, Anchor.Centre,
buttonWidth, buttonHeight, 0, -50, buttonWidth, buttonHeight, 0, -50,
() => game.SetScreen( new ClassiCubeScreen( game ) ) ); (x, y) => game.SetScreen( new ClassiCubeScreen( game ) ) );
MakeButtonAt( drawer, "Singleplayer", Anchor.LeftOrTop, Anchor.BottomOrRight, MakeButtonAt( "Singleplayer", Anchor.LeftOrTop, Anchor.BottomOrRight,
sideButtonWidth, buttonHeight, 10, -10, sideButtonWidth, buttonHeight, 10, -10,
() => Client.Start( "default.zip" ) ); (x, y) => Client.Start( "default.zip" ) );
MakeButtonAt( drawer, "Resume", Anchor.BottomOrRight, Anchor.BottomOrRight, MakeButtonAt( "Resume", Anchor.BottomOrRight, Anchor.BottomOrRight,
sideButtonWidth, buttonHeight, -10, -10, null ); sideButtonWidth, buttonHeight, -10, -10, null );
} }
const int buttonWidth = 220, buttonHeight = 35, sideButtonWidth = 150; const int buttonWidth = 220, buttonHeight = 35, sideButtonWidth = 150;
void MakeButtonAt( IDrawer2D drawer, string text, Anchor horAnchor, void MakeButtonAt( string text, Anchor horAnchor,
Anchor verAnchor, int width, int height, int x, int y, Action onClick ) { Anchor verAnchor, int width, int height, int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game ); LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text; widget.Text = text;
widget.OnClick = onClick; widget.OnClick = onClick;
widget.Active = false;
widget.DrawAt( drawer, text, textFont, horAnchor, verAnchor, width, height, x, y ); widget.DrawAt( drawer, text, textFont, horAnchor, verAnchor, width, height, x, y );
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }

View File

@ -32,9 +32,9 @@ namespace Launcher2 {
} }
public override void Resize() { public override void Resize() {
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
Draw( drawer ); Draw();
} }
Dirty = true; Dirty = true;
} }
@ -42,8 +42,8 @@ namespace Launcher2 {
protected override void UnselectWidget( LauncherWidget widget ) { protected override void UnselectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) { if( button != null ) {
button.Redraw( game.Drawer, button.Text, textFont ); button.Active = false;
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180, backColBGRA ); button.Redraw( drawer, button.Text, textFont );
Dirty = true; Dirty = true;
} }
} }
@ -51,13 +51,14 @@ namespace Launcher2 {
protected override void SelectWidget( LauncherWidget widget ) { protected override void SelectWidget( LauncherWidget widget ) {
LauncherButtonWidget button = widget as LauncherButtonWidget; LauncherButtonWidget button = widget as LauncherButtonWidget;
if( button != null ) { if( button != null ) {
button.Redraw( game.Drawer, button.Text, textFont ); button.Active = true;
button.Redraw( drawer, button.Text, textFont );
Dirty = true; Dirty = true;
} }
} }
ResourceFetcher fetcher; ResourceFetcher fetcher;
void DownloadResources() { void DownloadResources( int mouseX, int mouseY ) {
if( game.Downloader == null ) if( game.Downloader == null )
game.Downloader = new AsyncDownloader( "null" ); game.Downloader = new AsyncDownloader( "null" );
if( fetcher != null ) return; if( fetcher != null ) return;
@ -66,38 +67,37 @@ namespace Launcher2 {
fetcher.DownloadItems( SetStatus ); fetcher.DownloadItems( SetStatus );
selectedWidget = null; selectedWidget = null;
game.MakeBackground();
Resize(); Resize();
} }
Font textFont; Font textFont;
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 );
static FastColour backCol = new FastColour( 120, 85, 151 ); static FastColour backCol = new FastColour( 120, 85, 151 );
static uint backColBGRA = (uint)backCol.ToArgb(); static uint backColBGRA = (uint)backCol.ToArgb();
static readonly string mainText = "Some required resources weren't found" + static readonly string mainText = "Some required resources weren't found" +
Environment.NewLine + "Okay to download them?"; Environment.NewLine + "Okay to download them?";
static readonly string format = "Estimated size: {0} megabytes"; static readonly string format = "Estimated size: {0} megabytes";
static FastColour clearCol = new FastColour( 12, 12, 12 );
void Draw( IDrawer2D drawer ) { void Draw() {
widgetIndex = 0; widgetIndex = 0;
FilterArea( 0, 0, game.Width, game.Height, 100, 0 ); drawer.Clear( clearCol );
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 ?
String.Format( format, ResourceFetcher.EstimateDownloadSize().ToString( "F2" ) ) String.Format( format, ResourceFetcher.EstimateDownloadSize().ToString( "F2" ) )
: (widgets[0] as LauncherTextWidget).Text; : (widgets[0] as LauncherTextWidget).Text;
MakeTextAt( drawer, statusFont, text, 0, 5 ); MakeTextAt( statusFont, text, 0, 5 );
if( fetcher == null ) { if( fetcher == null ) {
MakeTextAt( drawer, infoFont, mainText, 0, -30 ); MakeTextAt( infoFont, mainText, 0, -30 );
MakeButtonAt( drawer, "Yes", 60, 30, -50, 40, DownloadResources ); MakeButtonAt( "Yes", 60, 30, -50, 40, DownloadResources );
MakeButtonAt( drawer, "No", 60, 30, 50, 40, MakeButtonAt( "No", 60, 30, 50, 40,
() => game.SetScreen( new MainScreen( game ) ) ); (x, y) => game.SetScreen( new MainScreen( game ) ) );
} else { } else {
MakeButtonAt( drawer, "Dismiss", 120, 30, 0, 40, MakeButtonAt( "Dismiss", 120, 30, 0, 40,
() => game.SetScreen( new MainScreen( game ) ) ); (x, y) => game.SetScreen( new MainScreen( game ) ) );
widgets[2] = null; widgets[2] = null;
widgets[3] = null; widgets[3] = null;
} }
@ -105,26 +105,26 @@ namespace Launcher2 {
void SetStatus( string text ) { void SetStatus( string text ) {
LauncherTextWidget widget = widgets[0] as LauncherTextWidget; LauncherTextWidget widget = widgets[0] as LauncherTextWidget;
using( IDrawer2D drawer = game.Drawer ) { using( drawer ) {
drawer.SetBitmap( game.Framebuffer ); drawer.SetBitmap( game.Framebuffer );
drawer.Clear( backCol, widget.X, widget.Y, widget.Width, widget.Height ); drawer.Clear( backCol, widget.X, widget.Y, widget.Width, widget.Height );
widget.Redraw( game.Drawer, text, statusFont ); widget.Redraw( drawer, text, statusFont );
Dirty = true; Dirty = true;
} }
} }
void MakeButtonAt( IDrawer2D drawer, string text, int width, void MakeButtonAt( string text, int width,
int height, int x, int y, Action onClick ) { int height, int x, int y, Action<int, int> onClick ) {
LauncherButtonWidget widget = new LauncherButtonWidget( game ); LauncherButtonWidget widget = new LauncherButtonWidget( game );
widget.Text = text; widget.Text = text;
widget.OnClick = onClick; widget.OnClick = onClick;
widget.Active = false;
widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.Centre, width, height, x, y ); widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.Centre, width, height, x, y );
FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180, backColBGRA );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;
} }
void MakeTextAt( IDrawer2D drawer, Font font, string text, int x, int y ) { void MakeTextAt( Font font, string text, int x, int y ) {
LauncherTextWidget widget = new LauncherTextWidget( game, text ); LauncherTextWidget widget = new LauncherTextWidget( game, text );
widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y ); widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y );
widgets[widgetIndex++] = widget; widgets[widgetIndex++] = widget;

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using ClassicalSharp;
namespace Launcher2 {
public partial class LauncherTableWidget : LauncherWidget {
NameComparer nameComp = new NameComparer();
PlayersComparer playerComp = new PlayersComparer();
public bool DraggingWidth = false;
void HandleOnClick( int mouseX, int mouseY ) {
if( mouseX >= Window.Width - 10 ) {
ScrollbarClick( mouseY ); return;
}
if( mouseY >= HeaderStartY && mouseY < HeaderEndY ) {
if( mouseX < ColumnWidths[0] - 10 ) {
nameComp.Invert = !nameComp.Invert;
Array.Sort( usedEntries, 0, Count, nameComp );
Array.Sort( entries, 0, entries.Length, nameComp );
NeedRedraw();
} else if( mouseX > ColumnWidths[0] + 10 ) {
playerComp.Invert = !playerComp.Invert;
Array.Sort( usedEntries, 0, Count, playerComp );
Array.Sort( entries, 0, entries.Length, playerComp );
NeedRedraw();
} else {
DraggingWidth = true;
}
} else {
for( int i = 0; i < Count; i++ ) {
TableEntry entry = usedEntries[i];
if( mouseY >= entry.Y && mouseY < entry.Y + entry.Height ) {
SelectedChanged( entry.Hash );
break;
}
}
}
}
public void MouseMove( int deltaX, int deltaY ) {
if( DraggingWidth ) {
ColumnWidths[0] += deltaX;
Utils.Clamp( ref ColumnWidths[0], 20, Window.Width - 20 );
NeedRedraw();
}
}
void ScrollbarClick( int mouseY ) {
mouseY -= Y;
float scale = (Window.Height - 10) / (float)Count;
int currentIndex = (int)(mouseY / scale);
CurrentIndex = currentIndex;
NeedRedraw();
}
}
}

View File

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using ClassicalSharp;
namespace Launcher2 {
public partial class LauncherTableWidget : LauncherWidget {
public LauncherTableWidget( LauncherWindow window ) : base( window ) {
OnClick = HandleOnClick;
}
public Action NeedRedraw;
public Action<string> SelectedChanged;
TableEntry[] entries, usedEntries;
public void SetEntries( List<ServerListEntry> servers ) {
entries = new TableEntry[servers.Count];
usedEntries = new TableEntry[servers.Count];
int index = 0;
foreach( ServerListEntry e in servers ) {
TableEntry tableEntry = default( TableEntry );
tableEntry.Hash = e.Hash;
tableEntry.Name = e.Name;
tableEntry.Players = e.Players + "/" + e.MaximumPlayers;
entries[index] = tableEntry;
usedEntries[index] = tableEntry;
index++;
}
Count = entries.Length;
}
public void FilterEntries( string filter ) {
Count = 0;
int index = 0;
for( int i = 0; i < entries.Length; i++ ) {
TableEntry entry = entries[i];
if( entry.Name.IndexOf( filter, StringComparison.OrdinalIgnoreCase ) >= 0 ) {
Count++;
usedEntries[index++] = entry;
}
entries[i] = entry;
}
}
public int CurrentIndex, Count;
public int[] ColumnWidths = { 350, 100 };
struct TableEntry {
public string Hash, Name, Players;
public int Y, Height;
}
public void DrawAt( IDrawer2D drawer, Font font, Font titleFont,
Anchor horAnchor, Anchor verAnchor, int x, int y ) {
CalculateOffset( x, y, horAnchor, verAnchor );
Redraw( drawer, font, titleFont );
}
static FastColour backCol = new FastColour( 120, 85, 151 ), foreCol = new FastColour( 160, 133, 186 );
static FastColour scrollCol = new FastColour( 200, 184, 216 );
public void Redraw( IDrawer2D drawer, Font font, Font titleFont ) {
Utils.Clamp( ref ColumnWidths[0], 20, Window.Width - 20 );
int x = X + 5;
DrawGrid( drawer, font, titleFont );
x += DrawColumn( drawer, true, font, titleFont, "Name", ColumnWidths[0], x, e => e.Name ) + 5;
x += DrawColumn( drawer, false, font, titleFont, "Players", ColumnWidths[1], x, e => e.Players ) + 5;
Width = Window.Width;
DrawScrollbar( drawer );
}
int DrawColumn( IDrawer2D drawer, bool separator, Font font, Font titleFont,
string header, int maxWidth, int x, Func<TableEntry, string> filter ) {
int y = Y + 10;
DrawTextArgs args = new DrawTextArgs( header, titleFont, true );
TableEntry headerEntry = default( TableEntry );
DrawColumnEntry( drawer, ref args, maxWidth, x, ref y, ref headerEntry );
MaxIndex = Count;
for( int i = CurrentIndex; i < Count; i++ ) {
args = new DrawTextArgs( filter( usedEntries[i] ), font, true );
if( !DrawColumnEntry( drawer, ref args, maxWidth, x, ref y, ref usedEntries[i] ) ) {
MaxIndex = i;
break;
}
}
Height = Window.Height - Y;
if( separator )
drawer.DrawRect( foreCol, x + maxWidth + 2, Y + 2, 3, Height );
return maxWidth + 5;
}
bool DrawColumnEntry( IDrawer2D drawer, ref DrawTextArgs args,
int maxWidth, int x, ref int y, ref TableEntry entry ) {
Size size = drawer.MeasureSize( ref args );
if( y + size.Height > Window.Height ) {
y = Window.Height + 5; return false;
}
size.Width = Math.Min( maxWidth, size.Width );
entry.Y = y; entry.Height = size.Height;
args.SkipPartsCheck = false;
drawer.DrawClippedText( ref args, x, y, maxWidth, 30 );
y += size.Height + 5;
return true;
}
int HeaderStartY, HeaderEndY;
void DrawGrid( IDrawer2D drawer, Font font, Font titleFont ) {
DrawTextArgs args = new DrawTextArgs( "I", titleFont, true );
Size size = drawer.MeasureSize( ref args );
drawer.DrawRect( foreCol, 0, Y, Window.Width, 5 );
drawer.DrawRect( foreCol, 0, Y + size.Height + 10, Window.Width, 3 );
HeaderStartY = Y;
HeaderEndY = Y + size.Height + 10;
args = new DrawTextArgs( "I", font, true );
int y = Y + size.Height + 10;
size = drawer.MeasureSize( ref args );
for( ; ; ) {
if( y + size.Height > Window.Height ) break;
drawer.DrawRect( foreCol, 0, y, Window.Width, 1 );
y += size.Height + 5;
}
}
int MaxIndex;
void DrawScrollbar( IDrawer2D drawer ) {
drawer.DrawRect( backCol, Window.Width - 10, Y, 10, Window.Height - Y );
float scale = (Window.Height - 10 - Y) / (float)Count;
int y1 = (int)(Y + CurrentIndex * scale);
int height = (int)((MaxIndex - CurrentIndex) * scale);
drawer.DrawRect( scrollCol, Window.Width - 10, y1, 10, height );
}
class NameComparer : IComparer<TableEntry> {
public bool Invert = false;
public int Compare( TableEntry a, TableEntry b ) {
StringComparison comparison = StringComparison.CurrentCultureIgnoreCase;
int value = String.Compare( a.Name, b.Name, comparison );
return Invert ? -value : value;
}
}
class PlayersComparer : IComparer<TableEntry> {
public bool Invert = false;
public int Compare( TableEntry a, TableEntry b ) {
long valX = Int64.Parse( a.Players.Substring( 0, a.Players.IndexOf( '/' ) ) );
long valY = Int64.Parse( b.Players.Substring( 0, b.Players.IndexOf( '/' ) ) );
int value = valX.CompareTo( valY );
return Invert ? -value : value;
}
}
}
}

View File

@ -9,11 +9,13 @@ namespace Launcher2 {
public int ButtonWidth, ButtonHeight; public int ButtonWidth, ButtonHeight;
public string Text; public string Text;
public bool Shadow = true; public bool Shadow = true;
public bool Active = false;
public LauncherButtonWidget( LauncherWindow window ) : base( window ) { public LauncherButtonWidget( LauncherWindow window ) : base( window ) {
} }
static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); static FastColour boxCol = new FastColour( 119, 100, 135 ), shadowCol = new FastColour( 68, 57, 77 ),
boxColActive = new FastColour( 169, 143, 192 ), shadowColActive = new FastColour( 97, 81, 110 );
public void DrawAt( IDrawer2D drawer, string text, Font font, Anchor horAnchor, public void DrawAt( IDrawer2D drawer, string text, Font font, Anchor horAnchor,
Anchor verAnchor, int width, int height, int x, int y ) { Anchor verAnchor, int width, int height, int x, int y ) {
ButtonWidth = width; ButtonHeight = height; ButtonWidth = width; ButtonHeight = height;
@ -23,15 +25,18 @@ namespace Launcher2 {
} }
public void Redraw( IDrawer2D drawer, string text, Font font ) { public void Redraw( IDrawer2D drawer, string text, Font font ) {
if( !Active )
text = "&7" + Text;
DrawTextArgs args = new DrawTextArgs( text, font, true ); DrawTextArgs args = new DrawTextArgs( text, font, true );
Size size = drawer.MeasureSize( ref args ); Size size = drawer.MeasureSize( ref args );
int width = ButtonWidth, height = ButtonHeight; int width = ButtonWidth, height = ButtonHeight;
int xOffset = width - size.Width, yOffset = height - size.Height; int xOffset = width - size.Width, yOffset = height - size.Height;
if( Shadow ) if( Shadow )
drawer.DrawRoundedRect( shadowCol, 3, X + IDrawer2D.Offset, drawer.DrawRoundedRect( Active ? shadowColActive : shadowCol,
Y + IDrawer2D.Offset, width, height ); 3, X + IDrawer2D.Offset, Y + IDrawer2D.Offset, width, height );
drawer.DrawRoundedRect( boxCol, 3, X, Y, width, height ); drawer.DrawRoundedRect( Active ? boxColActive : boxCol,
3, X, Y, width, height );
args.SkipPartsCheck = true; args.SkipPartsCheck = true;
drawer.DrawText( ref args, X + 1 + xOffset / 2, Y + 1 + yOffset / 2 ); drawer.DrawText( ref args, X + 1 + xOffset / 2, Y + 1 + yOffset / 2 );

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using ClassicalSharp;
namespace Launcher2 {
public class LauncherTableWidget : LauncherWidget {
public LauncherTableWidget( LauncherWindow window ) : base( window ) {
}
public List<ServerListEntry> Entries;
public int[] ColumnWidths = { 300, 50, 50, 50, };
public void Display( IDrawer2D drawer, Font font ) {
int y = 0;
for( int i = 0; i < 10; i++ ) {
ServerListEntry entry = Entries[i];
//Size size = drawer.MeasureSize( entry.Name, font, true );
//DrawTextArgs args = new DrawTextArgs( entry.Name, true );
//drawer.DrawText(
}
}
}
}

View File

@ -7,7 +7,7 @@ namespace Launcher2 {
public int X, Y, Width, Height; public int X, Y, Width, Height;
public LauncherWindow Window; public LauncherWindow Window;
public Action OnClick; public Action<int, int> OnClick;
public LauncherWidget( LauncherWindow window ) { public LauncherWidget( LauncherWindow window ) {
Window = window; Window = window;

View File

@ -58,8 +58,9 @@
<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\TableWidget\LauncherTableWidget.cs" />
<Compile Include="Gui\TableWidget\LauncherTableWidget.Input.cs" />
<Compile Include="Gui\Widgets\LauncherButtonWidget.cs" /> <Compile Include="Gui\Widgets\LauncherButtonWidget.cs" />
<Compile Include="Gui\Widgets\LauncherTableWidget.cs" />
<Compile Include="Gui\Widgets\LauncherTextInputWidget.cs" /> <Compile Include="Gui\Widgets\LauncherTextInputWidget.cs" />
<Compile Include="Gui\Widgets\LauncherTextWidget.cs" /> <Compile Include="Gui\Widgets\LauncherTextWidget.cs" />
<Compile Include="Gui\Widgets\LauncherWidget.cs" /> <Compile Include="Gui\Widgets\LauncherWidget.cs" />
@ -88,6 +89,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Gui" /> <Folder Include="Gui" />
<Folder Include="Gui\TableWidget" />
<Folder Include="Gui\Screens" /> <Folder Include="Gui\Screens" />
<Folder Include="Gui\Widgets" /> <Folder Include="Gui\Widgets" />
<Folder Include="Patcher" /> <Folder Include="Patcher" />

View File

@ -19,7 +19,6 @@ namespace Launcher2 {
public LauncherScreen screen; public LauncherScreen screen;
public bool Dirty; public bool Dirty;
public ClassicubeSession Session = new ClassicubeSession(); public ClassicubeSession Session = new ClassicubeSession();
public List<ServerListEntry> Servers = new List<ServerListEntry>();
public AsyncDownloader Downloader; public AsyncDownloader Downloader;
public int Width { get { return Window.Width; } } public int Width { get { return Window.Width; } }
@ -72,7 +71,7 @@ namespace Launcher2 {
if( !Window.Exists ) break; if( !Window.Exists ) break;
screen.Tick(); screen.Tick();
if( Dirty || (screen != null && screen.Dirty) ) if( Dirty || screen.Dirty )
Display(); Display();
Thread.Sleep( 1 ); Thread.Sleep( 1 );
} }

View File

@ -15,7 +15,7 @@ namespace Launcher2 {
public void DownloadItems( Action<string> setStatus ) { public void DownloadItems( Action<string> setStatus ) {
downloader.DownloadData( "http://s3.amazonaws.com/Minecraft.Download/versions/c0.30_01c/c0.30_01c.jar", false, "classic_jar" ); downloader.DownloadData( "http://s3.amazonaws.com/Minecraft.Download/versions/c0.30_01c/c0.30_01c.jar", false, "classic_jar" );
downloader.DownloadData( "http://s3.amazonaws.com/Minecraft.Download/versions/1.6.2/1.6.2.jar", false, "162_jar" ); downloader.DownloadData( "http://s3.amazonaws.com/Minecraft.Download/versions/1.6.2/1.6.2.jar", false, "162_jar" );
downloader.DownloadData( "http://static.classicube.net/terrain-patch.gpng", false, "terrain_patch" ); downloader.DownloadData( "http://static.classicube.net/terrain-patch.png", false, "terrain_patch" );
setStatus( "&eFetching classic jar.. (1/3)" ); setStatus( "&eFetching classic jar.. (1/3)" );
} }

View File

@ -3,6 +3,7 @@ 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 {
@ -15,13 +16,61 @@ namespace Launcher2 {
cookies = new CookieContainer(); cookies = new CookieContainer();
} }
public bool Working;
public WebException Exception;
public string Status;
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.LoginAsync";
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 Finish( bool success, WebException ex, string status ) {
if( !success )
Username = null;
Working = false;
Exception = ex;
Status = status;
}
public abstract void Login( string user, string password ); public abstract void Login( string user, string password );
public abstract GameStartData GetConnectInfo( string hash ); public abstract GameStartData GetConnectInfo( string hash );
public abstract List<ServerListEntry> GetPublicServers(); public abstract List<ServerListEntry> GetPublicServers();
CookieContainer cookies = new CookieContainer(); CookieContainer cookies = new CookieContainer();
protected HttpWebResponse MakeRequest( string uri, string referer, string data ) { protected HttpWebResponse MakeRequest( string uri, string referer, string data ) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create( uri ); HttpWebRequest request = (HttpWebRequest)WebRequest.Create( uri );
@ -31,6 +80,7 @@ namespace Launcher2 {
request.Referer = referer; request.Referer = referer;
request.KeepAlive = true; request.KeepAlive = true;
request.CookieContainer = cookies; request.CookieContainer = cookies;
// On my machine, these reduce minecraft server list download time from 40 seconds to 4. // On my machine, these reduce minecraft server list download time from 40 seconds to 4.
request.Proxy = null; request.Proxy = null;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
@ -60,7 +110,7 @@ namespace Launcher2 {
using( Stream stream = response.GetResponseStream() ) { using( Stream stream = response.GetResponseStream() ) {
using( StreamReader reader = new StreamReader( stream ) ) { using( StreamReader reader = new StreamReader( stream ) ) {
string line; string line;
while( ( line = reader.ReadLine() ) != null ) { while( (line = reader.ReadLine()) != null ) {
yield return line; yield return line;
} }
} }