mono/il2cpp config

This commit is contained in:
Gurge44 committed 2026-09-24 20:26:16 +02:00
1 parent e16d9119d1
commit 65281aeebc
59 files changed
+773 -146

No files matched your search

+18 -11
View File
@@ -5,7 +5,8 @@
</PropertyGroup>
<Import Project="local.props" Condition="Exists('local.props')" />
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework Condition="'$(Configuration)' == 'IL2CPP'">net6.0</TargetFramework>
<TargetFramework Condition="'$(Configuration)' != 'IL2CPP'">netstandard2.1</TargetFramework>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
@@ -16,9 +17,11 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>True</Optimize>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
<Configurations>Debug;Release;Android</Configurations>
<Configurations>Debug;Release;IL2CPP</Configurations>
<Platforms>AnyCPU</Platforms>
<RepositoryUrl>https://github.com/Gurge44/EndlessHostRoles</RepositoryUrl>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' != 'IL2CPP'">
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<ResolveAssemblyReferenceIgnoreTargetFrameworkAttributeVersionMismatch>true</ResolveAssemblyReferenceIgnoreTargetFrameworkAttributeVersionMismatch>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@@ -34,17 +37,21 @@
<EmbeddedResource Remove="CTA\**"/>
<None Remove="CTA\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AmongUs.GameLibs.Mono" Version="2026.6.5" PrivateAssets="all" Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'" />
<PackageReference Include="AmongUs.GameLibs.Android" Version="2025.10.14" PrivateAssets="all" Condition="'$(Configuration)' == 'Android'"/>
<PackageReference Include="BepInEx.Core" Version="5.4.21" Private="false" IncludeAssets="compile" />
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
<PackageReference Include="BepInEx.PluginInfoProps" Version="2.1.0" />
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="JetBrains.Annotations" Version="2026.2.0" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'IL2CPP'">
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.8.18" PrivateAssets="all" />
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1"/>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="Samboy063.Cpp2IL.Core" Version="2022.1.0-pre-release.21" />
</ItemGroup>
<ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'">
<PackageReference Include="AmongUs.GameLibs.Mono" Version="2026.6.5" PrivateAssets="all" />
<PackageReference Include="BepInEx.Core" Version="5.4.21" Private="false" IncludeAssets="compile" />
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.3" PrivateAssets="all" />
<Reference Include="Assembly-CSharp" Publicize="true">
@@ -67,7 +74,7 @@
<Target Name="Roles" AfterTargets="Build">
<Copy SourceFiles="CustomRoles.cs" DestinationFolder="CTA/CustomTeamAssigner/"/>
</Target>
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != '' And '$(Configuration)' != 'Android'">
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
<Copy SourceFiles="$(OutputPath)$(AssemblyName).dll" DestinationFolder="$(AmongUs)/BepInEx/plugins/"/>
</Target>
</Project>
+3 -3
View File
@@ -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
+67 -2
View File
@@ -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<string> 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<string> 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<ErrorText>();
ClassInjector.RegisterTypeInIl2Cpp<MeetingHudPagingBehaviour>();
ClassInjector.RegisterTypeInIl2Cpp<ShapeShifterPagingBehaviour>();
ClassInjector.RegisterTypeInIl2Cpp<VitalsPagingBehaviour>();
coroutines = AddComponent<Coroutines>();
AddComponent<ClientControlGUI>();
#else
gameObject.AddComponent<ClientControlGUI>();
#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<string> onComplete, string langParam = "", int length = 0, int difficulty = 0)
{
var api = new StringBuilder("https://random-word-api.herokuapp.com/word");
+8
View File
@@ -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)
{
+8
View File
@@ -104,13 +104,21 @@ public class ClientControlGUI : MonoBehaviour
{
_cam = Camera.main;
Instance = this;
#if IL2CPP
SceneManager.add_sceneLoaded((Action<Scene, LoadSceneMode>)OnSceneLoaded);
#else
SceneManager.sceneLoaded += OnSceneLoaded;
#endif
Logger.Info("ClientControlGUI initialised", "ClientControlGUI");
}
private void OnDestroy()
{
#if IL2CPP
SceneManager.remove_sceneLoaded((Action<Scene, LoadSceneMode>)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
+4 -50
View File
@@ -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<PlayerGameOptionsSender>().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)
+10
View File
@@ -20,7 +20,11 @@ public abstract class CustomSabotage
protected virtual void Fix()
{
Instances.Remove(this);
#if IL2CPP
(ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast<SabotageSystemType>()).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<SabotageSystemType>();
#else
if (Instances.Count > 0 && ShipStatus.Instance.Systems[SystemTypes.Sabotage] is SabotageSystemType sabotageSystemType)
{
#endif
sabotageSystemType.Timer = SabotageSystemTypeUpdateSystemPatch.IsCooldownModificationEnabled
? SabotageSystemTypeUpdateSystemPatch.ModifiedCooldownSec
: 30f;
+4
View File
@@ -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 = "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + text + "</font>";
#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);
+2 -2
View File
@@ -214,8 +214,8 @@ public class RemoveDisableDevicesPatch
Options.DisableDevicesIgnoreAfterAnyoneDied.GetBool() && GameStates.AlreadyDied;
ignore &= !rogueForce;
MapConsole[] admins = Object.FindObjectsOfType<MapConsole>(true);
SystemConsole[] consoles = Object.FindObjectsOfType<SystemConsole>(true);
var admins = Object.FindObjectsOfType<MapConsole>(true);
var consoles = Object.FindObjectsOfType<SystemConsole>(true);
if (admins == null || consoles == null) return;
switch (Main.NormalOptions.MapId)
+17
View File
@@ -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;
+17 -3
View File
@@ -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<byte>(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<PlayerControl> GetPlayersInAbilityRangeSorted(Predicate<PlayerControl> predicate, bool ignoreColliders = false)
{
List<PlayerControl> rangePlayersIL = RoleBehaviour.GetTempPlayerList();
var rangePlayersIL = RoleBehaviour.GetTempPlayerList();
List<PlayerControl> rangePlayers = [];
player.Data.Role.GetPlayersInAbilityRangeSorted(rangePlayersIL, ignoreColliders);
+4
View File
@@ -8,7 +8,11 @@ public static class ObjectHelper
{
if (!obj) return;
#if IL2CPP
obj.ForEachChild((Il2CppSystem.Action<GameObject>)(x => x.DestroyTranslator()));
#else
obj.ForEachChild(x => x.DestroyTranslator());
#endif
TextTranslatorTMP[] translator = obj.GetComponentsInChildren<TextTranslatorTMP>(true);
translator?.Do(Object.Destroy);
}
@@ -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());
@@ -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<ILogger>()).CastFast<IGameOptions>());
#else
Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger()));
#endif
protected override bool IsDirty { get; set; }
@@ -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
;
}
}
+55
View File
@@ -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<T>(this Il2CppObjectBase obj) where T : Il2CppObjectBase
{
if (obj is T casted) return casted;
return OperatingSystem.IsAndroid() ? obj.Cast<T>() : obj.Pointer.CastFast<T>();
}
private static T CastFast<T>(this IntPtr ptr) where T : Il2CppObjectBase
{
return CastHelper<T>.Cast(ptr);
}
private static class CastHelper<T> where T : Il2CppObjectBase
{
public static readonly Func<IntPtr, T> Cast;
static CastHelper()
{
ConstructorInfo constructor = typeof(T).GetConstructor([typeof(IntPtr)]);
ParameterExpression ptr = Expression.Parameter(typeof(IntPtr));
NewExpression create = Expression.New(constructor!, ptr);
Expression<Func<IntPtr, T>> lambda = Expression.Lambda<Func<IntPtr, T>>(create, ptr);
Cast = lambda.Compile();
}
}
public static bool TryCastFast<T>(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<T>()
: obj.Pointer.CastFast<T>();
return casted != null;
}
}
}
#endif
@@ -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
@@ -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;
@@ -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<string, Type> 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;
+10 -2
View File
@@ -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))
{
@@ -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.
+12
View File
@@ -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<OptionBehaviour>)(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<TextMeshPro>();
@@ -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<OptionBehaviour>)(menu.ValueChanged);
#else
row.OnValueChanged = menu.ValueChanged;
#endif
row.LabelBackground.transform.localScale += new Vector3(1f, 0f, 0f);
row.TitleText.GetComponent<RectTransform>().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);
+4
View File
@@ -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();
+4
View File
@@ -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());
}
+20 -19
View File
@@ -14,21 +14,25 @@ namespace EHR.Modules;
/// <typeparam name="T">The type of the parent class that owns the state machine.</typeparam>
public class StateMachineWrapper<T> : 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;
/// <summary>
/// Gets the instance of the parent class that owns the state machine.
/// </summary>
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
/// <summary>
/// Gets or sets the current state of the state machine.
@@ -36,14 +40,13 @@ public class StateMachineWrapper<T> : CompilerGeneratedObjectWrapper
/// <returns>The current state as an integer.</returns>
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
}
/// <summary>
@@ -52,15 +55,13 @@ public class StateMachineWrapper<T> : CompilerGeneratedObjectWrapper
/// <param name="stateMachine">The state machine instance to wrap.</param>
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
}
/// <summary>
+42 -3
View File
@@ -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<Dictionary<string, JsonElement>>(resourceStream);
#else
using var reader = new StreamReader(resourceStream);
using var jsonReader = new JsonTextReader(reader);
var jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, JToken>>(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<string>(), 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<string, Dictionary<int, string>> translationMaps, int languageId, Dictionary<string, JsonElement> 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<string, Dictionary<int, string>> translationMaps, int languageId, Dictionary<string, JToken> 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)
+12
View File
@@ -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<float>)(t =>
{
obj.SetActive(Math.Abs(t - 1f) > 0.1f);
obj.GetComponent<SpriteRenderer>().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<SpriteRenderer>().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)
+8 -3
View File
@@ -5,7 +5,11 @@ namespace EHR;
public static class AirshipElectricalDoors
{
#if IL2CPP
private static ElectricalDoors Instance => ShipStatus.Instance.Systems[SystemTypes.Decontamination].CastFast<ElectricalDoors>();
#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<byte> GetClosedDoors()
{
List<byte> 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);
}
+9 -4
View File
@@ -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<Announcement> 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();
}
}
+4
View File
@@ -658,7 +658,11 @@ internal static class ChatCommands
if (Main.CurrentMap == MapNames.Dleks || Main.NormalOptions.MapId == 6)
{
#if IL2CPP
IGameOptions opt = Main.NormalOptions.CastFast<IGameOptions>();
#else
IGameOptions opt = Main.NormalOptions;
#endif
Options.DefaultKillCooldown = Main.NormalOptions.KillCooldown;
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
+8 -1
View File
@@ -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<SystemTypes, ISystemType> systems = ShipStatus.Instance.Systems;
var systems = ShipStatus.Instance.Systems;
LifeSuppSystemType lifeSupp;
if (systems.ContainsKey(SystemTypes.LifeSupp) && // Confirmation of sabotage existence
+8
View File
@@ -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<ClientControlGUI>();
#else
Main.Instance.gameObject.AddComponent<ClientControlGUI>();
#endif
break;
case false when ClientControlGUI.Instance:
Object.Destroy(ClientControlGUI.Instance);
-10
View File
@@ -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
{
+4
View File
@@ -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<MapIconByName>)(x => x.Name != map)))
#else
if (instance.AllMapIcons.TrueForAll(x => x.Name != map))
#endif
{
instance.AllMapIcons.Insert((int)map, new MapIconByName
{
+31 -10
View File
@@ -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<OptionBehaviour, int> OptionList = new();
public static readonly Dictionary<int, OptionBehaviour> BehaviourList = new();
public static readonly Dictionary<int, CategoryHeaderMasked> CategoryHeaderList = new();
public static readonly Dictionary<CustomRoles, Transform> HelpIconList = [];
public static readonly Dictionary<OptionItem, BaseGameSetting> BaseGameSettingCache = [];
public static readonly System.Collections.Generic.Dictionary<CustomRoles, Transform> HelpIconList = [];
public static readonly System.Collections.Generic.Dictionary<OptionItem, BaseGameSetting> BaseGameSettingCache = [];
public static T Track<T>(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<OptionBehaviour>)__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<CustomGameMode, GameObject> GMButtons = [];
public static readonly System.Collections.Generic.Dictionary<CustomGameMode, GameObject> 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<TabGroup, PassiveButton> ModSettingsButtons = [];
public static readonly Dictionary<TabGroup, GameOptionsMenu> ModSettingsTabs = [];
public static readonly System.Collections.Generic.Dictionary<TabGroup, PassiveButton> ModSettingsButtons = [];
public static readonly System.Collections.Generic.Dictionary<TabGroup, GameOptionsMenu> ModSettingsTabs = [];
public static long LastPresetChange;
public static bool ChangingPreset;
public static FreeChatInputField InputField;
private static List<OptionItem> HiddenBySearch = [];
private static System.Collections.Generic.List<OptionItem> HiddenBySearch = [];
public static Action SearchForOptionsAction;
private static int NumImpsOnOpen = 1;
@@ -1157,7 +1175,7 @@ public static class GameSettingMenuPatch
SetupExtendedUI(__instance);
}
private static readonly Dictionary<int, GameObject> ExtraObjectsCache = [];
private static readonly System.Collections.Generic.Dictionary<int, GameObject> 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<OptionItem> 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<OptionItem> 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
);
}
+4
View File
@@ -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
}
}
+12
View File
@@ -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<IGameOptions>());
#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<IGameOptions>();
#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<IGameOptions>();
#else
IGameOptions opt = Main.NormalOptions;
#endif
AURoleOptions.SetOpt(opt);
if (__instance.startState == GameStartManager.StartingStates.Countdown)
+7 -3
View File
@@ -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<byte> __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();
}
}
}
}
#endif
+5
View File
@@ -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<DoorsSystemType>();
MapRoomDoorsUpdatePatch.AutoDoorsSystemType = ISystem.CastFast<AutoDoorsSystemType>();
#else
MapRoomDoorsUpdatePatch.DoorsSystemType = ISystem as DoorsSystemType;
MapRoomDoorsUpdatePatch.AutoDoorsSystemType = ISystem as AutoDoorsSystemType;
#endif
MapRoomDoorsUpdatePatch.AutoOpenDoors.Clear();
foreach (OpenableDoor door in shipStatusInstance.AllDoors)
+33 -2
View File
@@ -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<SabotageSystemType>()).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<PlayerControl> show = IntroCutscene.SelectTeamToShow((Il2CppSystem.Func<NetworkedPlayerInfo, bool>)(pcd => !PlayerControl.LocalPlayer.Data.Role.IsImpostor || pcd.Role.TeamType == PlayerControl.LocalPlayer.Data.Role.TeamType));
#else
List<PlayerControl> 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<PlayerControl>(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<PlayerControl> teamToDisplay)
#else
public static bool Prefix(IntroCutscene __instance, ref List<PlayerControl> 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<PlayerControl> teamToDisplay)
#else
public static void Postfix(IntroCutscene __instance, ref List<PlayerControl> 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<RoleBehaviour>)(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<PlayerControl> yourTeam)
#else
public static bool Prefix(IntroCutscene __instance, ref List<PlayerControl> 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<PlayerControl> yourTeam)
#else
public static void Postfix(IntroCutscene __instance, ref List<PlayerControl> yourTeam)
#endif
{
BeginCrewmatePatch.Postfix(__instance, ref yourTeam);
}
+11 -2
View File
@@ -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<ISoundPlayer>)(x => x.Name.Equals("MapTheme"));
#else
Lobbybgm = x => x.Name.Equals("MapTheme");
#endif
MapThemeSound = SoundManager.Instance.soundPlayers.Find(Lobbybgm);
if (!Main.LobbyMusic.Value)
+15
View File
@@ -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()
+9 -1
View File
@@ -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<TMP_Text>();
+8
View File
@@ -23,7 +23,11 @@ public static class GameOptionsMapPickerPatch
[HarmonyPrefix]
public static void Postfix_Prefix(GameOptionsMapPicker __instance)
{
#if IL2CPP
if (__instance.AllMapIcons.TrueForAll((Il2CppSystem.Predicate<MapIconByName>)(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<MapIconByName>)(x => x.Name != (MapNames)6)))
#else
if (__instance.AllMapIcons.TrueForAll(x => x.Name != (MapNames)6))
#endif
{
__instance.AllMapIcons.Insert((int)(MapNames)6, new MapIconByName
{
+4
View File
@@ -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);
}
+10
View File
@@ -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;
}
+8 -1
View File
@@ -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<PoolablePlayer>();
var pbs = __instance.transform.GetComponentsInChildren<PoolablePlayer>();
if (pbs != null)
{
+4
View File
@@ -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>)RoleEffectAnimation) && !__instance.Player.walkingToVent && !__instance.Player.inMovingPlat)
#else
if (!__instance.Player.currentRoleAnimations.Find(RoleEffectAnimation) && !__instance.Player.walkingToVent && !__instance.Player.inMovingPlat)
#endif
{
if (__instance.isInvisible)
{
+8
View File
@@ -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<PlayerTask>)(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<PlayerTask>)(x => taskId == x.Id));
#else
var task = pc.myTasks.Find(x => taskId == x.Id);
#endif
Benefactor.OnTaskComplete(pc, task);
}
+12 -1
View File
@@ -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<IGameOptions>());
#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<IGameDataMessage>());
#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<PlayerOutfitType, NetworkedPlayerInfo.PlayerOutfit> outfit in __instance.Outfits)
foreach (var outfit in __instance.Outfits)
{
if (outfit.Value != null)
{
+4
View File
@@ -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<IActivatable>)(s => s.IsActive)) || CustomSabotage.Instances.Count > 0;
#else
__result = __instance.specials.Exists(s => s.IsActive) || CustomSabotage.Instances.Count > 0;
#endif
return false;
}
}
+97 -1
View File
@@ -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<SabotageSystemType>();
#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<SabotageSystemType>()).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<SystemTypes> 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<HeliSabotageSystem>();
break;
default:
ShipStatusSystem.ReactorSystemType = ISystemType.CastFast<ReactorSystemType>();
break;
}
ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast<ICriticalSabotage>();
break;
}
case SystemTypes.Laboratory:
{
if (mapId != 2) continue;
ShipStatusSystem.ReactorSystemType = ISystemType.CastFast<ReactorSystemType>();
ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast<ICriticalSabotage>();
break;
}
case SystemTypes.HeliSabotage:
{
if (mapId != 4) continue;
ShipStatusSystem.HeliSabotageSystem = ISystemType.CastFast<HeliSabotageSystem>();
ShipStatusSystem.ICriticalSabotage = ISystemType.CastFast<ICriticalSabotage>();
break;
}
case SystemTypes.LifeSupp:
{
if (mapId is 2 or 4 or 5) continue;
ShipStatusSystem.LifeSuppSystemType = ISystemType.CastFast<LifeSuppSystemType>();
break;
}
case SystemTypes.Electrical:
{
if (mapId == 5) continue;
ShipStatusSystem.SwitchSystem = ISystemType.CastFast<SwitchSystem>();
break;
}
case SystemTypes.Comms:
{
if (mapId is 1 or 5)
ShipStatusSystem.HqHudSystemType = ISystemType.CastFast<HqHudSystemType>();
else
ShipStatusSystem.HudOverrideSystemType = ISystemType.CastFast<HudOverrideSystemType>();
break;
}
case SystemTypes.MushroomMixupSabotage:
{
if (mapId != 5) continue;
ShipStatusSystem.MushroomMixupSabotageSystem = ISystemType.CastFast<MushroomMixupSabotageSystem>();
break;
}
case SystemTypes.Ventilation:
{
ShipStatusSystem.VentilationSystem = ISystemType.CastFast<VentilationSystem>();
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<byte, byte> keyValuePair2 in __instance.PlayersInsideVents)
foreach (var keyValuePair2 in __instance.PlayersInsideVents)
{
writer.Write(keyValuePair2.Key);
writer.Write(keyValuePair2.Value);
+43 -4
View File
@@ -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<TaskTypes, OptionItem> DisableTasksSettings = [];
#if IL2CPP
public static void Prefix([HarmonyArgument(4)] Il2CppSystem.Collections.Generic.List<NormalPlayerTask> unusedTasks)
#else
public static void Prefix([HarmonyArgument(4)] List<NormalPlayerTask> 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<byte> 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<byte> TasksList = new();
#if IL2CPP
Il2CppSystem.Collections.Generic.List<byte> TasksList = new();
#else
List<byte> 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<TaskTypes> usedTaskTypes = new();
#if IL2CPP
Il2CppSystem.Collections.Generic.HashSet<TaskTypes> usedTaskTypes = new();
#else
HashSet<TaskTypes> usedTaskTypes = [];
#endif
var start2 = 0;
var start3 = 0;
// List of assignable long tasks
List<NormalPlayerTask> LongTasks = new();
#if IL2CPP
Il2CppSystem.Collections.Generic.List<NormalPlayerTask> LongTasks = new();
#else
List<NormalPlayerTask> LongTasks = [];
#endif
foreach (NormalPlayerTask task in ShipStatus.Instance.LongTasks) LongTasks.Add(task);
Shuffle(LongTasks);
// List of assignable short tasks
List<NormalPlayerTask> ShortTasks = new();
#if IL2CPP
Il2CppSystem.Collections.Generic.List<NormalPlayerTask> ShortTasks = new();
#else
List<NormalPlayerTask> 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<T>(Il2CppSystem.Collections.Generic.List<T> list)
#else
private static void Shuffle<T>(List<T> list)
#endif
{
for (var i = 0; i < list.Count - 1; i++)
{
+4
View File
@@ -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;
+4
View File
@@ -48,7 +48,11 @@ internal static class VentStartPatch
{
public static void Postfix(Vent __instance)
{
#if IL2CPP
CanUseVentPatch.IUsable = __instance.CastFast<IUsable>();
#else
CanUseVentPatch.IUsable = __instance;
#endif
}
}
[HarmonyPatch(typeof(Vent), nameof(Vent.CanUse))]
@@ -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<PlayerTask>)(x => !x.IsComplete));
#else
var incompleteTasks = pc.myTasks.FindAll(x => !x.IsComplete);
#endif
LateTask.New(() =>
{
if (GameStates.IsEnded) return;
@@ -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<PlayerTask>)(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()));
@@ -55,7 +55,11 @@ public class Operative : RoleBase
static void UseAbility()
{
#if IL2CPP
SabotageSystemType sabotageSystemType = ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast<SabotageSystemType>();
#else
if (ShipStatus.Instance.Systems[SystemTypes.Sabotage] is not SabotageSystemType sabotageSystemType) return;
#endif
sabotageSystemType.Timer = SabotageSystemTypeUpdateSystemPatch.IsCooldownModificationEnabled
? SabotageSystemTypeUpdateSystemPatch.ModifiedCooldownSec
: 30f;
-1
View File
@@ -4,6 +4,5 @@
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" />
<add key="Samboy" value="https://nuget.samboy.dev/v3/index.json" />
<add key="Local Packages" value="packages.local/" />
</packageSources>
</configuration>