Decompiled source of GK2 Coop v0.27.0

GK2Coop.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DG.Tweening;
using FlowCanvas;
using GK2.FlowCanvasNodes;
using HarmonyLib;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using Sirenix.Serialization;
using Steamworks;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GK2Coop")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GK2Coop")]
[assembly: AssemblyTitle("GK2Coop")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GK2Coop
{
	internal static class ChestLocks
	{
		private const byte OpRequest = 1;

		private const byte OpGrant = 2;

		private const byte OpDeny = 3;

		private const byte OpRelease = 4;

		private const byte OpTable = 5;

		private static readonly Dictionary<string, ulong> locks = new Dictionary<string, ulong>();

		private static string myOpenChest;

		private static float openedAt;

		private static ChestInteractionHandler pendingHandler;

		private static PlayerController pendingInteractor;

		private static string pendingChest;

		private static string grantedChest;

		private static ulong Me
		{
			get
			{
				if (CoopSession.Role != CoopRole.Host)
				{
					return CoopNetwork.LocalClientId;
				}
				return 0uL;
			}
		}

		public static void Reset()
		{
			locks.Clear();
			myOpenChest = null;
			pendingHandler = null;
			pendingInteractor = null;
			pendingChest = null;
			grantedChest = null;
		}

		private static string Name(ulong id)
		{
			object obj;
			if (id == 0L)
			{
				obj = PlayerSync.Host?.Label ?? "the host";
			}
			else
			{
				obj = PartnerProfiles.NameOf(id);
				if (obj == null)
				{
					obj = PlayerSync.Get(id)?.Label;
					if (obj == null)
					{
						return $"Player {id}";
					}
				}
			}
			return (string)obj;
		}

		public static bool BeforeOpen(ChestInteractionHandler handler, PlayerController interactor, Wgo chest)
		{
			if (CoopSession.Role != CoopRole.None && CoopSession.KeepWorldRunning)
			{
				object obj;
				if (chest == null)
				{
					obj = null;
				}
				else
				{
					WgoData data = chest.Data;
					obj = ((data != null) ? data.UniqueId : null);
				}
				if (!((SGuid)obj == (SGuid)null))
				{
					string id = chest.Data.UniqueId.Id;
					if (locks.TryGetValue(id, out var value) && value != Me)
					{
						CoopRunner.Think(Name(value) + " is using this chest.");
						return false;
					}
					if (CoopSession.Role == CoopRole.Host)
					{
						SetLock(id, 0uL);
						MarkOpen(id);
						return true;
					}
					if (grantedChest == id)
					{
						grantedChest = null;
						MarkOpen(id);
						return true;
					}
					pendingHandler = handler;
					pendingInteractor = interactor;
					pendingChest = id;
					Send(null, 1, id);
					return false;
				}
			}
			return true;
		}

		private static void MarkOpen(string uid)
		{
			myOpenChest = uid;
			openedAt = Time.unscaledTime;
		}

		public static void Tick()
		{
			if (myOpenChest != null && !(Time.unscaledTime - openedAt < 0.5f) && !AnyChestWindowOpen())
			{
				string uid = myOpenChest;
				myOpenChest = null;
				if (CoopSession.Role == CoopRole.Host)
				{
					ReleaseLock(uid);
				}
				else if (CoopSession.Role == CoopRole.Client)
				{
					ContainerSync.SendChangedEverywhere();
					Send(null, 4, uid);
				}
			}
		}

		private static bool AnyChestWindowOpen()
		{
			try
			{
				UIChestWindow window = LazyUI.GetWindow<UIChestWindow>();
				int result;
				if (window == null || !((LazyWindow<UIBaseChestWindowData>)(object)window).IsShown)
				{
					UIConveyorChestWindow window2 = LazyUI.GetWindow<UIConveyorChestWindow>();
					if (window2 == null || !((LazyWindow<UIBaseChestWindowData>)(object)window2).IsShown)
					{
						UIConveyorVegetablesChestWindow window3 = LazyUI.GetWindow<UIConveyorVegetablesChestWindow>();
						if (window3 == null || !((LazyWindow<UIBaseChestWindowData>)(object)window3).IsShown)
						{
							result = ((((LazyWindow<UIBaseChestWindowData>)(object)LazyUI.GetWindow<UIConveyorWineChestWindow>())?.IsShown ?? false) ? 1 : 0);
							goto IL_004d;
						}
					}
				}
				result = 1;
				goto IL_004d;
				IL_004d:
				return (byte)result != 0;
			}
			catch
			{
				return false;
			}
		}

		public static void OnPlayerLeft(ulong clientId)
		{
			foreach (string item in (from p in locks
				where p.Value == clientId
				select p.Key).ToList())
			{
				ReleaseLock(item);
			}
		}

		private static void SetLock(string uid, ulong owner)
		{
			locks[uid] = owner;
			BroadcastTable();
		}

		private static void ReleaseLock(string uid)
		{
			if (locks.Remove(uid))
			{
				BroadcastTable();
			}
		}

		private unsafe static void BroadcastTable()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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)
			if (CoopSession.Role != CoopRole.Host)
			{
				return;
			}
			FastBufferWriter val = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val;
				byte b = 5;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				int count = locks.Count;
				((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives));
				foreach (KeyValuePair<string, ulong> @lock in locks)
				{
					CoopMessages.WriteString(ref writer, @lock.Key);
					ulong value = @lock.Value;
					((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref value, default(ForPrimitives));
				}
				CoopMessages.SendToReadyClients("GK2Coop.Locks", writer, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void Send(ulong? to, byte op, string uid)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			FastBufferWriter val = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref op, default(ForPrimitives));
				CoopMessages.WriteString(ref writer, uid);
				if (CoopSession.Role == CoopRole.Client)
				{
					CoopMessages.SendToHost("GK2Coop.Locks", writer, (NetworkDelivery)3);
				}
				else if (to.HasValue)
				{
					CoopMessages.SendTo("GK2Coop.Locks", to.Value, writer, (NetworkDelivery)3);
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public static void OnLocks(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (b == 5)
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				locks.Clear();
				ulong value = default(ulong);
				for (int i = 0; i < num; i++)
				{
					string key = CoopMessages.ReadString(ref reader);
					((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref value, default(ForPrimitives));
					locks[key] = value;
				}
				return;
			}
			string text = CoopMessages.ReadString(ref reader);
			switch (b)
			{
			case 1:
				if (CoopSession.Role == CoopRole.Host)
				{
					if (locks.TryGetValue(text, out var value4) && value4 != sender)
					{
						Send(sender, 3, text);
						CoopLog.Info(Name(sender) + " can't open chest " + text + ": " + Name(value4) + " has it open.");
					}
					else
					{
						SetLock(text, sender);
						Send(sender, 2, text);
					}
				}
				break;
			case 4:
			{
				if (CoopSession.Role == CoopRole.Host && locks.TryGetValue(text, out var value3) && value3 == sender)
				{
					ReleaseLock(text);
				}
				break;
			}
			case 2:
				if (CoopSession.Role != CoopRole.Client)
				{
					break;
				}
				if (pendingChest == text && pendingHandler != null && (Object)(object)pendingInteractor != (Object)null)
				{
					grantedChest = text;
					ChestInteractionHandler val = pendingHandler;
					PlayerController val2 = pendingInteractor;
					pendingHandler = null;
					pendingInteractor = null;
					pendingChest = null;
					try
					{
						((WGOInteractionHandlerBase)val).Interact(val2);
						break;
					}
					catch (Exception e)
					{
						CoopLog.Error("Opening the chest after the host's OK failed", e);
						Send(null, 4, text);
						break;
					}
				}
				Send(null, 4, text);
				break;
			case 3:
				if (CoopSession.Role == CoopRole.Client)
				{
					pendingHandler = null;
					pendingInteractor = null;
					pendingChest = null;
					CoopRunner.Think(locks.TryGetValue(text, out var value2) ? (Name(value2) + " is using this chest.") : "Someone else is using this chest.");
				}
				break;
			}
		}
	}
	[HarmonyPatch(typeof(ChestInteractionHandler), "Interact")]
	internal static class LockChestWhileOpen
	{
		private static bool Prefix(ChestInteractionHandler __instance, PlayerController interactor, Wgo ___assignedWgo, ref bool __result)
		{
			try
			{
				if (!ChestLocks.BeforeOpen(__instance, interactor, ___assignedWgo))
				{
					__result = true;
					return false;
				}
			}
			catch (Exception e)
			{
				CoopLog.Error("Chest lock check failed; opening anyway", e);
			}
			return true;
		}
	}
	internal static class CombatSync
	{
		private struct HpEntry
		{
			public string Uid;

			public int Hp;

			public int Max;
		}

		private const byte OpFightState = 1;

		private const byte OpDamage = 2;

		private const byte OpPlayerHit = 3;

		private const byte OpKnockedOut = 4;

		private const byte OpHp = 5;

		private const byte OpWaves = 6;

		private const float HpInterval = 0.25f;

		private const float LocalHitGrace = 1.2f;

		private static readonly FieldInfo HpChangedField = AccessTools.Field(typeof(HPComponent), "OnHpChanged");

		private static readonly FieldInfo FirstDamageField = AccessTools.Field(typeof(HPComponent), "OnFirstDamageDealt");

		private static readonly FieldInfo FullHpField = AccessTools.Field(typeof(HPComponent), "OnFullHpRestored");

		private static readonly MethodInfo EnsureLevelMethod = AccessTools.Method(typeof(FightingGameController), "EnsureFightingLevelLoaded", (Type[])null, (Type[])null);

		private static readonly FieldRef<FightingGameController, bool> WasLevelLoadedField = AccessTools.FieldRefAccess<FightingGameController, bool>("wasLevelLoaded");

		private static readonly FieldRef<PlayerPhysicalBody, PlayerData> BodyPlayerDataField = AccessTools.FieldRefAccess<PlayerPhysicalBody, PlayerData>("playerData");

		private static readonly FieldRef<PlayerData, SGuid> PlayerGuidField = AccessTools.FieldRefAccess<PlayerData, SGuid>("guid");

		public static int Sent;

		public static int Applied;

		private static FightState hostState = (FightState)0;

		private static string hostLevel = "";

		private static string hostScene = "";

		private static readonly Dictionary<ulong, PlayerPhysicalBody> registered = new Dictionary<ulong, PlayerPhysicalBody>();

		private static readonly Dictionary<HPComponent, ulong> avatarHp = new Dictionary<HPComponent, ulong>();

		private static readonly HashSet<ulong> knockedOutPartners = new HashSet<ulong>();

		private static readonly Dictionary<string, long> sentHp = new Dictionary<string, long>();

		private static readonly Dictionary<ulong, string> hpSceneSentTo = new Dictionary<ulong, string>();

		private static float nextHp;

		private static float nextTargets;

		private static float nextWaves;

		private static readonly FieldRef<FightingGameController, FightingLevelPresetProcessor> HostWavesField = AccessTools.FieldRefAccess<FightingGameController, FightingLevelPresetProcessor>("presetProcessor");

		private static readonly MethodInfo WavesProgressSetter = AccessTools.PropertySetter(typeof(FightingLevelPresetProcessor), "CurrentProgress");

		private static readonly MethodInfo WavesTotalSetter = AccessTools.PropertySetter(typeof(FightingLevelPresetProcessor), "TotalDuration");

		private static readonly FieldInfo WavesProgressEvent = AccessTools.Field(typeof(FightingLevelPresetProcessor), "OnProgressChanged");

		private static FightingLevelPresetProcessor shownWaves;

		private static bool timelineShown;

		private static float hostWavesProgress;

		private static float hostWavesTotal;

		private static FightState fightHere = (FightState)0;

		private static string fightLevel = "";

		private static string fightScene = "";

		private static bool levelShown;

		private static bool levelLoadedHere;

		private static string shownLevel = "";

		private static bool armed;

		private static bool gearChecked;

		private static bool knockedOut;

		private static float nextStanceCheck;

		private static readonly HashSet<string> markedFighters = new HashSet<string>();

		private static readonly Dictionary<string, float> recentLocalHits = new Dictionary<string, float>();

		public static bool ApplyingRemote;

		public static bool FightAroundHost
		{
			get
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Invalid comparison between Unknown and I4
				if (CoopSession.Role == CoopRole.Client)
				{
					return (int)fightHere > 0;
				}
				return false;
			}
		}

		public static bool InHostFight
		{
			get
			{
				if (CoopSession.Role == CoopRole.Client)
				{
					return armed;
				}
				return false;
			}
		}

		public static void Reset()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (armed || levelShown)
			{
				try
				{
					LeaveFight("session ended");
				}
				catch (Exception e)
				{
					CoopLog.Error("Putting the weapon away failed", e);
				}
			}
			HideTimeline();
			hostWavesProgress = 0f;
			hostWavesTotal = 0f;
			hostState = (FightState)0;
			hostLevel = "";
			hostScene = "";
			registered.Clear();
			avatarHp.Clear();
			knockedOutPartners.Clear();
			sentHp.Clear();
			hpSceneSentTo.Clear();
			fightHere = (FightState)0;
			fightLevel = "";
			fightScene = "";
			levelShown = false;
			levelLoadedHere = false;
			shownLevel = "";
			armed = false;
			gearChecked = false;
			knockedOut = false;
			markedFighters.Clear();
			recentLocalHits.Clear();
			ApplyingRemote = false;
			Sent = 0;
			Applied = 0;
		}

		public static void Tick()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Invalid comparison between Unknown and I4
			if (CoopSession.Role == CoopRole.Host && CoopSession.HasReadyClients && CoopSession.IsInGame)
			{
				if (Time.unscaledTime >= nextHp)
				{
					nextHp = Time.unscaledTime + 0.25f;
					SendHp();
				}
				if (Time.unscaledTime >= nextTargets)
				{
					nextTargets = Time.unscaledTime + 0.5f;
					UpdatePartnerTargets();
				}
				if ((int)hostState == 2 && Time.unscaledTime >= nextWaves)
				{
					nextWaves = Time.unscaledTime + 0.25f;
					SendWaves();
				}
			}
			else if (CoopSession.Role == CoopRole.Client && CoopSession.ClientInWorld)
			{
				TickStamina();
				if (Time.unscaledTime >= nextStanceCheck)
				{
					nextStanceCheck = Time.unscaledTime + 0.5f;
					UpdateStance();
				}
			}
		}

		private static void TickStamina()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!armed || MainGame.IsGamePaused)
			{
				return;
			}
			try
			{
				FightingGameController instance = LazySingleton<FightingGameController>.Instance;
				if ((Object)(object)instance != (Object)null && (int)instance.CurrentFightState != 0)
				{
					return;
				}
				PlayerData playerData = MainGame.PlayerData;
				if (playerData != null)
				{
					StaminaSystem staminaSystem = playerData.staminaSystem;
					if (staminaSystem != null)
					{
						staminaSystem.UpdateStaminaLogic(Time.deltaTime);
					}
				}
			}
			catch (Exception ex)
			{
				CoopLog.Debug("Refilling stamina failed: " + ex.Message);
			}
		}

		private static long Pack(HPComponent hp)
		{
			return ((long)hp.MaxHpValue << 32) | (uint)hp.Hp;
		}

		private static void SendHp()
		{
			HashSet<string> hashSet = NpcSync.ScenesWithPartners();
			List<HpEntry> list = new List<HpEntry>();
			foreach (string item in hashSet)
			{
				foreach (WgoData item2 in SceneObjects(item))
				{
					HPComponent hpComponent = item2.HpComponent;
					if (hpComponent != null && hpComponent.MaxHpValue > 0 && !(item2.UniqueId == (SGuid)null))
					{
						string id = item2.UniqueId.Id;
						long num = Pack(hpComponent);
						long value;
						bool num2 = sentHp.TryGetValue(id, out value);
						sentHp[id] = num;
						if (num2 && value != num && hpComponent.Hp > 0)
						{
							list.Add(new HpEntry
							{
								Uid = id,
								Hp = hpComponent.Hp,
								Max = hpComponent.MaxHpValue
							});
						}
					}
				}
			}
			SendHpEntries(list, null);
			foreach (ulong item3 in CoopSession.ReadyClients.ToList())
			{
				RemotePlayer remotePlayer = PlayerSync.Get(item3);
				if (remotePlayer == null || !remotePlayer.HasState || string.IsNullOrEmpty(remotePlayer.Scene) || (hpSceneSentTo.TryGetValue(item3, out var value2) && value2 == remotePlayer.Scene))
				{
					continue;
				}
				hpSceneSentTo[item3] = remotePlayer.Scene;
				List<HpEntry> list2 = new List<HpEntry>();
				foreach (WgoData item4 in SceneObjects(remotePlayer.Scene))
				{
					HPComponent hpComponent2 = item4.HpComponent;
					if (hpComponent2 != null && hpComponent2.MaxHpValue > 0 && hpComponent2.Hp > 0 && hpComponent2.Hp < hpComponent2.MaxHpValue && item4.UniqueId != (SGuid)null)
					{
						list2.Add(new HpEntry
						{
							Uid = item4.UniqueId.Id,
							Hp = hpComponent2.Hp,
							Max = hpComponent2.MaxHpValue
						});
					}
				}
				SendHpEntries(list2, item3);
				if (list2.Count > 0)
				{
					CoopLog.Debug($"Sent the HP of {list2.Count} damaged objects in '{remotePlayer.Scene}' to {remotePlayer.Label}.");
				}
			}
		}

		private static IEnumerable<WgoData> SceneObjects(string scene)
		{
			WorldData worldData = MainGame.WorldData;
			GameSceneData val = ((worldData != null) ? worldData.GetGameSceneDataById(scene) : null);
			if (val == null)
			{
				return Enumerable.Empty<WgoData>();
			}
			return val.wgoDataList.Where((WgoData d) => d != null).ToList();
		}

		private unsafe static void SendHpEntries(List<HpEntry> entries, ulong? onlyTo)
		{
			//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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0047: 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_0080: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < entries.Count; i += 80)
			{
				List<HpEntry> list = entries.Skip(i).Take(80).ToList();
				FastBufferWriter val = CoopMessages.NewWriter();
				try
				{
					FastBufferWriter writer = val;
					byte b = 5;
					((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
					int count = list.Count;
					((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives));
					foreach (HpEntry item in list)
					{
						HpEntry current = item;
						CoopMessages.WriteString(ref writer, current.Uid);
						((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref current.Hp, default(ForPrimitives));
						((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref current.Max, default(ForPrimitives));
					}
					if (onlyTo.HasValue)
					{
						CoopMessages.SendTo("GK2Coop.Combat", onlyTo.Value, writer, (NetworkDelivery)3);
					}
					else
					{
						CoopMessages.SendToReadyClients("GK2Coop.Combat", writer, (NetworkDelivery)3);
					}
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
				Sent++;
			}
		}

		public static void NoteLocalHit(WgoData data)
		{
			if (((data != null) ? data.UniqueId : null) != (SGuid)null && CoopSession.Role == CoopRole.Client)
			{
				recentLocalHits[data.UniqueId.Id] = Time.unscaledTime + 1.2f;
			}
		}

		public static void ApplyHitHp(WgoData data, int hp, int max)
		{
			HPComponent val = ((data != null) ? data.HpComponent : null);
			if (val == null || hp <= 0 || max <= 0)
			{
				return;
			}
			if (CoopSession.Role == CoopRole.Host)
			{
				if (hp < val.Hp)
				{
					SetHp(data, hp, max);
				}
			}
			else
			{
				ApplyHostHp(data, hp, max);
			}
		}

		private static void ApplyHostHp(WgoData data, int hp, int max)
		{
			HPComponent hpComponent = data.HpComponent;
			if (hpComponent != null && (hp <= hpComponent.Hp || !recentLocalHits.TryGetValue(data.UniqueId.Id, out var value) || !(Time.unscaledTime < value)))
			{
				SetHp(data, hp, max);
			}
		}

		private static void SetHp(WgoData data, int hp, int max)
		{
			HPComponent hpComponent = data.HpComponent;
			if (hpComponent == null || hpComponent.isDeathDelayed || (hpComponent.Hp == hp && hpComponent.MaxHpValue == max))
			{
				return;
			}
			bool flag = !hpComponent.WasDamagedAtLeastOnce;
			if (hpComponent.MaxHpValue != max)
			{
				hpComponent.SetCustomHpValue(max, true);
			}
			hpComponent.SetCustomHpValue(Mathf.Clamp(hp, 1, max), false);
			bool flag2 = hp >= max;
			hpComponent.wasDamagedAtLeastOnce = !flag2;
			try
			{
				if (flag && !flag2)
				{
					(FirstDamageField?.GetValue(hpComponent) as Action)?.Invoke();
				}
				(HpChangedField?.GetValue(hpComponent) as Action<HPComponent>)?.Invoke(hpComponent);
				if (flag2)
				{
					(FullHpField?.GetValue(hpComponent) as Action)?.Invoke();
				}
			}
			catch (Exception ex)
			{
				CoopLog.Warn("HP change listeners on " + ((ObjectLinkedToDefinition<WGODef>)(object)data).id + " failed: " + ex.Message);
			}
			Applied++;
		}

		public unsafe static void OnHostFightState(FightingGameController controller, FightState state)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_007e: Invalid comparison between Unknown and I4
			if (CoopSession.Role == CoopRole.Host)
			{
				hostState = state;
				string value = (((Object)(object)controller.CurrentLevel != (Object)null) ? controller.CurrentLevel.id : "");
				if (!string.IsNullOrEmpty(value))
				{
					hostLevel = value;
				}
				hostScene = MainGame.PlayerData?.currentGameSceneId ?? "";
				CoopLog.Info($"Host fight state: {state} (level '{hostLevel}', area '{hostScene}').");
				if ((int)state != 2)
				{
					UnregisterPartners("fight is " + ((object)(*(FightState*)(&state))/*cast due to .constrained prefix*/).ToString());
					knockedOutPartners.Clear();
				}
				if (CoopSession.HasReadyClients)
				{
					SendFightState(null);
				}
			}
		}

		private unsafe static void SendFightState(ulong? onlyTo)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0010: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			FastBufferWriter val = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val;
				byte b = 1;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				b = (byte)hostState;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				CoopMessages.WriteString(ref writer, hostLevel ?? "");
				CoopMessages.WriteString(ref writer, hostScene ?? "");
				if (onlyTo.HasValue)
				{
					CoopMessages.SendTo("GK2Coop.Combat", onlyTo.Value, writer, (NetworkDelivery)3);
				}
				else
				{
					CoopMessages.SendToReadyClients("GK2Coop.Combat", writer, (NetworkDelivery)3);
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
			Sent++;
		}

		public static void OnClientReady(ulong clientId)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			hpSceneSentTo.Remove(clientId);
			if ((int)hostState != 0)
			{
				SendFightState(clientId);
			}
		}

		private static void UpdatePartnerTargets()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			FightingGameController instance = LazySingleton<FightingGameController>.Instance;
			if ((Object)(object)instance == (Object)null || (int)instance.CurrentFightState != 2)
			{
				if (registered.Count > 0)
				{
					UnregisterPartners("no fight");
				}
				return;
			}
			string text = MainGame.PlayerData?.currentGameSceneId;
			foreach (ulong item in CoopSession.ReadyClients.ToList())
			{
				RemotePlayer remotePlayer = PlayerSync.Get(item);
				bool flag = remotePlayer != null && (Object)(object)remotePlayer.Body != (Object)null && remotePlayer.Visible && remotePlayer.HasState && remotePlayer.Scene == text && !knockedOutPartners.Contains(item);
				registered.TryGetValue(item, out var value);
				if (flag && (Object)(object)value != (Object)(object)remotePlayer.Body)
				{
					if ((Object)(object)value != (Object)null)
					{
						Unregister(item, value);
					}
					Register(item, remotePlayer);
				}
				else if (!flag && (Object)(object)value != (Object)null)
				{
					Unregister(item, value);
				}
			}
			foreach (ulong item2 in registered.Keys.Where((ulong c) => !CoopSession.ReadyClients.Contains(c)).ToList())
			{
				Unregister(item2, registered[item2]);
			}
		}

		private static void Register(ulong clientId, RemotePlayer remote)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			try
			{
				PlayerData val = (((Object)(object)remote.Controller != (Object)null) ? remote.Controller.PlayerData : null);
				if (val != null)
				{
					if (PlayerGuidField.Invoke(val) == (SGuid)null || PlayerGuidField.Invoke(val).Equals(MainGame.PlayerData.Guid))
					{
						PlayerGuidField.Invoke(val) = new SGuid();
					}
					BodyPlayerDataField.Invoke(remote.Body) = val;
					val.hpComponent.RestoreFullHp();
					remote.Body.IsActiveCombatant = true;
					LazySingleton<FightingGameController>.Instance.RegisterTargetNonPersistent((ICombatEntity)(object)remote.Body, -1, -1, true);
					registered[clientId] = remote.Body;
					avatarHp[val.hpComponent] = clientId;
					CoopLog.Info(remote.Label + " is now a fight target.");
				}
			}
			catch (Exception e)
			{
				CoopLog.Error("Making " + remote.Label + " a fight target failed", e);
			}
		}

		private static void Unregister(ulong clientId, PlayerPhysicalBody body)
		{
			registered.Remove(clientId);
			foreach (HPComponent item in (from p in avatarHp
				where p.Value == clientId
				select p.Key).ToList())
			{
				avatarHp.Remove(item);
			}
			try
			{
				if ((Object)(object)body != (Object)null)
				{
					LazySingleton<FightingGameController>.Instance.UnregisterTarget((ICombatEntity)(object)body);
					body.IsActiveCombatant = true;
				}
			}
			catch (Exception ex)
			{
				CoopLog.Warn("Removing a partner from the fight targets failed: " + ex.Message);
			}
		}

		public static void UnregisterPartners(string why)
		{
			if (registered.Count == 0)
			{
				return;
			}
			CoopLog.Info($"Removing {registered.Count} partners from the fight targets ({why}).");
			foreach (KeyValuePair<ulong, PlayerPhysicalBody> item in registered.ToList())
			{
				Unregister(item.Key, item.Value);
			}
		}

		public unsafe static void OnHpDamaged(HPComponent component, int before)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			if (CoopSession.Role != CoopRole.Host || component == null || !avatarHp.TryGetValue(component, out var value))
			{
				return;
			}
			int num = before - component.Hp;
			component.RestoreFullHp();
			if (num > 0)
			{
				FastBufferWriter val = CoopMessages.NewWriter();
				try
				{
					FastBufferWriter writer = val;
					byte b = 3;
					((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
					((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					CoopMessages.SendTo("GK2Coop.Combat", value, writer, (NetworkDelivery)3);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
				Sent++;
				CoopLog.Debug($"{PlayerSync.Get(value)?.Label ?? value.ToString()} was hit for {num}.");
			}
		}

		private static void HostApplyPartnerDamage(ulong sender, string uid, int damage)
		{
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_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_0105: 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_010a: 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)
			WorldData worldData = MainGame.WorldData;
			WgoData val = ((worldData != null) ? worldData.GetWgoData(SGuid.Parse(uid)) : null);
			HPComponent val2 = ((val != null) ? val.HpComponent : null);
			if (val2 == null || damage <= 0)
			{
				return;
			}
			Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(val.UniqueId);
			val2.ApplyDamage(damage);
			Applied++;
			CoopLog.Debug($"{PlayerSync.Get(sender)?.Label ?? sender.ToString()} hit {((ObjectLinkedToDefinition<WGODef>)(object)val).id} for {damage} (HP {val2.Hp}/{val2.MaxHpValue}).");
			if ((Object)(object)wgoViewGlobal == (Object)null)
			{
				return;
			}
			try
			{
				PlayerPhysicalBody physicalBody = MainGame.PlayerController.PhysicalBody;
				Vector3 val3 = PlayerSync.Get(sender)?.Position ?? ((Component)physicalBody).transform.position;
				Vector3 val4 = val.Position - val3;
				Vector3 normalized = ((Vector3)(ref val4)).normalized;
				AttackContext val5 = default(AttackContext);
				((AttackContext)(ref val5))..ctor((ICombatEntity)(object)physicalBody, (TeamType)0, (FighterDef)null, (ItemDef)null, val3, normalized, val.Position, damage, false, (AttackComponent)null, (DamageEffectSettings)null);
				wgoViewGlobal.OnOtherCombatTargetHitMe(val5);
			}
			catch (Exception ex)
			{
				CoopLog.Warn("On-hit logic for " + ((ObjectLinkedToDefinition<WGODef>)(object)val).id + " failed: " + ex.Message);
			}
		}

		private static void UpdateStance()
		{
			//IL_0000: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if ((int)fightHere == 0)
			{
				gearChecked = false;
			}
			else if (!gearChecked)
			{
				PlayerController playerController = MainGame.PlayerController;
				if (((playerController != null) ? playerController.PlayerData : null) != null)
				{
					gearChecked = true;
					FightGear.EnsureOwn(MainGame.PlayerController, withSword: true);
				}
			}
			PlayerController playerController2 = MainGame.PlayerController;
			string text = ((playerController2 == null) ? null : playerController2.PlayerData?.currentGameSceneId);
			bool flag = (int)fightHere != 0 && !string.IsNullOrEmpty(text) && text == fightScene;
			if (flag && (!levelShown || shownLevel != fightLevel))
			{
				ShowLevel();
			}
			bool flag2 = flag && (int)fightHere == 2 && !knockedOut;
			if (flag2 && !armed)
			{
				Arm();
			}
			else if (!flag2 && armed)
			{
				Disarm();
			}
			if (!flag && levelShown)
			{
				LeaveFight(((int)fightHere == 0) ? "the fight ended" : "we left the fight's area");
			}
			else if (flag)
			{
				MarkFighters(text);
			}
		}

		private static void ShowLevel()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Invalid comparison between Unknown and I4
			levelShown = true;
			shownLevel = fightLevel;
			if (string.IsNullOrEmpty(fightLevel))
			{
				return;
			}
			FightingGameController instance = LazySingleton<FightingGameController>.Instance;
			try
			{
				bool flag = WasLevelLoadedField.Invoke(instance);
				WasLevelLoadedField.Invoke(instance) = false;
				EnsureLevelMethod?.Invoke(instance, new object[1] { fightLevel });
				levelLoadedHere = WasLevelLoadedField.Invoke(instance);
				WasLevelLoadedField.Invoke(instance) = flag;
			}
			catch (Exception e)
			{
				CoopLog.Error("Loading fight level '" + fightLevel + "' here failed", e);
			}
			try
			{
				FightingLevel fightingLevel = MainGame.GetFightingLevel(fightLevel);
				if ((Object)(object)fightingLevel != (Object)null)
				{
					fightingLevel.ApplyStageId(((int)fightHere == 2) ? 4 : 3);
					fightingLevel.SetActive(true);
					fightingLevel.SetBorderObjectsActive(true);
				}
				CoopLog.Info($"Showing the host's fight level '{fightLevel}' (loaded here: {levelLoadedHere}, found: {(Object)(object)fightingLevel != (Object)null}).");
			}
			catch (Exception e2)
			{
				CoopLog.Error("Showing fight level '" + fightLevel + "' failed", e2);
			}
		}

		private static void Arm()
		{
			armed = true;
			try
			{
				PlayerController playerController = MainGame.PlayerController;
				MainGame.PlayerData.RemoveInteractingItem();
				FightGear.EnsureOwn(playerController, withSword: true);
				playerController.SetArmorView(true, (int?)null, true);
				FightGear.DrawWeapon(playerController);
				Item sword = playerController.Sword;
				Item bow = playerController.Bow;
				ItemDef val = ((sword != null && ((ObjectLinkedToDefinition<ItemDef>)(object)sword).id != "empty") ? ((ObjectLinkedToDefinition<ItemDef>)(object)sword).Definition : ((bow != null && ((ObjectLinkedToDefinition<ItemDef>)(object)bow).id != "empty") ? ((ObjectLinkedToDefinition<ItemDef>)(object)bow).Definition : null));
				MainGame.PlayerData.staminaSystem.SetMax();
				playerController.View.UpdateStaminaBarState();
				try
				{
					FightingLevel fightingLevel = MainGame.GetFightingLevel(fightLevel);
					if (fightingLevel != null)
					{
						fightingLevel.ApplyStageId(4);
					}
				}
				catch
				{
				}
				ShowTimeline();
				string text = PlayerSync.Host?.Label ?? "the host";
				CoopRunner.Toast("Fight! Help " + text + ": attack the enemies.", 6f);
				CoopLog.Info("Joined " + text + "'s fight with " + ((val != null) ? ((BalanceBaseObject)val).id : "the default sword") + ".");
			}
			catch (Exception e)
			{
				CoopLog.Error("Getting the weapon out failed", e);
			}
		}

		private unsafe static void SendWaves()
		{
			//IL_0023: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0069: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			FightingLevelPresetProcessor val = HostWavesField.Invoke(LazySingleton<FightingGameController>.Instance);
			if ((Object)(object)val == (Object)null || !val.IsPlaying)
			{
				return;
			}
			FastBufferWriter val2 = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val2;
				byte b = 6;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				float currentProgress = val.CurrentProgress;
				((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref currentProgress, default(ForPrimitives));
				currentProgress = val.TotalDuration;
				((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref currentProgress, default(ForPrimitives));
				CoopMessages.SendToReadyClients("GK2Coop.Combat", writer, (NetworkDelivery)1);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void ShowTimeline()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//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_00a1: Expected O, but got Unknown
			if (timelineShown)
			{
				return;
			}
			try
			{
				FightingLevel fightingLevel = MainGame.GetFightingLevel(fightLevel);
				HUD val = LazyUI.Get<HUD>();
				if ((Object)(object)((fightingLevel != null) ? fightingLevel.FightingLevelPreset : null) == (Object)null || (Object)(object)val == (Object)null)
				{
					CoopLog.Debug("No wave timeline for '" + fightLevel + "' here (level " + (((Object)(object)fightingLevel != (Object)null) ? "has no preset" : "not found") + ").");
					return;
				}
				if ((Object)(object)shownWaves == (Object)null)
				{
					GameObject val2 = new GameObject("GK2Coop fight waves");
					Object.DontDestroyOnLoad((Object)val2);
					shownWaves = val2.AddComponent<FightingLevelPresetProcessor>();
				}
				SetShownWaves(hostWavesProgress, hostWavesTotal);
				val.DrawFightingTimeline(new UIFightingTimelineRendererData(fightingLevel.FightingLevelPreset, shownWaves, fightingLevel));
				val.SetMode((HUDMode)1);
				timelineShown = true;
				CoopLog.Info("Showing the host's wave timeline for '" + fightLevel + "'.");
			}
			catch (Exception ex)
			{
				CoopLog.Warn("Showing the wave timeline failed: " + ex.Message);
			}
		}

		private static void HideTimeline()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			if (!timelineShown)
			{
				return;
			}
			timelineShown = false;
			try
			{
				HUD val = LazyUI.Get<HUD>();
				if ((Object)(object)val != (Object)null && (int)val.Mode == 1)
				{
					val.HideFightingTimeline();
					val.SetMode((HUDMode)0);
				}
			}
			catch (Exception ex)
			{
				CoopLog.Warn("Putting the HUD back after the fight failed: " + ex.Message);
			}
		}

		private static void SetShownWaves(float progress, float total)
		{
			if (!((Object)(object)shownWaves == (Object)null))
			{
				WavesTotalSetter?.Invoke(shownWaves, new object[1] { total });
				WavesProgressSetter?.Invoke(shownWaves, new object[1] { Mathf.Clamp(progress, 0f, Mathf.Max(total, progress)) });
				(WavesProgressEvent?.GetValue(shownWaves) as Action<float>)?.Invoke(shownWaves.ProgressNormalized);
			}
		}

		private static void Disarm()
		{
			HideTimeline();
			armed = false;
			try
			{
				PlayerController playerController = MainGame.PlayerController;
				playerController.AttackComponent.UnequipWeapon();
				playerController.SetArmorView(false, (int?)null, true);
				playerController.View.UpdateStaminaBarState();
			}
			catch (Exception e)
			{
				CoopLog.Error("Putting the weapon away failed", e);
			}
		}

		private static void LeaveFight(string why)
		{
			if (armed)
			{
				Disarm();
			}
			UnmarkFighters();
			if (levelShown && !string.IsNullOrEmpty(shownLevel))
			{
				try
				{
					FightingLevel fightingLevel = MainGame.GetFightingLevel(shownLevel);
					if ((Object)(object)fightingLevel != (Object)null)
					{
						fightingLevel.SetActive(false);
						fightingLevel.SetBorderObjectsActive(false);
					}
					GameSceneData val = default(GameSceneData);
					GameSceneConfig val2 = default(GameSceneConfig);
					if (levelLoadedHere && MainGame.WorldData.TryGetGameSceneDataForContent(shownLevel, ref val, ref val2))
					{
						val.RemoveFightingLevelData(shownLevel);
					}
				}
				catch (Exception e)
				{
					CoopLog.Error("Hiding fight level '" + shownLevel + "' failed", e);
				}
			}
			try
			{
				PlayerData playerData = MainGame.PlayerData;
				if (playerData != null)
				{
					HPComponent hpComponent = playerData.hpComponent;
					if (hpComponent != null)
					{
						hpComponent.RestoreFullHp();
					}
				}
			}
			catch
			{
			}
			CoopLog.Info("Left the fight (" + why + ").");
			levelShown = false;
			levelLoadedHere = false;
			shownLevel = "";
			knockedOut = false;
		}

		private static void MarkFighters(string scene)
		{
			HashSet<string> hashSet = GameBalance.Me?.fighterWgoIdsCache;
			if (hashSet == null)
			{
				return;
			}
			foreach (WgoData item in SceneObjects(scene))
			{
				if (!(item.UniqueId == (SGuid)null) && hashSet.Contains(((ObjectLinkedToDefinition<WGODef>)(object)item).id))
				{
					Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(item.UniqueId);
					if ((Object)(object)wgoViewGlobal != (Object)null && !wgoViewGlobal.IsActiveCombatant)
					{
						wgoViewGlobal.IsActiveCombatant = true;
						markedFighters.Add(item.UniqueId.Id);
					}
				}
			}
		}

		private static void UnmarkFighters()
		{
			foreach (string markedFighter in markedFighters)
			{
				try
				{
					Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(SGuid.Parse(markedFighter));
					if ((Object)(object)wgoViewGlobal != (Object)null)
					{
						wgoViewGlobal.IsActiveCombatant = false;
					}
				}
				catch
				{
				}
			}
			markedFighters.Clear();
		}

		public unsafe static bool OnLocalAttackHit(AttackComponent attacker, ICombatEntity target, AttackContext context)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00ab: 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_00d5: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (CoopSession.Role != CoopRole.Client || !CoopSession.ClientInWorld || !Plugin.HostRunsWorld.Value || ApplyingRemote)
			{
				return true;
			}
			PlayerController playerController = MainGame.PlayerController;
			if ((Object)(object)playerController == (Object)null || (Object)(object)attacker != (Object)(object)playerController.AttackComponent)
			{
				return false;
			}
			Wgo val = (Wgo)(object)((target is Wgo) ? target : null);
			if (val != null)
			{
				WgoData data = val.Data;
				if (!(((data != null) ? data.UniqueId : null) == (SGuid)null) && !knockedOut)
				{
					int num = 0;
					try
					{
						num = target.ArmorValue;
					}
					catch
					{
					}
					int num2 = Mathf.Clamp(((AttackContext)(ref context)).Damage - num, 0, int.MaxValue);
					if (num2 > 0)
					{
						FastBufferWriter val2 = CoopMessages.NewWriter();
						try
						{
							FastBufferWriter writer = val2;
							byte b = 2;
							((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
							CoopMessages.WriteString(ref writer, val.Data.UniqueId.Id);
							((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num2, default(ForPrimitives));
							CoopMessages.SendToHost("GK2Coop.Combat", writer, (NetworkDelivery)3);
						}
						finally
						{
							((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
						}
						Sent++;
					}
					return false;
				}
			}
			return false;
		}

		private unsafe static void OnPlayerHit(int damage)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			HPComponent val = MainGame.PlayerData?.hpComponent;
			if (val == null || knockedOut || damage <= 0)
			{
				return;
			}
			if (val.Hp - damage > 0)
			{
				val.ApplyDamage(damage);
				return;
			}
			val.SetCustomHpValue(1, false);
			val.wasDamagedAtLeastOnce = true;
			try
			{
				(HpChangedField?.GetValue(val) as Action<HPComponent>)?.Invoke(val);
			}
			catch
			{
			}
			knockedOut = true;
			if (armed)
			{
				Disarm();
			}
			FastBufferWriter val2 = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val2;
				byte b = 4;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				CoopMessages.SendToHost("GK2Coop.Combat", writer, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
			CoopRunner.Toast("You're knocked out until the fight ends.", 8f);
			CoopLog.Info("Knocked out in the host's fight.");
		}

		public static void OnCombat(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: 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_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Invalid comparison between Unknown and I4
			//IL_00b5: 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_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (CoopSession.Role == CoopRole.Client && !CoopSession.ClientInWorld && b != 1)
			{
				return;
			}
			switch (b)
			{
			case 1:
				if (CoopSession.Role == CoopRole.Client)
				{
					byte b2 = default(byte);
					((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b2, default(ForPrimitives));
					fightLevel = CoopMessages.ReadString(ref reader);
					fightScene = CoopMessages.ReadString(ref reader);
					FightState val2 = fightHere;
					fightHere = (FightState)b2;
					CoopLog.Info($"Host fight state {fightHere} (level '{fightLevel}', area '{fightScene}').");
					if ((int)fightHere == 0 && (int)val2 != 0 && levelShown)
					{
						CoopRunner.Toast("The fight is over.");
					}
					else if ((int)fightHere == 1 && (int)val2 == 0)
					{
						CoopRunner.Toast((PlayerSync.Host?.Label ?? "The host") + " is getting ready for a fight.");
					}
					if (CoopSession.ClientInWorld)
					{
						UpdateStance();
					}
				}
				break;
			case 2:
				if (CoopSession.Role == CoopRole.Host)
				{
					string uid = CoopMessages.ReadString(ref reader);
					int damage2 = default(int);
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref damage2, default(ForPrimitives));
					if (!knockedOutPartners.Contains(sender))
					{
						HostApplyPartnerDamage(sender, uid, damage2);
					}
				}
				break;
			case 3:
				if (CoopSession.Role == CoopRole.Client)
				{
					int damage = default(int);
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref damage, default(ForPrimitives));
					OnPlayerHit(damage);
				}
				break;
			case 4:
				if (CoopSession.Role == CoopRole.Host)
				{
					knockedOutPartners.Add(sender);
					if (registered.TryGetValue(sender, out var value))
					{
						Unregister(sender, value);
					}
					CoopRunner.Toast((PlayerSync.Get(sender)?.Label ?? "A partner") + " is knocked out.");
					CoopLog.Info((PlayerSync.Get(sender)?.Label ?? sender.ToString()) + " is knocked out.");
				}
				break;
			case 6:
				if (CoopSession.Role == CoopRole.Client)
				{
					float progress = default(float);
					((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref progress, default(ForPrimitives));
					float total = default(float);
					((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref total, default(ForPrimitives));
					hostWavesProgress = progress;
					hostWavesTotal = total;
					if (timelineShown)
					{
						SetShownWaves(progress, total);
					}
				}
				break;
			case 5:
			{
				if (CoopSession.Role != CoopRole.Client)
				{
					break;
				}
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				int hp = default(int);
				int max = default(int);
				for (int i = 0; i < num; i++)
				{
					string text = CoopMessages.ReadString(ref reader);
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref hp, default(ForPrimitives));
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref max, default(ForPrimitives));
					WorldData worldData = MainGame.WorldData;
					WgoData val = ((worldData != null) ? worldData.GetWgoData(SGuid.Parse(text)) : null);
					if (val != null)
					{
						ApplyHostHp(val, hp, max);
					}
				}
				break;
			}
			}
		}

		public static string Describe()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (CoopSession.Role != CoopRole.Host)
			{
				return $"fight={fightHere} level='{fightLevel}' shown={levelShown} armed={armed} knockedOut={knockedOut} marked={markedFighters.Count} applied={Applied}";
			}
			return $"fight={hostState} level='{hostLevel}' targets={registered.Count} hpTracked={sentHp.Count} sent={Sent} applied={Applied}";
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class PartnerFightBars
	{
		private static void Postfix(PlayerView __instance, ref List<LazyWidgetDataBase> __result)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			try
			{
				if (!CombatSync.InHostFight || __result == null)
				{
					return;
				}
				PlayerController playerController = MainGame.PlayerController;
				if (!((Object)(object)__instance != (Object)(object)((playerController != null) ? playerController.View : null)))
				{
					HPComponent val = MainGame.PlayerData?.hpComponent;
					if (val != null && !__result.Any((LazyWidgetDataBase w) => w is HpBarPlayerWidgetData))
					{
						__result.Add((LazyWidgetDataBase)new HpBarPlayerWidgetData(val, -1f, -1f));
					}
					if (!__result.Any((LazyWidgetDataBase w) => w is StaminaBarPlayerWidgetData))
					{
						__result.Add((LazyWidgetDataBase)new StaminaBarPlayerWidgetData());
					}
				}
			}
			catch (Exception ex)
			{
				CoopLog.Debug("Showing our fight bars failed: " + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(FightingGameController), "SetFightState")]
	internal static class MirrorFightState
	{
		private static void Postfix(FightingGameController __instance, FightState newState)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CombatSync.OnHostFightState(__instance, newState);
			}
			catch (Exception e)
			{
				CoopLog.Error("Mirroring the fight state failed", e);
			}
		}
	}
	[HarmonyPatch(typeof(FightingGameController), "Stop")]
	internal static class PartnersLeaveFightTargets
	{
		private static void Prefix()
		{
			CombatSync.UnregisterPartners("fight stopping");
		}
	}
	[HarmonyPatch(typeof(HPComponent), "ApplyDamage")]
	internal static class RelayPartnerDamage
	{
		private static void Prefix(HPComponent __instance, out int __state)
		{
			__state = __instance.Hp;
		}

		private static void Postfix(HPComponent __instance, int __state)
		{
			CombatSync.OnHpDamaged(__instance, __state);
		}
	}
	[HarmonyPatch(typeof(AttackComponent), "HandleHit")]
	internal static class PartnerHitsGoToHost
	{
		private static bool Prefix(AttackComponent __instance, ICombatEntity target, AttackContext attackContext)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return CombatSync.OnLocalAttackHit(__instance, target, attackContext);
			}
			catch (Exception e)
			{
				CoopLog.Error("Forwarding our hit failed", e);
				return true;
			}
		}
	}
	internal static class ContainerSync
	{
		private enum Slot : byte
		{
			Inventory,
			CraftInventory
		}

		private const byte OpContents = 1;

		private const float PollInterval = 1f;

		private static readonly Dictionary<string, int> signatures = new Dictionary<string, int>();

		private static readonly Dictionary<ulong, string> sentSceneTo = new Dictionary<ulong, string>();

		private static float nextPoll;

		private static readonly Dictionary<Inventory, KeyValuePair<WgoData, Slot>> owners = new Dictionary<Inventory, KeyValuePair<WgoData, Slot>>();

		private static readonly HashSet<Inventory> announced = new HashSet<Inventory>();

		public static int Sent;

		public static int Applied;

		private const float ClientReach = 4f;

		public static void Reset()
		{
			signatures.Clear();
			sentSceneTo.Clear();
			owners.Clear();
			announced.Clear();
			nextPoll = 0f;
			Sent = 0;
			Applied = 0;
		}

		public static void OnInventoryEvent(Inventory inventory)
		{
			if (inventory != null && owners.ContainsKey(inventory))
			{
				announced.Add(inventory);
			}
		}

		private static void SendAnnounced()
		{
			//IL_0032: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if (announced.Count == 0)
			{
				return;
			}
			bool flag = CoopSession.Role == CoopRole.Client;
			Vector3 val;
			if (flag)
			{
				PlayerController playerController = MainGame.PlayerController;
				if ((Object)(object)((playerController != null) ? playerController.PhysicalBody : null) != (Object)null)
				{
					val = ((Component)MainGame.PlayerController.PhysicalBody).transform.position;
					goto IL_004d;
				}
			}
			val = Vector3.zero;
			goto IL_004d;
			IL_004d:
			Vector3 val2 = val;
			foreach (Inventory item in announced.ToList())
			{
				if (!owners.TryGetValue(item, out var value))
				{
					continue;
				}
				WgoData key = value.Key;
				if (((key != null) ? key.UniqueId : null) == (SGuid)null)
				{
					continue;
				}
				WgoData key2 = value.Key;
				if (flag)
				{
					if (ConveyorSync.IsBelt(key2))
					{
						continue;
					}
					Vector3 val3 = key2.Position - val2;
					if (((Vector3)(ref val3)).sqrMagnitude > 16f)
					{
						continue;
					}
				}
				List<Item> list = Items(key2, value.Value);
				if (list != null)
				{
					string key3 = Key(key2, value.Value);
					int num = Signature(list);
					int value2;
					bool num2 = signatures.TryGetValue(key3, out value2);
					signatures[key3] = num;
					if (num2 && value2 != num)
					{
						Send(key2, value.Value, list, null);
					}
				}
			}
			announced.Clear();
		}

		private static void Watch(WgoData data)
		{
			if (data.Inventory != null && !owners.ContainsKey(data.Inventory))
			{
				owners[data.Inventory] = new KeyValuePair<WgoData, Slot>(data, Slot.Inventory);
			}
			if (data.CraftInventory != null && !owners.ContainsKey(data.CraftInventory))
			{
				owners[data.CraftInventory] = new KeyValuePair<WgoData, Slot>(data, Slot.CraftInventory);
			}
		}

		public static void Tick()
		{
			bool flag = CoopSession.Role == CoopRole.Host && CoopSession.HasReadyClients && CoopSession.IsInGame;
			bool flag2 = CoopSession.Role == CoopRole.Client && CoopSession.ClientInWorld;
			if (!flag && !flag2)
			{
				announced.Clear();
				return;
			}
			SendAnnounced();
			if (Time.unscaledTime < nextPoll)
			{
				return;
			}
			if (owners.Count > 20000)
			{
				owners.Clear();
			}
			nextPoll = Time.unscaledTime + 1f;
			if (flag)
			{
				foreach (ulong item in CoopSession.ReadyClients.ToList())
				{
					RemotePlayer remotePlayer = PlayerSync.Get(item);
					if (remotePlayer != null && remotePlayer.HasState && !string.IsNullOrEmpty(remotePlayer.Scene) && (!sentSceneTo.TryGetValue(item, out var value) || value != remotePlayer.Scene))
					{
						sentSceneTo[item] = remotePlayer.Scene;
						int num = SendScene(remotePlayer.Scene, item);
						CoopLog.Debug($"Sent {num} containers in '{remotePlayer.Scene}' to {remotePlayer.Label}.");
					}
				}
				{
					foreach (string item2 in new HashSet<string>(from c in CoopSession.ReadyClients
						select PlayerSync.Get(c)?.Scene into s
						where !string.IsNullOrEmpty(s)
						select s))
					{
						SendChanged(item2, null);
					}
					return;
				}
			}
			PlayerController playerController = MainGame.PlayerController;
			string text = ((playerController == null) ? null : playerController.PlayerData?.currentGameSceneId);
			if (!string.IsNullOrEmpty(text))
			{
				SendChanged(text, null);
			}
		}

		private static IEnumerable<WgoData> Containers(string sceneId)
		{
			WorldData worldData = MainGame.WorldData;
			GameSceneData val = ((worldData != null) ? worldData.GetGameSceneDataById(sceneId) : null);
			if (val == null)
			{
				yield break;
			}
			foreach (WgoData item in val.wgoDataList.ToList())
			{
				if (((item != null) ? item.UniqueId : null) != (SGuid)null && ((ObjectLinkedToDefinition<WGODef>)(object)item).Definition != null && !((ObjectLinkedToDefinition<WGODef>)(object)item).Definition.hasRefToOtherWgoInventory)
				{
					yield return item;
				}
			}
		}

		private static List<Item> Items(WgoData data, Slot slot)
		{
			Inventory obj = ((slot == Slot.Inventory) ? data.Inventory : data.CraftInventory);
			if (obj == null)
			{
				return null;
			}
			Item data2 = obj.Data;
			if (data2 == null)
			{
				return null;
			}
			return data2.Inventory;
		}

		private static int Signature(List<Item> items, int depth = 0)
		{
			if (items == null)
			{
				return 0;
			}
			int num = 17 + items.Count;
			foreach (Item item in items)
			{
				if (item == null)
				{
					num *= 31;
					continue;
				}
				num = num * 31 + (((ObjectLinkedToDefinition<ItemDef>)(object)item).id?.GetHashCode() ?? 0);
				num = num * 31 + item.Count;
				if (depth < 2 && item.Inventory != null && item.Inventory.Count > 0)
				{
					num = num * 31 + Signature(item.Inventory, depth + 1);
				}
			}
			return num;
		}

		private static string Key(WgoData data, Slot slot)
		{
			return data.UniqueId.Id + ((slot == Slot.Inventory) ? "" : "#craft");
		}

		private static void SendChanged(string sceneId, ulong? onlyTo, bool ignoreReach = false)
		{
			//IL_0025: 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)
			//IL_003b: 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_0079: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			bool flag = CoopSession.Role == CoopRole.Client;
			Vector3 val;
			if (flag)
			{
				PlayerController playerController = MainGame.PlayerController;
				if ((Object)(object)((playerController != null) ? playerController.PhysicalBody : null) != (Object)null)
				{
					val = ((Component)MainGame.PlayerController.PhysicalBody).transform.position;
					goto IL_0040;
				}
			}
			val = Vector3.zero;
			goto IL_0040;
			IL_0040:
			Vector3 val2 = val;
			foreach (WgoData item in Containers(sceneId))
			{
				Watch(item);
				if (flag && ConveyorSync.IsBelt(item))
				{
					continue;
				}
				int num;
				if (!ignoreReach && flag)
				{
					Vector3 val3 = item.Position - val2;
					num = ((((Vector3)(ref val3)).sqrMagnitude <= 16f) ? 1 : 0);
				}
				else
				{
					num = 1;
				}
				bool flag2 = (byte)num != 0;
				Slot[] array = new Slot[2]
				{
					Slot.Inventory,
					Slot.CraftInventory
				};
				foreach (Slot slot in array)
				{
					List<Item> list = Items(item, slot);
					if (list != null)
					{
						string key = Key(item, slot);
						int num2 = Signature(list);
						int value;
						bool num3 = signatures.TryGetValue(key, out value);
						signatures[key] = num2;
						if (num3 && value != num2 && flag2)
						{
							Send(item, slot, list, onlyTo);
						}
					}
				}
			}
		}

		public static void SendChangedEverywhere()
		{
			if (CoopSession.Role == CoopRole.Client && CoopSession.ClientInWorld)
			{
				PlayerController playerController = MainGame.PlayerController;
				string text = ((playerController == null) ? null : playerController.PlayerData?.currentGameSceneId);
				if (!string.IsNullOrEmpty(text))
				{
					SendChanged(text, null, ignoreReach: true);
				}
			}
		}

		private static int SendScene(string sceneId, ulong clientId)
		{
			int num = 0;
			foreach (WgoData item in Containers(sceneId))
			{
				Watch(item);
				Slot[] array = new Slot[2]
				{
					Slot.Inventory,
					Slot.CraftInventory
				};
				foreach (Slot slot in array)
				{
					List<Item> list = Items(item, slot);
					if (list != null && list.Count != 0)
					{
						signatures[Key(item, slot)] = Signature(list);
						Send(item, slot, list, clientId);
						num++;
					}
				}
			}
			return num;
		}

		private unsafe static void Send(WgoData data, Slot slot, List<Item> items, ulong? onlyTo, ulong? except = null)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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)
			byte[] bytes;
			try
			{
				bytes = SerializationUtility.SerializeValue<List<Item>>(items, (DataFormat)0, (SerializationContext)null);
			}
			catch (Exception e)
			{
				CoopLog.Error("Serializing the contents of " + ((ObjectLinkedToDefinition<WGODef>)(object)data).id + " failed", e);
				return;
			}
			FastBufferWriter val = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val;
				byte b = 1;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				CoopMessages.WriteString(ref writer, data.UniqueId.Id);
				b = (byte)slot;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				CoopMessages.WriteBytes(ref writer, bytes);
				if (CoopSession.Role == CoopRole.Client)
				{
					CoopMessages.SendToHost("GK2Coop.Containers", writer, (NetworkDelivery)3);
				}
				else if (onlyTo.HasValue)
				{
					CoopMessages.SendTo("GK2Coop.Containers", onlyTo.Value, writer, (NetworkDelivery)3);
				}
				else
				{
					CoopMessages.SendToReadyClients("GK2Coop.Containers", writer, (NetworkDelivery)4, except);
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
			Sent++;
			CoopLog.Debug($"Sent contents of {((ObjectLinkedToDefinition<WGODef>)(object)data).id} ({slot}, {items.Count} stacks).");
		}

		public static void OnContainers(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (b != 1)
			{
				return;
			}
			string text = CoopMessages.ReadString(ref reader);
			byte b2 = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b2, default(ForPrimitives));
			byte[] array = CoopMessages.ReadBytes(ref reader);
			Slot slot = (Slot)b2;
			if (CoopSession.Role == CoopRole.Client && !CoopSession.ClientInWorld)
			{
				return;
			}
			WorldData worldData = MainGame.WorldData;
			WgoData val = ((worldData != null) ? worldData.GetWgoData(SGuid.Parse(text)) : null);
			Inventory val2 = ((val == null) ? null : ((slot == Slot.Inventory) ? val.Inventory : val.CraftInventory));
			if (((val2 != null) ? val2.Data : null) == null)
			{
				CoopLog.Debug($"Container {text} ({slot}) isn't in this world.");
				return;
			}
			try
			{
				List<Item> list = SerializationUtility.DeserializeValue<List<Item>>(array, (DataFormat)0, (DeserializationContext)null) ?? new List<Item>();
				Replace(val2, list, ((ObjectLinkedToDefinition<WGODef>)(object)val).id);
				signatures[Key(val, slot)] = Signature(Items(val, slot));
				Applied++;
				CoopLog.Debug(string.Format("Updated {0} ({1}) from {2}: {3} stacks.", ((ObjectLinkedToDefinition<WGODef>)(object)val).id, slot, (CoopSession.Role == CoopRole.Host) ? $"client {sender}" : "host", list.Count));
				if (CoopSession.Role == CoopRole.Host)
				{
					Send(val, slot, Items(val, slot), null, sender);
				}
			}
			catch (Exception e)
			{
				CoopLog.Error("Applying the contents of " + ((ObjectLinkedToDefinition<WGODef>)(object)val).id + " failed", e);
			}
		}

		public static List<Item> TakeChangedInventory(WgoData data)
		{
			List<Item> list = ((((data != null) ? data.UniqueId : null) != (SGuid)null) ? Items(data, Slot.Inventory) : null);
			if (list == null)
			{
				return null;
			}
			string key = Key(data, Slot.Inventory);
			int num = Signature(list);
			int value;
			bool num2 = signatures.TryGetValue(key, out value);
			signatures[key] = num;
			if (!num2 || value != num)
			{
				return list;
			}
			return null;
		}

		public static void ApplyInventory(WgoData data, List<Item> items)
		{
			Inventory val = ((data != null) ? data.Inventory : null);
			if (((val != null) ? val.Data : null) != null)
			{
				Replace(val, items, ((ObjectLinkedToDefinition<WGODef>)(object)data).id);
				signatures[Key(data, Slot.Inventory)] = Signature(Items(data, Slot.Inventory));
			}
		}

		private static void Replace(Inventory inventory, List<Item> items, string what)
		{
			List<Item> list = inventory.Data.RemoveAllItems() ?? new List<Item>();
			if (items != null && items.Count > 0)
			{
				inventory.Data.AddItemsToInventory(items);
			}
			bool num = CoopSession.Role == CoopRole.Client;
			bool applyingRemote = CraftSync.ApplyingRemote;
			if (num)
			{
				CraftSync.ApplyingRemote = true;
			}
			try
			{
				if (list.Count > 0)
				{
					inventory.NotifyItemsRemoved(list);
				}
				inventory.NotifyItemsAdded(items ?? new List<Item>());
			}
			catch (Exception ex)
			{
				CoopLog.Debug("Redrawing " + what + "'s contents failed: " + ex.Message);
			}
			finally
			{
				CraftSync.ApplyingRemote = applyingRemote;
			}
		}

		public static string Describe()
		{
			return $"tracked={signatures.Count} sent={Sent} applied={Applied}";
		}
	}
	internal static class ConveyorSync
	{
		private struct Moving
		{
			public bool Has;

			public int Direction;

			public string ItemId;

			public bool IsCommon;
		}

		private const byte OpStep = 1;

		private const byte OpDump = 2;

		private static readonly FieldInfo UpdatedEventField = AccessTools.Field(typeof(ConveyorSystem), "OnUpdated");

		public static bool ApplyingRemote;

		public static int StepsSent;

		public static int StepsApplied;

		public static int Dumps;

		public static void Reset()
		{
			ApplyingRemote = false;
			StepsSent = 0;
			StepsApplied = 0;
			Dumps = 0;
		}

		public static void Tick()
		{
		}

		public static void OnClientReady(ulong clientId)
		{
		}

		public static bool IsBelt(WgoData data)
		{
			WgoData obj = ((data is ConveyorWgoData) ? data : null);
			ConveyorComponent val = ((obj != null) ? ((ConveyorWgoData)obj).ConveyorComponent : null);
			if (!(val is ConveyorCellComponent) && !(val is ConveyorCellUndergroundComponent) && !(val is ConveyorCellStationComponent))
			{
				return val is ConveyorSplitterComponent;
			}
			return true;
		}

		private static Moving Read(ConveyorMovableItemData item)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected I4, but got Unknown
			if (item != null)
			{
				return new Moving
				{
					Has = true,
					Direction = (int)item.direction,
					ItemId = (item.itemId ?? ""),
					IsCommon = item.isCommon
				};
			}
			return default(Moving);
		}

		public unsafe static void OnHostStep()
		{
			//IL_01ac: 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_01e7: 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_00a5: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (CoopSession.Role != CoopRole.Host || !CoopSession.HasReadyClients || !CoopSession.IsInGame || !Plugin.HostRunsWorld.Value)
			{
				return;
			}
			List<ConveyorComponent> list = MainGame.Instance.GameSave?.conveyorSystemData?.conveyorComponents;
			if (list == null || list.Count == 0)
			{
				return;
			}
			HashSet<string> scenes = NpcSync.ScenesWithPartners();
			List<ConveyorComponent> list2 = list.Where(delegate(ConveyorComponent c)
			{
				object obj;
				if (c == null)
				{
					obj = null;
				}
				else
				{
					ConveyorWgoData wgoData2 = c.WgoData;
					obj = ((wgoData2 != null) ? ((WgoData)wgoData2).UniqueId : null);
				}
				return (SGuid)obj != (SGuid)null && scenes.Contains(((WgoData)c.WgoData).WorldId);
			}).ToList();
			if (list2.Count == 0)
			{
				return;
			}
			for (int num = 0; num < list2.Count; num += 60)
			{
				List<ConveyorComponent> list3 = list2.Skip(num).Take(60).ToList();
				FastBufferWriter val = CoopMessages.NewWriter();
				try
				{
					FastBufferWriter writer = val;
					byte b = 1;
					((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
					b = ((num + 60 >= list2.Count) ? ((byte)1) : ((byte)0));
					((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
					int count = list3.Count;
					((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives));
					foreach (ConveyorComponent item in list3)
					{
						ConveyorWgoData wgoData = item.WgoData;
						CoopMessages.WriteString(ref writer, ((WgoData)wgoData).UniqueId.Id);
						WriteMoving(ref writer, Read(item.InItem));
						WriteMoving(ref writer, Read(item.OutItem));
						byte[] array = null;
						List<Item> list4 = ContainerSync.TakeChangedInventory((WgoData)(object)wgoData);
						if (list4 != null)
						{
							try
							{
								array = SerializationUtility.SerializeValue<List<Item>>(list4, (DataFormat)0, (SerializationContext)null);
							}
							catch (Exception ex)
							{
								CoopLog.Warn("Couldn't send what " + ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id + " holds: " + ex.Message);
							}
						}
						b = ((array != null) ? ((byte)1) : ((byte)0));
						((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
						if (array != null)
						{
							CoopMessages.WriteBytes(ref writer, array);
						}
					}
					CoopMessages.SendToReadyClients("GK2Coop.Conveyors", writer, (NetworkDelivery)3);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			StepsSent++;
		}

		private static void WriteMoving(ref FastBufferWriter w, Moving moving)
		{
			//IL_0010: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			byte b = (moving.Has ? ((byte)1) : ((byte)0));
			((FastBufferWriter)(ref w)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
			if (moving.Has)
			{
				((FastBufferWriter)(ref w)).WriteValueSafe<int>(ref moving.Direction, default(ForPrimitives));
				CoopMessages.WriteString(ref w, moving.ItemId);
				b = (moving.IsCommon ? ((byte)1) : ((byte)0));
				((FastBufferWriter)(ref w)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
			}
		}

		private static ConveyorMovableItemData ReadMoving(ref FastBufferReader reader)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0021: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (b == 0)
			{
				return null;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			string text = CoopMessages.ReadString(ref reader);
			byte b2 = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b2, default(ForPrimitives));
			return new ConveyorMovableItemData(text, (Direction)num, b2 != 0);
		}

		private static void ApplyStep(ref FastBufferReader reader)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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)
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			byte b2 = default(byte);
			for (int i = 0; i < num; i++)
			{
				string text = CoopMessages.ReadString(ref reader);
				ConveyorMovableItemData inItem = ReadMoving(ref reader);
				ConveyorMovableItemData outItem = ReadMoving(ref reader);
				((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b2, default(ForPrimitives));
				byte[] array = ((b2 != 0) ? CoopMessages.ReadBytes(ref reader) : null);
				WorldData worldData = MainGame.WorldData;
				WgoData obj = ((worldData != null) ? worldData.GetWgoData(SGuid.Parse(text)) : null);
				ConveyorWgoData val = (ConveyorWgoData)(object)((obj is ConveyorWgoData) ? obj : null);
				ConveyorComponent val2 = ((val != null) ? val.ConveyorComponent : null);
				if (val2 == null)
				{
					continue;
				}
				val2.InItem = inItem;
				val2.OutItem = outItem;
				if (array != null)
				{
					try
					{
						ContainerSync.ApplyInventory((WgoData)(object)val, SerializationUtility.DeserializeValue<List<Item>>(array, (DataFormat)0, (DeserializationContext)null));
					}
					catch (Exception ex)
					{
						CoopLog.Warn("Couldn't apply what " + ((ObjectLinkedToDefinition<WGODef>)(object)val).id + " holds: " + ex.Message);
					}
				}
			}
			if (b == 0)
			{
				return;
			}
			ApplyingRemote = true;
			try
			{
				ConveyorSystem conveyorSystem = MainGame.Instance.conveyorSystem;
				(UpdatedEventField?.GetValue(conveyorSystem) as Action)?.Invoke();
				LazySingleton<ConveyorSystemAnimationOrchestrator>.Instance.SetState("Out");
				ConveyorSoundSystem instance = LazySingleton<ConveyorSoundSystem>.Instance;
				instance.PauseSounds();
				instance.PlaySounds();
				StepsApplied++;
			}
			catch (Exception e)
			{
				CoopLog.Error("Playing the conveyor step failed", e);
			}
			finally
			{
				ApplyingRemote = false;
			}
		}

		public static void OnLocalDump(Item item, RiverBodyReceiver receiver, Vector3 throwStartPos)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (ApplyingRemote || item == null || (Object)(object)receiver == (Object)null)
			{
				return;
			}
			Wgo wgo = receiver.Wgo;
			object obj;
			if (wgo == null)
			{
				obj = null;
			}
			else
			{
				WgoData data = wgo.Data;
				obj = ((data != null) ? data.UniqueId : null);
			}
			if (!((SGuid)obj == (SGuid)null))
			{
				bool num = CoopSession.Role == CoopRole.Host && CoopSession.HasReadyClients;
				bool flag = CoopSession.Role == CoopRole.Client && CoopSession.ClientInWorld;
				if (num || flag)
				{
					SendDump(item, receiver.Wgo.Data.UniqueId.Id, throwStartPos, null);
					CoopLog.Info("Dumped " + ((ObjectLinkedToDefinition<ItemDef>)(object)item).id + " in the river at " + ((ObjectLinkedToDefinition<WGODef>)(object)receiver.Wgo.Data).id + "; mirrored.");
				}
			}
		}

		private unsafe static void SendDump(Item item, string receiverUid, Vector3 throwStartPos, ulong? except)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_0051: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			byte[] bytes;
			try
			{
				bytes = SerializationUtility.SerializeValue<Item>(item, (DataFormat)0, (SerializationContext)null);
			}
			catch (Exception e)
			{
				CoopLog.Error("Serializing the dumped " + ((ObjectLinkedToDefinition<ItemDef>)(object)item).id + " failed", e);
				return;
			}
			FastBufferWriter val = CoopMessages.NewWriter();
			try
			{
				FastBufferWriter writer = val;
				byte b = 2;
				((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				CoopMessages.WriteString(ref writer, receiverUid);
				CoopMessages.WriteVector3(ref writer, throwStartPos);
				CoopMessages.WriteBytes(ref writer, bytes);
				if (CoopSession.Role == CoopRole.Host)
				{
					CoopMessages.SendToReadyClients("GK2Coop.Conveyors", writer, (NetworkDelivery)4, except);
				}
				else
				{
					CoopMessages.SendToHost("GK2Coop.Conveyors", writer, (NetworkDelivery)3);
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void ApplyDump(ulong sender, ref FastBufferReader reader)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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)
			string text = CoopMessages.ReadString(ref reader);
			Vector3 val = CoopMessages.ReadVector3(ref reader);
			Item val2 = SerializationUtility.DeserializeValue<Item>(CoopMessages.ReadBytes(ref reader), (DataFormat)0, (DeserializationContext)null);
			if (val2 == null)
			{
				return;
			}
			if (CoopSession.Role == CoopRole.Host)
			{
				MainGame.PlayerData.SubRes("cur_bodies_count", 1f);
				SendDump(val2, text, val, sender);
				CoopLog.Info((PlayerSync.Get(sender)?.Label ?? sender.ToString()) + " dumped " + ((ObjectLinkedToDefinition<ItemDef>)(object)val2).id + " in the river.");
			}
			Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(SGuid.Parse(text));
			RiverBodyReceiver val3 = (((Object)(object)wgoViewGlobal != (Object)null) ? wgoViewGlobal.RiverBodyReceiver : null);
			if ((Object)(object)val3 == (Object)null)
			{
				return;
			}
			ApplyingRemote = true;
			try
			{
				MainGame.Instance.riverDropSystem.BeginDump(val2, val3, val);
				Dumps++;
			}
			finally
			{
				ApplyingRemote = false;
			}
		}

		public static void OnConveyors(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (CoopSession.Role != CoopRole.Client || CoopSession.ClientInWorld)
			{
				if (b == 1 && CoopSession.Role == CoopRole.Client)
				{
					ApplyStep(ref reader);
				}
				else if (b == 2)
				{
					ApplyDump(sender, ref reader);
				}
			}
		}

		public static string Describe()
		{
			if (CoopSession.Role != CoopRole.Host)
			{
				return $"steps applied={StepsApplied} dumps={Dumps}";
			}
			return $"steps sent={StepsSent} dumps={Dumps}";
		}
	}
	[HarmonyPatch(typeof(ConveyorSystemAnimationOrchestrator), "SetState")]
	internal static class MirrorConveyorStep
	{
		private static void Postfix(string name)
		{
			if (name != "Out" || ConveyorSync.ApplyingRemote)
			{
				return;
			}
			try
			{
				ConveyorSync.OnHostStep();
			}
			catch (Exception e)
			{
				CoopLog.Error("Sending the conveyor step failed", e);
			}
		}
	}
	[HarmonyPatch(typeof(RiverDropSystem), "BeginDump")]
	internal static class MirrorRiverDump
	{
		private static void Postfix(bool __result, Item item, RiverBodyReceiver receiver, Vector3 throwStartPos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (!__result)
			{
				return;
			}
			try
			{
				ConveyorSync.OnLocalDump(item, receiver, throwStartPos);
			}
			catch (Exception e)
			{
				CoopLog.Error("Mirroring the river dump failed", e);
			}
		}
	}
	internal static class CoopLog
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static LogCallback <0>__OnUnityLog;
		}

		private const int KeepFiles = 12;

		private static StreamWriter writer;

		private static readonly Dictionary<string, int> sent = new Dictionary<string, int>();

		private static readonly Dictionary<string, int> received = new Dictionary<string, int>();

		private static readonly Dictionary<string, int> repeatedErrors = new Dictionary<string, int>();

		public static string FilePath { get; private set; }

		public static bool Verbose
		{
			get
			{
				if (Plugin.VerboseLogging != null)
				{
					return Plugin.VerboseLogging.Value;
				}
				return true;
			}
		}

		public static void Init()
		{
			//IL_0114: 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_011f: Expected O, but got Unknown
			try
			{
				string text = Path.Combine(Paths.BepInExRootPath, "GK2Coop-logs");
				Directory.CreateDirectory(text);
				foreach (FileInfo item in (from f in new DirectoryInfo(text).GetFiles("coop_*.log")
					orderby f.CreationTimeUtc descending
					select f).Skip(11))
				{
					try
					{
						item.Delete();
					}
					catch
					{
					}
				}
				FilePath = Path.Combine(text, $"coop_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_pid{Process.GetCurrentProcess().Id}.log");
				writer = new StreamWriter(new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false))
				{
					AutoFlush = true
				};
				writer.WriteLine(string.Format("GK2 Co-op {0} debug log. Game folder: {1}  pid {2}", "0.27.0", Path.GetDirectoryName(Application.dataPath), Process.GetCurrentProcess().Id));
				object obj2 = <>O.<0>__OnUnityLog;
				if (obj2 == null)
				{
					LogCallback val = OnUnityLog;
					<>O.<0>__OnUnityLog = val;
					obj2 = (object)val;
				}
				Application.logMessageReceived += (LogCallback)obj2;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't create the co-op debug log: " + ex.Message));
			}
		}

		public static void Info(string message)
		{
			Write("INFO ", message);
			Plugin.Log.LogInfo((object)message);
		}

		public static void Warn(string message)
		{
			Write("WARN ", message);
			Plugin.Log.LogWarning((object)message);
		}

		public static void Error(string message, Exception e = null)
		{
			Write("ERROR", (e == null) ? message : $"{message}: {e}");
			Plugin.Log.LogError((object)((e == null) ? message : $"{message}: {e}"));
		}

		public static void Debug(string message)
		{
			if (Verbose)
			{
				Write("DEBUG", message);
			}
		}

		public static void CountSent(string channel, int bytes)
		{
			Bump(sent, channel);
		}

		public static void CountReceived(string channel, int bytes)
		{
			Bump(received, channel);
		}

		public static string Counters()
		{
			return "sent[" + Format(sent) + "] recv[" + Format(received) + "]";
			static string Format(Dictionary<string, int> d)
			{
				if (d.Count != 0)
				{
					return string.Join(" ", from p in d
						orderby p.Key
						select $"{p.Key}={p.Value}");
				}
				return "-";
			}
		}

		public static void ResetCounters()
		{
			sent.Clear();
			received.Clear();
		}

		private static void Bump(Dictionary<string, int> counts, string key)
		{
			counts.TryGetValue(key, out var value);
			counts[key] = value + 1;
		}

		private static void OnUnityLog(string condition, string stackTrace, LogType type)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (CoopSession.Role != CoopRole.None && ((int)type == 0 || (int)type == 4 || (int)type == 1))
			{
				repeatedErrors.TryGetValue(condition, out var value);
				repeatedErrors[condition] = value + 1;
				if (value < 3)
				{
					Write("UNITY", $"{type}: {condition}\n{stackTrace}".TrimEnd());
				}
				else if (value == 3)
				{
					Write("UNITY", "(further repeats of this error are counted, not logged) " + condition);
				}
			}
		}

		private static void Write(string level, string message)
		{
			if (writer == null)
			{
				return;
			}
			try
			{
				string text = ((CoopSession.Role == CoopRole.None) ? "----" : CoopSession.Role.ToString().ToUpperInvariant());
				writer.WriteLine($"{DateTime.Now:HH:mm:ss.fff} f{Time.frameCount,-7} {text,-6} {level} {message}");
			}
			catch
			{
			}
		}
	}
	internal static class CoopMessages
	{
		public const string PlayerState = "GK2Coop.State";

		public const string PlayerInfo = "GK2Coop.Info";

		public const string Time = "GK2Coop.Time";

		public const string Story = "GK2Coop.Story";

		public const string World = "GK2Coop.World";

		public const string Request = "GK2Coop.Request";

		public const string Npc = "GK2Coop.Npc";

		public const string Drops = "GK2Coop.Drops";

		public const string Economy = "GK2Coop.Economy";

		public const string Knowledge = "GK2Coop.Knowledge";

		public const string Containers = "GK2Coop.Containers";

		public const string Sleep = "GK2Coop.Sleep";

		public const string WorldState = "GK2Coop.WorldState";

		public const string Vendors = "GK2Coop.Vendors";

		public const string Effects = "GK2Coop.Effects";

		public const string Crafts = "GK2Coop.Crafts";

		public const string Locks = "GK2Coop.Locks";

		public const string Combat = "GK2Coop.Combat";

		public const string Conveyors = "GK2Coop.Conveyors";

		public const string Progress = "GK2Coop.Progress";

		public const string Zombies = "GK2Coop.Zombies";

		public const string Director = "GK2Coop.Director";

		public const string Tutorial = "GK2Coop.Tutorial";

		public const string Travel = "GK2Coop.Travel";

		public const string Troops = "GK2Coop.Troops";

		public const string ItemScripts = "GK2Coop.ItemScripts";

		public const string Sermons = "GK2Coop.Sermons";

		private static readonly Dictionary<string, Action<ulong, FastBufferReader>> handlers = new Dictionary<string, Action<ulong, FastBufferReader>>
		{
			{
				"GK2Coop.State",
				PlayerSync.OnState
			},
			{
				"GK2Coop.Info",
				PlayerSync.OnInfo
			},
			{
				"GK2Coop.Time",
				TimeSync.OnTime
			},
			{
				"GK2Coop.Story",
				StorySync.OnStory
			},
			{
				"GK2Coop.World",
				WorldSync.OnWorld
			},
			{
				"GK2Coop.Request",
				StorySync.OnRequest
			},
			{
				"GK2Coop.Npc",
				NpcSync.OnNpc
			},
			{
				"GK2Coop.Drops",
				DropSync.OnDrops
			},
			{
				"GK2Coop.Economy",
				EconomySync.OnEconomy
			},
			{
				"GK2Coop.Knowledge",
				KnowledgeSync.OnKnowledge
			},
			{
				"GK2Coop.Containers",
				ContainerSync.OnContainers
			},
			{
				"GK2Coop.Sleep",
				SleepSync.OnSleep
			},
			{
				"GK2Coop.WorldState",
				WorldStateSync.OnWorldState
			},
			{
				"GK2Coop.Vendors",
				VendorSync.OnVendors
			},
			{
				"GK2Coop.Effects",
				EffectSync.OnEffects
			},
			{
				"GK2Coop.Crafts",
				CraftSync.OnCrafts
			},
			{
				"GK2Coop.Locks",
				ChestLocks.OnLocks
			},
			{
				"GK2Coop.Combat",
				CombatSync.OnCombat
			},
			{
				"GK2Coop.Conveyors",
				ConveyorSync.OnConveyors
			},
			{
				"GK2Coop.Progress",
				ProgressSync.OnProgress
			},
			{
				"GK2Coop.Zombies",
				InteractionProxy.OnZombies
			},
			{
				"GK2Coop.Troops",
				TroopSync.OnTroops
			},
			{
				"GK2Coop.ItemScripts",
				GK2Coop.ItemScripts.OnItemScripts
			},
			{
				"GK2Coop.Sermons",
				SermonSync.OnSermons
			},
			{
				"GK2Coop.Director",
				StandIn.OnDirector
			},
			{
				"GK2Coop.Tutorial",
				TutorialSync.OnTutorial
			},
			{
				"GK2Coop.Travel",
				SceneWait.OnTravel
			},
			{
				"GK2Coop.Profile",
				PartnerProfiles.OnMessage
			}
		};

		public static void Register()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			foreach (KeyValuePair<string, Action<ulong, FastBufferReader>> handler2 in handlers)
			{
				string name = handler2.Key;
				Action<ulong, FastBufferReader> handler = handler2.Value;
				customMessagingManager.RegisterNamedMessageHandler(name, (HandleNamedMessageDelegate)delegate(ulong sender, FastBufferReader reader)
				{
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					CoopLog.CountReceived(Short(name), ((FastBufferReader)(ref reader)).Length);
					try
					{
						handler(sender, reader);
					}
					catch (Exception e)
					{
						CoopLog.Error($"Handling {name} from {sender} failed", e);
					}
				});
			}
		}

		public static FastBufferWriter NewWriter()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)