diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index 42fccfd005..d9535b0ac6 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -529,10 +529,11 @@ namespace OpenRA.Mods.Common.Server }; // Pick a random color for the bot - var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); + var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); var terrainColors = server.ModData.DefaultTerrainInfo[server.Map.TileSet].RestrictedPlayerColors; var playerColors = server.LobbyInfo.Clients.Select(c => c.Color) .Concat(server.Map.Players.Players.Values.Select(p => p.Color)); + bot.Color = bot.PreferredColor = colorManager.RandomPresetColor(server.Random, terrainColors, playerColors); server.LobbyInfo.Clients.Add(bot); @@ -1239,7 +1240,7 @@ namespace OpenRA.Mods.Common.Server { lock (server.LobbyInfo) { - var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); + var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); var askColor = askedColor; void OnError(string message) diff --git a/OpenRA.Mods.Common/Traits/Palettes/ColorPickerPalette.cs b/OpenRA.Mods.Common/Traits/Palettes/ColorPickerPalette.cs index 384906ad1e..bba181ee81 100644 --- a/OpenRA.Mods.Common/Traits/Palettes/ColorPickerPalette.cs +++ b/OpenRA.Mods.Common/Traits/Palettes/ColorPickerPalette.cs @@ -44,19 +44,22 @@ namespace OpenRA.Mods.Common.Traits class ColorPickerPalette : ILoadsPalettes, IProvidesAssetBrowserColorPickerPalettes, ITickRender { readonly ColorPickerPaletteInfo info; - readonly ColorPickerManagerInfo colorManager; Color color; + Color preferredColor; public ColorPickerPalette(ColorPickerPaletteInfo info) { - // All users need to use the same TraitInfo instance, chosen as the default mod rules - colorManager = Game.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); this.info = info; + + // All users need to use the same TraitInfo instance, chosen as the default mod rules + var colorManager = Game.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo(); + colorManager.OnColorPickerColorUpdate += c => preferredColor = c; + preferredColor = Game.Settings.Player.Color; } void ILoadsPalettes.LoadPalettes(WorldRenderer wr) { - color = colorManager.Color; + color = preferredColor; var remap = new PlayerColorRemap(info.RemapIndex.Length == 0 ? Enumerable.Range(0, 256).ToArray() : info.RemapIndex, color); wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers); } @@ -65,10 +68,10 @@ namespace OpenRA.Mods.Common.Traits void ITickRender.TickRender(WorldRenderer wr, Actor self) { - if (color == colorManager.Color) + if (color == preferredColor) return; - color = colorManager.Color; + color = preferredColor; var remap = new PlayerColorRemap(info.RemapIndex.Length == 0 ? Enumerable.Range(0, 256).ToArray() : info.RemapIndex, color); wr.ReplacePalette(info.Name, new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap)); } diff --git a/OpenRA.Mods.Common/Traits/World/ColorPickerManager.cs b/OpenRA.Mods.Common/Traits/World/ColorPickerManager.cs index fba52d08d9..fc65e40e0a 100644 --- a/OpenRA.Mods.Common/Traits/World/ColorPickerManager.cs +++ b/OpenRA.Mods.Common/Traits/World/ColorPickerManager.cs @@ -12,15 +12,18 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Traits; +using OpenRA.Widgets; namespace OpenRA.Mods.Common.Traits { [TraitLocation(SystemActors.World)] [Desc("Configuration options for the lobby player color picker. Attach this to the world actor.")] - public class ColorPickerManagerInfo : TraitInfo + public class ColorPickerManagerInfo : TraitInfo, IColorPickerManagerInfo { [TranslationReference] const string PlayerColorTerrain = "notification-player-color-terrain"; @@ -52,9 +55,7 @@ namespace OpenRA.Mods.Common.Traits "A dictionary of [faction name]: [actor name].")] public readonly Dictionary FactionPreviewActors = new(); - public Color Color; - - bool TryGetBlockingColor((float R, float G, float B) color, List<(float R, float G, float B)> candidateBlockers, out (float R, float G, float B) closestBlocker) + public bool TryGetBlockingColor((float R, float G, float B) color, List<(float R, float G, float B)> candidateBlockers, out (float R, float G, float B) closestBlocker) { var closestDistance = SimilarityThreshold; closestBlocker = default; @@ -82,40 +83,6 @@ namespace OpenRA.Mods.Common.Traits return closestDistance < SimilarityThreshold; } - public Color RandomPresetColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors) - { - var terrainLinear = terrainColors.Select(c => c.ToLinear()).ToList(); - var playerLinear = playerColors.Select(c => c.ToLinear()).ToList(); - - foreach (var color in PresetColors.Shuffle(random)) - { - // Color may already be taken - var linear = color.ToLinear(); - if (!TryGetBlockingColor(linear, terrainLinear, out _) && !TryGetBlockingColor(linear, playerLinear, out _)) - return color; - } - - // Fall back to a random non-preset color - var randomHue = random.NextFloat(); - var randomSat = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat()); - var randomVal = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); - return MakeValid(randomHue, randomSat, randomVal, random, terrainLinear, playerLinear, null); - } - - public Color RandomValidColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors) - { - var h = random.NextFloat(); - var s = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat()); - var v = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); - return MakeValid(h, s, v, random, terrainColors, playerColors, null); - } - - public Color MakeValid(Color color, MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors, Action onError = null) - { - var (_, h, s, v) = color.ToAhsv(); - return MakeValid(h, s, v, random, terrainColors, playerColors, onError); - } - Color MakeValid(float hue, float sat, float val, MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors, Action onError) { var terrainLinear = terrainColors.Select(c => c.ToLinear()).ToList(); @@ -164,6 +131,97 @@ namespace OpenRA.Mods.Common.Traits var randomVal = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); return Color.FromAhsv(random.NextFloat(), randomSat, randomVal); } + + #region IColorPickerManagerInfo + + public event Action OnColorPickerColorUpdate; + + (float sMin, float sMax) IColorPickerManagerInfo.SaturationRange => (HsvSaturationRange[0], HsvSaturationRange[1]); + (float vMin, float vMax) IColorPickerManagerInfo.ValueRange => (HsvValueRange[0], HsvValueRange[1]); + + Color[] IColorPickerManagerInfo.PresetColors => PresetColors; + + Color IColorPickerManagerInfo.RandomPresetColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors) + { + var terrainLinear = terrainColors.Select(c => c.ToLinear()).ToList(); + var playerLinear = playerColors.Select(c => c.ToLinear()).ToList(); + + foreach (var color in PresetColors.Shuffle(random)) + { + // Color may already be taken + var linear = color.ToLinear(); + if (!TryGetBlockingColor(linear, terrainLinear, out _) && !TryGetBlockingColor(linear, playerLinear, out _)) + return color; + } + + // Fall back to a random non-preset color + var randomHue = random.NextFloat(); + var randomSat = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat()); + var randomVal = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); + return MakeValid(randomHue, randomSat, randomVal, random, terrainLinear, playerLinear, null); + } + + Color IColorPickerManagerInfo.MakeValid(Color color, MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors, Action onError) + { + var (_, h, s, v) = color.ToAhsv(); + return MakeValid(h, s, v, random, terrainColors, playerColors, onError); + } + + Color IColorPickerManagerInfo.RandomValidColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors) + { + var h = random.NextFloat(); + var s = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat()); + var v = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); + return MakeValid(h, s, v, random, terrainColors, playerColors, null); + } + + void IColorPickerManagerInfo.ShowColorDropDown(DropDownButtonWidget dropdownButton, Color initialColor, string initialFaction, WorldRenderer worldRenderer, Action onExit) + { + dropdownButton.RemovePanel(); + + // We do not want to force other ColorPickerManager implementations to have an Actor preview. + // We achieve this by fully encapsulating its initialisation. + void AddActorPreview(Widget parent) + { + var preview = parent.GetOrNull("PREVIEW"); + if (preview == null) + return; + + if (initialFaction == null || !FactionPreviewActors.TryGetValue(initialFaction, out var actorType)) + { + if (PreviewActor == null) + throw new YamlException($"{nameof(ColorPickerManager)} does not define a preview actor" + (initialFaction == null ? "." : $"for faction {initialFaction}.")); + + actorType = PreviewActor; + } + + var actor = worldRenderer.World.Map.Rules.Actors[actorType]; + + var td = new TypeDictionary + { + new OwnerInit(worldRenderer.World.WorldActor.Owner), + new FactionInit(worldRenderer.World.WorldActor.Owner.PlayerReference.Faction) + }; + + foreach (var api in actor.TraitInfos()) + foreach (var o in api.ActorPreviewInits(actor, ActorPreviewType.ColorPicker)) + td.Add(o); + + preview.SetPreview(actor, td); + } + + var finalColor = initialColor; + var colorChooser = Game.LoadWidget(worldRenderer.World, "COLOR_CHOOSER", null, new WidgetArgs() + { + { "onChange", (Action)(c => { finalColor = c; OnColorPickerColorUpdate(c); }) }, + { "initialColor", initialColor }, + { "extraLogic", (Action)AddActorPreview }, + }); + + dropdownButton.AttachPanel(colorChooser, () => onExit(finalColor)); + } + + #endregion } public class ColorPickerManager { } diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 2a44051d9f..bca48f2bf0 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -16,7 +16,9 @@ using OpenRA.Graphics; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Terrain; +using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -290,6 +292,18 @@ namespace OpenRA.Mods.Common.Traits IEnumerable ColorPickerPaletteNames { get; } } + public interface IColorPickerManagerInfo : ITraitInfoInterface + { + (float sMin, float sMax) SaturationRange { get; } + (float vMin, float vMax) ValueRange { get; } + event Action OnColorPickerColorUpdate; + Color[] PresetColors { get; } + Color RandomPresetColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors); + Color RandomValidColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors); + Color MakeValid(Color color, MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors, Action onError = null); + void ShowColorDropDown(DropDownButtonWidget dropdownButton, Color initialColor, string initialFaction, WorldRenderer worldRenderer, Action onExit); + } + public interface ICallForTransport { WDist MinimumDistance { get; } diff --git a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs index 94c932ed7e..76938f84a0 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs @@ -177,16 +177,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic panel.GetOrNull("PALETTE_DESC").IsVisible = () => currentSprites != null || currentVoxel != null; } - var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); - colorManager.Color = Game.Settings.Player.Color; + var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); var colorDropdown = panel.GetOrNull("COLOR"); if (colorDropdown != null) { + var color = Game.Settings.Player.Color; colorDropdown.IsDisabled = () => !colorPickerPalettes.Contains(currentPalette); - colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorManager, worldRenderer); + colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, color, null, worldRenderer, c => color = c); colorDropdown.IsVisible = () => currentSprites != null || currentVoxel != null; - panel.Get("COLORBLOCK").GetColor = () => colorManager.Color; + + panel.Get("COLORBLOCK").GetColor = () => color; } filenameInput = panel.Get("FILENAME_INPUT"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs index dbaa17d31f..88174a785a 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Widgets; @@ -25,7 +24,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic int paletteTabHighlighted = 0; [ObjectCreator.UseCtor] - public ColorPickerLogic(Widget widget, ModData modData, World world, Color initialColor, string initialFaction, Action onChange, + public ColorPickerLogic(Widget widget, ModData modData, World world, Color initialColor, Action onChange, Action extraLogic, Dictionary logicArgs) { var mixer = widget.Get("MIXER"); @@ -33,14 +32,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic // Set the initial state // All users need to use the same TraitInfo instance, chosen as the default mod rules - var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); - mixer.SetColorLimits(colorManager.HsvSaturationRange[0], colorManager.HsvSaturationRange[1], colorManager.HsvValueRange[0], colorManager.HsvValueRange[1]); + var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); + + var (sMin, sMax) = colorManager.SaturationRange; + var (vMin, vMax) = colorManager.ValueRange; + mixer.SetColorLimits(sMin, sMax, vMin, vMax); mixer.OnChange += () => onChange(mixer.Color); mixer.Set(initialColor); hueSlider.OnChange += h => { - mixer.SetColorLimits(colorManager.HsvSaturationRange[0], colorManager.HsvSaturationRange[1], colorManager.HsvValueRange[0], colorManager.HsvValueRange[1], h); + mixer.SetColorLimits(sMin, sMax, vMin, vMax, h); var (_, _, s, v) = mixer.Color.ToAhsv(); mixer.Set(Color.FromAhsv(h, s, v)); onChange(mixer.Color); @@ -64,34 +66,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic }; } - if (initialFaction == null || !colorManager.FactionPreviewActors.TryGetValue(initialFaction, out var actorType)) - actorType = colorManager.PreviewActor; - - if (actorType == null) - { - var message = "ColorPickerManager does not define a preview actor"; - if (initialFaction != null) - message += " for faction " + initialFaction; - message += "!"; - - throw new YamlException(message); - } - - var preview = widget.GetOrNull("PREVIEW"); - var actor = world.Map.Rules.Actors[actorType]; - - var td = new TypeDictionary - { - new OwnerInit(world.WorldActor.Owner), - new FactionInit(world.WorldActor.Owner.PlayerReference.Faction) - }; - - foreach (var api in actor.TraitInfos()) - foreach (var o in api.ActorPreviewInits(actor, ActorPreviewType.ColorPicker)) - td.Add(o); - - preview?.SetPreview(actor, td); - // HACK: the value returned from the color mixer will generally not // be equal to the given initialColor due to its internal RGB -> HSL -> RGB // conversion. This conversion can sometimes convert a valid initial value @@ -205,20 +179,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic paletteTabHighlighted = 4; }; } - } - public static void ShowColorDropDown(DropDownButtonWidget color, ColorPickerManagerInfo colorManager, WorldRenderer worldRenderer, Action onExit = null) - { - color.RemovePanel(); - - var colorChooser = Game.LoadWidget(worldRenderer.World, "COLOR_CHOOSER", null, new WidgetArgs() - { - { "onChange", (Action)(c => colorManager.Color = c) }, - { "initialColor", colorManager.Color }, - { "initialFaction", null } - }); - - color.AttachPanel(colorChooser, onExit); + // Attach logic to preview actor. + extraLogic(widget); } public override void Tick() diff --git a/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs index fc1c724259..dbdd120894 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs @@ -76,9 +76,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic return true; }; - var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); - colorManager.Color = ps.Color; - var mouseControlDescClassic = widget.Get("MOUSE_CONTROL_DESC_CLASSIC"); mouseControlDescClassic.IsVisible = () => gs.UseClassicMouseStyle; @@ -114,11 +111,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic SettingsUtils.BindCheckboxPref(widget, "EDGESCROLL_CHECKBOX", gs, "ViewportEdgeScroll"); + var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); + var colorDropdown = widget.Get("PLAYERCOLOR"); colorDropdown.IsDisabled = () => worldRenderer.World.Type != WorldType.Shellmap; - colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorManager, worldRenderer, () => + colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, ps.Color, null, worldRenderer, color => { - Game.Settings.Player.Color = colorManager.Color; + ps.Color = color; Game.Settings.Save(); }); colorDropdown.Get("COLORBLOCK").GetColor = () => ps.Color; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 68f675c3dd..09cd8ae1f6 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly Dictionary factions = new(); - readonly ColorPickerManagerInfo colorManager; + readonly IColorPickerManagerInfo colorManager; readonly TabCompletionLogic tabCompletion = new(); @@ -198,8 +198,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic editableSpectatorTemplate = players.Get("TEMPLATE_EDITABLE_SPECTATOR"); nonEditableSpectatorTemplate = players.Get("TEMPLATE_NONEDITABLE_SPECTATOR"); newSpectatorTemplate = players.Get("TEMPLATE_NEW_SPECTATOR"); - colorManager = modRules.Actors[SystemActors.World].TraitInfo(); - colorManager.Color = Game.Settings.Player.Color; + colorManager = modRules.Actors[SystemActors.World].TraitInfo(); foreach (var f in modRules.Actors[SystemActors.World].TraitInfos()) factions.Add(f.InternalName, new LobbyFaction { Selectable = f.Selectable, Name = f.Name, Side = f.Side, Description = f.Description }); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs index 06cb6b9fa8..2364174fd6 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs @@ -241,31 +241,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic dropdown.ShowDropDown("FACTION_DROPDOWN_TEMPLATE", 154, options, SetupItem); } - public static void ShowColorDropDown(DropDownButtonWidget color, Session.Client client, - OrderManager orderManager, WorldRenderer worldRenderer, ColorPickerManagerInfo colorManager) - { - void OnExit() - { - if (client == orderManager.LocalClient) - { - Game.Settings.Player.Color = colorManager.Color; - Game.Settings.Save(); - } - - color.RemovePanel(); - orderManager.IssueOrder(Order.Command($"color {client.Index} {colorManager.Color}")); - } - - var colorChooser = Game.LoadWidget(worldRenderer.World, "COLOR_CHOOSER", null, new WidgetArgs() - { - { "onChange", (Action)(c => colorManager.Color = c) }, - { "initialColor", client.Color }, - { "initialFaction", client.Faction } - }); - - color.AttachPanel(colorChooser, OnExit); - } - public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) { if (orderManager.LocalClient.State == Session.ClientState.Ready) @@ -544,13 +519,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic }; } - public static void SetupEditableColorWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer, ColorPickerManagerInfo colorManager) + public static void SetupEditableColorWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer, IColorPickerManagerInfo colorManager) { - var color = parent.Get("COLOR"); - color.IsDisabled = () => (s != null && s.LockColor) || orderManager.LocalClient.IsReady; - color.OnMouseDown = _ => ShowColorDropDown(color, c, orderManager, worldRenderer, colorManager); + var colorDropdown = parent.Get("COLOR"); + colorDropdown.IsDisabled = () => (s != null && s.LockColor) || orderManager.LocalClient.IsReady; + colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, c.Color, c.Faction, worldRenderer, color => + { + if (c == orderManager.LocalClient) + { + Game.Settings.Player.Color = color; + Game.Settings.Save(); + } - SetupColorWidget(color, c); + orderManager.IssueOrder(Order.Command($"color {c.Index} {color}")); + }); + + SetupColorWidget(colorDropdown, c); } public static void SetupColorWidget(Widget parent, Session.Client c) diff --git a/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs index d9a1a5b98f..f32634c9a4 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs @@ -268,14 +268,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic return true; }; - var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); - colorManager.Color = ps.Color; + var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo(); var colorDropdown = panel.Get("PLAYERCOLOR"); colorDropdown.IsDisabled = () => worldRenderer.World.Type != WorldType.Shellmap; - colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorManager, worldRenderer, () => + colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, ps.Color, null, worldRenderer, color => { - Game.Settings.Player.Color = colorManager.Color; + ps.Color = color; Game.Settings.Save(); }); colorDropdown.Get("COLORBLOCK").GetColor = () => ps.Color;