mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
Make everything more attribute-based, WIP
This commit is contained in:
1 parent
5f29175235
commit
658e3659c5
25 files changed
+604
-82
No files matched your search
@@ -0,0 +1,15 @@
|
||||
using MiraAPI.Roles;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example
|
||||
{
|
||||
[RegisterCustomRole(ExamplePlugin.Id)]
|
||||
public class CustomRole : CrewmateRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Sussy Baka";
|
||||
public string RoleDescription => "Role decs?";
|
||||
public string RoleLongDescription => "Extra role decs?";
|
||||
public Color RoleColor => Palette.Orange;
|
||||
public RoleTeamTypes Team => RoleTeamTypes.Crewmate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using MiraAPI.API.GameOptions;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example
|
||||
{
|
||||
[RegisterCustomOptions(ExamplePlugin.Id)]
|
||||
public class ExampleOptions : IModOptions
|
||||
{
|
||||
public LoadableAsset<Sprite> OptionsTabIcon => MiraAssets.Empty;
|
||||
public static CustomToggleOption YeOrNa = new CustomToggleOption("Ye or Na", true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using Reactor;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
|
||||
namespace MiraAPI.Example;
|
||||
|
||||
[BepInAutoPlugin("mira.example", "MiraAPIExample")]
|
||||
[BepInProcess("Among Us.exe")]
|
||||
[BepInDependency(ReactorPlugin.Id)]
|
||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
||||
public partial class ExamplePlugin : BasePlugin
|
||||
{
|
||||
public Harmony Harmony { get; } = new(Id);
|
||||
public static ExamplePlugin Instance { get; private set; }
|
||||
public override void Load()
|
||||
{
|
||||
Instance = this;
|
||||
Harmony.PatchAll();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<DebugType>embedded</DebugType>
|
||||
|
||||
<VersionPrefix>1.0.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
<Description>Simple and easy to use Among Us modding API.</Description>
|
||||
<Authors>Angxl, XtraCube</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GamePlatform Condition="'$(GamePlatform)' == ''">Steam</GamePlatform>
|
||||
<GameVersion Condition="'$(GamePlatform)' == 'Steam'">2024.3.5</GameVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Reactor" Version="2.2.0" />
|
||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.688" Private="false" ExcludeAssets="runtime;native" />
|
||||
<PackageReference Include="Iced" Version="1.20.0" />
|
||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.3.5" PrivateAssets="all" />
|
||||
|
||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime">
|
||||
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MiraAPI\MiraAPI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" />
|
||||
</Target>
|
||||
</Project>
|
||||
+13
-1
@@ -1,6 +1,11 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraAPI", "MiraAPI\MiraAPI.csproj", "{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}"
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34622.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiraAPI", "MiraAPI\MiraAPI.csproj", "{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraAPI.Example", "MiraAPI.Example\MiraAPI.Example.csproj", "{19B76855-16CC-43CC-A0A6-5A7FFB43F077}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -12,5 +17,12 @@ Global
|
||||
{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Roles;
|
||||
using BepInEx;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Localization.Utilities;
|
||||
using System;
|
||||
|
||||
@@ -14,6 +15,7 @@ public abstract class AbstractGameOption
|
||||
public CustomOptionGroup Group { get; set; }
|
||||
public Func<bool> Hidden { get; set; }
|
||||
public OptionBehaviour OptionBehaviour { get; protected set; }
|
||||
public PluginInfo ParentMod { get; set; }
|
||||
public void ValueChanged(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
OnValueChanged(optionBehaviour);
|
||||
@@ -33,6 +35,5 @@ public abstract class AbstractGameOption
|
||||
|
||||
Save = save;
|
||||
Hidden = () => false;
|
||||
CustomOptionsManager.CustomOptions.Add(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class RegisterCustomOptionAttribute : Attribute
|
||||
{
|
||||
private static readonly HashSet<Assembly> RegisteredAssemblies = [];
|
||||
public string ModId { get; }
|
||||
|
||||
public RegisterCustomOptionAttribute(string modId)
|
||||
{
|
||||
ModId = modId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.API.GameOptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterCustomOptionsAttribute : Attribute
|
||||
{
|
||||
private static readonly HashSet<Assembly> RegisteredAssemblies = [];
|
||||
public string ModId { get; }
|
||||
public List<FieldInfo> Options;
|
||||
|
||||
public RegisterCustomOptionsAttribute(string modId)
|
||||
{
|
||||
ModId = modId;
|
||||
}
|
||||
|
||||
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<RegisterCustomOptionsAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
attribute.Options = type.GetFields(BindingFlags.Static | BindingFlags.Public)
|
||||
.Where(fi => fi.FieldType.BaseType == typeof(AbstractGameOption) || fi.FieldType.BaseType == typeof(CustomOptionGroup)).ToList();
|
||||
CustomOptionsManager.RegisterOptionsForMod(type, attribute.Options, attribute.ModId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,6 @@ public class CustomNumberOption : AbstractGameOption
|
||||
Logger<MiraAPIPlugin>.Warning(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
CustomOptionsManager.CustomNumberOptions.Add(this);
|
||||
}
|
||||
|
||||
public void SetValue(float newValue)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Roles;
|
||||
using BepInEx;
|
||||
using MiraAPI.Roles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
@@ -11,6 +12,7 @@ public class CustomOptionGroup
|
||||
|
||||
public GameObject Header;
|
||||
public Type AdvancedRole { get; set; }
|
||||
public PluginInfo ParentMod { get; set; }
|
||||
|
||||
public readonly List<AbstractGameOption> Options = [];
|
||||
public readonly List<CustomNumberOption> CustomNumberOptions;
|
||||
@@ -40,7 +42,5 @@ public class CustomOptionGroup
|
||||
{
|
||||
option.Group = this;
|
||||
}
|
||||
|
||||
CustomOptionsManager.CustomGroups.Add(this);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
using MiraAPI.Networking.Options;
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Networking.Options;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.API.GameOptions;
|
||||
|
||||
@@ -13,6 +19,56 @@ public static class CustomOptionsManager
|
||||
public static readonly List<CustomToggleOption> CustomToggleOptions = [];
|
||||
public static readonly List<CustomStringOption> CustomStringOptions = [];
|
||||
public static readonly List<CustomOptionGroup> CustomGroups = [];
|
||||
public static readonly List<PluginInfo> RegisteredMods = [];
|
||||
|
||||
public static void RegisterOptionsForMod(Type type, List<FieldInfo> fields, string modId)
|
||||
{
|
||||
if (!typeof(IModOptions).IsAssignableFrom(type))
|
||||
{
|
||||
Debug.LogError($"Cannot register options for {modId}! Missing IModOptions interface.");
|
||||
return;
|
||||
}
|
||||
PluginInfo info = IL2CPPChainloader.Instance.Plugins[modId];
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"Registering Options for {modId}");
|
||||
|
||||
RegisteredMods.Add(info);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
AbstractGameOption option = (AbstractGameOption)field.GetValue(null);
|
||||
if (option == null)
|
||||
{
|
||||
CustomOptionGroup group = (CustomOptionGroup)field.GetValue(null);
|
||||
group.ParentMod = info;
|
||||
CustomGroups.Add(group);
|
||||
}
|
||||
|
||||
option.ParentMod = info;
|
||||
|
||||
CustomOptions.Add(option);
|
||||
switch (field.FieldType.Name)
|
||||
{
|
||||
case nameof(CustomNumberOption):
|
||||
CustomNumberOptions.Add((CustomNumberOption)option);
|
||||
break;
|
||||
|
||||
case nameof(CustomToggleOption):
|
||||
CustomToggleOptions.Add((CustomToggleOption)option);
|
||||
break;
|
||||
|
||||
case nameof(CustomStringOption):
|
||||
CustomStringOptions.Add((CustomStringOption)option);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncOptions()
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost)
|
||||
|
||||
@@ -1,38 +1,40 @@
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.API.GameOptions;
|
||||
public static class CustomOptionsTab
|
||||
{
|
||||
public static GameObject CustomTab;
|
||||
public static GameObject CustomScreen;
|
||||
public static List<GameObject> CustomTabs;
|
||||
public static List<GameObject> CustomScreens;
|
||||
public static SpriteRenderer Rend;
|
||||
|
||||
public static GameObject Initialize(GameSettingMenu __instance)
|
||||
{
|
||||
var gameBtn = __instance.transform.FindChild("Header/Tabs/GameTab").gameObject;
|
||||
var roleBtn = __instance.transform.FindChild("Header/Tabs/RoleTab").gameObject;
|
||||
var screen = CreateNewMenu(__instance);
|
||||
var tab = CreateCustomTab(__instance, screen, gameBtn, roleBtn);
|
||||
|
||||
CustomScreen = CreateNewMenu(__instance);
|
||||
CustomTab = CreateCustomTab(__instance, CustomScreen, gameBtn, roleBtn);
|
||||
CustomScreens.Add(screen);
|
||||
CustomTabs.Add(tab);
|
||||
|
||||
Rend = CustomTab.transform.FindChild("LaunchpadBtn/Tab Background").GetComponent<SpriteRenderer>();
|
||||
Rend = tab.transform.FindChild("Btn/Tab Background").GetComponent<SpriteRenderer>();
|
||||
Rend.enabled = false;
|
||||
|
||||
UpdateListeners(__instance, gameBtn.GetComponentInChildren<PassiveButton>(), roleBtn.GetComponentInChildren<PassiveButton>(), Rend);
|
||||
|
||||
var container = CustomScreen.transform.FindChild("GameGroup/SliderInner");
|
||||
var container = screen.transform.FindChild("GameGroup/SliderInner");
|
||||
container.DestroyChildren();
|
||||
CreateNewResetButton(__instance, container);
|
||||
//CreateNewResetButton(__instance, container);
|
||||
|
||||
return container.gameObject;
|
||||
}
|
||||
|
||||
private static void CreateNewResetButton(GameSettingMenu __instance, Transform container)
|
||||
/*private static void CreateNewResetButton(GameSettingMenu __instance, Transform container)
|
||||
{
|
||||
var resetBtn = __instance.RegularGameSettings.transform.FindChild("GameGroup/SliderInner/ResetToDefault");
|
||||
var newResetBtn = Object.Instantiate(resetBtn.gameObject, container);
|
||||
@@ -54,12 +56,12 @@ public static class CustomOptionsTab
|
||||
toggle.OnClick.AddListener((UnityAction)(() => { CustomOptionsManager.ResetToDefault(); }));
|
||||
toggle.OnMouseOver.AddListener((UnityAction)(() => { tmp.text = "<b>Reset Options</b>"; }));
|
||||
toggle.OnMouseOut.AddListener((UnityAction)(() => { tmp.text = "Reset Options"; }));
|
||||
}
|
||||
}*/
|
||||
|
||||
private static void UpdateListeners(GameSettingMenu __instance, PassiveButton gameB, PassiveButton roleB, SpriteRenderer rend)
|
||||
{
|
||||
gameB.OnClick.RemoveAllListeners();
|
||||
gameB.OnClick.AddListener((UnityAction)(() =>
|
||||
/* gameB.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
__instance.RegularGameSettings.SetActive(true);
|
||||
__instance.RolesSettings.gameObject.SetActive(false);
|
||||
@@ -82,7 +84,7 @@ public static class CustomOptionsTab
|
||||
|
||||
__instance.GameSettingsHightlight.enabled = false;
|
||||
__instance.RolesSettingsHightlight.enabled = true;
|
||||
}));
|
||||
}));*/
|
||||
}
|
||||
|
||||
public static GameObject CreateHeader(ToggleOption toggleOpt, Transform container, string title)
|
||||
@@ -113,11 +115,11 @@ public static class CustomOptionsTab
|
||||
GameObject gameTab, GameObject roleTab)
|
||||
{
|
||||
var newTab = Object.Instantiate(gameTab, gameTab.transform.parent);
|
||||
newTab.name = "LaunchpadTab";
|
||||
newTab.name = "Tab";
|
||||
gameTab.transform.position += new Vector3(-1, 0, 0);
|
||||
|
||||
var inside = newTab.transform.FindChild("ColorButton");
|
||||
inside.name = "LaunchpadBtn";
|
||||
inside.name = "Btn";
|
||||
|
||||
var btn = inside.GetComponentInChildren<PassiveButton>();
|
||||
|
||||
@@ -135,6 +137,12 @@ public static class CustomOptionsTab
|
||||
{
|
||||
__instance.RegularGameSettings.SetActive(false);
|
||||
__instance.RolesSettings.gameObject.SetActive(false);
|
||||
|
||||
foreach (var screen in CustomScreens)
|
||||
{
|
||||
screen.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
newSettings.gameObject.SetActive(true);
|
||||
|
||||
var rend = inside.transform.FindChild("Tab Background").GetComponent<SpriteRenderer>();
|
||||
@@ -142,6 +150,11 @@ public static class CustomOptionsTab
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,13 +162,13 @@ public static class CustomOptionsTab
|
||||
{
|
||||
var gameSettings = __instance.RegularGameSettings;
|
||||
var newSettings = Object.Instantiate(gameSettings, gameSettings.transform.parent);
|
||||
newSettings.name = "Launchpad Settings";
|
||||
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 = "Launchpad Settings";
|
||||
text.text = "Settings";
|
||||
|
||||
return newSettings;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ public class CustomStringOption : AbstractGameOption
|
||||
Options = options;
|
||||
Default = defaultValue;
|
||||
|
||||
CustomOptionsManager.CustomStringOptions.Add(this);
|
||||
if (Save)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -27,7 +27,6 @@ public class CustomToggleOption : AbstractGameOption
|
||||
Logger<MiraAPIPlugin>.Warning(e.ToString());
|
||||
}
|
||||
}
|
||||
CustomOptionsManager.CustomToggleOptions.Add(this);
|
||||
}
|
||||
|
||||
public void SetValue(bool newValue)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions
|
||||
{
|
||||
public interface IModOptions
|
||||
{
|
||||
LoadableAsset<Sprite> OptionsTabIcon { get; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor;
|
||||
@@ -11,7 +12,7 @@ using System.Reflection;
|
||||
|
||||
namespace MiraAPI;
|
||||
|
||||
[BepInAutoPlugin("dev.xtracube.launchpad", "MiraAPI")]
|
||||
[BepInAutoPlugin("mira.api", "MiraAPI")]
|
||||
[BepInProcess("Among Us.exe")]
|
||||
[BepInDependency(ReactorPlugin.Id)]
|
||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
||||
@@ -25,8 +26,10 @@ public partial class MiraAPIPlugin : BasePlugin
|
||||
Instance = this;
|
||||
Harmony.PatchAll();
|
||||
|
||||
RegisterGameModeAttribute.Register(Assembly.GetExecutingAssembly());
|
||||
RegisterCustomRoleAttribute.Register(Assembly.GetExecutingAssembly());
|
||||
RegisterCustomRoleAttribute.Initialize();
|
||||
RegisterCustomOptionsAttribute.Initialize();
|
||||
|
||||
RegisterGameModeAttribute.Register(Assembly.GetCallingAssembly());
|
||||
RegisterButtonAttribute.Register(Assembly.GetExecutingAssembly());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using HarmonyLib;
|
||||
using InnerNet;
|
||||
using MiraAPI.API.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Patches.Options;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches
|
||||
{
|
||||
[HarmonyPatch(typeof(HudManager))]
|
||||
public static class HudManagerPatches
|
||||
{
|
||||
/// Custom buttons parent
|
||||
private static GameObject _bottomLeft;
|
||||
|
||||
/// Custom role tab
|
||||
private static TaskPanelBehaviour _roleTab;
|
||||
|
||||
/// Scrolling increment
|
||||
private const float Increment = 0.3f;
|
||||
|
||||
/// Bounds for scrolling
|
||||
private static FloatRange _bounds = new FloatRange(2.9f, 4.6f);
|
||||
|
||||
/// <summary>
|
||||
/// Add options scrolling (on the hud text)
|
||||
/// </summary>
|
||||
public static void OptionsScrollingLogic(HudManager __instance)
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Tab))
|
||||
{
|
||||
if (ToHudStringPatch.CurrentPage >= CustomOptionsManager.RegisteredMods.Count)
|
||||
{
|
||||
ToHudStringPatch.CurrentPage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToHudStringPatch.CurrentPage += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var numPlayers = GameData.Instance ? GameData.Instance.PlayerCount : 10;
|
||||
HudManager.Instance.GameSettings.text = GameOptionsManager.Instance.CurrentGameOptions.ToHudString(numPlayers);
|
||||
var pos = __instance.GameSettings.transform.localPosition;
|
||||
|
||||
if (!PlayerControl.LocalPlayer.CanMove)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ToHudStringPatch.CurrentPage == 0)
|
||||
{
|
||||
__instance.GameSettings.transform.localPosition = new Vector3(pos.x, _bounds.min, pos.z);
|
||||
return;
|
||||
}
|
||||
|
||||
_bounds.max = __instance.GameSettings.rectTransform.sizeDelta.y + _bounds.min;
|
||||
|
||||
var delta = Input.mouseScrollDelta.y switch
|
||||
{
|
||||
> 0f => -Increment,
|
||||
< 0f => Increment,
|
||||
_ => 0f
|
||||
};
|
||||
|
||||
pos = new Vector3(pos.x, Mathf.Clamp(pos.y + delta, _bounds.min, _bounds.max), pos.z);
|
||||
|
||||
__instance.GameSettings.transform.localPosition = pos;
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch("Update")]
|
||||
public static void UpdatePostfix(HudManager __instance)
|
||||
{
|
||||
var local = PlayerControl.LocalPlayer;
|
||||
if (LobbyBehaviour.Instance)
|
||||
{
|
||||
OptionsScrollingLogic(__instance);
|
||||
}
|
||||
|
||||
if (AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started && !ShipStatus.Instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//CustomGameModeManager.ActiveMode.HudUpdate(__instance);
|
||||
|
||||
if (local.Data.Role is ICustomRole customRole)
|
||||
{
|
||||
customRole.HudUpdate(__instance);
|
||||
|
||||
if (customRole.SetTabText() != null)
|
||||
{
|
||||
if (_roleTab == null)
|
||||
{
|
||||
_roleTab = CustomRoleManager.CreateRoleTab(customRole);
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomRoleManager.UpdateRoleTab(_roleTab, customRole);
|
||||
}
|
||||
}
|
||||
else if (customRole.SetTabText() == null && _roleTab)
|
||||
{
|
||||
_roleTab.gameObject.Destroy();
|
||||
}
|
||||
}
|
||||
else if (_roleTab)
|
||||
{
|
||||
_roleTab.gameObject.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// Trigger hudstart on current custom gamemode
|
||||
/// </summary>
|
||||
[HarmonyPostfix, HarmonyPatch("OnGameStart")]
|
||||
public static void GameStartPatch(HudManager __instance)
|
||||
{
|
||||
CustomGameModeManager.ActiveMode.HudStart(__instance);
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Create custom buttons parent
|
||||
/// </summary>
|
||||
[HarmonyPostfix, HarmonyPatch("Start")]
|
||||
public static void StartPostfix(HudManager __instance)
|
||||
{
|
||||
if (!_bottomLeft)
|
||||
{
|
||||
var buttons = __instance.transform.Find("Buttons");
|
||||
_bottomLeft = UnityEngine.Object.Instantiate(buttons.Find("BottomRight").gameObject, buttons);
|
||||
}
|
||||
|
||||
foreach (var t in _bottomLeft.GetComponentsInChildren<ActionButton>(true))
|
||||
{
|
||||
t.gameObject.Destroy();
|
||||
}
|
||||
|
||||
var gridArrange = _bottomLeft.GetComponent<GridArrange>();
|
||||
var aspectPosition = _bottomLeft.GetComponent<AspectPosition>();
|
||||
|
||||
_bottomLeft.name = "BottomLeft";
|
||||
gridArrange.Alignment = GridArrange.StartAlign.Right;
|
||||
aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftBottom;
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
button.CreateButton(_bottomLeft.transform);
|
||||
}
|
||||
|
||||
gridArrange.Start();
|
||||
gridArrange.ArrangeChilds();
|
||||
|
||||
aspectPosition.AdjustPosition();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure all launchpad hud elements are inactive/active when appropriate
|
||||
/// </summary>
|
||||
[HarmonyPostfix, HarmonyPatch("SetHudActive", typeof(PlayerControl), typeof(RoleBehaviour), typeof(bool))]
|
||||
public static void SetHudActivePostfix(HudManager __instance, [HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] RoleBehaviour roleBehaviour, [HarmonyArgument(2)] bool isActive)
|
||||
{
|
||||
if (player.Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_roleTab)
|
||||
{
|
||||
_roleTab.gameObject.SetActive(isActive);
|
||||
}
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
button.SetActive(isActive, roleBehaviour);
|
||||
|
||||
if (roleBehaviour is ICustomRole role)
|
||||
{
|
||||
__instance.ImpostorVentButton.gameObject.SetActive(isActive && role.CanUseVent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,13 @@ public static class GameSettingsMenuPatches
|
||||
[HarmonyPrefix, HarmonyPatch("Start")]
|
||||
public static void StartPrefix(GameSettingMenu __instance)
|
||||
{
|
||||
if (CustomOptionsTab.CustomTab)
|
||||
if (CustomOptionsTab.CustomTabs != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CustomOptionsTab.CustomTabs = new();
|
||||
|
||||
__instance.Tabs.transform.position += new Vector3(0.5f, 0, 0);
|
||||
_gameBtn = __instance.transform.FindChild("Header/Tabs/GameTab").gameObject;
|
||||
_roleBtn = __instance.transform.FindChild("Header/Tabs/RoleTab").gameObject;
|
||||
@@ -81,7 +83,7 @@ public static class GameSettingsMenuPatches
|
||||
__instance.RegularGameSettings.SetActive(false);
|
||||
__instance.RolesSettings.gameObject.SetActive(false);
|
||||
|
||||
CustomOptionsTab.CustomScreen.gameObject.SetActive(true);
|
||||
//CustomOptionsTab.CustomScreen.gameObject.SetActive(true);
|
||||
CustomOptionsTab.Rend.enabled = true;
|
||||
|
||||
__instance.GameSettingsHightlight.enabled = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.API.GameOptions;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,11 +13,7 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(IGameOptionsExtensions), "ToHudString")]
|
||||
public static class ToHudStringPatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Show custom Launchpad options or vanilla game options
|
||||
/// </summary>
|
||||
public static bool ShowCustom = false;
|
||||
|
||||
public static int CurrentPage = 0;
|
||||
/// <summary>
|
||||
/// Generic method to add options
|
||||
/// </summary>
|
||||
@@ -82,28 +78,32 @@ public static class ToHudStringPatch
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var role in CustomRoleManager.CustomRoles.Values)
|
||||
foreach (var pair in CustomRoleManager.CustomRoles)
|
||||
{
|
||||
var customRole = role as ICustomRole;
|
||||
var customRole = pair.Value as ICustomRole;
|
||||
if (customRole.IsGhostRole)
|
||||
{
|
||||
role.Role = (RoleTypes)customRole.RoleId;
|
||||
pair.Value.Role = (RoleTypes)pair.Key;
|
||||
}
|
||||
}
|
||||
|
||||
if (ShowCustom || !CustomGameModeManager.ActiveMode.CanAccessSettingsTab())
|
||||
if (CurrentPage != 0)
|
||||
{
|
||||
var sb = new StringBuilder("<size=180%><b>Launchpad Options:</b></size>\n<size=130%>");
|
||||
var groupsWithRoles = CustomOptionsManager.CustomGroups.Where(group => group.AdvancedRole != null);
|
||||
var groupsWithoutRoles = CustomOptionsManager.CustomGroups.Where(group => group.AdvancedRole == null);
|
||||
PluginInfo currentPlugin = CustomOptionsManager.RegisteredMods[CurrentPage - 1];
|
||||
if (currentPlugin == null)
|
||||
{
|
||||
CurrentPage = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var suffix = CustomGameModeManager.ActiveMode.CanAccessSettingsTab() ? "\nPress <b>Tab</b> to view Normal Options" :
|
||||
$"\n<b>You can not access Normal Options on {CustomGameModeManager.ActiveMode.Name} mode.</b>";
|
||||
var sb = new StringBuilder($"<size=180%><b>{currentPlugin.Metadata.Name} Options:</b></size>\n<size=130%>");
|
||||
var groupsWithRoles = CustomOptionsManager.CustomGroups.Where(group => group.AdvancedRole != null && group.ParentMod == currentPlugin);
|
||||
var groupsWithoutRoles = CustomOptionsManager.CustomGroups.Where(group => group.AdvancedRole == null && group.ParentMod == currentPlugin);
|
||||
|
||||
AddOptions(sb,
|
||||
CustomOptionsManager.CustomNumberOptions.Where(option => option.Group == null && !option.Hidden()),
|
||||
CustomOptionsManager.CustomStringOptions.Where(option => option.Group == null && !option.Hidden()),
|
||||
CustomOptionsManager.CustomToggleOptions.Where(option => option.Group == null && !option.Hidden())
|
||||
CustomOptionsManager.CustomNumberOptions.Where(option => option.Group == null && option.ParentMod == currentPlugin && !option.Hidden()),
|
||||
CustomOptionsManager.CustomStringOptions.Where(option => option.Group == null && option.ParentMod == currentPlugin && !option.Hidden()),
|
||||
CustomOptionsManager.CustomToggleOptions.Where(option => option.Group == null && option.ParentMod == currentPlugin && !option.Hidden())
|
||||
);
|
||||
|
||||
foreach (var group in groupsWithoutRoles)
|
||||
@@ -117,14 +117,8 @@ public static class ToHudStringPatch
|
||||
AddOptions(sb, group.CustomNumberOptions, group.CustomStringOptions, group.CustomToggleOptions);
|
||||
}
|
||||
|
||||
if (GameManager.Instance.IsHideAndSeek())
|
||||
{
|
||||
__result = sb + suffix;
|
||||
return;
|
||||
}
|
||||
|
||||
var customOptionGroups = groupsWithRoles as CustomOptionGroup[] ?? groupsWithRoles.ToArray();
|
||||
if (customOptionGroups.Any() && CustomGameModeManager.ActiveMode.CanAccessRolesTab())
|
||||
if (customOptionGroups.Any())
|
||||
{
|
||||
sb.AppendLine("\n<size=160%><b>Roles</b></size>");
|
||||
|
||||
@@ -141,10 +135,13 @@ public static class ToHudStringPatch
|
||||
}
|
||||
}
|
||||
|
||||
__result = sb + suffix;
|
||||
return;
|
||||
__result = sb.ToString();
|
||||
}
|
||||
|
||||
__result = "<size=160%><b>Normal Options:</b></size>\n<size=130%>" + __result + "\nPress <b>Tab</b> to view Launchpad Options</size>";
|
||||
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}/{CustomOptionsManager.RegisteredMods.Count})</size>";
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ public static class RolesSettingsMenuPatches
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.Send(new SyncRoleOptionsRpc.Data(role.RoleId, numEntry.Value, chanceEntry.Value));
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.Send(new SyncRoleOptionsRpc.Data((ushort)roleSetting.Role.Role, numEntry.Value, chanceEntry.Value));
|
||||
}
|
||||
GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions;
|
||||
return false;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace MiraAPI.Patches.Roles;
|
||||
public static class TaskAdderPatch
|
||||
{
|
||||
public static TaskFolder RolesFolder;
|
||||
public static System.Collections.Generic.Dictionary<string, string> ModsFolders = new System.Collections.Generic.Dictionary<string, string>();
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(typeof(TaskAdderGame), nameof(TaskAdderGame.Begin))]
|
||||
public static void AddRolesFolder(TaskAdderGame __instance)
|
||||
@@ -21,7 +22,22 @@ public static class TaskAdderPatch
|
||||
RolesFolder.gameObject.SetActive(false);
|
||||
RolesFolder.FolderName = "Roles";
|
||||
RolesFolder.name = "RolesFolder";
|
||||
foreach (var pair in CustomRoleManager.ModRoles)
|
||||
{
|
||||
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, __instance.transform);
|
||||
newFolder.FolderName = pair.Key.Metadata.Name;
|
||||
newFolder.name = pair.Key.Metadata.Name;
|
||||
newFolder.gameObject.SetActive(false);
|
||||
RolesFolder.SubFolders.Add(newFolder);
|
||||
|
||||
if (!ModsFolders.ContainsKey(pair.Key.Metadata.Name))
|
||||
{
|
||||
ModsFolders.Add(pair.Key.Metadata.Name, pair.Key.Metadata.GUID);
|
||||
}
|
||||
}
|
||||
|
||||
__instance.Root.SubFolders.Add(RolesFolder);
|
||||
|
||||
__instance.GoToRoot();
|
||||
}
|
||||
|
||||
@@ -134,11 +150,11 @@ public static class TaskAdderPatch
|
||||
}
|
||||
}
|
||||
|
||||
if (taskFolder.FolderName == "Roles") // idk why only this works???
|
||||
if (ModsFolders.TryGetValue(taskFolder.FolderName, out string guid))
|
||||
{
|
||||
for (var m = 0; m < DestroyableSingleton<RoleManager>.Instance.AllRoles.Length; m++)
|
||||
for (var m = 0; m < CustomRoleManager.GetRolesRegistered(guid).Count; m++)
|
||||
{
|
||||
var roleBehaviour = DestroyableSingleton<RoleManager>.Instance.AllRoles[m];
|
||||
var roleBehaviour = CustomRoleManager.GetRolesRegistered(guid)[m];
|
||||
if (roleBehaviour.Role != RoleTypes.ImpostorGhost && roleBehaviour.Role != RoleTypes.CrewmateGhost && !roleBehaviour.IsDead)
|
||||
{
|
||||
var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using Il2CppInterop.Runtime;
|
||||
using MiraAPI.Networking.Options;
|
||||
using Reactor.Localization.Utilities;
|
||||
@@ -17,14 +19,21 @@ namespace MiraAPI.Roles;
|
||||
public static class CustomRoleManager
|
||||
{
|
||||
public static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
||||
public static readonly Dictionary<PluginInfo, List<RoleBehaviour>> ModRoles = [];
|
||||
|
||||
public static void RegisterInRoleManager()
|
||||
{
|
||||
RoleManager.Instance.AllRoles = RoleManager.Instance.AllRoles.Concat(CustomRoles.Values).ToArray();
|
||||
}
|
||||
|
||||
internal static void RegisterRole(Type roleType)
|
||||
internal static void RegisterRole(Type roleType, ushort roleId, string modId)
|
||||
{
|
||||
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;
|
||||
@@ -42,7 +51,13 @@ public static class CustomRoleManager
|
||||
return;
|
||||
}
|
||||
|
||||
roleBehaviour.Role = (RoleTypes)customRole.RoleId;
|
||||
if (CustomRoles.ContainsKey(roleId))
|
||||
{
|
||||
Debug.LogError($"Role ID conflict for {customRole.RoleName}. Use a different ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
roleBehaviour.Role = (RoleTypes)roleId;
|
||||
roleBehaviour.TeamType = customRole.Team;
|
||||
roleBehaviour.NameColor = customRole.RoleColor;
|
||||
roleBehaviour.StringName = CustomStringName.CreateAndRegister(customRole.RoleName);
|
||||
@@ -61,7 +76,16 @@ public static class CustomRoleManager
|
||||
RoleManager.GhostRoles.Add(roleBehaviour.Role);
|
||||
}
|
||||
|
||||
CustomRoles.Add(customRole.RoleId, roleBehaviour);
|
||||
if (ModRoles.TryGetValue(info, out List<RoleBehaviour> roles))
|
||||
{
|
||||
roles.Add(roleBehaviour);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModRoles.TryAdd(info, new List<RoleBehaviour>() { roleBehaviour });
|
||||
}
|
||||
|
||||
CustomRoles.Add(roleId, roleBehaviour);
|
||||
|
||||
if (customRole.HideSettings)
|
||||
{
|
||||
@@ -74,6 +98,19 @@ public static class CustomRoleManager
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -123,33 +160,35 @@ public static class CustomRoleManager
|
||||
|
||||
public static void SyncRoleSettings()
|
||||
{
|
||||
foreach (var role in CustomRoles.Values.Select(x => (ICustomRole)x))
|
||||
foreach (var role in CustomRoles.Values)
|
||||
{
|
||||
if (role.HideSettings)
|
||||
ICustomRole customRole = role as ICustomRole;
|
||||
if (customRole.HideSettings)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(role.NumConfigDefinition, out var numEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(role.ChanceConfigDefinition, out var chanceEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(customRole.NumConfigDefinition, out var numEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(customRole.ChanceConfigDefinition, out var chanceEntry);
|
||||
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.Send(new SyncRoleOptionsRpc.Data(role.RoleId, numEntry.Value, chanceEntry.Value));
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.Send(new SyncRoleOptionsRpc.Data((ushort)role.Role, numEntry.Value, chanceEntry.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncRoleSettings(int targetId)
|
||||
{
|
||||
foreach (var role in CustomRoles.Values.Select(x => (ICustomRole)x))
|
||||
foreach (var role in CustomRoles.Values)
|
||||
{
|
||||
if (role.HideSettings)
|
||||
ICustomRole customRole = role as ICustomRole;
|
||||
if (customRole.HideSettings)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(role.NumConfigDefinition, out var numEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(role.ChanceConfigDefinition, out var chanceEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(customRole.NumConfigDefinition, out var numEntry);
|
||||
PluginSingleton<MiraAPIPlugin>.Instance.Config.TryGetEntry<int>(customRole.ChanceConfigDefinition, out var chanceEntry);
|
||||
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.SendTo(targetId, new SyncRoleOptionsRpc.Data(role.RoleId, numEntry.Value, chanceEntry.Value));
|
||||
Rpc<SyncRoleOptionsRpc>.Instance.SendTo(targetId, new SyncRoleOptionsRpc.Data((ushort)role.Role, numEntry.Value, chanceEntry.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ public interface ICustomRole
|
||||
{
|
||||
string RoleName { get; }
|
||||
|
||||
ushort RoleId { get; }
|
||||
|
||||
string RoleDescription { get; }
|
||||
|
||||
string RoleLongDescription { get; }
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -8,6 +10,24 @@ namespace MiraAPI.Roles;
|
||||
public class RegisterCustomRoleAttribute : Attribute
|
||||
{
|
||||
private static readonly HashSet<Assembly> RegisteredAssemblies = [];
|
||||
public ushort RoleId { get; }
|
||||
public string ModId { get; }
|
||||
|
||||
public RegisterCustomRoleAttribute(string modId)
|
||||
{
|
||||
ModId = modId;
|
||||
RoleId = (ushort)(20 + CustomRoleManager.CustomRoles.Count);
|
||||
}
|
||||
public RegisterCustomRoleAttribute(string modId, ushort roleId)
|
||||
{
|
||||
ModId = modId;
|
||||
RoleId = roleId;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, plugin) => Register(assembly);
|
||||
}
|
||||
|
||||
public static void Register(Assembly assembly)
|
||||
{
|
||||
@@ -18,7 +38,8 @@ public class RegisterCustomRoleAttribute : Attribute
|
||||
var attribute = type.GetCustomAttribute<RegisterCustomRoleAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
CustomRoleManager.RegisterRole(type);
|
||||
Helpers.RegisterType(type);
|
||||
CustomRoleManager.RegisterRole(type, attribute.RoleId, attribute.ModId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using MiraAPI.Roles;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.Roles;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
@@ -14,6 +17,24 @@ 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