Decompiled source of NetworkingRevived v2.2.0

NetworkingRevived.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using NetworkingRevived.Patches;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Revival")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Revival")]
[assembly: AssemblyFileVersion("2.2.0.0")]
[assembly: AssemblyInformationalVersion("2.2.0")]
[assembly: AssemblyProduct("NetworkingRevived")]
[assembly: AssemblyTitle("NetworkingRevived")]
[assembly: AssemblyVersion("2.2.0.0")]
namespace NetworkingRevived
{
	public static class NetworkingRevivedAPI
	{
		public static bool IsLocallySimulated(PhotonTransformView ptv)
		{
			if (SimManager.Ready)
			{
				return SimManager.IsSuppressed(ptv);
			}
			return false;
		}

		public static bool IsLocallySimulated(PhysGrabObject pgo)
		{
			if (SimManager.Ready)
			{
				return SimManager.HasPhysicsAuthority(pgo);
			}
			return false;
		}
	}
	[BepInPlugin("com.Revival.networkingrevived", "NetworkingRevived", "2.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.Revival.networkingrevived";

		public const string PluginName = "NetworkingRevived";

		public const string PluginVersion = "2.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> SimulateCarts;

		internal static ConfigEntry<bool> SimulateHinges;

		internal static ConfigEntry<bool> InstantCartHandle;

		internal static ConfigEntry<float> PassiveSyncStrength;

		internal static ConfigEntry<float> PostThrowGrace;

		internal static ConfigEntry<float> SnapDistance;

		internal static ConfigEntry<float> HeldDriftCorrectAt;

		internal static ConfigEntry<float> HeldDriftHandbackAt;

		internal static ConfigEntry<bool> VerboseLogging;

		private void Awake()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			SimulateCarts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SimulateCarts", true, "Simulate carts locally (removes cart input lag).");
			SimulateHinges = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SimulateHinges", true, "Simulate doors and cabinets locally so they open instantly instead of waiting for the host. Turn off if hinged objects misbehave.");
			InstantCartHandle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "InstantCartHandle", true, "Register cart handle grabs locally right away instead of waiting for the host.");
			PassiveSyncStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Sync", "PassiveSyncStrength", 0.075f, new ConfigDescription("How strongly objects you are NOT holding blend toward the host's state each physics tick. This constant correction is what keeps both players seeing the same world.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
			PostThrowGrace = ((BaseUnityPlugin)this).Config.Bind<float>("Sync", "PostThrowGrace", 0.6f, new ConfigDescription("Seconds after you release/throw an object during which the correction is extra gentle, so your throw flies the way you saw it leave your hand.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			SnapDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Sync", "SnapDistance", 6f, new ConfigDescription("If an object you are not holding is further than this (meters) from the host's copy, snap it instead of blending.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			HeldDriftCorrectAt = ((BaseUnityPlugin)this).Config.Bind<float>("Sync", "HeldDriftCorrectAt", 1.5f, new ConfigDescription("While you hold an object: if your copy drifts further than this (meters) from the host's copy, gently pull it back so both players keep seeing roughly the same thing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			HeldDriftHandbackAt = ((BaseUnityPlugin)this).Config.Bind<float>("Sync", "HeldDriftHandbackAt", 4f, new ConfigDescription("While you hold an object: if your copy stays further than this (meters) from the host's copy (e.g. the host's version got stuck on a wall), give control back to the host until you re-grab.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "VerboseLogging", false, "Log simulation start/stop events (for debugging).");
			if (!SimManager.InitAccessors())
			{
				Log.LogError((object)"NetworkingRevived could not find expected game internals (the game probably updated). The mod has disabled itself to avoid breaking your game.");
				return;
			}
			Harmony val = new Harmony("com.Revival.networkingrevived");
			int num = 0;
			int num2 = 0;
			Type[] array = new Type[8]
			{
				typeof(HingeJointKeeperPatch),
				typeof(PhysGrabObjectStartPatch),
				typeof(GrabStartedPatch),
				typeof(GrabEndedPatch),
				typeof(GrabPlayerAddDedupePatch),
				typeof(TransformViewUpdatePatch),
				typeof(TransformViewSerializePatch),
				typeof(CartAuthorityPatch)
			};
			foreach (Type type in array)
			{
				try
				{
					val.PatchAll(type);
					num++;
				}
				catch (Exception arg)
				{
					num2++;
					Log.LogError((object)$"Failed to apply patch {type.Name}: {arg}");
				}
			}
			if (num == 0)
			{
				Log.LogError((object)"No patches could be applied — NetworkingRevived is inactive.");
				return;
			}
			GameObject val2 = new GameObject("NetworkingRevivedDriver");
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<SimDriver>();
			Log.LogInfo((object)(string.Format("NetworkingRevived {0} loaded. Patches applied: {1}, failed: {2}. ", "2.2.0", num, num2) + "Client-side prediction is active when you join someone else's lobby."));
		}
	}
	internal static class SimManager
	{
		internal class SimState
		{
			public PhysGrabObject pgo;

			public PhotonTransformView ptv;

			public Rigidbody rb;

			public PhysGrabCart cart;

			public bool isHinge;

			public PhysGrabHinge hinge;

			public HingeJoint joint;

			public bool localGrab;

			public float postThrowTimer;

			public float desyncTimer;

			public float stuckTimer;

			public float debugTimer;

			public int ridingTick;

			public bool hasHostState;

			public Vector3 hostPos;

			public Quaternion hostRot = Quaternion.identity;

			public Vector3 hostVel;

			public Vector3 hostAngVel;

			public bool hostKinematic;

			public bool hostSleeping;

			public bool hostTeleport;
		}

		private static readonly Dictionary<PhysGrabObject, SimState> states = new Dictionary<PhysGrabObject, SimState>();

		private static readonly Dictionary<PhotonTransformView, SimState> byPtv = new Dictionary<PhotonTransformView, SimState>();

		private static readonly List<SimState> tickBuffer = new List<SimState>(256);

		private static readonly HashSet<PhysGrabObject> handedBack = new HashSet<PhysGrabObject>();

		private static readonly List<PhysGrabObject> handedBackSweep = new List<PhysGrabObject>();

		private static FieldRef<PhysGrabObject, bool> pgoIsMaster;

		private static FieldRef<PhysGrabObject, bool> pgoIsActive;

		private static FieldRef<PhysGrabber, PhysGrabObject> grabberObject;

		private static FieldRef<PhysGrabCart, List<PhysGrabObject>> cartItems;

		private static FieldRef<PhysGrabHinge, bool> hingeBroken;

		private static FieldRef<PhysGrabCart, Transform> cartInCart;

		private static FieldRef<PlayerAvatar, bool> avatarSprinting;

		private static MethodInfo pgoThrow;

		private static FieldRef<PhotonTransformView, Vector3> ptvNetPos;

		private static FieldRef<PhotonTransformView, Quaternion> ptvNetRot;

		private static FieldRef<PhotonTransformView, Vector3> ptvStoredPos;

		private static FieldRef<PhotonTransformView, Vector3> ptvSmoothedPos;

		private static FieldRef<PhotonTransformView, Quaternion> ptvSmoothedRot;

		private static FieldRef<PhotonTransformView, Vector3> ptvRecvPos;

		private static FieldRef<PhotonTransformView, Quaternion> ptvRecvRot;

		private static FieldRef<PhotonTransformView, Vector3> ptvPrevPos;

		private static FieldRef<PhotonTransformView, Quaternion> ptvPrevRot;

		private static FieldRef<PhotonTransformView, Vector3> ptvRecvVel;

		private static FieldRef<PhotonTransformView, Vector3> ptvRecvAngVel;

		private static FieldRef<PhotonTransformView, float> ptvDistance;

		private static FieldRef<PhotonTransformView, float> ptvAngle;

		private static FieldRef<PhotonTransformView, bool> ptvFirstTake;

		private static FieldRef<PhotonTransformView, bool> ptvTeleport;

		private static FieldRef<PhotonTransformView, bool> ptvIsSleeping;

		private static FieldRef<PhotonTransformView, bool> ptvKinForced;

		private static FieldRef<PhotonTransformView, float> ptvKinForcedTimer;

		private static int tickCounter;

		private static readonly List<PhysGrabObject> deadPgos = new List<PhysGrabObject>();

		private static readonly List<PhotonTransformView> deadPtvs = new List<PhotonTransformView>();

		internal static bool Ready { get; private set; }

		internal static bool InitAccessors()
		{
			try
			{
				pgoIsMaster = AccessTools.FieldRefAccess<PhysGrabObject, bool>("isMaster");
				pgoIsActive = AccessTools.FieldRefAccess<PhysGrabObject, bool>("isActive");
				grabberObject = AccessTools.FieldRefAccess<PhysGrabber, PhysGrabObject>("grabbedPhysGrabObject");
				cartItems = AccessTools.FieldRefAccess<PhysGrabCart, List<PhysGrabObject>>("itemsInCart");
				hingeBroken = AccessTools.FieldRefAccess<PhysGrabHinge, bool>("broken");
				cartInCart = AccessTools.FieldRefAccess<PhysGrabCart, Transform>("inCart");
				avatarSprinting = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isSprinting");
				pgoThrow = AccessTools.Method(typeof(PhysGrabObject), "Throw", (Type[])null, (Type[])null);
				ptvNetPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("m_NetworkPosition");
				ptvNetRot = AccessTools.FieldRefAccess<PhotonTransformView, Quaternion>("m_NetworkRotation");
				ptvStoredPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("m_StoredPosition");
				ptvSmoothedPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("smoothedPosition");
				ptvSmoothedRot = AccessTools.FieldRefAccess<PhotonTransformView, Quaternion>("smoothedRotation");
				ptvRecvPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedPosition");
				ptvRecvRot = AccessTools.FieldRefAccess<PhotonTransformView, Quaternion>("receivedRotation");
				ptvPrevPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("prevPosition");
				ptvPrevRot = AccessTools.FieldRefAccess<PhotonTransformView, Quaternion>("prevRotation");
				ptvRecvVel = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedVelocity");
				ptvRecvAngVel = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedAngularVelocity");
				ptvDistance = AccessTools.FieldRefAccess<PhotonTransformView, float>("m_Distance");
				ptvAngle = AccessTools.FieldRefAccess<PhotonTransformView, float>("m_Angle");
				ptvFirstTake = AccessTools.FieldRefAccess<PhotonTransformView, bool>("m_firstTake");
				ptvTeleport = AccessTools.FieldRefAccess<PhotonTransformView, bool>("teleport");
				ptvIsSleeping = AccessTools.FieldRefAccess<PhotonTransformView, bool>("isSleeping");
				ptvKinForced = AccessTools.FieldRefAccess<PhotonTransformView, bool>("kinematicClientForced");
				ptvKinForcedTimer = AccessTools.FieldRefAccess<PhotonTransformView, float>("kinematicClientForcedTimer");
				if (pgoThrow == null)
				{
					Plugin.Log.LogWarning((object)"PhysGrabObject.Throw not found — throws will rely on host only.");
				}
				Ready = true;
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Accessor init failed: {arg}");
				Ready = false;
				return false;
			}
		}

		internal static bool IsClientInLobby()
		{
			if (GameManager.Multiplayer() && PhotonNetwork.InRoom)
			{
				return !PhotonNetwork.IsMasterClient;
			}
			return false;
		}

		internal static SimState GetByPtv(PhotonTransformView ptv)
		{
			if (!((Object)(object)ptv != (Object)null) || !byPtv.TryGetValue(ptv, out var value))
			{
				return null;
			}
			return value;
		}

		internal static bool IsSuppressed(PhotonTransformView ptv)
		{
			if ((Object)(object)ptv != (Object)null)
			{
				return byPtv.ContainsKey(ptv);
			}
			return false;
		}

		internal static bool IsLocalGrab(PhysGrabObject pgo)
		{
			if ((Object)(object)pgo != (Object)null && states.TryGetValue(pgo, out var value))
			{
				return value.localGrab;
			}
			return false;
		}

		internal static bool HasPhysicsAuthority(PhysGrabObject pgo)
		{
			if ((Object)(object)pgo != (Object)null)
			{
				return states.ContainsKey(pgo);
			}
			return false;
		}

		internal static bool IsHandedBack(PhysGrabObject pgo)
		{
			if ((Object)(object)pgo != (Object)null)
			{
				return handedBack.Contains(pgo);
			}
			return false;
		}

		internal static void ClearHandback(PhysGrabObject pgo)
		{
			if ((Object)(object)pgo != (Object)null)
			{
				handedBack.Remove(pgo);
			}
		}

		internal static bool CanSimulate(PhysGrabObject o)
		{
			if ((Object)(object)o == (Object)null || (Object)(object)o.rb == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponent<PhotonView>() == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponent<PhotonTransformView>() == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponent<PhysGrabCart>() != (Object)null)
			{
				return Plugin.SimulateCarts.Value;
			}
			if ((Object)(object)((Component)o).GetComponent<PlayerTumble>() != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponentInParent<Enemy>() != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponentInParent<EnemyRigidbody>() != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)o).GetComponentInParent<PhysGrabHinge>() != (Object)null)
			{
				return Plugin.SimulateHinges.Value;
			}
			if ((Object)(object)((Component)o).GetComponentInParent<ItemAttributes>() != (Object)null)
			{
				return false;
			}
			return true;
		}

		internal static SimState TryRegister(PhysGrabObject pgo)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready || (Object)(object)pgo == (Object)null)
			{
				return null;
			}
			if (states.TryGetValue(pgo, out var value))
			{
				return value;
			}
			if (!IsClientInLobby())
			{
				return null;
			}
			if (!CanSimulate(pgo))
			{
				return null;
			}
			PhotonTransformView component = ((Component)pgo).GetComponent<PhotonTransformView>();
			if ((Object)(object)component == (Object)null || (Object)(object)pgo.rb == (Object)null)
			{
				return null;
			}
			SimState simState = new SimState
			{
				pgo = pgo,
				ptv = component,
				rb = pgo.rb,
				cart = ((Component)pgo).GetComponent<PhysGrabCart>(),
				hinge = ((Component)pgo).GetComponent<PhysGrabHinge>()
			};
			simState.isHinge = (Object)(object)simState.hinge != (Object)null;
			if (simState.isHinge)
			{
				simState.joint = ((Component)pgo).GetComponent<HingeJoint>();
				if ((Object)(object)simState.joint != (Object)null)
				{
					((Joint)simState.joint).breakForce = float.PositiveInfinity;
					((Joint)simState.joint).breakTorque = float.PositiveInfinity;
					simState.joint.useSpring = false;
					simState.joint.useMotor = false;
				}
			}
			if (!ptvFirstTake.Invoke(component))
			{
				simState.hasHostState = true;
				simState.hostPos = ptvNetPos.Invoke(component);
				simState.hostRot = ptvNetRot.Invoke(component);
				simState.hostVel = ptvRecvVel.Invoke(component);
				simState.hostAngVel = ptvRecvAngVel.Invoke(component);
				simState.hostKinematic = simState.rb.isKinematic;
				simState.hostSleeping = ptvIsSleeping.Invoke(component);
			}
			states[pgo] = simState;
			byPtv[component] = simState;
			return simState;
		}

		internal static void StartLocalGrab(PhysGrabObject pgo)
		{
			if (!Ready || (Object)(object)pgo == (Object)null)
			{
				return;
			}
			SimState simState = TryRegister(pgo);
			if (simState != null)
			{
				if (!simState.localGrab && Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("Local grab authority: " + ((Object)pgo).name));
				}
				simState.localGrab = true;
				simState.postThrowTimer = 0f;
				simState.desyncTimer = 0f;
				pgoIsMaster.Invoke(pgo) = true;
				EnsureDynamic(simState);
			}
		}

		internal static void EndLocalGrab(PhysGrabObject pgo)
		{
			if (Ready && !((Object)(object)pgo == (Object)null) && states.TryGetValue(pgo, out var value) && value.localGrab)
			{
				value.localGrab = false;
				value.desyncTimer = 0f;
				value.stuckTimer = 0f;
				value.postThrowTimer = (((Object)(object)value.cart != (Object)null) ? (Plugin.PostThrowGrace.Value * 2.5f) : Plugin.PostThrowGrace.Value);
				pgoIsMaster.Invoke(pgo) = false;
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("Released grab authority: " + ((Object)pgo).name));
				}
			}
		}

		internal static void LocalThrow(PhysGrabObject pgo, PhysGrabber player)
		{
			if (pgoThrow == null || (Object)(object)pgo == (Object)null || (Object)(object)player == (Object)null || !states.TryGetValue(pgo, out var value) || (Object)(object)value.rb == (Object)null || value.rb.isKinematic)
			{
				return;
			}
			try
			{
				pgoThrow.Invoke(pgo, new object[1] { player });
			}
			catch (Exception ex)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogWarning((object)("Local throw failed: " + ex.Message));
				}
			}
		}

		private static void EnsureDynamic(SimState st)
		{
			if (!((Object)(object)st.rb == (Object)null))
			{
				if (st.rb.isKinematic)
				{
					st.rb.isKinematic = false;
				}
				if (st.rb.IsSleeping())
				{
					st.rb.WakeUp();
				}
			}
		}

		internal static void TickKinematicTimer(PhotonTransformView ptv)
		{
			if (ptvKinForcedTimer.Invoke(ptv) > 0f)
			{
				ptvKinForcedTimer.Invoke(ptv) -= Time.deltaTime;
				if (ptvKinForcedTimer.Invoke(ptv) <= 0f)
				{
					ptvKinForced.Invoke(ptv) = false;
				}
			}
		}

		internal static void Tick()
		{
			if (!Ready)
			{
				return;
			}
			SweepHandedBack();
			if (states.Count == 0)
			{
				return;
			}
			tickCounter++;
			bool flag = IsClientInLobby();
			tickBuffer.Clear();
			tickBuffer.AddRange(states.Values);
			foreach (SimState item in tickBuffer)
			{
				if (!item.localGrab || (Object)(object)item.cart == (Object)null)
				{
					continue;
				}
				List<PhysGrabObject> list = cartItems.Invoke(item.cart);
				if (list == null)
				{
					continue;
				}
				for (int i = 0; i < list.Count; i++)
				{
					if ((Object)(object)list[i] != (Object)null && states.TryGetValue(list[i], out var value))
					{
						value.ridingTick = tickCounter;
					}
				}
			}
			foreach (SimState item2 in tickBuffer)
			{
				if ((Object)(object)item2.pgo == (Object)null || (Object)(object)item2.rb == (Object)null || (Object)(object)item2.ptv == (Object)null)
				{
					HardRemove(item2);
				}
				else if (!flag)
				{
					Restore(item2);
				}
				else if (item2.localGrab)
				{
					TickHeld(item2);
				}
				else
				{
					TickShadow(item2);
				}
			}
		}

		private static void TickHeld(SimState st)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			PhysGrabber localGrabber = GetLocalGrabber(st);
			if (!pgoIsActive.Invoke(st.pgo) || (Object)(object)localGrabber == (Object)null)
			{
				EndLocalGrab(st.pgo);
				return;
			}
			pgoIsMaster.Invoke(st.pgo) = true;
			EnsureDynamic(st);
			if (st.isHinge)
			{
				CheckHingeBroken(st);
				return;
			}
			if ((Object)(object)st.cart != (Object)null)
			{
				DriveHeldCart(st, localGrabber);
			}
			if (!st.hasHostState || st.hostKinematic)
			{
				return;
			}
			st.hostTeleport = false;
			Vector3 velocity = st.rb.velocity;
			float magnitude = ((Vector3)(ref velocity)).magnitude;
			float num = magnitude * 0.4f;
			Vector3 val = st.hostPos + st.hostVel * 0.15f;
			float num2 = (((Object)(object)st.cart != (Object)null) ? (Plugin.HeldDriftCorrectAt.Value * 0.4f) : Plugin.HeldDriftCorrectAt.Value) + num;
			float num3 = Vector3.Distance(st.rb.position, val);
			if (num3 > Plugin.HeldDriftHandbackAt.Value + num)
			{
				st.desyncTimer += Time.fixedDeltaTime;
				if (st.desyncTimer > 0.6f)
				{
					ForceHandback(st);
					return;
				}
			}
			else
			{
				st.desyncTimer = 0f;
			}
			if (num3 > 1.5f && magnitude < 1f)
			{
				st.stuckTimer += Time.fixedDeltaTime;
				if (st.stuckTimer > 0.8f)
				{
					st.stuckTimer = 0f;
					Snap(st);
					return;
				}
			}
			else
			{
				st.stuckTimer = 0f;
			}
			if (num3 > num2)
			{
				st.rb.position = Vector3.Lerp(st.rb.position, val, 0.05f);
			}
			if (Plugin.VerboseLogging.Value && (Object)(object)st.cart != (Object)null)
			{
				st.debugTimer -= Time.fixedDeltaTime;
				if (st.debugTimer <= 0f)
				{
					st.debugTimer = 1f;
					Plugin.Log.LogInfo((object)$"[cart] speed={magnitude:F1} drift={num3:F1} steered={localGrabber.physGrabForcesDisabledTimer > 0f} hostVel={((Vector3)(ref st.hostVel)).magnitude:F1}");
				}
			}
		}

		private static void DriveHeldCart(SimState st, PhysGrabber grabber)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			if (grabber.physGrabForcesDisabledTimer > 0f)
			{
				return;
			}
			PlayerAvatar playerAvatar = grabber.playerAvatar;
			if ((Object)(object)playerAvatar == (Object)null || (Object)(object)PlayerController.instance == (Object)null)
			{
				return;
			}
			Transform val = cartInCart.Invoke(st.cart);
			BoxCollider val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<BoxCollider>() : null);
			Vector3 val3 = ((Component)playerAvatar).transform.position + Vector3.up * 0.25f;
			if (!((Object)(object)val2 != (Object)null) || !(Vector3.Distance(((Collider)val2).ClosestPoint(val3), val3) < 0.01f))
			{
				grabber.OverridePhysGrabForcesDisable(0.1f);
				bool num = avatarSprinting.Invoke(playerAvatar);
				float num2 = (st.cart.isSmallCart ? 1.5f : 2f);
				float num3 = (st.cart.isSmallCart ? 2f : 2.5f);
				float num4 = (num ? 7f : 5f);
				bool flag = Vector3.Dot(PlayerController.instance.rb.velocity, ((Component)st.pgo).transform.forward) > 0f;
				if (num && flag)
				{
					num2 = 3f;
					num3 = 4f;
				}
				float num5 = Mathf.Clamp01(Vector3.Dot(st.rb.velocity, ((Component)grabber).transform.forward) / num4);
				float num6 = Mathf.Lerp(num2, num3, num5);
				Vector3 val4 = ((Component)grabber).transform.rotation * Vector3.back;
				Vector3 val5 = ((Component)playerAvatar).transform.position - val4 * num6;
				float num7 = Mathf.Clamp01(Vector3.Distance(((Component)st.pgo).transform.position, val5));
				Vector3 val6 = val5 - ((Component)st.pgo).transform.position;
				Vector3 val7 = Vector3.ClampMagnitude(((Vector3)(ref val6)).normalized * 5f * num7, 5f);
				float y = st.rb.velocity.y;
				Vector3 val8 = Vector3.MoveTowards(st.rb.velocity, val7, num7 * 2f);
				val8.y = y;
				st.rb.velocity = Vector3.ClampMagnitude(val8, 5f);
				Quaternion val9 = Quaternion.LookRotation(((Component)grabber).transform.position - ((Component)st.pgo).transform.position, Vector3.up);
				Quaternion val10 = Quaternion.Euler(0f, ((Quaternion)(ref val9)).eulerAngles.y + 180f, 0f);
				val9 = st.rb.rotation;
				Quaternion val11 = Quaternion.Euler(0f, ((Quaternion)(ref val9)).eulerAngles.y, 0f);
				val9 = val10 * Quaternion.Inverse(val11);
				float num8 = default(float);
				Vector3 val12 = default(Vector3);
				((Quaternion)(ref val9)).ToAngleAxis(ref num8, ref val12);
				if (num8 > 180f)
				{
					num8 -= 360f;
				}
				float num9 = Mathf.Clamp(Mathf.Clamp(Mathf.Abs(num8) / 180f, 0.2f, 1f) * 20f, 0f, 4f);
				Vector3 val13 = Vector3.ClampMagnitude((float)Math.PI / 180f * num8 * ((Vector3)(ref val12)).normalized * num9, 4f);
				st.rb.angularVelocity = Vector3.ClampMagnitude(Vector3.MoveTowards(st.rb.angularVelocity, val13, num9), 4f);
			}
		}

		private static void CheckHingeBroken(SimState st)
		{
			if (st.isHinge && !((Object)(object)st.hinge == (Object)null) && hingeBroken.Invoke(st.hinge))
			{
				if ((Object)(object)st.joint != (Object)null)
				{
					Object.Destroy((Object)(object)st.joint);
					st.joint = null;
				}
				st.isHinge = false;
			}
		}

		private static void TickShadow(SimState st)
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			pgoIsMaster.Invoke(st.pgo) = false;
			if (!pgoIsActive.Invoke(st.pgo))
			{
				return;
			}
			if (st.ridingTick == tickCounter)
			{
				if (st.rb.isKinematic)
				{
					st.rb.isKinematic = false;
				}
				st.hostTeleport = false;
				return;
			}
			if (!st.hasHostState)
			{
				return;
			}
			if (st.postThrowTimer > 0f)
			{
				st.postThrowTimer -= Time.fixedDeltaTime;
			}
			if (st.hostTeleport)
			{
				st.hostTeleport = false;
				Snap(st);
				return;
			}
			if (st.isHinge)
			{
				CheckHingeBroken(st);
			}
			if (st.hostKinematic && !st.isHinge)
			{
				if (!st.rb.isKinematic)
				{
					st.rb.isKinematic = true;
				}
				st.rb.MovePosition(st.hostPos);
				st.rb.MoveRotation(st.hostRot);
				return;
			}
			if (st.rb.isKinematic)
			{
				st.rb.isKinematic = false;
			}
			if (st.isHinge)
			{
				if (Quaternion.Angle(st.rb.rotation, st.hostRot) > 0.5f)
				{
					float num = Mathf.Clamp01(Plugin.PassiveSyncStrength.Value);
					st.rb.rotation = Quaternion.Slerp(st.rb.rotation, st.hostRot, num);
					st.rb.angularVelocity = Vector3.Lerp(st.rb.angularVelocity, st.hostAngVel, num);
				}
				return;
			}
			Vector3 val;
			if (st.hostSleeping)
			{
				if (st.rb.IsSleeping())
				{
					return;
				}
				val = st.rb.position - st.hostPos;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0025f && Quaternion.Angle(st.rb.rotation, st.hostRot) < 3f)
				{
					st.rb.velocity = Vector3.zero;
					st.rb.angularVelocity = Vector3.zero;
					st.rb.position = st.hostPos;
					st.rb.rotation = st.hostRot;
					st.rb.Sleep();
					return;
				}
			}
			float num2 = Vector3.Distance(st.rb.position, st.hostPos);
			if (num2 > Plugin.SnapDistance.Value)
			{
				Snap(st);
				return;
			}
			if (num2 > 1.5f)
			{
				val = st.rb.velocity;
				if (((Vector3)(ref val)).sqrMagnitude < 1f && st.postThrowTimer <= 0f)
				{
					st.stuckTimer += Time.fixedDeltaTime;
					if (st.stuckTimer > 1.2f)
					{
						st.stuckTimer = 0f;
						Snap(st);
						return;
					}
					goto IL_02be;
				}
			}
			st.stuckTimer = 0f;
			goto IL_02be;
			IL_02be:
			float num3 = Mathf.Clamp01(Plugin.PassiveSyncStrength.Value);
			if (st.postThrowTimer > 0f)
			{
				num3 *= 0.3f;
			}
			st.rb.position = Vector3.Lerp(st.rb.position, st.hostPos, num3);
			st.rb.rotation = Quaternion.Slerp(st.rb.rotation, st.hostRot, num3);
			st.rb.velocity = Vector3.Lerp(st.rb.velocity, st.hostVel, num3);
			st.rb.angularVelocity = Vector3.Lerp(st.rb.angularVelocity, st.hostAngVel, num3);
		}

		private static void ForceHandback(SimState st)
		{
			st.localGrab = false;
			st.desyncTimer = 0f;
			st.postThrowTimer = 0f;
			pgoIsMaster.Invoke(st.pgo) = false;
			handedBack.Add(st.pgo);
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)("Handed " + ((Object)st.pgo).name + " back to the host (drifted too far from its copy)."));
			}
		}

		private static void SweepHandedBack()
		{
			if (handedBack.Count == 0)
			{
				return;
			}
			handedBackSweep.Clear();
			foreach (PhysGrabObject item in handedBack)
			{
				if ((Object)(object)item == (Object)null)
				{
					handedBackSweep.Add(item);
					continue;
				}
				bool flag = false;
				List<PhysGrabber> playerGrabbing = item.playerGrabbing;
				for (int i = 0; i < playerGrabbing.Count; i++)
				{
					PhysGrabber val = playerGrabbing[i];
					if ((Object)(object)val != (Object)null && val.isLocal && val.grabbed)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					handedBackSweep.Add(item);
				}
			}
			foreach (PhysGrabObject item2 in handedBackSweep)
			{
				handedBack.Remove(item2);
			}
		}

		private static PhysGrabber GetLocalGrabber(SimState st)
		{
			List<PhysGrabber> playerGrabbing = st.pgo.playerGrabbing;
			for (int i = 0; i < playerGrabbing.Count; i++)
			{
				PhysGrabber val = playerGrabbing[i];
				if ((Object)(object)val != (Object)null && val.isLocal && val.grabbed && (Object)(object)grabberObject.Invoke(val) == (Object)(object)st.pgo)
				{
					return val;
				}
			}
			return null;
		}

		private static void Snap(SimState st)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			st.rb.position = st.hostPos;
			st.rb.rotation = st.hostRot;
			if (!st.rb.isKinematic)
			{
				st.rb.velocity = st.hostVel;
				st.rb.angularVelocity = st.hostAngVel;
			}
		}

		private static void Restore(SimState st)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)st.pgo != (Object)null)
				{
					pgoIsMaster.Invoke(st.pgo) = false;
				}
				if ((Object)(object)st.ptv != (Object)null && (Object)(object)st.rb != (Object)null)
				{
					Vector3 val = (st.hasHostState ? st.hostPos : st.rb.position);
					Quaternion val2 = (st.hasHostState ? st.hostRot : st.rb.rotation);
					ptvNetPos.Invoke(st.ptv) = val;
					ptvNetRot.Invoke(st.ptv) = val2;
					ptvStoredPos.Invoke(st.ptv) = val;
					ptvRecvPos.Invoke(st.ptv) = val;
					ptvRecvRot.Invoke(st.ptv) = val2;
					ptvPrevPos.Invoke(st.ptv) = val;
					ptvPrevRot.Invoke(st.ptv) = val2;
					ptvSmoothedPos.Invoke(st.ptv) = st.rb.position;
					ptvSmoothedRot.Invoke(st.ptv) = st.rb.rotation;
					ptvDistance.Invoke(st.ptv) = Vector3.Distance(st.rb.position, val);
					ptvAngle.Invoke(st.ptv) = Quaternion.Angle(st.rb.rotation, val2);
					ptvRecvVel.Invoke(st.ptv) = (st.hasHostState ? st.hostVel : st.rb.velocity);
					ptvRecvAngVel.Invoke(st.ptv) = (st.hasHostState ? st.hostAngVel : st.rb.angularVelocity);
					ptvFirstTake.Invoke(st.ptv) = false;
					ptvTeleport.Invoke(st.ptv) = false;
					ptvIsSleeping.Invoke(st.ptv) = st.hasHostState && st.hostSleeping;
					if (st.hasHostState)
					{
						st.rb.isKinematic = st.hostKinematic;
					}
				}
			}
			catch (Exception ex)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogWarning((object)("Restore failed: " + ex.Message));
				}
			}
			finally
			{
				HardRemove(st);
			}
		}

		private static void HardRemove(SimState st)
		{
			if ((Object)(object)st.pgo != (Object)null)
			{
				states.Remove(st.pgo);
			}
			if ((Object)(object)st.ptv != (Object)null)
			{
				byPtv.Remove(st.ptv);
			}
			if ((Object)(object)st.pgo == (Object)null || (Object)(object)st.ptv == (Object)null)
			{
				SweepDead();
			}
		}

		private static void SweepDead()
		{
			deadPgos.Clear();
			deadPtvs.Clear();
			foreach (KeyValuePair<PhysGrabObject, SimState> state in states)
			{
				if ((Object)(object)state.Key == (Object)null)
				{
					deadPgos.Add(state.Key);
				}
			}
			foreach (KeyValuePair<PhotonTransformView, SimState> item in byPtv)
			{
				if ((Object)(object)item.Key == (Object)null)
				{
					deadPtvs.Add(item.Key);
				}
			}
			foreach (PhysGrabObject deadPgo in deadPgos)
			{
				states.Remove(deadPgo);
			}
			foreach (PhotonTransformView deadPtv in deadPtvs)
			{
				byPtv.Remove(deadPtv);
			}
		}

		internal static void RestoreAll()
		{
			tickBuffer.Clear();
			tickBuffer.AddRange(states.Values);
			foreach (SimState item in tickBuffer)
			{
				Restore(item);
			}
			states.Clear();
			byPtv.Clear();
			handedBack.Clear();
		}
	}
	internal class SimDriver : MonoBehaviour
	{
		private float nextRegisterSweep;

		private void Start()
		{
			if (Chainloader.PluginInfos.ContainsKey("net.ovchinikov.nwrework"))
			{
				Plugin.Log.LogWarning((object)"The old NetworkingReworked mod is still installed! It is broken on current game versions and will fight this mod. Please uninstall/disable it.");
			}
			if (Chainloader.PluginInfos.ContainsKey("BlueAmulet.REPONetworkTweaks"))
			{
				Plugin.Log.LogWarning((object)"The old REPONetworkTweaks mod is still installed! It forces client rigidbodies kinematic and replaces PhotonTransformView, which breaks this mod's local simulation. Please uninstall/disable it (use NetworkTweaksRevived instead).");
			}
		}

		private void Update()
		{
			if (Time.unscaledTime < nextRegisterSweep)
			{
				return;
			}
			nextRegisterSweep = Time.unscaledTime + 5f;
			if (SimManager.Ready && SimManager.IsClientInLobby())
			{
				PhysGrabObject[] array = Object.FindObjectsOfType<PhysGrabObject>();
				for (int i = 0; i < array.Length; i++)
				{
					SimManager.TryRegister(array[i]);
				}
			}
		}

		private void FixedUpdate()
		{
			SimManager.Tick();
		}

		private void OnDestroy()
		{
			SimManager.RestoreAll();
		}
	}
}
namespace NetworkingRevived.Patches
{
	[HarmonyPatch(typeof(PhysGrabObject), "Start")]
	internal static class PhysGrabObjectStartPatch
	{
		private static void Postfix(PhysGrabObject __instance)
		{
			if (SimManager.Ready)
			{
				SimManager.TryRegister(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabStarted")]
	internal static class GrabStartedPatch
	{
		private static void Postfix(PhysGrabObject __instance, PhysGrabber player)
		{
			if (!SimManager.Ready || !SimManager.IsClientInLobby() || (Object)(object)player == (Object)null || !player.isLocal)
			{
				return;
			}
			if (SimManager.IsLocalGrab(__instance))
			{
				if (!__instance.playerGrabbing.Contains(player))
				{
					__instance.playerGrabbing.Add(player);
				}
			}
			else if (!SimManager.IsHandedBack(__instance) && SimManager.CanSimulate(__instance))
			{
				if (!__instance.playerGrabbing.Contains(player))
				{
					__instance.playerGrabbing.Add(player);
				}
				SimManager.StartLocalGrab(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabEnded")]
	internal static class GrabEndedPatch
	{
		private static void Postfix(PhysGrabObject __instance, PhysGrabber player)
		{
			if (SimManager.Ready && SimManager.IsClientInLobby() && !((Object)(object)player == (Object)null) && player.isLocal)
			{
				SimManager.ClearHandback(__instance);
				if (SimManager.IsLocalGrab(__instance))
				{
					__instance.playerGrabbing.Remove(player);
					SimManager.LocalThrow(__instance, player);
					SimManager.EndLocalGrab(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC")]
	internal static class GrabPlayerAddDedupePatch
	{
		private static bool Prefix(PhysGrabObject __instance, int photonViewID)
		{
			if (!SimManager.Ready || !SimManager.IsClientInLobby())
			{
				return true;
			}
			PhotonView val = PhotonView.Find(photonViewID);
			PhysGrabber val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PhysGrabber>() : null);
			if ((Object)(object)val2 != (Object)null && __instance.playerGrabbing.Contains(val2))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PhotonTransformView), "Update")]
	internal static class TransformViewUpdatePatch
	{
		private static bool Prefix(PhotonTransformView __instance)
		{
			if (!SimManager.Ready || !SimManager.IsSuppressed(__instance))
			{
				return true;
			}
			SimManager.TickKinematicTimer(__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(PhotonTransformView), "OnPhotonSerializeView")]
	internal static class TransformViewSerializePatch
	{
		private static bool Prefix(PhotonTransformView __instance, PhotonStream stream, PhotonMessageInfo info, bool __runOriginal)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				return false;
			}
			if (!SimManager.Ready || stream.IsWriting)
			{
				return true;
			}
			SimManager.SimState byPtv = SimManager.GetByPtv(__instance);
			if (byPtv == null)
			{
				return true;
			}
			if (info.Sender != PhotonNetwork.MasterClient)
			{
				return false;
			}
			try
			{
				byPtv.hostSleeping = (bool)stream.ReceiveNext();
				bool flag = (bool)stream.ReceiveNext();
				byPtv.hostTeleport |= flag;
				byPtv.hostKinematic = (bool)stream.ReceiveNext();
				byPtv.hostVel = (Vector3)stream.ReceiveNext();
				byPtv.hostAngVel = (Vector3)stream.ReceiveNext();
				Vector3 val = (Vector3)stream.ReceiveNext();
				Vector3 val2 = (Vector3)stream.ReceiveNext();
				float num = Mathf.Abs((float)(PhotonNetwork.Time - ((PhotonMessageInfo)(ref info)).SentServerTime));
				byPtv.hostPos = val + val2 * num;
				byPtv.hostRot = (Quaternion)stream.ReceiveNext();
				byPtv.hasHostState = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to read host state for " + ((Object)__instance).name + ": " + ex.Message));
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PhysGrabHinge), "Awake")]
	internal static class HingeJointKeeperPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo notMaster = AccessTools.Method(typeof(SemiFunc), "IsNotMasterClient", (Type[])null, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(HingeJointKeeperPatch), "NotMasterAndHingeSimOff", (Type[])null, (Type[])null);
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (notMaster != null && CodeInstructionExtensions.Calls(instruction, notMaster))
				{
					instruction.operand = replacement;
					replaced++;
				}
				yield return instruction;
			}
			if (replaced == 0)
			{
				Plugin.Log.LogWarning((object)"HingeJointKeeperPatch: PhysGrabHinge.Awake changed — doors stay host-driven.");
			}
		}

		public static bool NotMasterAndHingeSimOff()
		{
			if (SemiFunc.IsNotMasterClient())
			{
				return !Plugin.SimulateHinges.Value;
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class CartAuthorityPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			List<MethodBase> targets = new List<MethodBase>();
			Add(typeof(PhysGrabObject), "FixedUpdate");
			Add(typeof(PhysGrabCart), "FixedUpdate");
			Add(typeof(PhysGrabCart), "CartSteer");
			if (Plugin.InstantCartHandle.Value)
			{
				Add(typeof(PhysGrabObjectGrabArea), "Update");
			}
			return targets;
			void Add(Type type, string name)
			{
				MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					targets.Add(methodInfo);
				}
				else
				{
					Plugin.Log.LogWarning((object)("CartAuthorityPatch: " + type.Name + "." + name + " not found, skipping."));
				}
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			MethodInfo masterOrSingle = AccessTools.Method(typeof(SemiFunc), "IsMasterClientOrSingleplayer", (Type[])null, (Type[])null);
			MethodInfo punIsMaster = AccessTools.PropertyGetter(typeof(PhotonNetwork), "IsMasterClient");
			MethodInfo replacement = AccessTools.Method(typeof(CartAuthorityPatch), "MasterOrLocallySimulated", (Type[])null, (Type[])null);
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if ((masterOrSingle != null && CodeInstructionExtensions.Calls(instruction, masterOrSingle)) || (punIsMaster != null && CodeInstructionExtensions.Calls(instruction, punIsMaster)))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					val.labels.AddRange(instruction.labels);
					val.blocks.AddRange(instruction.blocks);
					yield return val;
					yield return new CodeInstruction(OpCodes.Call, (object)replacement);
					replaced++;
				}
				else
				{
					yield return instruction;
				}
			}
			if (replaced == 0)
			{
				Plugin.Log.LogWarning((object)("CartAuthorityPatch: no authority checks found in " + original.DeclaringType?.Name + "." + original.Name + " — game code may have changed."));
			}
		}

		public static bool MasterOrLocallySimulated(Component self)
		{
			if (!GameManager.Multiplayer())
			{
				return true;
			}
			if (PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			if ((Object)(object)self == (Object)null)
			{
				return false;
			}
			PhysGrabObject val = (PhysGrabObject)(object)((self is PhysGrabObject) ? self : null);
			if ((Object)(object)val == (Object)null)
			{
				val = self.GetComponent<PhysGrabObject>();
			}
			if ((Object)(object)val == (Object)null)
			{
				val = self.GetComponentInParent<PhysGrabObject>();
			}
			if ((Object)(object)val != (Object)null)
			{
				return SimManager.HasPhysicsAuthority(val);
			}
			return false;
		}
	}
}