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);