diff --git a/ClassicalSharp/2D/Screens/HudScreen.cs b/ClassicalSharp/2D/Screens/HudScreen.cs index e3e88bc01..af2aa5cd7 100644 --- a/ClassicalSharp/2D/Screens/HudScreen.cs +++ b/ClassicalSharp/2D/Screens/HudScreen.cs @@ -123,7 +123,9 @@ namespace ClassicalSharp { } void CreatePlayerListWidget() { - if( game.Network.UsingExtPlayerList ) { + if( game.UseClassicTabList ) { + playerList = new ClassicPlayerListWidget( game, playerFont ); + } else if( game.Network.UsingExtPlayerList ) { playerList = new ExtPlayerListWidget( game, playerFont ); } else { playerList = new NormalPlayerListWidget( game, playerFont ); diff --git a/ClassicalSharp/2D/Screens/Menu/NostalgiaScreen.cs b/ClassicalSharp/2D/Screens/Menu/NostalgiaScreen.cs index c74b34044..94c36f8fd 100644 --- a/ClassicalSharp/2D/Screens/Menu/NostalgiaScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/NostalgiaScreen.cs @@ -27,6 +27,12 @@ namespace ClassicalSharp { Options.Set( OptionsKey.UseClassicGui, v == "yes" ); } ), + Make( -140, -50, "Classic player list", OnWidgetClick, + g => g.UseClassicTabList ? "yes" : "no", + (g, v) => { g.UseClassicTabList = v == "yes"; + Options.Set( OptionsKey.UseClassicTabList, v == "yes" ); + } ), + // Column 2 Make( 140, -100, "Allow custom blocks", OnWidgetClick, g => g.AllowCustomBlocks ? "yes" : "no", @@ -50,11 +56,12 @@ namespace ClassicalSharp { (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), null, }; - buttons[3].Disabled = true; + buttons[4].Disabled = true; validators = new MenuInputValidator[] { new BooleanValidator(), new BooleanValidator(), + new BooleanValidator(), new BooleanValidator(), new BooleanValidator(), diff --git a/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs new file mode 100644 index 000000000..b0704104c --- /dev/null +++ b/ClassicalSharp/2D/Widgets/PlayerList/ClassicPlayerListWidget.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace ClassicalSharp { + + public sealed class ClassicPlayerListWidget : PlayerListWidget { + + bool extList; + int elemHeight; + ChatTextWidget overview; + static FastColour lightTableCol = new FastColour( 20, 20, 20, 180 ); + public ClassicPlayerListWidget( Game game, Font font ) : base( game, font ) { + textures = new Texture[256]; + extList = game.Network.UsingExtPlayerList; + } + + PlayerInfo[] info = new PlayerInfo[256]; + class PlayerInfo { + + public string Name, ColouredName; + public byte Id; + + public PlayerInfo( Player p ) { + ColouredName = p.DisplayName; + Name = Utils.StripColours( p.DisplayName ); + Id = p.ID; + } + + public PlayerInfo( CpeListInfo p ) { + ColouredName = p.PlayerName; + Name = Utils.StripColours( p.PlayerName ); + Id = p.NameId; + } + } + + public override string GetNameUnder( int mouseX, int mouseY ) { + for( int i = 0; i < namesCount; i++ ) { + Texture texture = textures[i]; + if( texture.IsValid && texture.Bounds.Contains( mouseX, mouseY ) ) + return Utils.StripColours( info[i].Name ); + } + return null; + } + + protected override void OnSort() { + int width = 0, centreX = game.Width / 2; + for( int col = 0; col < columns; col++) + width += GetColumnWidth( col ); + if( width < 480 ) width = 480; + + xMin = centreX - width / 2; + xMax = centreX + width / 2; + + int x = xMin, y = game.Height / 2 - yHeight / 2; + for( int col = 0; col < columns; col++ ) { + SetColumnPos( col, x, y ); + x += GetColumnWidth( col ); + } + } + + public override void Render( double delta ) { + graphicsApi.Texturing = false; + int offset = overview.Height; + int height = namesPerColumn * (elemHeight + 1) + boundsSize * 2 + offset; + graphicsApi.Draw2DQuad( X, Y - offset, Width, height, lightTableCol ); + + graphicsApi.Texturing = true; + overview.MoveTo( game.Width / 2 - overview.Width / 2, + Y - offset + boundsSize / 2 ); + overview.Render( delta ); + + for( int i = 0; i < namesCount; i++ ) { + Texture texture = textures[i]; + if( texture.IsValid ) + texture.Render( graphicsApi ); + } + } + + public override void Init() { + DrawTextArgs measureArgs = new DrawTextArgs( "ABC", font, false ); + + elemHeight = game.Drawer2D.MeasureChatSize( ref measureArgs ).Height; + overview = ChatTextWidget.Create( game, 0, 0, "Connected players:", + Anchor.Centre, Anchor.Centre, font ); + + base.Init(); + if( !extList ) { + game.EntityEvents.EntityAdded += PlayerSpawned; + game.EntityEvents.EntityRemoved += PlayerDespawned; + } else { + game.EntityEvents.CpeListInfoAdded += PlayerListInfoAdded; + game.EntityEvents.CpeListInfoRemoved += PlayerDespawned; + game.EntityEvents.CpeListInfoChanged += PlayerListInfoChanged; + } + } + + public override void Dispose() { + base.Dispose(); + overview.Dispose(); + if( !extList ) { + game.EntityEvents.EntityAdded -= PlayerSpawned; + game.EntityEvents.EntityRemoved -= PlayerDespawned; + } else { + game.EntityEvents.CpeListInfoAdded -= PlayerListInfoAdded; + game.EntityEvents.CpeListInfoChanged -= PlayerListInfoChanged; + game.EntityEvents.CpeListInfoRemoved -= PlayerDespawned; + } + } + + protected override void CreateInitialPlayerInfo() { + for( int i = 0; i < EntityList.MaxCount; i++ ) { + PlayerInfo info = null; + if( extList ) { + CpeListInfo player = game.CpePlayersList[i]; + if( player != null ) + info = new PlayerInfo( player ); + } else { + Player player = game.Players[i]; + if( player != null ) + info = new PlayerInfo( player ); + } + if( info != null ) + AddPlayerInfo( info, -1 ); + } + } + + void AddPlayerInfo( PlayerInfo pInfo, int index ) { + DrawTextArgs args = new DrawTextArgs( pInfo.ColouredName, font, false ); + Texture tex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 ); + if( index < 0 ) { + info[namesCount] = pInfo; + textures[namesCount] = tex; + namesCount++; + } else { + info[index] = pInfo; + textures[index] = tex; + } + } + + void PlayerSpawned( object sender, IdEventArgs e ) { + AddPlayerInfo( new PlayerInfo( game.Players[e.Id] ), -1 ); + columns = Utils.CeilDiv( namesCount, namesPerColumn ); + SortPlayerInfo(); + } + + void PlayerListInfoAdded( object sender, IdEventArgs e ) { + AddPlayerInfo( new PlayerInfo( game.CpePlayersList[e.Id] ), -1 ); + columns = Utils.CeilDiv( namesCount, namesPerColumn ); + SortPlayerInfo(); + } + + void PlayerListInfoChanged( object sender, IdEventArgs e ) { + for( int i = 0; i < namesCount; i++ ) { + PlayerInfo pInfo = info[i]; + if( pInfo.Id != e.Id ) continue; + + Texture tex = textures[i]; + graphicsApi.DeleteTexture( ref tex ); + AddPlayerInfo( new PlayerInfo( game.CpePlayersList[e.Id] ), i ); + SortPlayerInfo(); + return; + } + } + + void PlayerDespawned( object sender, IdEventArgs e ) { + for( int i = 0; i < namesCount; i++ ) { + PlayerInfo pInfo = info[i]; + if( pInfo.Id == e.Id ) { + RemoveInfoAt( info, i ); + return; + } + } + } + + PlayerInfoComparer comparer = new PlayerInfoComparer(); + class PlayerInfoComparer : IComparer { + + public int Compare( PlayerInfo x, PlayerInfo y ) { + return x.Name.CompareTo( y.Name ); + } + } + + protected override void SortInfoList() { + Array.Sort( info, textures, 0, namesCount, comparer ); + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/2D/Widgets/ExtPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs similarity index 95% rename from ClassicalSharp/2D/Widgets/ExtPlayerListWidget.cs rename to ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs index 705aa12c1..fec3ef00d 100644 --- a/ClassicalSharp/2D/Widgets/ExtPlayerListWidget.cs +++ b/ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs @@ -83,13 +83,7 @@ namespace ClassicalSharp { for( int i = 0; i < namesCount; i++ ) { PlayerInfo pInfo = info[i]; if( !pInfo.IsGroup && pInfo.NameId == e.Id ) { - Texture tex = textures[i]; - graphicsApi.DeleteTexture( ref tex ); - RemoveItemAt( textures, i ); - RemoveItemAt( info, i ); - namesCount--; - columns = Utils.CeilDiv( namesCount, namesPerColumn ); - SortPlayerInfo(); + RemoveInfoAt( info, i ); return; } } diff --git a/ClassicalSharp/2D/Widgets/NormalPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs similarity index 90% rename from ClassicalSharp/2D/Widgets/NormalPlayerListWidget.cs rename to ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs index d4b77adf9..c52897d36 100644 --- a/ClassicalSharp/2D/Widgets/NormalPlayerListWidget.cs +++ b/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs @@ -71,13 +71,7 @@ namespace ClassicalSharp { for( int i = 0; i < namesCount; i++ ) { PlayerInfo pInfo = info[i]; if( pInfo.PlayerId == e.Id ) { - Texture tex = textures[i]; - graphicsApi.DeleteTexture( ref tex ); - RemoveItemAt( info, i ); - RemoveItemAt( textures, i ); - namesCount--; - columns = Utils.CeilDiv( namesCount, namesPerColumn ); - SortPlayerInfo(); + RemoveInfoAt( info, i ); return; } } diff --git a/ClassicalSharp/2D/Widgets/PlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs similarity index 86% rename from ClassicalSharp/2D/Widgets/PlayerListWidget.cs rename to ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs index 1e1a775ed..1bfa1a752 100644 --- a/ClassicalSharp/2D/Widgets/PlayerListWidget.cs +++ b/ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs @@ -70,7 +70,7 @@ namespace ClassicalSharp { for( ; i < maxIndex; i++ ) maxWidth = Math.Max( maxWidth, textures[i].Width ); - return maxWidth; + return maxWidth + 5; } protected int GetColumnHeight( int column ) { @@ -79,7 +79,7 @@ namespace ClassicalSharp { int maxIndex = Math.Min( namesCount, i + namesPerColumn ); for( ; i < maxIndex; i++ ) - total += textures[i].Height; + total += textures[i].Height + 1; return total; } @@ -90,7 +90,7 @@ namespace ClassicalSharp { for( ; i < maxIndex; i++ ) { Texture tex = textures[i]; tex.X1 = x; tex.Y1 = y; - y += tex.Height; + y += tex.Height + 1; textures[i] = tex; } } @@ -108,6 +108,16 @@ namespace ClassicalSharp { protected abstract void SortInfoList(); + protected void RemoveInfoAt( T[] info, int i ) { + Texture tex = textures[i]; + graphicsApi.DeleteTexture( ref tex ); + RemoveItemAt( info, i ); + RemoveItemAt( textures, i ); + namesCount--; + columns = Utils.CeilDiv( namesCount, namesPerColumn ); + SortPlayerInfo(); + } + protected void RemoveItemAt( T[] array, int index ) { for( int i = index; i < namesCount - 1; i++ ) { array[i] = array[i + 1]; @@ -139,8 +149,12 @@ namespace ClassicalSharp { xMax += GetColumnWidth( col ); } + OnSort(); UpdateTableDimensions(); MoveTo( X, game.Height / 4 ); } + + protected virtual void OnSort() { + } } } \ No newline at end of file diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 15053d1ea..5b46a490d 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -122,12 +122,13 @@ - - - + + + + @@ -279,6 +280,7 @@ + diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index b5a386171..1f86287ad 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -125,9 +125,9 @@ namespace ClassicalSharp { /// How sensitive the client is to changes in the player's mouse position. public int MouseSensitivity = 30; - public bool UseClassicGui = false; + public bool TabAutocomplete; - public bool TabAutocomplete = false; + public bool UseClassicGui, UseClassicTabList; public bool AllowCustomBlocks, AllowCPEBlocks, AllowServerTextures; diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index ed22abdf1..523a1cbe6 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -57,8 +57,10 @@ namespace ClassicalSharp { ChatScale = Options.GetFloat( OptionsKey.ChatScale, 0.35f, 5f, 1f ); defaultIb = Graphics.MakeDefaultIb(); MouseSensitivity = Options.GetInt( OptionsKey.Sensitivity, 1, 100, 30 ); - UseClassicGui = Options.GetBool( OptionsKey.UseClassicGui, true ); TabAutocomplete = Options.GetBool( OptionsKey.TabAutocomplete, false ); + + UseClassicGui = Options.GetBool( OptionsKey.UseClassicGui, true ); + UseClassicTabList = Options.GetBool( OptionsKey.UseClassicTabList, false ); AllowCustomBlocks = Options.GetBool( OptionsKey.AllowCustomBlocks, true ); AllowCPEBlocks = Options.GetBool( OptionsKey.AllowCPEBlocks, true ); AllowServerTextures = Options.GetBool( OptionsKey.AllowServerTextures, true ); diff --git a/ClassicalSharp/Utils/Options.cs b/ClassicalSharp/Utils/Options.cs index b477ab4b7..0c15a00a9 100644 --- a/ClassicalSharp/Utils/Options.cs +++ b/ClassicalSharp/Utils/Options.cs @@ -45,6 +45,7 @@ namespace ClassicalSharp { public const string AllowServerTextures = "nostalgia-servertextures"; public const string UseClassicGui = "nostalgia-classicgui"; public const string SimpleArmsAnim = "nostalgia-simplearms"; + public const string UseClassicTabList = "nostalgia-classictablist"; } // TODO: implement this