From d1c3f85518f2a802f50481041f542febdb86d13b Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 12 Jan 2018 15:28:06 +1100 Subject: [PATCH] Combine NormalPlayerListWidget and ExtPlayerListWidget into one class --- ClassicalSharp.sln | 4 +- ClassicalSharp/2D/Screens/HudScreen.cs | 12 +- .../2D/Widgets/Chat/ChatInputWidget.cs | 8 +- .../Widgets/PlayerList/ExtPlayerListWidget.cs | 190 ----------- .../PlayerList/NormalPlayerListWidget.cs | 123 ------- .../2D/Widgets/PlayerList/PlayerListWidget.cs | 201 ----------- ClassicalSharp/2D/Widgets/PlayerListWidget.cs | 313 ++++++++++++++++++ ClassicalSharp/ClassicalSharp.csproj | 5 +- ClassicalSharp/Entities/TabList.cs | 26 +- .../Network/NetworkProcessor.Helpers.cs | 8 +- 10 files changed, 337 insertions(+), 553 deletions(-) delete mode 100644 ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs delete mode 100644 ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs delete mode 100644 ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs create mode 100644 ClassicalSharp/2D/Widgets/PlayerListWidget.cs diff --git a/ClassicalSharp.sln b/ClassicalSharp.sln index 637ed5ce7..2b2653be6 100644 --- a/ClassicalSharp.sln +++ b/ClassicalSharp.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 # SharpDevelop 4.4 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassicalSharp", "ClassicalSharp\ClassicalSharp.csproj", "{BEB1C785-5CAD-48FF-A886-876BF0A318D4}" EndProject diff --git a/ClassicalSharp/2D/Screens/HudScreen.cs b/ClassicalSharp/2D/Screens/HudScreen.cs index cca2d6a4f..4bbcf6922 100644 --- a/ClassicalSharp/2D/Screens/HudScreen.cs +++ b/ClassicalSharp/2D/Screens/HudScreen.cs @@ -86,14 +86,10 @@ namespace ClassicalSharp.Gui.Screens { hotbar.Dispose(); hotbar.Init(); - if (!hadPlayerList) return; - - if (game.Server.UsingExtPlayerList && !game.UseClassicTabList) { - playerList = new ExtPlayerListWidget(game, playerFont); - } else { - playerList = new NormalPlayerListWidget(game, playerFont); - } - + if (!hadPlayerList) return; + bool extended = game.Server.UsingExtPlayerList && !game.UseClassicTabList; + playerList = new PlayerListWidget(game, playerFont, !extended); + playerList.Init(); playerList.RecalcYOffset(); playerList.Reposition(); diff --git a/ClassicalSharp/2D/Widgets/Chat/ChatInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/ChatInputWidget.cs index 245a350bb..479b4a27f 100644 --- a/ClassicalSharp/2D/Widgets/Chat/ChatInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/ChatInputWidget.cs @@ -138,12 +138,10 @@ namespace ClassicalSharp.Gui.Widgets { List matches = new List(); game.Chat.Add(null, MessageType.ClientStatus3); - TabListEntry[] entries = game.TabList.Entries; + TabListEntry[] entries = TabList.Entries; for (int i = 0; i < EntityList.MaxCount; i++) { - if (entries[i] == null) continue; - - string rawName = entries[i].PlayerName; - string name = Utils.StripColours(rawName); + if (entries[i] == null) continue; + string name = entries[i].PlayerName; if (Utils.CaselessStarts(name, part)) matches.Add(name); } diff --git a/ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs deleted file mode 100644 index 2aee70a23..000000000 --- a/ClassicalSharp/2D/Widgets/PlayerList/ExtPlayerListWidget.cs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using System.Collections.Generic; -using System.Drawing; -using ClassicalSharp.Entities; -using ClassicalSharp.Events; - -namespace ClassicalSharp.Gui.Widgets { - public class ExtPlayerListWidget : PlayerListWidget { - - public ExtPlayerListWidget(Game game, Font font) : base(game, font) { - textures = new Texture[512]; - elementOffset = 10; - } - - PlayerInfo[] info = new PlayerInfo[512]; - class PlayerInfo { - - public string ListName; - public string PlayerName; - public string GroupName; - public byte GroupRank; - public byte NameId; - public bool IsGroup = false; - - public PlayerInfo(TabListEntry p, byte id) { - ListName = Utils.StripColours(p.ListName); - PlayerName = Utils.StripColours(p.PlayerName); - NameId = id; - GroupName = p.GroupName; - GroupRank = p.GroupRank; - } - - public PlayerInfo(string groupName) { - GroupName = groupName; - IsGroup = true; - } - } - - PlayerInfoComparer comparer = new PlayerInfoComparer(); - class PlayerInfoComparer : IComparer { - - public bool JustComparingGroups = true; - - public int Compare(PlayerInfo x, PlayerInfo y) { - if (JustComparingGroups) - return x.GroupName.CompareTo(y.GroupName); - - int rankOrder = x.GroupRank.CompareTo(y.GroupRank); - return rankOrder != 0 ? rankOrder : - x.ListName.CompareTo(y.ListName); - } - } - - protected override bool ShouldOffset(int i) { - return info[i] == null || !info[i].IsGroup; - } - - public override void Init() { - base.Init(); - game.EntityEvents.TabListEntryAdded += TabEntryAdded; - game.EntityEvents.TabListEntryRemoved += TabEntryRemoved; - game.EntityEvents.TabListEntryChanged += TabEntryChanged; - } - - public override void Dispose() { - base.Dispose(); - game.EntityEvents.TabListEntryAdded -= TabEntryAdded; - game.EntityEvents.TabListEntryChanged -= TabEntryChanged; - game.EntityEvents.TabListEntryRemoved -= TabEntryRemoved; - } - - void TabEntryChanged(object sender, IdEventArgs e) { - for (int i = 0; i < namesCount; i++) { - PlayerInfo pInfo = info[i]; - if (!pInfo.IsGroup && pInfo.NameId == e.Id) { - Texture tex = textures[i]; - gfx.DeleteTexture(ref tex); - AddPlayerInfo(game.TabList.Entries[e.Id], e.Id, i); - SortPlayerInfo(); - return; - } - } - } - - void TabEntryRemoved(object sender, IdEventArgs e) { - for (int i = 0; i < namesCount; i++) { - PlayerInfo pInfo = info[i]; - if (!pInfo.IsGroup && pInfo.NameId == e.Id) { - RemoveItemAt(info, i); - RemoveTextureAt(i); - return; - } - } - } - - void TabEntryAdded(object sender, IdEventArgs e) { - AddPlayerInfo(game.TabList.Entries[e.Id], e.Id, -1); - SortPlayerInfo(); - } - - protected override void CreateInitialPlayerInfo() { - TabListEntry[] entries = game.TabList.Entries; - for (int i = 0; i < entries.Length; i++) { - TabListEntry e = entries[i]; - if (e != null) AddPlayerInfo(e, (byte)i, -1); - } - } - - public override string GetNameUnder(int mouseX, int mouseY) { - for (int i = 0; i < namesCount; i++) { - Texture tex = textures[i]; - if (tex.IsValid && tex.Bounds.Contains(mouseX, mouseY) && !info[i].IsGroup) { - return Utils.StripColours(info[i].PlayerName); - } - } - return null; - } - - void AddPlayerInfo(TabListEntry player, byte id, int index) { - DrawTextArgs args = new DrawTextArgs(player.ListName, font, true); - Texture tex = game.Drawer2D.MakeTextTexture(ref args, 0, 0); - game.Drawer2D.ReducePadding(ref tex, Utils.Floor(font.Size), 3); - - if (index < 0) { - info[namesCount] = new PlayerInfo(player, id); - textures[namesCount] = tex; - namesCount++; - } else { - info[index] = new PlayerInfo(player, id); - textures[index] = tex; - } - } - - protected override void SortInfoList() { - if (namesCount == 0) return; - - // Sort the list into groups - for (int i = 0; i < namesCount; i++) { - if (info[i].IsGroup) DeleteGroup(ref i); - } - comparer.JustComparingGroups = true; - Array.Sort(info, textures, 0, namesCount, comparer); - - // Sort the entries in each group - comparer.JustComparingGroups = false; - int index = 0; - while (index < namesCount) { - AddGroup(info[index].GroupName, ref index); - int count = GetGroupCount(index); - Array.Sort(info, textures, index, count, comparer); - index += count; - } - } - - void DeleteGroup(ref int i) { - gfx.DeleteTexture(ref textures[i]); - RemoveItemAt(info, i); - RemoveItemAt(textures, i); - - namesCount--; - i--; - } - - void AddGroup(string group, ref int index) { - DrawTextArgs args = new DrawTextArgs(group, font, true); - Texture tex = game.Drawer2D.MakeTextTexture(ref args, 0, 0); - game.Drawer2D.ReducePadding(ref tex, Utils.Floor(font.Size), 3); - - for (int i = info.Length - 1; i > index; i--) { - info[i] = info[i - 1]; - textures[i] = textures[i - 1]; - } - info[index] = new PlayerInfo(group); - textures[index] = tex; - - index++; - namesCount++; - } - - int GetGroupCount(int startIndex) { - string group = info[startIndex].GroupName; - int count = 0; - while (startIndex < namesCount && info[startIndex++].GroupName == group) { - count++; - } - return count; - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs deleted file mode 100644 index 4c8d29ec0..000000000 --- a/ClassicalSharp/2D/Widgets/PlayerList/NormalPlayerListWidget.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using System.Collections.Generic; -using System.Drawing; -using ClassicalSharp.Entities; -using ClassicalSharp.Events; - -namespace ClassicalSharp.Gui.Widgets { - public class NormalPlayerListWidget : PlayerListWidget { - - public NormalPlayerListWidget(Game game, Font font) : base(game, font) { - textures = new Texture[256]; - } - - PlayerInfo[] info = new PlayerInfo[256]; - protected class PlayerInfo { - - public string Name, ColouredName; - public byte Id; - - public PlayerInfo(TabListEntry p, byte id) { - ColouredName = p.PlayerName; - Name = Utils.StripColours(p.PlayerName); - Id = id; - } - } - - 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; - } - - public override void Init() { - base.Init(); - game.EntityEvents.TabListEntryAdded += TabEntryAdded; - game.EntityEvents.TabListEntryRemoved += TabEntryRemoved; - game.EntityEvents.TabListEntryChanged += TabEntryChanged; - } - - public override void Dispose() { - base.Dispose(); - game.EntityEvents.TabListEntryAdded -= TabEntryAdded; - game.EntityEvents.TabListEntryChanged -= TabEntryChanged; - game.EntityEvents.TabListEntryRemoved -= TabEntryRemoved; - } - - protected override void CreateInitialPlayerInfo() { - TabListEntry[] entries = game.TabList.Entries; - for (int i = 0; i < entries.Length; i++) { - TabListEntry e = entries[i]; - if (e != null) - AddPlayerInfo(new PlayerInfo(e, (byte)i), -1); - } - } - - void AddPlayerInfo(PlayerInfo pInfo, int index) { - Texture tex = DrawName(pInfo); - if (index < 0) { - info[namesCount] = pInfo; - textures[namesCount] = tex; - namesCount++; - } else { - info[index] = pInfo; - textures[index] = tex; - } - } - - Texture DrawName(PlayerInfo pInfo) { - string name = pInfo.ColouredName; - if (game.PureClassic) name = Utils.StripColours(name); - - DrawTextArgs args = new DrawTextArgs(name, font, false); - Texture tex = game.Drawer2D.MakeTextTexture(ref args, 0, 0); - game.Drawer2D.ReducePadding(ref tex, Utils.Floor(font.Size), 3); - return tex; - } - - void TabEntryAdded(object sender, IdEventArgs e) { - AddPlayerInfo(new PlayerInfo(game.TabList.Entries[e.Id], e.Id), -1); - SortPlayerInfo(); - } - - void TabEntryChanged(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]; - gfx.DeleteTexture(ref tex); - AddPlayerInfo(new PlayerInfo(game.TabList.Entries[e.Id], e.Id), i); - SortPlayerInfo(); - return; - } - } - - void TabEntryRemoved(object sender, IdEventArgs e) { - for (int i = 0; i < namesCount; i++) { - PlayerInfo pInfo = info[i]; - if (pInfo.Id == e.Id) { - RemoveItemAt(info, i); - RemoveTextureAt(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/PlayerList/PlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs deleted file mode 100644 index 5e1411bd3..000000000 --- a/ClassicalSharp/2D/Widgets/PlayerList/PlayerListWidget.cs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using System.Drawing; - -namespace ClassicalSharp.Gui.Widgets { - public abstract class PlayerListWidget : Widget { - - protected readonly Font font; - public PlayerListWidget(Game game, Font font) : base(game) { - HorizontalAnchor = Anchor.Centre; - VerticalAnchor = Anchor.Centre; - this.font = font; - } - - protected const int columnPadding = 5; - protected const int boundsSize = 10; - protected const int namesPerColumn = 20; - - protected int elementOffset = 0; - protected int namesCount = 0; - protected Texture[] textures; - protected int columns; - protected int xMin, xMax, yHeight; - - static FastColour topCol = new FastColour(0, 0, 0, 180); - static FastColour bottomCol = new FastColour(50, 50, 50, 205); - TextWidget overview; - - public override void Init() { - overview = TextWidget.Create(game, "Connected players:", font) - .SetLocation(Anchor.Centre, Anchor.LeftOrTop, 0, 0); - - CreateInitialPlayerInfo(); - SortPlayerInfo(); - } - - public abstract string GetNameUnder(int mouseX, int mouseY); - - public override void Render(double delta) { - gfx.Texturing = false; - int offset = overview.Height + 10; - int height = Math.Max(300, Height + overview.Height); - gfx.Draw2DQuad(X, Y - offset, Width, height, topCol, bottomCol); - - gfx.Texturing = true; - overview.YOffset = Y - offset + 5; - overview.Reposition(); - overview.Render(delta); - - for (int i = 0; i < namesCount; i++) { - Texture tex = textures[i]; - int texY = tex.Y; - tex.Y1 -= 10; - if (tex.IsValid) tex.Render(gfx); - tex.Y1 = texY; - } - } - - public override void Dispose() { - for (int i = 0; i < namesCount; i++) { - Texture tex = textures[i]; - gfx.DeleteTexture(ref tex); - textures[i] = tex; - } - overview.Dispose(); - } - - protected void UpdateTableDimensions() { - int width = xMax - xMin; - X = xMin - boundsSize; - Y = game.Height / 2 - yHeight / 2 - boundsSize; - Width = width + boundsSize * 2; - Height = yHeight + boundsSize * 2; - } - - protected void CalcMaxColumnHeight() { - yHeight = 0; - for (int col = 0; col < columns; col++) { - yHeight = Math.Max(GetColumnHeight(col), yHeight); - } - } - - protected int GetColumnWidth(int column) { - int i = column * namesPerColumn; - int maxWidth = 0; - int maxIndex = Math.Min(namesCount, i + namesPerColumn); - - for (; i < maxIndex; i++) - maxWidth = Math.Max(maxWidth, textures[i].Width); - return maxWidth + columnPadding + elementOffset; - } - - protected int GetColumnHeight(int column) { - int i = column * namesPerColumn; - int total = 0; - int maxIndex = Math.Min(namesCount, i + namesPerColumn); - - for (; i < maxIndex; i++) - total += textures[i].Height + 1; - return total; - } - - protected void SetColumnPos(int column, int x, int y) { - int i = column * namesPerColumn; - int maxIndex = Math.Min(namesCount, i + namesPerColumn); - - for (; i < maxIndex; i++) { - Texture tex = textures[i]; - tex.X1 = x; tex.Y1 = y; - - y += tex.Height + 1; - if (ShouldOffset(i)) - tex.X1 += elementOffset; - textures[i] = tex; - } - } - - protected virtual bool ShouldOffset(int i) { return true; } - - public void RecalcYOffset() { - YOffset = -Math.Max(0, game.Height / 4 - Height / 2); - } - - public override void Reposition() { - int oldX = X, oldY = Y; - base.Reposition(); - - for (int i = 0; i < namesCount; i++) { - textures[i].X1 += X - oldX; - textures[i].Y1 += Y - oldY; - } - } - - protected abstract void CreateInitialPlayerInfo(); - - protected abstract void SortInfoList(); - - protected void RemoveTextureAt(int i) { - Texture tex = textures[i]; - gfx.DeleteTexture(ref tex); - RemoveItemAt(textures, i); - namesCount--; - SortPlayerInfo(); - } - - protected void RemoveItemAt(T[] array, int index) { - for (int i = index; i < namesCount - 1; i++) { - array[i] = array[i + 1]; - } - array[namesCount - 1] = default(T); - } - - protected void SortPlayerInfo() { - columns = Utils.CeilDiv(namesCount, namesPerColumn); - SortInfoList(); - columns = Utils.CeilDiv(namesCount, namesPerColumn); - CalcMaxColumnHeight(); - int y = game.Height / 2 - yHeight / 2; - int midCol = columns / 2; - - int centreX = game.Width / 2; - int offset = 0; - if (columns % 2 != 0) { - // For an odd number of columns, the middle column is centred. - offset = Utils.CeilDiv(GetColumnWidth(midCol), 2); - } - - xMin = centreX - offset; - for (int col = midCol - 1; col >= 0; col--) { - xMin -= GetColumnWidth(col); - SetColumnPos(col, xMin, y); - } - xMax = centreX - offset; - for (int col = midCol; col < columns; col++) { - SetColumnPos(col, xMax, y); - xMax += GetColumnWidth(col); - } - - OnSort(); - UpdateTableDimensions(); - RecalcYOffset(); - Reposition(); - } - - protected virtual 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); - } - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/2D/Widgets/PlayerListWidget.cs b/ClassicalSharp/2D/Widgets/PlayerListWidget.cs new file mode 100644 index 000000000..1b4f221c7 --- /dev/null +++ b/ClassicalSharp/2D/Widgets/PlayerListWidget.cs @@ -0,0 +1,313 @@ +// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 +using System; +using System.Collections.Generic; +using System.Drawing; +using ClassicalSharp.Entities; +using ClassicalSharp.Events; + +namespace ClassicalSharp.Gui.Widgets { + public class PlayerListWidget : Widget { + + readonly Font font; + bool classic; + public PlayerListWidget(Game game, Font font, bool classic) : base(game) { + HorizontalAnchor = Anchor.Centre; + VerticalAnchor = Anchor.Centre; + this.font = font; + this.classic = classic; + elementOffset = classic ? 0 : 10; + } + + const int columnPadding = 5; + const int boundsSize = 10; + const int namesPerColumn = 20; + + int elementOffset, namesCount = 0; + Texture[] textures = new Texture[512]; + short[] IDs = new short[512]; + int xMin, xMax, yHeight; + + static FastColour topCol = new FastColour(0, 0, 0, 180); + static FastColour bottomCol = new FastColour(50, 50, 50, 205); + TextWidget overview; + + public override void Init() { + TabListEntry[] entries = TabList.Entries; + for (int id = 0; id < entries.Length; id++) { + TabListEntry e = entries[id]; + if (e != null) AddPlayerInfo((byte)id, -1); + } + SortAndReposition(); + + overview = TextWidget.Create(game, "Connected players:", font) + .SetLocation(Anchor.Centre, Anchor.LeftOrTop, 0, 0); + game.EntityEvents.TabListEntryAdded += TabEntryAdded; + game.EntityEvents.TabListEntryRemoved += TabEntryRemoved; + game.EntityEvents.TabListEntryChanged += TabEntryChanged; + } + + public override void Render(double delta) { + gfx.Texturing = false; + int offset = overview.Height + 10; + int height = Math.Max(300, Height + overview.Height); + gfx.Draw2DQuad(X, Y - offset, Width, height, topCol, bottomCol); + + gfx.Texturing = true; + overview.YOffset = Y - offset + 5; + overview.Reposition(); + overview.Render(delta); + + for (int i = 0; i < namesCount; i++) { + Texture tex = textures[i]; + int texY = tex.Y; + tex.Y1 -= 10; + if (tex.IsValid) tex.Render(gfx); + tex.Y1 = texY; + } + } + + public override void Dispose() { + for (int i = 0; i < namesCount; i++) { + Texture tex = textures[i]; + gfx.DeleteTexture(ref tex); + textures[i] = tex; + } + + overview.Dispose(); + game.EntityEvents.TabListEntryAdded -= TabEntryAdded; + game.EntityEvents.TabListEntryChanged -= TabEntryChanged; + game.EntityEvents.TabListEntryRemoved -= TabEntryRemoved; + } + + public string GetNameUnder(int mouseX, int mouseY) { + for (int i = 0; i < namesCount; i++) { + Texture tex = textures[i]; + if (tex.IsValid && tex.Bounds.Contains(mouseX, mouseY) && IDs[i] >= 0) { + return TabList.Entries[IDs[i]].PlayerName; + } + } + return null; + } + + + void RepositionColumns() { + int width = 0, centreX = game.Width / 2; + yHeight = 0; + + int columns = Utils.CeilDiv(namesCount, namesPerColumn); + for (int col = 0; col < columns; col++) { + width += GetColumnWidth(col); + yHeight = Math.Max(GetColumnHeight(col), yHeight); + } + + 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); + } + } + + void UpdateTableDimensions() { + int width = xMax - xMin; + X = xMin - boundsSize; + Y = game.Height / 2 - yHeight / 2 - boundsSize; + Width = width + boundsSize * 2; + Height = yHeight + boundsSize * 2; + } + + int GetColumnWidth(int column) { + int i = column * namesPerColumn; + int maxWidth = 0; + int maxIndex = Math.Min(namesCount, i + namesPerColumn); + + for (; i < maxIndex; i++) + maxWidth = Math.Max(maxWidth, textures[i].Width); + return maxWidth + columnPadding + elementOffset; + } + + int GetColumnHeight(int column) { + int i = column * namesPerColumn; + int total = 0; + int maxIndex = Math.Min(namesCount, i + namesPerColumn); + + for (; i < maxIndex; i++) + total += textures[i].Height + 1; + return total; + } + + void SetColumnPos(int column, int x, int y) { + int i = column * namesPerColumn; + int maxIndex = Math.Min(namesCount, i + namesPerColumn); + + for (; i < maxIndex; i++) { + Texture tex = textures[i]; + tex.X1 = x; tex.Y1 = y; + + y += tex.Height + 1; + // offset player names a bit, compared to group name + if (!classic && IDs[i] >= 0) { + tex.X1 += elementOffset; + } + textures[i] = tex; + } + } + + public void RecalcYOffset() { + YOffset = -Math.Max(0, game.Height / 4 - Height / 2); + } + + public override void Reposition() { + int oldX = X, oldY = Y; + base.Reposition(); + + for (int i = 0; i < namesCount; i++) { + textures[i].X1 += X - oldX; + textures[i].Y1 += Y - oldY; + } + } + + + void AddPlayerInfo(byte id, int index) { + string name = TabList.Entries[id].ListName; + Texture tex = DrawName(name); + + // insert at end of list + if (index == -1) { index = namesCount; namesCount++; } + IDs[index] = id; + textures[index] = tex; + } + + void TabEntryAdded(object sender, IdEventArgs e) { + AddPlayerInfo(e.Id, -1); + SortAndReposition(); + } + + void TabEntryChanged(object sender, IdEventArgs e) { + for (int i = 0; i < namesCount; i++) { + if (IDs[i] != e.Id) continue; + + Texture tex = textures[i]; + gfx.DeleteTexture(ref tex); + AddPlayerInfo(e.Id, i); + SortAndReposition(); + return; + } + } + + void TabEntryRemoved(object sender, IdEventArgs e) { + for (int i = 0; i < namesCount; i++) { + if (IDs[i] != e.Id) continue; + RemoveAt(i); + SortAndReposition(); + return; + } + } + + void RemoveAt(int i) { + Texture tex = textures[i]; + gfx.DeleteTexture(ref tex); + + for (; i < namesCount - 1; i++) { + IDs[i] = IDs[i + 1]; + textures[i] = textures[i + 1]; + } + + IDs[namesCount] = 0; + textures[namesCount] = default(Texture); + namesCount--; + } + + + void SortAndReposition() { + SortEntries(); + RepositionColumns(); + UpdateTableDimensions(); + RecalcYOffset(); + Reposition(); + } + + Texture DrawName(string name) { + if (game.PureClassic) name = Utils.StripColours(name); + + DrawTextArgs args = new DrawTextArgs(name, font, false); + Texture tex = game.Drawer2D.MakeTextTexture(ref args, 0, 0); + game.Drawer2D.ReducePadding(ref tex, Utils.Floor(font.Size), 3); + return tex; + } + + IComparer comparer = new PlayerComparer(); + class PlayerComparer : IComparer { + public int Compare(short x, short y) { + byte xRank = TabList.Entries[x].GroupRank; + byte yRank = TabList.Entries[y].GroupRank; + int rankOrder = xRank.CompareTo(yRank); + if (rankOrder != 0) return rankOrder; + + string xName = TabList.Entries[x].ListNameColourless; + string yName = TabList.Entries[y].ListNameColourless; + return xName.CompareTo(yName); + } + } + + IComparer grpComparer = new GroupComparer(); + class GroupComparer : IComparer { + public int Compare(short x, short y) { + string xGroup = TabList.Entries[x].Group; + string yGroup = TabList.Entries[y].Group; + return xGroup.CompareTo(yGroup); + } + } + + void SortEntries() { + if (namesCount == 0) return; + if (classic) { + Array.Sort(IDs, textures, 0, namesCount, grpComparer); + return; + } + + // Sort the list into groups + for (int i = 0; i < namesCount; i++) { + if (IDs[i] < 0) DeleteGroup(ref i); + } + Array.Sort(IDs, textures, 0, namesCount, grpComparer); + + // Sort the entries in each group + int index = 0; + while (index < namesCount) { + short id = IDs[index]; + AddGroup(id, ref index); + int count = GetGroupCount(id, index); + Array.Sort(IDs, textures, index, count, comparer); + index += count; + } + } + + void DeleteGroup(ref int i) { RemoveAt(i); i--; } + void AddGroup(short id, ref int index) { + for (int i = IDs.Length - 1; i > index; i--) { + IDs[i] = IDs[i - 1]; + textures[i] = textures[i - 1]; + } + + IDs[index] = (short)-id; + string group = TabList.Entries[id].Group; + textures[index] = DrawName(group); + + index++; + namesCount++; + } + + int GetGroupCount(short id, int idx) { + string group = TabList.Entries[id].Group; + int count = 0; + while (idx < namesCount && TabList.Entries[IDs[idx]].Group == group) { + idx++; count++; + } + return count; + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 10113c629..aa1a0a4e9 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -127,9 +127,7 @@ - - - + @@ -330,7 +328,6 @@ - diff --git a/ClassicalSharp/Entities/TabList.cs b/ClassicalSharp/Entities/TabList.cs index ea44e360b..434cb7cd0 100644 --- a/ClassicalSharp/Entities/TabList.cs +++ b/ClassicalSharp/Entities/TabList.cs @@ -3,7 +3,7 @@ namespace ClassicalSharp.Entities { public sealed class TabList : IGameComponent { - public TabListEntry[] Entries = new TabListEntry[256]; + public static TabListEntry[] Entries = new TabListEntry[256]; public void Init(Game game) { } public void Ready(Game game) { } @@ -17,30 +17,24 @@ namespace ClassicalSharp.Entities { } } - public sealed class TabListEntry { - - /// Unformatted name of the player for autocompletion, etc. - /// Colour codes are always removed from this. - public string PlayerName; - + public sealed class TabListEntry { + /// Plain name of the player for autocompletion, etc. + public string PlayerName; /// Formatted name for display in the player list. - /// Can include colour codes. public string ListName; - + public string ListNameColourless; /// Name of the group this player is in. - /// Can include colour codes. - public string GroupName; - + public string Group; /// Player's rank within the group. (0 is highest) - /// Multiple group members can share the same rank, - /// so a player's group rank is not a unique identifier. + /// Multiple players can share the same rank, so this is not a unique identifier. public byte GroupRank; public TabListEntry(string playerName, string listName, string groupName, byte groupRank) { - PlayerName = playerName; + PlayerName = Utils.StripColours(playerName); ListName = listName; - GroupName = groupName; + ListNameColourless = Utils.StripColours(listName); + Group = groupName; GroupRank = groupRank; } } diff --git a/ClassicalSharp/Network/NetworkProcessor.Helpers.cs b/ClassicalSharp/Network/NetworkProcessor.Helpers.cs index 487f5e83f..1601cd255 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Helpers.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Helpers.cs @@ -98,14 +98,14 @@ namespace ClassicalSharp.Network { internal void AddTablistEntry(byte id, string playerName, string listName, string groupName, byte groupRank) { - TabListEntry oldInfo = game.TabList.Entries[id]; + TabListEntry oldInfo = TabList.Entries[id]; TabListEntry info = new TabListEntry(playerName, listName, groupName, groupRank); - game.TabList.Entries[id] = info; + TabList.Entries[id] = info; if (oldInfo != null) { // Only redraw the tab list if something changed. if (info.PlayerName != oldInfo.PlayerName || info.ListName != oldInfo.ListName || - info.GroupName != oldInfo.GroupName || info.GroupRank != oldInfo.GroupRank) { + info.Group != oldInfo.Group || info.GroupRank != oldInfo.GroupRank) { game.EntityEvents.RaiseTabListEntryChanged(id); } } else { @@ -115,7 +115,7 @@ namespace ClassicalSharp.Network { internal void RemoveTablistEntry(byte id) { game.EntityEvents.RaiseTabEntryRemoved(id); - game.TabList.Entries[id] = null; + TabList.Entries[id] = null; } internal void DisableAddEntityHack() {