From bccc0f8f17941758c7f480cdb93a66f951f9082f Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 25 Dec 2017 13:20:13 +0000 Subject: [PATCH] Add a player list to the MP server browser. --- .../Widgets/Logic/MultiplayerLogic.cs | 112 ++++++++++++++++-- .../Widgets/MapPreviewWidget.cs | 12 +- mods/cnc/chrome/multiplayer-browser.yaml | 52 +------- .../cnc/chrome/multiplayer-browserpanels.yaml | 85 +++++++++++++ mods/cnc/mod.yaml | 1 + mods/common/chrome/multiplayer-browser.yaml | 53 ++------- .../chrome/multiplayer-browserpanels.yaml | 85 +++++++++++++ .../d2k/chrome/multiplayer-browserpanels.yaml | 84 +++++++++++++ mods/d2k/mod.yaml | 1 + mods/ra/mod.yaml | 1 + mods/ts/mod.yaml | 1 + 11 files changed, 383 insertions(+), 104 deletions(-) create mode 100644 mods/cnc/chrome/multiplayer-browserpanels.yaml create mode 100644 mods/common/chrome/multiplayer-browserpanels.yaml create mode 100644 mods/d2k/chrome/multiplayer-browserpanels.yaml diff --git a/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs index fd830e581b..ef113da481 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs @@ -18,6 +18,7 @@ using System.Text; using BeaconLib; using OpenRA.Network; using OpenRA.Server; +using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -37,13 +38,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly ModData modData; readonly WebServices services; readonly Probe lanGameProbe; + readonly ScrollItemWidget serverTemplate; + readonly ScrollItemWidget headerTemplate; + readonly Widget clientContainer; + readonly ScrollPanelWidget clientList; + readonly ScrollItemWidget clientTemplate, clientHeader; + readonly MapPreviewWidget mapPreview; + readonly ButtonWidget joinButton; + readonly int joinButtonY; GameServer currentServer; MapPreview currentMap; - ScrollItemWidget serverTemplate; - ScrollItemWidget headerTemplate; - Action onStart; Action onExit; @@ -85,10 +91,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic headerTemplate = serverList.Get("HEADER_TEMPLATE"); serverTemplate = serverList.Get("SERVER_TEMPLATE"); - var join = widget.Get("JOIN_BUTTON"); - join.IsVisible = () => currentServer != null; - join.IsDisabled = () => !currentServer.IsJoinable; - join.OnClick = () => Join(currentServer); + joinButton = widget.Get("JOIN_BUTTON"); + joinButton.IsVisible = () => currentServer != null; + joinButton.IsDisabled = () => !currentServer.IsJoinable; + joinButton.OnClick = () => Join(currentServer); + joinButtonY = joinButton.Bounds.Y; // Display the progress label over the server list // The text is only visible when the list is empty @@ -159,7 +166,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic refreshButton.OnClick = RefreshServerList; } - var mapPreview = widget.GetOrNull("SELECTED_MAP_PREVIEW"); + mapPreview = widget.GetOrNull("SELECTED_MAP_PREVIEW"); if (mapPreview != null) mapPreview.Preview = () => currentMap; @@ -201,10 +208,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic var players = widget.GetOrNull("SELECTED_PLAYERS"); if (players != null) { - players.IsVisible = () => currentServer != null; + players.IsVisible = () => currentServer != null && !currentServer.Clients.Any(); players.GetText = () => PlayersLabel(currentServer); } + clientContainer = widget.Get("CLIENT_LIST_CONTAINER"); + clientList = Ui.LoadWidget("MULTIPLAYER_CLIENT_LIST", clientContainer, new WidgetArgs()) as ScrollPanelWidget; + clientList.IsVisible = () => currentServer != null && currentServer.Clients.Any(); + clientHeader = clientList.Get("HEADER"); + clientTemplate = clientList.Get("TEMPLATE"); + clientList.RemoveChildren(); + var directConnectButton = widget.Get("DIRECTCONNECT_BUTTON"); directConnectButton.OnClick = () => { @@ -361,6 +375,86 @@ namespace OpenRA.Mods.Common.Widgets.Logic { currentServer = server; currentMap = server != null ? modData.MapCache[server.Map] : null; + + clientList.RemoveChildren(); + if (server == null || !server.Clients.Any()) + { + joinButton.Bounds.Y = joinButtonY; + return; + } + + joinButton.Bounds.Y = clientContainer.Bounds.Bottom; + + var players = server.Clients + .Where(c => !c.IsSpectator) + .GroupBy(p => p.Team) + .OrderBy(g => g.Key); + + var teams = new Dictionary>(); + var noTeams = players.Count() == 1; + foreach (var p in players) + { + var label = noTeams ? "Players" : p.Key == 0 ? "No Team" : "Team {0}".F(p.Key); + teams.Add(label, p); + } + + if (server.Clients.Any(c => c.IsSpectator)) + teams.Add("Spectators", server.Clients.Where(c => c.IsSpectator)); + + // Can only show factions if the server is running the same mod + var disableFactionDisplay = server.Mod != modData.Manifest.Id; + + if (mapPreview != null) + { + var spawns = currentMap.SpawnPoints; + var occupants = server.Clients + .Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length)) + .ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c, disableFactionDisplay)); + + mapPreview.SpawnOccupants = () => occupants; + } + + var factionInfo = modData.DefaultRules.Actors["world"].TraitInfos(); + foreach (var kv in teams) + { + var group = kv.Key; + if (group.Length > 0) + { + var header = ScrollItemWidget.Setup(clientHeader, () => true, () => { }); + header.Get("LABEL").GetText = () => group; + clientList.AddChild(header); + } + + foreach (var option in kv.Value) + { + var o = option; + + var item = ScrollItemWidget.Setup(clientTemplate, () => false, () => { }); + if (!o.IsSpectator && !disableFactionDisplay) + { + var label = item.Get("LABEL"); + var font = Game.Renderer.Fonts[label.Font]; + var name = WidgetUtils.TruncateText(o.Name, label.Bounds.Width, font); + label.GetText = () => name; + label.GetColor = () => o.Color.RGB; + + var flag = item.Get("FLAG"); + flag.IsVisible = () => true; + flag.GetImageCollection = () => "flags"; + flag.GetImageName = () => (factionInfo != null && factionInfo.Any(f => f.InternalName == o.Faction)) ? o.Faction : "Random"; + } + else + { + var label = item.Get("NOFLAG_LABEL"); + var font = Game.Renderer.Fonts[label.Font]; + var name = WidgetUtils.TruncateText(o.Name, label.Bounds.Width, font); + label.GetText = () => name; + label.GetColor = () => o.Color.RGB; + } + + clientList.AddChild(item); + } + } } void RefreshServerListInner(List games) diff --git a/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs b/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs index 54fb1f2d69..f152839cf6 100644 --- a/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs @@ -22,7 +22,6 @@ namespace OpenRA.Mods.Common.Widgets public class SpawnOccupant { public readonly HSLColor Color; - public readonly int ClientIndex; public readonly string PlayerName; public readonly int Team; public readonly string Faction; @@ -31,7 +30,6 @@ namespace OpenRA.Mods.Common.Widgets public SpawnOccupant(Session.Client client) { Color = client.Color; - ClientIndex = client.Index; PlayerName = client.Name; Team = client.Team; Faction = client.Faction; @@ -41,12 +39,20 @@ namespace OpenRA.Mods.Common.Widgets public SpawnOccupant(GameInformation.Player player) { Color = player.Color; - ClientIndex = player.ClientIndex; PlayerName = player.Name; Team = player.Team; Faction = player.FactionId; SpawnPoint = player.SpawnPoint; } + + public SpawnOccupant(GameClient player, bool suppressFaction) + { + Color = player.Color; + PlayerName = player.Name; + Team = player.Team; + Faction = !suppressFaction ? player.Faction : null; + SpawnPoint = player.SpawnPoint; + } } public class MapPreviewWidget : Widget diff --git a/mods/cnc/chrome/multiplayer-browser.yaml b/mods/cnc/chrome/multiplayer-browser.yaml index 4a13574d8d..17f0f24e87 100644 --- a/mods/cnc/chrome/multiplayer-browser.yaml +++ b/mods/cnc/chrome/multiplayer-browser.yaml @@ -118,6 +118,7 @@ Container@MULTIPLAYER_PANEL: Y: 1 Width: PARENT_RIGHT - 2 Height: PARENT_BOTTOM - 2 + TooltipContainer: TOOLTIP_CONTAINER Label@SELECTED_MAP: Y: 172 Width: PARENT_RIGHT @@ -148,6 +149,10 @@ Container@MULTIPLAYER_PANEL: Height: 25 Font: TinyBold Align: Center + Container@CLIENT_LIST_CONTAINER: + Y: 240 + Width: PARENT_RIGHT + Height: 230 Button@JOIN_BUTTON: Key: return Y: 255 @@ -185,49 +190,4 @@ Container@MULTIPLAYER_PANEL: Width: 140 Height: 35 Text: Back - TooltipContainer@TOOLTIP_CONTAINER: - -ScrollPanel@MULTIPLAYER_FILTER_PANEL: - Width: 147 - Height: 130 - Background: panel-black - Children: - Checkbox@WAITING_FOR_PLAYERS: - X: 5 - Y: 5 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Waiting - TextColor: 32CD32 - Font: Regular - Checkbox@EMPTY: - X: 5 - Y: 30 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Empty - Font: Regular - Checkbox@PASSWORD_PROTECTED: - X: 5 - Y: 55 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Protected - TextColor: FF0000 - Font: Regular - Checkbox@ALREADY_STARTED: - X: 5 - Y: 80 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Started - TextColor: FFA500 - Font: Regular - Checkbox@INCOMPATIBLE_VERSION: - X: 5 - Y: 105 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Incompatible - TextColor: BEBEBE - Font: Regular + TooltipContainer@TOOLTIP_CONTAINER: \ No newline at end of file diff --git a/mods/cnc/chrome/multiplayer-browserpanels.yaml b/mods/cnc/chrome/multiplayer-browserpanels.yaml new file mode 100644 index 0000000000..af3cccdbed --- /dev/null +++ b/mods/cnc/chrome/multiplayer-browserpanels.yaml @@ -0,0 +1,85 @@ +ScrollPanel@MULTIPLAYER_CLIENT_LIST: + Width: PARENT_RIGHT + Height: 225 + IgnoreChildMouseOver: true + Children: + ScrollItem@HEADER: + Width: PARENT_RIGHT - 27 + Height: 13 + X: 2 + Y: 0 + Visible: false + Children: + Label@LABEL: + Font: TinyBold + Width: PARENT_RIGHT + Height: 10 + Align: Center + ScrollItem@TEMPLATE: + Width: PARENT_RIGHT - 27 + Height: 25 + X: 2 + Y: 0 + Visible: false + Children: + Image@FLAG: + X: 4 + Y: 5 + Width: 32 + Height: 16 + Visible: False + Label@LABEL: + X: 40 + Width: PARENT_RIGHT - 50 + Height: 23 + Shadow: True + Label@NOFLAG_LABEL: + X: 5 + Width: PARENT_RIGHT + Height: 23 + Shadow: True + +ScrollPanel@MULTIPLAYER_FILTER_PANEL: + Width: 147 + Height: 130 + Background: panel-black + Children: + Checkbox@WAITING_FOR_PLAYERS: + X: 5 + Y: 5 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Waiting + TextColor: 32CD32 + Font: Regular + Checkbox@EMPTY: + X: 5 + Y: 30 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Empty + Font: Regular + Checkbox@PASSWORD_PROTECTED: + X: 5 + Y: 55 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Protected + TextColor: FF0000 + Font: Regular + Checkbox@ALREADY_STARTED: + X: 5 + Y: 80 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Started + TextColor: FFA500 + Font: Regular + Checkbox@INCOMPATIBLE_VERSION: + X: 5 + Y: 105 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Incompatible + TextColor: BEBEBE + Font: Regular \ No newline at end of file diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 9521f37d37..9b5c4d407d 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -90,6 +90,7 @@ Assemblies: ChromeLayout: cnc|chrome/mainmenu.yaml cnc|chrome/multiplayer-browser.yaml + cnc|chrome/multiplayer-browserpanels.yaml cnc|chrome/multiplayer-createserver.yaml cnc|chrome/multiplayer-directconnect.yaml cnc|chrome/lobby.yaml diff --git a/mods/common/chrome/multiplayer-browser.yaml b/mods/common/chrome/multiplayer-browser.yaml index 6c5469a28d..af0d470609 100644 --- a/mods/common/chrome/multiplayer-browser.yaml +++ b/mods/common/chrome/multiplayer-browser.yaml @@ -3,7 +3,7 @@ Background@MULTIPLAYER_PANEL: X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 Width: 808 - Height: 600 + Height: 550 Children: Label@TITLE: Y: 15 @@ -114,6 +114,7 @@ Background@MULTIPLAYER_PANEL: Y: 1 Width: PARENT_RIGHT - 2 Height: PARENT_BOTTOM - 2 + TooltipContainer: TOOLTIP_CONTAINER Label@SELECTED_MAP: Y: 172 Width: PARENT_RIGHT @@ -144,6 +145,10 @@ Background@MULTIPLAYER_PANEL: Height: 25 Font: TinyBold Align: Center + Container@CLIENT_LIST_CONTAINER: + Y: 240 + Width: PARENT_RIGHT + Height: 166 Button@JOIN_BUTTON: Key: return Y: 255 @@ -187,48 +192,4 @@ Background@MULTIPLAYER_PANEL: Height: 25 Text: Back Font: Bold - TooltipContainer@TOOLTIP_CONTAINER: - -ScrollPanel@MULTIPLAYER_FILTER_PANEL: - Width: 158 - Height: 130 - Children: - Checkbox@WAITING_FOR_PLAYERS: - X: 5 - Y: 5 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Waiting - TextColor: 32CD32 - Font: Regular - Checkbox@EMPTY: - X: 5 - Y: 30 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Empty - Font: Regular - Checkbox@PASSWORD_PROTECTED: - X: 5 - Y: 55 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Protected - TextColor: FF0000 - Font: Regular - Checkbox@ALREADY_STARTED: - X: 5 - Y: 80 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Started - TextColor: FFA500 - Font: Regular - Checkbox@INCOMPATIBLE_VERSION: - X: 5 - Y: 105 - Width: PARENT_RIGHT - 29 - Height: 20 - Text: Incompatible - TextColor: BEBEBE - Font: Regular \ No newline at end of file + TooltipContainer@TOOLTIP_CONTAINER: \ No newline at end of file diff --git a/mods/common/chrome/multiplayer-browserpanels.yaml b/mods/common/chrome/multiplayer-browserpanels.yaml new file mode 100644 index 0000000000..93133d3c1f --- /dev/null +++ b/mods/common/chrome/multiplayer-browserpanels.yaml @@ -0,0 +1,85 @@ +ScrollPanel@MULTIPLAYER_CLIENT_LIST: + Width: PARENT_RIGHT + Height: 159 + IgnoreChildMouseOver: true + Children: + ScrollItem@HEADER: + BaseName: scrollheader + Width: PARENT_RIGHT - 27 + Height: 13 + X: 2 + Y: 0 + Visible: false + Children: + Label@LABEL: + Font: TinyBold + Width: PARENT_RIGHT + Height: 10 + Align: Center + ScrollItem@TEMPLATE: + Width: PARENT_RIGHT - 27 + Height: 25 + X: 2 + Y: 0 + Visible: false + Children: + Image@FLAG: + X: 4 + Y: 6 + Width: 32 + Height: 16 + Visible: False + Label@LABEL: + X: 40 + Width: PARENT_RIGHT - 50 + Height: 23 + Shadow: True + Label@NOFLAG_LABEL: + X: 5 + Width: PARENT_RIGHT + Height: 23 + Shadow: True + +ScrollPanel@MULTIPLAYER_FILTER_PANEL: + Width: 158 + Height: 130 + Children: + Checkbox@WAITING_FOR_PLAYERS: + X: 5 + Y: 5 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Waiting + TextColor: 32CD32 + Font: Regular + Checkbox@EMPTY: + X: 5 + Y: 30 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Empty + Font: Regular + Checkbox@PASSWORD_PROTECTED: + X: 5 + Y: 55 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Protected + TextColor: FF0000 + Font: Regular + Checkbox@ALREADY_STARTED: + X: 5 + Y: 80 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Started + TextColor: FFA500 + Font: Regular + Checkbox@INCOMPATIBLE_VERSION: + X: 5 + Y: 105 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Incompatible + TextColor: BEBEBE + Font: Regular \ No newline at end of file diff --git a/mods/d2k/chrome/multiplayer-browserpanels.yaml b/mods/d2k/chrome/multiplayer-browserpanels.yaml new file mode 100644 index 0000000000..a5aa667577 --- /dev/null +++ b/mods/d2k/chrome/multiplayer-browserpanels.yaml @@ -0,0 +1,84 @@ +ScrollPanel@MULTIPLAYER_CLIENT_LIST: + Width: PARENT_RIGHT + Height: 159 + IgnoreChildMouseOver: true + Children: + ScrollItem@HEADER: + BaseName: scrollheader + Width: PARENT_RIGHT - 27 + Height: 13 + X: 2 + Y: 0 + Visible: false + Children: + Label@LABEL: + Font: TinyBold + Width: PARENT_RIGHT + Height: 10 + Align: Center + ScrollItem@TEMPLATE: + Width: PARENT_RIGHT - 27 + Height: 25 + X: 2 + Y: 0 + Visible: false + Children: + Image@FLAG: + X: 4 + Y: 2 + Width: 32 + Height: 16 + Visible: False + Label@LABEL: + X: 35 + Width: PARENT_RIGHT - 45 + Height: 23 + Shadow: True + Label@NOFLAG_LABEL: + X: 5 + Width: PARENT_RIGHT + Height: 23 + +ScrollPanel@MULTIPLAYER_FILTER_PANEL: + Width: 158 + Height: 130 + Children: + Checkbox@WAITING_FOR_PLAYERS: + X: 5 + Y: 5 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Waiting + TextColor: 32CD32 + Font: Regular + Checkbox@EMPTY: + X: 5 + Y: 30 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Empty + Font: Regular + Checkbox@PASSWORD_PROTECTED: + X: 5 + Y: 55 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Protected + TextColor: FF0000 + Font: Regular + Checkbox@ALREADY_STARTED: + X: 5 + Y: 80 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Started + TextColor: FFA500 + Font: Regular + Checkbox@INCOMPATIBLE_VERSION: + X: 5 + Y: 105 + Width: PARENT_RIGHT - 29 + Height: 20 + Text: Incompatible + TextColor: BEBEBE + Font: Regular \ No newline at end of file diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index fb675a42b2..6a026281ce 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -91,6 +91,7 @@ ChromeLayout: common|chrome/color-picker.yaml common|chrome/map-chooser.yaml common|chrome/multiplayer-browser.yaml + d2k|chrome/multiplayer-browserpanels.yaml common|chrome/multiplayer-createserver.yaml common|chrome/multiplayer-directconnect.yaml common|chrome/connection.yaml diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index d23e8a8352..c15a179caf 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -106,6 +106,7 @@ ChromeLayout: common|chrome/color-picker.yaml common|chrome/map-chooser.yaml common|chrome/multiplayer-browser.yaml + common|chrome/multiplayer-browserpanels.yaml common|chrome/multiplayer-createserver.yaml common|chrome/multiplayer-directconnect.yaml common|chrome/connection.yaml diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index cd1f69b472..a1de169280 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -154,6 +154,7 @@ ChromeLayout: ts|chrome/color-picker.yaml common|chrome/map-chooser.yaml common|chrome/multiplayer-browser.yaml + common|chrome/multiplayer-browserpanels.yaml common|chrome/multiplayer-createserver.yaml common|chrome/multiplayer-directconnect.yaml common|chrome/connection.yaml