diff --git a/ClassicalSharp/2D/Drawing/GdiPlusDrawer2D.cs b/ClassicalSharp/2D/Drawing/GdiPlusDrawer2D.cs index b18527ff9..d0fbe168c 100644 --- a/ClassicalSharp/2D/Drawing/GdiPlusDrawer2D.cs +++ b/ClassicalSharp/2D/Drawing/GdiPlusDrawer2D.cs @@ -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 ) { Brush brush = GetOrCreateBrush( colour ); g.FillRectangle( brush, x, y, width, height ); diff --git a/ClassicalSharp/2D/Drawing/IDrawer2D.cs b/ClassicalSharp/2D/Drawing/IDrawer2D.cs index e9d863ea8..b670a4dd7 100644 --- a/ClassicalSharp/2D/Drawing/IDrawer2D.cs +++ b/ClassicalSharp/2D/Drawing/IDrawer2D.cs @@ -20,6 +20,10 @@ namespace ClassicalSharp { /// specified coordinates in the currently bound bitmap. public abstract void DrawText( ref DrawTextArgs args, float x, float y ); + /// Draws a string using the specified arguments and fonts at the + /// specified coordinates in the currently bound bitmap, clipping if necessary. + public abstract void DrawClippedText( ref DrawTextArgs args, float x, float y, float maxWidth, float maxHeight ); + /// Draws a 2D flat rectangle of the specified dimensions at the /// specified coordinates in the currently bound bitmap. public abstract void DrawRect( Color colour, int x, int y, int width, int height ); diff --git a/ClassicalSharp/2D/IsometricBlockDrawer.cs b/ClassicalSharp/2D/IsometricBlockDrawer.cs index 55a02413b..d705aa0a3 100644 --- a/ClassicalSharp/2D/IsometricBlockDrawer.cs +++ b/ClassicalSharp/2D/IsometricBlockDrawer.cs @@ -105,13 +105,13 @@ namespace ClassicalSharp { FastColour col = colXSide; 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, - 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, - 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, - pos.Z + scale, rec.U2, rec.V2, colNormal ); + pos.Z + scale, rec.U2, rec.V2, col ); } } } \ No newline at end of file diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index ea1d1f1b4..4fd9750c4 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -123,8 +123,6 @@ namespace ClassicalSharp { } if( jumping ) { - Vector3I p = Vector3I.Floor( Position ); - if( TouchesAnyWater() || TouchesAnyLava() ) { BoundingBox bounds = CollisionBounds; bounds.Min.Y += 1; diff --git a/ClassicalSharp/Network/Utils/AsyncDownloader.cs b/ClassicalSharp/Network/Utils/AsyncDownloader.cs index 69c0d361a..8819ddc2f 100644 --- a/ClassicalSharp/Network/Utils/AsyncDownloader.cs +++ b/ClassicalSharp/Network/Utils/AsyncDownloader.cs @@ -13,7 +13,7 @@ namespace ClassicalSharp.Network { EventWaitHandle handle = new EventWaitHandle( false, EventResetMode.AutoReset ); Thread worker; readonly object requestLocker = new object(); - List requests = new List(); + List requests = new List(); readonly object downloadedLocker = new object(); Dictionary downloaded = new Dictionary(); string skinServer = null; @@ -50,7 +50,7 @@ namespace ClassicalSharp.Network { void AddRequest( string url, bool priority, string identifier, byte type ) { lock( requestLocker ) { - DownloadRequest request = new DownloadRequest( url, identifier, type ); + Request request = new Request( url, identifier, type ); if( priority ) { requests.Insert( 0, request ); } else { @@ -109,7 +109,7 @@ namespace ClassicalSharp.Network { WebClient client; void DownloadThreadWorker() { while( true ) { - DownloadRequest request = null; + Request request = null; lock( requestLocker ) { if( requests.Count > 0 ) { request = requests[0]; @@ -126,7 +126,7 @@ namespace ClassicalSharp.Network { } } - void DownloadItem( DownloadRequest request ) { + void DownloadItem( Request request ) { string url = request.Url; byte type = request.Type; 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 Identifier; public byte Type; // 0 = bitmap, 1 = string, 2 = byte[] public DateTime TimeAdded; - public DownloadRequest( string url, string identifier, byte type ) { + public Request( string url, string identifier, byte type ) { Url = url; Identifier = identifier; Type = type; diff --git a/ClassicalSharp/Rendering/MapEnvRenderer.cs b/ClassicalSharp/Rendering/MapEnvRenderer.cs index 4905f6acc..84e768f34 100644 --- a/ClassicalSharp/Rendering/MapEnvRenderer.cs +++ b/ClassicalSharp/Rendering/MapEnvRenderer.cs @@ -43,6 +43,7 @@ namespace ClassicalSharp { public void Render( double deltaTime ) { if( sidesVb == -1 || edgesVb == -1 ) return; graphics.Texturing = true; + graphics.AlphaTest = true; graphics.BindTexture( sideTexId ); graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b ); graphics.BindVb( sidesVb ); @@ -60,6 +61,7 @@ namespace ClassicalSharp { } graphics.AlphaBlending = false; graphics.Texturing = false; + graphics.AlphaTest = false; } public void Dispose() { diff --git a/Launcher2/Gui/Screens/ClassiCubeScreen.cs b/Launcher2/Gui/Screens/ClassiCubeScreen.cs index fd9b72607..494ebc894 100644 --- a/Launcher2/Gui/Screens/ClassiCubeScreen.cs +++ b/Launcher2/Gui/Screens/ClassiCubeScreen.cs @@ -15,18 +15,34 @@ namespace Launcher2 { titleFont = new Font( "Arial", 15, FontStyle.Bold ); inputFont = new Font( "Arial", 15, FontStyle.Regular ); enterIndex = 4; - widgets = new LauncherWidget[7]; + widgets = new LauncherWidget[8]; } public override void Init() { Resize(); - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); LoadSavedInfo( drawer ); } } 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 ) { @@ -45,31 +61,36 @@ namespace Launcher2 { } public override void Resize() { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - Draw( drawer ); + Draw(); } Dirty = true; } - - static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); - void Draw( IDrawer2D drawer ) { + + void Draw() { widgetIndex = 0; - MakeTextAt( drawer, "Username", -180, -100 ); - MakeTextAt( drawer, "Password", -180, -50 ); + MakeTextAt( "Username", -180, -100 ); + MakeTextAt( "Password", -180, -50 ); - MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, -100 ); - MakeTextInputAt( drawer, true, Get( widgetIndex ), 30, -50 ); + MakeTextInputAt( false, Get( widgetIndex ), 30, -100 ); + MakeTextInputAt( true, Get( widgetIndex ), 30, -50 ); - MakeButtonAt( drawer, "Sign in", 90, 35, -75, 0, StartClient ); - MakeButtonAt( drawer, "Back", 80, 35, 140, 0, () => game.SetScreen( new MainScreen( game ) ) ); - MakeTextAt( drawer, "", 0, 50 ); + MakeButtonAt( "Sign in", 90, 35, -75, 0, StartClient ); + MakeButtonAt( "Back", 80, 35, 140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) ); + MakeTextAt( "", 0, 50 ); + + if( HasServers && !signingIn ) + MakeButtonAt( "Servers", 90, 35, 35, 0, ShowServers ); } + string lastStatus; void SetStatus( string text ) { - using( IDrawer2D drawer = game.Drawer ) { + lastStatus = text; + using( 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, 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 ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); 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 ); widget.OnClick = InputClick; widget.Password = password; @@ -92,52 +113,46 @@ namespace Launcher2 { widgets[widgetIndex++] = widget; } - void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, - int x, int y, Action onClick ) { + void MakeButtonAt( string text, int width, int height, + int x, int y, Action 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 ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); 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 ) ) ) { 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 ) ); + if( signingIn ) return; + + 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; - 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 { - game.Servers = session.GetPublicServers(); - } catch( WebException ex ) { - game.Servers = new List(); - DisplayWebException( ex, "retrieve servers list" ); - return; - } - SetStatus( "&eSigned in" ); + if( !HasServers ) return; + game.SetScreen( new ClassiCubeServersScreen( game ) ); } void DisplayWebException( WebException ex, string action ) { diff --git a/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs b/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs index 3f530e968..4b8cae1e6 100644 --- a/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs +++ b/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs @@ -1,230 +1,168 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.IO; using System.Net; using ClassicalSharp; -using OpenTK; using OpenTK.Input; namespace Launcher2 { - public sealed class ClassiCubeServersScreen : LauncherScreen { + public sealed class ClassiCubeServersScreen : LauncherInputScreen { + const int tableIndex = 6; public ClassiCubeServersScreen( LauncherWindow game ) : base( game ) { - textFont = new Font( "Arial", 16, FontStyle.Bold ); - widgets = new LauncherWidget[5]; - game.Window.Mouse.Move += MouseMove; - game.Window.Mouse.ButtonDown += MouseButtonDown; + titleFont = new Font( "Arial", 16, FontStyle.Bold ); + inputFont = new Font( "Arial", 13, FontStyle.Regular ); + enterIndex = 4; - game.Window.KeyPress += KeyPress; - game.Window.Keyboard.KeyDown += KeyDown; - game.Window.Keyboard.KeyRepeat = true; + widgets = new LauncherWidget[7]; + game.Window.Mouse.WheelChanged += MouseWheelChanged; + game.Window.Mouse.ButtonUp += MouseButtonUp; } public override void Tick() { } - - void KeyDown( object sender, KeyboardKeyEventArgs e ) { - if( lastInput != null && e.Key == Key.BackSpace ) { - using( IDrawer2D drawer = game.Drawer ) { - drawer.SetBitmap( game.Framebuffer ); - lastInput.RemoveChar( textFont ); - Dirty = true; - } - } else if( e.Key == Key.Enter ) { // Click sign in button - LauncherWidget widget = widgets[4]; - if( widget.OnClick != null ) - widget.OnClick(); + + protected override void MouseMove( object sender, MouseMoveEventArgs e ) { + base.MouseMove( sender, e ); + if( selectedWidget != null && selectedWidget == widgets[tableIndex] ) { + LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + table.MouseMove( e.XDelta, e.YDelta ); } } - - void KeyPress( object sender, KeyPressEventArgs e ) { - if( lastInput != null ) { - using( IDrawer2D drawer = game.Drawer ) { - drawer.SetBitmap( game.Framebuffer ); - lastInput.AddChar( e.KeyChar, textFont ); - Dirty = true; - } + + void MouseButtonUp( object sender, MouseButtonEventArgs e ) { + LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + table.DraggingWidth = false; + } + + 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 Resize() { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); drawer.Clear( LauncherWindow.clearColour ); - DrawButtons( drawer ); + Draw(); } Dirty = true; } - Font textFont; - static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); - void DrawButtons( IDrawer2D drawer ) { + void Draw() { widgetIndex = 0; - MakeTextAt( drawer, "Search", -180, 0 ); - MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, 0 ); + int lastIndex = GetLastInputIndex(); - MakeTextAt( drawer, "classicube.net/server/play/", -320, 50 ); - MakeTextInputAt( drawer, false, Get( widgetIndex ), 30, 50 ); + MakeTextAt( titleFont, "Search", -200, 10 ); + 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(); - List servers = new List(); - void StartClient() { - 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(); - 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; - } + int GetLastInputIndex() { + return lastInput == null ? -1 : + Array.IndexOf( widgets, lastInput ); } - void MakeTextAt( IDrawer2D drawer, string text, int x, int y ) { - LauncherTextWidget widget = new LauncherTextWidget( game, text ); - widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.LeftOrTop, x, y ); + void MakeTextAt( Font font, string text, int x, int y ) { + LauncherTextWidget widget = new LauncherTextWidget( game, text ); + widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.LeftOrTop, x, y ); 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 ); 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; } - void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, - int x, int y, Action onClick ) { + void MakeButtonAt( string text, int width, int height, + int x, int y, Action onClick ) { LauncherButtonWidget widget = new LauncherButtonWidget( game ); widget.Text = text; widget.OnClick = onClick; - widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.LeftOrTop, width, height, x, y ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); + widget.Active = false; + widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.LeftOrTop, width, height, x, y ); widgets[widgetIndex++] = widget; } - protected override void UnselectWidget( LauncherWidget widget ) { - LauncherButtonWidget button = widget as LauncherButtonWidget; - if( button != null ) { - button.Redraw( game.Drawer, button.Text, textFont ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); - Dirty = true; + void MakeTableWidget() { + if( widgets[tableIndex] != null ) { + LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + table.Redraw( drawer, inputFont, titleFont ); + return; } + + 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 ) { - LauncherButtonWidget button = widget as LauncherButtonWidget; - 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 ) { + + void SelectedChanged( string hash ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - if( lastInput != null ) { - lastInput.Active = false; - lastInput.Redraw( game.Drawer, lastInput.Text, textFont ); - } - - input.Active = true; - input.Redraw( game.Drawer, input.Text, textFont ); + Set( 3, hash ); } - lastInput = input; Dirty = true; } - public override void Dispose() { - textFont.Dispose(); - game.Window.Mouse.Move -= MouseMove; - game.Window.Mouse.ButtonDown -= MouseButtonDown; - - game.Window.KeyPress -= KeyPress; - game.Window.Keyboard.KeyDown -= KeyDown; - game.Window.Keyboard.KeyRepeat = false; + void ConnectToServer( int mouseX, int mouseY ) { + GameStartData data = null; + try { + data = game.Session.GetConnectInfo( Get( 3 ) ); + } catch( WebException ex ) { + Program.LogException( ex ); + return; + } + Client.Start( data, true ); } - void DisplayWebException( WebException ex, string action ) { - Program.LogException( ex ); - if( ex.Status == WebExceptionStatus.Timeout ) { - string text = "&eFailed to " + action + ":" + - Environment.NewLine + "Timed out while connecting to classicube.net."; - SetStatus( text ); - } else if( ex.Status == WebExceptionStatus.ProtocolError ) { - HttpWebResponse response = (HttpWebResponse)ex.Response; - int errorCode = (int)response.StatusCode; - string description = response.StatusDescription; - string text = "&eFailed to " + action + ":" + - Environment.NewLine + " classicube.net returned: (" + errorCode + ") " + description; - SetStatus(text ); - } else if( ex.Status == WebExceptionStatus.NameResolutionFailure ) { - string text = "&eFailed to " + action + ":" + - Environment.NewLine + "Unable to resolve classicube.net" + - Environment.NewLine + "you may not be connected to the internet."; - SetStatus( text ); - } else { - string text = "&eFailed to " + action + ":" + - Environment.NewLine + ex.Status; - SetStatus( text ); - } + void MouseWheelChanged( object sender, MouseWheelEventArgs e ) { + LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + table.CurrentIndex -= e.Delta; + ClampIndex(); + Resize(); + } + + void ClampIndex() { + LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + if( table.CurrentIndex >= table.Count ) + table.CurrentIndex = table.Count - 1; + if( table.CurrentIndex < 0 ) + table.CurrentIndex = 0; + } + + public override void Dispose() { + base.Dispose(); + game.Window.Mouse.WheelChanged -= MouseWheelChanged; } } } diff --git a/Launcher2/Gui/Screens/DirectConnectScreen.cs b/Launcher2/Gui/Screens/DirectConnectScreen.cs index 70ee5e60e..8465e437f 100644 --- a/Launcher2/Gui/Screens/DirectConnectScreen.cs +++ b/Launcher2/Gui/Screens/DirectConnectScreen.cs @@ -19,7 +19,7 @@ namespace Launcher2 { public override void Init() { Resize(); - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); LoadSavedInfo( drawer ); } @@ -53,31 +53,30 @@ namespace Launcher2 { } public override void Resize() { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - Draw( drawer ); + Draw(); } Dirty = true; } - static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); - void Draw( IDrawer2D drawer ) { + void Draw() { widgetIndex = 0; - MakeTextAt( drawer, "Username", -180, -100 ); - MakeTextAt( drawer, "Address", -180, -50 ); - MakeTextAt( drawer, "Mppass", -180, 0 ); + MakeTextAt( "Username", -180, -100 ); + MakeTextAt( "Address", -180, -50 ); + MakeTextAt( "Mppass", -180, 0 ); - MakeTextInputAt( drawer, Get( widgetIndex ), 30, -100 ); - MakeTextInputAt( drawer, Get( widgetIndex ), 30, -50 ); - MakeTextInputAt( drawer, Get( widgetIndex ), 30, 0 ); + MakeTextInputAt( Get( widgetIndex ), 30, -100 ); + MakeTextInputAt( Get( widgetIndex ), 30, -50 ); + MakeTextInputAt( Get( widgetIndex ), 30, 0 ); - MakeButtonAt( drawer, "Connect", 110, 35, -65, 50, StartClient ); - MakeButtonAt( drawer, "Back", 80, 35, 140, 50, () => game.SetScreen( new MainScreen( game ) ) ); - MakeTextAt( drawer, "", 0, 100 ); + MakeButtonAt( "Connect", 110, 35, -65, 50, StartClient ); + MakeButtonAt( "Back", 80, 35, 140, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) ); + MakeTextAt( "", 0, 100 ); } void SetStatus( string text ) { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); LauncherTextWidget widget = (LauncherTextWidget)widgets[8]; 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 ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); 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 ); widget.OnClick = InputClick; @@ -101,18 +100,18 @@ namespace Launcher2 { widgets[widgetIndex++] = widget; } - void MakeButtonAt( IDrawer2D drawer, string text, int width, int height, - int x, int y, Action onClick ) { + void MakeButtonAt( string text, int width, int height, + int x, int y, Action 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 ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); widgets[widgetIndex++] = widget; } - void StartClient() { + void StartClient( int mouseX, int mouseY ) { SetStatus( "" ); if( String.IsNullOrEmpty( Get( 3 ) ) ) { diff --git a/Launcher2/Gui/Screens/LauncherInputScreen.cs b/Launcher2/Gui/Screens/LauncherInputScreen.cs index e629e1385..0bb1b337f 100644 --- a/Launcher2/Gui/Screens/LauncherInputScreen.cs +++ b/Launcher2/Gui/Screens/LauncherInputScreen.cs @@ -24,28 +24,34 @@ namespace Launcher2 { protected void KeyDown( object sender, KeyboardKeyEventArgs e ) { if( lastInput != null && e.Key == Key.BackSpace ) { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - lastInput.RemoveChar( inputFont ); + lastInput.RemoveChar( inputFont ); Dirty = true; } + OnRemovedChar(); } else if( e.Key == Key.Enter && enterIndex >= 0 ) { LauncherWidget widget = widgets[enterIndex]; if( widget.OnClick != null ) - widget.OnClick(); + widget.OnClick( 0, 0 ); } } protected void KeyPress( object sender, KeyPressEventArgs e ) { if( lastInput != null ) { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - lastInput.AddChar( e.KeyChar, inputFont ); + lastInput.AddChar( e.KeyChar, inputFont ); Dirty = true; } + OnAddedChar(); } } + protected virtual void OnAddedChar() { } + + protected virtual void OnRemovedChar() { } + protected string Get( int index ) { LauncherWidget widget = widgets[index]; return widget == null ? "" : ((widget as LauncherTextInputWidget)).Text; @@ -53,14 +59,14 @@ namespace Launcher2 { protected void Set( int index, string text ) { (widgets[index] as LauncherTextInputWidget) - .Redraw( game.Drawer, text, inputFont ); + .Redraw( drawer, text, inputFont ); } protected override void UnselectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; - if( button != null ) { - button.Redraw( game.Drawer, button.Text, titleFont ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); + if( button != null ) { + button.Active = false; + button.Redraw( drawer, button.Text, titleFont ); Dirty = true; } } @@ -68,23 +74,24 @@ namespace Launcher2 { protected override void SelectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; if( button != null ) { - button.Redraw( game.Drawer, button.Text, titleFont ); + button.Active = true; + button.Redraw( drawer, button.Text, titleFont ); Dirty = true; } } protected LauncherTextInputWidget lastInput; - protected void InputClick() { + protected void InputClick( int mouseX, int mouseY ) { LauncherTextInputWidget input = selectedWidget as LauncherTextInputWidget; - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); if( lastInput != null ) { lastInput.Active = false; - lastInput.Redraw( game.Drawer, lastInput.Text, inputFont ); + lastInput.Redraw( drawer, lastInput.Text, inputFont ); } input.Active = true; - input.Redraw( game.Drawer, input.Text, inputFont ); + input.Redraw( drawer, input.Text, inputFont ); } lastInput = input; Dirty = true; diff --git a/Launcher2/Gui/Screens/LauncherScreen.cs b/Launcher2/Gui/Screens/LauncherScreen.cs index d7f263d4a..a57a7579c 100644 --- a/Launcher2/Gui/Screens/LauncherScreen.cs +++ b/Launcher2/Gui/Screens/LauncherScreen.cs @@ -7,12 +7,14 @@ namespace Launcher2 { public abstract class LauncherScreen { protected LauncherWindow game; + protected IDrawer2D drawer; public bool Dirty; protected int widgetIndex; public LauncherScreen( LauncherWindow game ) { this.game = game; + drawer = game.Drawer; } public abstract void Init(); @@ -25,44 +27,9 @@ namespace Launcher2 { /// Cleans up all native resources held by this screen. 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 ); - } - - /// Scales the RGB components of the bitmap in the specified region by the given amount. - /// Pixels with same value as clearColour are left untouched. - 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[] widgets; - protected void MouseMove( object sender, MouseMoveEventArgs e ) { + protected virtual void MouseMove( object sender, MouseMoveEventArgs e ) { for( int i = 0; i < widgets.Length; i++ ) { LauncherWidget widget = widgets[i]; if( widget == null ) continue; @@ -70,7 +37,7 @@ namespace Launcher2 { e.X < widget.X + widget.Width && e.Y < widget.Y + widget.Height ) { if( selectedWidget == widget ) return; - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); if( selectedWidget != null ) UnselectWidget( selectedWidget ); @@ -82,7 +49,7 @@ namespace Launcher2 { } if( selectedWidget == null ) return; - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); UnselectWidget( selectedWidget ); } @@ -101,7 +68,7 @@ namespace Launcher2 { if( e.Button != MouseButton.Left || selectedWidget == null ) return; if( selectedWidget.OnClick != null ) - selectedWidget.OnClick(); + selectedWidget.OnClick( e.X, e.Y ); } } } diff --git a/Launcher2/Gui/Screens/MainScreen.cs b/Launcher2/Gui/Screens/MainScreen.cs index d6b92a76d..4b1c36228 100644 --- a/Launcher2/Gui/Screens/MainScreen.cs +++ b/Launcher2/Gui/Screens/MainScreen.cs @@ -16,14 +16,15 @@ namespace Launcher2 { protected override void UnselectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; - button.Redraw( game.Drawer, button.Text, textFont ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); + button.Active = false; + button.Redraw( drawer, button.Text, textFont ); Dirty = true; } protected override void SelectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; - button.Redraw( game.Drawer, button.Text, textFont ); + button.Active = true; + button.Redraw( drawer, button.Text, textFont ); Dirty = true; } @@ -33,42 +34,41 @@ namespace Launcher2 { } public override void Resize() { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - Draw( drawer ); + Draw(); } Dirty = true; } Font textFont; - static FastColour boxCol = new FastColour( 169, 143, 192 ), shadowCol = new FastColour( 97, 81, 110 ); - void Draw( IDrawer2D drawer ) { + void Draw() { widgetIndex = 0; - MakeButtonAt( drawer, "Direct connect", Anchor.Centre, Anchor.Centre, + MakeButtonAt( "Direct connect", Anchor.Centre, Anchor.Centre, 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, - () => 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, - () => 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 ); } const int buttonWidth = 220, buttonHeight = 35, sideButtonWidth = 150; - void MakeButtonAt( IDrawer2D drawer, string text, Anchor horAnchor, - Anchor verAnchor, int width, int height, int x, int y, Action onClick ) { + void MakeButtonAt( string text, Anchor horAnchor, + Anchor verAnchor, int width, int height, int x, int y, Action onClick ) { LauncherButtonWidget widget = new LauncherButtonWidget( game ); widget.Text = text; widget.OnClick = onClick; + widget.Active = false; widget.DrawAt( drawer, text, textFont, horAnchor, verAnchor, width, height, x, y ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180 ); widgets[widgetIndex++] = widget; } diff --git a/Launcher2/Gui/Screens/ResourcesScreen.cs b/Launcher2/Gui/Screens/ResourcesScreen.cs index fa989a815..4a4c9fadf 100644 --- a/Launcher2/Gui/Screens/ResourcesScreen.cs +++ b/Launcher2/Gui/Screens/ResourcesScreen.cs @@ -32,9 +32,9 @@ namespace Launcher2 { } public override void Resize() { - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - Draw( drawer ); + Draw(); } Dirty = true; } @@ -42,8 +42,8 @@ namespace Launcher2 { protected override void UnselectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; if( button != null ) { - button.Redraw( game.Drawer, button.Text, textFont ); - FilterArea( widget.X, widget.Y, widget.Width, widget.Height, 180, backColBGRA ); + button.Active = false; + button.Redraw( drawer, button.Text, textFont ); Dirty = true; } } @@ -51,13 +51,14 @@ namespace Launcher2 { protected override void SelectWidget( LauncherWidget widget ) { LauncherButtonWidget button = widget as LauncherButtonWidget; if( button != null ) { - button.Redraw( game.Drawer, button.Text, textFont ); + button.Active = true; + button.Redraw( drawer, button.Text, textFont ); Dirty = true; } } ResourceFetcher fetcher; - void DownloadResources() { + void DownloadResources( int mouseX, int mouseY ) { if( game.Downloader == null ) game.Downloader = new AsyncDownloader( "null" ); if( fetcher != null ) return; @@ -66,38 +67,37 @@ namespace Launcher2 { fetcher.DownloadItems( SetStatus ); selectedWidget = null; - game.MakeBackground(); Resize(); } 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 uint backColBGRA = (uint)backCol.ToArgb(); static readonly string mainText = "Some required resources weren't found" + Environment.NewLine + "Okay to download them?"; static readonly string format = "Estimated size: {0} megabytes"; + static FastColour clearCol = new FastColour( 12, 12, 12 ); - void Draw( IDrawer2D drawer ) { + void Draw() { widgetIndex = 0; - FilterArea( 0, 0, game.Width, game.Height, 100, 0 ); + drawer.Clear( clearCol ); drawer.DrawRect( backCol, game.Width / 2 - 175, game.Height / 2 - 70, 175 * 2, 70 * 2 ); string text = widgets[0] == null ? String.Format( format, ResourceFetcher.EstimateDownloadSize().ToString( "F2" ) ) : (widgets[0] as LauncherTextWidget).Text; - MakeTextAt( drawer, statusFont, text, 0, 5 ); + MakeTextAt( statusFont, text, 0, 5 ); if( fetcher == null ) { - MakeTextAt( drawer, infoFont, mainText, 0, -30 ); - MakeButtonAt( drawer, "Yes", 60, 30, -50, 40, DownloadResources ); + MakeTextAt( infoFont, mainText, 0, -30 ); + MakeButtonAt( "Yes", 60, 30, -50, 40, DownloadResources ); - MakeButtonAt( drawer, "No", 60, 30, 50, 40, - () => game.SetScreen( new MainScreen( game ) ) ); + MakeButtonAt( "No", 60, 30, 50, 40, + (x, y) => game.SetScreen( new MainScreen( game ) ) ); } else { - MakeButtonAt( drawer, "Dismiss", 120, 30, 0, 40, - () => game.SetScreen( new MainScreen( game ) ) ); + MakeButtonAt( "Dismiss", 120, 30, 0, 40, + (x, y) => game.SetScreen( new MainScreen( game ) ) ); widgets[2] = null; widgets[3] = null; } @@ -105,26 +105,26 @@ namespace Launcher2 { void SetStatus( string text ) { LauncherTextWidget widget = widgets[0] as LauncherTextWidget; - using( IDrawer2D drawer = game.Drawer ) { + using( drawer ) { drawer.SetBitmap( game.Framebuffer ); drawer.Clear( backCol, widget.X, widget.Y, widget.Width, widget.Height ); - widget.Redraw( game.Drawer, text, statusFont ); + widget.Redraw( drawer, text, statusFont ); Dirty = true; } } - void MakeButtonAt( IDrawer2D drawer, string text, int width, - int height, int x, int y, Action onClick ) { + void MakeButtonAt( string text, int width, + int height, int x, int y, Action onClick ) { LauncherButtonWidget widget = new LauncherButtonWidget( game ); widget.Text = text; widget.OnClick = onClick; + widget.Active = false; 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; } - 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 ); widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y ); widgets[widgetIndex++] = widget; diff --git a/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs b/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs new file mode 100644 index 000000000..03f448ad3 --- /dev/null +++ b/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs @@ -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(); + } + } +} diff --git a/Launcher2/Gui/TableWidget/LauncherTableWidget.cs b/Launcher2/Gui/TableWidget/LauncherTableWidget.cs new file mode 100644 index 000000000..876d13acb --- /dev/null +++ b/Launcher2/Gui/TableWidget/LauncherTableWidget.cs @@ -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 SelectedChanged; + + TableEntry[] entries, usedEntries; + public void SetEntries( List 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 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 { + + 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 { + + 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; + } + } + } +} diff --git a/Launcher2/Gui/Widgets/LauncherButtonWidget.cs b/Launcher2/Gui/Widgets/LauncherButtonWidget.cs index 440211412..4452e648d 100644 --- a/Launcher2/Gui/Widgets/LauncherButtonWidget.cs +++ b/Launcher2/Gui/Widgets/LauncherButtonWidget.cs @@ -9,11 +9,13 @@ namespace Launcher2 { public int ButtonWidth, ButtonHeight; public string Text; public bool Shadow = true; + public bool Active = false; 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, Anchor verAnchor, int width, int height, int x, int y ) { ButtonWidth = width; ButtonHeight = height; @@ -23,15 +25,18 @@ namespace Launcher2 { } public void Redraw( IDrawer2D drawer, string text, Font font ) { + if( !Active ) + text = "&7" + Text; DrawTextArgs args = new DrawTextArgs( text, font, true ); Size size = drawer.MeasureSize( ref args ); int width = ButtonWidth, height = ButtonHeight; int xOffset = width - size.Width, yOffset = height - size.Height; if( Shadow ) - drawer.DrawRoundedRect( shadowCol, 3, X + IDrawer2D.Offset, - Y + IDrawer2D.Offset, width, height ); - drawer.DrawRoundedRect( boxCol, 3, X, Y, width, height ); + drawer.DrawRoundedRect( Active ? shadowColActive : shadowCol, + 3, X + IDrawer2D.Offset, Y + IDrawer2D.Offset, width, height ); + drawer.DrawRoundedRect( Active ? boxColActive : boxCol, + 3, X, Y, width, height ); args.SkipPartsCheck = true; drawer.DrawText( ref args, X + 1 + xOffset / 2, Y + 1 + yOffset / 2 ); diff --git a/Launcher2/Gui/Widgets/LauncherTableWidget.cs b/Launcher2/Gui/Widgets/LauncherTableWidget.cs deleted file mode 100644 index 4ae5ae74c..000000000 --- a/Launcher2/Gui/Widgets/LauncherTableWidget.cs +++ /dev/null @@ -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 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( - } - } - } -} diff --git a/Launcher2/Gui/Widgets/LauncherWidget.cs b/Launcher2/Gui/Widgets/LauncherWidget.cs index 64819dbc0..08d6b403c 100644 --- a/Launcher2/Gui/Widgets/LauncherWidget.cs +++ b/Launcher2/Gui/Widgets/LauncherWidget.cs @@ -7,7 +7,7 @@ namespace Launcher2 { public int X, Y, Width, Height; public LauncherWindow Window; - public Action OnClick; + public Action OnClick; public LauncherWidget( LauncherWindow window ) { Window = window; diff --git a/Launcher2/Launcher2.csproj b/Launcher2/Launcher2.csproj index 95bc12647..34c3aec51 100644 --- a/Launcher2/Launcher2.csproj +++ b/Launcher2/Launcher2.csproj @@ -58,8 +58,9 @@ + + - @@ -88,6 +89,7 @@ + diff --git a/Launcher2/LauncherWindow.cs b/Launcher2/LauncherWindow.cs index b5485ea32..e9b553cd7 100644 --- a/Launcher2/LauncherWindow.cs +++ b/Launcher2/LauncherWindow.cs @@ -19,7 +19,6 @@ namespace Launcher2 { public LauncherScreen screen; public bool Dirty; public ClassicubeSession Session = new ClassicubeSession(); - public List Servers = new List(); public AsyncDownloader Downloader; public int Width { get { return Window.Width; } } @@ -72,7 +71,7 @@ namespace Launcher2 { if( !Window.Exists ) break; screen.Tick(); - if( Dirty || (screen != null && screen.Dirty) ) + if( Dirty || screen.Dirty ) Display(); Thread.Sleep( 1 ); } diff --git a/Launcher2/Patcher/ResourceFetcher.cs b/Launcher2/Patcher/ResourceFetcher.cs index 56c9d9f37..afadea1fb 100644 --- a/Launcher2/Patcher/ResourceFetcher.cs +++ b/Launcher2/Patcher/ResourceFetcher.cs @@ -15,7 +15,7 @@ namespace Launcher2 { public void DownloadItems( Action 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/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)" ); } diff --git a/Launcher2/WebService/GameSession.cs b/Launcher2/WebService/GameSession.cs index b42c720fe..807ae4fb4 100644 --- a/Launcher2/WebService/GameSession.cs +++ b/Launcher2/WebService/GameSession.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using System.Threading; namespace Launcher2 { @@ -15,13 +16,61 @@ namespace Launcher2 { cookies = new CookieContainer(); } + public bool Working; + public WebException Exception; + public string Status; + public List Servers = new List(); + + public void LoginAsync( string user, string password ) { + Username = user; + Working = true; + Exception = null; + Status = "&eSigning in.."; + Servers = new List(); + + 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(); + 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 GameStartData GetConnectInfo( string hash ); public abstract List GetPublicServers(); - CookieContainer cookies = new CookieContainer(); + CookieContainer cookies = new CookieContainer(); protected HttpWebResponse MakeRequest( string uri, string referer, string data ) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create( uri ); @@ -31,6 +80,7 @@ namespace Launcher2 { 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; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; @@ -60,7 +110,7 @@ namespace Launcher2 { using( Stream stream = response.GetResponseStream() ) { using( StreamReader reader = new StreamReader( stream ) ) { string line; - while( ( line = reader.ReadLine() ) != null ) { + while( (line = reader.ReadLine()) != null ) { yield return line; } }