Decompiled source of PEAK MX ParallelWorldFix v1.0.0

PEAK-MX-ParallelFix.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 PeakMXParallelFix
{
	[BepInPlugin("com.patch.peakmxparallelfix", "PEAK-MX-ParallelFix", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.patch.peakmxparallelfix";

		public const string Name = "PEAK-MX-ParallelFix";

		public const string Version = "1.0.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private static Type _photonType;

		private static PropertyInfo _inRoomProp;

		private static PropertyInfo _isMasterClientProp;

		private static PropertyInfo _currentRoomProp;

		private static float _lastRoomCheckTime = 0f;

		private static Type _modConfigType;

		private static readonly Dictionary<string, PropertyInfo> _cachedProps = new Dictionary<string, PropertyInfo>();

		private static readonly Dictionary<string, FieldInfo> _cachedFields = new Dictionary<string, FieldInfo>();

		private static Type _antiCheatType;

		private static FieldInfo _hostEnabledField;

		private static FieldInfo _hostLocksClientsField;

		private static FieldInfo _wasMasterClientField;

		private static bool _clientToolsLocked = false;

		private static bool _hostLockSet = false;

		private static float _lastLockApplyTime = 0f;

		private const float LockApplyInterval = 3f;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"PEAK-MX-ParallelFix v1.0.0 loaded.");
			CacheReflectionObjects();
			_harmony = new Harmony("com.patch.peakmxparallelfix");
			try
			{
				ApplyPatches();
				Log.LogInfo((object)"Patches applied.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to apply patches: {arg}");
			}
		}

		private void CacheReflectionObjects()
		{
			try
			{
				_photonType = AccessTools.TypeByName("Photon.Pun.PhotonNetwork");
				if (_photonType != null)
				{
					_inRoomProp = AccessTools.Property(_photonType, "InRoom");
					_isMasterClientProp = AccessTools.Property(_photonType, "IsMasterClient");
					_currentRoomProp = AccessTools.Property(_photonType, "CurrentRoom");
				}
				_modConfigType = AccessTools.TypeByName("PeakMX.ModConfig");
				if (_modConfigType != null)
				{
					string[] array = new string[44]
					{
						"SpeedMod", "JumpMod", "InfiniteJumps", "ClimbMod", "VineClimbMod", "RopeClimbMod", "GodMode", "InfiniteStamina", "NoFallDamage", "NoFallingRagdoll",
						"NoWeight", "LockStatus", "NoStatusEffects", "NoInjury", "NoHunger", "NoCold", "NoPoison", "NoCurse", "NoDrowsy", "NoHot",
						"NoCrab", "NoThorns", "NoSpores", "NoWeb", "NoArrows", "NoPetrify", "NoFlyTrap", "TeleportToPing", "NoSlipperySurfaces", "LongInteraction",
						"CinematicCamera", "GlobalVoice", "PlayerEsp", "ItemEsp", "WorldEsp", "GameSpeedMod", "OverrideExpeditionTime", "Fly", "Noclip", "InfiniteItems",
						"UnlimitedLanternFuel", "UnlimitedItemUses", "RapidRandomOutfitColor", "PingHandSizeMultiplier"
					};
					foreach (string text in array)
					{
						PropertyInfo propertyInfo = AccessTools.Property(_modConfigType, text);
						if (propertyInfo != null)
						{
							_cachedProps[text] = propertyInfo;
						}
						FieldInfo fieldInfo = AccessTools.Field(_modConfigType, text);
						if (fieldInfo != null)
						{
							_cachedFields[text] = fieldInfo;
						}
					}
				}
				_antiCheatType = AccessTools.TypeByName("PeakMX.AntiCheat");
				if (_antiCheatType != null)
				{
					_hostEnabledField = AccessTools.Field(_antiCheatType, "_hostEnabled");
					_hostLocksClientsField = AccessTools.Field(_antiCheatType, "_hostLocksClients");
					_wasMasterClientField = AccessTools.Field(_antiCheatType, "_wasMasterClient");
				}
				Log.LogInfo((object)$"Cached reflection objects: {_cachedProps.Count} props, {_cachedFields.Count} fields");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("CacheReflectionObjects error: " + ex.Message));
			}
		}

		private void Update()
		{
			try
			{
				if (Time.realtimeSinceStartup - _lastRoomCheckTime < 1f)
				{
					return;
				}
				_lastRoomCheckTime = Time.realtimeSinceStartup;
				if (_inRoomProp == null || _isMasterClientProp == null || _currentRoomProp == null)
				{
					return;
				}
				bool num = (bool)(_inRoomProp.GetValue(null) ?? ((object)false));
				bool flag = (bool)(_isMasterClientProp.GetValue(null) ?? ((object)false));
				if (!num)
				{
					if (_clientToolsLocked)
					{
						_clientToolsLocked = false;
						Log.LogInfo((object)"Left room - client tools unlock flag reset.");
					}
					if (_hostLockSet)
					{
						_hostLockSet = false;
						Log.LogInfo((object)"Left room - host lock flag reset.");
					}
					return;
				}
				if (flag && !_hostLockSet)
				{
					SetHostLockProperty();
					_hostLockSet = true;
				}
				if (flag)
				{
					return;
				}
				if (CheckHostLockProperty())
				{
					if (Time.realtimeSinceStartup - _lastLockApplyTime >= 3f)
					{
						LockClientTools();
						_lastLockApplyTime = Time.realtimeSinceStartup;
						if (!_clientToolsLocked)
						{
							_clientToolsLocked = true;
							Log.LogInfo((object)"Client tools locked by host (pmx_ac=true, pmx_ac_lock=true).");
						}
					}
				}
				else if (_clientToolsLocked)
				{
					ResetAntiCheatInternalState();
					_clientToolsLocked = false;
					Log.LogInfo((object)"Client tools unlocked (host disabled lock).");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Update error: " + ex.Message));
			}
		}

		private void SetHostLockProperty()
		{
			try
			{
				object obj = _currentRoomProp?.GetValue(null);
				if (obj != null)
				{
					Type type = AccessTools.TypeByName("ExitGames.Client.Photon.Hashtable");
					object obj2 = Activator.CreateInstance(type);
					MethodInfo method = type.GetMethod("Add", new Type[2]
					{
						typeof(object),
						typeof(object)
					});
					method?.Invoke(obj2, new object[2] { "pmx_ac", true });
					method?.Invoke(obj2, new object[2] { "pmx_ac_lock", true });
					object obj3 = AccessTools.Property(_photonType, "LocalPlayer")?.GetValue(null);
					if (obj3 != null)
					{
						int num = (int)(AccessTools.Property(obj3.GetType(), "ActorNumber")?.GetValue(obj3) ?? ((object)0));
						method?.Invoke(obj2, new object[2] { "pmx_ac_host", num });
					}
					method?.Invoke(obj2, new object[2] { "pmx_ac_ver", "1.0.0" });
					AccessTools.Method(obj.GetType(), "SetCustomProperties", (Type[])null, (Type[])null)?.Invoke(obj, new object[3] { obj2, null, null });
					Log.LogInfo((object)"Host lock properties set: pmx_ac=true, pmx_ac_lock=true");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("SetHostLockProperty error: " + ex.Message));
			}
		}

		private bool CheckHostLockProperty()
		{
			try
			{
				object obj = _currentRoomProp?.GetValue(null);
				if (obj == null)
				{
					return false;
				}
				object obj2 = AccessTools.Property(obj.GetType(), "CustomProperties")?.GetValue(obj);
				if (obj2 == null)
				{
					return false;
				}
				MethodInfo methodInfo = AccessTools.Method(obj2.GetType(), "TryGetValue", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					return false;
				}
				object[] array = new object[2] { "pmx_ac", null };
				bool flag = default(bool);
				int num;
				if ((bool)methodInfo.Invoke(obj2, array))
				{
					object obj3 = array[1];
					if (obj3 is bool)
					{
						flag = (bool)obj3;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
				object[] array2 = new object[2] { "pmx_ac_lock", null };
				bool flag3 = default(bool);
				int num2;
				if ((bool)methodInfo.Invoke(obj2, array2))
				{
					object obj3 = array2[1];
					if (obj3 is bool)
					{
						flag3 = (bool)obj3;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
				}
				else
				{
					num2 = 0;
				}
				bool flag4 = (byte)((uint)num2 & (flag3 ? 1u : 0u)) != 0;
				return flag2 && flag4;
			}
			catch
			{
				return false;
			}
		}

		private void LockClientTools()
		{
			try
			{
				UpdateAntiCheatInternalState();
				if (_modConfigType == null)
				{
					return;
				}
				string[] array = new string[43]
				{
					"SpeedMod", "JumpMod", "InfiniteJumps", "ClimbMod", "VineClimbMod", "RopeClimbMod", "GodMode", "InfiniteStamina", "NoFallDamage", "NoFallingRagdoll",
					"NoWeight", "LockStatus", "NoStatusEffects", "NoInjury", "NoHunger", "NoCold", "NoPoison", "NoCurse", "NoDrowsy", "NoHot",
					"NoCrab", "NoThorns", "NoSpores", "NoWeb", "NoArrows", "NoPetrify", "NoFlyTrap", "TeleportToPing", "NoSlipperySurfaces", "LongInteraction",
					"CinematicCamera", "GlobalVoice", "PlayerEsp", "ItemEsp", "WorldEsp", "GameSpeedMod", "OverrideExpeditionTime", "Fly", "Noclip", "InfiniteItems",
					"UnlimitedLanternFuel", "UnlimitedItemUses", "RapidRandomOutfitColor"
				};
				foreach (string text in array)
				{
					try
					{
						FieldInfo value3;
						if (_cachedProps.TryGetValue(text, out var value) && value.CanWrite)
						{
							object value2 = value.GetValue(null);
							if (value2 is bool)
							{
								value.SetValue(null, false);
							}
							else if (value2 is float)
							{
								value.SetValue(null, (text == "PingHandSizeMultiplier") ? 1f : 0f);
							}
						}
						else if (_cachedFields.TryGetValue(text, out value3))
						{
							object value4 = value3.GetValue(null);
							if (value4 is bool)
							{
								value3.SetValue(null, false);
							}
							else if (value4 is float)
							{
								value3.SetValue(null, (text == "PingHandSizeMultiplier") ? 1f : 0f);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("LockClientTools error: " + ex.Message));
			}
		}

		private void UpdateAntiCheatInternalState()
		{
			try
			{
				if (!(_antiCheatType == null))
				{
					if (_hostEnabledField != null)
					{
						_hostEnabledField.SetValue(null, true);
					}
					if (_hostLocksClientsField != null)
					{
						_hostLocksClientsField.SetValue(null, true);
					}
					if (_wasMasterClientField != null)
					{
						_wasMasterClientField.SetValue(null, false);
					}
				}
			}
			catch
			{
			}
		}

		private void ResetAntiCheatInternalState()
		{
			try
			{
				if (!(_antiCheatType == null))
				{
					if (_hostEnabledField != null)
					{
						_hostEnabledField.SetValue(null, false);
					}
					if (_hostLocksClientsField != null)
					{
						_hostLocksClientsField.SetValue(null, false);
					}
				}
			}
			catch
			{
			}
		}

		private void ApplyPatches()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("PeakMX.MxAhgHost");
			if (type != null)
			{
				MethodInfo methodInfo = AccessTools.Method(type, "Init", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					HarmonyMethod val = new HarmonyMethod(typeof(MxAhgFix), "InitPrefix", (Type[])null)
					{
						priority = 0
					};
					_harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched MxAhgHost.Init (disabled)");
				}
				MethodInfo methodInfo2 = AccessTools.Method(type, "Tick", (Type[])null, (Type[])null);
				if (methodInfo2 != null)
				{
					HarmonyMethod val2 = new HarmonyMethod(typeof(MxAhgFix), "TickPrefix", (Type[])null)
					{
						priority = 0
					};
					_harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched MxAhgHost.Tick (disabled)");
				}
			}
			Type type2 = AccessTools.TypeByName("PeakMX.AntiCheat");
			if (type2 != null)
			{
				MethodInfo methodInfo3 = AccessTools.Method(type2, "Tick", (Type[])null, (Type[])null);
				if (methodInfo3 != null)
				{
					HarmonyMethod val3 = new HarmonyMethod(typeof(AntiCheatFix), "TickPrefix", (Type[])null)
					{
						priority = 0
					};
					_harmony.Patch((MethodBase)methodInfo3, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched AntiCheat.Tick (disabled)");
				}
			}
			Type type3 = AccessTools.TypeByName("Peak.Network.NetworkingUtilities");
			if (type3 != null)
			{
				MethodInfo methodInfo4 = AccessTools.Method(type3, "HostRoomOptions", (Type[])null, (Type[])null);
				if (methodInfo4 != null)
				{
					HarmonyMethod val4 = new HarmonyMethod(typeof(HostRoomOptionsFix), "Prefix", (Type[])null)
					{
						priority = 0
					};
					_harmony.Patch((MethodBase)methodInfo4, val4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched NetworkingUtilities.HostRoomOptions");
				}
			}
			Type type4 = AccessTools.TypeByName("AirportCheckInKiosk");
			if (type4 != null)
			{
				MethodInfo methodInfo5 = AccessTools.Method(type4, "LoadIslandMaster", (Type[])null, (Type[])null);
				if (methodInfo5 != null)
				{
					HarmonyMethod val5 = new HarmonyMethod(typeof(IslandSyncFix), "Postfix", (Type[])null);
					_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, val5, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched AirportCheckInKiosk.LoadIslandMaster");
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class MxAhgFix
	{
		public static bool InitPrefix()
		{
			return false;
		}

		public static bool TickPrefix()
		{
			return false;
		}
	}
	internal static class AntiCheatFix
	{
		public static bool TickPrefix()
		{
			return false;
		}
	}
	internal static class HostRoomOptionsFix
	{
		public static bool Prefix(ref object __result)
		{
			try
			{
				Plugin.Log.LogInfo((object)"HostRoomOptions Prefix called.");
				Type type = AccessTools.TypeByName("Photon.Realtime.RoomOptions");
				if (type == null)
				{
					return true;
				}
				object obj = Activator.CreateInstance(type);
				int effectiveMaxPlayers = GetEffectiveMaxPlayers();
				SetProp(obj, "IsVisible", false);
				SetProp(obj, "MaxPlayers", (byte)Mathf.Clamp(effectiveMaxPlayers, 1, 30));
				SetProp(obj, "PublishUserId", true);
				SetProp(obj, "EmptyRoomTtl", 0);
				SetProp(obj, "PlayerTtl", 0);
				Type type2 = AccessTools.TypeByName("ExitGames.Client.Photon.Hashtable");
				if (type2 != null)
				{
					object value = Activator.CreateInstance(type2);
					SetProp(obj, "CustomRoomProperties", value);
				}
				SetProp(obj, "CustomRoomPropertiesForLobby", Array.Empty<string>());
				__result = obj;
				Plugin.Log.LogInfo((object)$"HostRoomOptions fixed. MaxPlayers={effectiveMaxPlayers}");
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"HostRoomOptionsFix error: {arg}");
				return true;
			}
		}

		private static int GetEffectiveMaxPlayers()
		{
			try
			{
				Type type = AccessTools.TypeByName("PeakMX.ManyPlayers");
				if (type != null && (bool)(AccessTools.Property(type, "Enabled")?.GetValue(null) ?? ((object)false)))
				{
					return (int)(AccessTools.Property(type, "MaxPlayers")?.GetValue(null) ?? ((object)4));
				}
			}
			catch
			{
			}
			return 12;
		}

		private static void SetProp(object instance, string propName, object value)
		{
			try
			{
				PropertyInfo propertyInfo = AccessTools.Property(instance.GetType(), propName);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(instance, value);
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), propName);
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(instance, value);
				}
			}
			catch
			{
			}
		}
	}
	internal static class IslandSyncFix
	{
		public static void Postfix(object __0, object __1)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("Photon.Pun.PhotonNetwork");
				if (!(type == null))
				{
					bool flag = (bool)(AccessTools.Property(type, "IsMasterClient")?.GetValue(null) ?? ((object)false));
					Plugin.Log.LogInfo((object)$"LoadIslandMaster Postfix. IsMasterClient={flag}");
					if (flag)
					{
						GameObject val = new GameObject("ParallelFixSync");
						Object.DontDestroyOnLoad((Object)val);
						val.AddComponent<SyncRunner>().StartSync();
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("IslandSyncFix error: " + ex.Message));
			}
		}
	}
	public class SyncRunner : MonoBehaviour
	{
		public void StartSync()
		{
			((MonoBehaviour)this).StartCoroutine(SyncCoroutine());
		}

		private IEnumerator SyncCoroutine()
		{
			yield return (object)new WaitForSeconds(3f);
			yield return null;
			try
			{
				Type type = AccessTools.TypeByName("Photon.Pun.PhotonNetwork");
				bool flag = (bool)(AccessTools.Property(type, "InRoom")?.GetValue(null) ?? ((object)false));
				bool flag2 = (bool)(AccessTools.Property(type, "IsMasterClient")?.GetValue(null) ?? ((object)false));
				if (!flag || !flag2)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
					yield break;
				}
				object obj = AccessTools.Property(type, "CurrentRoom")?.GetValue(null);
				if (obj == null)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
					yield break;
				}
				Type type2 = AccessTools.TypeByName("ExitGames.Client.Photon.Hashtable");
				object obj2 = Activator.CreateInstance(type2);
				type2.GetMethod("Add", new Type[2]
				{
					typeof(object),
					typeof(object)
				})?.Invoke(obj2, new object[2]
				{
					"mx_parallelfix_world_ready",
					DateTime.UtcNow.Ticks
				});
				AccessTools.Method(obj.GetType(), "SetCustomProperties", (Type[])null, (Type[])null)?.Invoke(obj, new object[3] { obj2, null, null });
				Plugin.Log.LogInfo((object)"World sync event sent.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("SyncCoroutine error: " + ex.Message));
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
}