mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-27 23:44:35 +00:00
Add new value type + number suffix
This commit is contained in:
1 parent
7917d4b5d9
commit
38ec50bcc7
7 files changed
+264
-15
No files matched your search
+2
-1
@@ -5,4 +5,5 @@ obj/
|
||||
bin/
|
||||
|
||||
*.user
|
||||
*.lock.json
|
||||
*.lock.json
|
||||
.qodo
|
||||
+10
-10
@@ -1,19 +1,13 @@
|
||||
using System;
|
||||
using BepInEx;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MonoMod.Utils;
|
||||
using Reactor;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.ProBuilder;
|
||||
using Delegate = Il2CppSystem.Delegate;
|
||||
|
||||
namespace MiraAPI;
|
||||
|
||||
@@ -26,9 +20,13 @@ namespace MiraAPI;
|
||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
||||
public partial class MiraApiPlugin : BasePlugin
|
||||
{
|
||||
public static Color MiraColor { get; } = new Color32(238, 154, 112, 255);
|
||||
public static Color DefaultHeaderColor = new Color32(77, 77, 77, 255);
|
||||
internal static Color MiraColor { get; } = new Color32(238, 154, 112, 255);
|
||||
internal static Color DefaultHeaderColor { get; } = new Color32(77, 77, 77, 255);
|
||||
|
||||
private static MiraPluginManager? PluginManager { get; set; }
|
||||
|
||||
internal static ConfigEntry<string>? DistanceSuffix { get; private set; }
|
||||
|
||||
internal Harmony Harmony { get; } = new(Id);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -38,6 +36,8 @@ public partial class MiraApiPlugin : BasePlugin
|
||||
|
||||
ReactorCredits.Register("Mira API", Version, true, ReactorCredits.AlwaysShow);
|
||||
|
||||
DistanceSuffix = Config.Bind("Display", "Distance", "unit(s)", "Dictates how a distance is shown in numeric option displays");
|
||||
|
||||
PluginManager = new MiraPluginManager();
|
||||
PluginManager.Initialize();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Denotes a failure in conversion of values.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to log.</param>
|
||||
public class ConversionFailException(string message) : Exception(message);
|
||||
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Modules;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a collection of enum values that can be stored and manipulated as a comma-separated string.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The enum type that this collection will store.</typeparam>
|
||||
/// <param name="values">One or more enum values to initialize the collection with.</param>
|
||||
[Serializable]
|
||||
public struct MultiSelectValue<T>(params T[] values) : IEnumerable<T>, IEquatable<MultiSelectValue<T>> where T : struct, Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the underlying comma-separated string representation of enum values.
|
||||
/// </summary>
|
||||
public string Values
|
||||
{
|
||||
readonly get => Helpers.Join(',', values);
|
||||
set => values = [.. value.TrueSplit(',').Select(Enum.Parse<T>)];
|
||||
}
|
||||
private HashSet<T> values = [.. values];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of values contained within.
|
||||
/// </summary>
|
||||
public readonly int Count => values.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a single enum value to the end of the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">The enum value to add.</param>
|
||||
/// <returns><c>true</c> if successfully added; otherwise, <c>false</c>.</returns>
|
||||
public readonly bool Add(T item) => values.Add(item);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of the specified enum value.<br/>
|
||||
/// Returns <c>true</c> if the value was found and removed, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="item">The enum value to remove.</param>
|
||||
/// <returns><c>true</c> if successfully removed; otherwise, <c>false</c>.</returns>
|
||||
public readonly bool Remove(T item) => values.Remove(item);
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple enum values to the end of the collection.
|
||||
/// </summary>
|
||||
/// <param name="items">The collection of enum values to add.</param>
|
||||
public readonly void AddRange(IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
values.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes multiple enum values from the collection.
|
||||
/// </summary>
|
||||
/// <param name="items">The enum values to remove.</param>
|
||||
/// <returns>The number of items successfully removed.</returns>
|
||||
public readonly int RemoveRange(params T[] items) => RemoveRange((IEnumerable<T>)items);
|
||||
|
||||
/// <summary>
|
||||
/// Removes multiple enum values from the collection.
|
||||
/// </summary>
|
||||
/// <param name="items">The collection of enum values to remove.</param>
|
||||
/// <returns>The number of items successfully removed.</returns>
|
||||
public readonly int RemoveRange(IEnumerable<T> items) => items.Count(Remove);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the collection contains the specified enum value.
|
||||
/// </summary>
|
||||
/// <param name="item">The enum value to locate.</param>
|
||||
/// <returns>true if the item is found in the collection; otherwise, false.</returns>
|
||||
public readonly bool Contains(T item) => values.Contains(item);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all enum values that match the specified predicate condition.<br/>
|
||||
/// Iterates through the collection and removes each matching value.
|
||||
/// </summary>
|
||||
/// <param name="predicate">A function that defines the condition for removing items.</param>
|
||||
/// <returns>The number of items removed from the collection.</returns>
|
||||
public readonly int RemoveAll(Func<T, bool> predicate)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
foreach (var item in this)
|
||||
{
|
||||
if (predicate(item) && Remove(item))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all enum values from the collection.
|
||||
/// </summary>
|
||||
public readonly void Clear() => values.Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first value in the collection.
|
||||
/// </summary>
|
||||
/// <returns>Returns the first value.</returns>
|
||||
public readonly T First() => values.First();
|
||||
|
||||
/// <summary>
|
||||
/// Converts the collection to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A comma-separated string of enum values.</returns>
|
||||
public override readonly string ToString() => Values;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override readonly bool Equals(object? obj) => obj is MultiSelectValue<T> other && Equals(other);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public readonly bool Equals(MultiSelectValue<T> other) => values.SetEquals(other.values);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override readonly int GetHashCode() => Values?.GetHashCode() ?? 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public readonly IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)values).GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance to its string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
public static implicit operator string(MultiSelectValue<T> value) => value.Values;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance to its array representation of values.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
public static implicit operator T[](MultiSelectValue<T> value) => [.. value.values];
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance to one singular value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
/// <exception cref="ConversionFailException">There were either no values, or more than one value.</exception>
|
||||
#pragma warning disable S3877 // Exceptions should not be thrown from unexpected methods
|
||||
public static implicit operator T(MultiSelectValue<T> value) =>
|
||||
value.Count == 1
|
||||
? value.values.First()
|
||||
: throw new ConversionFailException($"Tried to convert multiple or no values ({value.Values}) to a singular one");
|
||||
#pragma warning restore S3877 // Exceptions should not be thrown from unexpected methods
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value to an instance of MultiSelectValue.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
public static implicit operator MultiSelectValue<T>(T value) => new(value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the array of values to an instance of MultiSelectValue.
|
||||
/// </summary>
|
||||
/// <param name="values">The values to convert.</param>
|
||||
public static implicit operator MultiSelectValue<T>(T[] values) => new(values);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value string to an instance of MultiSelectValue.
|
||||
/// </summary>
|
||||
/// <param name="values">The values to convert.</param>
|
||||
public static implicit operator MultiSelectValue<T>(string values) => new([.. values.TrueSplit(',').Select(Enum.Parse<T>)]);
|
||||
|
||||
/// <summary>
|
||||
/// Equality comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">Left.</param>
|
||||
/// <param name="right">Right.</param>
|
||||
public static bool operator ==(MultiSelectValue<T> left, MultiSelectValue<T> right) => left.Equals(right);
|
||||
|
||||
/// <summary>
|
||||
/// Inequality comparison.
|
||||
/// </summary>
|
||||
/// <param name="left">Left.</param>
|
||||
/// <param name="right">Right.</param>
|
||||
public static bool operator !=(MultiSelectValue<T> left, MultiSelectValue<T> right) => !left.Equals(right);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ public static class SettingPatches
|
||||
MiraNumberSuffixes.None => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo),
|
||||
MiraNumberSuffixes.Multiplier => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo) + "x",
|
||||
MiraNumberSuffixes.Percent => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo) + "%",
|
||||
MiraNumberSuffixes.Distance => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo) + MiraApiPlugin.DistanceSuffix.Value,
|
||||
_ => TranslationController.Instance.GetString(
|
||||
StringNames.GameSecondsAbbrev,
|
||||
(Il2CppSystem.Object[])[value.ToString(__instance.FormatString, CultureInfo.InvariantCulture)]),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -37,7 +39,7 @@ public static class Helpers
|
||||
return true;
|
||||
default:
|
||||
{
|
||||
var num = Random.RandomRangeInt(1, 101);
|
||||
var num = UnityEngine.Random.RandomRangeInt(1, 101);
|
||||
return num <= probability;
|
||||
}
|
||||
}
|
||||
@@ -375,6 +377,7 @@ public static class Helpers
|
||||
MiraNumberSuffixes.Multiplier => "x",
|
||||
MiraNumberSuffixes.Seconds => "s",
|
||||
MiraNumberSuffixes.Percent => "%",
|
||||
MiraNumberSuffixes.Distance => MiraApiPlugin.DistanceSuffix?.Value ?? "unit",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
@@ -397,7 +400,34 @@ public static class Helpers
|
||||
/// <returns>The random string.</returns>
|
||||
public static string RandomString(int length, string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
{
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Random.RandomRangeInt(0, s.Length)]).ToArray());
|
||||
return new string([.. Enumerable.Repeat(chars, length).Select(s => s[UnityEngine.Random.RandomRangeInt(0, s.Length)])]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shorthand for <see cref="string.Split(char, StringSplitOptions)"/> that removes empty entries and trims leading and ending spaces.
|
||||
/// </summary>
|
||||
/// <param name="value">The string to split.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <returns>An array of substrings.</returns>
|
||||
public static string[] TrueSplit(this string value, char separator) => value.Split(separator, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
/// <summary>
|
||||
/// Joins a collection of items that are separated by a character.
|
||||
/// </summary>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="items">The collection of items to string together.</param>
|
||||
/// <typeparam name="T">The type of the items.</typeparam>
|
||||
/// <returns>A string formed by concatenating the ToString results of each item, each separated by a separator.</returns>
|
||||
public static string Join<T>(char separator, IEnumerable<T> items) => Join(separator.ToString(), items);
|
||||
|
||||
/// <inheritdoc cref="Join{T}(char, IEnumerable{T})"/>
|
||||
public static string Join<T>(string separator, IEnumerable<T> items)
|
||||
{
|
||||
if (!items.Any())
|
||||
return string.Empty;
|
||||
|
||||
var result = string.Empty;
|
||||
items.Do(x => result += $"{separator}{x}");
|
||||
return result[separator.Length..];
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,32 @@
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// An enum to dictate how to represent a numeric value.
|
||||
/// </summary>
|
||||
public enum MiraNumberSuffixes
|
||||
{
|
||||
/// <summary>
|
||||
/// There should be no suffix.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Display as a multiplier.
|
||||
/// </summary>
|
||||
Multiplier,
|
||||
|
||||
/// <summary>
|
||||
/// Display in seconds.
|
||||
/// </summary>
|
||||
Seconds,
|
||||
|
||||
/// <summary>
|
||||
/// Display as a percentage.
|
||||
/// </summary>
|
||||
Percent,
|
||||
|
||||
/// <summary>
|
||||
/// Display in units.
|
||||
/// </summary>
|
||||
Distance,
|
||||
}
|
||||
Reference in new issue
Block a user