Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of IKEASimulator Fixer v1.0.0
IKEASimulator_Fixer.dll
Decompiled 4 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using IKEASimulator_Fixer.Patches; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("sasnews")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0b87d15f3ef4e643400cec9f0e8e83de13e340b0")] [assembly: AssemblyProduct("IKEASimulator_Fixer")] [assembly: AssemblyTitle("IKEASimulator_Fixer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace IKEASimulator_Fixer { [HarmonyPatch(typeof(PlayerController))] internal static class ExamplePlayerControllerPatch { [HarmonyPrefix] [HarmonyPatch("Start")] private static void Start_Prefix(PlayerController __instance) { IKEASimulator_Fixer.Logger.LogDebug((object)$"{__instance} Start Prefix"); } [HarmonyPostfix] [HarmonyPatch("Start")] private static void Start_Postfix(PlayerController __instance) { IKEASimulator_Fixer.Logger.LogDebug((object)$"{__instance} Start Postfix"); } } [BepInPlugin("sasnews.IKEASimulator_Fixer", "IKEASimulator_Fixer", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class IKEASimulator_Fixer : BaseUnityPlugin { public const string PluginGUID = "sasnews.IKEASimulator_Fixer"; public const string PluginName = "IKEASimulator_Fixer"; public const string PluginVersion = "1.0.0"; private static bool _ikeaPatched; internal static IKEASimulator_Fixer Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; private set; } public static ConfigEntry<bool> EnableImmediatePhysics { get; private set; } private void Awake() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; EnableImmediatePhysics = ((BaseUnityPlugin)this).Config.Bind<bool>("Physics", "EnableImmediatePhysics", false, "true: オブジェクトがスポーン直後から落下する\nfalse: つかむまで固定される(デフォルト)"); EnableImmediatePhysics.SettingChanged += OnImmediatePhysicsSettingChanged; Logger.LogInfo((object)"================================================="); Logger.LogInfo((object)"IKEASimulator_Fixer v1.0.0"); Logger.LogInfo((object)"REPOLib 3.x Compatibility Patch"); Logger.LogInfo((object)$"EnableImmediatePhysics: {EnableImmediatePhysics.Value}"); Logger.LogInfo((object)"================================================="); Harmony = new Harmony("sasnews.IKEASimulator_Fixer"); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "IKEASimulator") { Logger.LogWarning((object)"IKEASimulator already loaded - attempting late patch"); ApplyIKEAPatches(assembly); break; } } Logger.LogInfo((object)"Waiting for IKEASimulator to load..."); Logger.LogInfo((object)"================================================="); } private void OnAssemblyLoad(object? sender, AssemblyLoadEventArgs args) { if (args.LoadedAssembly.GetName().Name == "IKEASimulator") { Logger.LogInfo((object)"================================================="); Logger.LogInfo((object)"→ IKEASimulator.dll detected loading!"); Logger.LogInfo((object)"================================================="); ApplyIKEAPatches(args.LoadedAssembly); } } private void ApplyIKEAPatches(Assembly ikeaAssembly) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown if (_ikeaPatched) { Logger.LogInfo((object)"(Patches already applied)"); return; } try { Type type = ikeaAssembly.GetType("IKEASimulator.IKEASimulator"); if (type == null) { Logger.LogError((object)"Could not find IKEASimulator.IKEASimulator type!"); return; } Logger.LogInfo((object)"Applying critical patches BEFORE Awake executes..."); MethodInfo methodInfo = AccessTools.Method(type, "Awake", (Type[])null, (Type[])null); if (methodInfo != null) { HarmonyMethod val = new HarmonyMethod(typeof(IKEACriticalPatches), "Awake_Prefix", (Type[])null); Harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ IKEASimulator.Awake → COMPLETE TAKEOVER"); } else { Logger.LogError((object)" ✗ Could not find Awake method!"); } MethodInfo methodInfo2 = AccessTools.Method(type, "Start", (Type[])null, (Type[])null); if (methodInfo2 != null) { HarmonyMethod val2 = new HarmonyMethod(typeof(IKEACriticalPatches), "Start_Prefix", (Type[])null); Harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ IKEASimulator.Start → COMPLETE TAKEOVER"); } MethodInfo methodInfo3 = AccessTools.Method(type, "Patch", (Type[])null, (Type[])null); if (methodInfo3 != null) { HarmonyMethod val3 = new HarmonyMethod(typeof(IKEACriticalPatches), "Patch_Prefix", (Type[])null); Harmony.Patch((MethodBase)methodInfo3, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ IKEASimulator.Patch → BLOCKED (IL incompatible patches)"); } ApplyNetworkManagerPatches(ikeaAssembly); ApplySafetyPatches(); _ikeaPatched = true; Logger.LogInfo((object)"================================================="); Logger.LogInfo((object)"✓ All critical patches applied successfully!"); Logger.LogInfo((object)"================================================="); } catch (Exception arg) { Logger.LogError((object)$"Failed to apply patches: {arg}"); } } private void ApplyNetworkManagerPatches(Assembly ikeaAssembly) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown try { Type type = ikeaAssembly.GetType("IKEASimulator.NetworkManager"); if (type == null) { Logger.LogWarning((object)" NetworkManager type not found - skipping NM patches"); return; } MethodInfo methodInfo = AccessTools.Method(type, "OnCreatedRoom", (Type[])null, (Type[])null); if (methodInfo != null) { HarmonyMethod val = new HarmonyMethod(typeof(NetworkManagerPatches), "OnCreatedRoom_Prefix", (Type[])null); Harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ NetworkManager.OnCreatedRoom → Fixed"); } MethodInfo methodInfo2 = AccessTools.Method(type, "SingleplayerRoomData", (Type[])null, (Type[])null); if (methodInfo2 != null) { HarmonyMethod val2 = new HarmonyMethod(typeof(NetworkManagerPatches), "SingleplayerRoomData_Prefix", (Type[])null); Harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ NetworkManager.SingleplayerRoomData → Fixed"); } } catch (Exception ex) { Logger.LogWarning((object)(" NetworkManager patches partially failed: " + ex.Message)); } } private void ApplySafetyPatches() { try { ClientRoomDataPatches.ApplyPatches(Harmony); PathMapperPatches.ApplyPatches(Harmony); FurnitureConversionPatches.ApplyPatches(Harmony); DestructionSafetyPatches.ApplyPatches(Harmony); Harmony.CreateClassProcessor(typeof(ModuleSafetyPatch)).Patch(); Logger.LogInfo((object)" ✓ Module.Start safety finalizer"); Harmony.CreateClassProcessor(typeof(LevelGeneratorSafetyPatch)).Patch(); Logger.LogInfo((object)" ✓ LevelGenerator.ModuleGeneration safety finalizer"); } catch (Exception ex) { Logger.LogWarning((object)("Safety patches partially failed: " + ex.Message)); } } private void OnDestroy() { AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad; EnableImmediatePhysics.SettingChanged -= OnImmediatePhysicsSettingChanged; Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void OnImmediatePhysicsSettingChanged(object? sender, EventArgs e) { if (!EnableImmediatePhysics.Value) { Logger.LogInfo((object)"EnableImmediatePhysics disabled - new objects will be fixed until grabbed"); return; } Logger.LogInfo((object)"EnableImmediatePhysics enabled - enabling physics on all existing objects..."); try { Type type = AccessTools.TypeByName("IKEASimulator.PropsParenting"); if (type == null) { return; } FieldInfo fieldInfo = AccessTools.Field(type, "allowMovement"); if (!(fieldInfo == null)) { Object[] array = Object.FindObjectsOfType(type); int num = 0; Object[] array2 = array; foreach (Object obj in array2) { fieldInfo.SetValue(obj, true); num++; } Logger.LogInfo((object)$" ✓ Enabled physics on {num} objects"); } } catch (Exception ex) { Logger.LogWarning((object)("Failed to enable physics on existing objects: " + ex.Message)); } } } } namespace IKEASimulator_Fixer.Patches { public static class ClientRoomDataPatches { private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static void ApplyPatches(Harmony harmony) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown Type type = AccessTools.TypeByName("IKEASimulator.NetworkManager"); if (type != null) { MethodInfo methodInfo = AccessTools.Method(type, "OnJoinedRoom", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ClientRoomDataPatches), "OnJoinedRoom_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ NetworkManager.OnJoinedRoom → Patched"); } } } public static void OnJoinedRoom_Postfix(object __instance) { try { Logger.LogInfo((object)"[ClientRoomData] Joined Room. Checking for RoomData..."); MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return; } Type type = __instance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "roomData"); object? obj = fieldInfo?.GetValue(__instance); GameObject val2 = (GameObject)((obj is GameObject) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { return; } Logger.LogInfo((object)"[ClientRoomData] RoomData missing on Client. Instantiating locally..."); GameObject val3 = null; string prefabId = "managers/roomdata"; val3 = IKEACriticalPatches.GetPrefab(prefabId); if ((Object)(object)val3 == (Object)null) { foreach (KeyValuePair<string, GameObject> prefab in IKEACriticalPatches.Prefabs) { if (prefab.Key.ToLower().Contains("roomdata")) { val3 = prefab.Value; break; } } } if ((Object)(object)val3 != (Object)null) { GameObject val4 = Object.Instantiate<GameObject>(val3); fieldInfo?.SetValue(__instance, val4); Logger.LogInfo((object)("[ClientRoomData] RoomData instantiated: " + ((Object)val4).name)); Type type2 = AccessTools.TypeByName("IKEASimulator.PathMapper"); if (type2 != null) { Component component = val4.GetComponent(type2); AccessTools.Property(type, "PathMapper")?.SetValue(__instance, component); } } else { Logger.LogError((object)"[ClientRoomData] Failed to find RoomData prefab!"); } } catch (Exception arg) { Logger.LogError((object)$"OnJoinedRoom_Postfix error: {arg}"); } } } public static class DestructionSafetyPatches { private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static void ApplyPatches(Harmony harmony) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("PhysGrabObjectImpactDetector"); if (type != null) { MethodInfo methodInfo = AccessTools.Method(type, "BreakRPC", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DestructionSafetyPatches), "BreakRPC_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PhysGrabObjectImpactDetector.BreakRPC → Patched (Safety Wrapper)"); } MethodInfo methodInfo2 = AccessTools.Method(type, "DestroyObjectRPC", (Type[])null, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(DestructionSafetyPatches), "DestroyObjectRPC_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PhysGrabObjectImpactDetector.DestroyObjectRPC → Patched (Safety Wrapper)"); } } } catch (Exception arg) { Logger.LogError((object)$"DestructionSafetyPatches.ApplyPatches failed: {arg}"); } } public static bool BreakRPC_Prefix(object __instance, PhotonMessageInfo _info) { try { Component val = (Component)((__instance is Component) ? __instance : null); if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)"[Safety] BreakRPC skipped: instance is null or not a Component"); return false; } if ((Object)(object)val.gameObject == (Object)null) { Logger.LogWarning((object)"[Safety] BreakRPC skipped: gameObject is null"); return false; } return true; } catch (Exception ex) { Logger.LogError((object)("[Safety] BreakRPC_Prefix Error: " + ex.Message)); return false; } } public static bool DestroyObjectRPC_Prefix(object __instance, PhotonMessageInfo _info) { try { Component val = (Component)((__instance is Component) ? __instance : null); if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)"[Safety] DestroyObjectRPC skipped: instance is null or not a Component"); return false; } if ((Object)(object)val.gameObject == (Object)null) { Logger.LogWarning((object)"[Safety] DestroyObjectRPC skipped: gameObject is null"); return false; } return true; } catch (Exception ex) { Logger.LogError((object)("[Safety] DestroyObjectRPC_Prefix Error: " + ex.Message)); return false; } } } public static class FurnitureConversionPatches { [CompilerGenerated] private sealed class <EnableMovementAfterDelay>d__27 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public object propsParenting; public Type propsParentingType; private FieldInfo <allowMovementField>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnableMovementAfterDelay>d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <allowMovementField>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; try { <allowMovementField>5__1 = AccessTools.Field(propsParentingType, "allowMovement"); if (<allowMovementField>5__1 != null) { <allowMovementField>5__1.SetValue(propsParenting, true); } <allowMovementField>5__1 = null; } catch { } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RunPrefabSpawning>d__29 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public IEnumerator original; private List<Action> <spawnActions>5__1; private int <toSpawn>5__2; private object <pathMapper>5__3; private List<Action> <actionsToRun>5__4; private List<Action>.Enumerator <>s__5; private Action <action>5__6; private MethodInfo <clearMethod>5__7; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RunPrefabSpawning>d__29(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <spawnActions>5__1 = null; <pathMapper>5__3 = null; <actionsToRun>5__4 = null; <>s__5 = default(List<Action>.Enumerator); <action>5__6 = null; <clearMethod>5__7 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; goto IL_005d; case 1: <>1__state = -1; goto IL_005d; case 2: { <>1__state = -3; <action>5__6 = null; goto IL_0156; } IL_005d: if (original.MoveNext()) { <>2__current = original.Current; <>1__state = 1; return true; } <spawnActions>5__1 = GetSpawnActions(); <toSpawn>5__2 = GetToSpawn(); Logger.LogInfo((object)$"Furniture conversion: {<spawnActions>5__1?.Count ?? 0} actions, ToSpawn: {<toSpawn>5__2}"); if (<spawnActions>5__1 == null || <spawnActions>5__1.Count <= 0) { break; } <actionsToRun>5__4 = new List<Action>(<spawnActions>5__1); <spawnActions>5__1.Clear(); <>s__5 = <actionsToRun>5__4.GetEnumerator(); <>1__state = -3; goto IL_0156; IL_0156: if (<>s__5.MoveNext()) { <action>5__6 = <>s__5.Current; <action>5__6(); <>2__current = null; <>1__state = 2; return true; } <>m__Finally1(); <>s__5 = default(List<Action>.Enumerator); <actionsToRun>5__4 = null; break; } _spawnedField?.SetValue(null, 0); _toSpawnField?.SetValue(null, 0); <pathMapper>5__3 = GetPathMapper(); if (<pathMapper>5__3 != null) { <clearMethod>5__7 = AccessTools.Method(<pathMapper>5__3.GetType(), "ClearAllPaths", (Type[])null, (Type[])null); <clearMethod>5__7?.Invoke(<pathMapper>5__3, null); <clearMethod>5__7 = null; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>s__5).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static FieldInfo? _toSpawnField; private static FieldInfo? _spawnedField; private static FieldInfo? _spawnActionsField; private static FieldInfo? _furnitureLimitField; private static object? _cachedWrapper; private static bool _wrapperInitialized; private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static void ApplyPatches(Harmony harmony) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("IKEASimulator.IKEASimulator"); if (type != null) { _toSpawnField = AccessTools.Field(type, "ToSpawn"); _spawnedField = AccessTools.Field(type, "Spawned"); _spawnActionsField = AccessTools.Field(type, "SpawnActions"); _furnitureLimitField = AccessTools.Field(type, "FurnitureLimit"); Logger.LogInfo((object)$" IKEASimulator fields: ToSpawn={_toSpawnField != null}, SpawnActions={_spawnActionsField != null}"); } Type type2 = AccessTools.TypeByName("Module"); if (type2 != null) { MethodInfo methodInfo = AccessTools.Method(type2, "Start", (Type[])null, (Type[])null); if (methodInfo != null) { HarmonyMethod val = new HarmonyMethod(typeof(FurnitureConversionPatches), "ModuleStart_Prefix", (Type[])null); HarmonyMethod val2 = new HarmonyMethod(typeof(FurnitureConversionPatches), "ModuleStart_Postfix", (Type[])null); harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ Module.Start → Patched"); } } Type type3 = AccessTools.TypeByName("LevelGenerator"); if (type3 != null) { MethodInfo methodInfo2 = AccessTools.Method(type3, "ModuleGeneration", (Type[])null, (Type[])null); if (methodInfo2 != null) { HarmonyMethod val3 = new HarmonyMethod(typeof(FurnitureConversionPatches), "ModuleGeneration_Postfix", (Type[])null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ LevelGenerator.ModuleGeneration → Patched"); } } Type type4 = AccessTools.TypeByName("PhysGrabObject"); if (type4 != null) { MethodInfo methodInfo3 = AccessTools.Method(type4, "GrabStarted", (Type[])null, (Type[])null); if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(FurnitureConversionPatches), "PhysGrabObject_GrabStarted_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PhysGrabObject.GrabStarted → Patched"); } MethodInfo methodInfo4 = AccessTools.Method(type4, "GrabStartedRPC", (Type[])null, (Type[])null); if (methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(FurnitureConversionPatches), "PhysGrabObject_GrabStartedRPC_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PhysGrabObject.GrabStartedRPC → Patched"); } } } catch (Exception arg) { Logger.LogError((object)$"FurnitureConversionPatches.ApplyPatches failed: {arg}"); } } private static int GetToSpawn() { if (_toSpawnField != null) { return (int)_toSpawnField.GetValue(null); } return 0; } private static void SetToSpawn(int value) { _toSpawnField?.SetValue(null, value); } private static void IncrementToSpawn() { if (_toSpawnField != null) { int num = (int)_toSpawnField.GetValue(null); _toSpawnField.SetValue(null, num + 1); } } private static List<Action>? GetSpawnActions() { if (_spawnActionsField != null) { return _spawnActionsField.GetValue(null) as List<Action>; } return null; } private static int GetFurnitureLimit() { if (_furnitureLimitField != null) { object value = _furnitureLimitField.GetValue(null); if (value != null) { PropertyInfo propertyInfo = AccessTools.Property(value.GetType(), "Value"); if (propertyInfo != null) { return (int)(propertyInfo.GetValue(value) ?? ((object)(-1))); } } } return -1; } public static void PhysGrabObject_GrabStarted_Postfix(object __instance) { try { if (IsMultiplayer()) { return; } Component val = (Component)((__instance is Component) ? __instance : null); if (!((Object)(object)val != (Object)null)) { return; } Type type = AccessTools.TypeByName("IKEASimulator.PropsParenting"); if (type != null) { Component component = val.gameObject.GetComponent(type); if ((Object)(object)component != (Object)null) { AccessTools.Method(type, "OnGrabStarted", (Type[])null, (Type[])null)?.Invoke(component, null); } } } catch { } } public static void PhysGrabObject_GrabStartedRPC_Postfix(object __instance) { try { Component val = (Component)((__instance is Component) ? __instance : null); if (!((Object)(object)val != (Object)null)) { return; } Type type = AccessTools.TypeByName("IKEASimulator.PropsParenting"); if (type != null) { Component component = val.gameObject.GetComponent(type); if ((Object)(object)component != (Object)null) { AccessTools.Method(type, "OnGrabStarted", (Type[])null, (Type[])null)?.Invoke(component, null); } } } catch { } } private static bool IsMasterClientOrSingleplayer() { try { Type type = AccessTools.TypeByName("SemiFunc"); MethodInfo methodInfo = AccessTools.Method(type, "IsMasterClientOrSingleplayer", (Type[])null, (Type[])null); if (methodInfo != null) { return (bool)methodInfo.Invoke(null, null); } } catch { } return true; } private static bool RunIsLevel() { try { Type type = AccessTools.TypeByName("SemiFunc"); MethodInfo methodInfo = AccessTools.Method(type, "RunIsLevel", (Type[])null, (Type[])null); if (methodInfo != null) { return (bool)methodInfo.Invoke(null, null); } } catch { } return false; } private static bool IsMultiplayer() { try { Type type = AccessTools.TypeByName("SemiFunc"); MethodInfo methodInfo = AccessTools.Method(type, "IsMultiplayer", (Type[])null, (Type[])null); if (methodInfo != null) { return (bool)methodInfo.Invoke(null, null); } } catch { } return false; } private static object? GetWrapper() { if (_wrapperInitialized) { return _cachedWrapper; } _wrapperInitialized = true; try { GameObject prefab = IKEACriticalPatches.GetPrefab("FurnitureWrapper"); if ((Object)(object)prefab != (Object)null) { Type type = AccessTools.TypeByName("ValuableObject"); if (type != null) { _cachedWrapper = prefab.GetComponent(type); if (_cachedWrapper != null) { Logger.LogInfo((object)" FurnitureWrapper obtained from cache"); return _cachedWrapper; } } } Logger.LogWarning((object)" FurnitureWrapper not found in cache"); } catch (Exception ex) { Logger.LogError((object)("GetWrapper error: " + ex.Message)); } return null; } private static object? GetNetworkManager() { return IKEACriticalPatches.CachedNetworkManager; } private static object? GetPathMapper() { object networkManager = GetNetworkManager(); if (networkManager == null) { return null; } try { return AccessTools.Property(networkManager.GetType(), "PathMapper")?.GetValue(networkManager); } catch { } return null; } public static void ModuleStart_Prefix(object __instance) { try { bool flag = IsMasterClientOrSingleplayer(); bool flag2 = RunIsLevel(); MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); string text = ((val != null) ? ((Object)val).name : null) ?? "unknown"; if ((Object)(object)val != (Object)null) { string text2 = ((Object)val).name; Transform parent = ((Component)val).transform.parent; while ((Object)(object)parent != (Object)null) { text2 = ((Object)parent).name + "/" + text2; parent = parent.parent; } Logger.LogInfo((object)("[Prefix] Module: " + text + ", FullPath: " + text2)); if (!flag && flag2 && (Object)(object)((Component)val).transform.parent == (Object)null) { GameObject val2 = GameObject.Find("Level Generator"); if ((Object)(object)val2 != (Object)null) { Transform val3 = val2.transform.Find("Level"); if ((Object)(object)val3 != (Object)null) { ((Component)val).transform.SetParent(val3, true); Logger.LogInfo((object)(" [Fix] Reparented " + text + " to Level Generator/Level")); } } } } Logger.LogInfo((object)$"[Prefix] Module: {text}, IsMaster: {flag}, RunIsLevel: {flag2}"); if (!flag2 || (Object)(object)val == (Object)null) { return; } if (!IsMultiplayer()) { object networkManager = GetNetworkManager(); if (networkManager != null) { AccessTools.Method(networkManager.GetType(), "SingleplayerRoomData", (Type[])null, (Type[])null)?.Invoke(networkManager, null); } } Type type = AccessTools.TypeByName("IKEASimulator.PropSwitchContext"); if (type == null) { return; } Component val4 = ((Component)val).gameObject.AddComponent(type); if ((Object)(object)val4 == (Object)null) { return; } AccessTools.Field(type, "ModuleName")?.SetValue(val4, ((Object)val).name); if (!flag) { return; } object pathMapper = GetPathMapper(); if (pathMapper != null) { MethodInfo methodInfo = AccessTools.Method(pathMapper.GetType(), "MapPath", (Type[])null, (Type[])null); if (methodInfo != null) { object value = methodInfo.Invoke(pathMapper, new object[1] { ((Object)val).name }); AccessTools.Field(type, "PathId")?.SetValue(val4, value); } } else { object networkManager2 = GetNetworkManager(); Logger.LogWarning((object)(" [Prefix] PathMapper is null! NetworkManager: " + ((networkManager2 != null) ? "found" : "NULL"))); } } catch (Exception ex) { Logger.LogWarning((object)("ModuleStart_Prefix error: " + ex.Message)); } } public static void ModuleStart_Postfix(object __instance) { //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Expected O, but got Unknown //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Expected O, but got Unknown //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) try { bool flag = IsMasterClientOrSingleplayer(); bool flag2 = RunIsLevel(); MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); string arg = ((val != null) ? ((Object)val).name : null) ?? "unknown"; Logger.LogInfo((object)$"[Postfix] Module: {arg}, IsMaster: {flag}, RunIsLevel: {flag2}"); if (!flag2 || (Object)(object)val == (Object)null) { return; } object wrapper = GetWrapper(); if (wrapper == null) { Logger.LogWarning((object)"FurnitureWrapper not found"); return; } Type type = AccessTools.TypeByName("IKEASimulator.PropSwitchContext"); if (type == null) { Logger.LogWarning((object)"PropSwitchContext type not found"); return; } Component component = ((Component)val).gameObject.GetComponent(type); if ((Object)(object)component == (Object)null) { Logger.LogWarning((object)("PropSwitchContext not found on " + ((Object)val).name)); return; } FieldInfo fieldInfo = AccessTools.Field(type, "ModuleName"); FieldInfo fieldInfo2 = AccessTools.Field(type, "PathId"); string text = fieldInfo?.GetValue(component) as string; int? num = fieldInfo2?.GetValue(component) as int?; if (text == null) { Logger.LogWarning((object)" ModuleName is null, skipping"); return; } if (flag && !num.HasValue) { Logger.LogWarning((object)" PathId is null on Master, skipping spawn"); return; } Type type2 = AccessTools.TypeByName("IKEASimulator.PropUtils"); if (type2 != null) { AccessTools.Field(type2, "ModuleName")?.SetValue(null, text); AccessTools.Field(type2, "PathId")?.SetValue(null, num); } Transform val2 = null; foreach (Transform item in ((Component)val).transform) { Transform val3 = item; if (((Object)val3).name.Contains(" Props ") && ((Object)val3).name.StartsWith("-") && ((Object)val3).name.EndsWith("-")) { val2 = val3; break; } } if ((Object)(object)val2 == (Object)null) { return; } Transform val4 = null; foreach (Transform item2 in val2) { Transform val5 = item2; if (((Object)val5).name == "Props") { val4 = val5; break; } } if ((Object)(object)val4 == (Object)null) { return; } int furnitureLimit = GetFurnitureLimit(); int num2 = 0; List<Action> list = null; if (flag) { list = GetSpawnActions(); if (list == null) { return; } } GameObject wrapperPrefab = IKEACriticalPatches.GetPrefab("FurnitureWrapper"); if ((Object)(object)wrapperPrefab == (Object)null) { return; } foreach (Transform item3 in val4) { Transform val6 = item3; if (furnitureLimit != -1 && GetToSpawn() >= furnitureLimit) { break; } if (!HasValidCollider(val6) || !HasMeshRenderer(val6)) { continue; } IncrementToSpawn(); num2++; string propName = ((Object)val6).name; Vector3 position = val6.position; Quaternion rotation = val6.rotation; if (!flag || !num.HasValue) { continue; } int capturedPathId = num.Value; list?.Add(delegate { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) try { SpawnFurnitureWrapper(wrapperPrefab, position, rotation, capturedPathId, propName); } catch (Exception ex2) { Logger.LogWarning((object)("Spawn error for " + propName + ": " + ex2.Message)); } }); } if (num2 > 0) { Logger.LogInfo((object)$"Found {num2} Props in {text} (Disabled)"); } } catch (Exception ex) { Logger.LogWarning((object)("ModuleStart_Postfix error: " + ex.Message)); } } private static bool HasValidCollider(Transform transform) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown MeshCollider component = ((Component)transform).GetComponent<MeshCollider>(); if ((Object)(object)component != (Object)null && !component.convex) { return false; } foreach (Transform item in transform) { Transform val = item; MeshCollider component2 = ((Component)val).GetComponent<MeshCollider>(); if ((Object)(object)component2 != (Object)null && !component2.convex) { return false; } } if ((Object)(object)((Component)transform).GetComponent<BoxCollider>() != (Object)null || (Object)(object)((Component)transform).GetComponent<SphereCollider>() != (Object)null || (Object)(object)((Component)transform).GetComponent<CapsuleCollider>() != (Object)null) { if (transform.childCount <= 0) { return true; } foreach (Transform item2 in transform) { Transform transform2 = item2; if (HasValidCollider(transform2)) { return true; } } } foreach (Transform item3 in transform) { Transform transform3 = item3; if (HasValidCollider(transform3)) { return true; } } return false; } private static bool HasMeshRenderer(Transform transform) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if ((Object)(object)((Component)transform).GetComponent<MeshRenderer>() != (Object)null) { return true; } foreach (Transform item in transform) { Transform transform2 = item; if (HasMeshRenderer(transform2)) { return true; } } return false; } private static void SpawnFurnitureWrapper(GameObject prefab, Vector3 position, Quaternion rotation, int pathId, string propName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = IKEACriticalPatches.SpawnPrefab("furniturewrapper", position, rotation); if ((Object)(object)val == (Object)null) { val = Object.Instantiate<GameObject>(prefab, position, rotation); Logger.LogDebug((object)" FurnitureWrapper spawned via direct Instantiate (fallback)"); } if (!((Object)(object)val != (Object)null)) { return; } Type type = AccessTools.TypeByName("IKEASimulator.PropsParenting"); if (type != null) { Component component = val.GetComponent(type); if ((Object)(object)component != (Object)null) { Type type2 = AccessTools.TypeByName("Photon.Pun.PhotonView"); Component val2 = ((type2 != null) ? val.GetComponent(type2) : null); bool flag = false; if ((Object)(object)val2 != (Object)null && IsMultiplayer()) { MethodInfo methodInfo = AccessTools.Method(type2, "RPC", new Type[3] { typeof(string), typeof(RpcTarget), typeof(object[]) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(val2, new object[3] { "SetPropPathRPC", (object)(RpcTarget)0, new object[2] { pathId, propName } }); flag = true; Logger.LogInfo((object)(" [Spawn] Sent SetPropPathRPC(All) for " + propName)); } } if (!flag) { MethodInfo methodInfo2 = AccessTools.Method(type, "SetPropPathRPC", (Type[])null, (Type[])null); if (methodInfo2 != null) { methodInfo2.Invoke(component, new object[2] { pathId, propName }); Logger.LogDebug((object)(" [Spawn] Invoked SetPropPathRPC (Direct) for " + propName)); } } if (IKEASimulator_Fixer.EnableImmediatePhysics.Value) { MonoBehaviour val3 = (MonoBehaviour)(object)((component is MonoBehaviour) ? component : null); if ((Object)(object)val3 != (Object)null) { val3.StartCoroutine(EnableMovementAfterDelay(component, type)); } } } } if (_spawnedField != null) { int num = (int)_spawnedField.GetValue(null); _spawnedField.SetValue(null, num + 1); } } catch (Exception ex) { Logger.LogWarning((object)("SpawnFurnitureWrapper error: " + ex.Message)); } } [IteratorStateMachine(typeof(<EnableMovementAfterDelay>d__27))] private static IEnumerator EnableMovementAfterDelay(object propsParenting, Type propsParentingType) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnableMovementAfterDelay>d__27(0) { propsParenting = propsParenting, propsParentingType = propsParentingType }; } public static void ModuleGeneration_Postfix(object __instance, ref IEnumerator __result) { __result = RunPrefabSpawning(__result); } [IteratorStateMachine(typeof(<RunPrefabSpawning>d__29))] private static IEnumerator RunPrefabSpawning(IEnumerator original) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RunPrefabSpawning>d__29(0) { original = original }; } } public static class PathMapperPatches { public const byte MapPathEventCode = 142; private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static void ApplyPatches(Harmony harmony) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("IKEASimulator.PathMapper"); if (type == null) { Logger.LogWarning((object)" ✗ PathMapper type not found"); return; } MethodInfo methodInfo = AccessTools.Method(type, "Start", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(PathMapperPatches), "Start_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PathMapper.Start → Patched (Event Register)"); } MethodInfo methodInfo2 = AccessTools.Method(type, "OnDestroy", (Type[])null, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(PathMapperPatches), "OnDestroy_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PathMapper.OnDestroy → Patched"); } MethodInfo methodInfo3 = AccessTools.Method(type, "MapPath", (Type[])null, (Type[])null); if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(PathMapperPatches), "MapPath_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)" ✓ PathMapper.MapPath → Patched (Event Raise)"); } } catch (Exception arg) { Logger.LogError((object)$"PathMapperPatches.ApplyPatches failed: {arg}"); } } public static bool MapPath_Prefix(object __instance, string path, ref int __result) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) try { Type type = __instance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "nextPathId"); FieldInfo fieldInfo2 = AccessTools.Field(type, "pathMap"); if (fieldInfo == null || fieldInfo2 == null) { return true; } int num = (int)fieldInfo.GetValue(__instance); if (fieldInfo2.GetValue(__instance) is IDictionary dictionary) { dictionary[num] = path; Logger.LogDebug((object)$"[PathMapper.MapPath] Added: {num} → {path}"); if (PhotonNetwork.InRoom) { object[] array = new object[2] { num, path }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0, CachingOption = (EventCaching)4 }; PhotonNetwork.RaiseEvent((byte)142, (object)array, val, SendOptions.SendReliable); } } fieldInfo.SetValue(__instance, num + 1); __result = num; return false; } catch (Exception ex) { Logger.LogWarning((object)("[PathMapper.MapPath] Error: " + ex.Message)); return true; } } public static bool Start_Prefix(object __instance) { try { PhotonNetwork.NetworkingClient.EventReceived += OnEvent; object cachedNetworkManager = IKEACriticalPatches.CachedNetworkManager; if (cachedNetworkManager == null) { return false; } PropertyInfo propertyInfo = AccessTools.Property(cachedNetworkManager.GetType(), "PathMapper"); if (propertyInfo != null) { propertyInfo.SetValue(cachedNetworkManager, __instance); Logger.LogInfo((object)" [PathMapper] Configured NetworkManager.PathMapper reference"); } else { Logger.LogWarning((object)" [PathMapper] Could not find PathMapper property on NetworkManager!"); } Component val = (Component)((__instance is Component) ? __instance : null); if ((Object)(object)val == (Object)null) { return false; } MethodInfo methodInfo = AccessTools.Method(cachedNetworkManager.GetType(), "SetRoomData", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(cachedNetworkManager, new object[1] { val.gameObject }); } Object.DontDestroyOnLoad((Object)(object)val.gameObject); return false; } catch (Exception) { return false; } } public static bool OnDestroy_Prefix() { try { PhotonNetwork.NetworkingClient.EventReceived -= OnEvent; return false; } catch { return false; } } private static void OnEvent(EventData photonEvent) { if (photonEvent.Code != 142) { return; } try { object[] array = (object[])photonEvent.CustomData; int num = (int)array[0]; string value = (string)array[1]; object cachedNetworkManager = IKEACriticalPatches.CachedNetworkManager; if (cachedNetworkManager != null) { object obj = AccessTools.Property(cachedNetworkManager.GetType(), "PathMapper")?.GetValue(cachedNetworkManager); if (obj != null && AccessTools.Field(obj.GetType(), "pathMap")?.GetValue(obj) is IDictionary dictionary) { dictionary[num] = value; } } } catch (Exception ex) { Logger.LogWarning((object)("OnEvent error: " + ex.Message)); } } } [HarmonyPatch(typeof(Harmony), "PatchAll", new Type[] { typeof(Assembly) })] internal static class HarmonyPatchAllFinalizer { private static bool _patchesApplied; [HarmonyPrefix] private static bool Prefix(Harmony __instance, Assembly assembly) { if (assembly == null) { return true; } string text = assembly.GetName().Name ?? ""; if (text == "IKEASimulator" || text.Contains("IKEASimulator")) { IKEASimulator_Fixer.Logger.LogInfo((object)"================================================="); IKEASimulator_Fixer.Logger.LogInfo((object)"→ Intercepted IKEASimulator Harmony.PatchAll()"); IKEASimulator_Fixer.Logger.LogInfo((object)" SKIPPING all IKEASimulator patches (IL incompatible)"); if (!_patchesApplied) { IKEASimulator_Fixer.Logger.LogInfo((object)" Applying REPOLib 3.x compatible patches..."); try { IKEASimulator_Fixer.Logger.LogInfo((object)" ✓ Patches handled by Fixer!"); _patchesApplied = true; } catch (Exception ex) { IKEASimulator_Fixer.Logger.LogError((object)(" ✗ Failed to apply patches: " + ex.Message)); IKEASimulator_Fixer.Logger.LogDebug((object)ex.ToString()); } } else { IKEASimulator_Fixer.Logger.LogInfo((object)" (Patches already applied)"); } IKEASimulator_Fixer.Logger.LogInfo((object)"================================================="); return false; } return true; } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, Harmony __instance, Assembly assembly) { if (__exception != null) { string text = assembly?.GetName().Name ?? "unknown"; if (text.Contains("IKEASimulator")) { IKEASimulator_Fixer.Logger.LogWarning((object)"================================================="); IKEASimulator_Fixer.Logger.LogWarning((object)"⊗ Suppressed Harmony.PatchAll() error from IKEASimulator"); IKEASimulator_Fixer.Logger.LogInfo((object)(" → Error: " + __exception.Message)); IKEASimulator_Fixer.Logger.LogWarning((object)"================================================="); return null; } } return __exception; } } public static class IKEACriticalPatches { private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static AssetBundle? LoadedBundle { get; private set; } public static Dictionary<string, GameObject> Prefabs { get; } = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase); public static Dictionary<string, object> PrefabRefs { get; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); public static object? IKEAInstance { get; private set; } public static bool Initialized { get; private set; } public static object? CachedNetworkManager { get; private set; } public static GameObject? ManagerInstance { get; private set; } public static bool Awake_Prefix(object __instance) { try { Logger.LogInfo((object)"=== IKEASimulator Fixer: Awake Override ==="); IKEAInstance = __instance; Type type = __instance.GetType(); PropertyInfo propertyInfo = AccessTools.Property(type, "Instance"); if (propertyInfo != null && propertyInfo.GetSetMethod(nonPublic: true) != null) { propertyInfo.SetValue(null, __instance); Logger.LogInfo((object)" ✓ IKEASimulator.Instance set"); } else { FieldInfo fieldInfo = AccessTools.Field(type, "<Instance>k__BackingField"); if (fieldInfo != null) { fieldInfo.SetValue(null, __instance); Logger.LogInfo((object)" ✓ IKEASimulator.Instance set (via backing field)"); } } ConfigureLogging(__instance); LoadAssetBundleSafe(__instance); if ((Object)(object)LoadedBundle != (Object)null) { RegisterAllResources(); } SetInstanceFields(__instance); Initialized = true; Logger.LogInfo((object)"=== Awake Override Complete ==="); return false; } catch (Exception arg) { Logger.LogError((object)$"Awake_Prefix error: {arg}"); return false; } } public static bool Start_Prefix(object __instance) { try { Logger.LogInfo((object)"=== IKEASimulator Fixer: Start Override ==="); Component val = (Component)((__instance is Component) ? __instance : null); if ((Object)(object)val == (Object)null) { Logger.LogError((object)" Instance is not a Component!"); return false; } string prefabId = "managers/ikeasimulatormanager"; GameObject prefab = GetPrefab(prefabId); if ((Object)(object)prefab == (Object)null) { foreach (KeyValuePair<string, GameObject> prefab2 in Prefabs) { if (prefab2.Key.Contains("manager") || prefab2.Key.Contains("ikeasimulator")) { Logger.LogDebug((object)(" Available prefab: " + prefab2.Key)); } } Logger.LogWarning((object)" IKEASimulatorManager prefab not found in cache"); Logger.LogWarning((object)" NetworkManager will not be initialized - some features may not work"); return false; } GameObject val2 = Object.Instantiate<GameObject>(prefab, val.transform); if ((Object)(object)val2 != (Object)null) { ManagerInstance = val2; Type type = AccessTools.TypeByName("IKEASimulator.NetworkManager"); if (type != null) { Component val3 = (Component)(CachedNetworkManager = val2.GetComponent(type)); Type type2 = __instance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type2, "networkManager"); if (fieldInfo != null && (Object)(object)val3 != (Object)null) { fieldInfo.SetValue(__instance, val3); Logger.LogInfo((object)" ✓ NetworkManager component obtained and cached"); } else { Logger.LogWarning((object)$" NetworkManager setup: nmField={fieldInfo != null}, nmComponent={(Object)(object)val3 != (Object)null}"); } } val2.transform.parent = null; ((Object)val2).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val2); Logger.LogInfo((object)" ✓ IKEASimulatorManager instantiated locally"); } Logger.LogInfo((object)"Initializing IKEASimulator Mod (via Fixer)"); Logger.LogInfo((object)"=== Start Override Complete ==="); return false; } catch (Exception arg) { Logger.LogError((object)$"Start_Prefix error: {arg}"); return false; } } public static bool Patch_Prefix() { Logger.LogInfo((object)" → Skipping IKEASimulator.Patch() (IL incompatible with REPOLib 3.x)"); return false; } private static void ConfigureLogging(object instance) { try { Logger.LogInfo((object)" ✓ Logging configured via BepInEx"); } catch (Exception ex) { Logger.LogDebug((object)("ConfigureLogging: " + ex.Message)); } } private static void LoadAssetBundleSafe(object instance) { try { BaseUnityPlugin val = (BaseUnityPlugin)((instance is BaseUnityPlugin) ? instance : null); if ((Object)(object)val == (Object)null) { return; } string location = val.Info.Location; string path = Path.GetDirectoryName(location) ?? ""; string text = Path.Combine(path, "IKEASimulator.bundle"); Logger.LogInfo((object)(" Loading bundle: " + text)); if (!File.Exists(text)) { Logger.LogError((object)" ✗ Bundle file not found!"); return; } if ((Object)(object)LoadedBundle != (Object)null) { Logger.LogInfo((object)" Bundle already loaded"); return; } LoadedBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)LoadedBundle != (Object)null) { Logger.LogInfo((object)" ✓ AssetBundle loaded successfully"); } else { Logger.LogError((object)" ✗ AssetBundle.LoadFromFile returned null"); } } catch (Exception arg) { Logger.LogError((object)$"LoadAssetBundleSafe error: {arg}"); } } private static void RegisterAllResources() { Logger.LogInfo((object)" Registering resources with REPOLib 3.x..."); Type type = AccessTools.TypeByName("REPOLib.Modules.NetworkPrefabs"); Type type2 = AccessTools.TypeByName("REPOLib.Modules.Valuables"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "RegisterNetworkPrefab", new Type[2] { typeof(string), typeof(GameObject) }, (Type[])null) : null); MethodInfo methodInfo2 = ((type2 != null) ? AccessTools.Method(type2, "RegisterValuable", new Type[1] { typeof(GameObject) }, (Type[])null) : null); Logger.LogInfo((object)" REPOLib API:"); Logger.LogInfo((object)(" NetworkPrefabs.RegisterNetworkPrefab: " + ((methodInfo != null) ? "✓" : "✗"))); Logger.LogInfo((object)(" Valuables.RegisterValuable: " + ((methodInfo2 != null) ? "✓" : "✗"))); if ((Object)(object)LoadedBundle == (Object)null) { return; } string[] allAssetNames = LoadedBundle.GetAllAssetNames(); foreach (string text in allAssetNames) { if (text.EndsWith(".prefab")) { GameObject val = LoadedBundle.LoadAsset<GameObject>(text); if ((Object)(object)val != (Object)null && (text.Contains("/valuables/") || text.Contains("/assets/")) && !text.ToLowerInvariant().Contains("manager") && !text.ToLowerInvariant().Contains("roomdata")) { OptimizeNetworkPrefab(val, text); } } } string[] allAssetNames2 = LoadedBundle.GetAllAssetNames(); int num = 0; int num2 = 0; string[] array = allAssetNames2; foreach (string text2 in array) { try { if (!text2.EndsWith(".prefab")) { continue; } GameObject val2 = LoadedBundle.LoadAsset<GameObject>(text2); if ((Object)(object)val2 == (Object)null) { continue; } string text3 = ExtractPrefabId(text2); if (text2.Contains("/assets/") && methodInfo != null) { try { object obj = methodInfo.Invoke(null, new object[2] { text3, val2 }); Prefabs[text3] = val2; if (obj != null) { PrefabRefs[text3] = obj; num++; } } catch (TargetInvocationException ex) { Logger.LogDebug((object)(" " + text3 + ": " + ex.InnerException?.Message)); Prefabs[text3] = val2; } } else { if (!text2.Contains("/valuables/") || !(methodInfo2 != null)) { continue; } try { methodInfo2.Invoke(null, new object[1] { val2 }); num2++; string text4 = ((Object)val2).name.ToLowerInvariant(); Prefabs[text4] = val2; if (!(text4 == "furniturewrapper") || !(methodInfo != null)) { continue; } try { object obj2 = methodInfo.Invoke(null, new object[2] { text4, val2 }); if (obj2 != null) { PrefabRefs[text4] = obj2; Logger.LogInfo((object)(" Cached valuable as NetworkPrefab: " + text4)); } } catch (Exception ex2) { Logger.LogDebug((object)(" FurnitureWrapper NetworkPrefab registration: " + ex2.Message)); } } catch (TargetInvocationException ex3) { Logger.LogDebug((object)(" Valuable " + ((Object)val2).name + ": " + ex3.InnerException?.Message)); } continue; } } catch (Exception ex4) { Logger.LogDebug((object)(" Error processing " + text2 + ": " + ex4.Message)); } } Logger.LogInfo((object)" Registration results:"); Logger.LogInfo((object)$" Network Prefabs: {num} registered, {Prefabs.Count} cached"); Logger.LogInfo((object)$" Valuables: {num2}"); } private static string ExtractPrefabId(string assetPath) { int num = assetPath.IndexOf("/assets/", StringComparison.OrdinalIgnoreCase); if (num >= 0 && num + 8 < assetPath.Length) { string text = assetPath.Substring(num + 8); return text.Replace(".prefab", ""); } return Path.GetFileNameWithoutExtension(assetPath); } private static void SetInstanceFields(object instance) { try { Type type = instance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "assetBundle"); if (fieldInfo != null) { fieldInfo.SetValue(instance, LoadedBundle); } FieldInfo fieldInfo2 = AccessTools.Field(type, "prefabs"); if (fieldInfo2 != null) { fieldInfo2.SetValue(instance, Prefabs); } Logger.LogInfo((object)" ✓ Instance fields configured"); } catch (Exception ex) { Logger.LogDebug((object)("SetInstanceFields: " + ex.Message)); } } public static GameObject? GetPrefab(string prefabId) { string text = prefabId?.ToLowerInvariant() ?? ""; if (Prefabs.TryGetValue(text, out GameObject value)) { return value; } foreach (KeyValuePair<string, GameObject> prefab in Prefabs) { if (prefab.Key.EndsWith(text) || prefab.Key.EndsWith("/" + text)) { return prefab.Value; } } return null; } public static GameObject? SpawnPrefab(string prefabId, Vector3 position, Quaternion rotation) { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) try { string text = prefabId?.ToLowerInvariant() ?? ""; if (PrefabRefs.TryGetValue(text, out object value)) { Type type = AccessTools.TypeByName("REPOLib.Modules.NetworkPrefabs"); if (type != null) { MethodInfo methodInfo = AccessTools.Method(type, "SpawnNetworkPrefab", new Type[5] { value.GetType(), typeof(Vector3), typeof(Quaternion), typeof(byte), typeof(object[]) }, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(null, new object[5] { value, position, rotation, (byte)0, null }); if (obj != null) { Logger.LogInfo((object)(" [Spawn] Networked Spawn Success: " + text)); return (GameObject?)((obj is GameObject) ? obj : null); } } } } Logger.LogWarning((object)(" [Spawn] Falling back to Local Instantiation for " + text)); GameObject prefab = GetPrefab(text); if ((Object)(object)prefab != (Object)null) { GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation); if ((Object)(object)val != (Object)null) { Type type2 = AccessTools.TypeByName("Photon.Pun.PhotonView"); if (type2 != null) { } Logger.LogInfo((object)$" [Spawn] Local Instantiated: {((Object)val).name} at {position}"); return val; } } Logger.LogWarning((object)(" SpawnPrefab failed for '" + prefabId + "'")); return null; } catch (Exception arg) { Logger.LogError((object)$"SpawnPrefab error for {prefabId}: {arg}"); return null; } } private static void OptimizeNetworkPrefab(GameObject prefab, string prefabName) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) try { PhotonView val2 = prefab.GetComponent<PhotonView>(); if ((Object)(object)val2 == (Object)null) { val2 = prefab.AddComponent<PhotonView>(); Logger.LogDebug((object)(" [Optimize] Added PhotonView to " + ((Object)prefab).name)); } PhotonTransformView val3 = prefab.GetComponent<PhotonTransformView>(); if ((Object)(object)val3 == (Object)null) { val3 = prefab.AddComponent<PhotonTransformView>(); Logger.LogDebug((object)(" [Optimize] Added PhotonTransformView to " + ((Object)prefab).name)); } SetBool(val3, "m_SynchronizePosition", val: true); SetBool(val3, "m_SynchronizeRotation", val: true); if (!val2.ObservedComponents.Contains((Component)(object)val3)) { val2.ObservedComponents.Add((Component)(object)val3); val2.Synchronization = (ViewSynchronization)3; } Logger.LogInfo((object)$" [Optimize] Configured {((Object)prefab).name}: PV={(Object)(object)val2 != (Object)null}, PTV={(Object)(object)val3 != (Object)null}"); } catch (Exception ex) { Logger.LogWarning((object)(" [Optimize] Failed to optimize " + ((Object)prefab).name + ": " + ex.Message)); } static void SetBool(object target, string name, bool val) { FieldInfo fieldInfo = AccessTools.Field(target.GetType(), name); if (fieldInfo != null) { fieldInfo.SetValue(target, val); } } } } public static class NetworkManagerPatches { [CompilerGenerated] private sealed class <InstantiateRoomDataFixed>d__4 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public object networkManager; private Type <photonNetworkType>5__1; private bool <isMasterClient>5__2; private Type <nmType>5__3; private FieldInfo <roomDataField>5__4; private GameObject <existingRoomData>5__5; private FieldInfo <retryCountField>5__6; private int <retryCount>5__7; private PropertyInfo <isMasterClientProp>5__8; private GameObject <roomData>5__9; private Type <pathMapperType>5__10; private Component <pathMapperComponent>5__11; private PropertyInfo <pathMapperProp>5__12; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InstantiateRoomDataFixed>d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <photonNetworkType>5__1 = null; <nmType>5__3 = null; <roomDataField>5__4 = null; <existingRoomData>5__5 = null; <retryCountField>5__6 = null; <isMasterClientProp>5__8 = null; <roomData>5__9 = null; <pathMapperType>5__10 = null; <pathMapperComponent>5__11 = null; <pathMapperProp>5__12 = null; <>1__state = -2; } private bool MoveNext() { //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <photonNetworkType>5__1 = AccessTools.TypeByName("Photon.Pun.PhotonNetwork"); <isMasterClient>5__2 = false; if (<photonNetworkType>5__1 != null) { <isMasterClientProp>5__8 = AccessTools.Property(<photonNetworkType>5__1, "IsMasterClient"); if (<isMasterClientProp>5__8 != null) { <isMasterClient>5__2 = (bool)(<isMasterClientProp>5__8.GetValue(null) ?? ((object)false)); } <isMasterClientProp>5__8 = null; } if (!<isMasterClient>5__2) { return false; } <nmType>5__3 = networkManager.GetType(); <roomDataField>5__4 = AccessTools.Field(<nmType>5__3, "roomData"); ref GameObject reference = ref <existingRoomData>5__5; object? obj = <roomDataField>5__4?.GetValue(networkManager); reference = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)<existingRoomData>5__5 != (Object)null) { return false; } <retryCountField>5__6 = AccessTools.Field(<nmType>5__3, "retryCount"); <retryCount>5__7 = (int)(<retryCountField>5__6?.GetValue(networkManager) ?? ((object)0)); break; } case 1: <>1__state = -1; <roomData>5__9 = null; break; } if (<retryCount>5__7 < 5) { <roomData>5__9 = InstantiateRoomDataLocal(); if ((Object)(object)<roomData>5__9 != (Object)null) { <roomDataField>5__4?.SetValue(networkManager, <roomData>5__9); <pathMapperType>5__10 = AccessTools.TypeByName("IKEASimulator.PathMapper"); if (<pathMapperType>5__10 != null) { <pathMapperComponent>5__11 = <roomData>5__9.GetComponent(<pathMapperType>5__10); <pathMapperProp>5__12 = AccessTools.Property(<nmType>5__3, "PathMapper"); <pathMapperProp>5__12?.SetValue(networkManager, <pathMapperComponent>5__11); <pathMapperComponent>5__11 = null; <pathMapperProp>5__12 = null; } Logger.LogDebug((object)" InstantiateRoomData: RoomData instantiated locally"); return false; } <retryCount>5__7++; <retryCountField>5__6?.SetValue(networkManager, <retryCount>5__7); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } Logger.LogWarning((object)" InstantiateRoomData: Failed to create RoomData after 5 retries"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static ManualLogSource Logger => IKEASimulator_Fixer.Logger; public static bool OnCreatedRoom_Prefix(object __instance) { try { Logger.LogDebug((object)"NetworkManager.OnCreatedRoom intercepted"); MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } val.StartCoroutine(InstantiateRoomDataFixed(__instance)); return false; } catch (Exception arg) { Logger.LogError((object)$"OnCreatedRoom_Prefix error: {arg}"); return false; } } public static bool SingleplayerRoomData_Prefix(object __instance) { try { Logger.LogDebug((object)"NetworkManager.SingleplayerRoomData intercepted"); Type type = __instance.GetType(); AccessTools.Field(type, "isSingleplayer")?.SetValue(__instance, true); FieldInfo fieldInfo = AccessTools.Field(type, "roomData"); object? obj = fieldInfo?.GetValue(__instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val != (Object)null) { return false; } GameObject val2 = InstantiateRoomDataLocal(); if ((Object)(object)val2 != (Object)null) { fieldInfo?.SetValue(__instance, val2); Type type2 = AccessTools.TypeByName("IKEASimulator.PathMapper"); if (type2 != null) { Component component = val2.GetComponent(type2); AccessTools.Property(type, "PathMapper")?.SetValue(__instance, component); } Logger.LogDebug((object)" SingleplayerRoomData: RoomData instantiated locally"); } return false; } catch (Exception arg) { Logger.LogError((object)$"SingleplayerRoomData_Prefix error: {arg}"); return false; } } [IteratorStateMachine(typeof(<InstantiateRoomDataFixed>d__4))] private static IEnumerator InstantiateRoomDataFixed(object networkManager) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InstantiateRoomDataFixed>d__4(0) { networkManager = networkManager }; } private static GameObject? InstantiateRoomDataLocal() { try { string prefabId = "managers/roomdata"; GameObject val = IKEACriticalPatches.GetPrefab(prefabId); if ((Object)(object)val == (Object)null) { foreach (KeyValuePair<string, GameObject> prefab in IKEACriticalPatches.Prefabs) { if (prefab.Key.ToLower().Contains("roomdata")) { val = prefab.Value; Logger.LogDebug((object)(" Found RoomData prefab with key: " + prefab.Key)); break; } } } if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)" RoomData prefab not found in cache"); return null; } return Object.Instantiate<GameObject>(val); } catch (Exception arg) { Logger.LogError((object)$"InstantiateRoomDataLocal error: {arg}"); return null; } } } [HarmonyPatch(typeof(Module), "Start")] internal static class ModuleSafetyPatch { [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, Module __instance) { if (__exception != null && __exception is NullReferenceException) { string text = __exception.StackTrace ?? ""; if (text.Contains("IKEASimulator")) { IKEASimulator_Fixer.Logger.LogWarning((object)("Suppressed IKEASimulator NullReferenceException in Module.Start for " + (((__instance != null) ? ((Object)__instance).name : null) ?? "unknown"))); return null; } } return __exception; } } [HarmonyPatch(typeof(LevelGenerator), "ModuleGeneration")] internal static class LevelGeneratorSafetyPatch { [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception) { if (__exception != null && __exception is NullReferenceException) { string text = __exception.StackTrace ?? ""; if (text.Contains("IKEASimulator")) { IKEASimulator_Fixer.Logger.LogWarning((object)"Suppressed IKEASimulator NullReferenceException in LevelGenerator.ModuleGeneration"); return null; } } return __exception; } } }