Decompiled source of RevivalSync v1.0.4

RevivalSync.dll

Decompiled 6 hours 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 ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using RevivalSync.Patches;
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("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3+3db4f8c1d373e4a357297b57513458d2600d7918")]
[assembly: AssemblyProduct("RevivalSync")]
[assembly: AssemblyTitle("RevivalSync")]
[assembly: AssemblyVersion("1.0.3.0")]
namespace RevivalSync
{
	[BepInPlugin("com.Revival.revivalsync", "RevivalSync", "1.0.3")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.Revival.revivalsync";

		public const string PluginName = "RevivalSync";

		public const string PluginVersion = "1.0.3";

		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> DisableTimeout;

		internal static ConfigEntry<bool> PhotonLateUpdate;

		internal static ConfigEntry<bool> SmoothSync;

		internal static ConfigEntry<bool> Extrapolate;

		internal static ConfigEntry<float> Future;

		internal static ConfigEntry<float> RateSmoothing;

		internal static ConfigEntry<float> TimingThreshold;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static bool PhotonReady;

		private static Harmony harmony;

		private static bool capturePatched;

		internal static void EnsureCapturePatch()
		{
			if (capturePatched || !PhotonReady || harmony == null)
			{
				return;
			}
			capturePatched = true;
			try
			{
				harmony.PatchAll(typeof(SerializeReadCapturePatch));
				Log.LogInfo((object)"Host-state capture hooked (deferred until Photon start).");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to hook host-state capture: {arg}");
			}
		}

		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_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Expected O, but got Unknown
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Expected O, but got Unknown
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			SimulateCarts = ((BaseUnityPlugin)this).Config.Bind<bool>("Simulation", "SimulateCarts", true, "Simulate carts locally (removes cart input lag).");
			SimulateHinges = ((BaseUnityPlugin)this).Config.Bind<bool>("Simulation", "SimulateHinges", true, "Simulate doors/cabinets locally: the game's own hinge logic (closing, latching, bounce) runs on your machine so they respond instantly. Turn off to make them host-driven.");
			InstantCartHandle = ((BaseUnityPlugin)this).Config.Bind<bool>("Simulation", "InstantCartHandle", true, "Register cart handle grabs locally right away instead of waiting for the host.");
			PassiveSyncStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Simulation", "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>("Simulation", "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>("Simulation", "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>("Simulation", "HeldDriftCorrectAt", 1.5f, new ConfigDescription("While you hold an object: if your copy drifts further than this (meters) beyond the normal ping-trail from the host's copy, gently pull it back.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			HeldDriftHandbackAt = ((BaseUnityPlugin)this).Config.Bind<float>("Simulation", "HeldDriftHandbackAt", 4f, new ConfigDescription("While you hold an object: if your copy stays further than this (meters) beyond the normal ping-trail (e.g. the host's version got stuck), give control back to the host until you re-grab.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			DisableTimeout = ((BaseUnityPlugin)this).Config.Bind<bool>("NetworkTweaks", "DisableTimeout", true, "Remove Photon's client-sided timeout that randomly kicks you from lobbies on brief lag spikes.");
			PhotonLateUpdate = ((BaseUnityPlugin)this).Config.Bind<bool>("NetworkTweaks", "PhotonLateUpdate", true, "Process network packets every rendered frame instead of on the physics tick. Lower perceived latency.");
			SmoothSync = ((BaseUnityPlugin)this).Config.Bind<bool>("SmoothSync", "Enabled", true, "Hermite interpolation for host-driven objects the simulation doesn't own (enemies, doors...).");
			Extrapolate = ((BaseUnityPlugin)this).Config.Bind<bool>("SmoothSync", "Extrapolate", true, "Keep projecting movement briefly when an update is late or lost.");
			Future = ((BaseUnityPlugin)this).Config.Bind<float>("SmoothSync", "Future", 1f, new ConfigDescription("How far to project received data into the future, in update intervals.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			RateSmoothing = ((BaseUnityPlugin)this).Config.Bind<float>("SmoothSync", "RateSmoothing", 0.1f, new ConfigDescription("How quickly the measured update rate adapts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			TimingThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("SmoothSync", "TimingThreshold", 1f, new ConfigDescription("Seconds between updates after which data is considered discontinuous.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 5f), Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "VerboseLogging", true, "Log everything the sync system does: registrations, grabs/releases, snaps, handbacks, host packet flow, stale-data warnings and periodic stats. ON by default while the mod is in its experimental testing phase — attach LogOutput.log to bug reports.");
			if (!SimManager.InitAccessors())
			{
				Log.LogError((object)"RevivalSync could not find expected game internals (the game probably updated). The mod has disabled itself to avoid breaking your game.");
				return;
			}
			harmony = new Harmony("com.Revival.revivalsync");
			int num = 0;
			int num2 = 0;
			Type[] array = new Type[10]
			{
				typeof(DriverHooksPatch),
				typeof(PhotonHandlerAwakePatch),
				typeof(HingeJointKeeperPatch),
				typeof(PhysGrabObjectStartPatch),
				typeof(GrabStartedPatch),
				typeof(GrabEndedPatch),
				typeof(GrabPlayerAddDedupePatch),
				typeof(TransformViewUpdatePatch),
				typeof(TransformViewSerializePatch),
				typeof(CartAuthorityPatch)
			};
			foreach (Type type in array)
			{
				try
				{
					harmony.PatchAll(type);
					num++;
				}
				catch (Exception arg)
				{
					num2++;
					Log.LogError((object)$"Failed to apply patch {type.Name}: {arg}");
				}
			}
			if (SmoothSync.Value && Smoothing.InitAccessors())
			{
				try
				{
					harmony.PatchAll(typeof(Smoothing.SerializePatch));
					harmony.PatchAll(typeof(Smoothing.UpdatePatch));
					harmony.PatchAll(typeof(Smoothing.TeleportPatch));
					harmony.PatchAll(typeof(Smoothing.EnablePatch));
					Smoothing.Active = true;
				}
				catch (Exception arg2)
				{
					Log.LogError((object)$"Failed to apply SmoothSync patches, interpolation disabled: {arg2}");
				}
			}
			if (num == 0)
			{
				Log.LogError((object)"No patches could be applied — RevivalSync is inactive.");
				return;
			}
			Log.LogInfo((object)(string.Format("{0} {1} loaded. Patches: {2} ok, {3} failed. ", "RevivalSync", "1.0.3", num, num2) + $"SmoothSync: {Smoothing.Active}. Prediction activates when you join someone else's lobby; " + "the mod is inert while hosting."));
		}

		private void Update()
		{
			SimDriver.FrameUpdate();
		}

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

		private void OnDestroy()
		{
			SimManager.RestoreAll();
		}

		internal static void ApplyPhotonSettings()
		{
			if (!PhotonReady)
			{
				return;
			}
			try
			{
				if (PhotonLateUpdate.Value)
				{
					PhotonNetwork.MinimalTimeScaleToDispatchInFixedUpdate = float.PositiveInfinity;
				}
				if (DisableTimeout.Value)
				{
					LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient;
					LoadBalancingPeer val = ((networkingClient != null) ? networkingClient.LoadBalancingPeer : null);
					if (val != null)
					{
						((PhotonPeer)val).DisconnectTimeout = 3600000;
						((PhotonPeer)val).SentCountAllowance = 10000;
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not apply Photon settings: " + ex.Message));
			}
		}
	}
	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 int viewId;

			public bool localGrab;

			public float postThrowTimer;

			public float desyncTimer;

			public float stuckTimer;

			public float debugTimer;

			public int ridingTick;

			public bool hasHostState;

			public float lastPacketTime = -999f;

			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 Dictionary<int, SimState> byViewId = new Dictionary<int, 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>();

		internal static int PacketsCaptured;

		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<PhysGrabCart, Transform> cartInCart;

		private static FieldRef<PhysGrabCart, PhysGrabObjectGrabArea> cartGrabArea;

		private static FieldRef<PlayerAvatar, bool> avatarSprinting;

		private static FieldRef<PhysGrabHinge, bool> hingeBroken;

		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 bool wasClientInLobby;

		private static float lastTickFixedTime = -1f;

		private static bool tickMarker;

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

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

		private static readonly List<int> deadIds = new List<int>();

		internal static bool Ready { get; private set; }

		internal static int RegisteredCount => states.Count;

		internal static int HeldCount
		{
			get
			{
				int num = 0;
				foreach (SimState value in states.Values)
				{
					if (value.localGrab)
					{
						num++;
					}
				}
				return num;
			}
		}

		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");
				cartInCart = AccessTools.FieldRefAccess<PhysGrabCart, Transform>("inCart");
				cartGrabArea = AccessTools.FieldRefAccess<PhysGrabCart, PhysGrabObjectGrabArea>("physGrabObjectGrabArea");
				avatarSprinting = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isSprinting");
				hingeBroken = AccessTools.FieldRefAccess<PhysGrabHinge, bool>("broken");
				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 bool IsSuppressed(PhotonTransformView ptv)
		{
			if ((Object)(object)ptv != (Object)null)
			{
				return byPtv.ContainsKey(ptv);
			}
			return false;
		}

		internal static bool IsRegistered(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 GetByViewId(int viewId)
		{
			if (!byViewId.TryGetValue(viewId, out var value))
			{
				return null;
			}
			return value;
		}

		internal static void CacheHostState(SimState st, object[] data, int networkTime)
		{
			//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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 3; i + 7 < data.Length; i++)
			{
				if (data[i] is bool hostSleeping && data[i + 1] is bool flag && data[i + 2] is bool hostKinematic && data[i + 3] is Vector3 hostVel && data[i + 4] is Vector3 hostAngVel && data[i + 5] is Vector3 val && data[i + 6] is Vector3 val2 && data[i + 7] is Quaternion hostRot)
				{
					st.hostSleeping = hostSleeping;
					st.hostTeleport |= flag;
					st.hostKinematic = hostKinematic;
					st.hostVel = hostVel;
					st.hostAngVel = hostAngVel;
					float num = Mathf.Abs((float)(PhotonNetwork.Time - (double)networkTime / 1000.0));
					st.hostPos = val + val2 * num;
					st.hostRot = hostRot;
					st.hasHostState = true;
					st.lastPacketTime = Time.unscaledTime;
					PacketsCaptured++;
					break;
				}
			}
		}

		internal static SimState TryRegister(PhysGrabObject pgo)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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>();
			PhotonView component2 = ((Component)pgo).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (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>(),
				viewId = component2.ViewID
			};
			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;
				}
				pgo.spawned = true;
			}
			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;
			if (simState.viewId != 0)
			{
				byViewId[simState.viewId] = simState;
			}
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"[reg] {((Object)pgo).name} (view {simState.viewId}, cart={(Object)(object)simState.cart != (Object)null}, seeded={simState.hasHostState})");
			}
			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;
				simState.stuckTimer = 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)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			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 });
				if (Plugin.VerboseLogging.Value)
				{
					ManualLogSource log = Plugin.Log;
					string name = ((Object)pgo).name;
					Vector3 velocity = value.rb.velocity;
					log.LogInfo((object)$"[throw] {name} vel={((Vector3)(ref velocity)).magnitude:F1}");
				}
			}
			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 || Time.fixedTime == lastTickFixedTime)
			{
				return;
			}
			lastTickFixedTime = Time.fixedTime;
			if (!tickMarker)
			{
				tickMarker = true;
				Plugin.Log.LogInfo((object)"[driver] physics tick loop running");
			}
			SweepHandedBack();
			bool flag = IsClientInLobby();
			if (flag != wasClientInLobby)
			{
				wasClientInLobby = flag;
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)(flag ? "[mode] CLIENT — simulation active (we are not the host)" : "[mode] simulation idle (hosting, singleplayer or no lobby)"));
				}
			}
			if (states.Count == 0)
			{
				return;
			}
			tickCounter++;
			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);
					continue;
				}
				if (item2.viewId == 0)
				{
					PhotonView component = ((Component)item2.pgo).GetComponent<PhotonView>();
					if ((Object)(object)component != (Object)null && component.ViewID != 0)
					{
						item2.viewId = component.ViewID;
						byViewId[item2.viewId] = item2;
					}
				}
				if (!flag)
				{
					Restore(item2);
				}
				else if (item2.localGrab)
				{
					TickHeld(item2);
				}
				else
				{
					TickShadow(item2);
				}
			}
		}

		private static void TickHeld(SimState st)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: 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)
			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)
			{
				DebugHeld(st, localGrabber, -1f, 0f);
				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, "held object wedged in geometry, freeing to host position");
					return;
				}
			}
			else
			{
				st.stuckTimer = 0f;
			}
			if (num3 > num2)
			{
				st.rb.position = Vector3.Lerp(st.rb.position, val, 0.05f);
			}
			DebugHeld(st, localGrabber, num3, magnitude);
		}

		private static void DebugHeld(SimState st, PhysGrabber grabber, float drift, float speed)
		{
			if (Plugin.VerboseLogging.Value)
			{
				st.debugTimer -= Time.fixedDeltaTime;
				if (!(st.debugTimer > 0f))
				{
					st.debugTimer = 1f;
					float num = (st.hasHostState ? (Time.unscaledTime - st.lastPacketTime) : (-1f));
					Plugin.Log.LogInfo((object)($"[held] {((Object)st.pgo).name}: speed={speed:F1} drift={drift:F1} hostState={st.hasHostState} " + $"packetAge={num:F1}s hostKin={st.hostKinematic} hostSleep={st.hostSleeping} " + $"steered={grabber.physGrabForcesDisabledTimer > 0f}"));
				}
			}
		}

		private static void DriveHeldCart(SimState st, PhysGrabber grabber)
		{
			//IL_0081: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: 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_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_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: 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_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: 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_0208: 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_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: 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_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: 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_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: 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_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: 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_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			if (grabber.physGrabForcesDisabledTimer > 0f)
			{
				return;
			}
			PhysGrabObjectGrabArea val = cartGrabArea.Invoke(st.cart);
			if ((Object)(object)val == (Object)null || !val.listOfAllGrabbers.Contains(grabber))
			{
				return;
			}
			PlayerAvatar playerAvatar = grabber.playerAvatar;
			if ((Object)(object)playerAvatar == (Object)null || (Object)(object)PlayerController.instance == (Object)null)
			{
				return;
			}
			Transform val2 = cartInCart.Invoke(st.cart);
			BoxCollider val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<BoxCollider>() : null);
			Vector3 val4 = ((Component)playerAvatar).transform.position + Vector3.up * 0.25f;
			if (!((Object)(object)val3 != (Object)null) || !(Vector3.Distance(((Collider)val3).ClosestPoint(val4), val4) < 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 val5 = ((Component)grabber).transform.rotation * Vector3.back;
				Vector3 val6 = ((Component)playerAvatar).transform.position - val5 * num6;
				float num7 = Mathf.Clamp01(Vector3.Distance(((Component)st.pgo).transform.position, val6));
				Vector3 val7 = val6 - ((Component)st.pgo).transform.position;
				Vector3 val8 = Vector3.ClampMagnitude(((Vector3)(ref val7)).normalized * 5f * num7, 5f);
				float y = st.rb.velocity.y;
				Vector3 val9 = Vector3.MoveTowards(st.rb.velocity, val8, num7 * 2f);
				val9.y = y;
				st.rb.velocity = Vector3.ClampMagnitude(val9, 5f);
				Quaternion val10 = Quaternion.LookRotation(((Component)grabber).transform.position - ((Component)st.pgo).transform.position, Vector3.up);
				Quaternion val11 = Quaternion.Euler(0f, ((Quaternion)(ref val10)).eulerAngles.y + 180f, 0f);
				val10 = st.rb.rotation;
				Quaternion val12 = Quaternion.Euler(0f, ((Quaternion)(ref val10)).eulerAngles.y, 0f);
				val10 = val11 * Quaternion.Inverse(val12);
				float num8 = default(float);
				Vector3 val13 = default(Vector3);
				((Quaternion)(ref val10)).ToAngleAxis(ref num8, ref val13);
				if (num8 > 180f)
				{
					num8 -= 360f;
				}
				float num9 = Mathf.Clamp(Mathf.Clamp(Mathf.Abs(num8) / 180f, 0.2f, 1f) * 20f, 0f, 4f);
				Vector3 val14 = Vector3.ClampMagnitude((float)Math.PI / 180f * num8 * ((Vector3)(ref val13)).normalized * num9, 4f);
				st.rb.angularVelocity = Vector3.ClampMagnitude(Vector3.MoveTowards(st.rb.angularVelocity, val14, num9), 4f);
			}
		}

		private static void TickShadow(SimState st)
		{
			//IL_00d4: 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_00b7: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: 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_0296: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: 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_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: 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_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: 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, "host teleported it");
				return;
			}
			float num = Time.unscaledTime - st.lastPacketTime;
			bool flag = num > 0.35f;
			Vector3 val = (flag ? st.hostPos : (st.hostPos + st.hostVel * Mathf.Min(num, 0.25f)));
			Vector3 val2 = (flag ? Vector3.zero : st.hostVel);
			Vector3 val3 = (flag ? Vector3.zero : st.hostAngVel);
			if (st.hostKinematic && !st.isHinge)
			{
				if (!st.rb.isKinematic)
				{
					st.rb.isKinematic = true;
				}
				st.rb.MovePosition(val);
				st.rb.MoveRotation(st.hostRot);
				return;
			}
			if (st.rb.isKinematic)
			{
				st.rb.isKinematic = false;
			}
			if (st.isHinge)
			{
				CheckHingeBroken(st);
				if (Quaternion.Angle(st.rb.rotation, st.hostRot) > 0.5f)
				{
					float num2 = Mathf.Clamp01(Plugin.PassiveSyncStrength.Value);
					st.rb.MoveRotation(Quaternion.Slerp(st.rb.rotation, st.hostRot, num2));
					st.rb.angularVelocity = Vector3.Lerp(st.rb.angularVelocity, val3, num2);
				}
				return;
			}
			Vector3 val4;
			if (st.hostSleeping || flag)
			{
				if (st.rb.IsSleeping())
				{
					return;
				}
				val4 = st.rb.position - st.hostPos;
				if (((Vector3)(ref val4)).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;
					if (st.hostSleeping)
					{
						st.rb.Sleep();
					}
					return;
				}
			}
			float num3 = Vector3.Distance(st.rb.position, val);
			if (num3 > Plugin.SnapDistance.Value)
			{
				Snap(st, "beyond snap distance");
				return;
			}
			if (num3 > 1.5f)
			{
				val4 = st.rb.velocity;
				if (((Vector3)(ref val4)).sqrMagnitude < 1f && st.postThrowTimer <= 0f)
				{
					st.stuckTimer += Time.fixedDeltaTime;
					if (st.stuckTimer > 1.2f)
					{
						st.stuckTimer = 0f;
						Snap(st, "wedged in geometry, freeing to host position");
						return;
					}
					goto IL_032f;
				}
			}
			st.stuckTimer = 0f;
			goto IL_032f;
			IL_032f:
			float num4 = Mathf.Clamp01(Plugin.PassiveSyncStrength.Value);
			if (st.postThrowTimer > 0f)
			{
				num4 *= 0.3f;
			}
			st.rb.MovePosition(Vector3.Lerp(st.rb.position, val, num4));
			st.rb.MoveRotation(Quaternion.Slerp(st.rb.rotation, st.hostRot, num4));
			st.rb.velocity = Vector3.Lerp(st.rb.velocity, val2, num4);
			st.rb.angularVelocity = Vector3.Lerp(st.rb.angularVelocity, val3, num4);
		}

		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;
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("[hinge] " + ((Object)st.pgo).name + " broke on the host — local joint dropped"));
				}
			}
		}

		private static void ForceHandback(SimState st)
		{
			st.localGrab = false;
			st.desyncTimer = 0f;
			st.stuckTimer = 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, string reason)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.VerboseLogging.Value)
			{
				float num = Vector3.Distance(st.rb.position, st.hostPos);
				Plugin.Log.LogInfo((object)$"[snap] {((Object)st.pgo).name}: {reason} (dist={num:F1}m)");
			}
			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 (st.viewId != 0)
			{
				byViewId.Remove(st.viewId);
			}
			if ((Object)(object)st.pgo == (Object)null || (Object)(object)st.ptv == (Object)null)
			{
				SweepDead();
			}
		}

		private static void SweepDead()
		{
			deadPgos.Clear();
			deadPtvs.Clear();
			deadIds.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 (KeyValuePair<int, SimState> item2 in byViewId)
			{
				if ((Object)(object)item2.Value.pgo == (Object)null)
				{
					deadIds.Add(item2.Key);
				}
			}
			foreach (PhysGrabObject deadPgo in deadPgos)
			{
				states.Remove(deadPgo);
			}
			foreach (PhotonTransformView deadPtv in deadPtvs)
			{
				byPtv.Remove(deadPtv);
			}
			foreach (int deadId in deadIds)
			{
				byViewId.Remove(deadId);
			}
		}

		internal static void RestoreAll()
		{
			if (Plugin.VerboseLogging.Value && states.Count > 0)
			{
				Plugin.Log.LogInfo((object)$"[mode] restoring {states.Count} objects to vanilla sync");
			}
			tickBuffer.Clear();
			tickBuffer.AddRange(states.Values);
			foreach (SimState item in tickBuffer)
			{
				Restore(item);
			}
			states.Clear();
			byPtv.Clear();
			byViewId.Clear();
			handedBack.Clear();
		}
	}
	internal static class SimDriver
	{
		private static bool announced;

		private static bool conflictsChecked;

		private static float nextRegisterSweep;

		private static float nextStatsLog;

		private static int lastPacketCount;

		private static int lastFrame = -1;

		internal static void FrameUpdate()
		{
			if (Time.frameCount == lastFrame)
			{
				return;
			}
			lastFrame = Time.frameCount;
			if (!announced)
			{
				announced = true;
				Plugin.Log.LogInfo((object)"[driver] alive — update loop running");
			}
			Plugin.EnsureCapturePatch();
			if (!conflictsChecked && Time.unscaledTime > 10f)
			{
				conflictsChecked = true;
				string[] array = new string[4] { "net.ovchinikov.nwrework", "BlueAmulet.REPONetworkTweaks", "com.Revival.networkingrevived", "com.Revival.networktweaksrevived" };
				foreach (string text in array)
				{
					if (Chainloader.PluginInfos.ContainsKey(text))
					{
						Plugin.Log.LogWarning((object)("Conflicting mod '" + text + "' is still installed! RevivalSync replaces it — please uninstall/disable the old mod."));
					}
				}
			}
			if (Time.unscaledTime >= nextRegisterSweep)
			{
				nextRegisterSweep = Time.unscaledTime + 5f;
				if (SimManager.Ready && SimManager.IsClientInLobby())
				{
					PhysGrabObject[] array2 = Object.FindObjectsOfType<PhysGrabObject>();
					for (int i = 0; i < array2.Length; i++)
					{
						SimManager.TryRegister(array2[i]);
					}
				}
			}
			if (Plugin.VerboseLogging.Value && Time.unscaledTime >= nextStatsLog)
			{
				nextStatsLog = Time.unscaledTime + 10f;
				if (SimManager.IsClientInLobby())
				{
					int packetsCaptured = SimManager.PacketsCaptured;
					Plugin.Log.LogInfo((object)($"[stats] registered={SimManager.RegisteredCount} held={SimManager.HeldCount} " + $"packets={packetsCaptured} (+{packetsCaptured - lastPacketCount} in 10s)"));
					lastPacketCount = packetsCaptured;
				}
			}
			Plugin.ApplyPhotonSettings();
			Smoothing.Sweep();
		}
	}
	internal static class Smoothing
	{
		private class Snapshot
		{
			internal Vector3 position;

			internal Quaternion rotation;

			internal Vector3 velocity;

			internal Vector3 angularVelocity;
		}

		private class InterpState
		{
			internal Rigidbody rb;

			internal Transform tf;

			internal PhysGrabHinge hinge;

			internal readonly LinkedList<Snapshot> snapshots = new LinkedList<Snapshot>();

			internal Snapshot prev;

			internal float interpStartTime = -1f;

			internal float smoothFreq = 0.1f;

			internal int lastTimestamp;

			internal bool haveFirst;

			internal Vector3 interpVel;

			internal Vector3 interpAngVel;

			internal void Clear()
			{
				snapshots.Clear();
				prev = null;
				interpStartTime = -1f;
			}
		}

		[HarmonyPatch(typeof(PhotonTransformView), "OnPhotonSerializeView")]
		internal static class SerializePatch
		{
			private static void Postfix(PhotonTransformView __instance, PhotonStream stream, PhotonMessageInfo info, bool __runOriginal)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				if (!__runOriginal || stream.IsWriting || !ShouldSmooth(__instance) || info.Sender != PhotonNetwork.MasterClient)
				{
					return;
				}
				InterpState orCreate = GetOrCreate(__instance);
				int sentServerTimestamp = ((PhotonMessageInfo)(ref info)).SentServerTimestamp;
				if (orCreate.haveFirst && sentServerTimestamp == orCreate.lastTimestamp)
				{
					return;
				}
				try
				{
					Record(__instance, orCreate, sentServerTimestamp);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("SmoothSync record failed on " + ((Object)__instance).name + ": " + ex.Message));
					orCreate.Clear();
				}
			}
		}

		[HarmonyPatch(typeof(PhotonTransformView), "Update")]
		internal static class UpdatePatch
		{
			private static void Postfix(PhotonTransformView __instance)
			{
				if (ShouldSmooth(__instance) && states.TryGetValue(__instance, out var value) && value.snapshots.Count != 0 && !teleportField.Invoke(__instance) && !sleepingField.Invoke(__instance))
				{
					Apply(value);
				}
			}
		}

		[HarmonyPatch(typeof(PhotonTransformView), "Teleport")]
		internal static class TeleportPatch
		{
			private static void Postfix(PhotonTransformView __instance)
			{
				if (states.TryGetValue(__instance, out var value))
				{
					value.Clear();
				}
			}
		}

		[HarmonyPatch(typeof(PhotonTransformView), "OnEnable")]
		internal static class EnablePatch
		{
			private static void Postfix(PhotonTransformView __instance)
			{
				if (states.TryGetValue(__instance, out var value))
				{
					value.Clear();
					value.haveFirst = false;
				}
			}
		}

		internal static bool Active;

		private static readonly Dictionary<PhotonTransformView, InterpState> states = new Dictionary<PhotonTransformView, InterpState>();

		private static FieldRef<PhotonTransformView, Vector3> recvPos;

		private static FieldRef<PhotonTransformView, Quaternion> recvRot;

		private static FieldRef<PhotonTransformView, Vector3> recvVel;

		private static FieldRef<PhotonTransformView, Vector3> recvAngVel;

		private static FieldRef<PhotonTransformView, Vector3> direction;

		private static FieldRef<PhotonTransformView, bool> teleportField;

		private static FieldRef<PhotonTransformView, bool> sleepingField;

		private static FieldRef<PhysGrabHinge, bool> hingeBroken;

		private static float nextSweep;

		internal static bool InitAccessors()
		{
			try
			{
				recvPos = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedPosition");
				recvRot = AccessTools.FieldRefAccess<PhotonTransformView, Quaternion>("receivedRotation");
				recvVel = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedVelocity");
				recvAngVel = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("receivedAngularVelocity");
				direction = AccessTools.FieldRefAccess<PhotonTransformView, Vector3>("m_Direction");
				teleportField = AccessTools.FieldRefAccess<PhotonTransformView, bool>("teleport");
				sleepingField = AccessTools.FieldRefAccess<PhotonTransformView, bool>("isSleeping");
				hingeBroken = AccessTools.FieldRefAccess<PhysGrabHinge, bool>("broken");
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SmoothSync accessor init failed: {arg}");
				return false;
			}
		}

		private static float BaseFrequency()
		{
			return 1f / (float)Mathf.Max(1, PhotonNetwork.SerializationRate);
		}

		private static bool ShouldSmooth(PhotonTransformView ptv)
		{
			if (!Active || PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom)
			{
				return false;
			}
			if (SimManager.IsSuppressed(ptv))
			{
				states.Remove(ptv);
				return false;
			}
			return true;
		}

		private static InterpState GetOrCreate(PhotonTransformView ptv)
		{
			if (!states.TryGetValue(ptv, out var value))
			{
				value = new InterpState
				{
					rb = ((Component)ptv).GetComponent<Rigidbody>(),
					tf = ((Component)ptv).transform,
					hinge = ((Component)ptv).GetComponent<PhysGrabHinge>(),
					smoothFreq = BaseFrequency()
				};
				states[ptv] = value;
			}
			return value;
		}

		internal static void Sweep()
		{
			if (Time.unscaledTime < nextSweep || states.Count == 0)
			{
				return;
			}
			nextSweep = Time.unscaledTime + 10f;
			if (!PhotonNetwork.InRoom)
			{
				states.Clear();
				return;
			}
			List<PhotonTransformView> list = null;
			foreach (KeyValuePair<PhotonTransformView, InterpState> state in states)
			{
				if ((Object)(object)state.Key == (Object)null)
				{
					(list ?? (list = new List<PhotonTransformView>())).Add(state.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (PhotonTransformView item in list)
			{
				states.Remove(item);
			}
		}

		private static void Record(PhotonTransformView ptv, InterpState st, int timestamp)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: 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_00c3: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: 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_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			bool num = teleportField.Invoke(ptv);
			bool flag = sleepingField.Invoke(ptv);
			if (num || flag)
			{
				st.Clear();
				st.lastTimestamp = timestamp;
				st.haveFirst = true;
				return;
			}
			Vector3 velocity = recvVel.Invoke(ptv);
			Snapshot snapshot = new Snapshot
			{
				position = recvPos.Invoke(ptv),
				rotation = recvRot.Invoke(ptv),
				velocity = velocity,
				angularVelocity = recvAngVel.Invoke(ptv)
			};
			if ((Object)(object)st.hinge != (Object)null && !hingeBroken.Invoke(st.hinge))
			{
				Vector3 val = direction.Invoke(ptv);
				snapshot.velocity = (st.haveFirst ? (val / (float)Mathf.Max(1, timestamp - st.lastTimestamp) * 1000f) : (val / st.smoothFreq));
			}
			float num2 = Mathf.Max(Plugin.Future.Value * st.smoothFreq, 0f);
			if (st.snapshots.Count > 0 && (float)(timestamp - st.lastTimestamp) / 1000f < Plugin.TimingThreshold.Value)
			{
				Snapshot value = st.snapshots.Last.Value;
				Vector3 val2 = (snapshot.velocity - value.velocity) / st.smoothFreq;
				snapshot.position += snapshot.velocity * num2 + 0.5f * val2 * num2 * num2;
				Vector3 val3 = (snapshot.angularVelocity - value.angularVelocity) / st.smoothFreq;
				snapshot.rotation *= Quaternion.Euler((snapshot.angularVelocity + val3 * num2) * num2);
			}
			else
			{
				snapshot.position += snapshot.velocity * num2;
				snapshot.rotation *= Quaternion.Euler(snapshot.angularVelocity * num2);
			}
			st.snapshots.AddLast(snapshot);
			if (st.snapshots.Count == 2)
			{
				st.interpStartTime = Time.timeSinceLevelLoad;
			}
			else if (st.snapshots.Count >= 4)
			{
				st.snapshots.RemoveFirst();
				Snapshot value2 = st.snapshots.First.Value;
				value2.position = st.tf.position;
				value2.rotation = st.tf.rotation;
				value2.velocity = st.interpVel;
				value2.angularVelocity = st.interpAngVel;
				st.interpStartTime = Time.timeSinceLevelLoad;
			}
			if (st.haveFirst)
			{
				float num3 = (float)(timestamp - st.lastTimestamp) / 1000f;
				st.smoothFreq = ((num3 >= Plugin.TimingThreshold.Value) ? BaseFrequency() : Mathf.Lerp(st.smoothFreq, num3, Plugin.RateSmoothing.Value));
			}
			else
			{
				st.haveFirst = true;
			}
			st.lastTimestamp = timestamp;
		}

		private static void Apply(InterpState st)
		{
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: 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_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_01f1: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: 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)
			float num = InterpFactor(st);
			while (num >= 1f && st.snapshots.Count > 1)
			{
				st.prev = st.snapshots.First.Value;
				st.snapshots.RemoveFirst();
				st.interpStartTime += st.smoothFreq;
				num = InterpFactor(st);
			}
			Vector3 val;
			Quaternion val2;
			if (st.snapshots.Count == 1)
			{
				Snapshot value = st.snapshots.First.Value;
				if (st.prev != null && Plugin.Extrapolate.Value)
				{
					float num2 = 2f - Mathf.Pow((float)Math.E, 0f - num);
					val = value.position + Vector3.SlerpUnclamped(st.prev.velocity, value.velocity, num2) * ((num2 - 1f) * st.smoothFreq);
					val2 = Quaternion.SlerpUnclamped(st.prev.rotation, value.rotation, num2);
				}
				else
				{
					val = value.position;
					val2 = value.rotation;
				}
				st.interpVel = value.velocity;
				st.interpAngVel = value.angularVelocity;
			}
			else
			{
				Snapshot value2 = st.snapshots.First.Value;
				Snapshot value3 = st.snapshots.First.Next.Value;
				val = HermitePosition(value2.position, value2.velocity, value3.position, value3.velocity, num, st.smoothFreq);
				val2 = HermiteRotation(value2.rotation, value2.angularVelocity, value3.rotation, value3.angularVelocity, num, st.smoothFreq);
				st.interpVel = Vector3.Slerp(value2.velocity, value3.velocity, num);
				st.interpAngVel = Vector3.Lerp(value2.angularVelocity, value3.angularVelocity, num);
			}
			if ((Object)(object)st.rb != (Object)null)
			{
				st.rb.MovePosition(val);
				st.rb.MoveRotation(val2);
			}
			else if ((Object)(object)st.tf != (Object)null)
			{
				st.tf.position = val;
				st.tf.rotation = val2;
			}
		}

		private static float InterpFactor(InterpState st)
		{
			if (st.smoothFreq <= 0f || st.interpStartTime < 0f)
			{
				return 1f;
			}
			return (Time.timeSinceLevelLoad - st.interpStartTime) / st.smoothFreq;
		}

		private static Vector3 HermitePosition(Vector3 startPos, Vector3 startVel, Vector3 endPos, Vector3 endVel, float t, float freq)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = startPos + startVel * (freq * t) / 3f;
			Vector3 val2 = endPos - endVel * (freq * (1f - t)) / 3f;
			return Vector3.Lerp(val, val2, t);
		}

		private static Quaternion HermiteRotation(Quaternion startRot, Vector3 startSpin, Quaternion endRot, Vector3 endSpin, float t, float freq)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			Quaternion val = startRot * Quaternion.Euler(startSpin * (freq * t) / 3f);
			Quaternion val2 = endRot * Quaternion.Euler(endSpin * (-1f * freq * (1f - t)) / 3f);
			return Quaternion.Slerp(val, val2, t);
		}
	}
}
namespace RevivalSync.Patches
{
	[HarmonyPatch(typeof(PhysGrabObject), "Start")]
	internal static class PhysGrabObjectStartPatch
	{
		private static void Postfix(PhysGrabObject __instance)
		{
			if (SimManager.Ready)
			{
				SimManager.TryRegister(__instance);
			}
		}
	}
	[HarmonyPatch]
	internal static class SerializeReadCapturePatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(PhotonNetwork), "OnSerializeRead", (Type[])null, (Type[])null);
		}

		private static void Prefix(object[] data, Player sender, int networkTime)
		{
			if (!SimManager.Ready || data == null || data.Length < 4 || PhotonNetwork.IsMasterClient || sender == null || sender != PhotonNetwork.MasterClient || !(data[0] is int num))
			{
				return;
			}
			SimManager.SimState byViewId = SimManager.GetByViewId(num);
			if (byViewId == null)
			{
				return;
			}
			try
			{
				SimManager.CacheHostState(byViewId, data, networkTime);
			}
			catch (Exception ex)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogWarning((object)$"Capture failed for view {num}: {ex.Message}");
				}
			}
		}
	}
	[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))
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("[dedupe] host grab broadcast for " + ((Object)__instance).name + " (already registered locally)"));
				}
				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_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				return false;
			}
			if (!SimManager.Ready || stream.IsWriting)
			{
				return true;
			}
			if (!SimManager.IsRegistered(__instance))
			{
				return true;
			}
			if (info.Sender != PhotonNetwork.MasterClient)
			{
				return false;
			}
			try
			{
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
				stream.ReceiveNext();
			}
			catch (Exception ex)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogWarning((object)("Stream discard failed on " + ((Object)__instance).name + ": " + ex.Message));
				}
			}
			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.SimulateHinges.Value)
			{
				Add(typeof(PhysGrabHinge), "FixedUpdate");
			}
			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;
		}
	}
	[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 DriverHooksPatch
	{
		[HarmonyPatch(typeof(GameDirector), "Update")]
		[HarmonyPostfix]
		private static void OnFrame()
		{
			SimDriver.FrameUpdate();
		}

		[HarmonyPatch(typeof(PlayerController), "FixedUpdate")]
		[HarmonyPostfix]
		private static void OnPhysicsTick()
		{
			SimManager.Tick();
		}
	}
	[HarmonyPatch(typeof(PhotonHandler), "Awake")]
	internal static class PhotonHandlerAwakePatch
	{
		private static void Postfix()
		{
			bool num = !Plugin.PhotonReady;
			Plugin.PhotonReady = true;
			Plugin.ApplyPhotonSettings();
			if (num)
			{
				Plugin.Log.LogInfo((object)"Photon is up — timeout and LateUpdate dispatch settings applied.");
			}
		}
	}
}