diff --git a/Reactor/Networking/Patches/ClientPatches.cs b/Reactor/Networking/Patches/ClientPatches.cs index c03e805..a9c9f6b 100644 --- a/Reactor/Networking/Patches/ClientPatches.cs +++ b/Reactor/Networking/Patches/ClientPatches.cs @@ -38,12 +38,12 @@ internal static class ClientPatches { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.HandleGameDataInner))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.HandleGameDataInner))!; } public static bool Prefix(Il2CppObjectBase __instance, ref bool __result) { - var wrapper = new StateMachineWrapper(__instance); + var wrapper = new Il2CppStateMachineWrapper(__instance); var innerNetClient = wrapper.Instance; var reader = wrapper.GetParameter("reader"); @@ -177,12 +177,12 @@ internal static class ClientPatches { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoSendSceneChange))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoSendSceneChange))!; } public static bool Prefix(Il2CppObjectBase __instance, ref bool __result) { - var wrapper = new StateMachineWrapper(__instance); + var wrapper = new Il2CppStateMachineWrapper(__instance); if (ReactorConnection.Instance!.Syncer != Syncer.Host) return true; @@ -233,14 +233,14 @@ internal static class ClientPatches { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoHandleSpawn))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoHandleSpawn))!; } public static void Postfix(Il2CppObjectBase __instance, bool __result) { if (ReactorConnection.Instance!.Syncer != Syncer.Host) return; - var wrapper = new StateMachineWrapper(__instance); + var wrapper = new Il2CppStateMachineWrapper(__instance); var ownerId = wrapper.GetParameter("_ownerId_5__2"); if (!__result && !AmongUsClient.Instance.AmHost && ownerId == AmongUsClient.Instance.ClientId) diff --git a/Reactor/Networking/Patches/ReactorConnection.cs b/Reactor/Networking/Patches/ReactorConnection.cs index 5ec921e..f64e809 100644 --- a/Reactor/Networking/Patches/ReactorConnection.cs +++ b/Reactor/Networking/Patches/ReactorConnection.cs @@ -28,7 +28,7 @@ public class ReactorConnection { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoConnect))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(InnerNetClient.CoConnect))!; } public static void Prefix() diff --git a/Reactor/Patches/Fixes/CoFindGamePatch.cs b/Reactor/Patches/Fixes/CoFindGamePatch.cs index 58ed2af..17da834 100644 --- a/Reactor/Patches/Fixes/CoFindGamePatch.cs +++ b/Reactor/Patches/Fixes/CoFindGamePatch.cs @@ -12,7 +12,7 @@ internal static class CoFindGamePatch { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(AmongUsClient.CoFindGame))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(AmongUsClient.CoFindGame))!; } public static void Prefix() diff --git a/Reactor/Patches/Miscellaneous/CustomServersPatch.cs b/Reactor/Patches/Miscellaneous/CustomServersPatch.cs index 0f328dc..6232fba 100644 --- a/Reactor/Patches/Miscellaneous/CustomServersPatch.cs +++ b/Reactor/Patches/Miscellaneous/CustomServersPatch.cs @@ -24,8 +24,8 @@ internal static class CustomServersPatch { public static IEnumerable TargetMethods() => [ - StateMachineWrapper.GetStateMachineMoveNext(nameof(AuthManager.CoConnect))!, - StateMachineWrapper.GetStateMachineMoveNext(nameof(AuthManager.CoWaitForNonce))! + Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(AuthManager.CoConnect))!, + Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(AuthManager.CoWaitForNonce))! ]; public static bool Prefix(ref bool __result) @@ -45,28 +45,28 @@ internal static class CustomServersPatch { public static MethodBase TargetMethod() { - return StateMachineWrapper.GetStateMachineMoveNext(nameof(AmongUsClient.CoJoinOnlinePublicGame))!; + return Il2CppStateMachineWrapper.GetStateMachineMoveNext(nameof(AmongUsClient.CoJoinOnlinePublicGame))!; } public static void Prefix(Il2CppObjectBase __instance) { - var stateMachine = new StateMachineWrapper(__instance); + var stateMachine = new Il2CppStateMachineWrapper(__instance); // Skip to state 1 which just calls CoJoinOnlineGameDirect if (stateMachine.State == 0 && !ServerManager.Instance.IsHttp) { stateMachine.State = 1; var lambdaType = stateMachine.GetParameter("__8__1").GetType(); - var newDisplayClass = Activator.CreateInstance(lambdaType); - if (newDisplayClass == null) + var newDisplayClassObject = Activator.CreateInstance(lambdaType); + if (newDisplayClassObject == null) { throw new InvalidOperationException($"Could not create display class of type '{lambdaType}'."); } - var displayClass = new CompilerGeneratedObjectWrapper(newDisplayClass); - displayClass.SetField("matchmakerToken", string.Empty); + var wrappedDisplayClassObject = new Il2CppCompilerGeneratedObjectWrapper(newDisplayClassObject); + wrappedDisplayClassObject.SetField("matchmakerToken", string.Empty); - stateMachine.SetParameter("__8__1", newDisplayClass); + stateMachine.SetParameter("__8__1", newDisplayClassObject); } } } diff --git a/Reactor/Utilities/CompilerGeneratedObjectWrapper.cs b/Reactor/Utilities/Il2CppCompilerGeneratedObjectWrapper.cs similarity index 74% rename from Reactor/Utilities/CompilerGeneratedObjectWrapper.cs rename to Reactor/Utilities/Il2CppCompilerGeneratedObjectWrapper.cs index 99e3610..87f4de1 100644 --- a/Reactor/Utilities/CompilerGeneratedObjectWrapper.cs +++ b/Reactor/Utilities/Il2CppCompilerGeneratedObjectWrapper.cs @@ -6,9 +6,14 @@ using HarmonyLib; namespace Reactor.Utilities; /// -/// A safe wrapper around compiler generated classes like DisplayClass or IEnumerator state machines. +/// A safe wrapper around IL2CPP compiler generated classes like DisplayClass or IEnumerator state machines. +/// This is useful for gracefully handling changes across different game versions and updates, which may affect +/// compiler generated names. +/// To use this class, pass the instance object of the compiler generated class into the constructor. +/// Then you can use the GetField and SetField methods to access the fields of the compiler generated class +/// by their original names. /// -public class CompilerGeneratedObjectWrapper +public class Il2CppCompilerGeneratedObjectWrapper { /// /// Gets a reference to the compiler generated object. @@ -36,10 +41,10 @@ public class CompilerGeneratedObjectWrapper protected Dictionary SetterCache { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// An instance of the compiler generated object. - public CompilerGeneratedObjectWrapper(object generatedObject) + public Il2CppCompilerGeneratedObjectWrapper(object generatedObject) { GeneratedObject = generatedObject; GeneratedType = generatedObject.GetType(); @@ -49,6 +54,14 @@ public class CompilerGeneratedObjectWrapper SetterCache = []; } + /// + /// Caches the property info, getter, and setter for a given field name and type. + /// + /// The name of the field to cache. + /// The expected type of the field. + /// The cached for the specified field. + /// Thrown if the field does not exist in the compiler generated type. + /// Thrown if the field exists but is not of the expected type. public PropertyInfo CacheProperty(string fieldName) { var propertyInfo = AccessTools.Property(GeneratedType, fieldName) @@ -117,4 +130,3 @@ public class CompilerGeneratedObjectWrapper propertyInfo.SetValue(GeneratedObject, value); } } - diff --git a/Reactor/Utilities/StateMachineWrapper.cs b/Reactor/Utilities/Il2CppStateMachineWrapper.cs similarity index 78% rename from Reactor/Utilities/StateMachineWrapper.cs rename to Reactor/Utilities/Il2CppStateMachineWrapper.cs index f67617b..0ece8f4 100644 --- a/Reactor/Utilities/StateMachineWrapper.cs +++ b/Reactor/Utilities/Il2CppStateMachineWrapper.cs @@ -6,10 +6,13 @@ using HarmonyLib; namespace Reactor.Utilities; /// -/// A wrapper for state machine objects to access their parent instance and state. +/// A wrapper for IL2CPP state machine objects to access their parent instance and state. +/// This class is useful for working with IL2CPP state machines across different game versions. +/// To use it, pass the instance object of the state machine into the constructor. To access the parent class, +/// use the Instance property. To access the current state of the state machine, use the State property. /// /// The type of the parent class that owns the state machine. -public class StateMachineWrapper : CompilerGeneratedObjectWrapper +public class Il2CppStateMachineWrapper : Il2CppCompilerGeneratedObjectWrapper { // normally it is fields, but IL2CPP turns them into properties private readonly PropertyInfo _thisProperty; @@ -33,11 +36,13 @@ public class StateMachineWrapper : CompilerGeneratedObjectWrapper } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The state machine instance to wrap. - public StateMachineWrapper(object stateMachine) : base(stateMachine) + /// The instance object of the state machine being wrapped. + public Il2CppStateMachineWrapper(object stateMachine) : base(stateMachine) { + // The names of these properties are implementation details of the IL compiler used by Unity. + // They should be stable as long as Unity sticks to mono. _thisProperty = AccessTools.Property(GeneratedType, "__4__this"); _stateProperty = AccessTools.Property(GeneratedType, "__1__state"); @@ -72,10 +77,9 @@ public class StateMachineWrapper : CompilerGeneratedObjectWrapper } /// - /// Attempts to retrieve the MoveNext method of a state machine for the specified method name in type T. + /// Attempts to retrieve the MoveNext method of a state machine for the specified method name. /// /// The name of the method whose state machine MoveNext method is to be retrieved. - /// The type containing the state machine. /// The MoveNext if found; otherwise, null. public static MethodBase? GetStateMachineMoveNext(string methodName) {