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);
}
}
}