mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-27 23:44:35 +00:00
Compare commits
22
Commits
id-builder
...
test-fixes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1947c536d3 | ||
|
|
28b276b9e2 | ||
|
|
e0e55e065e | ||
|
|
89e8870e35 | ||
|
|
c627c03590 | ||
|
|
29e9f9c8b5 | ||
|
|
af255c3e64 | ||
|
|
a8dfbb616c | ||
|
|
b79c14ce50 | ||
|
|
17dafadec8 | ||
|
|
f9274eda09 | ||
|
|
10daf01a55 | ||
|
|
1daffd7560 | ||
|
|
7c09dbdaaa | ||
|
|
0596278b78 | ||
|
|
13864b8fd9 | ||
|
|
f8c9045517 | ||
|
|
7632e543c8 | ||
|
|
6deaae350e | ||
|
|
5f6ac17e52 | ||
|
|
16e2c25c2d | ||
|
|
0e02a02156 |
No files matched your search
@@ -104,3 +104,12 @@ 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
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
|
||||
<VersionPrefix>0.5.0</VersionPrefix>
|
||||
<VersionPrefix>0.6.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System.Reflection;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
|
||||
namespace MiraAPI.Example;
|
||||
|
||||
public static class ExampleAssets
|
||||
{
|
||||
public static LoadableResourceAsset ExampleButton { get; } = new("MiraAPI.Example.Resources.ExampleButton.png");
|
||||
public static LoadableResourceAsset CallMeetingButton { get; } = new("MiraAPI.Example.Resources.CallMeeting.png");
|
||||
private static readonly Assembly _assembly = typeof(MiraAssets).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);
|
||||
|
||||
// Credit to EpicHorrors for the teleport button asset.
|
||||
public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png");
|
||||
public static LoadableResourceAsset SharpshootButton { get; } = new("MiraAPI.Example.Resources.SharpshootButton.png");
|
||||
public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg");
|
||||
public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png", _assembly);
|
||||
public static LoadableResourceAsset SharpshootButton { get; } = new("MiraAPI.Example.Resources.SharpshootButton.png", _assembly);
|
||||
public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg", _assembly);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public static class ExampleEventHandlers
|
||||
|
||||
MiraEventManager.RegisterEventHandler<CompleteTaskEvent>(@event =>
|
||||
{
|
||||
Logger<ExamplePlugin>.Info($"{@event.Player.Data.PlayerName} completed {@event.Task.TaskType.ToString()}");
|
||||
Logger<ExamplePlugin>.Info($"{@event.Player.Data.PlayerName} completed {@event.Task.TaskType}");
|
||||
});
|
||||
|
||||
// You can also unregister event handlers using the handle returned from RegisterEventHandler.
|
||||
@@ -89,7 +89,7 @@ public static class ExampleEventHandlers
|
||||
[RegisterEvent]
|
||||
public static void UpdateSystemEventHandler(UpdateSystemEvent @event)
|
||||
{
|
||||
Logger<ExamplePlugin>.Error(@event.SystemType.ToString());
|
||||
Logger<ExamplePlugin>.Error(@event.SystemType);
|
||||
}
|
||||
|
||||
// Example event handler
|
||||
|
||||
@@ -19,7 +19,7 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin
|
||||
{
|
||||
public ExamplePlugin()
|
||||
{
|
||||
MiraLocaleManager.Register("mira.example");
|
||||
MiraLocaleManager.Register("mira.example", typeof(ExamplePlugin).Assembly);
|
||||
}
|
||||
|
||||
public Harmony Harmony { get; } = new(Id);
|
||||
|
||||
@@ -35,7 +35,7 @@ public static class MiraEventManager
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}");
|
||||
Error($"Error invoking event handler for {typeof(T).Name}: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public static class MiraEventManager
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error($"Error invoking event handler for {type.Name}: {ex.ToString()}");
|
||||
Error($"Error invoking event handler for {type.Name}: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
public class ModdedEnumOptionListAttribute(string title, Type enumType, string[]? values = null)
|
||||
: ModdedOptionListAttribute(title)
|
||||
{
|
||||
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] as ModdedEnumOption;
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedEnumOption;
|
||||
opt?.SetValue((int)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?[idx] is ModdedEnumOption opt
|
||||
return HolderOptionList?.ElementAt(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 IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] as ModdedEnumOption<T>;
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedEnumOption<T>;
|
||||
opt?.SetValue((T)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?[idx] is ModdedEnumOption<T> opt
|
||||
return HolderOptionList?.ElementAt(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 IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] is not ModdedNumberOption opt)
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedNumberOption opt)
|
||||
return;
|
||||
|
||||
var final = value switch
|
||||
@@ -95,7 +95,7 @@ public class ModdedNumberOptionListAttribute(
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
|
||||
if (HolderOptionList?.ElementAt(idx) is not ModdedNumberOption opt)
|
||||
throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedNumberOption");
|
||||
|
||||
var value = opt.Value;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAttribute
|
||||
{
|
||||
internal IModdedOptionList? HolderOptionList { get; set; }
|
||||
internal IBaseModdedOptionList? 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 IModdedOptionList? CreateOptionList(IList value, PropertyInfo property);
|
||||
internal abstract IBaseModdedOptionList? 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 IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] is not ModdedPlayerOption opt)
|
||||
if (HolderOptionList?.ElementAt(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?[idx] is not ModdedPlayerOption opt)
|
||||
if (HolderOptionList?.ElementAt(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 IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] as ModdedStringOption;
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedStringOption;
|
||||
opt?.SetValue((string)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?[idx] is ModdedStringOption opt
|
||||
return HolderOptionList?.ElementAt(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 IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
|
||||
internal override IBaseModdedOptionList 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?[idx] as ModdedToggleOption;
|
||||
var opt = HolderOptionList?.ElementAt(idx) as ModdedToggleOption;
|
||||
opt?.SetValue((bool)value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue(int idx)
|
||||
{
|
||||
return HolderOptionList?[idx] is ModdedToggleOption opt
|
||||
return HolderOptionList?.ElementAt(idx) is ModdedToggleOption opt
|
||||
? opt.Value
|
||||
: throw new InvalidOperationException($"Holder option for {GetFormattedTitle(idx)} is not a ModdedToggleOption.");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.Networking;
|
||||
@@ -143,9 +144,11 @@ public interface IModdedOption
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for list of modded options.
|
||||
/// Base interface for list of modded options.
|
||||
/// <para/>
|
||||
/// Do not implement directly, implement <see cref="IModdedOptionList"/> or <see cref="IModdedOptionList{T}"/> instead.
|
||||
/// </summary>
|
||||
public interface IModdedOptionList : IReadOnlyList<IModdedOption>
|
||||
public interface IBaseModdedOptionList : IEnumerable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the function to name the keys of the individual options in the configuration file.
|
||||
@@ -153,18 +156,34 @@ public interface IModdedOptionList : IReadOnlyList<IModdedOption>
|
||||
/// 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> : IModdedOptionList
|
||||
public interface IModdedOptionList<out T> : IBaseModdedOptionList, IReadOnlyList<T>
|
||||
where T : IModdedOption
|
||||
{
|
||||
/// <inheritdoc cref="IReadOnlyList{T}.this[int]"/>
|
||||
new T this[int index] { get; }
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
new IEnumerator<T> GetEnumerator();
|
||||
IModdedOption IBaseModdedOptionList.ElementAt(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ public static class ModdedOptionsManager
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.GetValue(group) is not IModdedOptionList optionList)
|
||||
if (property.GetValue(group) is not IBaseModdedOptionList 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[i], group, configName(i), pluginInfo);
|
||||
RegisterOption(optionList.ElementAt(i), group, configName(i), pluginInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ public static class ModdedOptionsManager
|
||||
|
||||
for (var i = 0; i < optionList.Count; i++)
|
||||
{
|
||||
var option = optionList[i];
|
||||
var option = optionList.ElementAt(i);
|
||||
|
||||
if (visibilityFactory != null)
|
||||
option.Visible = (Func<bool>)(visibilityFactory(i) ?? DelegateUtilities.AlwaysTrue);
|
||||
|
||||
@@ -62,13 +62,4 @@ 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,6 +3,7 @@ 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;
|
||||
@@ -106,6 +107,7 @@ 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;
|
||||
@@ -116,6 +118,7 @@ public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMult
|
||||
back.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
selectedEntries.Clear();
|
||||
MeetingVoteAreaVisibility.Restore(Component);
|
||||
onClick(null);
|
||||
}));
|
||||
|
||||
@@ -177,6 +180,7 @@ public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMult
|
||||
}
|
||||
|
||||
selectedEntries.Add(menuEntry);
|
||||
MeetingVoteAreaVisibility.Restore(Component);
|
||||
|
||||
// Add choice to list of selections
|
||||
if (selectedEntries.Count <= totalSelections)
|
||||
|
||||
@@ -387,6 +387,7 @@ public abstract class CustomPaginableMenu : CustomPhoneMenu<CustomPaginableMenu.
|
||||
protected void Begin(Action registerEntryPanels)
|
||||
{
|
||||
MinigameStubs.Begin(Component, null);
|
||||
MeetingVoteAreaVisibility.HideNameplates(Component);
|
||||
|
||||
searchText = string.Empty;
|
||||
currentPage = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -21,6 +22,7 @@ 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,6 +74,7 @@ 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.
|
||||
@@ -106,6 +107,17 @@ 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>
|
||||
@@ -118,11 +130,13 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
tab.transform.DestroyChildren();
|
||||
tab.gameObject.SetActive(false);
|
||||
|
||||
if (Scroller == null)
|
||||
if (Scroller == null || Scroller.transform.parent != tab.transform)
|
||||
{
|
||||
Scroller = Helpers.CreateScroller(tab.transform, OptionsMenuPatches.MaskCollider);
|
||||
}
|
||||
|
||||
Labels.Clear();
|
||||
|
||||
if (TabButton != null)
|
||||
{
|
||||
TabButton.Content = tab.gameObject;
|
||||
@@ -216,7 +230,11 @@ public abstract class LocalSettingsTab(ConfigFile config)
|
||||
contentIndex++;
|
||||
}
|
||||
|
||||
Scroller.SetBounds(new FloatRange(0, (Settings.Count + Buttons.Count) * 0.5f - 5f), new FloatRange(0, 0));
|
||||
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);
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public partial class MiraApiPlugin : BasePlugin, IMiraPlugin
|
||||
PluginManager = new MiraPluginManager();
|
||||
PluginManager.Initialize(this, this);
|
||||
|
||||
MiraLocaleManager.Register("mira.api");
|
||||
MiraLocaleManager.Register("mira.api", typeof(MiraApiPlugin).Assembly);
|
||||
LocalizationManager.Register(new MiraLocalizationProvider());
|
||||
|
||||
IL2CPPChainloader.Instance.Finished +=
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error while deactivating modifier {modifier.ModifierName}: {e.ToString()}");
|
||||
Error($"Error while deactivating modifier {modifier.ModifierName}: {e}");
|
||||
}
|
||||
|
||||
Modifiers.Remove(modifier);
|
||||
@@ -95,7 +95,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error while activating modifier {modifier.ModifierName}: {e.ToString()}");
|
||||
Error($"Error while activating modifier {modifier.ModifierName}: {e}");
|
||||
}
|
||||
|
||||
if (modifier is TimedModifier { AutoStart: true } timer)
|
||||
@@ -122,7 +122,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error while (fixed) updating modifier {modifier.ModifierName}: {e.ToString()}");
|
||||
Error($"Error while (fixed) updating modifier {modifier.ModifierName}: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error while updating modifier {modifier.ModifierName}: {e.ToString()}");
|
||||
Error($"Error while updating modifier {modifier.ModifierName}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Globalization;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.PluginLoading;
|
||||
|
||||
namespace MiraAPI.Modifiers.Types;
|
||||
|
||||
@@ -571,7 +571,7 @@ public static class CustomMurderRpc
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error with kill animation: {e.ToString()}");
|
||||
Error($"Error with kill animation: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ public static class CustomMurderRpc
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Error with kill animation: {e.ToString()}");
|
||||
Error($"Error with kill animation: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
@@ -27,7 +28,7 @@ public static class CanUsePatches
|
||||
|
||||
[HarmonyPriority(Priority.Last)]
|
||||
[HarmonyPrefix]
|
||||
public static bool CanUsePatch(Il2CppSystem.Object __instance, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
|
||||
public static bool CanUsePatch(MonoBehaviour __instance, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
|
||||
{
|
||||
canUse = couldUse = false;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
@@ -25,7 +26,7 @@ public static class UsePatches
|
||||
|
||||
[HarmonyPriority(Priority.Last)]
|
||||
[HarmonyPrefix]
|
||||
public static bool UsePatch(Il2CppSystem.Object __instance)
|
||||
public static bool UsePatch(MonoBehaviour __instance)
|
||||
{
|
||||
var @event = new PlayerUseEvent(__instance.Cast<IUsable>());
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
|
||||
@@ -186,9 +186,11 @@ public static class TaskAdderPatches
|
||||
systemTypes = SystemTypes.UpperEngine;
|
||||
}
|
||||
|
||||
if (!folders.TryGetValue(systemTypes.ToString(), out var taskFolder3))
|
||||
var systemType = systemTypes.ToString();
|
||||
|
||||
if (!folders.TryGetValue(systemType, out var taskFolder3))
|
||||
{
|
||||
taskFolder3 = folders[systemTypes.ToString()] = Object.Instantiate(__instance.RootFolderPrefab, __instance.transform);
|
||||
taskFolder3 = folders[systemType] = Object.Instantiate(__instance.RootFolderPrefab, __instance.transform);
|
||||
taskFolder3.SetFolderColor(TaskFolder.FolderColor.Tan);
|
||||
taskFolder3.gameObject.SetActive(false);
|
||||
taskFolder3.FolderName = systemTypes == SystemTypes.UpperEngine
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
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;
|
||||
@@ -183,7 +185,9 @@ public static class OptionsMenuPatches
|
||||
// Tabs with index 10 and above are the mod settings tabs
|
||||
if (index >= 10)
|
||||
{
|
||||
CustomOpen(LocalSettingsManager.AvailableTabs[index - 10]);
|
||||
var tab = LocalSettingsManager.AvailableTabs[index - 10];
|
||||
CustomOpen(tab);
|
||||
__instance.StartCoroutine(RefreshScrollBoundsAfterOpen(__instance, tab).WrapToIl2Cpp());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -229,6 +233,16 @@ 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)
|
||||
|
||||
@@ -362,6 +362,7 @@ public static class RoleSettingMenuPatches
|
||||
}
|
||||
|
||||
roleMenu.SetScrollBounds();
|
||||
roleMenu.scrollBar.ScrollToTop();
|
||||
_quotaTabCoroutine = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ using MiraAPI.Roles;
|
||||
using MiraAPI.Translation;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using MiraAPI.Utilities.Components;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
@@ -278,6 +279,8 @@ public static class RoleGuidePatches
|
||||
MapBehaviour.Instance.Close();
|
||||
}
|
||||
|
||||
MeetingVoteAreaVisibility.HideNameplates(__instance);
|
||||
|
||||
if (HudManager.InstanceExists)
|
||||
{
|
||||
ConsoleJoystick.SetMode_MenuAdditive();
|
||||
@@ -389,6 +392,13 @@ 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,6 +106,7 @@ internal static class MeetingHudPatches
|
||||
[HarmonyPatch(nameof(MeetingHud.OnDestroy))]
|
||||
public static void OnDestroyPatch(MeetingHud __instance)
|
||||
{
|
||||
MeetingVoteAreaVisibility.RestoreAll();
|
||||
MiraEventManager.InvokeEvent(new EndMeetingEvent(__instance));
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ 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)))
|
||||
{
|
||||
|
||||
@@ -25,6 +25,26 @@ public class MiraPluginInfo
|
||||
PluginId = info.Metadata.GUID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's ID, as defined in the plugin's BepInEx metadata.
|
||||
/// </summary>
|
||||
public string PluginId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's instance as an <see cref="IMiraPlugin"/>.
|
||||
/// </summary>
|
||||
public IMiraPlugin MiraPlugin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's BepInEx metadata.
|
||||
/// </summary>
|
||||
public PluginInfo PluginInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's <see cref="ConfigFile"/>.
|
||||
/// </summary>
|
||||
public ConfigFile PluginConfig { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IReadOnlyCollection{T}"/> of this <see cref="IMiraPlugin"/>'s <see cref="BaseModifier"/>s. This is not safe for <see cref="BaseModifier"/>s with constructors.
|
||||
/// </summary>
|
||||
@@ -45,15 +65,6 @@ public class MiraPluginInfo
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<ushort, RoleBehaviour> Roles { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read only dictionary of Game Mode IDs and the AbstractGameMode object they are associated with.
|
||||
/// </summary>
|
||||
/// <returns>Read only dictionary of IDs and Game Modes.</returns>
|
||||
public ReadOnlyDictionary<uint, AbstractGameMode> GetModes()
|
||||
{
|
||||
return new ReadOnlyDictionary<uint, AbstractGameMode>(GameModes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IReadOnlyCollection{T}"/> of this <see cref="IMiraPlugin"/>'s <see cref="CustomActionButton"/>.
|
||||
/// </summary>
|
||||
@@ -74,6 +85,15 @@ public class MiraPluginInfo
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<OptionPreset> Presets { get; internal set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read only dictionary of Game Mode IDs and the AbstractGameMode object they are associated with.
|
||||
/// </summary>
|
||||
/// <returns>Read only dictionary of IDs and Game Modes.</returns>
|
||||
public ReadOnlyDictionary<uint, AbstractGameMode> GetModes()
|
||||
{
|
||||
return new ReadOnlyDictionary<uint, AbstractGameMode>(GameModes);
|
||||
}
|
||||
|
||||
internal void SavePublicCollections()
|
||||
{
|
||||
Presets = [.. InternalPresets];
|
||||
@@ -87,39 +107,13 @@ public class MiraPluginInfo
|
||||
}
|
||||
|
||||
internal List<OptionPreset> InternalPresets { get; } = [];
|
||||
|
||||
internal List<AbstractOptionGroup> InternalOptionGroups { get; } = [];
|
||||
|
||||
internal List<IModdedOption> InternalOptions { get; } = [];
|
||||
|
||||
internal List<BaseModifier> InternalModifiers { get; } = [];
|
||||
internal List<CustomActionButton> InternalButtons { get; } = [];
|
||||
internal List<AbstractOptionGroup> InternalOptionGroups { get; } = [];
|
||||
internal List<MeetingActionButton> InternalMeetingButtons { get; } = [];
|
||||
internal List<TargetedMeetingButton> InternalTargetedMeetingButtons { get; } = [];
|
||||
|
||||
internal Dictionary<uint, AbstractGameMode> GameModes { get; } = [];
|
||||
internal Dictionary<ushort, RoleBehaviour> InternalRoles { get; } = [];
|
||||
|
||||
internal List<CustomActionButton> InternalButtons { get; } = [];
|
||||
|
||||
internal List<TargetedMeetingButton> InternalTargetedMeetingButtons { get; } = [];
|
||||
|
||||
internal List<MeetingActionButton> InternalMeetingButtons { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's ID, as defined in the plugin's BepInEx metadata.
|
||||
/// </summary>
|
||||
public string PluginId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's instance as an <see cref="IMiraPlugin"/>.
|
||||
/// </summary>
|
||||
public IMiraPlugin MiraPlugin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's BepInEx metadata.
|
||||
/// </summary>
|
||||
public PluginInfo PluginInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin's <see cref="ConfigFile"/>.
|
||||
/// </summary>
|
||||
public ConfigFile PluginConfig { get; }
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
@@ -24,7 +25,6 @@ using MiraAPI.Roles;
|
||||
using MiraAPI.Translation;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.PluginLoading;
|
||||
|
||||
@@ -49,100 +49,14 @@ public sealed class MiraPluginManager
|
||||
Instance = this;
|
||||
CustomGameModeManager.RegisterDefaultMode();
|
||||
CustomGameModeManager.GetAndSetGameMode();
|
||||
|
||||
if (IL2CPPChainloader.Instance.Plugins.TryGetValue(MiraApiPlugin.Id, out var newPlugin))
|
||||
{
|
||||
var assembly = Assembly.GetCallingAssembly();
|
||||
var info = new MiraPluginInfo(apiPlugin, newPlugin);
|
||||
var roles = new List<Type>();
|
||||
var info = RegisterPlugin(typeof(MiraPluginManager).Assembly, apiPlugin, newPlugin, miraApiPlugin, true);
|
||||
|
||||
var oldConfigSetting = info.PluginConfig.SaveOnConfigSet;
|
||||
info.PluginConfig.SaveOnConfigSet = false;
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.IsAbstract || type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var method in AccessTools.GetDeclaredMethods(type))
|
||||
{
|
||||
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
||||
if (eventAttribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!method.IsStatic)
|
||||
{
|
||||
Error($"Event method {method.Name} in {type.Name} must be static.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
||||
{
|
||||
Error($"Invalid event registration method {method.Name} in {type.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = parameters[0].ParameterType;
|
||||
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
||||
}
|
||||
|
||||
if (RegisterModifier(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterOptions(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterLocalTabs(type, miraApiPlugin))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterRole(type, info, out var role))
|
||||
{
|
||||
roles.Add(role);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterButton(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterGameOver(type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterGameModeAttribute(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterColorClasses(type);
|
||||
RegisterKeybinds(type, miraApiPlugin);
|
||||
}
|
||||
|
||||
info.PluginConfig.Save();
|
||||
info.PluginConfig.SaveOnConfigSet = oldConfigSetting;
|
||||
MiraApiConfig = info.PluginConfig;
|
||||
|
||||
info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||
QueuedRoleRegistrations.Add(info, roles);
|
||||
|
||||
_registeredPlugins.Add(assembly, info);
|
||||
MiraApiPluginInfo = info;
|
||||
|
||||
info.SavePublicCollections();
|
||||
PresetManager.CreateDefaultPreset(info);
|
||||
PresetManager.LoadPresets(info);
|
||||
Info($"Registering Mira API as mod.");
|
||||
}
|
||||
|
||||
@@ -153,110 +67,14 @@ public sealed class MiraPluginManager
|
||||
return;
|
||||
}
|
||||
|
||||
var info = new MiraPluginInfo(miraPlugin, pluginInfo);
|
||||
var roles = new List<Type>();
|
||||
|
||||
var oldConfigSetting = info.PluginConfig.SaveOnConfigSet;
|
||||
info.PluginConfig.SaveOnConfigSet = false;
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var method in AccessTools.GetDeclaredMethods(type))
|
||||
{
|
||||
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
||||
if (eventAttribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!method.IsStatic)
|
||||
{
|
||||
Error($"Event method {method.Name} in {type.Name} must be static.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
||||
{
|
||||
Error($"Invalid event registration method {method.Name} in {type.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = parameters[0].ParameterType;
|
||||
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
||||
}
|
||||
|
||||
if (RegisterModifier(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterOptions(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterLocalTabs(type, plugin))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterRole(type, info, out var role))
|
||||
{
|
||||
roles.Add(role);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterButton(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterGameOver(type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterMeetingAbility(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterTargetedMeetingAbility(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterGameModeAttribute(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterColorClasses(type);
|
||||
RegisterKeybinds(type, plugin);
|
||||
}
|
||||
|
||||
info.PluginConfig.Save();
|
||||
info.PluginConfig.SaveOnConfigSet = oldConfigSetting;
|
||||
|
||||
info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||
QueuedRoleRegistrations.Add(info, roles);
|
||||
|
||||
_registeredPlugins.Add(assembly, info);
|
||||
|
||||
info.SavePublicCollections();
|
||||
PresetManager.CreateDefaultPreset(info);
|
||||
PresetManager.LoadPresets(info);
|
||||
RegisterPlugin(assembly, miraPlugin, pluginInfo, plugin, false);
|
||||
Info($"Registering mod {pluginInfo.Metadata.GUID} with Mira API.");
|
||||
};
|
||||
IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors;
|
||||
|
||||
IL2CPPChainloader.Instance.Finished += () =>
|
||||
{
|
||||
PaletteManager.RegisterAllColors();
|
||||
|
||||
// Save all buttons into a read-only collection for easy access
|
||||
CustomButtonManager.Buttons = new ReadOnlyCollection<CustomActionButton>(CustomButtonManager.CustomButtons);
|
||||
CustomButtonManager.EventTypes = new ReadOnlyDictionary<Type, Type>(CustomButtonManager.ButtonEventTypes);
|
||||
@@ -269,9 +87,101 @@ public sealed class MiraPluginManager
|
||||
|
||||
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
|
||||
};
|
||||
}
|
||||
|
||||
RegisterKeybinds(typeof(MiraGlobalKeybinds), PluginSingleton<MiraApiPlugin>.Instance);
|
||||
RegisterLocalTabs(typeof(MiraApiSettings), PluginSingleton<MiraApiPlugin>.Instance);
|
||||
private MiraPluginInfo RegisterPlugin(Assembly assembly, IMiraPlugin plugin, PluginInfo pluginInfo, BasePlugin basePlugin, bool isMira)
|
||||
{
|
||||
var info = new MiraPluginInfo(plugin, pluginInfo);
|
||||
var roles = new List<Type>();
|
||||
|
||||
var oldConfigSetting = info.PluginConfig.SaveOnConfigSet;
|
||||
info.PluginConfig.SaveOnConfigSet = false;
|
||||
|
||||
ProcessAssemblyTypes(assembly, info, basePlugin, roles, isMira);
|
||||
|
||||
info.PluginConfig.Save();
|
||||
info.PluginConfig.SaveOnConfigSet = oldConfigSetting;
|
||||
|
||||
info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||
QueuedRoleRegistrations.Add(info, roles);
|
||||
_registeredPlugins.Add(assembly, info);
|
||||
|
||||
info.SavePublicCollections();
|
||||
PresetManager.CreateDefaultPreset(info);
|
||||
PresetManager.LoadPresets(info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private static void ProcessAssemblyTypes(Assembly assembly, MiraPluginInfo info, BasePlugin basePlugin, List<Type> roles, bool isMira)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if ((isMira && type.IsAbstract) || type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
||||
continue;
|
||||
|
||||
RegisterEvents(type);
|
||||
|
||||
if (RegisterModifier(type, info))
|
||||
continue;
|
||||
|
||||
if (RegisterOptions(type, info))
|
||||
continue;
|
||||
|
||||
if (RegisterLocalTabs(type, basePlugin))
|
||||
continue;
|
||||
|
||||
if (RegisterRole(type, info, out var role))
|
||||
{
|
||||
roles.Add(role);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterButton(type, info))
|
||||
continue;
|
||||
|
||||
if (RegisterGameOver(type))
|
||||
continue;
|
||||
|
||||
if (RegisterMeetingAbility(type, info))
|
||||
continue;
|
||||
|
||||
if (RegisterTargetedMeetingAbility(type, info))
|
||||
continue;
|
||||
|
||||
if (RegisterGameModeAttribute(type, info))
|
||||
continue;
|
||||
|
||||
RegisterColorClasses(type);
|
||||
RegisterKeybinds(type, basePlugin);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterEvents(Type type)
|
||||
{
|
||||
foreach (var method in AccessTools.GetDeclaredMethods(type))
|
||||
{
|
||||
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
||||
|
||||
if (eventAttribute == null)
|
||||
continue;
|
||||
|
||||
if (!method.IsStatic)
|
||||
{
|
||||
Error($"Event method {method.Name} in {type.Name} must be static.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
||||
{
|
||||
Error($"Invalid event registration method {method.Name} in {type.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = parameters[0].ParameterType;
|
||||
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -328,7 +238,7 @@ public sealed class MiraPluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.PropertyType.IsAssignableTo(typeof(IModdedOptionList)))
|
||||
if (property.PropertyType.IsAssignableTo(typeof(IBaseModdedOptionList)))
|
||||
{
|
||||
ModdedOptionsManager.RegisterPropertyOptionList(type, property, pluginInfo);
|
||||
continue;
|
||||
@@ -349,7 +259,7 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
|
||||
foreach (var field in type.GetFields()
|
||||
.Where(f => f.FieldType.IsAssignableTo(typeof(IModdedOption)) || f.FieldType.IsAssignableTo(typeof(IModdedOptionList))))
|
||||
.Where(f => f.FieldType.IsAssignableTo(typeof(IModdedOption)) || f.FieldType.IsAssignableTo(typeof(IBaseModdedOptionList))))
|
||||
{
|
||||
Error($"{field.Name} is a field, not a property. Use properties for options.");
|
||||
}
|
||||
@@ -358,7 +268,7 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Failed to register options for {type.Name}: {e.ToString()}");
|
||||
Error($"Failed to register options for {type.Name}: {e}");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -543,7 +453,7 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error($"Failed to register options for {type.Name}: {e.ToString()}");
|
||||
Error($"Failed to register options for {type.Name}: {e}");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -72,6 +72,7 @@ public static class MiraLocaleManager
|
||||
/// </summary>
|
||||
public static Dictionary<MiraLanguage, string> LangCultureList { get; } = new()
|
||||
{
|
||||
// Vanilla
|
||||
{ MiraLanguage.English, "en-US" },
|
||||
{ MiraLanguage.Latam, "es-419" },
|
||||
{ MiraLanguage.Brazilian, "pt-BR" },
|
||||
@@ -88,15 +89,17 @@ public static class MiraLocaleManager
|
||||
{ MiraLanguage.SChinese, "zh-CN" },
|
||||
{ MiraLanguage.TChinese, "zh-TW" },
|
||||
{ MiraLanguage.Irish, "ga-IE" },
|
||||
{ MiraLanguage.Polish, "pl-PL" }, // Custom
|
||||
{ MiraLanguage.Turkish, "tr-TR" }, // Custom
|
||||
{ MiraLanguage.Swedish, "sv-SE" }, // Custom
|
||||
{ MiraLanguage.Lithuanian, "lt-LT" }, // Custom
|
||||
{ MiraLanguage.Czech, "cs-CZ" }, // Custom
|
||||
{ MiraLanguage.LChinese, "lzh-CN" }, // Custom
|
||||
{ MiraLanguage.Greek, "el-GR" }, // Custom
|
||||
{ MiraLanguage.Arabic, "arb" }, // Custom
|
||||
{ MiraLanguage.Hebrew, "heb" }, // Custom
|
||||
|
||||
// Custom
|
||||
{ MiraLanguage.Polish, "pl-PL" },
|
||||
{ MiraLanguage.Turkish, "tr-TR" },
|
||||
{ MiraLanguage.Swedish, "sv-SE" },
|
||||
{ MiraLanguage.Lithuanian, "lt-LT" },
|
||||
{ MiraLanguage.Czech, "cs-CZ" },
|
||||
{ MiraLanguage.LChinese, "lzh-CN" },
|
||||
{ MiraLanguage.Greek, "el-GR" },
|
||||
{ MiraLanguage.Arabic, "arb" },
|
||||
{ MiraLanguage.Hebrew, "heb" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -123,26 +126,49 @@ public static class MiraLocaleManager
|
||||
/// Call once per mod during plugin Load().
|
||||
/// </summary>
|
||||
/// <param name="modGuid">The mod GUID (e.g., "mira.example").</param>
|
||||
[Obsolete("Pass typeof(YourPlugin).Assembly directly to Register for better performance.")]
|
||||
public static void Register(string modGuid)
|
||||
{
|
||||
var callingAssembly = Assembly.GetCallingAssembly();
|
||||
|
||||
LoadInternalStrings(callingAssembly, callingAssembly.GetName().Name!, modGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers translations for a mod.
|
||||
/// Call once per mod during plugin Load().
|
||||
/// </summary>
|
||||
/// <param name="modGuid">The mod GUID (e.g., "mira.example").</param>
|
||||
/// <param name="assembly">The <see cref="Assembly"/> to load the strings from.</param>
|
||||
public static void Register(string modGuid, Assembly assembly)
|
||||
{
|
||||
LoadInternalStrings(assembly, assembly.GetName().Name!, modGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers translations for a mod.
|
||||
/// Call once per mod during plugin Load().
|
||||
/// </summary>
|
||||
/// <param name="modGuid">The mod GUID (e.g., "mira.example").</param>
|
||||
/// <param name="internalName">The mod's root namespace (e.g., "mira.api").</param>
|
||||
[Obsolete("Pass typeof(YourPlugin).Assembly directly to Register for better performance.")]
|
||||
public static void Register(string modGuid, string internalName)
|
||||
{
|
||||
var callingAssembly = Assembly.GetCallingAssembly();
|
||||
|
||||
LoadInternalStrings(callingAssembly, internalName, modGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers translations for a mod.
|
||||
/// Call once per mod during plugin Load().
|
||||
/// </summary>
|
||||
/// <param name="modGuid">The mod GUID (e.g., "mira.example").</param>
|
||||
/// <param name="internalName">The mod's root namespace (e.g., "mira.api").</param>
|
||||
/// <param name="assembly">The <see cref="Assembly"/> to load the strings from.</param>
|
||||
public static void Register(string modGuid, string internalName, Assembly assembly)
|
||||
{
|
||||
LoadInternalStrings(assembly, internalName, modGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a key into the current language.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -6,17 +7,39 @@ namespace MiraAPI.Utilities.Assets;
|
||||
/// <summary>
|
||||
/// A utility class for loading .WAV audio assets from the DLL's embedded resources.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the wave file.</param>
|
||||
public class LoadableAudioResourceAsset(string path) : LoadableAsset<AudioClip>
|
||||
public class LoadableAudioResourceAsset : LoadableAsset<AudioClip>
|
||||
{
|
||||
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
|
||||
private readonly string _path;
|
||||
private readonly Assembly _assembly;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadableAudioResourceAsset"/> class with the provided resource path and the assembly containing the asset.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the wave file.</param>
|
||||
/// <param name="assembly">The <see cref="Assembly"/> containing the asset.</param>
|
||||
public LoadableAudioResourceAsset(string path, Assembly assembly)
|
||||
{
|
||||
_path = path;
|
||||
_assembly = assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadableAudioResourceAsset"/> class with the provided resource path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the wave file.</param>
|
||||
[Obsolete("Pass typeof(YourPlugin).Assembly directly to the constructor for better performance.")]
|
||||
public LoadableAudioResourceAsset(string path)
|
||||
{
|
||||
_path = path;
|
||||
_assembly = Assembly.GetCallingAssembly();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AudioClip LoadAsset()
|
||||
{
|
||||
if (!LoadedAsset)
|
||||
{
|
||||
LoadedAsset = AudioTools.LoadAudioFromResources(path, _assembly);
|
||||
LoadedAsset = AudioTools.LoadAudioFromResources(_path, _assembly);
|
||||
}
|
||||
|
||||
return LoadedAsset!;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
@@ -6,18 +7,44 @@ namespace MiraAPI.Utilities.Assets;
|
||||
/// <summary>
|
||||
/// A utility class for loading assets from embedded resources.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the embedded resource.</param>
|
||||
/// <param name="pixelsPerUnit">The pixels per unit for the loaded sprite.</param>
|
||||
public class LoadableResourceAsset(string path, float pixelsPerUnit = 100f) : LoadableAsset<Sprite>
|
||||
public class LoadableResourceAsset : LoadableAsset<Sprite>
|
||||
{
|
||||
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
|
||||
private readonly string _path;
|
||||
private readonly float _pixelsPerUnit;
|
||||
private readonly Assembly _assembly;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadableResourceAsset"/> class with the provided resource path and the assembly containing the asset.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the embedded resource.</param>
|
||||
/// <param name="assembly">The <see cref="Assembly"/> containing the asset.</param>
|
||||
/// <param name="pixelsPerUnit">The pixels per unit for the loaded sprite.</param>
|
||||
public LoadableResourceAsset(string path, Assembly assembly, float pixelsPerUnit = 100f)
|
||||
{
|
||||
_path = path;
|
||||
_assembly = assembly;
|
||||
_pixelsPerUnit = pixelsPerUnit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadableResourceAsset"/> class with the provided resource path and the assembly containing the asset.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the embedded resource.</param>
|
||||
/// <param name="pixelsPerUnit">The pixels per unit for the loaded sprite.</param>
|
||||
[Obsolete("Pass typeof(YourPlugin).Assembly directly to the constructor for better performance.")]
|
||||
public LoadableResourceAsset(string path, float pixelsPerUnit = 100f)
|
||||
{
|
||||
_path = path;
|
||||
_pixelsPerUnit = pixelsPerUnit;
|
||||
_assembly = Assembly.GetCallingAssembly();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Sprite LoadAsset()
|
||||
{
|
||||
if (!LoadedAsset)
|
||||
{
|
||||
LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly, pixelsPerUnit);
|
||||
LoadedAsset = SpriteTools.LoadSpriteFromPath(_path, _assembly, _pixelsPerUnit);
|
||||
}
|
||||
|
||||
return LoadedAsset!;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Reactor.Utilities;
|
||||
using System.Reflection;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
@@ -8,11 +9,13 @@ namespace MiraAPI.Utilities.Assets;
|
||||
/// </summary>
|
||||
public static class MiraAssets
|
||||
{
|
||||
private static readonly Assembly _assembly = typeof(MiraAssets).Assembly;
|
||||
|
||||
static MiraAssets()
|
||||
{
|
||||
var boxTex = SpriteTools.LoadTextureFromResourcePath(
|
||||
"MiraAPI.Resources.RoundedBox.png",
|
||||
System.Reflection.Assembly.GetExecutingAssembly());
|
||||
_assembly);
|
||||
var boxSprite = Sprite.Create(
|
||||
boxTex,
|
||||
new Rect(0, 0, boxTex.width, boxTex.height),
|
||||
@@ -58,7 +61,7 @@ public static class MiraAssets
|
||||
/// <summary>
|
||||
/// Gets the empty <see cref="Sprite"/> asset.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset Empty { get; } = new("MiraAPI.Resources.Empty.png");
|
||||
public static LoadableResourceAsset Empty { get; } = new("MiraAPI.Resources.Empty.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RoundedBox <see cref="Sprite"/>, which is a rounded rectangle used for UI elements.
|
||||
@@ -68,312 +71,312 @@ public static class MiraAssets
|
||||
/// <summary>
|
||||
/// Gets the Next Button sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset NextButton { get; } = new("MiraAPI.Resources.NextButton.png");
|
||||
public static LoadableResourceAsset NextButton { get; } = new("MiraAPI.Resources.NextButton.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mira settings icon.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SettingsIcon { get; } = new("MiraAPI.Resources.Settings.png");
|
||||
public static LoadableResourceAsset SettingsIcon { get; } = new("MiraAPI.Resources.Settings.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the highlighted Next Button sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset NextButtonActive { get; } = new("MiraAPI.Resources.NextButtonActive.png");
|
||||
public static LoadableResourceAsset NextButtonActive { get; } = new("MiraAPI.Resources.NextButtonActive.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Cog icon used in Role Settings Menu.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset Cog { get; } = new("MiraAPI.Resources.Cog.png");
|
||||
public static LoadableResourceAsset Cog { get; } = new("MiraAPI.Resources.Cog.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Checkmark Box used in the Settings Menu.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset CheckmarkBox { get; } = new("MiraAPI.Resources.CheckMarkBox.png");
|
||||
public static LoadableResourceAsset CheckmarkBox { get; } = new("MiraAPI.Resources.CheckMarkBox.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Reset Box used in the Settings Menu.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ResetButton { get; } = new("MiraAPI.Resources.ResetButton.png");
|
||||
public static LoadableResourceAsset ResetButton { get; } = new("MiraAPI.Resources.ResetButton.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Checkmark used in the Settings Menu.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset Checkmark { get; } = new("MiraAPI.Resources.Checkmark.png");
|
||||
public static LoadableResourceAsset Checkmark { get; } = new("MiraAPI.Resources.Checkmark.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the white CategoryHeader used in the Settings Menu.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset CategoryHeader { get; } = new("MiraAPI.Resources.CategoryHeader.png");
|
||||
public static LoadableResourceAsset CategoryHeader { get; } = new("MiraAPI.Resources.CategoryHeader.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the Keybind icons.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset KeybindButton { get; } = new("MiraAPI.Resources.KeybindButton.png");
|
||||
public static LoadableResourceAsset KeybindButton { get; } = new("MiraAPI.Resources.KeybindButton.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for crewmate role files in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset CrewmateFile { get; } = new("MiraAPI.Resources.CrewmateFile.png");
|
||||
public static LoadableResourceAsset CrewmateFile { get; } = new("MiraAPI.Resources.CrewmateFile.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for impostor role files in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ImpostorFile { get; } = new("MiraAPI.Resources.ImpostorFile.png");
|
||||
public static LoadableResourceAsset ImpostorFile { get; } = new("MiraAPI.Resources.ImpostorFile.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for custom team role files in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset CustomTeamFile { get; } = new("MiraAPI.Resources.CustomFile.png");
|
||||
public static LoadableResourceAsset CustomTeamFile { get; } = new("MiraAPI.Resources.CustomFile.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for modifier file in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ModifierFile { get; } = new("MiraAPI.Resources.ModifierFile.png");
|
||||
public static LoadableResourceAsset ModifierFile { get; } = new("MiraAPI.Resources.ModifierFile.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the Classic gamemode.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ClassicGamemodeIcon { get; } = new("MiraAPI.Resources.ClassicGamemodeIcon.png");
|
||||
public static LoadableResourceAsset ClassicGamemodeIcon { get; } = new("MiraAPI.Resources.ClassicGamemodeIcon.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the Hide n Seek gamemode.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset HnSGamemodeIcon { get; } = new("MiraAPI.Resources.HnSGamemodeIcon.png");
|
||||
public static LoadableResourceAsset HnSGamemodeIcon { get; } = new("MiraAPI.Resources.HnSGamemodeIcon.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for timed modifier file in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset TimedModifierFile { get; } = new("MiraAPI.Resources.TimedModifierFile.png");
|
||||
public static LoadableResourceAsset TimedModifierFile { get; } = new("MiraAPI.Resources.TimedModifierFile.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the new chat button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ChatHoverSprite { get; } = new("MiraAPI.Resources.NormalChatHover.png");
|
||||
public static LoadableResourceAsset ChatHoverSprite { get; } = new("MiraAPI.Resources.NormalChatHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the new chat button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ChatIdleSprite { get; } = new("MiraAPI.Resources.NormalChatIdle.png");
|
||||
public static LoadableResourceAsset ChatIdleSprite { get; } = new("MiraAPI.Resources.NormalChatIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the new chat button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset ChatOpenSprite { get; } = new("MiraAPI.Resources.NormalChatOpen.png");
|
||||
public static LoadableResourceAsset ChatOpenSprite { get; } = new("MiraAPI.Resources.NormalChatOpen.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for players button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiPlayersButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonHover.png");
|
||||
public static LoadableResourceAsset WikiPlayersButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the players button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiPlayersButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonIdle.png");
|
||||
public static LoadableResourceAsset WikiPlayersButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the players button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiPlayersButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonOpen.png");
|
||||
public static LoadableResourceAsset WikiPlayersButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonOpen.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the settings button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiSettingsButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonHover.png");
|
||||
public static LoadableResourceAsset WikiSettingsButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the settings button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiSettingsButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonIdle.png");
|
||||
public static LoadableResourceAsset WikiSettingsButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the settings button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiSettingsButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonOpen.png");
|
||||
public static LoadableResourceAsset WikiSettingsButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonOpen.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiRolesButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonHover.png");
|
||||
public static LoadableResourceAsset WikiRolesButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiRolesButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonIdle.png");
|
||||
public static LoadableResourceAsset WikiRolesButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiRolesButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonOpen.png");
|
||||
public static LoadableResourceAsset WikiRolesButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonOpen.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the modifiers button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiModifiersButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonHover.png");
|
||||
public static LoadableResourceAsset WikiModifiersButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the modifiers button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiModifiersButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonIdle.png");
|
||||
public static LoadableResourceAsset WikiModifiersButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the modifiers button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset WikiModifiersButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonOpen.png");
|
||||
public static LoadableResourceAsset WikiModifiersButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarModifiersButtonOpen.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupCountHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountHover.png");
|
||||
public static LoadableResourceAsset GroupCountHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupCountIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountIdle.png");
|
||||
public static LoadableResourceAsset GroupCountIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupFactionHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionHover.png");
|
||||
public static LoadableResourceAsset GroupFactionHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupFactionIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionIdle.png");
|
||||
public static LoadableResourceAsset GroupFactionIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupNoneHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneHover.png");
|
||||
public static LoadableResourceAsset GroupNoneHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset GroupNoneIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneIdle.png");
|
||||
public static LoadableResourceAsset GroupNoneIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SearchClearHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearHover.png");
|
||||
public static LoadableResourceAsset SearchClearHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SearchClearIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearIdle.png");
|
||||
public static LoadableResourceAsset SearchClearIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SearchIconHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconHover.png");
|
||||
public static LoadableResourceAsset SearchIconHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SearchIconIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconIdle.png");
|
||||
public static LoadableResourceAsset SearchIconIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SortingAzHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzHover.png");
|
||||
public static LoadableResourceAsset SortingAzHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SortingAzIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzIdle.png");
|
||||
public static LoadableResourceAsset SortingAzIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SortingZaHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaHover.png");
|
||||
public static LoadableResourceAsset SortingZaHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SortingZaIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaIdle.png");
|
||||
public static LoadableResourceAsset SortingZaIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleAllHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllHover.png");
|
||||
public static LoadableResourceAsset VisibleAllHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleAllIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllIdle.png");
|
||||
public static LoadableResourceAsset VisibleAllIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleOffHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffHover.png");
|
||||
public static LoadableResourceAsset VisibleOffHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleOffIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffIdle.png");
|
||||
public static LoadableResourceAsset VisibleOffIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleOnHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnHover.png");
|
||||
public static LoadableResourceAsset VisibleOnHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the roles button while hovering.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset VisibleOnIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnIdle.png");
|
||||
public static LoadableResourceAsset VisibleOnIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for crewmates.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconCrewmate { get; } = new("MiraAPI.Resources.Wiki.IconCrewmate.png");
|
||||
public static LoadableResourceAsset IconCrewmate { get; } = new("MiraAPI.Resources.Wiki.IconCrewmate.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for impostors.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconImpostor { get; } = new("MiraAPI.Resources.Wiki.IconImpostor.png");
|
||||
public static LoadableResourceAsset IconImpostor { get; } = new("MiraAPI.Resources.Wiki.IconImpostor.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for neutrals.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconNeutral { get; } = new("MiraAPI.Resources.Wiki.IconNeutral.png");
|
||||
public static LoadableResourceAsset IconNeutral { get; } = new("MiraAPI.Resources.Wiki.IconNeutral.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for the player list.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconPlayerList { get; } = new("MiraAPI.Resources.Wiki.IconPlayerList.png");
|
||||
public static LoadableResourceAsset IconPlayerList { get; } = new("MiraAPI.Resources.Wiki.IconPlayerList.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for settings.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconSettings { get; } = new("MiraAPI.Resources.Wiki.IconSettings.png");
|
||||
public static LoadableResourceAsset IconSettings { get; } = new("MiraAPI.Resources.Wiki.IconSettings.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used for terminology.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset IconTerminology { get; } = new("MiraAPI.Resources.Wiki.IconTerminology.png");
|
||||
public static LoadableResourceAsset IconTerminology { get; } = new("MiraAPI.Resources.Wiki.IconTerminology.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Page switching sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset PageLeftHover { get; } = new("MiraAPI.Resources.Wiki.PageLeftHover.png");
|
||||
public static LoadableResourceAsset PageLeftHover { get; } = new("MiraAPI.Resources.Wiki.PageLeftHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Page switching sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset PageLeftIdle { get; } = new("MiraAPI.Resources.Wiki.PageLeftIdle.png");
|
||||
public static LoadableResourceAsset PageLeftIdle { get; } = new("MiraAPI.Resources.Wiki.PageLeftIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Page switching sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset PageRightHover { get; } = new("MiraAPI.Resources.Wiki.PageRightHover.png");
|
||||
public static LoadableResourceAsset PageRightHover { get; } = new("MiraAPI.Resources.Wiki.PageRightHover.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Page switching sprite.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset PageRightIdle { get; } = new("MiraAPI.Resources.Wiki.PageRightIdle.png");
|
||||
public static LoadableResourceAsset PageRightIdle { get; } = new("MiraAPI.Resources.Wiki.PageRightIdle.png", _assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sprite used below the tab icons in the wiki.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset TabButtonContainer { get; } = new("MiraAPI.Resources.Wiki.TabButtonContainer.png");
|
||||
public static LoadableResourceAsset TabButtonContainer { get; } = new("MiraAPI.Resources.Wiki.TabButtonContainer.png", _assembly);
|
||||
|
||||
internal static LoadableResourceAsset BlankSprite { get; } = new("MiraAPI.Resources.BlankSprite.png");
|
||||
internal static LoadableResourceAsset BlankSprite { get; } = new("MiraAPI.Resources.BlankSprite.png", _assembly);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
namespace MiraAPI.Utilities.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A spinning ring used to indicate that content is loading.
|
||||
@@ -26,6 +26,8 @@ namespace MiraAPI.Utilities;
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
private static readonly Regex DisplayRegex = new(@"([^\^])([A-Z][a-z$])", default, Regex.InfiniteMatchTimeout);
|
||||
|
||||
internal static NetData GetNetData(this ICustomRole role)
|
||||
{
|
||||
var count = role.GetCount();
|
||||
@@ -492,14 +494,25 @@ public static class Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a proper string for an <see cref="Enum"/>. (with spaces).
|
||||
/// Gets a proper string for an <see cref="Enum"/> (with spaces).
|
||||
/// </summary>
|
||||
/// <param name="enum">The <see cref="Enum"/> you would like to change.</param>
|
||||
/// <returns>A proper string for the <see cref="Enum"/>.</returns>
|
||||
/// <returns>A proper string for the provided <see cref="Enum"/>.</returns>
|
||||
public static string ToDisplayString(this Enum @enum)
|
||||
{
|
||||
var regex = new Regex(@"([^\^])([A-Z][a-z$])", default, Regex.InfiniteMatchTimeout);
|
||||
return regex.Replace(@enum.ToString(), m => $"{m.Groups[1].Value} {m.Groups[2].Value}");
|
||||
return DisplayRegex.Replace(@enum.ToString(), m => $"{m.Groups[1].Value} {m.Groups[2].Value}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a proper string for a(n) <typeparamref name="T"/> value (with spaces).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the enum value.</typeparam>
|
||||
/// <param name="enum">The <typeparamref name="T"/> enum value you would like to change.</param>
|
||||
/// <returns>A proper string for the provided <typeparamref name="T"/> value.</returns>
|
||||
public static string ToDisplayString<T>(this T @enum)
|
||||
where T : struct, Enum
|
||||
{
|
||||
return DisplayRegex.Replace(@enum.ToString(), m => $"{m.Groups[1].Value} {m.Groups[2].Value}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -526,17 +539,46 @@ public static class Extensions
|
||||
/// <returns>The distance between the types.</returns>
|
||||
public static int GetInheritanceDistance(Type from, Type to)
|
||||
{
|
||||
if (!from.IsAssignableFrom(to)) return int.MaxValue;
|
||||
if (from == null || to == null)
|
||||
throw new ArgumentNullException(from == null ? nameof(from) : nameof(to));
|
||||
|
||||
var type = from;
|
||||
var distance = 0;
|
||||
while (type != null && type != to)
|
||||
if (from == to)
|
||||
return 0;
|
||||
|
||||
if (!to.IsGenericTypeDefinition && !to.IsAssignableFrom(from))
|
||||
return int.MaxValue;
|
||||
|
||||
var queue = new Queue<(Type Type, int Distance)>();
|
||||
var visited = new HashSet<Type>();
|
||||
|
||||
queue.Enqueue((from, 0));
|
||||
visited.Add(from);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
type = type.BaseType;
|
||||
distance++;
|
||||
var (current, dist) = queue.Dequeue();
|
||||
|
||||
if (current == to || (current.IsGenericType && current.GetGenericTypeDefinition() == to))
|
||||
return dist;
|
||||
|
||||
if (current.BaseType != null && visited.Add(current.BaseType))
|
||||
queue.Enqueue((current.BaseType, dist + 1));
|
||||
|
||||
var allInterfaces = current.GetInterfaces();
|
||||
var baseInterfaces = current.BaseType?.GetInterfaces() ?? Type.EmptyTypes;
|
||||
|
||||
var directInterfaces = allInterfaces.Except(baseInterfaces).ToList();
|
||||
var inheritedInterfaces = directInterfaces.SelectMany(i => i.GetInterfaces());
|
||||
var immediateInterfaces = directInterfaces.Except(inheritedInterfaces);
|
||||
|
||||
foreach (var iFace in immediateInterfaces)
|
||||
{
|
||||
if (visited.Add(iFace))
|
||||
queue.Enqueue((iFace, dist + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return type == to ? distance : int.MaxValue;
|
||||
return to.IsAssignableFrom(from) ? int.MaxValue - 1 : int.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,7 +8,6 @@ using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Translation;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
@@ -103,40 +102,42 @@ internal static class GuideOptionPages
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.Count > 0)
|
||||
if (entries.Count <= 0)
|
||||
{
|
||||
var pageKey = item.Group.MatchInfoGuidePageKey?.Trim();
|
||||
var combinedKey = string.IsNullOrEmpty(pageKey) ? null : $"{item.Plugin.PluginId}\0{pageKey}";
|
||||
if (combinedKey != null && combinedPages.TryGetValue(combinedKey, out var combinedPage))
|
||||
continue;
|
||||
}
|
||||
|
||||
var pageKey = item.Group.MatchInfoGuidePageKey?.Trim();
|
||||
var combinedKey = string.IsNullOrEmpty(pageKey) ? null : $"{item.Plugin.PluginId}\0{pageKey}";
|
||||
if (combinedKey != null && combinedPages.TryGetValue(combinedKey, out var combinedPage))
|
||||
{
|
||||
combinedPage.Groups.Add(item.Group);
|
||||
combinedPage.Entries.AddRange(entries);
|
||||
combinedPage.ModSearchTerms.UnionWith(modSearchTerms);
|
||||
combinedPage.Order = Math.Min(combinedPage.Order, item.Group.MatchInfoGuidePageOrder);
|
||||
combinedPage.MenuOrder = Math.Min(
|
||||
combinedPage.MenuOrder,
|
||||
GetMenuOrder(item.Group.ParentMenu));
|
||||
combinedPage.GroupPriority = Math.Min(
|
||||
combinedPage.GroupPriority,
|
||||
item.Group.GroupPriority);
|
||||
}
|
||||
else
|
||||
{
|
||||
var page = new GuideOptionPage(
|
||||
item.Group,
|
||||
item.Group.MatchInfoGuidePageTitle,
|
||||
item.Group.MatchInfoGuidePageOrder,
|
||||
GetMenuOrder(item.Group.ParentMenu),
|
||||
item.Group.GroupPriority,
|
||||
Mathf.Clamp(item.Group.MatchInfoGuidePageColumns, 1, 6),
|
||||
item.ModAbbreviation,
|
||||
modSearchTerms,
|
||||
entries);
|
||||
pages.Add(page);
|
||||
if (combinedKey != null)
|
||||
{
|
||||
combinedPage.Groups.Add(item.Group);
|
||||
combinedPage.Entries.AddRange(entries);
|
||||
combinedPage.ModSearchTerms.UnionWith(modSearchTerms);
|
||||
combinedPage.Order = Math.Min(combinedPage.Order, item.Group.MatchInfoGuidePageOrder);
|
||||
combinedPage.MenuOrder = Math.Min(
|
||||
combinedPage.MenuOrder,
|
||||
GetMenuOrder(item.Group.ParentMenu));
|
||||
combinedPage.GroupPriority = Math.Min(
|
||||
combinedPage.GroupPriority,
|
||||
item.Group.GroupPriority);
|
||||
}
|
||||
else
|
||||
{
|
||||
var page = new GuideOptionPage(
|
||||
item.Group,
|
||||
item.Group.MatchInfoGuidePageTitle,
|
||||
item.Group.MatchInfoGuidePageOrder,
|
||||
GetMenuOrder(item.Group.ParentMenu),
|
||||
item.Group.GroupPriority,
|
||||
Mathf.Clamp(item.Group.MatchInfoGuidePageColumns, 1, 6),
|
||||
item.ModAbbreviation,
|
||||
modSearchTerms,
|
||||
entries);
|
||||
pages.Add(page);
|
||||
if (combinedKey != null)
|
||||
{
|
||||
combinedPages.Add(combinedKey, page);
|
||||
}
|
||||
combinedPages.Add(combinedKey, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,7 +270,7 @@ internal static class GuideOptionPages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Warning($"GroupVisible threw for {group.GetType().Name}: {e.Message}");
|
||||
Warning($"GroupVisible threw for {group.GetType().Name}: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,7 @@ internal static class GuideOptionPages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Warning($"Visible threw for option '{option.Title}': {e.Message}");
|
||||
Warning($"Visible threw for option '{option.Title}': {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -303,7 +304,7 @@ internal static class GuideOptionPages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Warning($"Could not format option '{option.Title}' for the guide: {e.Message}");
|
||||
Warning($"Could not format option '{option.Title}' for the guide: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,7 +936,7 @@ public static class Helpers
|
||||
{
|
||||
const float contentTop = 0.95f;
|
||||
const float horizontalOffset = -0.2f;
|
||||
const float headerContentGap = 0.2f;
|
||||
const float groupHeaderContentGap = 0.05f;
|
||||
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) + headerContentGap + 0.25f);
|
||||
rowPitch * (groupedSettings[i].Count() + 1) + groupHeaderContentGap + 0.25f);
|
||||
}
|
||||
|
||||
var bandOffset = 0f;
|
||||
@@ -1040,7 +1040,6 @@ public static class Helpers
|
||||
}
|
||||
}
|
||||
|
||||
var contentBottom = float.PositiveInfinity;
|
||||
var previousGroup = (AbstractOptionGroup?)null;
|
||||
var rowIndex = 0;
|
||||
var column = 0;
|
||||
@@ -1089,12 +1088,12 @@ public static class Helpers
|
||||
|
||||
if (headerSource)
|
||||
{
|
||||
const float headerScale = 0.46f;
|
||||
const float groupHeaderScale = 0.42f;
|
||||
var headerWidth = groupsAsColumns
|
||||
? columnWidth / headerScale
|
||||
: (columns * columnWidth + (columns - 1) * columnGap) / headerScale;
|
||||
? columnWidth / groupHeaderScale
|
||||
: (columns * columnWidth + (columns - 1) * columnGap) / groupHeaderScale;
|
||||
var header = Object.Instantiate(headerSource!, page.transform, false);
|
||||
header.transform.localScale = Vector3.one * headerScale;
|
||||
header.transform.localScale = Vector3.one * groupHeaderScale;
|
||||
if (groupsAsColumns)
|
||||
{
|
||||
var totalWidth = columns * columnWidth + (columns - 1) * columnGap;
|
||||
@@ -1155,12 +1154,6 @@ 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))
|
||||
@@ -1171,9 +1164,6 @@ public static class Helpers
|
||||
if (text.enabled)
|
||||
{
|
||||
text.ForceMeshUpdate();
|
||||
contentBottom = Mathf.Min(
|
||||
contentBottom,
|
||||
inner.InverseTransformPoint(text.bounds.min).y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1191,7 +1181,7 @@ public static class Helpers
|
||||
horizontalOffset;
|
||||
var centerY = groupsAsColumns && settings[i].Group is { } rowGroup
|
||||
? contentTop - groupTopOffsets[rowGroup] -
|
||||
(rowPitch * (groupRows[rowGroup] + 1)) - headerContentGap - (rowHeight / 2f)
|
||||
(rowPitch * (groupRows[rowGroup] + 1)) - groupHeaderContentGap - (rowHeight / 2f)
|
||||
: contentTop - (rowHeight / 2f) - (rowIndex * rowPitch) - groupSpacing;
|
||||
var row = Object.Instantiate(rowPrefab, page.transform);
|
||||
row.enabled = false;
|
||||
@@ -1238,27 +1228,6 @@ 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);
|
||||
@@ -1277,6 +1246,26 @@ 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
|
||||
@@ -1288,7 +1277,6 @@ public static class Helpers
|
||||
? contentOverflow + 0.05f
|
||||
: 0f;
|
||||
parent.SetYBoundsMax(Mathf.Clamp(scrollRange, 0f, 999f));
|
||||
page.SetActive(true);
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
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