mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
add variable color system + color spaces
This commit is contained in:
12 files changed
+618
-2
No files matched your search
@@ -86,3 +86,6 @@ dotnet_diagnostic.SA1133.severity = none
|
||||
|
||||
# IDE0001: Simplify Names
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
|
||||
# IDE0079: Remove unnecessary suppression
|
||||
dotnet_diagnostic.IDE0079.severity = none
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Colors.ColorSpaces;
|
||||
|
||||
/// <summary>
|
||||
/// A struct that denotes the CMYK (Cyan, Magenta, Yellow, Key) color space.
|
||||
/// </summary>
|
||||
/// <param name="c">The cyan component.</param>
|
||||
/// <param name="m">The magenta component.</param>
|
||||
/// <param name="y">The yellow component.</param>
|
||||
/// <param name="k">The key component.</param>
|
||||
/// <param name="a">The alpha component.</param>
|
||||
[Serializable]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
|
||||
public record struct CmykColor(float c, float m, float y, float k, float a = 1f)
|
||||
{
|
||||
/// <summary>
|
||||
/// Implicitly converts a <see cref="CmykColor"/> to a Unity <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator Color(CmykColor c)
|
||||
{
|
||||
return ToColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly converts a Unity <see cref="Color"/> to a <see cref="CmykColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator CmykColor(Color c)
|
||||
{
|
||||
return FromColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="CmykColor"/> to a standard Unity RGB <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="cmyk">The CMYK color to convert.</param>
|
||||
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
|
||||
public static Color ToColor(CmykColor cmyk)
|
||||
{
|
||||
var r = (1f - cmyk.c) * (1f - cmyk.k);
|
||||
var g = (1f - cmyk.m) * (1f - cmyk.k);
|
||||
var b = (1f - cmyk.y) * (1f - cmyk.k);
|
||||
|
||||
return new Color(Mathf.Clamp01(r), Mathf.Clamp01(g), Mathf.Clamp01(b), cmyk.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a standard Unity RGB <see cref="Color"/> to a <see cref="CmykColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The Unity Color to convert.</param>
|
||||
/// <returns>A <see cref="CmykColor"/> representing the same visual color.</returns>
|
||||
public static CmykColor FromColor(Color color)
|
||||
{
|
||||
var r = color.r;
|
||||
var g = color.g;
|
||||
var b = color.b;
|
||||
|
||||
var k = 1f - Mathf.Max(r, g, b);
|
||||
|
||||
if (k >= 1f)
|
||||
return new CmykColor(0f, 0f, 0f, 1f, color.a);
|
||||
|
||||
var c = (1f - r - k) / (1f - k);
|
||||
var m = (1f - g - k) / (1f - k);
|
||||
var y = (1f - b - k) / (1f - k);
|
||||
|
||||
return new CmykColor(Mathf.Clamp01(c), Mathf.Clamp01(m), Mathf.Clamp01(y), Mathf.Clamp01(k), color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="CmykColor"/> values.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
|
||||
/// <returns>The interpolated <see cref="CmykColor"/>.</returns>
|
||||
public static CmykColor Lerp(CmykColor a, CmykColor b, float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
return LerpUnclamped(a, b, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="CmykColor"/> values without clamping the interpolant.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors.</param>
|
||||
/// <returns>The interpolated <see cref="CmykColor"/>.</returns>
|
||||
public static CmykColor LerpUnclamped(CmykColor a, CmykColor b, float t)
|
||||
{
|
||||
return new CmykColor(
|
||||
Mathf.LerpUnclamped(a.c, b.c, t),
|
||||
Mathf.LerpUnclamped(a.m, b.m, t),
|
||||
Mathf.LerpUnclamped(a.y, b.y, t),
|
||||
Mathf.LerpUnclamped(a.k, b.k, t),
|
||||
Mathf.LerpUnclamped(a.a, b.a, t));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Colors.ColorSpaces;
|
||||
|
||||
/// <summary>
|
||||
/// A struct that denotes the HSB (Hue, Saturation, Brightness) color space.
|
||||
/// </summary>
|
||||
/// <param name="h">The hue component.</param>
|
||||
/// <param name="s">The saturation component.</param>
|
||||
/// <param name="b">The brightness component.</param>
|
||||
/// <param name="a">The alpha component.</param>
|
||||
[Serializable]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
|
||||
public record struct HsbColor(float h, float s, float b, float a = 1f)
|
||||
{
|
||||
/// <summary>
|
||||
/// Implicitly converts an <see cref="HsbColor"/> to a Unity <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator Color(HsbColor c)
|
||||
{
|
||||
return ToColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly converts a Unity <see cref="Color"/> to an <see cref="HsbColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator HsbColor(Color c)
|
||||
{
|
||||
return FromColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an <see cref="HsbColor"/> to a standard Unity RGB <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="hsb">The HSB color to convert.</param>
|
||||
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
|
||||
public static Color ToColor(HsbColor hsb)
|
||||
{
|
||||
var r = hsb.b;
|
||||
var g = hsb.b;
|
||||
var b = hsb.b;
|
||||
|
||||
if (hsb.s <= Mathf.Epsilon)
|
||||
return new Color(Mathf.Clamp01(r), Mathf.Clamp01(g), Mathf.Clamp01(b), hsb.a);
|
||||
|
||||
var max = hsb.b;
|
||||
var dif = hsb.b * hsb.s;
|
||||
var min = hsb.b - dif;
|
||||
|
||||
var h = hsb.h * 360f;
|
||||
|
||||
(r, g, b) = h switch
|
||||
{
|
||||
< 60f => (max, h * dif / 60f + min, min),
|
||||
< 120f => (-(h - 120f) * dif / 60f + min, max, min),
|
||||
< 180f => (min, max, (h - 120f) * dif / 60f + min),
|
||||
< 240f => (min, -(h - 240f) * dif / 60f + min, max),
|
||||
< 300f => ((h - 240f) * dif / 60f + min, min, max),
|
||||
<= 360f => (max, min, -(h - 360f) * dif / 60f + min),
|
||||
_ => (0f, 0f, 0f),
|
||||
};
|
||||
|
||||
return new Color(Mathf.Clamp01(r), Mathf.Clamp01(g), Mathf.Clamp01(b), hsb.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a standard Unity RGB <see cref="Color"/> to an <see cref="HsbColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The Unity Color to convert.</param>
|
||||
/// <returns>An <see cref="HsbColor"/> representing the same visual color.</returns>
|
||||
public static HsbColor FromColor(Color color)
|
||||
{
|
||||
Color.RGBToHSV(color, out var h, out var s, out var v);
|
||||
return new HsbColor(h, s, v, color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="HsbColor"/> values, using the shortest path for the hue.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
|
||||
/// <returns>The interpolated <see cref="HsbColor"/>.</returns>
|
||||
public static HsbColor Lerp(HsbColor a, HsbColor b, float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
return LerpUnclamped(a, b, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="HsbColor"/> values without clamping the interpolant.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors.</param>
|
||||
/// <returns>The interpolated <see cref="HsbColor"/>.</returns>
|
||||
public static HsbColor LerpUnclamped(HsbColor a, HsbColor b, float t)
|
||||
{
|
||||
var hueDifference = Mathf.Repeat(b.h - a.h, 1f);
|
||||
|
||||
if (hueDifference > 0.5f)
|
||||
hueDifference -= 1f;
|
||||
|
||||
return new HsbColor(
|
||||
Mathf.Repeat(a.h + (hueDifference * t), 1f),
|
||||
Mathf.LerpUnclamped(a.s, b.s, t),
|
||||
Mathf.LerpUnclamped(a.b, b.b, t),
|
||||
Mathf.LerpUnclamped(a.a, b.a, t));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Colors.ColorSpaces;
|
||||
|
||||
/// <summary>
|
||||
/// A struct that denotes the HSL (Hue, Saturation, Lightness) color space.
|
||||
/// </summary>
|
||||
/// <param name="h">The hue component.</param>
|
||||
/// <param name="s">The saturation component.</param>
|
||||
/// <param name="l">The lightness component.</param>
|
||||
/// <param name="a">The alpha component.</param>
|
||||
[Serializable]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
|
||||
public record struct HslColor(float h, float s, float l, float a = 1f)
|
||||
{
|
||||
/// <summary>
|
||||
/// Implicitly converts an <see cref="HslColor"/> to a Unity <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator Color(HslColor c)
|
||||
{
|
||||
return ToColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly converts a Unity <see cref="Color"/> to an <see cref="HslColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="c">The color being converted.</param>
|
||||
public static implicit operator HslColor(Color c)
|
||||
{
|
||||
return FromColor(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an <see cref="HslColor"/> to a standard Unity RGB <see cref="Color"/>.
|
||||
/// </summary>
|
||||
/// <param name="hsl">The HSL color to convert.</param>
|
||||
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
|
||||
public static Color ToColor(HslColor hsl)
|
||||
{
|
||||
if (hsl.s <= Mathf.Epsilon)
|
||||
return new Color(Mathf.Clamp01(hsl.l), Mathf.Clamp01(hsl.l), Mathf.Clamp01(hsl.l), hsl.a);
|
||||
|
||||
var c = (1f - Mathf.Abs(2f * hsl.l - 1f)) * hsl.s;
|
||||
var hPrime = hsl.h * 6f;
|
||||
var x = c * (1f - Mathf.Abs((hPrime % 2f) - 1f));
|
||||
var m = hsl.l - c / 2f;
|
||||
|
||||
var (r, g, b) = hPrime switch
|
||||
{
|
||||
< 1f => (c, x, 0f),
|
||||
< 2f => (x, c, 0f),
|
||||
< 3f => (0f, c, x),
|
||||
< 4f => (0f, x, c),
|
||||
< 5f => (x, 0f, c),
|
||||
< 6f => (c, 0f, x),
|
||||
_ => (0f, 0f, 0f),
|
||||
};
|
||||
|
||||
return new Color(Mathf.Clamp01(r + m), Mathf.Clamp01(g + m), Mathf.Clamp01(b + m), hsl.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a standard Unity RGB <see cref="Color"/> to an <see cref="HslColor"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The Unity Color to convert.</param>
|
||||
/// <returns>An <see cref="HslColor"/> representing the same visual color.</returns>
|
||||
public static HslColor FromColor(Color color)
|
||||
{
|
||||
var max = Mathf.Max(color.r, Mathf.Max(color.g, color.b));
|
||||
var min = Mathf.Min(color.r, Mathf.Min(color.g, color.b));
|
||||
var l = (max + min) / 2f;
|
||||
var delta = max - min;
|
||||
|
||||
var s = delta == 0f ? 0f : delta / (1f - Mathf.Abs(2f * l - 1f));
|
||||
|
||||
Color.RGBToHSV(color, out var h, out _, out _);
|
||||
|
||||
return new HslColor(h, s, l, color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="HslColor"/> values, using the shortest path for the hue.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
|
||||
/// <returns>The interpolated <see cref="HslColor"/>.</returns>
|
||||
public static HslColor Lerp(HslColor a, HslColor b, float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
return LerpUnclamped(a, b, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between two <see cref="HslColor"/> values without clamping the interpolant.
|
||||
/// </summary>
|
||||
/// <param name="a">The starting color.</param>
|
||||
/// <param name="b">The ending color.</param>
|
||||
/// <param name="t">The interpolation value between the two colors.</param>
|
||||
/// <returns>The interpolated <see cref="HslColor"/>.</returns>
|
||||
public static HslColor LerpUnclamped(HslColor a, HslColor b, float t)
|
||||
{
|
||||
var hueDifference = Mathf.Repeat(b.h - a.h, 1f);
|
||||
|
||||
if (hueDifference > 0.5f)
|
||||
hueDifference -= 1f;
|
||||
|
||||
return new HslColor(
|
||||
Mathf.Repeat(a.h + (hueDifference * t), 1f),
|
||||
Mathf.LerpUnclamped(a.s, b.s, t),
|
||||
Mathf.LerpUnclamped(a.l, b.l, t),
|
||||
Mathf.LerpUnclamped(a.a, b.a, t));
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace MiraAPI.Colors;
|
||||
/// <param name="name">The name of the option.</param>
|
||||
/// <param name="mainColor">The main color.</param>
|
||||
/// <param name="shadowColor">The shadow color.</param>
|
||||
public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
|
||||
public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the main color.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Colors;
|
||||
|
||||
@@ -15,6 +16,8 @@ public static class PaletteManager
|
||||
public static CustomColor[] RegisteredColors => [.. CustomColors];
|
||||
|
||||
internal static readonly List<CustomColor> CustomColors = [];
|
||||
internal static readonly HashSet<StringNames> VariableColorNames = [];
|
||||
internal static readonly Dictionary<int, CustomColor> ColorIdToColorMap = [];
|
||||
|
||||
internal static void RegisterAllColors()
|
||||
{
|
||||
@@ -22,11 +25,64 @@ public static class PaletteManager
|
||||
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 < originalLength + CustomColors.Count; i++)
|
||||
ColorIdToColorMap[i + originalLength] = CustomColors[i];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the provided color ID belongs to a variant color.
|
||||
/// </summary>
|
||||
/// <param name="colorId">The id of the color.</param>
|
||||
/// <returns><c>true</c> if the color is a variable color; <c>false</c> otherwise.</returns>
|
||||
public static bool IsVariable(int colorId)
|
||||
{
|
||||
return VariableColorNames.Contains(Palette.ColorNames[colorId]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the provided color ID belongs to a custom color.
|
||||
/// </summary>
|
||||
/// <param name="colorId">The id of the color.</param>
|
||||
/// <returns><c>true</c> if the color is a custom color; <c>false</c> otherwise.</returns>
|
||||
public static bool IsCustomColor(int colorId)
|
||||
{
|
||||
return ColorIdToColorMap.ContainsKey(colorId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the main color of the provided color ID.
|
||||
/// </summary>
|
||||
/// <param name="colorId">The id of the color.</param>
|
||||
/// <returns>The main color associated with the provided ID.</returns>
|
||||
public static Color32 GetMainColor(int colorId)
|
||||
{
|
||||
return !ColorIdToColorMap.TryGetValue(colorId, out var custom)
|
||||
? Palette.PlayerColors[colorId]
|
||||
: (custom is VariableColor variable
|
||||
? variable.EvaluateMainColor()
|
||||
: custom.MainColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shadow color of the provided color ID.
|
||||
/// </summary>
|
||||
/// <param name="colorId">The id of the color.</param>
|
||||
/// <returns>The shadow color associated with the provided ID.</returns>
|
||||
public static Color32 GetShadowColor(int colorId)
|
||||
{
|
||||
return !ColorIdToColorMap.TryGetValue(colorId, out var custom)
|
||||
? Palette.ShadowColors[colorId]
|
||||
: (custom is VariableColor variable
|
||||
? variable.EvaluateShadowColor()
|
||||
: custom.ShadowColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Translation;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Colors;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dynamic custom color that changes over time.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the color.</param>
|
||||
/// <param name="mainEvaluator">The function to evaluate the dynamic main color.</param>
|
||||
/// <param name="shadowEvaluator">The function to evaluate the dynamic shadow color.</param>
|
||||
/// <param name="mainColor">The static main color used when dynamic colors are disabled.</param>
|
||||
/// <param name="shadowColor">The static shadow color used when dynamic colors are disabled.</param>
|
||||
public sealed class VariableColor(StringNames name, Func<float, Color32> mainEvaluator, Func<float, Color32>? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null)
|
||||
: CustomColor(name, mainColor ?? mainEvaluator(0f), shadowColor ?? shadowEvaluator?.Invoke(0f) ?? (mainColor ?? mainEvaluator(0f)).GetShadowColor(60))
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that takes a normalized time value and returns the dynamic main color.
|
||||
/// </summary>
|
||||
public Func<float, Color32> MainEvaluator { get; set; } = mainEvaluator;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that takes a normalized time value and returns the dynamic shadow color.
|
||||
/// </summary>
|
||||
public Func<float, Color32> ShadowEvaluator { get; set; } = shadowEvaluator ?? (t => mainEvaluator(t).GetShadowColor(60));
|
||||
|
||||
/// <inheritdoc cref="VariableColor"/>
|
||||
public VariableColor(StringNames name, Func<float, Color32> mainEvaluator, Color32? mainColor = null)
|
||||
: this(name, mainEvaluator, null, mainColor, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="VariableColor"/>
|
||||
public VariableColor(string name, Func<float, Color32> mainEvaluator, Color32? mainColor = null)
|
||||
: this(name, mainEvaluator, null, mainColor, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="VariableColor"/>
|
||||
public VariableColor(string name, Func<float, Color32> mainEvaluator, Func<float, Color32>? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null)
|
||||
: this(MiraLocaleManager.GetOrCreateLocaleString(name), mainEvaluator, shadowEvaluator, mainColor, shadowColor)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the dynamic main color based on the current in-game time.
|
||||
/// </summary>
|
||||
/// <returns>The dynamically evaluated color, or the static <see cref="CustomColor.MainColor"/> if static variant colors are enabled in the user's settings.</returns>
|
||||
public Color32 EvaluateMainColor()
|
||||
{
|
||||
return LocalSettingsTabSingleton<MiraApiSettings>.Instance.EnableVariableColors.Value
|
||||
? MainEvaluator(Time.time)
|
||||
: MainColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the dynamic shadow color based on the current in-game time.
|
||||
/// </summary>
|
||||
/// <returns>The dynamically evaluated color, or the static <see cref="CustomColor.ShadowColor"/> if static variant colors are enabled in the user's settings.</returns>
|
||||
public Color32 EvaluateShadowColor()
|
||||
{
|
||||
return LocalSettingsTabSingleton<MiraApiSettings>.Instance.EnableVariableColors.Value
|
||||
? ShadowEvaluator(Time.time)
|
||||
: ShadowColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Colors;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI;
|
||||
|
||||
/// <summary>
|
||||
/// A mono script that adjusts the material colors of a <see cref="SpriteRenderer"/> component that it's attached to based on the provided variable color.
|
||||
/// </summary>
|
||||
[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
|
||||
{
|
||||
private SpriteRenderer rend;
|
||||
private Material material;
|
||||
private VariableColor? color;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current variant color.
|
||||
/// </summary>
|
||||
/// <param name="col">The new variant color.</param>
|
||||
[HideFromIl2Cpp]
|
||||
public void SetColor(VariableColor? col)
|
||||
{
|
||||
color = col;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
rend = GetComponent<SpriteRenderer>();
|
||||
material = rend.material;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!rend || color == null)
|
||||
return;
|
||||
|
||||
material.SetColor(ShaderID.BodyColor, color.EvaluateMainColor());
|
||||
material.SetColor(ShaderID.BackColor, color.EvaluateShadowColor());
|
||||
material.SetColor(ShaderID.VisorColor, Palette.VisorColor);
|
||||
}
|
||||
}
|
||||
@@ -233,4 +233,10 @@ public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
|
||||
/// </summary>
|
||||
[LocalToggleSetting]
|
||||
public ConfigEntry<bool> EnableSabotageBlares { get; private set; } = config.Bind("MiraApi.Accessibility", "MiraApi.EnableSabotageBlare", true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether variant colors will remain static or not.
|
||||
/// </summary>
|
||||
[LocalToggleSetting]
|
||||
public ConfigEntry<bool> EnableVariableColors { get; private set; } = config.Bind("MiraApi.Accessibility", "MiraApi.EnableVariableColors", true);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.RegularExpressions;
|
||||
using AmongUs.Data;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Colors;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Hud;
|
||||
|
||||
[HarmonyPatch(typeof(PlayerMaterial))]
|
||||
internal static class SetPlayerMaterialPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(PlayerMaterial.SetColors), typeof(int), typeof(Renderer))]
|
||||
public static bool Prefix(int colorId, Renderer rend)
|
||||
{
|
||||
var r = rend.gameObject.GetComponent<VariableColorBehaviour>()
|
||||
?? rend.gameObject.AddComponent<VariableColorBehaviour>();
|
||||
r.SetColor(PaletteManager.IsVariable(colorId) ? (VariableColor)PaletteManager.ColorIdToColorMap[colorId] : null);
|
||||
return !PaletteManager.IsVariable(colorId);
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(PlayerMaterial.SetColors), typeof(Color), typeof(Renderer))]
|
||||
public static void Prefix(Renderer rend)
|
||||
{
|
||||
var r = rend.gameObject.GetComponent<VariableColorBehaviour>()
|
||||
?? rend.gameObject.AddComponent<VariableColorBehaviour>();
|
||||
r.SetColor(null);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerTab), nameof(PlayerTab.Update))]
|
||||
internal static class PlayerTabPatch
|
||||
{
|
||||
public static void Postfix(PlayerTab __instance)
|
||||
{
|
||||
for (var i = 0; i < __instance.ColorChips.Count; i++)
|
||||
{
|
||||
__instance.ColorChips[i].Inner.SpriteColor = PaletteManager.GetMainColor(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(ChatNotification), nameof(ChatNotification.Update))]
|
||||
internal static class ChatNotifRainbowPatch
|
||||
{
|
||||
public static void Postfix(ChatNotification __instance)
|
||||
{
|
||||
if (!__instance.gameObject.active || !PaletteManager.IsVariable(__instance.player.cosmetics.ColorId))
|
||||
return;
|
||||
|
||||
var str = ColorUtility.ToHtmlStringRGB(PaletteManager.GetMainColor(__instance.player.cosmetics.ColorId));
|
||||
__instance.playerNameText.text = "<color=#" + str + ">" + __instance.playerNameText.text.WithoutRichText();
|
||||
}
|
||||
|
||||
private static string WithoutRichText(this string text)
|
||||
{
|
||||
var richTagRegex = new Regex(@"<[^>]*>", default, Regex.InfiniteMatchTimeout);
|
||||
return richTagRegex.Replace(text, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(HostInfoPanel), nameof(HostInfoPanel.Update))]
|
||||
internal static class RainbowLobbyInfoPanePatch
|
||||
{
|
||||
[SuppressMessage("Style", "IDE0045:Convert to conditional expression", Justification = "Operator becomes too large.")]
|
||||
public static void Postfix(HostInfoPanel __instance)
|
||||
{
|
||||
if (!__instance.gameObject.activeInHierarchy || !PaletteManager.IsVariable(__instance.player.cosmetics.ColorId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var host = GameData.Instance.GetHost();
|
||||
var text = ColorUtility.ToHtmlStringRGB(PaletteManager.GetMainColor(__instance.player.cosmetics.ColorId));
|
||||
__instance.hostLabel.text =
|
||||
TranslationController.Instance.GetString(StringNames.HostNounLabel);
|
||||
if (__instance.ShouldBoldenHostLabel(DataManager.Settings.Language.CurrentLanguage))
|
||||
{
|
||||
__instance.hostLabel.text = __instance.hostLabel.text.Insert(0, "<b>");
|
||||
__instance.hostLabel.text = __instance.hostLabel.text.Insert(__instance.hostLabel.text.Length, "</b>");
|
||||
}
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
__instance.playerName.text = (string.IsNullOrEmpty(host.PlayerName)
|
||||
? "..."
|
||||
: $"<color=#{text}>{host.PlayerName}</color>")
|
||||
+ " <size=90%><b><font=\"Barlow-BoldItalic SDF\" material=\"Barlow-BoldItalic SDF Outline\">" +
|
||||
TranslationController.Instance.GetString(StringNames.HostYouLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance.playerName.text =
|
||||
(string.IsNullOrEmpty(host.PlayerName) ? "..." : $"<color=#{text}>{host.PlayerName}</color>") +
|
||||
" (" + __instance.player.ColorBlindName + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,7 +404,7 @@ public sealed class MiraPluginManager
|
||||
|
||||
foreach (var property in type.GetProperties())
|
||||
{
|
||||
if (property.PropertyType != typeof(CustomColor))
|
||||
if (property.PropertyType.IsAssignableTo(typeof(CustomColor)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -416,6 +416,9 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
|
||||
PaletteManager.CustomColors.Add(color);
|
||||
|
||||
if (color is VariableColor)
|
||||
PaletteManager.VariableColorNames.Add(color.Name);
|
||||
}
|
||||
|
||||
foreach (var field in type.GetFields().Where(f => f.FieldType.IsAssignableTo(typeof(CustomColor))))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<string name="MiraApi.WikiOnBottomRow">Display Wiki on Bottom Row</string>
|
||||
<string name="MiraApi.EnableSabotageFlashes">Enable Sabotage Flashes</string>
|
||||
<string name="MiraApi.EnableSabotageBlare">Enable Sabotage Blare</string>
|
||||
<string name="MiraApi.EnableVariableColors">Enable Variable Color Changes</string>
|
||||
<string name="MiraApi.ReturnToRoleSettings">RETURN TO ROLE SETTINGS</string>
|
||||
<string name="MiraApi.CustomCategory1">Custom Category 1</string>
|
||||
<string name="MiraApi.CustomCategory2">Custom Category 2</string>
|
||||
|
||||
Reference in new issue
Block a user