diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index cc1e769..007f0c4 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -15,8 +15,8 @@ namespace MiraAPI.Example; public partial class ExamplePlugin : BasePlugin, IMiraConfig { public Harmony Harmony { get; } = new(Id); - - public ModdedOptionTabSettings TabSettings => new() + public static ExamplePlugin Instance { get; private set; } + public ModdedOptionTabSettings TabSettings => new ModdedOptionTabSettings() { Title = "MiraAPI Example Mod", TabIcon = MiraAssets.Empty @@ -24,6 +24,7 @@ public partial class ExamplePlugin : BasePlugin, IMiraConfig public override void Load() { + Instance = this; Harmony.PatchAll(); } } \ No newline at end of file diff --git a/MiraAPI/GameModes/ActiveMode.cs b/MiraAPI/GameModes/ActiveMode.cs deleted file mode 100644 index d687695..0000000 --- a/MiraAPI/GameModes/ActiveMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace MiraAPI.GameModes; - -public struct ActiveMode -{ - public string PluginId { get; set; } - public int ModeId { get; set; } -} \ No newline at end of file diff --git a/MiraAPI/GameModes/DefaultMode.cs b/MiraAPI/GameModes/DefaultMode.cs index 0993fb6..2e7fcb0 100644 --- a/MiraAPI/GameModes/DefaultMode.cs +++ b/MiraAPI/GameModes/DefaultMode.cs @@ -4,6 +4,6 @@ public class DefaultMode : CustomGameMode { public override string Name => "Default"; - public override string Description => "Default Among Us Game Mode"; + public override string Description => "Default Among Us GameMode"; public override int Id => 0; } \ No newline at end of file diff --git a/MiraAPI/GameOptions/Attributes/ModdedOptionAttribute.cs b/MiraAPI/GameOptions/Attributes/ModdedOptionAttribute.cs index 151ec90..e2379b5 100644 --- a/MiraAPI/GameOptions/Attributes/ModdedOptionAttribute.cs +++ b/MiraAPI/GameOptions/Attributes/ModdedOptionAttribute.cs @@ -19,7 +19,7 @@ namespace MiraAPI.GameOptions.Attributes { foreach (var type in assembly.GetTypes()) { - foreach (var property in type.GetProperties()) + foreach (PropertyInfo property in type.GetProperties()) { foreach (var attribute in property.GetCustomAttributes()) { diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs index 2f6ef31..d8d5dcf 100644 --- a/MiraAPI/GameOptions/ModdedOptionsManager.cs +++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs @@ -18,6 +18,21 @@ namespace MiraAPI.GameOptions private static Dictionary OriginalTypes = new(); public static Dictionary RegisteredMods = new(); + public static void Initialize() + { + 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) { diff --git a/MiraAPI/IMiraConfig.cs b/MiraAPI/IMiraConfig.cs index 5c12a44..3cde9a5 100644 --- a/MiraAPI/IMiraConfig.cs +++ b/MiraAPI/IMiraConfig.cs @@ -1,4 +1,5 @@ -using MiraAPI.Utilities.Assets; +using MiraAPI.Utilities; +using MiraAPI.Utilities.Assets; using UnityEngine; namespace MiraAPI diff --git a/MiraAPI/MiraPluginInfo.cs b/MiraAPI/MiraPluginInfo.cs deleted file mode 100644 index bb739be..0000000 --- a/MiraAPI/MiraPluginInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using MiraAPI.GameModes; -using MiraAPI.GameOptions; -using MiraAPI.Roles; - -namespace MiraAPI; - -public class MiraPluginInfo -{ - public string PluginId { get; set; } - public IMiraConfig Config { get; set; } - - public readonly List OptionGroups = []; - public readonly List Options = []; - - public readonly Dictionary CustomRoles = []; - public readonly Dictionary GameModes = []; - - public MiraPluginInfo(string id, IMiraConfig config) - { - PluginId = id; - Config = config; - } - -} \ No newline at end of file diff --git a/MiraAPI/MiraPluginManager.cs b/MiraAPI/MiraPluginManager.cs deleted file mode 100644 index ba52a7f..0000000 --- a/MiraAPI/MiraPluginManager.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using BepInEx; -using BepInEx.Unity.IL2CPP; -using MiraAPI.GameOptions.Attributes; -using MiraAPI.Roles; -using MiraAPI.Utilities; - -namespace MiraAPI; - -public class MiraPluginManager -{ - public Dictionary RegisteredPlugins = []; - - public void Initialize() - { - IL2CPPChainloader.Instance.PluginLoad += (_, assembly, plugin) => - { - if (!plugin.GetType().GetInterfaces().Contains(typeof(IMiraConfig))) return; - - var id = MetadataHelper.GetMetadata(plugin.GetType()).GUID; - var info = new MiraPluginInfo(id, plugin as IMiraConfig); - - RegisterRoleAttribute(assembly, info); - - ModdedOptionAttribute.Register(assembly); - - RegisteredPlugins.Add(assembly, info); - - }; - } - - private static void RegisterRoleAttribute(Assembly assembly, MiraPluginInfo pluginInfo) - { - foreach (var type in assembly.GetTypes()) - { - var attribute = type.GetCustomAttribute(); - if (attribute == null) continue; - - Helpers.RegisterIl2CppType(type); - var role = CustomRoleManager.RegisterRole(type, attribute.RoleId); - - pluginInfo.CustomRoles.Add((ushort)role.Role, role as ICustomRole); - } - } - - - -} \ No newline at end of file diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs index c0f92e9..8fcf456 100644 --- a/MiraAPI/Patches/HudManagerPatches.cs +++ b/MiraAPI/Patches/HudManagerPatches.cs @@ -6,7 +6,6 @@ using MiraAPI.Patches.Options; using MiraAPI.Roles; using Reactor.Utilities.Extensions; using UnityEngine; -using UnityEngine.Events; namespace MiraAPI.Patches { diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs index b5b66bd..962c551 100644 --- a/MiraAPI/Roles/CustomRoleManager.cs +++ b/MiraAPI/Roles/CustomRoleManager.cs @@ -8,6 +8,7 @@ using Reactor.Utilities; using Reactor.Utilities.Extensions; using System; using System.Collections.Generic; +using System.Linq; using MiraAPI.Networking; using TMPro; using UnityEngine; @@ -17,35 +18,46 @@ namespace MiraAPI.Roles; public static class CustomRoleManager { - public static Dictionary CustomRoles = new(); - - public static int GetNextRoleId(ushort requestedId) - { - while (CustomRoles.ContainsKey(requestedId)) - { - requestedId++; - } + public static readonly Dictionary CustomRoles = []; + public static readonly Dictionary> ModRoles = []; - return requestedId; + public static void RegisterInRoleManager() + { + RoleManager.Instance.AllRoles = RoleManager.Instance.AllRoles.Concat(CustomRoles.Values).ToArray(); } - internal static RoleBehaviour RegisterRole(Type roleType, ushort roleId) + 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))) { - Debug.LogError($"{roleType?.Name} does not inherit from RoleBehaviour or ICustomRole."); - return null; + return; + } + + if (CustomRoles.Any(behaviour => behaviour.GetType() == roleType)) + { + return; } var roleBehaviour = (RoleBehaviour)new GameObject(roleType.Name).DontDestroy().AddComponent(Il2CppType.From(roleType)); if (roleBehaviour is not ICustomRole customRole) { - roleBehaviour.gameObject.Destroy(); - return null; + return; } - roleBehaviour.Role = (RoleTypes)GetNextRoleId(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 == ModdedRoleTeams.Neutral ? RoleTeamTypes.Crewmate : (RoleTeamTypes)customRole.Team; roleBehaviour.NameColor = customRole.RoleColor; roleBehaviour.StringName = CustomStringName.CreateAndRegister(customRole.RoleName); @@ -63,27 +75,48 @@ public static class CustomRoleManager { RoleManager.GhostRoles.Add(roleBehaviour.Role); } - - CustomRoles.Add(roleId, customRole); + + if (ModRoles.TryGetValue(info, out List roles)) + { + roles.Add(roleBehaviour); + } + else + { + ModRoles.TryAdd(info, [roleBehaviour]); + } + + CustomRoles.Add(roleId, roleBehaviour); if (customRole.HideSettings) { - return roleBehaviour; + return; } var config = PluginSingleton.Instance.Config; config.Bind(customRole.NumConfigDefinition, 1); config.Bind(customRole.ChanceConfigDefinition, 100); - return roleBehaviour; } + public static List GetRolesRegistered(string modId) + { + PluginInfo info = ModRoles.Keys.First(key => key.Metadata.GUID == modId); + if (ModRoles.TryGetValue(info, out List 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 != null) + if (temp is ICustomRole role) { - result = temp; + result = role; return true; } diff --git a/MiraAPI/Roles/RegisterCustomRoleAttribute.cs b/MiraAPI/Roles/RegisterCustomRoleAttribute.cs index 87fdc39..0c49aeb 100644 --- a/MiraAPI/Roles/RegisterCustomRoleAttribute.cs +++ b/MiraAPI/Roles/RegisterCustomRoleAttribute.cs @@ -7,11 +7,40 @@ using System.Reflection; namespace MiraAPI.Roles; [AttributeUsage(AttributeTargets.Class)] -public class RegisterCustomRoleAttribute(ushort roleId) : Attribute -{ - public ushort RoleId { get; } = roleId; +public class RegisterCustomRoleAttribute : Attribute +{ + private static readonly HashSet RegisteredAssemblies = []; + public ushort RoleId { get; } + public string ModId { get; } - public RegisterCustomRoleAttribute() : this((ushort)(20 + CustomRoleManager.CustomRoles.Count)) + 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) + { + if (!RegisteredAssemblies.Add(assembly)) return; + + foreach (var type in assembly.GetTypes()) + { + var attribute = type.GetCustomAttribute(); + if (attribute != null) + { + Helpers.RegisterType(type); + CustomRoleManager.RegisterRole(type, attribute.RoleId, attribute.ModId); + } + } } } \ No newline at end of file diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index ceee3b1..5cef351 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -17,7 +17,7 @@ namespace MiraAPI.Utilities return ShipStatus.Instance.AllRooms.ToList().Find(room => room.roomArea.OverlapPoint(pos)); } - public static void RegisterIl2CppType(Type type) + public static void RegisterType(Type type) { if (ClassInjector.IsTypeRegisteredInIl2Cpp(type)) {