diff --git a/EHR.csproj b/EHR.csproj
index 29e2dc7a6..e0b11f510 100644
--- a/EHR.csproj
+++ b/EHR.csproj
@@ -5,7 +5,8 @@
- netstandard2.1
+ net6.0
+ netstandard2.1
false
false
false
@@ -16,9 +17,11 @@
true
True
$(MSBuildProjectName)
- Debug;Release;Android
+ Debug;Release;IL2CPP
AnyCPU
https://github.com/Gurge44/EndlessHostRoles
+
+
true
true
true
@@ -34,17 +37,21 @@
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
+
+
@@ -67,7 +74,7 @@
-
+
diff --git a/EHR.sln b/EHR.sln
index 35482ff23..b831d1b54 100644
--- a/EHR.sln
+++ b/EHR.sln
@@ -14,15 +14,15 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
- Android|Any CPU = Android|Any CPU
+ IL2CPP|Any CPU = IL2CPP|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{807AD310-21DA-4160-9D72-926745B02A85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{807AD310-21DA-4160-9D72-926745B02A85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{807AD310-21DA-4160-9D72-926745B02A85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{807AD310-21DA-4160-9D72-926745B02A85}.Release|Any CPU.Build.0 = Release|Any CPU
- {807AD310-21DA-4160-9D72-926745B02A85}.Android|Any CPU.ActiveCfg = Android|Any CPU
- {807AD310-21DA-4160-9D72-926745B02A85}.Android|Any CPU.Build.0 = Android|Any CPU
+ {807AD310-21DA-4160-9D72-926745B02A85}.IL2CPP|Any CPU.ActiveCfg = IL2CPP|Any CPU
+ {807AD310-21DA-4160-9D72-926745B02A85}.IL2CPP|Any CPU.Build.0 = IL2CPP|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Main.cs b/Main.cs
index 16a983636..cbc527175 100644
--- a/Main.cs
+++ b/Main.cs
@@ -8,7 +8,6 @@ using System.Linq;
using System.Reflection;
using AmongUs.GameOptions;
using BepInEx;
-using BepInEx.Bootstrap;
using BepInEx.Configuration;
using EHR;
using EHR.Modules;
@@ -18,6 +17,15 @@ using HarmonyLib;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP;
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+using Il2CppInterop.Runtime.Injection;
+#else
+using BepInEx.Bootstrap;
+#endif
+
+// ReSharper disable RedundantNameQualifier
[assembly: AssemblyFileVersion(Main.PluginVersion)]
[assembly: AssemblyInformationalVersion(Main.PluginVersion)]
@@ -34,7 +42,7 @@ namespace EHR;
[BepInDependency(SubmergedCompatibility.SubmergedGuid, BepInDependency.DependencyFlags.SoftDependency)]
[BepInProcess("Among Us.exe")]
[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
-public class Main : BaseUnityPlugin
+public class Main : BasePlugin
{
private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d";
private const string DebugKeySalt = "59687b";
@@ -187,7 +195,12 @@ public class Main : BaseUnityPlugin
// ReSharper disable once StringLiteralTypo
private static readonly List NameSnacksEn = ["Ice cream", "Milk tea", "Chocolate", "Cake", "Donut", "Coke", "Lemonade", "Candied haws", "Jelly", "Candy", "Milk", "Matcha", "Burning Grass Jelly", "Pineapple Bun", "Pudding", "Coconut Jelly", "Cookies", "Red Bean Toast", "Three Color Dumplings", "Wormwood Dumplings", "Puffs", "Can be Crepe", "Peach Crisp", "Mochi", "Egg Waffle", "Macaron", "Snow Plum Niang", "Fried Yogurt", "Egg Tart", "Muffin", "Sago Dew", "panna cotta", "soufflé", "croissant", "toffee"];
+#if IL2CPP
+ private Coroutines coroutines;
+ public static bool HasReactorPlugin => IL2CPPChainloader.Instance.Plugins.ContainsKey("gg.reactor.api");
+#else
public static bool HasReactorPlugin => Chainloader.PluginInfos.ContainsKey("gg.reactor.api");
+#endif
private static HashAuth DebugKeyAuth { get; set; }
private static ConfigEntry DebugKeyInput { get; set; }
@@ -349,7 +362,11 @@ public class Main : BaseUnityPlugin
public static bool LIMap => NormalOptions is { MapId: 7 };
+#if IL2CPP
+ public override void Load()
+#else
private void Awake()
+#endif
{
// EmbeddedDeps.Install();
Instance = this;
@@ -386,7 +403,16 @@ public class Main : BaseUnityPlugin
ShowClientControlGUI = Config.Bind("Client Options", "ShowClientControlGUI", true);
UIScaleFactor = Config.Bind("Client Options", "UIScaleFactor", 1f);
+#if IL2CPP
+ ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
+ coroutines = AddComponent();
+ AddComponent();
+#else
gameObject.AddComponent();
+#endif
//Logger = BepInEx.Logging.Logger.CreateLogSource("EHR");
EHR.Logger.Enable();
@@ -985,6 +1011,10 @@ public class Main : BaseUnityPlugin
[CustomGameMode.DoomTag] = Utils.GetRoleColor(CustomRoles.Tagger)
};
+#if IL2CPP
+ IL2CPPChainloader.Instance.Finished += Start;
+#endif
+
try
{
if (TryFixStuttering.Value && OperatingSystem.IsWindows() && Environment.ProcessorCount >= 4)
@@ -1035,7 +1065,11 @@ public class Main : BaseUnityPlugin
private static void HandleRoleColorFiles()
{
+#if IL2CPP
+ string serialized = System.Text.Json.JsonSerializer.Serialize(RoleHtmlColors, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
+#else
string serialized = JsonConvert.SerializeObject(RoleHtmlColors, Formatting.Indented);
+#endif
File.WriteAllText($"{DataPath}/OriginalRoleColors.json", serialized);
if (!Directory.Exists($"{DataPath}/EHR_DATA"))
@@ -1091,6 +1125,37 @@ public class Main : BaseUnityPlugin
catch (Exception e) { Utils.ThrowException(e); }
}
+#if IL2CPP
+ public Coroutine StartCoroutine(Il2CppSystem.Collections.IEnumerator coroutine)
+ {
+ if (coroutine == null) return null;
+ return coroutines.StartCoroutine(coroutine);
+ }
+
+ public Coroutine StartCoroutine(IEnumerator coroutine)
+ {
+ if (coroutine == null) return null;
+ return coroutines.StartCoroutine(coroutine.WrapToIl2Cpp());
+ }
+
+ public void StopCoroutine(IEnumerator coroutine)
+ {
+ if (coroutine == null) return;
+ coroutines.StopCoroutine(coroutine.WrapToIl2Cpp());
+ }
+
+ public void StopCoroutine(Coroutine coroutine)
+ {
+ if (coroutine == null) return;
+ coroutines.StopCoroutine(coroutine);
+ }
+
+ public void StopAllCoroutines()
+ {
+ coroutines.StopAllCoroutines();
+ }
+#endif
+
public static IEnumerator GetRandomWord(Action onComplete, string langParam = "", int length = 0, int difficulty = 0)
{
var api = new StringBuilder("https://random-word-api.herokuapp.com/word");
diff --git a/Modules/Achievements.cs b/Modules/Achievements.cs
index f4dd1370d..9b34caef7 100644
--- a/Modules/Achievements.cs
+++ b/Modules/Achievements.cs
@@ -213,7 +213,11 @@ public static class Achievements
private static void SaveAllData()
{
+#if IL2CPP
+ string json = System.Text.Json.JsonSerializer.Serialize(CompletedAchievements);
+#else
string json = JsonConvert.SerializeObject(CompletedAchievements);
+#endif
File.WriteAllText(SaveFilePath, json);
if (!Options.StoreCompletedAchievementsOnEHRDatabase.GetBool()) return;
@@ -232,7 +236,11 @@ public static class Achievements
achievements = CompletedAchievements
};
+#if IL2CPP
+ string payload = System.Text.Json.JsonSerializer.Serialize(data);
+#else
string payload = JsonConvert.SerializeObject(data);
+#endif
var request = new UnityWebRequest(ApiSaveEndpoint, UnityWebRequest.kHttpVerbPOST)
{
diff --git a/Modules/ClientControlGUI.cs b/Modules/ClientControlGUI.cs
index 962953c00..fc4d5108f 100644
--- a/Modules/ClientControlGUI.cs
+++ b/Modules/ClientControlGUI.cs
@@ -104,13 +104,21 @@ public class ClientControlGUI : MonoBehaviour
{
_cam = Camera.main;
Instance = this;
+#if IL2CPP
+ SceneManager.add_sceneLoaded((Action)OnSceneLoaded);
+#else
SceneManager.sceneLoaded += OnSceneLoaded;
+#endif
Logger.Info("ClientControlGUI initialised", "ClientControlGUI");
}
private void OnDestroy()
{
+#if IL2CPP
+ SceneManager.remove_sceneLoaded((Action)OnSceneLoaded);
+#else
SceneManager.sceneLoaded -= OnSceneLoaded;
+#endif
}
// Resets HUD visibility flag on scene change; HudManager is recreated each load so its new instance is always active
diff --git a/Modules/CustomRpcSender.cs b/Modules/CustomRpcSender.cs
index 748602c3e..7b72ab337 100644
--- a/Modules/CustomRpcSender.cs
+++ b/Modules/CustomRpcSender.cs
@@ -484,7 +484,7 @@ public class CustomRpcSender
{
return Write(w => w.Write(val));
}
-
+/*
public CustomRpcSender Write(byte[] bytes)
{
return Write(w => w.Write(bytes));
@@ -499,7 +499,7 @@ public class CustomRpcSender
{
return Write(w => w.WriteBytesAndSize(bytes));
}
-
+*/
public CustomRpcSender WritePacked(int val)
{
return Write(w => w.WritePacked(val));
@@ -891,54 +891,8 @@ public static class CustomRpcSenderExtensions
public bool SyncSettings(PlayerControl player)
{
- if (GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
- {
- player.SyncSettings();
- return false;
- }
-
- var optionsender = GameOptionsSender.AllSenders.OfType().FirstOrDefault(x => x.player.PlayerId == player.PlayerId);
- if (optionsender == null) return false;
-
- var options = optionsender.BuildGameOptions();
-
- if (player.AmOwner)
- {
- foreach (GameLogicComponent com in GameManager.Instance.LogicComponents)
- {
- if (com is LogicOptions lo)
- lo.SetGameOptions(options);
- }
-
- GameOptionsManager.Instance.CurrentGameOptions = options;
- return false;
- }
-
- var logicOptions = GameManager.Instance.LogicOptions;
- var id = GameManager.Instance.LogicComponents.IndexOf(logicOptions);
-
- if (sender.CurrentState == CustomRpcSender.State.InRootMessage) sender.EndMessage();
-
- var writer = sender.stream;
-
- writer.StartMessage(6);
- {
- writer.Write(AmongUsClient.Instance.GameId);
- writer.WritePacked(player.OwnerId);
- writer.StartMessage(1);
- {
- writer.WritePacked(GameManager.Instance.NetId);
- writer.StartMessage((byte)id);
- {
- writer.WriteBytesAndSize(logicOptions.gameOptionsFactory.ToBytes(options, AprilFoolsMode.IsAprilFoolsModeToggledOn));
- }
- writer.EndMessage();
- }
- writer.EndMessage();
- }
- writer.EndMessage();
-
- return true;
+ player.SyncSettings();
+ return false;
}
public bool SyncGeneralOptions(PlayerControl player)
diff --git a/Modules/CustomSabotage.cs b/Modules/CustomSabotage.cs
index 238e65ec4..8c4588891 100644
--- a/Modules/CustomSabotage.cs
+++ b/Modules/CustomSabotage.cs
@@ -20,7 +20,11 @@ public abstract class CustomSabotage
protected virtual void Fix()
{
Instances.Remove(this);
+#if IL2CPP
+ (ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast()).IsDirty = true;
+#else
(ShipStatus.Instance.Systems[SystemTypes.Sabotage] as SabotageSystemType)?.IsDirty = true;
+#endif
}
protected virtual string GetSuffix(PlayerControl seer, PlayerControl target, bool hud, bool meeting)
@@ -91,8 +95,14 @@ public abstract class CustomSabotage
catch (Exception e) { Utils.ThrowException(e); }
}
+#if IL2CPP
+ if (Instances.Count > 0)
+ {
+ SabotageSystemType sabotageSystemType = ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast();
+#else
if (Instances.Count > 0 && ShipStatus.Instance.Systems[SystemTypes.Sabotage] is SabotageSystemType sabotageSystemType)
{
+#endif
sabotageSystemType.Timer = SabotageSystemTypeUpdateSystemPatch.IsCooldownModificationEnabled
? SabotageSystemTypeUpdateSystemPatch.ModifiedCooldownSec
: 30f;
diff --git a/Modules/Debugger.cs b/Modules/Debugger.cs
index cdfc722f8..c0125a886 100644
--- a/Modules/Debugger.cs
+++ b/Modules/Debugger.cs
@@ -64,7 +64,11 @@ internal static class Logger
LobbyNotificationMessage newMessage = Object.Instantiate(np.notificationMessageOrigin, Vector3.zero, Quaternion.identity, np.transform);
newMessage.transform.localPosition = new(0f, 0f, -2f);
text = "" + text + "";
+#if IL2CPP
+ newMessage.SetUp(text, np.settingsChangeSprite, textColor ?? np.settingsChangeColor, (Action)(() => np.OnMessageDestroy(newMessage)));
+#else
newMessage.SetUp(text, np.settingsChangeSprite, textColor ?? np.settingsChangeColor, () => np.OnMessageDestroy(newMessage));
+#endif
np.ShiftMessages();
np.AddMessageToQueue(newMessage);
diff --git a/Modules/DisableDevice.cs b/Modules/DisableDevice.cs
index b4a51a64a..c20ac1fcc 100644
--- a/Modules/DisableDevice.cs
+++ b/Modules/DisableDevice.cs
@@ -214,8 +214,8 @@ public class RemoveDisableDevicesPatch
Options.DisableDevicesIgnoreAfterAnyoneDied.GetBool() && GameStates.AlreadyDied;
ignore &= !rogueForce;
- MapConsole[] admins = Object.FindObjectsOfType(true);
- SystemConsole[] consoles = Object.FindObjectsOfType(true);
+ var admins = Object.FindObjectsOfType(true);
+ var consoles = Object.FindObjectsOfType(true);
if (admins == null || consoles == null) return;
switch (Main.NormalOptions.MapId)
diff --git a/Modules/EAC.cs b/Modules/EAC.cs
index 92e334818..2c04ed575 100644
--- a/Modules/EAC.cs
+++ b/Modules/EAC.cs
@@ -5,6 +5,9 @@ using System.Diagnostics;
using System.Linq;
using AmongUs.GameOptions;
using AmongUs.QuickChat;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+#endif
using HarmonyLib;
using Hazel;
using InnerNet;
@@ -1259,12 +1262,26 @@ internal static class GameDataHandlerPatch
return !OperatingSystem.IsAndroid();
}
+#if IL2CPP
+ private static Il2CppSystem.Collections.IEnumerator EmptyCoroutine()
+ {
+ return DummyCoroutine().WrapToIl2Cpp();
+ }
+
+ private static IEnumerator DummyCoroutine()
+ {
+ yield break;
+ }
+
+ public static bool Prefix(InnerNetClient __instance, MessageReader reader, int msgNum, ref Il2CppSystem.Collections.IEnumerator __result)
+#else
private static IEnumerator EmptyCoroutine() // fixes errors if we return false
{
yield break;
}
public static bool Prefix(InnerNetClient __instance, MessageReader reader, int msgNum, ref IEnumerator __result)
+#endif
{
var tag = (GameDataTag)reader.Tag;
diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs
index 137da441e..a36990d90 100644
--- a/Modules/ExtendedPlayerControl.cs
+++ b/Modules/ExtendedPlayerControl.cs
@@ -8,13 +8,16 @@ using AmongUs.GameOptions;
using EHR.Gamemodes;
using EHR.Modules;
using EHR.Modules.Extensions;
-using EHR.Modules.MonoHelpers;
using EHR.Roles;
using Hazel;
using InnerNet;
using UnityEngine;
using static EHR.Translator;
using static EHR.Utils;
+#if IL2CPP
+using Il2CppInterop.Runtime;
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
+#endif
namespace EHR;
@@ -338,8 +341,11 @@ internal static class ExtendedPlayerControl
public void RpcResetTasks(bool init = true)
{
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !player) return;
-
+#if IL2CPP
+ player.Data.RpcSetTasks(new Il2CppStructArray(0));
+#else
player.Data.RpcSetTasks([]);
+#endif
if (init) Main.PlayerStates[player.PlayerId].InitTask(player);
}
@@ -1345,6 +1351,14 @@ internal static class ExtendedPlayerControl
Logger.Warn($"{nullReferenceException.Message} - player is null? {!player}", "GetRealName");
return string.Empty;
}
+#if IL2CPP
+ catch (Il2CppException il2CppException)
+ {
+ Logger.Warn($"{il2CppException.Message} - player is null? {!player}", "GetRealName");
+ Logger.Warn($"{il2CppException.Message} - player is null? {!player}", "GetRealName");
+ return string.Empty;
+ }
+#endif
catch (Exception exception)
{
ThrowException(exception);
@@ -2146,7 +2160,7 @@ internal static class ExtendedPlayerControl
public List GetPlayersInAbilityRangeSorted(Predicate predicate, bool ignoreColliders = false)
{
- List rangePlayersIL = RoleBehaviour.GetTempPlayerList();
+ var rangePlayersIL = RoleBehaviour.GetTempPlayerList();
List rangePlayers = [];
player.Data.Role.GetPlayersInAbilityRangeSorted(rangePlayersIL, ignoreColliders);
diff --git a/Modules/Extensions/ObjectHelper.cs b/Modules/Extensions/ObjectHelper.cs
index 05c873cd9..ebc5f681e 100644
--- a/Modules/Extensions/ObjectHelper.cs
+++ b/Modules/Extensions/ObjectHelper.cs
@@ -8,7 +8,11 @@ public static class ObjectHelper
{
if (!obj) return;
+#if IL2CPP
+ obj.ForEachChild((Il2CppSystem.Action)(x => x.DestroyTranslator()));
+#else
obj.ForEachChild(x => x.DestroyTranslator());
+#endif
TextTranslatorTMP[] translator = obj.GetComponentsInChildren(true);
translator?.Do(Object.Destroy);
}
diff --git a/Modules/GameOptionsSender/GameOptionsSender.cs b/Modules/GameOptionsSender/GameOptionsSender.cs
index b903f640b..f45173d59 100644
--- a/Modules/GameOptionsSender/GameOptionsSender.cs
+++ b/Modules/GameOptionsSender/GameOptionsSender.cs
@@ -22,9 +22,15 @@ public abstract class GameOptionsSender
writer.StartMessage(0);
writer.Write((byte)currentGameMode);
+#if IL2CPP
+ if (opt.TryCastFast(out NormalGameOptionsV11 normalOpt))
+ NormalGameOptionsV11.Serialize(writer, normalOpt);
+ else if (opt.TryCastFast(out HideNSeekGameOptionsV11 hnsOpt))
+#else
if (opt is NormalGameOptionsV11 normalOpt)
NormalGameOptionsV11.Serialize(writer, normalOpt);
else if (opt is HideNSeekGameOptionsV11 hnsOpt)
+#endif
HideNSeekGameOptionsV11.Serialize(writer, hnsOpt);
else
Logger.Error("Option cast failed", ToString());
diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs
index 49de9860e..cab2da8e8 100644
--- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs
+++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs
@@ -18,7 +18,11 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
public PlayerControl player = player;
private static IGameOptions BasedGameOptions =>
+#if IL2CPP
+ Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger().CastFast()).CastFast());
+#else
Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger()));
+#endif
protected override bool IsDirty { get; set; }
diff --git a/Patches/SillyIl2CppCrashFixPatches.cs b/Modules/Il2CppHelpers/ButtonClickCrashFix.cs
similarity index 58%
rename from Patches/SillyIl2CppCrashFixPatches.cs
rename to Modules/Il2CppHelpers/ButtonClickCrashFix.cs
index 6aa935c9f..df05c36c7 100644
--- a/Patches/SillyIl2CppCrashFixPatches.cs
+++ b/Modules/Il2CppHelpers/ButtonClickCrashFix.cs
@@ -1,20 +1,29 @@
-using HarmonyLib;
+using System;
+using HarmonyLib;
namespace EHR.Patches;
// By https://github.com/TouseefX
[HarmonyPatch]
-internal static class SillyIl2CppCrashFixPatches
+internal static class ButtonClickCrashFix
{
[HarmonyPatch(typeof(PassiveButton), nameof(PassiveButton.ReceiveClickDown)), HarmonyPrefix]
public static bool ReceiveClickDownPrefix(PassiveButton __instance)
{
- return __instance != null;
+ return __instance != null
+#if IL2CPP
+ && __instance.Pointer != IntPtr.Zero
+#endif
+ ;
}
[HarmonyPatch(typeof(PassiveButton), nameof(PassiveButton.ReceiveClickUp)), HarmonyPrefix]
public static bool ReceiveClickUpPrefix(PassiveButton __instance)
{
- return __instance != null;
+ return __instance != null
+#if IL2CPP
+ && __instance.Pointer != IntPtr.Zero
+#endif
+ ;
}
}
\ No newline at end of file
diff --git a/Modules/Il2CppHelpers/CastHelper.cs b/Modules/Il2CppHelpers/CastHelper.cs
new file mode 100644
index 000000000..93943e201
--- /dev/null
+++ b/Modules/Il2CppHelpers/CastHelper.cs
@@ -0,0 +1,55 @@
+#if IL2CPP
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+using Il2CppInterop.Runtime.InteropTypes;
+
+namespace EHR;
+
+public static class Il2CppCastHelper
+{
+ public static T CastFast(this Il2CppObjectBase obj) where T : Il2CppObjectBase
+ {
+ if (obj is T casted) return casted;
+ return OperatingSystem.IsAndroid() ? obj.Cast() : obj.Pointer.CastFast();
+ }
+
+ private static T CastFast(this IntPtr ptr) where T : Il2CppObjectBase
+ {
+ return CastHelper.Cast(ptr);
+ }
+
+ private static class CastHelper where T : Il2CppObjectBase
+ {
+ public static readonly Func Cast;
+
+ static CastHelper()
+ {
+ ConstructorInfo constructor = typeof(T).GetConstructor([typeof(IntPtr)]);
+ ParameterExpression ptr = Expression.Parameter(typeof(IntPtr));
+ NewExpression create = Expression.New(constructor!, ptr);
+ Expression> lambda = Expression.Lambda>(create, ptr);
+ Cast = lambda.Compile();
+ }
+ }
+
+ public static bool TryCastFast(this Il2CppObjectBase obj, out T casted) where T : Il2CppObjectBase
+ {
+ switch (obj)
+ {
+ case T t:
+ casted = t;
+ return true;
+ case null:
+ casted = null;
+ return false;
+ default:
+ casted = OperatingSystem.IsAndroid()
+ ? obj.Cast()
+ : obj.Pointer.CastFast();
+
+ return casted != null;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Modules/Il2CppHelpers/UnityActionDelegateFix.cs b/Modules/Il2CppHelpers/UnityActionDelegateFix.cs
new file mode 100644
index 000000000..6968e5b30
--- /dev/null
+++ b/Modules/Il2CppHelpers/UnityActionDelegateFix.cs
@@ -0,0 +1,15 @@
+#if IL2CPP
+using System;
+using UnityEngine.Events;
+using UnityEngine.UI;
+
+namespace EHR;
+
+public static class UnityActionDelegateFix
+{
+ public static void AddListener(this UnityEvent e, Action listener)
+ {
+ e.AddListener(listener);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Modules/ModCompatibility/LevelImposterCompatibility.cs b/Modules/ModCompatibility/LevelImposterCompatibility.cs
index 20f53d9da..b8d3b5d48 100644
--- a/Modules/ModCompatibility/LevelImposterCompatibility.cs
+++ b/Modules/ModCompatibility/LevelImposterCompatibility.cs
@@ -4,9 +4,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BepInEx;
-using BepInEx.Bootstrap;
using HarmonyLib;
using UnityEngine;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP;
+#else
+using BepInEx.Bootstrap;
+#endif
namespace EHR.Modules;
@@ -176,7 +180,11 @@ public static class LevelImposterCompatibility
if (_initialized) return;
_initialized = true;
+#if IL2CPP
+ if (!IL2CPPChainloader.Instance.Plugins.TryGetValue(LevelImposterGuid, out PluginInfo plugin))
+#else
if (!Chainloader.PluginInfos.TryGetValue(LevelImposterGuid, out PluginInfo plugin))
+#endif
{
Logger.Info("[LI] Not found, skipping", "LI");
return;
diff --git a/Modules/ModCompatibility/SubmergedCompatibility.cs b/Modules/ModCompatibility/SubmergedCompatibility.cs
index aa05d929e..5f9f85682 100644
--- a/Modules/ModCompatibility/SubmergedCompatibility.cs
+++ b/Modules/ModCompatibility/SubmergedCompatibility.cs
@@ -4,9 +4,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BepInEx;
-using BepInEx.Bootstrap;
using EHR.Patches;
using HarmonyLib;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP;
+#else
+using BepInEx.Bootstrap;
+#endif
+
namespace EHR;
@@ -26,7 +31,11 @@ public static class SubmergedCompatibility
// public static SemanticVersioning.Version Version { get; private set; }
public static bool Loaded { get; set; }
+#if IL2CPP
+ private static BasePlugin Plugin { get; set; }
+#else
private static BaseUnityPlugin Plugin { get; set; }
+#endif
private static Assembly Assembly { get; set; }
private static Type[] Types { get; set; }
// public static Dictionary InjectedTypes { get; private set; }
@@ -97,10 +106,18 @@ public static class SubmergedCompatibility
public static void Initialize()
{
+#if IL2CPP
+ Loaded = IL2CPPChainloader.Instance.Plugins.TryGetValue(SubmergedGuid, out PluginInfo plugin);
+#else
Loaded = Chainloader.PluginInfos.TryGetValue(SubmergedGuid, out PluginInfo plugin);
+#endif
if (!Loaded) return;
+#if IL2CPP
+ Plugin = plugin!.Instance as BasePlugin;
+#else
Plugin = plugin!.Instance;
+#endif
// Version = plugin.Metadata.Version;
Assembly = Plugin!.GetType().Assembly;
diff --git a/Modules/ModUpdater.cs b/Modules/ModUpdater.cs
index 7a7bd66c5..fbbdbb2dd 100644
--- a/Modules/ModUpdater.cs
+++ b/Modules/ModUpdater.cs
@@ -70,7 +70,7 @@ public static class ModUpdater
const string url = URLGithub + "/releases/latest";
- using UnityWebRequest request = UnityWebRequest.Get(url);
+ UnityWebRequest request = UnityWebRequest.Get(url);
request.SetRequestHeader("User-Agent", "EHR Updater");
request.downloadHandler = new DownloadHandlerBuffer();
@@ -227,9 +227,13 @@ public static class ModUpdater
}
catch (Exception e) { Utils.ThrowException(e); }
- using UnityWebRequest request = UnityWebRequest.Get(url);
+ UnityWebRequest request = UnityWebRequest.Get(url);
request.SetRequestHeader("User-Agent", "EHR Updater");
+#if IL2CPP
+ request.downloadHandler = new DownloadHandlerBuffer();
+#else
request.downloadHandler = new DownloadHandlerFile(SavePath);
+#endif
yield return request.SendWebRequest();
try
@@ -240,6 +244,10 @@ public static class ModUpdater
UpdateFailed();
yield break;
}
+
+#if IL2CPP
+ File.WriteAllBytes(SavePath, request.downloadHandler.data);
+#endif
if (!File.Exists(SavePath))
{
diff --git a/Modules/MonoHelpers/CustomNetworkTransformHelper.cs b/Modules/MonoHelpers/CustomNetworkTransformHelper.cs
index b7fc691e2..0a1bcbb3d 100644
--- a/Modules/MonoHelpers/CustomNetworkTransformHelper.cs
+++ b/Modules/MonoHelpers/CustomNetworkTransformHelper.cs
@@ -1,7 +1,7 @@
using HarmonyLib;
using Hazel;
-namespace EHR.Modules.MonoHelpers;
+namespace EHR;
// There is no efficient way to get the last element of a Queue.
// So instead we keep track of the most recent incoming network transform data manually.
diff --git a/Modules/OnlinePresetsManager.cs b/Modules/OnlinePresetsManager.cs
index c00445425..408e73d3a 100644
--- a/Modules/OnlinePresetsManager.cs
+++ b/Modules/OnlinePresetsManager.cs
@@ -51,7 +51,11 @@ public static class OnlinePresetsManager
Object.Destroy(upload.transform.Find("ValueBox").gameObject);
Object.Destroy(upload.PlusBtn.gameObject);
+#if IL2CPP
+ upload.OnValueChanged = (Il2CppSystem.Action)(menu.ValueChanged);
+#else
upload.OnValueChanged = menu.ValueChanged;
+#endif
upload.MinusBtn.OnClick = new();
upload.MinusBtn.OnClick.AddListener(() => Main.Instance.StartCoroutine(UploadCurrentPreset()));
TextMeshPro text = upload.MinusBtn.GetComponentInChildren();
@@ -96,7 +100,11 @@ public static class OnlinePresetsManager
Object.Destroy(row.transform.Find("Value_TMP (1)").gameObject);
Object.Destroy(row.transform.Find("ValueBox").gameObject);
+#if IL2CPP
+ row.OnValueChanged = (Il2CppSystem.Action)(menu.ValueChanged);
+#else
row.OnValueChanged = menu.ValueChanged;
+#endif
row.LabelBackground.transform.localScale += new Vector3(1f, 0f, 0f);
row.TitleText.GetComponent().sizeDelta = new(5.7f, 0.37f);
@@ -188,7 +196,11 @@ public static class OnlinePresetsManager
preset = preset
};
+#if IL2CPP
+ string json = System.Text.Json.JsonSerializer.Serialize(body);
+#else
string json = JsonConvert.SerializeObject(body);
+#endif
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs
index 9eecb632b..69528d36e 100644
--- a/Modules/OptionHolder.cs
+++ b/Modules/OptionHolder.cs
@@ -1207,7 +1207,11 @@ public static class Options
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
+#if IL2CPP
+ File.WriteAllText(path + "/friendcode#1234.txt", System.Text.Json.JsonSerializer.Serialize(new UserData { Tag = string.Empty }, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
+#else
File.WriteAllText(path + "/friendcode#1234.txt", JsonConvert.SerializeObject(new UserData { Tag = string.Empty }, Formatting.Indented));
+#endif
}
Errors.Clear();
diff --git a/Modules/OptionSaver.cs b/Modules/OptionSaver.cs
index 9b2b2e4b3..01b22a029 100644
--- a/Modules/OptionSaver.cs
+++ b/Modules/OptionSaver.cs
@@ -93,7 +93,11 @@ public static class OptionSaver
{
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost) return;
+#if IL2CPP
+ string jsonString = System.Text.Json.JsonSerializer.Serialize(GenerateOptionsData(), new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
+#else
string jsonString = JsonConvert.SerializeObject(GenerateOptionsData(), Formatting.Indented);
+#endif
File.WriteAllText(OptionSaverFileInfo.FullName, jsonString);
File.WriteAllText(DefaultPresetFileInfo.FullName, DefaultPresetNumber.ToString());
}
diff --git a/Modules/StateMachineWrapper.cs b/Modules/StateMachineWrapper.cs
index 1c47afd30..fb11faab3 100644
--- a/Modules/StateMachineWrapper.cs
+++ b/Modules/StateMachineWrapper.cs
@@ -14,21 +14,25 @@ namespace EHR.Modules;
/// The type of the parent class that owns the state machine.
public class StateMachineWrapper : CompilerGeneratedObjectWrapper
{
+#if IL2CPP
// normally it is fields, but IL2CPP turns them into properties
private readonly PropertyInfo _thisProperty;
private readonly PropertyInfo _stateProperty;
-
+#else
private readonly FieldInfo _stateField;
private readonly FieldInfo _thisField;
-
- private readonly bool _mono;
+#endif
private T? _parentInstance;
///
/// Gets the instance of the parent class that owns the state machine.
///
- public T Instance => _parentInstance ??= (T) (_mono ? _thisField.GetValue(GeneratedObject)! : _thisProperty.GetValue(GeneratedObject)!);
+#if IL2CPP
+ public T Instance => _parentInstance ??= (T) (_thisProperty.GetValue(GeneratedObject)!);
+#else
+ public T Instance => _parentInstance ??= (T) (_thisField.GetValue(GeneratedObject)!);
+#endif
///
/// Gets or sets the current state of the state machine.
@@ -36,14 +40,13 @@ public class StateMachineWrapper : CompilerGeneratedObjectWrapper
/// The current state as an integer.
public int State
{
- get => _mono ? (int) _stateField.GetValue(GeneratedObject)! : (int) _stateProperty.GetValue(GeneratedObject)!;
- set
- {
- if (_mono)
- _stateField.SetValue(GeneratedObject, value);
- else
- _stateProperty.SetValue(GeneratedObject, value);
- }
+#if IL2CPP
+ get => (int) _stateProperty.GetValue(GeneratedObject)!;
+ set => _stateProperty.SetValue(GeneratedObject, value);
+#else
+ get => (int) _stateField.GetValue(GeneratedObject)!;
+ set => _stateField.SetValue(GeneratedObject, value);
+#endif
}
///
@@ -52,15 +55,13 @@ public class StateMachineWrapper : CompilerGeneratedObjectWrapper
/// The state machine instance to wrap.
public StateMachineWrapper(object stateMachine) : base(stateMachine)
{
+#if IL2CPP
_thisProperty = AccessTools.Property(GeneratedType, "__4__this");
_stateProperty = AccessTools.Property(GeneratedType, "__1__state");
-
- if (_thisProperty == null || _stateProperty == null)
- {
- _mono = true;
- _thisField = AccessTools.Field(GeneratedType, "<>4__this");
- _stateField = AccessTools.Field(GeneratedType, "<>1__state");
- }
+#else
+ _thisField = AccessTools.Field(GeneratedType, "<>4__this");
+ _stateField = AccessTools.Field(GeneratedType, "<>1__state");
+#endif
}
///
diff --git a/Modules/Translator.cs b/Modules/Translator.cs
index e5c2be129..11fa70358 100644
--- a/Modules/Translator.cs
+++ b/Modules/Translator.cs
@@ -6,8 +6,11 @@ using System.Linq;
using System.Reflection;
using System.Text;
using EHR.Gamemodes;
-using Newtonsoft.Json;
+#if IL2CPP
+using System.Text.Json;
+#else
using Newtonsoft.Json.Linq;
+#endif
namespace EHR;
@@ -25,7 +28,9 @@ public static class Translator
Logger.Info("Loaded Custom Translations", "Translator");
}
+#if !IL2CPP
private static readonly JsonSerializer JsonSerializer = new();
+#endif
public static void LoadLangs()
{
@@ -52,19 +57,27 @@ public static class Translator
try
{
+#if IL2CPP
+ var jsonDictionary = JsonSerializer.Deserialize>(resourceStream);
+#else
using var reader = new StreamReader(resourceStream);
using var jsonReader = new JsonTextReader(reader);
var jsonDictionary = JsonSerializer.Deserialize>(jsonReader);
+#endif
if (jsonDictionary == null)
{
- Logger.Warn( $"Failed to deserialize JSON file: {jsonFileName}. Is it a valid jsonc?", "Translator");
+ Logger.Warn($"Failed to deserialize JSON file: {jsonFileName}. Is it a valid jsonc?", "Translator");
continue;
}
+#if IL2CPP
+ if (!jsonDictionary.TryGetValue("LanguageID", out var langElem) || langElem.ValueKind != JsonValueKind.String || !int.TryParse(langElem.GetString(), out int languageId))
+#else
if (!jsonDictionary.TryGetValue("LanguageID", out var langElem) || langElem.Type != JTokenType.String || !int.TryParse(langElem.Value(), out int languageId))
+#endif
{
- Logger.Warn( $"Invalid JSON format in {jsonFileName}: Missing or invalid 'LanguageID' field.", "Translator");
+ Logger.Warn($"Invalid JSON format in {jsonFileName}: Missing or invalid 'LanguageID' field.", "Translator");
continue;
}
@@ -102,6 +115,31 @@ public static class Translator
}
}
+#if IL2CPP
+ private static void MergeJsonIntoTranslationMap(Dictionary> translationMaps, int languageId, Dictionary jsonDictionary)
+ {
+ foreach ((string key, JsonElement value) in jsonDictionary)
+ {
+ if (value.ValueKind != JsonValueKind.String)
+ {
+ Logger.Warn($"Invalid value type for key '{key}' in language ID {languageId}. Expected a string.", "Translator");
+ continue;
+ }
+
+ string translation = value.GetString();
+ if (string.IsNullOrEmpty(translation))
+ continue;
+
+ if (!translationMaps.TryGetValue(key, out var langMap))
+ {
+ langMap = [];
+ translationMaps[key] = langMap;
+ }
+
+ langMap[languageId] = translation.Replace("\\n", "\n").Replace("\\r", "\r");
+ }
+ }
+#else
private static void MergeJsonIntoTranslationMap(Dictionary> translationMaps, int languageId, Dictionary jsonDictionary)
{
foreach ((string key, JToken value) in jsonDictionary)
@@ -125,6 +163,7 @@ public static class Translator
langMap[languageId] = translation.Replace("\\n", "\n").Replace("\\r", "\r");
}
}
+#endif
// Function to get a list of JSON file names in a directory
private static string[] GetJsonFileNames(Assembly assembly, string directoryName)
diff --git a/Modules/Utils.cs b/Modules/Utils.cs
index 0cda32203..abf507e0f 100644
--- a/Modules/Utils.cs
+++ b/Modules/Utils.cs
@@ -407,7 +407,11 @@ public static class Utils
});
});
+#if IL2CPP
+ File.WriteAllText(path, System.Text.Json.JsonSerializer.Serialize(data, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
+#else
File.WriteAllText(path, JsonConvert.SerializeObject(data, Formatting.Indented));
+#endif
}
catch (Exception e)
{
@@ -4841,11 +4845,19 @@ public static class Utils
obj.name = "FlashColor_FullScreen";
}
+#if IL2CPP
+ hud.StartCoroutine(Effects.Lerp(duration, (Il2CppSystem.Action)(t =>
+ {
+ obj.SetActive(Math.Abs(t - 1f) > 0.1f);
+ obj.GetComponent().color = new(color.r, color.g, color.b, Mathf.Clamp01((-2f * Mathf.Abs(t - 0.5f) + 1) * color.a / 2));
+ })));
+#else
hud.StartCoroutine(Effects.Lerp(duration, t =>
{
obj.SetActive(Math.Abs(t - 1f) > 0.1f);
obj.GetComponent().color = new(color.r, color.g, color.b, Mathf.Clamp01((-2f * Mathf.Abs(t - 0.5f) + 1) * color.a / 2));
}));
+#endif
}
public static Sprite LoadSprite(string path, float pixelsPerUnit = 1f)
diff --git a/Patches/AirShipElectricalDoors.cs b/Patches/AirShipElectricalDoors.cs
index cd1e77968..00eed8c8f 100644
--- a/Patches/AirShipElectricalDoors.cs
+++ b/Patches/AirShipElectricalDoors.cs
@@ -5,7 +5,11 @@ namespace EHR;
public static class AirshipElectricalDoors
{
+#if IL2CPP
+ private static ElectricalDoors Instance => ShipStatus.Instance.Systems[SystemTypes.Decontamination].CastFast();
+#else
private static ElectricalDoors Instance => ShipStatus.Instance.Systems[SystemTypes.Decontamination] as ElectricalDoors;
+#endif
public static void Initialize()
{
@@ -16,11 +20,12 @@ public static class AirshipElectricalDoors
public static IEnumerable GetClosedDoors()
{
List doorsArray = [];
- if (Instance.Doors == null || Instance.Doors.Length == 0) return doorsArray;
+ ElectricalDoors electricalDoors = Instance;
+ if (electricalDoors.Doors == null || electricalDoors.Doors.Length == 0) return doorsArray;
- for (byte i = 0; i < Instance.Doors.Length; i++)
+ for (byte i = 0; i < electricalDoors.Doors.Length; i++)
{
- StaticDoor door = Instance.Doors[i];
+ StaticDoor door = electricalDoors.Doors[i];
if (door != null && !door.IsOpen) doorsArray.Add(i);
}
diff --git a/Patches/AnnouncementPatch.cs b/Patches/AnnouncementPatch.cs
index 096b07f04..403222cff 100644
--- a/Patches/AnnouncementPatch.cs
+++ b/Patches/AnnouncementPatch.cs
@@ -9,6 +9,10 @@ using HarmonyLib;
using Newtonsoft.Json;
using UnityEngine.Networking;
+#if IL2CPP
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
+#endif
+
namespace EHR;
// ReSharper disable once ClassNeverInstantiated.Global
@@ -88,7 +92,11 @@ public static class ModNewsHistory
[HarmonyPatch(typeof(PlayerAnnouncementData), nameof(PlayerAnnouncementData.SetAnnouncements))]
[HarmonyPrefix]
+#if IL2CPP
+ public static void SetModAnnouncements(ref Il2CppReferenceArray aRange)
+#else
public static void SetModAnnouncements(ref Announcement[] aRange)
+#endif
{
if (AllModNews.Count == 0)
{
@@ -100,9 +108,6 @@ public static class ModNewsHistory
finalAllNews.AddRange(aRange.Where(news => AllModNews.All(x => x.Number != news.Number)));
finalAllNews.Sort((a1, a2) => DateTime.Compare(DateTime.Parse(a2.Date), DateTime.Parse(a1.Date)));
- aRange = new Announcement[finalAllNews.Count];
-
- for (var i = 0; i < finalAllNews.Count; i++)
- aRange[i] = finalAllNews[i];
+ aRange = finalAllNews.ToArray();
}
}
\ No newline at end of file
diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs
index d42999e72..fff29bc69 100644
--- a/Patches/ChatCommandPatch.cs
+++ b/Patches/ChatCommandPatch.cs
@@ -658,7 +658,11 @@ internal static class ChatCommands
if (Main.CurrentMap == MapNames.Dleks || Main.NormalOptions.MapId == 6)
{
+#if IL2CPP
+ IGameOptions opt = Main.NormalOptions.CastFast();
+#else
IGameOptions opt = Main.NormalOptions;
+#endif
Options.DefaultKillCooldown = Main.NormalOptions.KillCooldown;
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
diff --git a/Patches/CheckGameEndPatch.cs b/Patches/CheckGameEndPatch.cs
index 546d15d2f..13a7aebde 100644
--- a/Patches/CheckGameEndPatch.cs
+++ b/Patches/CheckGameEndPatch.cs
@@ -3,6 +3,9 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+#endif
using EHR.Gamemodes;
using EHR.Modules;
using EHR.Roles;
@@ -395,7 +398,11 @@ internal static class GameEndChecker
SetEverythingUpPatch.LastWinsReason = WinnerTeam is CustomWinner.Crewmate or CustomWinner.Impostor ? GetString($"GameOverReason.{reason}") : string.Empty;
var self = AmongUsClient.Instance;
+#if IL2CPP
+ self.StartCoroutine(CoEndGame(self, reason).WrapToIl2Cpp());
+#else
self.StartCoroutine(CoEndGame(self, reason));
+#endif
}
private static IEnumerator CoEndGame(InnerNetClient self, GameOverReason reason)
@@ -1476,7 +1483,7 @@ internal static class GameEndChecker
if (ShipStatus.Instance.Systems == null) return false;
// TryGetValue is not available
- Dictionary systems = ShipStatus.Instance.Systems;
+ var systems = ShipStatus.Instance.Systems;
LifeSuppSystemType lifeSupp;
if (systems.ContainsKey(SystemTypes.LifeSupp) && // Confirmation of sabotage existence
diff --git a/Patches/ClientOptionsPatch.cs b/Patches/ClientOptionsPatch.cs
index 998dbbe35..45655f50b 100644
--- a/Patches/ClientOptionsPatch.cs
+++ b/Patches/ClientOptionsPatch.cs
@@ -129,7 +129,11 @@ public static class OptionsMenuBehaviourStartPatch
MainMenuManagerPatch.ShowRightPanelImmediately();
Main.Instance.Harmony.UnpatchSelf();
+#if IL2CPP
+ Main.Instance.Unload();
+#else
Object.Destroy(Main.Instance.gameObject);
+#endif
}
}
}
@@ -272,7 +276,11 @@ public static class OptionsMenuBehaviourStartPatch
switch (Main.ShowClientControlGUI.Value)
{
case true when !ClientControlGUI.Instance:
+#if IL2CPP
+ Main.Instance.AddComponent();
+#else
Main.Instance.gameObject.AddComponent();
+#endif
break;
case false when ClientControlGUI.Instance:
Object.Destroy(ClientControlGUI.Instance);
diff --git a/Patches/Crowded.cs b/Patches/Crowded.cs
index 8afa3d8df..ac5b7104b 100644
--- a/Patches/Crowded.cs
+++ b/Patches/Crowded.cs
@@ -277,16 +277,6 @@ internal static class Crowded
}
}
- [HarmonyPatch(typeof(SecurityLogger), nameof(SecurityLogger.Awake))]
- public static class SecurityLoggerPatch
- {
- [SuppressMessage("ReSharper", "UnusedMember.Global")]
- public static void Postfix(ref SecurityLogger __instance)
- {
- __instance.Timers = new float[127];
- }
- }
-
[HarmonyPatch(typeof(PlayerTab), nameof(PlayerTab.UpdateAvailableColors))]
public static class PlayerTabUpdateAvailableColorsPatch
{
diff --git a/Patches/DleksPatch.cs b/Patches/DleksPatch.cs
index f047a10ce..4e3d1f5e1 100644
--- a/Patches/DleksPatch.cs
+++ b/Patches/DleksPatch.cs
@@ -10,7 +10,11 @@ internal static class AllMapIconsPatch
{
private static void EnsureMapIcon(GameStartManager instance, MapNames map, string spritePath, float pixelsPerUnit)
{
+#if IL2CPP
+ if (instance.AllMapIcons.TrueForAll((Il2CppSystem.Predicate)(x => x.Name != map)))
+#else
if (instance.AllMapIcons.TrueForAll(x => x.Name != map))
+#endif
{
instance.AllMapIcons.Insert((int)map, new MapIconByName
{
diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs
index 0b16b9332..f984535ad 100644
--- a/Patches/GameOptionsMenuPatch.cs
+++ b/Patches/GameOptionsMenuPatch.cs
@@ -1,7 +1,12 @@
using System;
using System.Collections;
-using System.Collections.Generic;
using System.Linq;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+using Il2CppSystem.Collections.Generic;
+#else
+using System.Collections.Generic;
+#endif
using EHR.Gamemodes;
using EHR.Modules;
using EHR.Patches;
@@ -12,6 +17,7 @@ using UnityEngine;
using Priority = HarmonyLib.Priority;
// ReSharper disable PossibleLossOfFraction
+// ReSharper disable RedundantNameQualifier
namespace EHR;
// Credit: https://github.com/Yumenopai/TownOfHost_Y
@@ -22,8 +28,8 @@ public static class ModGameOptionsMenu
public static readonly Dictionary OptionList = new();
public static readonly Dictionary BehaviourList = new();
public static readonly Dictionary CategoryHeaderList = new();
- public static readonly Dictionary HelpIconList = [];
- public static readonly Dictionary BaseGameSettingCache = [];
+ public static readonly System.Collections.Generic.Dictionary HelpIconList = [];
+ public static readonly System.Collections.Generic.Dictionary BaseGameSettingCache = [];
public static T Track(T obj) where T : Object
{
@@ -144,7 +150,11 @@ public static class GameOptionsMenuPatch
currentGen++;
BuildGenerations[__instance] = currentGen;
+#if IL2CPP
+ BuildCoroutines[__instance] = __instance.StartCoroutine(CoRoutine(currentGen).WrapToIl2Cpp());
+#else
BuildCoroutines[__instance] = __instance.StartCoroutine(CoRoutine(currentGen));
+#endif
return false;
IEnumerator CoRoutine(int gen)
@@ -232,7 +242,11 @@ public static class GameOptionsMenuPatch
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
optionBehaviour.SetUpFromData(baseGameSetting, 20);
optionBehaviour.gameObject.SetActive(enabledOrNotCollapsed);
+#if IL2CPP
+ optionBehaviour.OnValueChanged = (Il2CppSystem.Action)__instance.ValueChanged;
+#else
optionBehaviour.OnValueChanged = __instance.ValueChanged;
+#endif
ModGameOptionsMenu.OptionList[optionBehaviour] = index;
ModGameOptionsMenu.BehaviourList[index] = optionBehaviour;
@@ -916,7 +930,11 @@ public static class StringOptionPatch
long now = Utils.TimeStamp;
bool startCoRoutine = now > HelpShowEndTS;
HelpShowEndTS = now + 15;
+#if IL2CPP
+ if (startCoRoutine) GameSettingMenu.Instance.StartCoroutine(CoRoutine().WrapToIl2Cpp());
+#else
if (startCoRoutine) GameSettingMenu.Instance.StartCoroutine(CoRoutine());
+#endif
IEnumerator CoRoutine()
{
@@ -1059,7 +1077,7 @@ public static class StringOptionPatch
[HarmonyPatch(typeof(GameSettingMenu))]
public static class GameSettingMenuPatch
{
- public static readonly Dictionary GMButtons = [];
+ public static readonly System.Collections.Generic.Dictionary GMButtons = [];
private static readonly Vector3 ButtonPositionLeft = new(-3.9f, -0.55f, 0f);
private static readonly Vector3 ButtonPositionRight = new(-2.4f, -0.55f, 0f);
@@ -1069,14 +1087,14 @@ public static class GameSettingMenuPatch
private static GameOptionsMenu TemplateGameOptionsMenu;
private static PassiveButton TemplateGameSettingsButton;
- public static readonly Dictionary ModSettingsButtons = [];
- public static readonly Dictionary ModSettingsTabs = [];
+ public static readonly System.Collections.Generic.Dictionary ModSettingsButtons = [];
+ public static readonly System.Collections.Generic.Dictionary ModSettingsTabs = [];
public static long LastPresetChange;
public static bool ChangingPreset;
public static FreeChatInputField InputField;
- private static List HiddenBySearch = [];
+ private static System.Collections.Generic.List HiddenBySearch = [];
public static Action SearchForOptionsAction;
private static int NumImpsOnOpen = 1;
@@ -1157,7 +1175,7 @@ public static class GameSettingMenuPatch
SetupExtendedUI(__instance);
}
- private static readonly Dictionary ExtraObjectsCache = [];
+ private static readonly System.Collections.Generic.Dictionary ExtraObjectsCache = [];
private static Coroutine KeepSearchBarDarkThemedCoroutine;
// Thanks: Drakos for the preset button and search bar code (https://github.com/0xDrMoe/TownofHost-Enhanced/pull/1115)
@@ -1430,9 +1448,9 @@ public static class GameSettingMenuPatch
string text = textField.textArea.text.Trim().ToLower();
var modTab = (TabGroup)(ModGameOptionsMenu.TabIndex - 3);
OptionItem[] optionItems = Options.GroupedOptions[modTab];
- List result = optionItems.Where(x => x.Parent == null && !x.IsCurrentlyHidden() && !Translator.GetString($"{x.Name}").Contains(text, StringComparison.OrdinalIgnoreCase)).ToList();
+ var result = optionItems.Where(x => x.Parent == null && !x.IsCurrentlyHidden() && !Translator.GetString($"{x.Name}").Contains(text, StringComparison.OrdinalIgnoreCase)).ToList();
HiddenBySearch = result;
- List searchWinners = optionItems.Where(x => x.Parent == null && !x.IsCurrentlyHidden() && !result.Contains(x)).ToList();
+ var searchWinners = optionItems.Where(x => x.Parent == null && !x.IsCurrentlyHidden() && !result.Contains(x)).ToList();
if (searchWinners.Count == 0 || !ModSettingsTabs.TryGetValue(modTab, out GameOptionsMenu gameSettings) || !gameSettings)
{
@@ -1545,6 +1563,9 @@ public static class GameSettingMenuPatch
if (ModSettingsTabs.TryGetValue(tabGroup, out settingsTab) && settingsTab)
OnlinePresetsManager.CreatePresetExplorerUI(settingsTab);
})
+#if IL2CPP
+ .WrapToIl2Cpp()
+#endif
);
}
diff --git a/Patches/GameOptionsPatch.cs b/Patches/GameOptionsPatch.cs
index c83ec2403..8cc1d8585 100644
--- a/Patches/GameOptionsPatch.cs
+++ b/Patches/GameOptionsPatch.cs
@@ -34,6 +34,10 @@ internal static class SwitchGameModePatch
Zoom.SetZoomSize(reset: true);
Main.Instance.Harmony.UnpatchSelf();
+#if IL2CPP
+ Main.Instance.Unload();
+#else
Object.Destroy(Main.Instance.gameObject);
+#endif
}
}
\ No newline at end of file
diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs
index 7ed2e8e37..4fc810604 100644
--- a/Patches/GameStartManagerPatch.cs
+++ b/Patches/GameStartManagerPatch.cs
@@ -113,7 +113,11 @@ public static class GameStartManagerPatch
if (Main.NormalOptions.KillCooldown == 0f) Main.NormalOptions.KillCooldown = Main.LastKillCooldown.Value;
+#if IL2CPP
+ AURoleOptions.SetOpt(Main.NormalOptions.CastFast());
+#else
AURoleOptions.SetOpt(Main.NormalOptions);
+#endif
if (AURoleOptions.ShapeshifterCooldown == 0f) AURoleOptions.ShapeshifterCooldown = Main.LastShapeshifterCooldown.Value;
AURoleOptions.ProtectionDurationSeconds = 0f;
@@ -257,7 +261,11 @@ public static class GameStartManagerPatch
if (Main.CurrentMap == MapNames.Dleks || Main.NormalOptions.MapId == 6)
{
+#if IL2CPP
+ IGameOptions opt = Main.NormalOptions.CastFast();
+#else
IGameOptions opt = Main.NormalOptions;
+#endif
Options.DefaultKillCooldown = Main.NormalOptions.KillCooldown;
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
@@ -600,7 +608,11 @@ public static class GameStartRandomMap
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
}
+#if IL2CPP
+ IGameOptions opt = Main.NormalOptions.CastFast();
+#else
IGameOptions opt = Main.NormalOptions;
+#endif
AURoleOptions.SetOpt(opt);
if (__instance.startState == GameStartManager.StartingStates.Countdown)
diff --git a/Patches/HandshakePatch.cs b/Patches/HandshakePatch.cs
index 2446a0468..b3b140475 100644
--- a/Patches/HandshakePatch.cs
+++ b/Patches/HandshakePatch.cs
@@ -1,6 +1,8 @@
+#if IL2CPP
using System;
using HarmonyLib;
using Hazel;
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
using InnerNet;
namespace EHR.Patches;
@@ -62,7 +64,7 @@ public enum ReactorProtocolVersion : byte
Latest = V3
}
-//[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.GetConnectionData))]
+[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.GetConnectionData))]
public static class HandshakePatch
{
private const ulong MAGIC = 0x72656163746f72; // "reactor" in ascii, 7 bytes
@@ -75,7 +77,7 @@ public static class HandshakePatch
useDtlsLayout = AmongUsClient.Instance.useDtls;
}
- public static void Postfix(ref byte[] __result)
+ public static void Postfix(ref Il2CppStructArray __result)
{
if (!Main.HasReactorPlugin && !ServerManager.Instance.CurrentRegion.PingServer.Contains("among.us"))
{
@@ -96,6 +98,8 @@ public static class HandshakePatch
handshake.Write((ushort)(ModFlags.RequireOnHost | ModFlags.DisableServerAuthority));
__result = handshake.ToByteArray(true);
+ handshake.Recycle();
}
}
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs
index 9200dbe65..1b36ce834 100644
--- a/Patches/HudPatch.cs
+++ b/Patches/HudPatch.cs
@@ -944,8 +944,13 @@ internal static class MapRoomDoorsStartPatch
ShipStatus shipStatusInstance = ShipStatus.Instance;
if (!shipStatusInstance || !shipStatusInstance.Systems.TryGetValue(SystemTypes.Doors, out ISystemType ISystem)) return;
+#if IL2CPP
+ MapRoomDoorsUpdatePatch.DoorsSystemType = ISystem.CastFast();
+ MapRoomDoorsUpdatePatch.AutoDoorsSystemType = ISystem.CastFast();
+#else
MapRoomDoorsUpdatePatch.DoorsSystemType = ISystem as DoorsSystemType;
MapRoomDoorsUpdatePatch.AutoDoorsSystemType = ISystem as AutoDoorsSystemType;
+#endif
MapRoomDoorsUpdatePatch.AutoOpenDoors.Clear();
foreach (OpenableDoor door in shipStatusInstance.AllDoors)
diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs
index 3ca4aefe3..5a0fc2445 100644
--- a/Patches/IntroPatch.cs
+++ b/Patches/IntroPatch.cs
@@ -84,9 +84,16 @@ static class CoShowIntroPatch
yield return CoBegin(Object.Instantiate(__instance.IntroPrefab, __instance.transform));
PlayerControl.LocalPlayer.SetKillTimer(10f);
+#if IL2CPP
+ (ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast()).SetInitialSabotageCooldown();
+
+ if (ShipStatus.Instance.Systems.TryGetValue(SystemTypes.Doors, out ISystemType systemType) && systemType.TryCastFast(out IDoorSystem doorSystem))
+#else
(ShipStatus.Instance.Systems[SystemTypes.Sabotage] as SabotageSystemType)?.SetInitialSabotageCooldown();
-
+
if (ShipStatus.Instance.Systems.TryGetValue(SystemTypes.Doors, out ISystemType systemType) && systemType is IDoorSystem doorSystem)
+#endif
+
doorSystem.SetInitialSabotageCooldown();
yield return ShipStatus.Instance.PrespawnStep();
@@ -115,12 +122,16 @@ static class CoShowIntroPatch
introCutscene.ImpostorName.gameObject.SetActive(false);
introCutscene.ImpostorTitle.gameObject.SetActive(false);
+#if IL2CPP
+ Il2CppSystem.Collections.Generic.List show = IntroCutscene.SelectTeamToShow((Il2CppSystem.Func)(pcd => !PlayerControl.LocalPlayer.Data.Role.IsImpostor || pcd.Role.TeamType == PlayerControl.LocalPlayer.Data.Role.TeamType));
+#else
List show = IntroCutscene.SelectTeamToShow(pcd => !PlayerControl.LocalPlayer.Data.Role.IsImpostor || pcd.Role.TeamType == PlayerControl.LocalPlayer.Data.Role.TeamType);
+#endif
if (show == null || show.Count < 1)
{
Logger.Error("IntroCutscene :: CoBegin() :: teamToShow is EMPTY or NULL", "BASE GAME LOGGER");
- show = new List(1);
+ show = new(1);
show.Add(PlayerControl.LocalPlayer);
}
@@ -451,7 +462,11 @@ internal static class SetUpRoleTextPatch
[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.BeginCrewmate))]
internal static class BeginCrewmatePatch
{
+#if IL2CPP
+ public static bool Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List teamToDisplay)
+#else
public static bool Prefix(IntroCutscene __instance, ref List teamToDisplay)
+#endif
{
CustomRoles role = PlayerControl.LocalPlayer.GetCustomRole();
@@ -529,7 +544,11 @@ internal static class BeginCrewmatePatch
return true;
}
+#if IL2CPP
+ public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List teamToDisplay)
+#else
public static void Postfix(IntroCutscene __instance, ref List teamToDisplay)
+#endif
{
CustomRoles role = PlayerControl.LocalPlayer.GetCustomRole();
@@ -1055,14 +1074,22 @@ internal static class BeginCrewmatePatch
private static AudioClip GetIntroSound(RoleTypes roleType)
{
+#if IL2CPP
+ return RoleManager.Instance.AllRoles.Find((Il2CppSystem.Predicate)(role => role.Role == roleType))?.IntroSound;
+#else
return RoleManager.Instance.AllRoles.Find(role => role.Role == roleType)?.IntroSound;
+#endif
}
}
[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.BeginImpostor))]
internal static class BeginImpostorPatch
{
+#if IL2CPP
+ public static bool Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List yourTeam)
+#else
public static bool Prefix(IntroCutscene __instance, ref List yourTeam)
+#endif
{
CustomRoles role = PlayerControl.LocalPlayer.GetCustomRole();
@@ -1139,7 +1166,11 @@ internal static class BeginImpostorPatch
return true;
}
+#if IL2CPP
+ public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List yourTeam)
+#else
public static void Postfix(IntroCutscene __instance, ref List yourTeam)
+#endif
{
BeginCrewmatePatch.Postfix(__instance, ref yourTeam);
}
diff --git a/Patches/LobbyPatch.cs b/Patches/LobbyPatch.cs
index 08fdd0a6e..deb0dbc65 100644
--- a/Patches/LobbyPatch.cs
+++ b/Patches/LobbyPatch.cs
@@ -1,7 +1,12 @@
-using System;
+#if IL2CPP
+using Il2CppSystem;
+#else
+using System;
+#endif
using HarmonyLib;
using TMPro;
using UnityEngine;
+// ReSharper disable RedundantNameQualifier
namespace EHR;
@@ -44,7 +49,7 @@ public static class LobbyFixedUpdatePatch
RightEngineSR.color = Color.cyan;
}
}
- catch (Exception e) { Utils.ThrowException(e); }
+ catch (System.Exception e) { Utils.ThrowException(e); }
}
}
@@ -86,7 +91,11 @@ internal static class LobbyBehaviourUpdatePatch
public static void Postfix(LobbyBehaviour __instance)
{
// ReSharper disable once ConvertToLocalFunction
+#if IL2CPP
+ Lobbybgm = (Predicate)(x => x.Name.Equals("MapTheme"));
+#else
Lobbybgm = x => x.Name.Equals("MapTheme");
+#endif
MapThemeSound = SoundManager.Instance.soundPlayers.Find(Lobbybgm);
if (!Main.LobbyMusic.Value)
diff --git a/Patches/LobbyViewSettingsPanePatch.cs b/Patches/LobbyViewSettingsPanePatch.cs
index 26ba92757..f2b3fcf9f 100644
--- a/Patches/LobbyViewSettingsPanePatch.cs
+++ b/Patches/LobbyViewSettingsPanePatch.cs
@@ -2,6 +2,9 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+#endif
using EHR.Roles;
using HarmonyLib;
using TMPro;
@@ -45,7 +48,11 @@ public static class LobbyViewSettingsPanePatch
[HarmonyPostfix]
public static void Awake_Postfix(LobbyViewSettingsPane __instance)
{
+#if IL2CPP
+ __instance.StartCoroutine(CoAwakeViwer().WrapToIl2Cpp());
+#else
__instance.StartCoroutine(CoAwakeViwer());
+#endif
return;
IEnumerator CoAwakeViwer()
@@ -603,7 +610,11 @@ public static class LobbyViewSettingsPanePatch
ShowOnlyEnabledRolesButton.gameObject.SetActive(false);
if (OptionsCoroutine != null) viewSettings.StopCoroutine(OptionsCoroutine);
+#if IL2CPP
+ OptionsCoroutine = viewSettings.StartCoroutine(CoDrawOptions().WrapToIl2Cpp());
+#else
OptionsCoroutine = viewSettings.StartCoroutine(CoDrawOptions());
+#endif
return;
IEnumerator CoDrawOptions()
@@ -774,7 +785,11 @@ public static class LobbyViewSettingsPanePatch
}
if (RoleListCoroutine != null) viewSettings.StopCoroutine(RoleListCoroutine);
+#if IL2CPP
+ RoleListCoroutine = viewSettings.StartCoroutine(CoDrawRoleList().WrapToIl2Cpp());
+#else
RoleListCoroutine = viewSettings.StartCoroutine(CoDrawRoleList());
+#endif
return;
IEnumerator CoDrawRoleList()
diff --git a/Patches/MainMenuManagerPatch.cs b/Patches/MainMenuManagerPatch.cs
index f47143bad..567633750 100644
--- a/Patches/MainMenuManagerPatch.cs
+++ b/Patches/MainMenuManagerPatch.cs
@@ -1,9 +1,13 @@
using System;
-using BepInEx.Bootstrap;
using HarmonyLib;
using TMPro;
using UnityEngine;
using Priority = HarmonyLib.Priority;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP;
+#else
+using BepInEx.Bootstrap;
+#endif
namespace EHR;
@@ -174,7 +178,11 @@ public static class MainMenuManagerPatch
foreach (string buttonName in new[] { "SettingsButton", "Inventory Button", "CreditsButton", "ExitGameButton" })
{
+#if IL2CPP
+ if (buttonName == "Inventory Button" && IL2CPPChainloader.Instance.Plugins.ContainsKey("com.DigiWorm.LevelImposter")) continue;
+#else
if (buttonName == "Inventory Button" && Chainloader.PluginInfos.ContainsKey("com.DigiWorm.LevelImposter")) continue;
+#endif
var go = GameObject.Find(buttonName);
if (!go) continue;
var buttonText = go.GetComponentInChildren();
diff --git a/Patches/MapPickerMenuPatch.cs b/Patches/MapPickerMenuPatch.cs
index ad5d40571..2208c48b4 100644
--- a/Patches/MapPickerMenuPatch.cs
+++ b/Patches/MapPickerMenuPatch.cs
@@ -23,7 +23,11 @@ public static class GameOptionsMapPickerPatch
[HarmonyPrefix]
public static void Postfix_Prefix(GameOptionsMapPicker __instance)
{
+#if IL2CPP
+ if (__instance.AllMapIcons.TrueForAll((Il2CppSystem.Predicate)(x => x.Name != MapNames.Dleks)))
+#else
if (__instance.AllMapIcons.TrueForAll(x => x.Name != MapNames.Dleks))
+#endif
{
__instance.AllMapIcons.Insert((int)MapNames.Dleks, new MapIconByName
{
@@ -35,7 +39,11 @@ public static class GameOptionsMapPickerPatch
}
if (SubmergedCompatibility.Loaded)
{
+#if IL2CPP
+ if (__instance.AllMapIcons.TrueForAll((Il2CppSystem.Predicate)(x => x.Name != (MapNames)6)))
+#else
if (__instance.AllMapIcons.TrueForAll(x => x.Name != (MapNames)6))
+#endif
{
__instance.AllMapIcons.Insert((int)(MapNames)6, new MapIconByName
{
diff --git a/Patches/NotificationPopperPatch.cs b/Patches/NotificationPopperPatch.cs
index d5e3b55be..a3efcc057 100644
--- a/Patches/NotificationPopperPatch.cs
+++ b/Patches/NotificationPopperPatch.cs
@@ -52,7 +52,11 @@ internal static class NotificationPopperPatch
Instance.lastMessageKey = option.Id;
LobbyNotificationMessage newMessage = Object.Instantiate(Instance.notificationMessageOrigin, Vector3.zero, Quaternion.identity, Instance.transform);
newMessage.transform.localPosition = new(0f, 0f, -2f);
+#if IL2CPP
+ newMessage.SetUp(item, Instance.settingsChangeSprite, Instance.settingsChangeColor, (System.Action)(() => Instance.OnMessageDestroy(newMessage)));
+#else
newMessage.SetUp(item, Instance.settingsChangeSprite, Instance.settingsChangeColor, () => Instance.OnMessageDestroy(newMessage));
+#endif
Instance.ShiftMessages();
Instance.AddMessageToQueue(newMessage);
}
diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs
index 6437d2989..eff01cdf3 100644
--- a/Patches/OnGameStartedPatch.cs
+++ b/Patches/OnGameStartedPatch.cs
@@ -3,6 +3,9 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+#endif
using EHR.Gamemodes;
using EHR.Modules;
using EHR.Patches;
@@ -412,10 +415,17 @@ internal static class StartGameHostPatch
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CoStartGameHost))]
[HarmonyPrefix]
+#if IL2CPP
+ public static bool CoStartGameHost_Prefix(AmongUsClient __instance, ref Il2CppSystem.Collections.IEnumerator __result)
+ {
+ AUClient = __instance;
+ __result = StartGameHost().WrapToIl2Cpp();
+#else
public static bool CoStartGameHost_Prefix(AmongUsClient __instance, ref IEnumerator __result)
{
AUClient = __instance;
__result = StartGameHost();
+#endif
return false;
}
diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs
index 597cc7a95..46b2ffbf7 100644
--- a/Patches/OutroPatch.cs
+++ b/Patches/OutroPatch.cs
@@ -2,6 +2,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+#if IL2CPP
+using BepInEx.Unity.IL2CPP.Utils.Collections;
+#endif
using EHR.Gamemodes;
using EHR.Modules;
using EHR.Roles;
@@ -664,7 +667,11 @@ internal static class SetEverythingUpPatch
roleSummaryObjects.Add(lineText);
yield return null;
+#if IL2CPP
+ __instance.StartCoroutine(SlideAndFadeIn(lineRect, lineText, i * 0.15f).WrapToIl2Cpp()); // stagger animation
+#else
__instance.StartCoroutine(SlideAndFadeIn(lineRect, lineText, i * 0.15f)); // stagger animation
+#endif
continue;
static IEnumerator SlideAndFadeIn(RectTransform rect, TextMeshPro text, float delay)
@@ -725,7 +732,7 @@ internal static class SetEverythingUpPatch
try
{
- PoolablePlayer[] pbs = __instance.transform.GetComponentsInChildren();
+ var pbs = __instance.transform.GetComponentsInChildren();
if (pbs != null)
{
diff --git a/Patches/PhantomRolePatch.cs b/Patches/PhantomRolePatch.cs
index 09a3cc71d..c878f4fb2 100644
--- a/Patches/PhantomRolePatch.cs
+++ b/Patches/PhantomRolePatch.cs
@@ -112,7 +112,11 @@ public static class PhantomRoleUseAbilityPatch
{
bool RoleEffectAnimation(RoleEffectAnimation x) => x.effectType == global::RoleEffectAnimation.EffectType.Vanish_Charge;
+#if IL2CPP
+ if (!__instance.Player.currentRoleAnimations.Find((Il2CppSystem.Predicate)RoleEffectAnimation) && !__instance.Player.walkingToVent && !__instance.Player.inMovingPlat)
+#else
if (!__instance.Player.currentRoleAnimations.Find(RoleEffectAnimation) && !__instance.Player.walkingToVent && !__instance.Player.inMovingPlat)
+#endif
{
if (__instance.isInvisible)
{
diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs
index dadbfe5dc..3311dd590 100644
--- a/Patches/PlayerControlPatch.cs
+++ b/Patches/PlayerControlPatch.cs
@@ -2429,14 +2429,22 @@ internal static class GameDataCompleteTaskPatch
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.PlayerRoles[pc.PlayerId].Interface.Team == Team.Crewmate && pc.IsAlive())
{
+#if IL2CPP
+ var task = pc.myTasks.Find((Il2CppSystem.Predicate)(x => taskId == x.Id));
+#else
var task = pc.myTasks.Find(x => taskId == x.Id);
+#endif
Hider.OnSpecificTaskComplete(pc, task);
}
if (pc.IsAlive())
{
+#if IL2CPP
+ var task = pc.myTasks.Find((Il2CppSystem.Predicate)(x => taskId == x.Id));
+#else
var task = pc.myTasks.Find(x => taskId == x.Id);
+#endif
Benefactor.OnTaskComplete(pc, task);
}
diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs
index 1961f7a6b..70173ee38 100644
--- a/Patches/PlayerJoinAndLeftPatch.cs
+++ b/Patches/PlayerJoinAndLeftPatch.cs
@@ -5,6 +5,9 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using AmongUs.Data;
+#if IL2CPP
+using AmongUs.GameOptions;
+#endif
using AmongUs.InnerNet.GameDataMessages;
using EHR.Gamemodes;
using EHR.Modules;
@@ -78,7 +81,11 @@ internal static class OnGameJoinedPatch
if (Main.NormalOptions?.KillCooldown == 0f) Main.NormalOptions.KillCooldown = Main.LastKillCooldown.Value;
+#if IL2CPP
+ AURoleOptions.SetOpt(Main.NormalOptions.CastFast());
+#else
AURoleOptions.SetOpt(Main.NormalOptions);
+#endif
if (AURoleOptions.ShapeshifterCooldown == 0f) AURoleOptions.ShapeshifterCooldown = Main.LastShapeshifterCooldown.Value;
LateTask.New(() =>
@@ -654,7 +661,11 @@ internal static class OnPlayerLeftPatch
if (GameStates.IsOnlineGame)
{
var message = new DespawnGameDataMessage(netid);
+#if IL2CPP
+ AmongUsClient.Instance.LateBroadcastReliableMessage(message.CastFast());
+#else
AmongUsClient.Instance.LateBroadcastReliableMessage(message);
+#endif
}
if (GameStates.IsLobby)
@@ -888,7 +899,7 @@ internal static class NetworkedPlayerInfoInitPatch
{
public static void Postfix(NetworkedPlayerInfo __instance)
{
- foreach (KeyValuePair outfit in __instance.Outfits)
+ foreach (var outfit in __instance.Outfits)
{
if (outfit.Value != null)
{
diff --git a/Patches/SabotageSystemPatch.cs b/Patches/SabotageSystemPatch.cs
index 545739db3..87ddcab32 100644
--- a/Patches/SabotageSystemPatch.cs
+++ b/Patches/SabotageSystemPatch.cs
@@ -355,7 +355,11 @@ internal static class SabotageSystemTypeAnyActivePatch
{
public static bool Prefix(SabotageSystemType __instance, ref bool __result)
{
+#if IL2CPP
+ __result = __instance.specials.Exists((Il2CppSystem.Predicate)(s => s.IsActive)) || CustomSabotage.Instances.Count > 0;
+#else
__result = __instance.specials.Exists(s => s.IsActive) || CustomSabotage.Instances.Count > 0;
+#endif
return false;
}
}
diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs
index 39473e9dc..196b35b1c 100644
--- a/Patches/ShipStatusPatch.cs
+++ b/Patches/ShipStatusPatch.cs
@@ -181,7 +181,11 @@ internal static class UpdateSystemPatch
}
case SystemTypes.Sabotage when AmongUsClient.Instance.NetworkMode != NetworkModes.FreePlay:
{
+#if IL2CPP
+ var sabotageSystemType = __instance.Systems[SystemTypes.Sabotage].CastFast();
+#else
var sabotageSystemType = (SabotageSystemType)__instance.Systems[SystemTypes.Sabotage];
+#endif
return SabotageSystemTypeUpdateSystemPatch.CheckSabotage(sabotageSystemType, player, systemType);
}
case SystemTypes.Security when amount == 1:
@@ -288,7 +292,11 @@ internal static class CloseDoorsPatch
if (Doorjammer.JammedRooms.Contains(room)) allow = false;
if (SecurityGuard.BlockSabo.Count > 0) allow = false;
if (Options.DisableCloseDoor.GetBool()) allow = false;
+#if IL2CPP
+ if (Main.CurrentMap != MapNames.Polus && ((__instance.Systems[SystemTypes.Sabotage].CastFast()).AnyActive)) allow = false;
+#else
if (Main.CurrentMap != MapNames.Polus && ((__instance.Systems[SystemTypes.Sabotage] as SabotageSystemType)?.AnyActive ?? false)) allow = false;
+#endif
Logger.Info($"({room}) => {(allow ? "Allowed" : "Blocked")}", "DoorClose");
return allow;
@@ -386,6 +394,93 @@ internal static class AirshipStatusOnEnablePatch
ShipStatusOnEnablePatch.Postfix();
}
}
+#if IL2CPP
+[HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.OnEnable))]
+internal static class ShipStatusOnEnablePatch
+{
+ public static void Postfix()
+ {
+ int mapId = Main.NormalOptions.MapId;
+ List SystemTypesList = ShipStatusSystem.AllSabotage.ToList();
+ SystemTypesList.Add(SystemTypes.Ventilation);
+
+ foreach (var systemType in SystemTypesList)
+ {
+ try
+ {
+ if (!ShipStatus.Instance.Systems.TryGetValue(systemType, out ISystemType ISystemType)) continue;
+
+ switch (systemType)
+ {
+ case SystemTypes.Reactor:
+ {
+ switch (mapId)
+ {
+ case 2:
+ continue;
+ case 4:
+ ShipStatusSystem.HeliSabotageSystem = ISystemType.CastFast();
+ break;
+ default:
+ ShipStatusSystem.ReactorSystemType = ISystemType.CastFast();
+ break;
+ }
+
+ ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.Laboratory:
+ {
+ if (mapId != 2) continue;
+ ShipStatusSystem.ReactorSystemType = ISystemType.CastFast();
+ ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.HeliSabotage:
+ {
+ if (mapId != 4) continue;
+ ShipStatusSystem.HeliSabotageSystem = ISystemType.CastFast();
+ ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.LifeSupp:
+ {
+ if (mapId is 2 or 4 or 5) continue;
+ ShipStatusSystem.LifeSuppSystemType = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.Electrical:
+ {
+ if (mapId == 5) continue;
+ ShipStatusSystem.SwitchSystem = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.Comms:
+ {
+ if (mapId is 1 or 5)
+ ShipStatusSystem.HqHudSystemType = ISystemType.CastFast();
+ else
+ ShipStatusSystem.HudOverrideSystemType = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.MushroomMixupSabotage:
+ {
+ if (mapId != 5) continue;
+ ShipStatusSystem.MushroomMixupSabotageSystem = ISystemType.CastFast();
+ break;
+ }
+ case SystemTypes.Ventilation:
+ {
+ ShipStatusSystem.VentilationSystem = ISystemType.CastFast();
+ break;
+ }
+ }
+ }
+ catch (Exception e) { Utils.ThrowException(e); }
+ }
+ }
+}
+#else
[HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.OnEnable))]
internal static class ShipStatusOnEnablePatch
{
@@ -471,6 +566,7 @@ internal static class ShipStatusOnEnablePatch
}
}
}
+#endif
// From https://github.com/0xDrMoe/TownofHost-Enhanced
[HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Begin))]
@@ -745,7 +841,7 @@ internal static class VentilationSystemDeterioratePatch
writer.WritePacked(__instance.PlayersInsideVents.Count);
- foreach (KeyValuePair keyValuePair2 in __instance.PlayersInsideVents)
+ foreach (var keyValuePair2 in __instance.PlayersInsideVents)
{
writer.Write(keyValuePair2.Key);
writer.Write(keyValuePair2.Value);
diff --git a/Patches/TaskAssignPatch.cs b/Patches/TaskAssignPatch.cs
index b4f6d50ba..a42c5caa7 100644
--- a/Patches/TaskAssignPatch.cs
+++ b/Patches/TaskAssignPatch.cs
@@ -4,6 +4,9 @@ using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Roles;
using HarmonyLib;
+#if IL2CPP
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
+#endif
namespace EHR;
@@ -12,7 +15,11 @@ internal static class AddTasksFromListPatch
{
public static Dictionary DisableTasksSettings = [];
+#if IL2CPP
+ public static void Prefix([HarmonyArgument(4)] Il2CppSystem.Collections.Generic.List unusedTasks)
+#else
public static void Prefix([HarmonyArgument(4)] List unusedTasks)
+#endif
{
if (!AmongUsClient.Instance.AmHost) return;
@@ -129,7 +136,11 @@ internal static class RpcSetTasksPatch
{
// Patch that overwrites the task just before assigning the task and sending the RPC
// Do not interfere with vanilla task allocation process itself
+#if IL2CPP
+ public static void Prefix(NetworkedPlayerInfo __instance, [HarmonyArgument(0)] ref Il2CppStructArray taskTypeIds)
+#else
public static void Prefix(NetworkedPlayerInfo __instance, [HarmonyArgument(0)] ref byte[] taskTypeIds)
+#endif
{
// Android host somehow doesn't assign tasks in some game modes, so we skip the patch
bool notTaskingGM = Options.CurrentGameMode is not (CustomGameMode.Standard or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.StopAndGo);
@@ -207,7 +218,11 @@ internal static class RpcSetTasksPatch
// List containing IDs of assignable tasks
// Clone of the second argument of the original RpcSetTasks
- List TasksList = new();
+#if IL2CPP
+ Il2CppSystem.Collections.Generic.List TasksList = new();
+#else
+ List TasksList = [];
+#endif
foreach (byte num in taskTypeIds) TasksList.Add(num);
// Reference: ShipStatus.Begin
@@ -223,18 +238,30 @@ internal static class RpcSetTasksPatch
// HashSet where assigned tasks will be placed
// Prevents multiple assignments of the same task
- HashSet usedTaskTypes = new();
+#if IL2CPP
+ Il2CppSystem.Collections.Generic.HashSet usedTaskTypes = new();
+#else
+ HashSet usedTaskTypes = [];
+#endif
var start2 = 0;
var start3 = 0;
// List of assignable long tasks
- List LongTasks = new();
+#if IL2CPP
+ Il2CppSystem.Collections.Generic.List LongTasks = new();
+#else
+ List LongTasks = [];
+#endif
foreach (NormalPlayerTask task in ShipStatus.Instance.LongTasks) LongTasks.Add(task);
Shuffle(LongTasks);
// List of assignable short tasks
- List ShortTasks = new();
+#if IL2CPP
+ Il2CppSystem.Collections.Generic.List ShortTasks = new();
+#else
+ List ShortTasks = [];
+#endif
foreach (NormalPlayerTask task in ShipStatus.Instance.ShortTasks) ShortTasks.Add(task);
Shuffle(ShortTasks);
@@ -257,7 +284,11 @@ internal static class RpcSetTasksPatch
);
// Convert the list of tasks to array
+#if IL2CPP
+ taskTypeIds = new(TasksList.Count);
+#else
taskTypeIds = new byte[TasksList.Count];
+#endif
for (var i = 0; i < TasksList.Count; i++) taskTypeIds[i] = TasksList[i];
#region Logging
@@ -265,7 +296,11 @@ internal static class RpcSetTasksPatch
try
{
NormalPlayerTask[] allTasks = ShortTasks.ToArray().Concat(LongTasks.ToArray()).ToArray();
+#if IL2CPP
+ Il2CppSystem.Text.StringBuilder sb = new();
+#else
StringBuilder sb = new();
+#endif
foreach (TaskTypes taskType in usedTaskTypes)
GetTaskFromTaskType(taskType)?.AppendTaskText(sb);
@@ -279,7 +314,11 @@ internal static class RpcSetTasksPatch
#endregion
}
+#if IL2CPP
+ private static void Shuffle(Il2CppSystem.Collections.Generic.List list)
+#else
private static void Shuffle(List list)
+#endif
{
for (var i = 0; i < list.Count - 1; i++)
{
diff --git a/Patches/TmpAwakePatch.cs b/Patches/TmpAwakePatch.cs
index c024fdced..9e14f8554 100644
--- a/Patches/TmpAwakePatch.cs
+++ b/Patches/TmpAwakePatch.cs
@@ -1,5 +1,9 @@
using System;
+#if IL2CPP
+using Il2CppSystem.Collections.Generic;
+#else
using System.Collections.Generic;
+#endif
using System.IO;
using System.Reflection;
using HarmonyLib;
diff --git a/Patches/UsablesPatch.cs b/Patches/UsablesPatch.cs
index b52af39ba..8e5e23159 100644
--- a/Patches/UsablesPatch.cs
+++ b/Patches/UsablesPatch.cs
@@ -48,7 +48,11 @@ internal static class VentStartPatch
{
public static void Postfix(Vent __instance)
{
+#if IL2CPP
+ CanUseVentPatch.IUsable = __instance.CastFast();
+#else
CanUseVentPatch.IUsable = __instance;
+#endif
}
}
[HarmonyPatch(typeof(Vent), nameof(Vent.CanUse))]
diff --git a/Roles/Standard/Addons/Crewmate/TaskMaster.cs b/Roles/Standard/Addons/Crewmate/TaskMaster.cs
index 45a621fa4..f1f17a4f9 100644
--- a/Roles/Standard/Addons/Crewmate/TaskMaster.cs
+++ b/Roles/Standard/Addons/Crewmate/TaskMaster.cs
@@ -18,7 +18,11 @@ public class TaskMaster : IAddon
{
TaskState ts = pc.GetTaskState();
if (!ts.HasTasks || ts.IsTaskFinished || !Utils.HasTasks(pc.Data, forRecompute: false)) return;
+#if IL2CPP
+ var incompleteTasks = pc.myTasks.FindAll((Il2CppSystem.Predicate)(x => !x.IsComplete));
+#else
var incompleteTasks = pc.myTasks.FindAll(x => !x.IsComplete);
+#endif
LateTask.New(() =>
{
if (GameStates.IsEnded) return;
diff --git a/Roles/Standard/Crewmate/Support/Helper.cs b/Roles/Standard/Crewmate/Support/Helper.cs
index f0bd21c98..1bd58e735 100644
--- a/Roles/Standard/Crewmate/Support/Helper.cs
+++ b/Roles/Standard/Crewmate/Support/Helper.cs
@@ -28,7 +28,11 @@ public class Helper : RoleBase
public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount)
{
var randomPlayer = Main.EnumeratePlayerControls().Without(pc).Where(x => x.Is(Team.Crewmate)).Select(x => (pc: x, ts: x.GetTaskState())).Where(x => !x.ts.IsTaskFinished && x.ts.HasTasks).Select(x => x.pc).RandomElement();
+#if IL2CPP
+ var incompleteTasks = randomPlayer.myTasks.FindAll((Il2CppSystem.Predicate)(x => !x.IsComplete));
+#else
var incompleteTasks = randomPlayer.myTasks.FindAll(x => !x.IsComplete);
+#endif
RPC.PlaySoundRPC(randomPlayer.PlayerId, Sounds.TaskUpdateSound);
randomPlayer.RpcCompleteTask(incompleteTasks[IRandom.Instance.Next(0, incompleteTasks.Count)].Id);
randomPlayer.Notify(string.Format(Translator.GetString("HelperCompletedTaskForYou"), CustomRoles.Helper.ToColoredString()));
diff --git a/Roles/Standard/Crewmate/Support/Operative.cs b/Roles/Standard/Crewmate/Support/Operative.cs
index 0a7396fe9..69573885d 100644
--- a/Roles/Standard/Crewmate/Support/Operative.cs
+++ b/Roles/Standard/Crewmate/Support/Operative.cs
@@ -55,7 +55,11 @@ public class Operative : RoleBase
static void UseAbility()
{
+#if IL2CPP
+ SabotageSystemType sabotageSystemType = ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast();
+#else
if (ShipStatus.Instance.Systems[SystemTypes.Sabotage] is not SabotageSystemType sabotageSystemType) return;
+#endif
sabotageSystemType.Timer = SabotageSystemTypeUpdateSystemPatch.IsCooldownModificationEnabled
? SabotageSystemTypeUpdateSystemPatch.ModifiedCooldownSec
: 30f;
diff --git a/nuget.config b/nuget.config
index 2d4874f7e..cb01a3919 100644
--- a/nuget.config
+++ b/nuget.config
@@ -4,6 +4,5 @@
-