mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-28 19:43:55 +00:00
Compare commits
3
Commits
test-fixes
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51397d78a7 | ||
|
|
08fd56754e | ||
|
|
181013efec |
No files matched your search
@@ -105,11 +105,5 @@ dotnet_diagnostic.S1244.severity = none
|
||||
# S2325: Methods and properties that don't access instance data should be static
|
||||
dotnet_diagnostic.S2325.severity = none
|
||||
|
||||
# CA1710: Identifiers should have correct suffix
|
||||
dotnet_diagnostic.CA1710.severity = silent
|
||||
|
||||
# CA1010: Generic interface should also be implemented
|
||||
dotnet_diagnostic.CA1010.severity = silent
|
||||
|
||||
# IDE0005: Using directive is unnecessary.
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
@@ -5,7 +5,7 @@ namespace MiraAPI.Example;
|
||||
|
||||
public static class ExampleAssets
|
||||
{
|
||||
private static readonly Assembly _assembly = typeof(MiraAssets).Assembly;
|
||||
private static readonly Assembly _assembly = typeof(ExampleAssets).Assembly;
|
||||
|
||||
public static LoadableResourceAsset ExampleButton { get; } = new("MiraAPI.Example.Resources.ExampleButton.png", _assembly);
|
||||
public static LoadableResourceAsset CallMeetingButton { get; } = new("MiraAPI.Example.Resources.CallMeeting.png", _assembly);
|
||||
|
||||
@@ -58,13 +58,13 @@ public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColo
|
||||
|
||||
/// <inheritdoc cref="CustomColor"/>
|
||||
public CustomColor(StringNames name, Color32 mainColor)
|
||||
: this(name, mainColor, mainColor.GetShadowColor(60))
|
||||
: this(name, mainColor, mainColor.DarkenAbsolute(60))
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="CustomColor"/>
|
||||
public CustomColor(string name, Color32 mainColor)
|
||||
: this(name, mainColor, mainColor.GetShadowColor(60))
|
||||
: this(name, mainColor, mainColor.DarkenAbsolute(60))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace MiraAPI.Colors;
|
||||
/// <param name="shadowColor">The static shadow color used when dynamic colors are disabled.</param>
|
||||
/// <param name="defaultTime">The default time that is used to automatically fill in the static colors when the latter is not provided.</param>
|
||||
public sealed class VariableColor(StringNames name, Func<float, Color> mainEvaluator, Func<float, Color>? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null, float defaultTime = 0f)
|
||||
: CustomColor(name, mainColor ?? mainEvaluator(defaultTime), shadowColor ?? shadowEvaluator?.Invoke(defaultTime) ?? (mainColor ?? mainEvaluator(defaultTime)).GetShadowColor(60))
|
||||
: CustomColor(name, mainColor ?? mainEvaluator(defaultTime), shadowColor ?? shadowEvaluator?.Invoke(defaultTime) ?? (mainColor ?? mainEvaluator(defaultTime)).DarkenAbsolute(60))
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that takes in a time value and returns the dynamic main color.
|
||||
@@ -26,7 +26,7 @@ public sealed class VariableColor(StringNames name, Func<float, Color> mainEvalu
|
||||
/// <summary>
|
||||
/// Gets or sets a delegate that takes in a time value and returns the dynamic shadow color.
|
||||
/// </summary>
|
||||
public Func<float, Color> ShadowEvaluator { get; set; } = shadowEvaluator ?? (t => mainEvaluator(t).GetShadowColor(0.24f));
|
||||
public Func<float, Color> ShadowEvaluator { get; set; } = shadowEvaluator ?? (t => mainEvaluator(t).DarkenAbsolute(0.24f));
|
||||
|
||||
/// <inheritdoc cref="VariableColor"/>
|
||||
public VariableColor(StringNames name, Func<float, Color> mainEvaluator, Color32? mainColor = null, float defaultTime = 0f)
|
||||
|
||||
@@ -97,7 +97,7 @@ public class ModdedNumberOptionAttribute(
|
||||
var value = opt.Value;
|
||||
|
||||
if (ValueType == typeof(int))
|
||||
return (int)Math.Round(value);
|
||||
return (int)MathF.Round(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
public class ModdedEnumOptionListAttribute(string title, Type enumType, string[]? values = null)
|
||||
: ModdedOptionListAttribute(title)
|
||||
{
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
var optList = new ModdedOptionList<ModdedEnumOption>(
|
||||
value.Count, idx => new(GetFormattedTitle(idx), (int)(value[idx] ?? 0), enumType, values));
|
||||
@@ -25,14 +25,14 @@ public class ModdedEnumOptionListAttribute(string title, Type enumType, string[]
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedEnumOption;
|
||||
var opt = HolderOptionList?[idx] as ModdedEnumOption;
|
||||
opt?.SetValue((int)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?.ElementAt(idx) is ModdedEnumOption opt
|
||||
return HolderOptionList?[idx] is ModdedEnumOption opt
|
||||
? Enum.ToObject(enumType, opt.Value)
|
||||
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType {enumType.FullName} is not a ModdedEnumOption");
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class ModdedEnumOptionListAttribute<T>(string title, string[]? values = n
|
||||
: ModdedOptionListAttribute(title)
|
||||
where T : struct, Enum
|
||||
{
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
var optList = new ModdedOptionList<ModdedEnumOption<T>>(
|
||||
value.Count, idx => new(GetFormattedTitle(idx), (T)(value[idx] ?? 0), values));
|
||||
@@ -59,14 +59,14 @@ public class ModdedEnumOptionListAttribute<T>(string title, string[]? values = n
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedEnumOption<T>;
|
||||
var opt = HolderOptionList?[idx] as ModdedEnumOption<T>;
|
||||
opt?.SetValue((T)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?.ElementAt(idx) is ModdedEnumOption<T> opt
|
||||
return HolderOptionList?[idx] is ModdedEnumOption<T> opt
|
||||
? opt.Value
|
||||
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType {typeof(T).FullName} is not a ModdedEnumOption<{typeof(T).FullName}>");
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ModdedNumberOptionListAttribute(
|
||||
{
|
||||
}
|
||||
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
return new ModdedOptionList<ModdedNumberOption>(value.Count, idx =>
|
||||
{
|
||||
@@ -81,7 +81,7 @@ public class ModdedNumberOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedNumberOption opt)
|
||||
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
|
||||
return;
|
||||
|
||||
var final = value switch
|
||||
@@ -95,13 +95,13 @@ public class ModdedNumberOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedNumberOption opt)
|
||||
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
|
||||
throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedNumberOption");
|
||||
|
||||
var value = opt.Value;
|
||||
|
||||
if (ValueType == typeof(int))
|
||||
return (int)Math.Round(value);
|
||||
return (int)MathF.Round(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAttribute
|
||||
{
|
||||
internal IBaseModdedOptionList? HolderOptionList { get; set; }
|
||||
internal IModdedOptionList? HolderOptionList { get; set; }
|
||||
internal IList? Value { get; set; }
|
||||
internal Type ValueType { get; set; }
|
||||
|
||||
@@ -68,7 +68,7 @@ public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAt
|
||||
/// <returns>The value of the option as an object.</returns>
|
||||
public abstract object GetValue(int idx);
|
||||
|
||||
internal abstract IBaseModdedOptionList? CreateOptionList(IList value, PropertyInfo property);
|
||||
internal abstract IModdedOptionList? CreateOptionList(IList value, PropertyInfo property);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Title"/> formatted with the option's index.
|
||||
|
||||
@@ -16,7 +16,7 @@ public class ModdedPlayerOptionListAttribute(
|
||||
bool allowNone = true)
|
||||
: ModdedOptionListAttribute(title)
|
||||
{
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
return new ModdedOptionList<ModdedPlayerOption>(value.Count, idx =>
|
||||
{
|
||||
@@ -27,7 +27,7 @@ public class ModdedPlayerOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedPlayerOption opt)
|
||||
if (HolderOptionList?[idx] is not ModdedPlayerOption opt)
|
||||
return;
|
||||
|
||||
var final = value switch
|
||||
@@ -41,7 +41,7 @@ public class ModdedPlayerOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedPlayerOption opt)
|
||||
if (HolderOptionList?[idx] is not ModdedPlayerOption opt)
|
||||
throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedPlayerOption");
|
||||
|
||||
if (ValueType == typeof(int))
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ModdedStringOptionListAttribute(
|
||||
string[] values)
|
||||
: ModdedOptionListAttribute(title)
|
||||
{
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
return new ModdedOptionList<ModdedStringOption>(value.Count, idx =>
|
||||
{
|
||||
@@ -28,14 +28,14 @@ public class ModdedStringOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedStringOption;
|
||||
var opt = HolderOptionList?[idx] as ModdedStringOption;
|
||||
opt?.SetValue((string)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?.ElementAt(idx) is ModdedStringOption opt
|
||||
return HolderOptionList?[idx] is ModdedStringOption opt
|
||||
? opt.Value
|
||||
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedStringOption");
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ModdedToggleOptionListAttribute(
|
||||
{
|
||||
}
|
||||
|
||||
internal override IBaseModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
{
|
||||
var optList = new ModdedOptionList<ModdedToggleOption>(
|
||||
value.Count, idx => new(GetFormattedTitle(idx), (bool)(value[idx] ?? false), on, off));
|
||||
@@ -37,14 +37,14 @@ public class ModdedToggleOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override void SetValue(int idx, object value)
|
||||
{
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedToggleOption;
|
||||
var opt = HolderOptionList?[idx] as ModdedToggleOption;
|
||||
opt?.SetValue((bool)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?.ElementAt(idx) is ModdedToggleOption opt
|
||||
return HolderOptionList?[idx] is ModdedToggleOption opt
|
||||
? opt.Value
|
||||
: throw new InvalidOperationException($"Holder option for {GetFormattedTitle(idx)} is not a ModdedToggleOption.");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.Networking;
|
||||
@@ -144,11 +143,9 @@ public interface IModdedOption
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for list of modded options.
|
||||
/// <para/>
|
||||
/// Do not implement directly, implement <see cref="IModdedOptionList"/> or <see cref="IModdedOptionList{T}"/> instead.
|
||||
/// Interface for list of modded options.
|
||||
/// </summary>
|
||||
public interface IBaseModdedOptionList : IEnumerable
|
||||
public interface IModdedOptionList : IReadOnlyList<IModdedOption>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the function to name the keys of the individual options in the configuration file.
|
||||
@@ -156,34 +153,18 @@ public interface IBaseModdedOptionList : IEnumerable
|
||||
/// Return <see langword="null"/> to use the default of the property's name with its index appended.
|
||||
/// </summary>
|
||||
Func<int, string>? ConfigName { get; init; }
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyCollection{T}.Count"/>
|
||||
int Count { get; }
|
||||
|
||||
/// <inheritdoc cref="System.Linq.Enumerable.ElementAt{TSource}(IEnumerable{TSource}, int)"/>
|
||||
IModdedOption ElementAt(int index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for list of modded options.
|
||||
/// </summary>
|
||||
public interface IModdedOptionList : IBaseModdedOptionList, IReadOnlyList<IModdedOption>
|
||||
{
|
||||
IModdedOption IBaseModdedOptionList.ElementAt(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for list of <typeparamref name="T"/> options.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of <see cref="IModdedOption"/>.</typeparam>
|
||||
public interface IModdedOptionList<out T> : IBaseModdedOptionList, IReadOnlyList<T>
|
||||
public interface IModdedOptionList<out T> : IModdedOptionList
|
||||
where T : IModdedOption
|
||||
{
|
||||
IModdedOption IBaseModdedOptionList.ElementAt(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
/// <inheritdoc cref="IReadOnlyList{T}.this[int]"/>
|
||||
new T this[int index] { get; }
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
new IEnumerator<T> GetEnumerator();
|
||||
}
|
||||
@@ -217,7 +217,7 @@ public static class ModdedOptionsManager
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.GetValue(group) is not IBaseModdedOptionList optionList)
|
||||
if (property.GetValue(group) is not IModdedOptionList optionList)
|
||||
{
|
||||
Error($"Failed to get option list for {property.Name}");
|
||||
return;
|
||||
@@ -227,7 +227,7 @@ public static class ModdedOptionsManager
|
||||
|
||||
for (var i = 0; i < optionList.Count; i++)
|
||||
{
|
||||
RegisterOption(optionList.ElementAt(i), group, configName(i), pluginInfo);
|
||||
RegisterOption(optionList[i], group, configName(i), pluginInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ public static class ModdedOptionsManager
|
||||
|
||||
for (var i = 0; i < optionList.Count; i++)
|
||||
{
|
||||
var option = optionList.ElementAt(i);
|
||||
var option = optionList[i];
|
||||
|
||||
if (visibilityFactory != null)
|
||||
option.Visible = (Func<bool>)(visibilityFactory(i) ?? DelegateUtilities.AlwaysTrue);
|
||||
|
||||
@@ -62,4 +62,13 @@ public class ModdedOptionList<T> : IModdedOptionList<T>
|
||||
{
|
||||
return Options.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
IEnumerator<IModdedOption> IEnumerable<IModdedOption>.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<IModdedOption>)Options).GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyList{T}.this"/>
|
||||
IModdedOption IReadOnlyList<IModdedOption>.this[int index] => this[index];
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -107,7 +106,6 @@ public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMult
|
||||
protected void Begin(IEnumerable<TEntry> entries, Action<List<TEntry>?> onClick, int totalSelections, bool shouldConfirm, bool canRepeat = false)
|
||||
{
|
||||
MinigameStubs.Begin(Component, null);
|
||||
MeetingVoteAreaVisibility.HideNameplates(Component);
|
||||
|
||||
this.totalSelections = totalSelections;
|
||||
this.shouldConfirm = shouldConfirm;
|
||||
@@ -118,7 +116,6 @@ public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMult
|
||||
back.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
selectedEntries.Clear();
|
||||
MeetingVoteAreaVisibility.Restore(Component);
|
||||
onClick(null);
|
||||
}));
|
||||
|
||||
@@ -180,7 +177,6 @@ public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMult
|
||||
}
|
||||
|
||||
selectedEntries.Add(menuEntry);
|
||||
MeetingVoteAreaVisibility.Restore(Component);
|
||||
|
||||
// Add choice to list of selections
|
||||
if (selectedEntries.Count <= totalSelections)
|
||||
|
||||
@@ -387,7 +387,6 @@ public abstract class CustomPaginableMenu : CustomPhoneMenu<CustomPaginableMenu.
|
||||
protected void Begin(Action registerEntryPanels)
|
||||
{
|
||||
MinigameStubs.Begin(Component, null);
|
||||
MeetingVoteAreaVisibility.HideNameplates(Component);
|
||||
|
||||
searchText = string.Empty;
|
||||
currentPage = 0;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
@@ -22,7 +21,6 @@ public class CustomPhoneMenuComponent(IntPtr cppPtr) : Minigame(cppPtr)
|
||||
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
|
||||
private void OnDisable()
|
||||
{
|
||||
MeetingVoteAreaVisibility.Restore(this);
|
||||
if (ControllerManager.Instance)
|
||||
{
|
||||
ControllerManager.Instance.CloseOverlayMenu(name);
|
||||
|
||||
@@ -74,7 +74,6 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
protected int TabIndex => LocalSettingsManager.Tabs.IndexOf(this) + 10;
|
||||
|
||||
private Scroller? Scroller { get; set; }
|
||||
private float MaxScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an option value is changed.
|
||||
@@ -107,17 +106,6 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
}
|
||||
}
|
||||
|
||||
internal void RefreshScrollBounds()
|
||||
{
|
||||
if (Scroller == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Scroller.SetBounds(new FloatRange(0, MaxScroll), new FloatRange(0, 0));
|
||||
Scroller.ScrollToTop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the tab <see cref="GameObject"/> and it's content.
|
||||
/// </summary>
|
||||
@@ -130,13 +118,11 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
tab.transform.DestroyChildren();
|
||||
tab.gameObject.SetActive(false);
|
||||
|
||||
if (Scroller == null || Scroller.transform.parent != tab.transform)
|
||||
if (Scroller == null)
|
||||
{
|
||||
Scroller = Helpers.CreateScroller(tab.transform, OptionsMenuPatches.MaskCollider);
|
||||
}
|
||||
|
||||
Labels.Clear();
|
||||
|
||||
if (TabButton != null)
|
||||
{
|
||||
TabButton.Content = tab.gameObject;
|
||||
@@ -230,11 +216,7 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
contentIndex++;
|
||||
}
|
||||
|
||||
const float visibleHeight = 5f;
|
||||
const float extraPadding = 0.25f;
|
||||
var itemRange = (Settings.Count + Buttons.Count) * 0.5f - visibleHeight;
|
||||
var offsetRange = contentOffset - visibleHeight + extraPadding;
|
||||
MaxScroll = Mathf.Max(0f, itemRange, offsetRange);
|
||||
Scroller.SetBounds(new FloatRange(0, (Settings.Count + Buttons.Count) * 0.5f - 5f), new FloatRange(0, 0));
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public abstract class TimedModifier : BaseModifier
|
||||
/// <returns>A string with the time remaining.</returns>
|
||||
public override string GetDescription()
|
||||
{
|
||||
return $"Remaining Time: {Math.Round(Duration - TimeRemaining, 0)}s/{Duration}s";
|
||||
return $"Remaining Time: {MathF.Round(Duration - TimeRemaining, 0)}s/{Duration}s";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.RegularExpressions;
|
||||
using AmongUs.Data;
|
||||
using HarmonyLib;
|
||||
@@ -42,7 +41,7 @@ internal static class PlayerTabPatch
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(ChatNotification), nameof(ChatNotification.Update))]
|
||||
internal static class ChatNotifRainbowPatch
|
||||
internal static class ChatNotifVariablePatch
|
||||
{
|
||||
private static readonly Regex RichTags = new(@"<[^>]*>", default, Regex.InfiniteMatchTimeout);
|
||||
|
||||
@@ -60,14 +59,13 @@ internal static class ChatNotifRainbowPatch
|
||||
var str = color.ToHtmlStringRGBA();
|
||||
var nameText = __instance.playerNameText;
|
||||
nameText.text = "<color=#" + str + ">" + RichTags.Replace(nameText.text, string.Empty);
|
||||
nameText.outlineColor = color.GetShadowColor(0.5f);
|
||||
nameText.outlineColor = color.DarkenAbsolute(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(HostInfoPanel), nameof(HostInfoPanel.Update))]
|
||||
internal static class RainbowLobbyInfoPanePatch
|
||||
internal static class VariableLobbyInfoPanePatch
|
||||
{
|
||||
[SuppressMessage("Style", "IDE0045:Convert to conditional expression", Justification = "Operator becomes too large.")]
|
||||
public static void Postfix(HostInfoPanel __instance)
|
||||
{
|
||||
if (!__instance.gameObject.activeInHierarchy)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.LocalSettings;
|
||||
@@ -185,9 +183,7 @@ public static class OptionsMenuPatches
|
||||
// Tabs with index 10 and above are the mod settings tabs
|
||||
if (index >= 10)
|
||||
{
|
||||
var tab = LocalSettingsManager.AvailableTabs[index - 10];
|
||||
CustomOpen(tab);
|
||||
__instance.StartCoroutine(RefreshScrollBoundsAfterOpen(__instance, tab).WrapToIl2Cpp());
|
||||
CustomOpen(LocalSettingsManager.AvailableTabs[index - 10]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -233,16 +229,6 @@ public static class OptionsMenuPatches
|
||||
tab.Open();
|
||||
}
|
||||
|
||||
private static IEnumerator RefreshScrollBoundsAfterOpen(OptionsMenuBehaviour menu, LocalSettingsTab tab)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
if (menu && tab.TabButton?.Content && tab.TabButton.Content.activeInHierarchy)
|
||||
{
|
||||
tab.RefreshScrollBounds();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CustomClose(LocalSettingsTab tab)
|
||||
{
|
||||
if (tab.TabButton?.Button)
|
||||
|
||||
@@ -464,7 +464,7 @@ public static class LobbyViewPanePatches
|
||||
|
||||
if (name is not (StringNames.CrewmateRolesHeader or StringNames.ImpostorRolesHeader))
|
||||
{
|
||||
var veryDarkColor = group.Color.DarkenColor(.35f);
|
||||
var veryDarkColor = group.Color.DarkenRelative(.35f);
|
||||
categoryHeaderRoleVariant.Title.color = veryDarkColor;
|
||||
categoryHeaderRoleVariant.Background.color = group.Color;
|
||||
}
|
||||
|
||||
@@ -362,7 +362,6 @@ public static class RoleSettingMenuPatches
|
||||
}
|
||||
|
||||
roleMenu.SetScrollBounds();
|
||||
roleMenu.scrollBar.ScrollToTop();
|
||||
_quotaTabCoroutine = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -279,8 +279,6 @@ public static class RoleGuidePatches
|
||||
MapBehaviour.Instance.Close();
|
||||
}
|
||||
|
||||
MeetingVoteAreaVisibility.HideNameplates(__instance);
|
||||
|
||||
if (HudManager.InstanceExists)
|
||||
{
|
||||
ConsoleJoystick.SetMode_MenuAdditive();
|
||||
@@ -392,13 +390,6 @@ public static class RoleGuidePatches
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MatchInfoGuide), nameof(MatchInfoGuide.Close))]
|
||||
private static void ClosePostfix(MatchInfoGuide __instance)
|
||||
{
|
||||
MeetingVoteAreaVisibility.Restore(__instance);
|
||||
}
|
||||
|
||||
private static void SetUpTabGrids(MatchInfoTabPos position)
|
||||
{
|
||||
tabButtonContainer.startCorner = GridLayoutGroup.Corner.UpperLeft;
|
||||
|
||||
@@ -106,7 +106,6 @@ internal static class MeetingHudPatches
|
||||
[HarmonyPatch(nameof(MeetingHud.OnDestroy))]
|
||||
public static void OnDestroyPatch(MeetingHud __instance)
|
||||
{
|
||||
MeetingVoteAreaVisibility.RestoreAll();
|
||||
MiraEventManager.InvokeEvent(new EndMeetingEvent(__instance));
|
||||
}
|
||||
|
||||
@@ -114,7 +113,6 @@ internal static class MeetingHudPatches
|
||||
[HarmonyPatch(nameof(MeetingHud.VotingComplete))]
|
||||
public static void VotingCompletePatch(MeetingHud __instance)
|
||||
{
|
||||
MeetingVoteAreaVisibility.RestoreAll();
|
||||
foreach (var meetingAbility in MeetingButtonManager.UntargetedButtons.Where(x => x.Enabled(PlayerControl.LocalPlayer.Data.Role) &&
|
||||
(x.DisableUponVoting || x.HideUponWrapUp)))
|
||||
{
|
||||
|
||||
@@ -238,7 +238,7 @@ public sealed class MiraPluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.PropertyType.IsAssignableTo(typeof(IBaseModdedOptionList)))
|
||||
if (property.PropertyType.IsAssignableTo(typeof(IModdedOptionList)))
|
||||
{
|
||||
ModdedOptionsManager.RegisterPropertyOptionList(type, property, pluginInfo);
|
||||
continue;
|
||||
@@ -259,7 +259,7 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
|
||||
foreach (var field in type.GetFields()
|
||||
.Where(f => f.FieldType.IsAssignableTo(typeof(IModdedOption)) || f.FieldType.IsAssignableTo(typeof(IBaseModdedOptionList))))
|
||||
.Where(f => f.FieldType.IsAssignableTo(typeof(IModdedOption)) || f.FieldType.IsAssignableTo(typeof(IModdedOptionList))))
|
||||
{
|
||||
Error($"{field.Name} is a field, not a property. Use properties for options.");
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="Color"/> struct.
|
||||
/// Extension methods for the <see cref="Color"/> and <see cref="Color32"/> structs.
|
||||
/// </summary>
|
||||
public static class ColorExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static float ToFloat(this byte @byte)
|
||||
{
|
||||
return @byte / 255f;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static byte ToByte(this float @float)
|
||||
{
|
||||
return (byte)MathF.Round(@float * 255f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relative luminance of a <see cref="Color"/> (WCAG 2.1 specification). 0 is black, 1 is white.
|
||||
/// </summary>
|
||||
@@ -19,6 +33,18 @@ public static class ColorExtensions
|
||||
(0.0722f * Linearize(color.b));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relative luminance of a <see cref="Color32"/> (WCAG 2.1 specification). 0 is black, 1 is white.
|
||||
/// </summary>
|
||||
/// <param name="color"><see cref="Color32"/> to calculate luminance for.</param>
|
||||
/// <returns>Luminance value between 0 and 1.</returns>
|
||||
public static float GetRelativeLuminance(this Color32 color)
|
||||
{
|
||||
return (0.2126f * Linearize(color.r.ToFloat())) +
|
||||
(0.7152f * Linearize(color.g.ToFloat())) +
|
||||
(0.0722f * Linearize(color.b.ToFloat()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearizes an sRGB component into linear space.
|
||||
/// </summary>
|
||||
@@ -26,7 +52,7 @@ public static class ColorExtensions
|
||||
/// <returns>The linearized result.</returns>
|
||||
public static float Linearize(float c)
|
||||
{
|
||||
return c <= 0.03928f ? c / 12.92f : Mathf.Pow((c + 0.055f) / 1.055f, 2.4f);
|
||||
return c <= 0.03928f ? c / 12.92f : MathF.Pow((c + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,11 +65,27 @@ public static class ColorExtensions
|
||||
{
|
||||
var luminanceA = colorA.GetRelativeLuminance();
|
||||
var luminanceB = colorB.GetRelativeLuminance();
|
||||
return (Mathf.Max(luminanceA, luminanceB) + 0.05f) / (Mathf.Min(luminanceA, luminanceB) + 0.05f);
|
||||
|
||||
return (Math.Max(luminanceA, luminanceB) + 0.05f) / (Math.Min(luminanceA, luminanceB) + 0.05f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates an accessible alternate <see cref="Color"/> with sufficient contrast.
|
||||
/// Calculates the contrast ratio between two <see cref="Color32"/>s.
|
||||
/// </summary>
|
||||
/// <param name="colorA">First <see cref="Color32"/>.</param>
|
||||
/// <param name="colorB">Second <see cref="Color32"/>.</param>
|
||||
/// <returns>Contrast ratio between the two <see cref="Color32"/>s.</returns>
|
||||
public static float GetContrastRatio(this Color32 colorA, Color32 colorB)
|
||||
{
|
||||
var luminanceA = colorA.GetRelativeLuminance();
|
||||
var luminanceB = colorB.GetRelativeLuminance();
|
||||
|
||||
return (Math.Max(luminanceA, luminanceB) + 0.05f) / (Math.Min(luminanceA, luminanceB) + 0.05f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates an accessible alternate <see cref="Color"/> by shifting towards black or white
|
||||
/// based on which extreme offers the highest potential contrast from the original color.
|
||||
/// </summary>
|
||||
/// <param name="color">Base <see cref="Color"/>.</param>
|
||||
/// <param name="desiredRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
@@ -57,10 +99,120 @@ public static class ColorExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the <see cref="Color"/> with the minimum contrast ratio to the target <see cref="Color"/>.
|
||||
/// Generates an accessible alternate <see cref="Color32"/> with sufficient contrast.
|
||||
/// </summary>
|
||||
/// <param name="color">Base <see cref="Color32"/>.</param>
|
||||
/// <param name="desiredRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>Alternate <see cref="Color32"/> with sufficient contrast.</returns>
|
||||
public static Color32 FindAlternateColor(this Color32 color, float desiredRatio = 4.5f)
|
||||
{
|
||||
var colorF = new Color(color.r.ToFloat(), color.g.ToFloat(), color.b.ToFloat());
|
||||
var result = colorF.FindAlternateColor(desiredRatio);
|
||||
return new Color32(result.r.ToByte(), result.g.ToByte(), result.b.ToByte(), color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Darkens a <see cref="Color"/> towards black until it reaches the target WCAG contrast ratio against a background.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A darkened <see cref="Color"/> meeting the contrast ratio, or black if impossible.</returns>
|
||||
public static Color DarkenToWCAG(this Color color, Color background, float targetRatio = 4.5f)
|
||||
{
|
||||
return color.GetContrastRatio(background) >= targetRatio
|
||||
? color
|
||||
: FindMinimumContrastColor(color, Color.black, targetRatio);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Darkens a <see cref="Color32"/> towards black until it reaches the target WCAG contrast ratio against a background.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color32"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color32"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A darkened <see cref="Color32"/> meeting the contrast ratio, or black if impossible.</returns>
|
||||
public static Color32 DarkenToWCAG(this Color32 color, Color32 background, float targetRatio = 4.5f)
|
||||
{
|
||||
var colorF = new Color(color.r.ToFloat(), color.g.ToFloat(), color.b.ToFloat(), color.a.ToFloat());
|
||||
var bgF = new Color(background.r.ToFloat(), background.g.ToFloat(), background.b.ToFloat(), background.a.ToFloat());
|
||||
|
||||
var result = colorF.DarkenToWCAG(bgF, targetRatio);
|
||||
return new Color32(result.r.ToByte(), result.g.ToByte(), result.b.ToByte(), color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightens a <see cref="Color"/> towards white until it reaches the target WCAG contrast ratio against a background.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A lightened <see cref="Color"/> meeting the contrast ratio, or white if impossible.</returns>
|
||||
public static Color LightenToWCAG(this Color color, Color background, float targetRatio = 4.5f)
|
||||
{
|
||||
return color.GetContrastRatio(background) >= targetRatio
|
||||
? color
|
||||
: FindMinimumContrastColor(color, Color.white, targetRatio);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightens a <see cref="Color32"/> towards white until it reaches the target WCAG contrast ratio against a background.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color32"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color32"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A lightened <see cref="Color32"/> meeting the contrast ratio, or white if impossible.</returns>
|
||||
public static Color32 LightenToWCAG(this Color32 color, Color32 background, float targetRatio = 4.5f)
|
||||
{
|
||||
var colorF = new Color(color.r.ToFloat(), color.g.ToFloat(), color.b.ToFloat(), color.a.ToFloat());
|
||||
var bgF = new Color(background.r.ToFloat(), background.g.ToFloat(), background.b.ToFloat(), background.a.ToFloat());
|
||||
|
||||
var result = colorF.LightenToWCAG(bgF, targetRatio);
|
||||
return new Color32(result.r.ToByte(), result.g.ToByte(), result.b.ToByte(), color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically decides whether to lighten or darken the <see cref="Color"/> to achieve WCAG compliance
|
||||
/// based on which extreme offers the highest potential contrast against the provided background.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A modified <see cref="Color"/> meeting the WCAG contrast requirement.</returns>
|
||||
public static Color EnsureWCAGContrast(this Color color, Color background, float targetRatio = 4.5f)
|
||||
{
|
||||
if (color.GetContrastRatio(background) >= targetRatio)
|
||||
return color;
|
||||
|
||||
var blackContrast = Color.black.GetContrastRatio(background);
|
||||
var whiteContrast = Color.white.GetContrastRatio(background);
|
||||
|
||||
return blackContrast > whiteContrast
|
||||
? color.DarkenToWCAG(background, targetRatio)
|
||||
: color.LightenToWCAG(background, targetRatio);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically decides whether to lighten or darken the <see cref="Color32"/> to achieve WCAG compliance.
|
||||
/// </summary>
|
||||
/// <param name="color">The foreground <see cref="Color32"/> to modify.</param>
|
||||
/// <param name="background">The background <see cref="Color32"/> it sits on.</param>
|
||||
/// <param name="targetRatio">Target contrast ratio (default 4.5f for AA).</param>
|
||||
/// <returns>A modified <see cref="Color32"/> meeting the WCAG contrast requirement.</returns>
|
||||
public static Color32 EnsureWCAGContrast(this Color32 color, Color32 background, float targetRatio = 4.5f)
|
||||
{
|
||||
var colorF = new Color(color.r.ToFloat(), color.g.ToFloat(), color.b.ToFloat(), color.a.ToFloat());
|
||||
var bgF = new Color(background.r.ToFloat(), background.g.ToFloat(), background.b.ToFloat(), background.a.ToFloat());
|
||||
|
||||
var result = colorF.EnsureWCAGContrast(bgF, targetRatio);
|
||||
return new Color32(result.r.ToByte(), result.g.ToByte(), result.b.ToByte(), color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the <see cref="Color"/> with the minimum contrast ratio to the target <see cref="Color"/> using binary search.
|
||||
/// </summary>
|
||||
/// <param name="baseColor">The base <see cref="Color"/> to start from.</param>
|
||||
/// <param name="targetColor">The target <see cref="Color"/> to compare against.</param>
|
||||
/// <param name="targetColor">The target <see cref="Color"/> to approach (usually white or black).</param>
|
||||
/// <param name="desiredRatio">The desired contrast ratio.</param>
|
||||
/// <returns>The <see cref="Color"/> with the minimum contrast ratio to the target <see cref="Color"/>.</returns>
|
||||
public static Color FindMinimumContrastColor(Color baseColor, Color targetColor, float desiredRatio)
|
||||
@@ -72,18 +224,28 @@ public static class ColorExtensions
|
||||
? desiredRatio * (baseLuminance + 0.05f) - 0.05f
|
||||
: (baseLuminance + 0.05f) / desiredRatio - 0.05f;
|
||||
|
||||
if (isLightening && targetLuminance > 1f) return Color.white;
|
||||
if (!isLightening && targetLuminance < 0f) return Color.black;
|
||||
if (isLightening && targetLuminance > 1f)
|
||||
return Color.white;
|
||||
|
||||
if (!isLightening && targetLuminance < 0f)
|
||||
return Color.black;
|
||||
|
||||
float low = 0f, high = 1f;
|
||||
var bestColor = targetColor;
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var t = (low + high) / 2f;
|
||||
var testColor = Color.Lerp(baseColor, targetColor, t);
|
||||
|
||||
var testColor = new Color(
|
||||
baseColor.r + (targetColor.r - baseColor.r) * t,
|
||||
baseColor.g + (targetColor.g - baseColor.g) * t,
|
||||
baseColor.b + (targetColor.b - baseColor.b) * t,
|
||||
baseColor.a);
|
||||
|
||||
var testLuminance = testColor.GetRelativeLuminance();
|
||||
|
||||
if ((isLightening && testLuminance >= targetLuminance) || (!isLightening && testLuminance <= targetLuminance))
|
||||
if (isLightening ? testLuminance >= targetLuminance : testLuminance <= targetLuminance)
|
||||
{
|
||||
high = t;
|
||||
bestColor = testColor;
|
||||
@@ -96,4 +258,128 @@ public static class ColorExtensions
|
||||
|
||||
return bestColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts a flat amount from the <see cref="Color"/>'s RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original color.</param>
|
||||
/// <param name="amount">The flat amount to subtract (typically 0.0 to 1.0).</param>
|
||||
/// <returns>A uniformly darkened <see cref="Color"/>.</returns>
|
||||
public static Color DarkenAbsolute(this Color color, float amount)
|
||||
{
|
||||
return new Color(
|
||||
Math.Max(0f, color.r - amount),
|
||||
Math.Max(0f, color.g - amount),
|
||||
Math.Max(0f, color.b - amount),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts a flat byte amount from the <see cref="Color32"/>'s RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original <see cref="Color32"/>.</param>
|
||||
/// <param name="amount">The flat amount to subtract (0 to 255).</param>
|
||||
/// <returns>A uniformly darkened <see cref="Color32"/>.</returns>
|
||||
public static Color32 DarkenAbsolute(this Color32 color, byte amount)
|
||||
{
|
||||
return new Color32(
|
||||
(byte)Math.Max(0, color.r - amount),
|
||||
(byte)Math.Max(0, color.g - amount),
|
||||
(byte)Math.Max(0, color.b - amount),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a flat amount to the <see cref="Color"/>'s RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original color.</param>
|
||||
/// <param name="amount">The flat amount to add (typically 0.0 to 1.0).</param>
|
||||
/// <returns>A uniformly lightened <see cref="Color"/>.</returns>
|
||||
public static Color LightenAbsolute(this Color color, float amount)
|
||||
{
|
||||
return new Color(
|
||||
Math.Min(1f, color.r + amount),
|
||||
Math.Min(1f, color.g + amount),
|
||||
Math.Min(1f, color.b + amount),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a flat byte amount to the <see cref="Color32"/>'s RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original <see cref="Color32"/>.</param>
|
||||
/// <param name="amount">The flat amount to add (0 to 255).</param>
|
||||
/// <returns>A uniformly lightened <see cref="Color32"/>.</returns>
|
||||
public static Color32 LightenAbsolute(this Color32 color, byte amount)
|
||||
{
|
||||
return new Color32(
|
||||
(byte)Math.Min(255, color.r + amount),
|
||||
(byte)Math.Min(255, color.g + amount),
|
||||
(byte)Math.Min(255, color.b + amount),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Darkens the <see cref="Color"/> multiplicatively, preserving the ratio between RGB channels to maintain hue.
|
||||
/// </summary>
|
||||
/// <param name="color">The original color.</param>
|
||||
/// <param name="percentage">The percentage to darken by (e.g., 0.2 for 20% darker).</param>
|
||||
/// <returns>A ratio-preserved darkened <see cref="Color"/>.</returns>
|
||||
public static Color DarkenRelative(this Color color, float percentage)
|
||||
{
|
||||
var multiplier = Math.Max(0f, Math.Min(1f, 1f - percentage));
|
||||
return new Color(
|
||||
color.r * multiplier,
|
||||
color.g * multiplier,
|
||||
color.b * multiplier,
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Darkens the <see cref="Color32"/> multiplicatively, preserving the ratio between RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original <see cref="Color32"/>.</param>
|
||||
/// <param name="percentage">The percentage to darken by (e.g., 0.2 for 20% darker).</param>
|
||||
/// <returns>A ratio-preserved darkened <see cref="Color32"/>.</returns>
|
||||
public static Color32 DarkenRelative(this Color32 color, float percentage)
|
||||
{
|
||||
var multiplier = Math.Max(0f, Math.Min(1f, 1f - percentage));
|
||||
return new Color32(
|
||||
(color.r * multiplier).ToByte(),
|
||||
(color.g * multiplier).ToByte(),
|
||||
(color.b * multiplier).ToByte(),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightens the <see cref="Color"/> multiplicatively, preserving the ratio between RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original color.</param>
|
||||
/// <param name="percentage">The percentage to lighten by (e.g., 0.2 for 20% lighter).</param>
|
||||
/// <returns>A ratio-preserved lightened <see cref="Color"/>.</returns>
|
||||
public static Color LightenRelative(this Color color, float percentage)
|
||||
{
|
||||
var multiplier = 1f + percentage;
|
||||
return new Color(
|
||||
Math.Min(1f, color.r * multiplier),
|
||||
Math.Min(1f, color.g * multiplier),
|
||||
Math.Min(1f, color.b * multiplier),
|
||||
color.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightens the <see cref="Color32"/> multiplicatively, preserving the ratio between RGB channels.
|
||||
/// </summary>
|
||||
/// <param name="color">The original <see cref="Color32"/>.</param>
|
||||
/// <param name="percentage">The percentage to lighten by (e.g., 0.2 for 20% lighter).</param>
|
||||
/// <returns>A ratio-preserved lightened <see cref="Color32"/>.</returns>
|
||||
public static Color32 LightenRelative(this Color32 color, float percentage)
|
||||
{
|
||||
var multiplier = 1f + percentage;
|
||||
return new Color32(
|
||||
Math.Min(255f, color.r * 255f * multiplier / 255f).ToByte(),
|
||||
Math.Min(255f, color.g * 255f * multiplier / 255f).ToByte(),
|
||||
Math.Min(255f, color.b * 255f * multiplier / 255f).ToByte(),
|
||||
color.a);
|
||||
}
|
||||
}
|
||||
@@ -607,14 +607,10 @@ public static class Extensions
|
||||
/// <param name="color">The original <see cref="Color32"/>.</param>
|
||||
/// <param name="darknessAmount">A darkness amount between 0 and 255.</param>
|
||||
/// <returns>The darkened <see cref="Color32"/>.</returns>
|
||||
[Obsolete("Use ColorExtensions.DarkenAbsolute instead. This will be removed in a future version.")]
|
||||
public static Color32 GetShadowColor(this Color32 color, byte darknessAmount)
|
||||
{
|
||||
return
|
||||
new Color32(
|
||||
(byte)Mathf.Clamp(color.r - darknessAmount, 0, 255),
|
||||
(byte)Mathf.Clamp(color.g - darknessAmount, 0, 255),
|
||||
(byte)Mathf.Clamp(color.b - darknessAmount, 0, 255),
|
||||
color.a);
|
||||
return color.DarkenAbsolute(darknessAmount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -623,14 +619,10 @@ public static class Extensions
|
||||
/// <param name="color">The original <see cref="Color"/>.</param>
|
||||
/// <param name="darknessAmount">A darkness amount between 0 and 1.</param>
|
||||
/// <returns>The darkened <see cref="Color"/>.</returns>
|
||||
[Obsolete("Use ColorExtensions.DarkenAbsolute instead. This will be removed in a future version.")]
|
||||
public static Color GetShadowColor(this Color color, float darknessAmount)
|
||||
{
|
||||
return
|
||||
new Color(
|
||||
MathUtilities.Clamp01(color.r - darknessAmount),
|
||||
MathUtilities.Clamp01(color.g - darknessAmount),
|
||||
MathUtilities.Clamp01(color.b - darknessAmount),
|
||||
color.a);
|
||||
return color.DarkenAbsolute(darknessAmount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -719,9 +711,10 @@ public static class Extensions
|
||||
/// <param name="color">The original <see cref="Color"/>.</param>
|
||||
/// <param name="amount">A <see langword="float"/> amount between 0 and 1.</param>
|
||||
/// <returns>The darkened <see cref="Color"/>.</returns>
|
||||
[Obsolete("Use ColorExtensions.DarkenAbsolute instead. This will be removed in a future version.")]
|
||||
public static Color DarkenColor(this Color color, float amount = 0.45f)
|
||||
{
|
||||
return new Color(color.r - amount, color.g - amount, color.b - amount);
|
||||
return color.DarkenAbsolute(amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -730,9 +723,10 @@ public static class Extensions
|
||||
/// <param name="color">The original <see cref="Color"/>.</param>
|
||||
/// <param name="amount">A <see langword="float"/> amount between 0.0 and 1.0.</param>
|
||||
/// <returns>The lightened <see cref="Color"/>.</returns>
|
||||
[Obsolete("Use ColorExtensions.LightenAbsolute instead. This will be removed in a future version.")]
|
||||
public static Color LightenColor(this Color color, float amount = 0.45f)
|
||||
{
|
||||
return new Color(color.r + amount, color.g + amount, color.b + amount);
|
||||
return color.LightenAbsolute(amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -936,7 +936,7 @@ public static class Helpers
|
||||
{
|
||||
const float contentTop = 0.95f;
|
||||
const float horizontalOffset = -0.2f;
|
||||
const float groupHeaderContentGap = 0.05f;
|
||||
const float headerContentGap = 0.2f;
|
||||
const int contentSortingOrder = 151;
|
||||
|
||||
columns = Mathf.Clamp(columns, 1, 6);
|
||||
@@ -1024,7 +1024,7 @@ public static class Helpers
|
||||
groupColumns[group] = i % columns;
|
||||
bandHeights[band] = Mathf.Max(
|
||||
bandHeights[band],
|
||||
rowPitch * (groupedSettings[i].Count() + 1) + groupHeaderContentGap + 0.25f);
|
||||
rowPitch * (groupedSettings[i].Count() + 1) + headerContentGap + 0.25f);
|
||||
}
|
||||
|
||||
var bandOffset = 0f;
|
||||
@@ -1040,6 +1040,7 @@ public static class Helpers
|
||||
}
|
||||
}
|
||||
|
||||
var contentBottom = float.PositiveInfinity;
|
||||
var previousGroup = (AbstractOptionGroup?)null;
|
||||
var rowIndex = 0;
|
||||
var column = 0;
|
||||
@@ -1088,12 +1089,12 @@ public static class Helpers
|
||||
|
||||
if (headerSource)
|
||||
{
|
||||
const float groupHeaderScale = 0.42f;
|
||||
const float headerScale = 0.46f;
|
||||
var headerWidth = groupsAsColumns
|
||||
? columnWidth / groupHeaderScale
|
||||
: (columns * columnWidth + (columns - 1) * columnGap) / groupHeaderScale;
|
||||
? columnWidth / headerScale
|
||||
: (columns * columnWidth + (columns - 1) * columnGap) / headerScale;
|
||||
var header = Object.Instantiate(headerSource!, page.transform, false);
|
||||
header.transform.localScale = Vector3.one * groupHeaderScale;
|
||||
header.transform.localScale = Vector3.one * headerScale;
|
||||
if (groupsAsColumns)
|
||||
{
|
||||
var totalWidth = columns * columnWidth + (columns - 1) * columnGap;
|
||||
@@ -1154,6 +1155,12 @@ public static class Helpers
|
||||
renderer.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
renderer.material.SetInt(PlayerMaterial.MaskLayer, 50);
|
||||
renderer.sortingOrder = contentSortingOrder;
|
||||
if (renderer.enabled && renderer.sprite)
|
||||
{
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(renderer.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var text in header.GetComponentsInChildren<TextMeshPro>(true))
|
||||
@@ -1164,6 +1171,9 @@ public static class Helpers
|
||||
if (text.enabled)
|
||||
{
|
||||
text.ForceMeshUpdate();
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(text.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1181,7 +1191,7 @@ public static class Helpers
|
||||
horizontalOffset;
|
||||
var centerY = groupsAsColumns && settings[i].Group is { } rowGroup
|
||||
? contentTop - groupTopOffsets[rowGroup] -
|
||||
(rowPitch * (groupRows[rowGroup] + 1)) - groupHeaderContentGap - (rowHeight / 2f)
|
||||
(rowPitch * (groupRows[rowGroup] + 1)) - headerContentGap - (rowHeight / 2f)
|
||||
: contentTop - (rowHeight / 2f) - (rowIndex * rowPitch) - groupSpacing;
|
||||
var row = Object.Instantiate(rowPrefab, page.transform);
|
||||
row.enabled = false;
|
||||
@@ -1228,6 +1238,27 @@ public static class Helpers
|
||||
renderer.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
renderer.material.SetInt(PlayerMaterial.MaskLayer, 50);
|
||||
renderer.sortingOrder = contentSortingOrder;
|
||||
if (renderer.enabled &&
|
||||
renderer.sprite &&
|
||||
renderer.transform != row.PlusBtn.transform &&
|
||||
!renderer.transform.IsChildOf(row.PlusBtn.transform) &&
|
||||
renderer.transform != row.MinusBtn.transform &&
|
||||
!renderer.transform.IsChildOf(row.MinusBtn.transform))
|
||||
{
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(renderer.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var text in row.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
if (text.enabled)
|
||||
{
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(text.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
row.gameObject.SetActive(true);
|
||||
@@ -1246,26 +1277,6 @@ public static class Helpers
|
||||
}
|
||||
}
|
||||
|
||||
page.SetActive(true);
|
||||
var contentBottom = float.PositiveInfinity;
|
||||
foreach (var text in page.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
if (text.enabled && text.gameObject.activeInHierarchy)
|
||||
{
|
||||
text.ForceMeshUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var renderer in page.GetComponentsInChildren<Renderer>(true))
|
||||
{
|
||||
if (renderer.enabled && renderer.gameObject.activeInHierarchy)
|
||||
{
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(renderer.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
var maskArea = parent.transform.FindChild("MaskArea")?.GetComponent<SpriteRenderer>();
|
||||
var maskBottom = maskArea
|
||||
? inner.InverseTransformPoint(maskArea!.bounds.min).y
|
||||
@@ -1277,6 +1288,7 @@ public static class Helpers
|
||||
? contentOverflow + 0.05f
|
||||
: 0f;
|
||||
parent.SetYBoundsMax(Mathf.Clamp(scrollRange, 0f, 999f));
|
||||
page.SetActive(true);
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
internal static class MeetingVoteAreaVisibility
|
||||
{
|
||||
private static readonly Dictionary<Renderer, bool> originalRendererStates = [];
|
||||
private static readonly HashSet<int> activeOwners = [];
|
||||
|
||||
internal static void HideNameplates(UnityEngine.Object owner)
|
||||
{
|
||||
var meetingHud = MeetingHud.Instance;
|
||||
if (!owner ||
|
||||
!meetingHud ||
|
||||
meetingHud.state is not (MeetingHud.MeetingStates.Discussion or
|
||||
MeetingHud.MeetingStates.NotVoted or
|
||||
MeetingHud.MeetingStates.Voted))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activeOwners.Add(owner.GetInstanceID());
|
||||
foreach (var playerVoteArea in meetingHud.playerStates)
|
||||
{
|
||||
if (!playerVoteArea)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var buttons = playerVoteArea.Buttons;
|
||||
foreach (var renderer in playerVoteArea.GetComponentsInChildren<Renderer>(true))
|
||||
{
|
||||
if (!renderer ||
|
||||
(buttons &&
|
||||
(renderer.transform == buttons.transform || renderer.transform.IsChildOf(buttons.transform))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!originalRendererStates.ContainsKey(renderer))
|
||||
{
|
||||
originalRendererStates.Add(renderer, renderer.enabled);
|
||||
}
|
||||
|
||||
renderer.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Restore(UnityEngine.Object owner)
|
||||
{
|
||||
if (!owner || !activeOwners.Remove(owner.GetInstanceID()) || activeOwners.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RestoreAll();
|
||||
}
|
||||
|
||||
internal static void RestoreAll()
|
||||
{
|
||||
activeOwners.Clear();
|
||||
foreach (var rendererState in originalRendererStates)
|
||||
{
|
||||
if (rendererState.Key)
|
||||
{
|
||||
rendererState.Key.enabled = rendererState.Value;
|
||||
}
|
||||
}
|
||||
|
||||
originalRendererStates.Clear();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user