mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
wip options api
This commit is contained in:
1 parent
2affea8c96
commit
e2e811254a
30 files changed
+544
-632
No files matched your search
@@ -3,7 +3,7 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example
|
||||
{
|
||||
[RegisterCustomRole(ExamplePlugin.Id)]
|
||||
[RegisterCustomRole]
|
||||
public class CustomRole : CrewmateRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Test Role";
|
||||
|
||||
@@ -9,11 +9,11 @@ namespace MiraAPI.Example
|
||||
public string GroupName => "General Group";
|
||||
public Color GroupColor => Color.red;
|
||||
|
||||
[ModdedToggleOption("Use Thing")] public bool useThing { get; set; } = true;
|
||||
[ModdedToggleOption("Use another thing")] public bool useAnotherThing { get; set; } = false;
|
||||
[ModdedToggleOption("Use Thing")] public bool useThing { get; set; } = false;
|
||||
[ModdedToggleOption("Use another thing")] public bool useAnotherThing { get; set; } = true;
|
||||
[ModdedNumberOption("Sussy level", min: 0, max: 10)] public float sussyLevel { get; set; } = 4f;
|
||||
[ModdedStringOption("Sus choices", ["hello", "hello 2", "hello 3"])] public int susChoices { get; set; } = 0;
|
||||
[ModdedEnumOption("Enum test", typeof(TestEnum))] public TestEnum enumTest { get; set; } = TestEnum.Hello;
|
||||
[ModdedStringOption("Sus choices", ["hello", "hello 2", "hello 3"])] public int susChoices { get; set; } = 2;
|
||||
[ModdedEnumOption("Enum test", typeof(TestEnum))] public TestEnum enumTest { get; set; } = TestEnum.Bye;
|
||||
}
|
||||
|
||||
public enum TestEnum
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using MiraAPI.PluginLoading;
|
||||
using Reactor;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
@@ -12,19 +12,11 @@ namespace MiraAPI.Example;
|
||||
[BepInProcess("Among Us.exe")]
|
||||
[BepInDependency(ReactorPlugin.Id)]
|
||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
||||
public partial class ExamplePlugin : BasePlugin, IMiraConfig
|
||||
public partial class ExamplePlugin : BasePlugin, IMiraPlugin
|
||||
{
|
||||
public Harmony Harmony { get; } = new(Id);
|
||||
public static ExamplePlugin Instance { get; private set; }
|
||||
public ModdedOptionTabSettings TabSettings => new ModdedOptionTabSettings()
|
||||
{
|
||||
Title = "MiraAPI Example Mod",
|
||||
TabIcon = MiraAssets.Empty
|
||||
};
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
Instance = this;
|
||||
Harmony.PatchAll();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace MiraAPI.Example
|
||||
{
|
||||
public class SomeRandomNonGroupClass
|
||||
{
|
||||
[ModdedStringOption("Yeah, idk", ["Idk 1", "idk 2", "idk 3", "idk 4"])] public static int yeaIdk { get; set; } = 2;
|
||||
[ModdedStringOption("Yeah, idk", ["Idk 1", "idk 2", "idk 3", "idk 4"])] public static int yeaIdk { get; set; } = 3;
|
||||
[ModdedNumberOption("Aw man", min: 45, max: 95)] public float sussyLevel { get; set; } = 63;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes
|
||||
{
|
||||
@@ -24,7 +23,6 @@ namespace MiraAPI.GameOptions.Attributes
|
||||
|
||||
public override IModdedOption CreateOption(object value, PropertyInfo property)
|
||||
{
|
||||
Debug.LogError(value.ToString());
|
||||
var toggleOpt = new ModdedNumberOption(Title, (float)value, Min, Max, Increment, SuffixType, ZeroInfinity, RoleType);
|
||||
return toggleOpt;
|
||||
}
|
||||
|
||||
@@ -15,23 +15,6 @@ namespace MiraAPI.GameOptions.Attributes
|
||||
RoleType = roleType;
|
||||
}
|
||||
|
||||
public static void Register(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
foreach (PropertyInfo property in type.GetProperties())
|
||||
{
|
||||
foreach (var attribute in property.GetCustomAttributes())
|
||||
{
|
||||
if (attribute.GetType().BaseType == typeof(ModdedOptionAttribute))
|
||||
{
|
||||
ModdedOptionsManager.RegisterOption(assembly, type, (ModdedOptionAttribute)attribute, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void SetValue(object val);
|
||||
public abstract object GetValue();
|
||||
public abstract IModdedOption CreateOption(object value, PropertyInfo property);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using MiraAPI.PluginLoading;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions
|
||||
@@ -11,9 +12,8 @@ namespace MiraAPI.GameOptions
|
||||
public StringNames StringName { get; }
|
||||
public Func<bool> Visible { get; set; }
|
||||
public ModdedOptionGroup Group { get; set; }
|
||||
public IMiraConfig ParentMod { get; set; }
|
||||
public IMiraPlugin ParentMod { get; set; }
|
||||
public void ValueChanged(OptionBehaviour optionBehaviour);
|
||||
public string GetHudStringText();
|
||||
public OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container);
|
||||
public OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using MiraAPI.PluginLoading;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions
|
||||
{
|
||||
public class ModdedOptionGroup
|
||||
{
|
||||
public IMiraConfig ParentMod;
|
||||
public IMiraPlugin ParentMod;
|
||||
public GameObject Header;
|
||||
public string GroupName;
|
||||
public Func<bool> GroupVisible;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions
|
||||
{
|
||||
@@ -15,51 +13,11 @@ namespace MiraAPI.GameOptions
|
||||
public static List<IModdedOption> Options = [];
|
||||
public static List<ModdedOptionGroup> Groups = [];
|
||||
private static Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = new();
|
||||
private static Dictionary<Type, ModdedOptionGroup> OriginalTypes = new();
|
||||
public static Dictionary<Assembly, IMiraConfig> RegisteredMods = new();
|
||||
public static Dictionary<Type, ModdedOptionGroup> OriginalTypes = new();
|
||||
|
||||
public static void Initialize()
|
||||
public static IModdedOption RegisterOption(Type type, ModdedOptionAttribute attribute, PropertyInfo property)
|
||||
{
|
||||
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, plugin) =>
|
||||
{
|
||||
if (plugin.GetType().GetInterfaces().Contains(typeof(IMiraConfig)))
|
||||
{
|
||||
IMiraConfig config = (IMiraConfig)Activator.CreateInstance(plugin.GetType());
|
||||
RegisteredMods.Add(assembly, config);
|
||||
}
|
||||
|
||||
RegisterOptionGroups(assembly);
|
||||
|
||||
ModdedOptionAttribute.Register(assembly);
|
||||
};
|
||||
}
|
||||
|
||||
private static void RegisterOptionGroups(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (typeof(IModdedOptionGroup).IsAssignableFrom(type))
|
||||
{
|
||||
IModdedOptionGroup group = (IModdedOptionGroup)Activator.CreateInstance(type);
|
||||
ModdedOptionGroup newGroup = new ModdedOptionGroup()
|
||||
{
|
||||
AdvancedRole = group.AdvancedRole,
|
||||
GroupColor = group.GroupColor,
|
||||
GroupName = group.GroupName,
|
||||
GroupVisible = group.GroupVisible
|
||||
};
|
||||
|
||||
Groups.Add(newGroup);
|
||||
OriginalTypes.Add(type, newGroup);
|
||||
|
||||
newGroup.ParentMod = RegisteredMods[assembly];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterOption(Assembly assembly, Type type, ModdedOptionAttribute attribute, PropertyInfo property)
|
||||
{
|
||||
if (OptionAttributes.ContainsKey(property)) return;
|
||||
if (OptionAttributes.ContainsKey(property)) return null;
|
||||
object newObj = Activator.CreateInstance(type);
|
||||
IModdedOption result = attribute.CreateOption(property.GetValue(newObj), property);
|
||||
|
||||
@@ -74,17 +32,18 @@ namespace MiraAPI.GameOptions
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Harmony.Patch(getterOriginal, prefix: new HarmonyMethod(getterPatch));
|
||||
|
||||
attribute.HolderOption = result;
|
||||
result.ParentMod = RegisteredMods[assembly];
|
||||
|
||||
Options.Add(result);
|
||||
OptionAttributes.Add(property, attribute);
|
||||
|
||||
if (OriginalTypes.ContainsKey(type))
|
||||
{
|
||||
Debug.LogError($"grouping {attribute.Title} with {OriginalTypes[type].GroupName}");
|
||||
Logger<MiraAPIPlugin>.Error($"Grouping {attribute.Title} with {OriginalTypes[type].GroupName}");
|
||||
result.Group = OriginalTypes[type];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.GameOptions.OptionTypes
|
||||
{
|
||||
@@ -14,19 +15,30 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
Values = Enum.GetNames(enumType);
|
||||
}
|
||||
|
||||
public override OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
{
|
||||
var stringOption = (StringOption)UnityEngine.Object.Instantiate(optionBehaviour, container);
|
||||
var stringOption = Object.Instantiate(stringOpt, container);
|
||||
var vals = Values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
var data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||
|
||||
stringOption.name = Title;
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.String;
|
||||
data.Values = vals;
|
||||
data.Index = Value;
|
||||
|
||||
stringOption.data = data;
|
||||
stringOption.Title = StringName;
|
||||
stringOption.Value = Value;
|
||||
stringOption.Values = Values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
stringOption.TitleText.text = Title;
|
||||
stringOption.Values = vals;
|
||||
|
||||
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||
stringOption.Initialize();
|
||||
|
||||
OptionBehaviour = stringOption;
|
||||
stringOption.Initialize();
|
||||
stringOption.Value = Value;
|
||||
stringOption.ValueText.text = Values[Value];
|
||||
|
||||
stringOption.SetUpFromData(stringOption.data, 20);
|
||||
return stringOption;
|
||||
}
|
||||
|
||||
@@ -46,6 +58,8 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
|
||||
var opt = OptionBehaviour as StringOption;
|
||||
opt.Value = newValue;
|
||||
|
||||
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, OptionBehaviour.GetValueString(Value), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,23 +21,26 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
Value = Mathf.Clamp(defaultValue, min, max);
|
||||
}
|
||||
|
||||
public override OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
{
|
||||
var numberOption = (NumberOption)Object.Instantiate(optionBehaviour, container);
|
||||
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
||||
var data = ScriptableObject.CreateInstance<FloatGameSetting>();
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.Float;
|
||||
data.Increment = Increment;
|
||||
data.SuffixType = SuffixType;
|
||||
data.FormatString = "0";
|
||||
data.ValidRange = new FloatRange(Min, Max);
|
||||
data.ZeroIsInfinity = ZeroInfinity;
|
||||
data.Value = Value;
|
||||
|
||||
numberOption.name = Title;
|
||||
numberOption.Title = StringName;
|
||||
numberOption.Value = Value;
|
||||
numberOption.Increment = Increment;
|
||||
numberOption.SuffixType = SuffixType;
|
||||
numberOption.FormatString = "0";
|
||||
numberOption.ValidRange = new FloatRange(Min, Max);
|
||||
numberOption.ZeroIsInfinity = ZeroInfinity;
|
||||
numberOption.data = data;
|
||||
numberOption.SetUpFromData(numberOption.data, 20);
|
||||
numberOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||
numberOption.Initialize();
|
||||
|
||||
OptionBehaviour = numberOption;
|
||||
|
||||
numberOption.Value = Value;
|
||||
|
||||
return numberOption;
|
||||
}
|
||||
|
||||
@@ -59,6 +62,8 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
|
||||
var opt = OptionBehaviour as NumberOption;
|
||||
opt.Value = newValue;
|
||||
|
||||
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, OptionBehaviour.GetValueString(Value), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Localization.Utilities;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
@@ -16,7 +17,7 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
public Type AdvancedRole { get; }
|
||||
public OptionBehaviour OptionBehaviour { get; set; }
|
||||
public ModdedOptionGroup Group { get; set; } = null;
|
||||
public IMiraConfig ParentMod { get; set; } = null;
|
||||
public IMiraPlugin ParentMod { get; set; } = null;
|
||||
|
||||
public ModdedOption(string title, T defaultValue, Type roleType)
|
||||
{
|
||||
@@ -53,7 +54,7 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
|
||||
public abstract T GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour);
|
||||
|
||||
public abstract OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container);
|
||||
public abstract OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
|
||||
|
||||
public abstract string GetHudStringText();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Reactor.Localization.Utilities;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.GameOptions.OptionTypes
|
||||
{
|
||||
@@ -12,19 +13,26 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public override OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
{
|
||||
var stringOption = (StringOption)Object.Instantiate(optionBehaviour, container);
|
||||
var stringOption = Object.Instantiate(stringOpt, container);
|
||||
var vals = Values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
var data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||
|
||||
stringOption.name = Title;
|
||||
stringOption.Title = StringName;
|
||||
stringOption.Value = Value;
|
||||
stringOption.Values = Values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.String;
|
||||
data.Values = vals;
|
||||
data.Index = Value;
|
||||
|
||||
stringOption.data = data;
|
||||
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||
stringOption.Initialize();
|
||||
|
||||
OptionBehaviour = stringOption;
|
||||
|
||||
stringOption.SetUpFromData(stringOption.data, 20);
|
||||
|
||||
stringOption.Value = Value;
|
||||
|
||||
return stringOption;
|
||||
}
|
||||
|
||||
@@ -44,6 +52,8 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
|
||||
var opt = OptionBehaviour as StringOption;
|
||||
opt.Value = newValue;
|
||||
|
||||
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, OptionBehaviour.GetValueString(Value), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,16 +8,23 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
{
|
||||
}
|
||||
|
||||
public override OptionBehaviour CreateOption(OptionBehaviour optionBehaviour, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
{
|
||||
var toggleOption = (ToggleOption)Object.Instantiate(optionBehaviour, container);
|
||||
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
||||
var data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.Checkbox;
|
||||
|
||||
toggleOption.name = Title;
|
||||
toggleOption.Title = StringName;
|
||||
toggleOption.data = data;
|
||||
|
||||
toggleOption.TitleText.text = Title;
|
||||
toggleOption.CheckMark.enabled = Value;
|
||||
toggleOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||
toggleOption.Initialize();
|
||||
|
||||
OptionBehaviour = toggleOption;
|
||||
|
||||
toggleOption.SetUpFromData(toggleOption.data, 20);
|
||||
|
||||
return toggleOption;
|
||||
}
|
||||
|
||||
@@ -37,6 +44,8 @@ namespace MiraAPI.GameOptions.OptionTypes
|
||||
|
||||
var toggleOpt = OptionBehaviour as ToggleOption;
|
||||
toggleOpt.CheckMark.enabled = newValue;
|
||||
|
||||
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, Value ? "On" : "Off", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.GameOptions.UI;
|
||||
|
||||
/*
|
||||
public static class ModdedOptionsTab
|
||||
{
|
||||
public static readonly List<GameObject> CustomTabs = [];
|
||||
public static readonly List<GameObject> CustomScreens = [];
|
||||
|
||||
public static GameObject InitializeForMod(IMiraConfig config, GameSettingMenu __instance)
|
||||
{
|
||||
var gameBtn = __instance.transform.FindChild("Header/Tabs/GameTab").gameObject;
|
||||
var roleBtn = __instance.transform.FindChild("Header/Tabs/RoleTab").gameObject;
|
||||
var screen = CreateNewMenu(config, __instance);
|
||||
var tab = CreateCustomTab(config, __instance, screen, gameBtn, roleBtn);
|
||||
|
||||
CustomScreens.Add(screen);
|
||||
CustomTabs.Add(tab);
|
||||
|
||||
SpriteRenderer rend = tab.transform.FindChild("Btn/Tab Background").GetComponent<SpriteRenderer>();
|
||||
rend.enabled = false;
|
||||
|
||||
UpdateListeners(__instance, gameBtn.GetComponentInChildren<PassiveButton>(), roleBtn.GetComponentInChildren<PassiveButton>(), rend);
|
||||
|
||||
var container = screen.transform.FindChild("GameGroup/SliderInner");
|
||||
container.DestroyChildren();
|
||||
//CreateNewResetButton(__instance, container);
|
||||
|
||||
return container.gameObject;
|
||||
}
|
||||
|
||||
private static void UpdateListeners(GameSettingMenu __instance, PassiveButton gameB, PassiveButton roleB, SpriteRenderer rend)
|
||||
{
|
||||
gameB.OnClick.RemoveAllListeners();
|
||||
gameB.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
__instance.RegularGameSettings.SetActive(true);
|
||||
__instance.RolesSettings.gameObject.SetActive(false);
|
||||
|
||||
foreach (var screen in CustomScreens) screen.gameObject.SetActive(false);
|
||||
|
||||
rend.enabled = false;
|
||||
|
||||
__instance.GameSettingsHightlight.enabled = true;
|
||||
__instance.RolesSettingsHightlight.enabled = false;
|
||||
}));
|
||||
|
||||
roleB.OnClick.RemoveAllListeners();
|
||||
roleB.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
__instance.RegularGameSettings.SetActive(false);
|
||||
__instance.RolesSettings.gameObject.SetActive(true);
|
||||
|
||||
foreach (var screen in CustomScreens) screen.gameObject.SetActive(false);
|
||||
|
||||
rend.enabled = false;
|
||||
|
||||
__instance.GameSettingsHightlight.enabled = false;
|
||||
__instance.RolesSettingsHightlight.enabled = true;
|
||||
}));
|
||||
}
|
||||
|
||||
public static GameObject CreateHeader(ToggleOption toggleOpt, Transform container, string title, Color color)
|
||||
{
|
||||
var header = Object.Instantiate(toggleOpt, container);
|
||||
|
||||
header.Title = StringNames.None;
|
||||
header.TitleText.text = title;
|
||||
header.TitleText.color = color;
|
||||
header.name = "Header";
|
||||
|
||||
var checkBox = header.transform.FindChild("CheckBox")?.gameObject;
|
||||
if (checkBox)
|
||||
{
|
||||
checkBox.Destroy();
|
||||
}
|
||||
|
||||
var background = header.transform.FindChild("Background")?.gameObject;
|
||||
if (background)
|
||||
{
|
||||
background.Destroy();
|
||||
}
|
||||
|
||||
header.GetComponent<OptionBehaviour>().Destroy();
|
||||
return header.gameObject;
|
||||
}
|
||||
|
||||
public static GameObject CreateCustomTab(IMiraConfig options, GameSettingMenu __instance, GameObject newSettings,
|
||||
GameObject gameTab, GameObject roleTab)
|
||||
{
|
||||
var newTab = Object.Instantiate(gameTab, gameTab.transform.parent);
|
||||
newTab.name = "Tab";
|
||||
newTab.transform.position = roleTab.transform.position;
|
||||
newTab.transform.position += new Vector3(CustomTabs.Count + 1, 0, 0);
|
||||
__instance.Tabs.transform.position -= new Vector3(0.5f, 0, 0);
|
||||
|
||||
var inside = newTab.transform.FindChild("ColorButton");
|
||||
inside.name = "Btn";
|
||||
|
||||
var btn = inside.GetComponentInChildren<PassiveButton>();
|
||||
|
||||
btn.OnClick.RemoveAllListeners();
|
||||
|
||||
btn.OnClick.AddListener((Action)TabAction);
|
||||
|
||||
var spriteRend = inside.GetComponentInChildren<SpriteRenderer>();
|
||||
// if (options.TabSettings.TabIcon != null) spriteRend.sprite = options.TabSettings.TabIcon.LoadAsset();
|
||||
|
||||
return newTab;
|
||||
|
||||
void TabAction()
|
||||
{
|
||||
__instance.RegularGameSettings.SetActive(false);
|
||||
__instance.RolesSettings.gameObject.SetActive(false);
|
||||
|
||||
foreach (var screen in CustomScreens)
|
||||
{
|
||||
screen.gameObject.SetActive(false);
|
||||
}
|
||||
newSettings.gameObject.SetActive(true);
|
||||
|
||||
SpriteRenderer rend = newTab.transform.FindChild("Btn/Tab Background").GetComponent<SpriteRenderer>();
|
||||
rend.enabled = true;
|
||||
|
||||
gameTab.transform.FindChild("ColorButton/Tab Background").gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
roleTab.transform.FindChild("Hat Button/Tab Background").gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
|
||||
foreach (var tab in CustomTabs)
|
||||
{
|
||||
tab.transform.FindChild("Btn/Tab Background").gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject CreateNewMenu(IMiraConfig config, GameSettingMenu __instance)
|
||||
{
|
||||
var gameSettings = __instance.RegularGameSettings;
|
||||
var newSettings = Object.Instantiate(gameSettings, gameSettings.transform.parent);
|
||||
newSettings.name = "Settings";
|
||||
newSettings.SetActive(false);
|
||||
|
||||
var launchpadGroup = newSettings.transform.FindChild("GameGroup").gameObject;
|
||||
var text = launchpadGroup.transform.FindChild("Text").gameObject.GetComponent<TextMeshPro>();
|
||||
text.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
text.text = $"{config.TabSettings.Title} Options";
|
||||
|
||||
return newSettings;
|
||||
}
|
||||
}*/
|
||||
@@ -1,17 +0,0 @@
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI
|
||||
{
|
||||
public interface IMiraConfig
|
||||
{
|
||||
public ModdedOptionTabSettings TabSettings { get; }
|
||||
}
|
||||
|
||||
public struct ModdedOptionTabSettings(string title, LoadableAsset<Sprite> tabIcon)
|
||||
{
|
||||
public string Title { get; set; } = title;
|
||||
public LoadableAsset<Sprite> TabIcon { get; set; } = tabIcon;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.PluginLoading;
|
||||
using Reactor;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
using System.Reflection;
|
||||
using Reactor.Patches;
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI;
|
||||
|
||||
@@ -20,16 +20,31 @@ public partial class MiraAPIPlugin : BasePlugin
|
||||
{
|
||||
public Harmony Harmony { get; } = new(Id);
|
||||
public static MiraAPIPlugin Instance { get; private set; }
|
||||
public static MiraPluginManager PluginManager { get; private set; }
|
||||
public static Color MiraColor = new Color32(238, 154, 112, 255);
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
Instance = this;
|
||||
Harmony.PatchAll();
|
||||
|
||||
RegisterCustomRoleAttribute.Initialize();
|
||||
ModdedOptionsManager.Initialize();
|
||||
PluginManager = new MiraPluginManager();
|
||||
PluginManager.Initialize();
|
||||
|
||||
RegisterGameModeAttribute.Register(Assembly.GetCallingAssembly());
|
||||
RegisterButtonAttribute.Register(Assembly.GetExecutingAssembly());
|
||||
ReactorVersionShower.TextUpdated += (text) =>
|
||||
{
|
||||
text.text = new StringBuilder($"{MiraColor.ToTextColor()}Mira API</color> ")
|
||||
.Append(GetShortHashVersion(Version))
|
||||
.Append("\n")
|
||||
.Append(text.text)
|
||||
.ToString();
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetShortHashVersion(string version)
|
||||
{
|
||||
var index = version.IndexOf("+", StringComparison.Ordinal);
|
||||
|
||||
return index < 0 ? version : version[..(index + 3)];
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using InnerNet;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Patches.Options;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
@@ -30,7 +28,7 @@ namespace MiraAPI.Patches
|
||||
}
|
||||
|
||||
//CustomGameModeManager.ActiveMode.HudUpdate(__instance);
|
||||
if (local.Data.Role is null) return;
|
||||
if (local is null || local.Data is null || local.Data.Role is null) return;
|
||||
|
||||
if (local.Data.Role is ICustomRole customRole)
|
||||
{
|
||||
|
||||
@@ -1,109 +1,122 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Localization.Utilities;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
/*
|
||||
|
||||
[HarmonyPatch(typeof(GameOptionsMenu))]
|
||||
public static class GameOptionsMenuPatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Change the OnValueChanged action for all custom game options
|
||||
/// </summary>
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(GameOptionsMenu.Start))]
|
||||
public static void StartPostfix(GameOptionsMenu __instance)
|
||||
[HarmonyPrefix, HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
|
||||
public static bool SettingsPatch(GameOptionsMenu __instance)
|
||||
{
|
||||
foreach (var customOption in ModdedOptionsManager.Options)
|
||||
if (GameSettingMenuPatches.currentSelectedMod == 0) return true;
|
||||
|
||||
__instance.MapPicker.gameObject.SetActive(false);
|
||||
|
||||
float num = 2.1f;
|
||||
foreach (IModdedOptionGroup group in GameSettingMenuPatches.selectedMod.OptionGroups)
|
||||
{
|
||||
if (customOption.AdvancedRole is not null || !customOption.OptionBehaviour)
|
||||
CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||
num -= 0.63f;
|
||||
|
||||
foreach (var opt in ModdedOptionsManager.Options.Where(opt => opt.Group is not null && opt.Group.GroupName == group.GroupName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
OptionBehaviour newOpt = opt.CreateOption(__instance.checkboxOrigin, __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.settingsContainer);
|
||||
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
newOpt.SetClickMask(__instance.ButtonClickMask);
|
||||
|
||||
customOption.OptionBehaviour.OnValueChanged = (Action<OptionBehaviour>)customOption.ValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set the position and offset of all custom game options
|
||||
/// </summary>
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(GameOptionsMenu.Update))]
|
||||
public static void UpdatePostfix(GameOptionsMenu __instance)
|
||||
{
|
||||
if (!GameSettingMenu.Instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameSettingMenu.Instance.GameSettingsTab.gameObject.active || GameSettingMenu.Instance.RoleSettingsTab.gameObject.active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var startOffset = 2.5f;
|
||||
__instance.GetComponentInParent<Scroller>().ContentYBounds.max = startOffset + __instance.Children.Count * 0.5f;
|
||||
|
||||
foreach (var option in ModdedOptionsManager.Options.Where(option => option.Group == null))
|
||||
{
|
||||
if (!option.OptionBehaviour) continue;
|
||||
|
||||
option.OptionBehaviour.enabled = option.Visible();
|
||||
option.OptionBehaviour.gameObject.SetActive(option.Visible());
|
||||
|
||||
if (option.Visible())
|
||||
{
|
||||
startOffset -= 0.55f;
|
||||
}
|
||||
|
||||
var transform = option.OptionBehaviour.transform;
|
||||
var optionPosition = transform.localPosition;
|
||||
transform.localPosition = new Vector3(optionPosition.x, startOffset, optionPosition.z);
|
||||
}
|
||||
|
||||
foreach (var group in ModdedOptionsManager.Groups.Where(group => group.AdvancedRole == null))
|
||||
{
|
||||
if (group.Header == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
group.Header.SetActive(group.GroupVisible());
|
||||
|
||||
if (group.GroupVisible())
|
||||
{
|
||||
startOffset -= 0.5f;
|
||||
}
|
||||
|
||||
var position = group.Header.transform.localPosition;
|
||||
group.Header.transform.localPosition = new Vector3(position.x, startOffset, position.z);
|
||||
|
||||
foreach (var option in ModdedOptionsManager.Options.Where(x => x.Group == group))
|
||||
{
|
||||
if (!option.OptionBehaviour)
|
||||
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
for (int i = 0; i < componentsInChildren.Length; i++)
|
||||
{
|
||||
continue;
|
||||
componentsInChildren[i].material.SetInt(PlayerMaterial.MaskLayer, 20);
|
||||
}
|
||||
foreach (TextMeshPro textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
textMeshPro.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
textMeshPro.fontMaterial.SetFloat("_Stencil", 20);
|
||||
}
|
||||
|
||||
var enabled = group.GroupVisible() && option.Visible();
|
||||
__instance.Children.Add(newOpt);
|
||||
|
||||
option.OptionBehaviour.enabled = enabled;
|
||||
option.OptionBehaviour.gameObject.SetActive(enabled);
|
||||
|
||||
if (group.GroupVisible() && option.Visible())
|
||||
{
|
||||
startOffset -= 0.5f;
|
||||
}
|
||||
|
||||
var transform = option.OptionBehaviour.transform;
|
||||
var optionPosition = transform.localPosition;
|
||||
transform.localPosition = new Vector3(optionPosition.x, startOffset, optionPosition.z);
|
||||
num -= 0.45f;
|
||||
newOpt.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
CategoryHeaderMasked ungroupedHeader = UnityEngine.Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
ungroupedHeader.SetHeader(CustomStringName.CreateAndRegister("Ungrouped Options"), 20);
|
||||
ungroupedHeader.transform.localScale = Vector3.one * 0.63f;
|
||||
ungroupedHeader.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||
|
||||
num -= 0.63f;
|
||||
|
||||
foreach (var opt in ModdedOptionsManager.Options.Where(opt => opt.Group is null))
|
||||
{
|
||||
OptionBehaviour newOpt = opt.CreateOption(__instance.checkboxOrigin, __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.settingsContainer);
|
||||
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
newOpt.SetClickMask(__instance.ButtonClickMask);
|
||||
newOpt.SetUpFromData(newOpt.data, 20);
|
||||
|
||||
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
for (int i = 0; i < componentsInChildren.Length; i++)
|
||||
{
|
||||
componentsInChildren[i].material.SetInt(PlayerMaterial.MaskLayer, 20);
|
||||
}
|
||||
foreach (TextMeshPro textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
textMeshPro.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
textMeshPro.fontMaterial.SetFloat("_Stencil", 20);
|
||||
}
|
||||
|
||||
__instance.Children.Add(newOpt);
|
||||
|
||||
num -= 0.45f;
|
||||
|
||||
newOpt.Initialize();
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
||||
public static bool InitPatch(GameOptionsMenu __instance)
|
||||
{
|
||||
if (__instance.Children == null || __instance.Children.Count == 0)
|
||||
{
|
||||
__instance.MapPicker.gameObject.SetActive(true);
|
||||
__instance.MapPicker.Initialize(20);
|
||||
BaseGameSetting mapNameSetting = GameManager.Instance.GameSettingsList.MapNameSetting;
|
||||
__instance.MapPicker.SetUpFromData(mapNameSetting, 20);
|
||||
__instance.Children = new List<OptionBehaviour>();
|
||||
__instance.Children.Add(__instance.MapPicker);
|
||||
__instance.CreateSettings();
|
||||
__instance.cachedData = GameOptionsManager.Instance.CurrentGameOptions;
|
||||
for (int i = 0; i < __instance.Children.Count; i++)
|
||||
{
|
||||
OptionBehaviour optionBehaviour = __instance.Children[i];
|
||||
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
optionBehaviour.SetAsPlayer();
|
||||
}
|
||||
|
||||
if (optionBehaviour.IsCustom()) continue;
|
||||
|
||||
optionBehaviour.OnValueChanged = new System.Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -10,8 +13,9 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(GameSettingMenu))]
|
||||
public static class GameSettingMenuPatches
|
||||
{
|
||||
|
||||
public static int currentSelectedMod = 0;
|
||||
public static MiraPluginInfo selectedMod = null;
|
||||
public static TextMeshPro text;
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Start))]
|
||||
@@ -26,11 +30,11 @@ public static class GameSettingMenuPatches
|
||||
tmpText.name = "SelectedMod";
|
||||
tmpText.transform.localPosition = new Vector3(-3.3382f, 1.5399f, -2);
|
||||
|
||||
TextMeshPro tmp = tmpText.GetComponent<TextMeshPro>();
|
||||
tmp.text = "<b>Default</b>";
|
||||
tmp.fontSizeMax = 3.2f;
|
||||
text = tmpText.GetComponent<TextMeshPro>();
|
||||
text.fontSizeMax = 3.2f;
|
||||
UpdateText(__instance.GameSettingsTab);
|
||||
|
||||
tmp.alignment = TextAlignmentOptions.Center;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
|
||||
GameObject nextButton = GameObject.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject;
|
||||
nextButton.transform.localPosition = new Vector3(-2.2663f, 1.5272f, -25f);
|
||||
@@ -48,7 +52,11 @@ public static class GameSettingMenuPatches
|
||||
passiveButton.inactiveSprites = nextButton.transform.FindChild("Inactive").gameObject;
|
||||
passiveButton.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
currentSelectedMod += 1;
|
||||
if (currentSelectedMod != MiraPluginManager.Instance.RegisteredPlugins.Count)
|
||||
{
|
||||
currentSelectedMod += 1;
|
||||
}
|
||||
UpdateText(__instance.GameSettingsTab);
|
||||
}));
|
||||
|
||||
GameObject backButton = GameObject.Instantiate(nextButton, __instance.BackButton.transform.parent).gameObject;
|
||||
@@ -58,7 +66,53 @@ public static class GameSettingMenuPatches
|
||||
backButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX = backButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
|
||||
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
currentSelectedMod -= 1;
|
||||
if (currentSelectedMod != 0)
|
||||
{
|
||||
currentSelectedMod -= 1;
|
||||
}
|
||||
UpdateText(__instance.GameSettingsTab);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void UpdateText(GameOptionsMenu settings)
|
||||
{
|
||||
if (currentSelectedMod == 0)
|
||||
{
|
||||
text.text = "Default";
|
||||
text.fontSizeMax = 3.2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
text.fontSizeMax = 2f;
|
||||
selectedMod = MiraPluginManager.Instance.RegisteredPlugins.ElementAt(currentSelectedMod - 1).Value;
|
||||
if (selectedMod == null)
|
||||
{
|
||||
currentSelectedMod = 0;
|
||||
UpdateText(settings);
|
||||
}
|
||||
|
||||
string name = selectedMod.PluginInfo.Metadata.Name;
|
||||
text.text = name.Substring(0, Math.Min(name.Length, 15));
|
||||
}
|
||||
|
||||
if (settings.Children is null || settings is null) return;
|
||||
|
||||
foreach (var child in settings.Children)
|
||||
{
|
||||
if (child.TryCast<GameOptionsMapPicker>()) continue;
|
||||
if (child.gameObject is null) continue;
|
||||
|
||||
child.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
foreach (var header in settings.settingsContainer.GetComponentsInChildren<CategoryHeaderMasked>())
|
||||
{
|
||||
header.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
settings.Children.Clear();
|
||||
settings.Children = null;
|
||||
|
||||
settings.Initialize();
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Roles;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
[HarmonyPatch(typeof(IGameOptionsExtensions), "ToHudString")]
|
||||
public static class ToHudStringPatch
|
||||
{
|
||||
public static int CurrentPage = 0;
|
||||
/// <summary>
|
||||
/// Generic method to add options
|
||||
/// </summary>
|
||||
public static void AddOptions(StringBuilder sb,
|
||||
List<IModdedOption> options)
|
||||
{
|
||||
foreach (var opt in options)
|
||||
{
|
||||
sb.AppendLine(opt.GetHudStringText());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Prefix()
|
||||
{
|
||||
if (GameManager.Instance is null || GameManager.Instance.IsHideAndSeek())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var role in CustomRoleManager.CustomRoles.Values)
|
||||
{
|
||||
var customRole = role as ICustomRole;
|
||||
if (customRole.IsGhostRole)
|
||||
{
|
||||
role.Role = RoleTypes.CrewmateGhost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the HudOptions on the left of the screen if player is using Launchpad options
|
||||
/// </summary>
|
||||
public static void Postfix(IGameOptions __instance, ref string __result)
|
||||
{
|
||||
if (GameManager.Instance is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pair in CustomRoleManager.CustomRoles)
|
||||
{
|
||||
var customRole = pair.Value as ICustomRole;
|
||||
if (customRole.IsGhostRole)
|
||||
{
|
||||
pair.Value.Role = (RoleTypes)pair.Key;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentPage != 0)
|
||||
{
|
||||
IMiraConfig currentPlugin = ModdedOptionsManager.RegisteredMods.Values.ToArray()[CurrentPage - 1];
|
||||
if (currentPlugin == null)
|
||||
{
|
||||
CurrentPage = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder($"<size=180%><b>{currentPlugin.TabSettings.Title} Options:</b></size>\n<size=130%>");
|
||||
var groupsWithRoles = ModdedOptionsManager.Groups.Where(group => group.AdvancedRole != null && group.ParentMod == currentPlugin);
|
||||
var groupsWithoutRoles = ModdedOptionsManager.Groups.Where(group => group.AdvancedRole == null && group.ParentMod == currentPlugin);
|
||||
|
||||
AddOptions(sb,
|
||||
ModdedOptionsManager.Options.Where(option => option.Group == null && option.ParentMod == currentPlugin && option.Visible()).ToList()
|
||||
);
|
||||
|
||||
foreach (var group in groupsWithoutRoles)
|
||||
{
|
||||
if (!group.GroupVisible())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.AppendLine($"\n<size=160%><b>{group.GroupColor.ToTextColor()}{group.GroupName}</color></b></size>");
|
||||
AddOptions(sb, ModdedOptionsManager.Options.Where(x => x.Group == group).ToList());
|
||||
}
|
||||
|
||||
var customOptionGroups = groupsWithRoles as ModdedOptionGroup[] ?? groupsWithRoles.ToArray();
|
||||
if (customOptionGroups.Any())
|
||||
{
|
||||
sb.AppendLine("\n<size=160%><b>Roles</b></size>");
|
||||
|
||||
foreach (var group in customOptionGroups)
|
||||
{
|
||||
if (!group.GroupVisible())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.AppendLine($"<size=140%><b>{group.GroupColor.ToTextColor()}{group.GroupName}</color></b></size><size=120%>");
|
||||
AddOptions(sb, ModdedOptionsManager.Options.Where(x => x.Group == group).ToList());
|
||||
sb.Append("</size>\n");
|
||||
}
|
||||
}
|
||||
|
||||
__result = sb.ToString();
|
||||
}
|
||||
|
||||
if (CurrentPage == 0)
|
||||
{
|
||||
__result = "<size=160%><b>Normal Options:</b></size>\n<size=130%>" + __result;
|
||||
}
|
||||
__result += $"\nUse <b>TAB</b> to switch pages (Page {CurrentPage}/{ModdedOptionsManager.RegisteredMods.Count})</size>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Options
|
||||
{
|
||||
[HarmonyPatch]
|
||||
public static class OptionsPatches
|
||||
{
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(ToggleOption), nameof(ToggleOption.Initialize))]
|
||||
public static bool ToggleInit(ToggleOption __instance)
|
||||
{
|
||||
if (!__instance.IsCustom()) return true;
|
||||
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(ToggleOption), nameof(ToggleOption.UpdateValue))]
|
||||
public static bool ToggleUpdate(ToggleOption __instance)
|
||||
{
|
||||
return !__instance.IsCustom();
|
||||
}
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(NumberOption), nameof(NumberOption.Initialize))]
|
||||
public static bool NumberInit(NumberOption __instance)
|
||||
{
|
||||
if (!__instance.IsCustom()) return true;
|
||||
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(NumberOption), nameof(NumberOption.UpdateValue))]
|
||||
public static bool NumberUpdate(NumberOption __instance)
|
||||
{
|
||||
return !__instance.IsCustom();
|
||||
}
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(StringOption), nameof(StringOption.Initialize))]
|
||||
public static bool StringInit(StringOption __instance)
|
||||
{
|
||||
if (!__instance.IsCustom()) return true;
|
||||
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
|
||||
__instance.ValueText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Values[__instance.Value], Array.Empty<Object>());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix, HarmonyPatch(typeof(StringOption), nameof(StringOption.UpdateValue))]
|
||||
public static bool StringUpdate(StringOption __instance)
|
||||
{
|
||||
return !__instance.IsCustom();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using Il2CppSystem.Text;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -22,17 +24,16 @@ public static class TaskAdderPatch
|
||||
RolesFolder.gameObject.SetActive(false);
|
||||
RolesFolder.FolderName = "Roles";
|
||||
RolesFolder.name = "RolesFolder";
|
||||
foreach (var pair in CustomRoleManager.ModRoles)
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins.Values)
|
||||
{
|
||||
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, __instance.transform);
|
||||
newFolder.FolderName = pair.Key.Metadata.Name;
|
||||
newFolder.name = pair.Key.Metadata.Name;
|
||||
newFolder.FolderName = newFolder.name = plugin.PluginInfo.Metadata.Name;
|
||||
newFolder.gameObject.SetActive(false);
|
||||
RolesFolder.SubFolders.Add(newFolder);
|
||||
|
||||
if (!ModsFolders.ContainsKey(pair.Key.Metadata.Name))
|
||||
if (!ModsFolders.ContainsKey(plugin.PluginId))
|
||||
{
|
||||
ModsFolders.Add(pair.Key.Metadata.Name, pair.Key.Metadata.GUID);
|
||||
ModsFolders.Add(plugin.PluginInfo.Metadata.Name, plugin.PluginId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,12 +151,42 @@ public static class TaskAdderPatch
|
||||
}
|
||||
}
|
||||
}
|
||||
if (taskFolder.FolderName == "Roles")
|
||||
{
|
||||
for (int m = 0; m < DestroyableSingleton<RoleManager>.Instance.AllRoles.Length; m++)
|
||||
{
|
||||
RoleBehaviour roleBehaviour = DestroyableSingleton<RoleManager>.Instance.AllRoles[m];
|
||||
if (roleBehaviour.Role != RoleTypes.ImpostorGhost && roleBehaviour.Role != RoleTypes.CrewmateGhost && !CustomRoleManager.CustomRoles.ContainsKey((ushort)roleBehaviour.Role))
|
||||
{
|
||||
TaskAddButton taskAddButton2 = Object.Instantiate<TaskAddButton>(__instance.RoleButton);
|
||||
taskAddButton2.SafePositionWorld = __instance.SafePositionWorld;
|
||||
taskAddButton2.Text.text = "Be_" + roleBehaviour.NiceName + ".exe";
|
||||
__instance.AddFileAsChild(RolesFolder, taskAddButton2, ref num, ref num2, ref num3);
|
||||
taskAddButton2.Role = roleBehaviour;
|
||||
if (taskAddButton2 != null && taskAddButton2.Button != null)
|
||||
{
|
||||
ControllerManager.Instance.AddSelectableUiElement(taskAddButton2.Button, false);
|
||||
if (m == 0 && __instance.restorePreviousSelectionFound != null)
|
||||
{
|
||||
ControllerManager.Instance.SetDefaultSelection(__instance.restorePreviousSelectionFound, null);
|
||||
__instance.restorePreviousSelectionByFolderName = string.Empty;
|
||||
__instance.restorePreviousSelectionFound = null;
|
||||
}
|
||||
else if (m == 0)
|
||||
{
|
||||
ControllerManager.Instance.SetDefaultSelection(taskAddButton2.Button, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ModsFolders.TryGetValue(taskFolder.FolderName, out string guid))
|
||||
{
|
||||
for (var m = 0; m < CustomRoleManager.GetRolesRegistered(guid).Count; m++)
|
||||
MiraPluginInfo plugin = MiraPluginManager.Instance.GetPluginByGUID(guid);
|
||||
for (var m = 0; m < plugin.CustomRoles.Count; m++)
|
||||
{
|
||||
var roleBehaviour = CustomRoleManager.GetRolesRegistered(guid)[m];
|
||||
var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
|
||||
if (roleBehaviour.Role != RoleTypes.ImpostorGhost && roleBehaviour.Role != RoleTypes.CrewmateGhost && !roleBehaviour.IsDead)
|
||||
{
|
||||
var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MiraAPI.PluginLoading
|
||||
{
|
||||
public interface IMiraPlugin
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using BepInEx;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MiraAPI.PluginLoading;
|
||||
|
||||
public class MiraPluginInfo
|
||||
{
|
||||
public string PluginId { get; set; }
|
||||
public IMiraPlugin Config { get; set; }
|
||||
public PluginInfo PluginInfo { get; set; }
|
||||
|
||||
public readonly List<IModdedOptionGroup> OptionGroups = [];
|
||||
public readonly List<IModdedOption> Options = [];
|
||||
|
||||
public readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
||||
public readonly Dictionary<int, CustomGameMode> GameModes = [];
|
||||
|
||||
public MiraPluginInfo(string id, IMiraPlugin config, PluginInfo info)
|
||||
{
|
||||
PluginId = id;
|
||||
Config = config;
|
||||
PluginInfo = info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.PluginLoading;
|
||||
|
||||
public class MiraPluginManager
|
||||
{
|
||||
public Dictionary<Assembly, MiraPluginInfo> RegisteredPlugins = [];
|
||||
public static MiraPluginManager Instance;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Instance = this;
|
||||
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, plugin) =>
|
||||
{
|
||||
if (!plugin.GetType().GetInterfaces().Contains(typeof(IMiraPlugin))) return;
|
||||
|
||||
var id = MetadataHelper.GetMetadata(plugin.GetType()).GUID;
|
||||
var info = new MiraPluginInfo(id, plugin as IMiraPlugin, IL2CPPChainloader.Instance.Plugins[id]);
|
||||
|
||||
RegisterRoleAttribute(assembly, info);
|
||||
RegisterOptionsGroups(assembly, info);
|
||||
RegisterOptionsAttributes(assembly, info);
|
||||
|
||||
RegisteredPlugins.Add(assembly, info);
|
||||
|
||||
Logger<MiraAPIPlugin>.Info($"Registering mod {id} with Mira API.");
|
||||
};
|
||||
}
|
||||
|
||||
public MiraPluginInfo GetPluginByGUID(string guid)
|
||||
{
|
||||
return RegisteredPlugins.Values.Where(plugin => plugin.PluginId == guid).First();
|
||||
}
|
||||
|
||||
|
||||
private static void RegisterOptionsAttributes(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
foreach (PropertyInfo property in type.GetProperties())
|
||||
{
|
||||
foreach (var attribute in property.GetCustomAttributes())
|
||||
{
|
||||
if (attribute.GetType().BaseType == typeof(ModdedOptionAttribute))
|
||||
{
|
||||
pluginInfo.Options.Add(ModdedOptionsManager.RegisterOption(type, (ModdedOptionAttribute)attribute, property));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterOptionsGroups(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (typeof(IModdedOptionGroup).IsAssignableFrom(type))
|
||||
{
|
||||
IModdedOptionGroup group = (IModdedOptionGroup)Activator.CreateInstance(type);
|
||||
ModdedOptionGroup newGroup = new ModdedOptionGroup()
|
||||
{
|
||||
AdvancedRole = group.AdvancedRole,
|
||||
GroupColor = group.GroupColor,
|
||||
GroupName = group.GroupName,
|
||||
GroupVisible = group.GroupVisible
|
||||
};
|
||||
|
||||
ModdedOptionsManager.Groups.Add(newGroup);
|
||||
ModdedOptionsManager.OriginalTypes.Add(type, newGroup);
|
||||
pluginInfo.OptionGroups.Add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterRoleAttribute(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterCustomRoleAttribute>();
|
||||
if (attribute == null) continue;
|
||||
|
||||
ClassInjector.RegisterTypeInIl2Cpp(type);
|
||||
|
||||
var role = CustomRoleManager.RegisterRole(type, attribute.RoleId);
|
||||
|
||||
pluginInfo.CustomRoles.Add((ushort)role.Role, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using Il2CppInterop.Runtime;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
@@ -9,7 +8,6 @@ using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MiraAPI.Networking;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -18,46 +16,40 @@ namespace MiraAPI.Roles;
|
||||
|
||||
public static class CustomRoleManager
|
||||
{
|
||||
public static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
||||
public static readonly Dictionary<PluginInfo, List<RoleBehaviour>> ModRoles = [];
|
||||
public static Dictionary<ushort, RoleBehaviour> CustomRoles = new();
|
||||
|
||||
public static int GetNextRoleId(ushort requestedId)
|
||||
{
|
||||
while (CustomRoles.ContainsKey(requestedId))
|
||||
{
|
||||
requestedId++;
|
||||
}
|
||||
|
||||
return requestedId;
|
||||
}
|
||||
|
||||
public static void RegisterInRoleManager()
|
||||
{
|
||||
RoleManager.Instance.AllRoles = RoleManager.Instance.AllRoles.Concat(CustomRoles.Values).ToArray();
|
||||
}
|
||||
|
||||
internal static void RegisterRole(Type roleType, ushort roleId, string modId)
|
||||
internal static RoleBehaviour RegisterRole(Type roleType, ushort roleId)
|
||||
{
|
||||
if (!IL2CPPChainloader.Instance.Plugins.TryGetValue(modId, out PluginInfo info))
|
||||
{
|
||||
Debug.LogError($"{modId} is not a valid mod!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(typeof(RoleBehaviour).IsAssignableFrom(roleType) && typeof(ICustomRole).IsAssignableFrom(roleType)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CustomRoles.Any(behaviour => behaviour.GetType() == roleType))
|
||||
{
|
||||
return;
|
||||
Logger<MiraAPIPlugin>.Error($"{roleType?.Name} does not inherit from RoleBehaviour or ICustomRole.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var roleBehaviour = (RoleBehaviour)new GameObject(roleType.Name).DontDestroy().AddComponent(Il2CppType.From(roleType));
|
||||
|
||||
if (roleBehaviour is not ICustomRole customRole)
|
||||
{
|
||||
return;
|
||||
roleBehaviour.gameObject.Destroy();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CustomRoles.ContainsKey(roleId))
|
||||
{
|
||||
Debug.LogError($"Role ID conflict for {customRole.RoleName}. Use a different ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
roleBehaviour.Role = (RoleTypes)roleId;
|
||||
roleBehaviour.Role = (RoleTypes)GetNextRoleId(roleId);
|
||||
roleBehaviour.TeamType = customRole.Team == ModdedRoleTeams.Neutral ? RoleTeamTypes.Crewmate : (RoleTeamTypes)customRole.Team;
|
||||
roleBehaviour.NameColor = customRole.RoleColor;
|
||||
roleBehaviour.StringName = CustomStringName.CreateAndRegister(customRole.RoleName);
|
||||
@@ -76,47 +68,27 @@ public static class CustomRoleManager
|
||||
RoleManager.GhostRoles.Add(roleBehaviour.Role);
|
||||
}
|
||||
|
||||
if (ModRoles.TryGetValue(info, out List<RoleBehaviour> roles))
|
||||
{
|
||||
roles.Add(roleBehaviour);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModRoles.TryAdd(info, [roleBehaviour]);
|
||||
}
|
||||
|
||||
CustomRoles.Add(roleId, roleBehaviour);
|
||||
|
||||
if (customRole.HideSettings)
|
||||
{
|
||||
return;
|
||||
return roleBehaviour;
|
||||
}
|
||||
|
||||
var config = PluginSingleton<MiraAPIPlugin>.Instance.Config;
|
||||
config.Bind(customRole.NumConfigDefinition, 1);
|
||||
config.Bind(customRole.ChanceConfigDefinition, 100);
|
||||
|
||||
return roleBehaviour;
|
||||
}
|
||||
|
||||
public static List<RoleBehaviour> GetRolesRegistered(string modId)
|
||||
{
|
||||
PluginInfo info = ModRoles.Keys.First(key => key.Metadata.GUID == modId);
|
||||
if (ModRoles.TryGetValue(info, out List<RoleBehaviour> roles))
|
||||
{
|
||||
return roles;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"{modId} has no roles registered.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetCustomRoleBehaviour(RoleTypes roleType, out ICustomRole result)
|
||||
{
|
||||
CustomRoles.TryGetValue((ushort)roleType, out var temp);
|
||||
if (temp is ICustomRole role)
|
||||
if (temp != null)
|
||||
{
|
||||
result = role;
|
||||
result = temp as ICustomRole;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,46 +1,18 @@
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterCustomRoleAttribute : Attribute
|
||||
{
|
||||
private static readonly HashSet<Assembly> RegisteredAssemblies = [];
|
||||
public ushort RoleId { get; }
|
||||
public string ModId { get; }
|
||||
|
||||
public RegisterCustomRoleAttribute(string modId)
|
||||
public RegisterCustomRoleAttribute()
|
||||
{
|
||||
ModId = modId;
|
||||
RoleId = (ushort)(20 + CustomRoleManager.CustomRoles.Count);
|
||||
}
|
||||
public RegisterCustomRoleAttribute(string modId, ushort roleId)
|
||||
public RegisterCustomRoleAttribute(ushort roleId)
|
||||
{
|
||||
ModId = modId;
|
||||
RoleId = roleId;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, plugin) => Register(assembly);
|
||||
}
|
||||
|
||||
public static void Register(Assembly assembly)
|
||||
{
|
||||
if (!RegisteredAssemblies.Add(assembly)) return;
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterCustomRoleAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
Helpers.RegisterType(type);
|
||||
CustomRoleManager.RegisterRole(type, attribute.RoleId, attribute.ModId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
@@ -7,6 +8,13 @@ namespace MiraAPI.Utilities
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static bool IsCustom(this OptionBehaviour optionBehaviour)
|
||||
{
|
||||
if (ModdedOptionsManager.Options.Any(opt => opt.OptionBehaviour == optionBehaviour)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void UpdateBodies(this PlayerControl playerControl, Color outlineColor, ref DeadBody target)
|
||||
{
|
||||
foreach (var body in Object.FindObjectsOfType<DeadBody>())
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.Roles;
|
||||
using System;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
@@ -17,24 +14,6 @@ namespace MiraAPI.Utilities
|
||||
return ShipStatus.Instance.AllRooms.ToList().Find(room => room.roomArea.OverlapPoint(pos));
|
||||
}
|
||||
|
||||
public static void RegisterType(Type type)
|
||||
{
|
||||
if (ClassInjector.IsTypeRegisteredInIl2Cpp(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ClassInjector.RegisterTypeInIl2Cpp(type);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to register {type.FullDescription()}: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string GetSuffix(NumberSuffixes suffix)
|
||||
{
|
||||
return suffix switch
|
||||
|
||||
Reference in new issue
Block a user