diff --git a/MiraAPI.Example/GameModes/ExampleMode.cs b/MiraAPI.Example/GameModes/ExampleMode.cs
new file mode 100644
index 0000000..ff8292d
--- /dev/null
+++ b/MiraAPI.Example/GameModes/ExampleMode.cs
@@ -0,0 +1,9 @@
+using MiraAPI.GameModes;
+
+namespace MiraAPI.Example.GameModes;
+
+public class ExampleMode : AbstractGameMode
+{
+ public override string Name => "Example Mode";
+ public override string Description => "An example gamemode.";
+}
diff --git a/MiraAPI/GameModes/AbstractGameMode.cs b/MiraAPI/GameModes/AbstractGameMode.cs
index 3bb80ff..2da08aa 100644
--- a/MiraAPI/GameModes/AbstractGameMode.cs
+++ b/MiraAPI/GameModes/AbstractGameMode.cs
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
+using MiraAPI.GameOptions;
using MiraAPI.PluginLoading;
using UnityEngine;
@@ -9,7 +10,7 @@ namespace MiraAPI.GameModes;
/// Base class for custom gamemodes.
///
[MiraIgnore]
-public abstract class AbstractGameMode
+public abstract class AbstractGameMode : IOptionable
{
///
/// Gets the game mode name.
diff --git a/MiraAPI/GameModes/CustomGameModeManager.cs b/MiraAPI/GameModes/CustomGameModeManager.cs
index 8e531bb..f179944 100644
--- a/MiraAPI/GameModes/CustomGameModeManager.cs
+++ b/MiraAPI/GameModes/CustomGameModeManager.cs
@@ -12,7 +12,7 @@ namespace MiraAPI.GameModes;
///
public static class CustomGameModeManager
{
- private static readonly Dictionary IdToModeMap = [];
+ public static readonly Dictionary IdToModeMap = [];
private static uint GetNextId()
{
diff --git a/MiraAPI/GameModes/GameModeOption.cs b/MiraAPI/GameModes/GameModeOption.cs
index 9c02dc6..83de6ff 100644
--- a/MiraAPI/GameModes/GameModeOption.cs
+++ b/MiraAPI/GameModes/GameModeOption.cs
@@ -6,6 +6,7 @@ namespace MiraAPI.GameModes;
///
/// The game mode option.
///
+// TODO: Replace this with a proper gamemode selection.
public class GameModeOption : AbstractOptionGroup
{
///
diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs
index 7aaa154..8a89500 100644
--- a/MiraAPI/GameOptions/ModdedOptionsManager.cs
+++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection;
using BepInEx.Configuration;
using HarmonyLib;
+using Il2CppInterop.Runtime.Injection;
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
@@ -27,6 +28,29 @@ public static class ModdedOptionsManager
internal static uint NextId => _nextId++;
private static uint _nextId = 1;
+ internal static bool RegisterGroup(Type type)
+ {
+ if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
+ {
+ return false;
+ }
+
+ if (TypeToGroup.ContainsKey(type))
+ {
+ Logger.Error($"Group {type.Name} already exists.");
+ return false;
+ }
+
+ Groups.Add(group);
+ TypeToGroup.Add(type, group);
+
+ typeof(OptionGroupSingleton<>).MakeGenericType(type)
+ .GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
+ .SetValue(null, group);
+
+ return true;
+ }
+
internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo)
{
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
diff --git a/MiraAPI/Patches/GameModes/CreateOptionsPatch.cs b/MiraAPI/Patches/GameModes/CreateOptionsPatch.cs
new file mode 100644
index 0000000..7e8144e
--- /dev/null
+++ b/MiraAPI/Patches/GameModes/CreateOptionsPatch.cs
@@ -0,0 +1,18 @@
+using HarmonyLib;
+
+namespace MiraAPI.Patches.GameModes;
+
+[HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.SetGameMode))]
+internal static class CreateOptionsPatch
+{
+ public static bool Prefix(CreateOptionsPicker __instance, AmongUs.GameOptions.GameModes mode)
+ {
+ if (mode <= AmongUs.GameOptions.GameModes.SeekFools)
+ {
+ return true;
+ }
+
+ // TODO: finish this
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs
index c2e2e61..f636d61 100644
--- a/MiraAPI/PluginLoading/MiraPluginManager.cs
+++ b/MiraAPI/PluginLoading/MiraPluginManager.cs
@@ -6,8 +6,10 @@ using System.Linq;
using System.Reflection;
using BepInEx;
using BepInEx.Unity.IL2CPP;
+using Il2CppInterop.Runtime.Injection;
using MiraAPI.Colors;
using MiraAPI.Events;
+using MiraAPI.GameEnd;
using MiraAPI.GameModes;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
@@ -15,6 +17,7 @@ using MiraAPI.Hud;
using MiraAPI.Modifiers;
using MiraAPI.Roles;
using MiraAPI.Utilities;
+using Reactor.Localization.Utilities;
using Reactor.Networking;
using Reactor.Utilities;
@@ -34,6 +37,7 @@ public sealed class MiraPluginManager
internal void Initialize()
{
Instance = this;
+ ModdedOptionsManager.RegisterGroup(typeof(GameModeOption)); // TODO: dont do this
CustomGameModeManager.RegisterDefaultMode();
CustomGameModeManager.GetAndSetGameMode();
IL2CPPChainloader.Instance.PluginLoad += RegisterPlugin;
@@ -44,6 +48,20 @@ public sealed class MiraPluginManager
{
CustomButtonManager.Buttons = new ReadOnlyCollection(CustomButtonManager.CustomButtons);
};
+ IL2CPPChainloader.Instance.Finished += () =>
+ {
+ var dict = new Dictionary();
+ foreach (var (key, value) in CustomGameModeManager.IdToModeMap)
+ {
+ if (value is DefaultMode)
+ {
+ continue;
+ }
+ dict.Add(value.Name, key);
+ GameModesHelpers.ModeToName.Add((AmongUs.GameOptions.GameModes)key, CustomStringName.CreateAndRegister(value.Name));
+ }
+ EnumInjector.InjectEnumValues(dict);
+ };
}
private void RegisterPlugin(PluginInfo pluginInfo, Assembly assembly, BasePlugin plugin)
@@ -63,57 +81,57 @@ public sealed class MiraPluginManager
continue;
}
- foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
+ foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
+ {
+ var eventAttribute = method.GetCustomAttribute();
+ if (eventAttribute != null)
{
- var eventAttribute = method.GetCustomAttribute();
- if (eventAttribute != null)
+ var parameters = method.GetParameters();
+ if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
{
- var parameters = method.GetParameters();
- if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
- {
- Logger.Error($"Invalid event registration method {method.Name} in {type.Name}");
- continue;
- }
-
- var paramType = parameters[0].ParameterType;
- MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
+ Logger.Error($"Invalid event registration method {method.Name} in {type.Name}");
+ continue;
}
- }
- if (RegisterModifier(type, info))
- {
- continue;
+ var paramType = parameters[0].ParameterType;
+ MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
}
-
- if (RegisterOptions(type, info))
- {
- continue;
- }
-
- if (RegisterRoleAttribute(type, info, out var role))
- {
- roles.Add(role);
- continue;
- }
-
- if (RegisterButtonAttribute(type, info))
- {
- continue;
- }
-
- if (RegisterGameOver(type))
- {
- continue;
- }
-
- if (RegisterGameModeAttribute(type, info))
- {
- continue;
- }
-
- RegisterColorClasses(type);
}
+ if (RegisterModifier(type, info))
+ {
+ continue;
+ }
+
+ if (RegisterOptions(type, info))
+ {
+ continue;
+ }
+
+ if (RegisterRoleAttribute(type, info, out var role))
+ {
+ roles.Add(role);
+ continue;
+ }
+
+ if (RegisterButtonAttribute(type, info))
+ {
+ continue;
+ }
+
+ if (RegisterGameOver(type))
+ {
+ continue;
+ }
+
+ if (RegisterGameModeAttribute(type, info))
+ {
+ continue;
+ }
+
+ RegisterColorClasses(type);
+ }
+
info.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
CustomRoleManager.RegisterRoleTypes(roles, info);
@@ -181,6 +199,7 @@ public sealed class MiraPluginManager
{
Logger.Error($"Failed to register options for {type.Name}: {e}");
}
+
return false;
}
@@ -207,6 +226,7 @@ public sealed class MiraPluginManager
{
Logger.Error($"Failed to register role for {type.Name}: {e}");
}
+
return false;
}