From 19dd1bb497b96ea57508d6d2d6ebb9dfc399293c Mon Sep 17 00:00:00 2001 From: Az <56699741+AlchlcDvl@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:18:56 -0400 Subject: [PATCH] fix mentioned issues + add more functionality --- MiraAPI.Example/ExampleColors.cs | 2 +- MiraAPI.Example/Resources/Locale/en_US.xml | 1 + MiraAPI/Colors/CustomColor.cs | 5 ++ MiraAPI/Colors/PaletteManager.cs | 78 +++++++++++++--- MiraAPI/Colors/VariableColor.cs | 17 ++-- MiraAPI/Colors/VariableColorBehaviour.cs | 88 +++++++++++++++---- .../{Hud => Colors}/VariableColorPatches.cs | 22 +++-- 7 files changed, 167 insertions(+), 46 deletions(-) rename MiraAPI/Patches/{Hud => Colors}/VariableColorPatches.cs (83%) diff --git a/MiraAPI.Example/ExampleColors.cs b/MiraAPI.Example/ExampleColors.cs index 1a5efec..297a370 100644 --- a/MiraAPI.Example/ExampleColors.cs +++ b/MiraAPI.Example/ExampleColors.cs @@ -17,7 +17,7 @@ public static class ExampleColors public static CustomColor Gold { get; } = new("color.gold", new Color(1.0f, 0.84f, 0.0f)); - public static VariableColor Rainbow { get; } = new("color.rainbow", t => new HsbColor(MathUtilities.PingPong(t, 1f), 1f, 1f)) + public static VariableColor Rainbow { get; } = new("color.rainbow", t => new HsbColor(MathUtilities.PingPong(t, 1f, 0.3f), 1f, 1f)) { ColorBrightness = CustomColorBrightness.Lighter, }; diff --git a/MiraAPI.Example/Resources/Locale/en_US.xml b/MiraAPI.Example/Resources/Locale/en_US.xml index e370dc3..d44100c 100644 --- a/MiraAPI.Example/Resources/Locale/en_US.xml +++ b/MiraAPI.Example/Resources/Locale/en_US.xml @@ -80,4 +80,5 @@ Eliminate every other faction. Cerulean Rose Gold + Rainbow diff --git a/MiraAPI/Colors/CustomColor.cs b/MiraAPI/Colors/CustomColor.cs index ea54e72..db91356 100644 --- a/MiraAPI/Colors/CustomColor.cs +++ b/MiraAPI/Colors/CustomColor.cs @@ -80,6 +80,11 @@ public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColo /// public enum CustomColorBrightness { + /// + /// An invalid color. + /// + Invalid = -1, + /// /// A lighter color. /// diff --git a/MiraAPI/Colors/PaletteManager.cs b/MiraAPI/Colors/PaletteManager.cs index 9127bb6..3b9cd4a 100644 --- a/MiraAPI/Colors/PaletteManager.cs +++ b/MiraAPI/Colors/PaletteManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using HarmonyLib; using UnityEngine; @@ -17,25 +18,45 @@ public static class PaletteManager internal static readonly List CustomColors = []; internal static readonly HashSet VariableColorNames = []; - internal static readonly Dictionary ColorIdToColorMap = []; + + private static readonly CustomColorBrightness[] ColorBrightnessMap = + [ + CustomColorBrightness.Darker, // Red + CustomColorBrightness.Darker, // Blue + CustomColorBrightness.Darker, // Green + CustomColorBrightness.Lighter, // Pink + CustomColorBrightness.Lighter, // Orange + CustomColorBrightness.Lighter, // Yellow + CustomColorBrightness.Darker, // Black + CustomColorBrightness.Lighter, // White + CustomColorBrightness.Darker, // Purple + CustomColorBrightness.Darker, // Brown + CustomColorBrightness.Lighter, // Cyan + CustomColorBrightness.Lighter, // Lime + CustomColorBrightness.Darker, // Maroon + CustomColorBrightness.Lighter, // Rose + CustomColorBrightness.Lighter, // Banana + CustomColorBrightness.Darker, // Gray + CustomColorBrightness.Darker, // Tan + CustomColorBrightness.Lighter, // Coral + ]; + + private static int originalLength; internal static void RegisterAllColors() { + originalLength = Palette.PlayerColors.Length; + var colors = CustomColors.Select(x => x.MainColor).ToArray(); var shadowColors = CustomColors.Select(x => x.ShadowColor).ToArray(); var stringNames = CustomColors.Select(x => x.Name).ToArray(); - var originalLength = Palette.PlayerColors.Length; - Palette.PlayerColors = Palette.PlayerColors.ToArray().AddRangeToArray(colors); Palette.ShadowColors = Palette.ShadowColors.ToArray().AddRangeToArray(shadowColors); Palette.ColorNames = Palette.ColorNames.ToArray().AddRangeToArray(stringNames); Palette.TextColors = Palette.TextColors.ToArray().AddRangeToArray(colors); Palette.TextOutlineColors = Palette.TextOutlineColors.ToArray().AddRangeToArray(shadowColors); - - for (var i = 0; i < CustomColors.Count; i++) - ColorIdToColorMap[i + originalLength] = CustomColors[i]; } /// @@ -45,7 +66,7 @@ public static class PaletteManager /// true if the color is a variable color; false otherwise. public static bool IsVariable(int colorId) { - if (colorId < 0 || colorId >= Palette.ColorNames.Length) + if ((uint)colorId >= (uint)Palette.ColorNames.Length) return false; return VariableColorNames.Contains(Palette.ColorNames[colorId]); @@ -54,11 +75,11 @@ public static class PaletteManager /// /// Checks to see if the provided color ID belongs to a custom color. /// - /// The id of the color. + /// The ID of the color. /// true if the color is a custom color; false otherwise. public static bool IsCustomColor(int colorId) { - return ColorIdToColorMap.ContainsKey(colorId); + return (uint)(colorId - originalLength) < (uint)CustomColors.Count; } /// @@ -68,10 +89,10 @@ public static class PaletteManager /// The main color associated with the provided ID. public static Color GetMainColor(int colorId) { - if (colorId < 0 || colorId >= Palette.ColorNames.Length) + if ((uint)colorId >= (uint)Palette.ColorNames.Length) return Color.white; - return !ColorIdToColorMap.TryGetValue(colorId, out var custom) + return !TryGetCustomColor(colorId, out var custom) ? Palette.PlayerColors[colorId] : (custom is VariableColor variable ? variable.EvaluateMainColor(Time.time) @@ -81,17 +102,46 @@ public static class PaletteManager /// /// Gets the shadow color of the provided color ID. /// - /// The id of the color. + /// The ID of the color. /// The shadow color associated with the provided ID. public static Color GetShadowColor(int colorId) { - if (colorId < 0 || colorId >= Palette.ColorNames.Length) + if ((uint)colorId >= (uint)Palette.ColorNames.Length) return Color.white; - return !ColorIdToColorMap.TryGetValue(colorId, out var custom) + return !TryGetCustomColor(colorId, out var custom) ? Palette.ShadowColors[colorId] : (custom is VariableColor variable ? variable.EvaluateShadowColor(Time.time) : custom.InternalShadowColor); } + + /// + /// Gets the brightness type of the color associated with the provided ID. + /// + /// The ID of the color. + /// The brightness type of the provided ID. + public static CustomColorBrightness GetBrightness(int colorId) + { + if ((uint)colorId >= (uint)Palette.ColorNames.Length) + return CustomColorBrightness.Invalid; + + return TryGetCustomColor(colorId, out var custom) + ? custom.ColorBrightness + : ColorBrightnessMap[colorId]; + } + + internal static bool TryGetCustomColor(int colorId, [NotNullWhen(true)] out CustomColor? custom) + { + var index = colorId - originalLength; + + if ((uint)index >= (uint)CustomColors.Count) + { + custom = null; + return false; + } + + custom = CustomColors[index]; + return true; + } } diff --git a/MiraAPI/Colors/VariableColor.cs b/MiraAPI/Colors/VariableColor.cs index 264b06e..1ca610f 100644 --- a/MiraAPI/Colors/VariableColor.cs +++ b/MiraAPI/Colors/VariableColor.cs @@ -14,8 +14,9 @@ namespace MiraAPI.Colors; /// The function to evaluate the dynamic shadow color. /// The static main color used when dynamic colors are disabled. /// The static shadow color used when dynamic colors are disabled. -public sealed class VariableColor(StringNames name, Func mainEvaluator, Func? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null) - : CustomColor(name, mainColor ?? mainEvaluator(0f), shadowColor ?? shadowEvaluator?.Invoke(0f) ?? (mainColor ?? mainEvaluator(0f)).GetShadowColor(60)) +/// The default time that is used to automatically fill in the static colors when the latter are not provided. +public sealed class VariableColor(StringNames name, Func mainEvaluator, Func? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null, float defaultTime = 0f) + : CustomColor(name, mainColor ?? mainEvaluator(defaultTime), shadowColor ?? shadowEvaluator?.Invoke(defaultTime) ?? (mainColor ?? mainEvaluator(defaultTime)).GetShadowColor(60)) { /// /// Gets or sets a delegate that takes in a time value and returns the dynamic main color. @@ -28,20 +29,20 @@ public sealed class VariableColor(StringNames name, Func mainEvalu public Func ShadowEvaluator { get; set; } = shadowEvaluator ?? (t => mainEvaluator(t).GetShadowColor(0.24f)); /// - public VariableColor(StringNames name, Func mainEvaluator, Color32? mainColor = null) - : this(name, mainEvaluator, null, mainColor, null) + public VariableColor(StringNames name, Func mainEvaluator, Color32? mainColor = null, float defaultTime = 0f) + : this(name, mainEvaluator, null, mainColor, null, defaultTime) { } /// - public VariableColor(string name, Func mainEvaluator, Color32? mainColor = null) - : this(name, mainEvaluator, null, mainColor, null) + public VariableColor(string name, Func mainEvaluator, Color32? mainColor = null, float defaultTime = 0f) + : this(name, mainEvaluator, null, mainColor, null, defaultTime) { } /// - public VariableColor(string name, Func mainEvaluator, Func? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null) - : this(MiraLocaleManager.GetOrCreateLocaleString(name), mainEvaluator, shadowEvaluator, mainColor, shadowColor) + public VariableColor(string name, Func mainEvaluator, Func? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null, float defaultTime = 0f) + : this(MiraLocaleManager.GetOrCreateLocaleString(name), mainEvaluator, shadowEvaluator, mainColor, shadowColor, defaultTime) { } diff --git a/MiraAPI/Colors/VariableColorBehaviour.cs b/MiraAPI/Colors/VariableColorBehaviour.cs index d827e61..e0d4cea 100644 --- a/MiraAPI/Colors/VariableColorBehaviour.cs +++ b/MiraAPI/Colors/VariableColorBehaviour.cs @@ -8,43 +8,95 @@ using UnityEngine; namespace MiraAPI; /// -/// A mono script that adjusts the material colors of a component that it's attached to based on the provided variable color. +/// The base class for variable color behaviour on s. /// -[RegisterInIl2Cpp] [SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")] [SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity fields.")] [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")] -public sealed class VariableColorBehaviour : MonoBehaviour +public abstract class BaseVariableColorBehaviour : MonoBehaviour { - private SpriteRenderer rend; - private VariableColor? color; - - private static readonly Color VisorColor = Palette.VisorColor; + /// + /// The to apply. + /// + protected VariableColor? color; /// /// Sets the current variable color. /// - /// The new variable color. + /// The new . [HideFromIl2Cpp] - public void SetColor(VariableColor? col) + public void SetColor(VariableColor? newColor) { - color = col; + color = newColor; + } +} + +/// +/// A mono script that adjusts the material colors of a component that it's attached to based on the provided variable color. +/// +[RegisterInIl2Cpp] +[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")] +public sealed class VariableColorBehaviour : BaseVariableColorBehaviour +{ + private Renderer? rend; + + private static readonly Color VisorColor = Palette.VisorColor; + + /// + /// Sets the new target. + /// + /// The new that the script must target. + public void SetRend(Renderer? newRend) + { + rend = newRend; + } + + private void Awake() + { + rend = GetComponent(); + } + + private void Update() + { + if (color == null || rend == null) + return; + + var time = Time.time; + var material = rend.material; + + material.SetColor(ShaderID.VisorColor, VisorColor); + + material.SetColor(ShaderID.BodyColor, color.EvaluateMainColor(time)); + material.SetColor(ShaderID.BackColor, color.EvaluateShadowColor(time)); + } +} + +/// +/// A mono script that adjusts the graphic colors of a component that it's attached to based on the provided variable color. +/// +[RegisterInIl2Cpp] +[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")] +public sealed class BasicVariableColorBehaviour : BaseVariableColorBehaviour +{ + private SpriteRenderer? rend; + + /// + /// Sets the new target. + /// + /// The new that the script must target. + public void SetRend(SpriteRenderer? newRend) + { + rend = newRend; } private void Awake() { rend = GetComponent(); - rend.material.SetColor(ShaderID.VisorColor, VisorColor); } private void Update() { - if (!rend || color == null) - return; - - var time = Time.time; - var material = rend.material; - material.SetColor(ShaderID.BodyColor, color.EvaluateMainColor(time)); - material.SetColor(ShaderID.BackColor, color.EvaluateShadowColor(time)); + if (color != null && rend != null) + rend.color = color.EvaluateMainColor(Time.time); } } diff --git a/MiraAPI/Patches/Hud/VariableColorPatches.cs b/MiraAPI/Patches/Colors/VariableColorPatches.cs similarity index 83% rename from MiraAPI/Patches/Hud/VariableColorPatches.cs rename to MiraAPI/Patches/Colors/VariableColorPatches.cs index 9bf9e32..cf64d6d 100644 --- a/MiraAPI/Patches/Hud/VariableColorPatches.cs +++ b/MiraAPI/Patches/Colors/VariableColorPatches.cs @@ -7,7 +7,7 @@ using MiraAPI.Utilities; using Reactor.Utilities.Extensions; using UnityEngine; -namespace MiraAPI.Patches.Hud; +namespace MiraAPI.Patches.Colors; [HarmonyPatch(typeof(PlayerMaterial))] internal static class SetPlayerMaterialPatch @@ -16,7 +16,7 @@ internal static class SetPlayerMaterialPatch public static bool Prefix(int colorId, Renderer rend) { rend.gameObject.GetOrAddComponent().SetColor( - PaletteManager.ColorIdToColorMap.TryGetValue(colorId, out var color) && color is VariableColor variable + PaletteManager.TryGetCustomColor(colorId, out var color) && color is VariableColor variable ? variable : null); return !PaletteManager.IsVariable(colorId); @@ -48,11 +48,19 @@ internal static class ChatNotifRainbowPatch public static void Postfix(ChatNotification __instance) { - if (!__instance.gameObject.active || !PaletteManager.IsVariable(__instance.player.cosmetics.ColorId)) + if (!__instance.gameObject.active) return; - var str = PaletteManager.GetMainColor(__instance.player.cosmetics.ColorId).ToHtmlStringRGBA(); - __instance.playerNameText.text = "" + RichTags.Replace(__instance.playerNameText.text, string.Empty); + var colorId = __instance.player.cosmetics.ColorId; + + if (!PaletteManager.IsVariable(colorId)) + return; + + var color = PaletteManager.GetMainColor(colorId); + var str = color.ToHtmlStringRGBA(); + var nameText = __instance.playerNameText; + nameText.text = "" + RichTags.Replace(nameText.text, string.Empty); + nameText.outlineColor = color.GetShadowColor(0.5f); } } @@ -68,6 +76,10 @@ internal static class RainbowLobbyInfoPanePatch } var host = GameData.Instance.GetHost(); + + if (!host) + return; + var text = PaletteManager.GetMainColor(__instance.player.cosmetics.ColorId).ToHtmlStringRGBA(); __instance.hostLabel.text = TranslationController.Instance.GetString(StringNames.HostNounLabel);