Decompiled source of GTFOReplay v0.0.4

ReplayRecorder.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using AIGraph;
using API;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using ChainedPuzzles;
using Enemies;
using GameData;
using Gear;
using Globals;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using ReplayRecorder;
using ReplayRecorder.ChainedPuzzle;
using ReplayRecorder.Dimensions;
using ReplayRecorder.Enemies;
using ReplayRecorder.Enemies.Patches;
using ReplayRecorder.Map;
using ReplayRecorder.Map.Patches;
using ReplayRecorder.Mines;
using ReplayRecorder.Player;
using SNetwork;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Analytics;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ReplayRecorder")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+32e89ab0cced64a6c2434703c1ffa46f5f11fd20")]
[assembly: AssemblyProduct("ReplayRecorder")]
[assembly: AssemblyTitle("ReplayRecorder")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ReplayRecorder
{
	public static class Module
	{
		public const string GUID = "randomuserhi.ReplayRecorder";

		public const string Name = "ReplayRecorder";

		public const string Version = "0.0.1";
	}
	internal static class ConfigManager
	{
		private static ConfigEntry<bool> debug;

		private static ConfigEntry<string> replayFolder;

		private static ConfigEntry<string> replayFilename;

		private static ConfigEntry<int> pelletLingerTime;

		public static bool Debug
		{
			get
			{
				return debug.Value;
			}
			set
			{
				debug.Value = value;
			}
		}

		public static string ReplayFolder
		{
			get
			{
				return replayFolder.Value;
			}
			set
			{
				replayFolder.Value = value;
			}
		}

		public static string ReplayFileName
		{
			get
			{
				return replayFilename.Value;
			}
			set
			{
				replayFilename.Value = value;
			}
		}

		public static int PelletLingerTime
		{
			get
			{
				return pelletLingerTime.Value;
			}
			set
			{
				pelletLingerTime.Value = value;
			}
		}

		static ConfigManager()
		{
			//IL_0010: 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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "ReplayRecorder.cfg"), true);
			debug = val.Bind<bool>("Debug", "enable", false, "Enables debug messages when true.");
			replayFolder = val.Bind<string>("Settings", "replayFolder", "./", "Location of which replays will be stored. If invalid, defaults to the games location.");
			replayFilename = val.Bind<string>("Settings", "replayFilename", "{0} {1:yyyy-MM-dd HH-mm}", "Filename format of stored replays. Follows C# string format syntax with (0: Rundown + Level, 1: Date). If filename is invalid (contains invalid characters etc...) default name of 'replay' is used.");
			pelletLingerTime = val.Bind<int>("ReplayRecorder", "lingerTime", 500, "Time projectiles linger post removal.");
		}
	}
	[HarmonyPatch]
	internal class GameEventManager
	{
		[HarmonyPatch(typeof(RundownManager), "EndGameSession")]
		[HarmonyPrefix]
		private static void EndGameSession()
		{
			APILogger.Debug("Level ended!");
			SnapshotManager.Dispose();
			ReplayRecorder.Map.Map.Reset();
			Mine.Reset();
			Enemy.Reset();
			PlayerSentry.Reset();
			ReplayRecorder.ChainedPuzzle.ChainedPuzzle.Reset();
		}
	}
	internal struct GTFOSpecification
	{
		private static GTFOSpecification defaultSpec = new GTFOSpecification
		{
			items = new Dictionary<uint, byte> { 
			{
				uint.MaxValue,
				0
			} },
			enemies = new Dictionary<uint, byte>
			{
				{
					uint.MaxValue,
					0
				},
				{ 20u, 1 },
				{ 40u, 2 },
				{ 41u, 3 },
				{ 21u, 4 },
				{ 35u, 5 },
				{ 38u, 6 },
				{ 48u, 6 },
				{ 13u, 7 },
				{ 32u, 7 },
				{ 31u, 7 },
				{ 24u, 7 },
				{ 49u, 7 },
				{ 16u, 8 },
				{ 28u, 8 },
				{ 50u, 8 },
				{ 26u, 9 },
				{ 51u, 9 },
				{ 11u, 9 },
				{ 18u, 10 },
				{ 33u, 11 },
				{ 30u, 12 },
				{ 39u, 13 },
				{ 29u, 14 },
				{ 36u, 15 },
				{ 37u, 16 },
				{ 46u, 17 },
				{ 47u, 18 },
				{ 42u, 19 },
				{ 45u, 20 },
				{ 43u, 21 },
				{ 44u, 22 },
				{ 53u, 23 },
				{ 52u, 24 },
				{ 54u, 25 }
			}
		};

		private static GTFOSpecification spec = defaultSpec;

		public Dictionary<uint, byte> enemies { get; set; }

		public Dictionary<uint, byte> items { get; set; }

		public static GTFOSpecification LoadSpecification(string filepath)
		{
			spec = JsonSerializer.Deserialize<GTFOSpecification>(File.ReadAllText(filepath));
			return spec;
		}

		public static byte GetEnemyType(uint type)
		{
			if (spec.enemies.ContainsKey(type))
			{
				return spec.enemies[type];
			}
			APILogger.Error($"Unknown enemy type, {type}, found. Please create a custom specification and add it.");
			return 0;
		}

		public static byte GetItem(uint item)
		{
			if (spec.items.ContainsKey(item))
			{
				return spec.items[item];
			}
			APILogger.Error($"Unknown item type, {item}, found. Please create a custom specification and add it.");
			return 0;
		}
	}
	[HarmonyPatch]
	internal class Network
	{
		private static byte msgtype = 172;

		private static uint magickey = 10992881u;

		private static ushort repKey = 65531;

		public static void SendReplay(byte[] replay)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (!SNet.IsMaster)
			{
				return;
			}
			SNet_ChannelType val = (SNet_ChannelType)0;
			SNet_SendGroup val2 = default(SNet_SendGroup);
			SNet_SendQuality val3 = default(SNet_SendQuality);
			int num = default(int);
			SNet.GetSendSettings(ref val, ref val2, ref val3, ref num);
			List<SNet_Player> val4 = new List<SNet_Player>(PlayerManager.PlayerAgentsInLevel.Count);
			for (int i = 0; i < PlayerManager.PlayerAgentsInLevel.Count; i++)
			{
				if (!((Agent)PlayerManager.PlayerAgentsInLevel[i]).IsLocallyOwned && !PlayerManager.PlayerAgentsInLevel[i].Owner.IsBot)
				{
					val4.Add(PlayerManager.PlayerAgentsInLevel[i].Owner);
					APILogger.Debug("[Networking] Sending report to " + PlayerManager.PlayerAgentsInLevel[i].PlayerName);
				}
			}
			APILogger.Debug($"[Networking] Replay is {replay.Length} bytes large.");
			byte[] array = new byte[11];
			Array.Copy(BitConverter.GetBytes(repKey), 0, array, 0, 2);
			Array.Copy(BitConverter.GetBytes(magickey), 0, array, 2, 4);
			array[6] = msgtype;
			Array.Copy(BitConverter.GetBytes(replay.Length), 0, array, 7, 4);
			byte[] array2 = new byte[array.Length + replay.Length];
			Array.Copy(array, 0, array2, 0, array.Length);
			Array.Copy(replay, 0, array2, array.Length, replay.Length);
			SNet.Core.SendBytes(Il2CppStructArray<byte>.op_Implicit(array2), val3, num, val4);
		}

		[HarmonyPatch(typeof(SNet_Replication), "RecieveBytes")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static bool RecieveBytes_Prefix(Il2CppStructArray<byte> bytes, uint size, ulong messagerID)
		{
			if (size < 12)
			{
				return true;
			}
			ushort num = BitConverter.ToUInt16(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)bytes), 0);
			if (repKey == num)
			{
				if (BitConverter.ToUInt32(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)bytes), 2) != magickey)
				{
					APILogger.Debug("[Networking] Magic key is incorrect.");
					return true;
				}
				byte b = ((Il2CppArrayBase<byte>)(object)bytes)[6];
				if (b != msgtype)
				{
					if (msgtype == 173)
					{
						return true;
					}
					APILogger.Debug($"[Networking] msg type is incorrect. {b} {msgtype}");
					return true;
				}
				int num2 = BitConverter.ToInt32(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)bytes), 7);
				byte[] array = new byte[num2];
				Array.Copy(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)bytes), 11, array, 0, num2);
				if (SnapshotManager.active)
				{
					APILogger.Debug("Snapshot manager was still running, assuming end of run and closing...");
					SnapshotManager.Dispose();
				}
				APILogger.Debug($"[Networking] Report received: {num2} bytes");
				File.WriteAllBytes(SnapshotManager.fullpath, array);
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("randomuserhi.ReplayRecorder", "ReplayRecorder", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private static Harmony? harmony;

		public override void Load()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			APILogger.Log("Plugin is loaded!");
			harmony = new Harmony("randomuserhi.ReplayRecorder");
			harmony.PatchAll();
			if (((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("randomuserhi.BetterChat", out var _))
			{
				APILogger.Log("BetterChat is installed, adding commands.");
			}
			APILogger.Log("Debug is " + (ConfigManager.Debug ? "Enabled" : "Disabled"));
			ClassInjector.RegisterTypeInIl2Cpp<SnapshotManager>();
			SnapshotManager.Setup();
		}
	}
	internal static class Raudy
	{
		public static long Now => ((DateTimeOffset)DateTime.Now).ToUnixTimeMilliseconds();
	}
	internal static class BitHelper
	{
		public const int SizeOfHalf = 2;

		public const int SizeOfVector3 = 12;

		public const int SizeOfQuaternion = 13;

		public const int SizeOfHalfVector3 = 6;

		public const int SizeOfHalfQuaternion = 7;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static uint RotateLeft(uint value, int offset)
		{
			return (value << offset) | (value >> 32 - offset);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static uint RotateRight(uint value, int offset)
		{
			return (value >> offset) | (value << 32 - offset);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static long ReverseEndianness(long value)
		{
			return (long)ReverseEndianness((ulong)value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int ReverseEndianness(int value)
		{
			return (int)ReverseEndianness((uint)value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static short ReverseEndianness(short value)
		{
			return (short)ReverseEndianness((ushort)value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static ushort ReverseEndianness(ushort value)
		{
			return (ushort)((value >> 8) + (value << 8));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static uint ReverseEndianness(uint value)
		{
			return RotateRight(value & 0xFF00FFu, 8) + RotateLeft(value & 0xFF00FF00u, 8);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static ulong ReverseEndianness(ulong value)
		{
			return ((ulong)ReverseEndianness((uint)value) << 32) + ReverseEndianness((uint)(value >> 32));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private unsafe static void _WriteBytes(byte* source, int size, byte[] destination, ref int index)
		{
			int num = 0;
			while (num < size)
			{
				destination[index++] = source[num++];
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WriteBytes(byte value, byte[] destination, ref int index)
		{
			destination[index++] = value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(ulong value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(uint value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(ushort value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(long value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(int value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(short value, byte[] destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static void WriteBytes(float value, byte[] destination, ref int index)
		{
			int value2 = *(int*)(&value);
			if (!BitConverter.IsLittleEndian)
			{
				value2 = ReverseEndianness(value2);
			}
			_WriteBytes((byte*)(&value2), 4, destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WriteBytes(string value, byte[] destination, ref int index)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(value);
			WriteBytes((ushort)bytes.Length, destination, ref index);
			Array.Copy(bytes, 0, destination, index, bytes.Length);
			index += bytes.Length;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WriteBytes(byte[] buffer, byte[] destination, ref int index)
		{
			WriteBytes((ushort)buffer.Length, destination, ref index);
			Array.Copy(buffer, 0, destination, index, buffer.Length);
			index += buffer.Length;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WriteHalf(float value, byte[] destination, ref int index)
		{
			WriteBytes(FloatToHalf(value), destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private unsafe static uint AsUInt(float x)
		{
			return *(uint*)(&x);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private unsafe static float AsFloat(uint x)
		{
			return *(float*)(&x);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float HalfToFloat(ushort x)
		{
			int num = (x & 0x7C00) >> 10;
			int num2 = (x & 0x3FF) << 13;
			int num3 = (int)(AsUInt(num2) >> 23);
			return AsFloat((uint)(((x & 0x8000) << 16) | (Convert.ToInt32(num != 0) * ((num + 112 << 23) | num2)) | ((Convert.ToInt32(num == 0) & Convert.ToInt32(num2 != 0)) * ((num3 - 37 << 23) | ((num2 << 150 - num3) & 0x7FE000)))));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static ushort FloatToHalf(float x)
		{
			uint num = AsUInt(x) + 4096;
			uint num2 = (num & 0x7F800000) >> 23;
			uint num3 = num & 0x7FFFFFu;
			return (ushort)(((num & 0x80000000u) >> 16) | (Convert.ToInt32(num2 > 112) * (((num2 - 112 << 10) & 0x7C00) | (num3 >> 13))) | ((Convert.ToInt32(num2 < 113) & Convert.ToInt32(num2 > 101)) * ((8384512 + num3 >> (int)(125 - num2)) + 1 >> 1)) | (Convert.ToUInt32(num2 > 143) * 32767));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static byte ReadByte(byte[] source, ref int index)
		{
			return source[index++];
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static ulong ReadULong(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 8;
				ulong num2 = *(ulong*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static long ReadLong(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 8;
				long num2 = *(long*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static uint ReadUInt(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 4;
				uint num2 = *(uint*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static int ReadInt(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 4;
				int num2 = *(int*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static ushort ReadUShort(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 2;
				ushort num2 = *(ushort*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static short ReadShort(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* num = ptr + index;
				index += 2;
				short num2 = *(short*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ReadHalf(byte[] source, ref int index)
		{
			return HalfToFloat(ReadUShort(source, ref index));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static float ReadFloat(byte[] source, ref int index)
		{
			fixed (byte* ptr = source)
			{
				byte* ptr2 = ptr + index;
				index += 4;
				if (!BitConverter.IsLittleEndian)
				{
					int num = ReverseEndianness(*(int*)ptr2);
					return *(float*)(&num);
				}
				return *(float*)ptr2;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static string ReadString(byte[] source, ref int index)
		{
			int num = ReadUShort(source, ref index);
			string @string = Encoding.UTF8.GetString(source, index, num);
			index += num;
			return @string;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WriteBytes(Vector3 value, byte[] destination, ref int index)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			WriteBytes(value.x, destination, ref index);
			WriteBytes(value.y, destination, ref index);
			WriteBytes(value.z, destination, ref index);
		}

		public static void WriteBytes(Quaternion value, byte[] destination, ref int index)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			float num = value.x;
			byte b = 0;
			if (value.y > num)
			{
				num = value.y;
				b = 1;
			}
			if (value.z > num)
			{
				num = value.z;
				b = 2;
			}
			if (value.w > num)
			{
				num = value.w;
				b = 3;
			}
			WriteBytes(b, destination, ref index);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteBytes(value.y, destination, ref index);
					WriteBytes(value.z, destination, ref index);
					WriteBytes(value.w, destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.y, destination, ref index);
					WriteBytes(0f - value.z, destination, ref index);
					WriteBytes(0f - value.w, destination, ref index);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteBytes(value.x, destination, ref index);
					WriteBytes(value.z, destination, ref index);
					WriteBytes(value.w, destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, destination, ref index);
					WriteBytes(0f - value.z, destination, ref index);
					WriteBytes(0f - value.w, destination, ref index);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteBytes(value.x, destination, ref index);
					WriteBytes(value.y, destination, ref index);
					WriteBytes(value.w, destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, destination, ref index);
					WriteBytes(0f - value.y, destination, ref index);
					WriteBytes(0f - value.w, destination, ref index);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteBytes(value.x, destination, ref index);
					WriteBytes(value.y, destination, ref index);
					WriteBytes(value.z, destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, destination, ref index);
					WriteBytes(0f - value.y, destination, ref index);
					WriteBytes(0f - value.z, destination, ref index);
				}
				break;
			}
		}

		public static Vector3 ReadVector3(byte[] source, ref int index)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(ReadFloat(source, ref index), ReadFloat(source, ref index), ReadFloat(source, ref index));
		}

		public static Quaternion ReadQuaternion(byte[] source, ref int index)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			byte b = ReadByte(source, ref index);
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			switch (b)
			{
			case 0:
				num2 = ReadFloat(source, ref index);
				num3 = ReadFloat(source, ref index);
				num4 = ReadFloat(source, ref index);
				num = Mathf.Sqrt(1f - num2 * num2 - num3 * num3 - num4 * num4);
				break;
			case 1:
				num = ReadFloat(source, ref index);
				num3 = ReadFloat(source, ref index);
				num4 = ReadFloat(source, ref index);
				num2 = Mathf.Sqrt(1f - num * num - num3 * num3 - num4 * num4);
				break;
			case 2:
				num = ReadFloat(source, ref index);
				num2 = ReadFloat(source, ref index);
				num4 = ReadFloat(source, ref index);
				num3 = Mathf.Sqrt(1f - num * num - num2 * num2 - num4 * num4);
				break;
			case 3:
				num = ReadFloat(source, ref index);
				num2 = ReadFloat(source, ref index);
				num3 = ReadFloat(source, ref index);
				num4 = Mathf.Sqrt(1f - num * num - num2 * num2 - num3 * num3);
				break;
			}
			return new Quaternion(num, num2, num3, num4);
		}

		public static void WriteHalf(Vector3 value, byte[] destination, ref int index)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			WriteHalf(value.x, destination, ref index);
			WriteHalf(value.y, destination, ref index);
			WriteHalf(value.z, destination, ref index);
		}

		public static void WriteHalf(Quaternion value, byte[] destination, ref int index)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			float num = value.x;
			byte b = 0;
			if (value.y > num)
			{
				num = value.y;
				b = 1;
			}
			if (value.z > num)
			{
				num = value.z;
				b = 2;
			}
			if (value.w > num)
			{
				num = value.w;
				b = 3;
			}
			WriteBytes(b, destination, ref index);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteHalf(value.y, destination, ref index);
					WriteHalf(value.z, destination, ref index);
					WriteHalf(value.w, destination, ref index);
				}
				else
				{
					WriteHalf(0f - value.y, destination, ref index);
					WriteHalf(0f - value.z, destination, ref index);
					WriteHalf(0f - value.w, destination, ref index);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteHalf(value.x, destination, ref index);
					WriteHalf(value.z, destination, ref index);
					WriteHalf(value.w, destination, ref index);
				}
				else
				{
					WriteHalf(0f - value.x, destination, ref index);
					WriteHalf(0f - value.z, destination, ref index);
					WriteHalf(0f - value.w, destination, ref index);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteHalf(value.x, destination, ref index);
					WriteHalf(value.y, destination, ref index);
					WriteHalf(value.w, destination, ref index);
				}
				else
				{
					WriteHalf(0f - value.x, destination, ref index);
					WriteHalf(0f - value.y, destination, ref index);
					WriteHalf(0f - value.w, destination, ref index);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteHalf(value.x, destination, ref index);
					WriteHalf(value.y, destination, ref index);
					WriteHalf(value.z, destination, ref index);
				}
				else
				{
					WriteHalf(0f - value.x, destination, ref index);
					WriteHalf(0f - value.y, destination, ref index);
					WriteHalf(0f - value.z, destination, ref index);
				}
				break;
			}
		}

		public static Vector3 ReadHalfVector3(byte[] source, ref int index)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(ReadHalf(source, ref index), ReadHalf(source, ref index), ReadHalf(source, ref index));
		}

		public static Quaternion ReadHalfQuaternion(byte[] source, ref int index)
		{
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			byte b = ReadByte(source, ref index);
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			switch (b)
			{
			case 0:
				num2 = ReadHalf(source, ref index);
				num3 = ReadHalf(source, ref index);
				num4 = ReadHalf(source, ref index);
				num = Mathf.Sqrt(1f - num2 * num2 - num3 * num3 - num4 * num4);
				break;
			case 1:
				num = ReadHalf(source, ref index);
				num3 = ReadHalf(source, ref index);
				num4 = ReadHalf(source, ref index);
				num2 = Mathf.Sqrt(1f - num * num - num3 * num3 - num4 * num4);
				break;
			case 2:
				num = ReadHalf(source, ref index);
				num2 = ReadHalf(source, ref index);
				num4 = ReadHalf(source, ref index);
				num3 = Mathf.Sqrt(1f - num * num - num2 * num2 - num4 * num4);
				break;
			case 3:
				num = ReadHalf(source, ref index);
				num2 = ReadHalf(source, ref index);
				num3 = ReadHalf(source, ref index);
				num4 = Mathf.Sqrt(1f - num * num - num2 * num2 - num3 * num3);
				break;
			}
			return new Quaternion(num, num2, num3, num4);
		}
	}
	internal interface ISerializable
	{
		void Serialize(FileStream fs);
	}
	internal struct rInstance : ISerializable
	{
		private int instance;

		public const int SizeOf = 4;

		private static byte[] buffer = new byte[4];

		public rInstance(int instance)
		{
			this.instance = instance;
		}

		public void Serialize(FileStream fs)
		{
			int index = 0;
			BitHelper.WriteBytes(instance, buffer, ref index);
			fs.Write(buffer);
		}
	}
	internal class GameplayEvent
	{
		public enum Type
		{
			AddPlayer,
			RemovePlayer,
			SpawnEnemy,
			DespawnEnemy,
			EnemyDead,
			EnemyBehaviourChangeState,
			EnemyLocomotionChangeState,
			EnemyBulletDamage,
			EnemyMeleeDamage,
			EnemyMineDamage,
			PlayerDead,
			PlayerRevive,
			PlayerTongueDamage,
			PlayerMeleeDamage,
			PlayerPelletDamage,
			PlayerBulletDamage,
			PlayerMineDamage,
			PlayerFallDamage,
			PlayerPelletDodge,
			PlayerTongueDodge,
			PlayerWield,
			DoorChangeState,
			DoorDamage,
			SpawnMine,
			DespawnMine,
			ExplodeMine,
			MineTripLine,
			SpawnSentry,
			DespawnSentry,
			SpawnPellet,
			DespawnPellet,
			SpawnTongue,
			DespawnTongue,
			SetTongue,
			SpawnGlue,
			DespawnGlue,
			EnemyAlerted,
			EnemyScreamed,
			EnemyTargetSet,
			BulletShot,
			SpawnScanCircle,
			DespawnScanCircle,
			SpawnHolopath,
			DespawnHolopath,
			Checkpoint,
			SpawnTendril,
			DespawnTendril
		}

		public long timestamp;

		public Type type;

		public ISerializable? detail;

		public GameplayEvent(long timestamp, Type type, ISerializable? detail)
		{
			this.timestamp = timestamp;
			this.type = type;
			this.detail = detail;
		}
	}
	internal abstract class DynamicProperty : ISerializable
	{
		public enum Type
		{
			Tongue,
			Scan,
			Holopath
		}

		public int instance;

		public Type type;

		public bool remove;

		private static byte[] buffer = new byte[4];

		public bool Serializable
		{
			get
			{
				if (!remove)
				{
					return IsSerializable();
				}
				return false;
			}
		}

		protected virtual bool IsSerializable()
		{
			return true;
		}

		public DynamicProperty(Type type, int instance)
		{
			this.type = type;
			this.instance = instance;
		}

		public virtual void Serialize(FileStream fs)
		{
			fs.WriteByte((byte)type);
			int index = 0;
			BitHelper.WriteBytes(instance, buffer, ref index);
			fs.Write(buffer);
		}
	}
	internal class SnapshotManager : MonoBehaviour
	{
		public struct rAgent : ITransform
		{
			private Agent agent;

			public bool active => (Object)(object)agent != (Object)null;

			public byte dimensionIndex => (byte)agent.m_dimensionIndex;

			public Vector3 position => ((Component)agent).transform.position;

			public Quaternion rotation => ((Component)agent).transform.rotation;

			public float scale => 0f;

			public rAgent(Agent agent)
			{
				this.agent = agent;
			}
		}

		public interface ITransform
		{
			bool active { get; }

			byte dimensionIndex { get; }

			Vector3 position { get; }

			Quaternion rotation { get; }

			float scale { get; }
		}

		public class DynamicObject
		{
			public bool remove;

			public ITransform transform;

			public readonly int instance;

			public Vector3 oldPosition = Vector3.zero;

			public Quaternion oldRotation = Quaternion.identity;

			public float oldScale;

			public const float threshold = 50f;

			public const int SizeOf = 27;

			public const int SizeOfHalf = 21;

			private static byte[] buffer = new byte[27];

			public bool Serializable
			{
				get
				{
					//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_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)
					if (!remove && transform.active)
					{
						if (!(transform.position != oldPosition) && !(transform.rotation != oldRotation))
						{
							return transform.scale != oldScale;
						}
						return true;
					}
					return false;
				}
			}

			public DynamicObject(int instance, ITransform transform)
			{
				//IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				this.instance = instance;
				this.transform = transform;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0008: 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_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Unknown result type (might be due to invalid IL or missing references)
				//IL_015c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Unknown result type (might be due to invalid IL or missing references)
				//IL_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_018f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_0245: Unknown result type (might be due to invalid IL or missing references)
				//IL_024a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0256: Unknown result type (might be due to invalid IL or missing references)
				//IL_025b: Unknown result type (might be due to invalid IL or missing references)
				//IL_01bd: 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_01f1: 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)
				int index = 0;
				Vector3 val = transform.position - oldPosition;
				if (((Vector3)(ref val)).sqrMagnitude > 2500f)
				{
					BitHelper.WriteBytes((byte)1, buffer, ref index);
					BitHelper.WriteBytes(instance, buffer, ref index);
					BitHelper.WriteBytes(transform.position, buffer, ref index);
					if (float.IsNaN(transform.rotation.x) || float.IsNaN(transform.rotation.y) || float.IsNaN(transform.rotation.z) || float.IsNaN(transform.rotation.w))
					{
						BitHelper.WriteHalf(Quaternion.identity, buffer, ref index);
						APILogger.Debug("Dynamic rotation had NaN component.");
					}
					else
					{
						BitHelper.WriteHalf(transform.rotation, buffer, ref index);
					}
					BitHelper.WriteHalf(transform.scale, buffer, ref index);
					BitHelper.WriteBytes(transform.dimensionIndex, buffer, ref index);
					fs.Write(buffer, 0, 27);
				}
				else
				{
					BitHelper.WriteBytes((byte)0, buffer, ref index);
					BitHelper.WriteBytes(instance, buffer, ref index);
					BitHelper.WriteHalf(transform.position - oldPosition, buffer, ref index);
					if (float.IsNaN(transform.rotation.x) || float.IsNaN(transform.rotation.y) || float.IsNaN(transform.rotation.z) || float.IsNaN(transform.rotation.w))
					{
						BitHelper.WriteHalf(Quaternion.identity, buffer, ref index);
						APILogger.Debug("Dynamic rotation had NaN component.");
					}
					else
					{
						BitHelper.WriteHalf(transform.rotation, buffer, ref index);
					}
					BitHelper.WriteHalf(transform.scale, buffer, ref index);
					BitHelper.WriteBytes(transform.dimensionIndex, buffer, ref index);
					fs.Write(buffer, 0, 21);
				}
				oldPosition = transform.position;
				oldRotation = transform.rotation;
				oldScale = transform.scale;
			}
		}

		private static GameObject? obj = null;

		public static SnapshotManager? instance = null;

		public static FileStream? fs = null;

		public static bool active = false;

		private float tickRate = 0.2f;

		private float timer;

		private long start;

		private List<GameplayEvent> events = new List<GameplayEvent>(100);

		private List<DynamicObject> _dynamic = new List<DynamicObject>(100);

		private List<DynamicObject> dynamic = new List<DynamicObject>(100);

		public Dictionary<int, DynamicObject> mapOfDynamics = new Dictionary<int, DynamicObject>();

		private List<DynamicProperty> _dynamicProp = new List<DynamicProperty>(100);

		private List<DynamicProperty> dynamicProp = new List<DynamicProperty>(100);

		public Dictionary<int, DynamicProperty> mapOfDynamicProps = new Dictionary<int, DynamicProperty>();

		public static Action? OnTick;

		private static byte[] buffer = new byte[4];

		public static string fullpath = "./replay.gtfo";

		public long Now => Raudy.Now - start;

		private void Update()
		{
			//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_000e: 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_0012: Invalid comparison between Unknown and I4
			if (active)
			{
				DRAMA_State currentStateEnum = DramaManager.CurrentStateEnum;
				float num = ((currentStateEnum - 5 > 3) ? 0.2f : 0.05f);
				if (tickRate != num)
				{
					timer = 0f;
					tickRate = num;
				}
				timer += Time.deltaTime;
				if (timer > tickRate)
				{
					timer = 0f;
					Tick();
				}
			}
		}

		public static void AddEvent(GameplayEvent.Type type, ISerializable? e)
		{
			if ((Object)(object)instance == (Object)null)
			{
				APILogger.Error("Tried to add an event before snapshotmanager was ready.");
			}
			else
			{
				instance.events.Add(new GameplayEvent(instance.Now, type, e));
			}
		}

		public static void AddDynamicObject(DynamicObject obj)
		{
			if ((Object)(object)instance == (Object)null)
			{
				APILogger.Error("Tried to add a dynamic object before snapshotmanager was ready.");
				return;
			}
			instance.dynamic.Add(obj);
			instance.mapOfDynamics.Add(obj.instance, obj);
		}

		public static void RemoveDynamicObject(int instanceID)
		{
			if ((Object)(object)instance == (Object)null)
			{
				APILogger.Error("Tried to remove a dynamic object before snapshotmanager was ready.");
			}
			else if (instance.mapOfDynamics.ContainsKey(instanceID))
			{
				instance.mapOfDynamics[instanceID].remove = true;
				instance.mapOfDynamics.Remove(instanceID);
			}
		}

		public static void RemoveDynamicObject(DynamicObject obj)
		{
			RemoveDynamicObject(obj.instance);
		}

		public static void AddDynamicProperty(DynamicProperty obj)
		{
			if ((Object)(object)instance == (Object)null)
			{
				APILogger.Error("Tried to add a dynamic property before snapshotmanager was ready.");
				return;
			}
			instance.dynamicProp.Add(obj);
			instance.mapOfDynamicProps.Add(obj.instance, obj);
		}

		public static void RemoveDynamicProperty(int instanceID)
		{
			if ((Object)(object)instance == (Object)null)
			{
				APILogger.Error("Tried to remove a dynamic property before snapshotmanager was ready.");
			}
			else if (instance.mapOfDynamicProps.ContainsKey(instanceID))
			{
				instance.mapOfDynamicProps[instanceID].remove = true;
				instance.mapOfDynamicProps.Remove(instanceID);
			}
		}

		public static void RemoveDynamicProperty(DynamicProperty obj)
		{
			RemoveDynamicProperty(obj.instance);
		}

		private void Tick()
		{
			if (!active || fs == null)
			{
				return;
			}
			OnTick?.Invoke();
			int num = (ushort)dynamic.Where((DynamicObject d) => d.Serializable).Count();
			int num2 = (ushort)dynamicProp.Where((DynamicProperty d) => d.Serializable).Count();
			if (num2 == 0 && num == 0 && events.Count == 0)
			{
				return;
			}
			int index = 0;
			long now = Now;
			BitHelper.WriteBytes((uint)now, buffer, ref index);
			fs.Write(buffer, 0, 4);
			index = 0;
			BitHelper.WriteBytes((ushort)events.Count, buffer, ref index);
			fs.Write(buffer, 0, 2);
			for (int i = 0; i < events.Count; i++)
			{
				GameplayEvent gameplayEvent = events[i];
				index = 0;
				BitHelper.WriteBytes((byte)gameplayEvent.type, buffer, ref index);
				BitHelper.WriteBytes((ushort)(now - gameplayEvent.timestamp), buffer, ref index);
				fs.Write(buffer, 0, 3);
				if (gameplayEvent.detail != null)
				{
					gameplayEvent.detail.Serialize(fs);
				}
			}
			index = 0;
			int num3 = 0;
			BitHelper.WriteBytes(num, buffer, ref index);
			fs.Write(buffer, 0, 2);
			_dynamic.Clear();
			for (int j = 0; j < dynamic.Count; j++)
			{
				DynamicObject dynamicObject = dynamic[j];
				if (dynamicObject.Serializable)
				{
					num3++;
					dynamicObject.Serialize(fs);
				}
				if (!dynamicObject.remove)
				{
					_dynamic.Add(dynamicObject);
				}
			}
			if (num3 != num)
			{
				APILogger.Error($"Number of serialized and nSerializable don't match: {num3} {num}");
			}
			List<DynamicObject> list = dynamic;
			dynamic = _dynamic;
			_dynamic = list;
			index = 0;
			num3 = 0;
			BitHelper.WriteBytes(num2, buffer, ref index);
			fs.Write(buffer, 0, 2);
			_dynamicProp.Clear();
			for (int k = 0; k < dynamicProp.Count; k++)
			{
				DynamicProperty dynamicProperty = dynamicProp[k];
				if (dynamicProperty.Serializable)
				{
					num3++;
					dynamicProperty.Serialize(fs);
				}
				if (!dynamicProperty.remove)
				{
					_dynamicProp.Add(dynamicProperty);
				}
			}
			if (num3 != num2)
			{
				APILogger.Error($"Number of serialized and nSerializableProps don't match: {num3} {num2}");
			}
			List<DynamicProperty> list2 = dynamicProp;
			dynamicProp = _dynamicProp;
			_dynamicProp = list2;
			fs.Flush();
			events.Clear();
		}

		public static void Setup()
		{
			OnTick = (Action)Delegate.Combine(OnTick, new Action(ReplayRecorder.Player.Player.OnTick));
		}

		public static void Init()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance != (Object)null)
			{
				APILogger.Error("Instance has already started, this should not happen");
				return;
			}
			active = true;
			obj = new GameObject();
			instance = obj.AddComponent<SnapshotManager>();
			instance.start = Raudy.Now;
			pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
			string shortName = GameDataBlockBase<RundownDataBlock>.GetBlock(Global.RundownIdToLoad).GetExpeditionData(activeExpeditionData.tier, activeExpeditionData.expeditionIndex).GetShortName(activeExpeditionData.expeditionIndex);
			DateTime now = DateTime.Now;
			string text = string.Format(ConfigManager.ReplayFileName, shortName, now);
			string text2 = ConfigManager.ReplayFolder;
			if (text.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
			{
				text = "replay";
			}
			if (!Directory.Exists(text2))
			{
				text2 = "./";
			}
			fullpath = Path.Combine(text2, text);
			fs = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.Read);
			ReplayRecorder.Player.Player.Init();
		}

		public static void Dispose()
		{
			active = false;
			if (fs == null)
			{
				APILogger.Warn("Filestream was never started, this should not happen.");
			}
			else
			{
				fs.Dispose();
				fs = null;
			}
			Network.SendReplay(File.ReadAllBytes(fullpath));
			if ((Object)(object)obj == (Object)null)
			{
				APILogger.Debug("Snapshot manager has already been destroyed!");
				return;
			}
			APILogger.Debug("Disposing snapshot manager...");
			instance = null;
			Object.Destroy((Object)(object)obj);
			obj = null;
		}
	}
}
namespace ReplayRecorder.Player
{
	internal struct rPlayer : ISerializable
	{
		private byte slot;

		public rPlayer(PlayerAgent agent)
		{
			slot = (byte)agent.PlayerSlotIndex;
		}

		public void Serialize(FileStream fs)
		{
			fs.WriteByte(slot);
		}
	}
	internal class rPlayerAgent
	{
		public PlayerAgent agent;

		public ItemEquippable? lastEquipped;

		public SNet_Player owner;

		public int instanceID;

		public rPlayerAgent(PlayerAgent agent)
		{
			this.agent = agent;
			owner = agent.Owner;
			instanceID = ((Object)agent).GetInstanceID();
			lastEquipped = null;
		}
	}
	internal static class Player
	{
		public struct PlayerJoin : ISerializable
		{
			private rPlayerAgent player;

			private byte slot;

			private const int SizeOf = 15;

			private byte[] buffer;

			public PlayerJoin(rPlayerAgent player)
			{
				buffer = new byte[15];
				this.player = player;
				slot = (byte)player.agent.PlayerSlotIndex;
			}

			public void Serialize(FileStream fs)
			{
				byte[] bytes = Encoding.UTF8.GetBytes(player.owner.NickName);
				int num = 15 + bytes.Length;
				if (buffer.Length < num)
				{
					buffer = new byte[num];
				}
				int index = 0;
				BitHelper.WriteBytes(player.owner.Lookup, buffer, ref index);
				BitHelper.WriteBytes(player.instanceID, buffer, ref index);
				BitHelper.WriteBytes(slot, buffer, ref index);
				BitHelper.WriteBytes(bytes, buffer, ref index);
				fs.Write(buffer, 0, num);
			}
		}

		public struct PlayerLeave : ISerializable
		{
			private rPlayerAgent player;

			public const int SizeOf = 12;

			private byte[] buffer;

			public PlayerLeave(rPlayerAgent player)
			{
				buffer = new byte[12];
				this.player = player;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(player.owner.Lookup, buffer, ref index);
				BitHelper.WriteBytes(player.instanceID, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public struct rPlayerRevive : ISerializable
		{
			private byte player;

			private byte source;

			public rPlayerRevive(PlayerAgent player, PlayerAgent source)
			{
				this.player = (byte)player.PlayerSlotIndex;
				this.source = (byte)source.PlayerSlotIndex;
			}

			public void Serialize(FileStream fs)
			{
				fs.WriteByte(player);
				fs.WriteByte(source);
			}
		}

		public struct rPlayerWield : ISerializable
		{
			private byte slot;

			private byte item;

			private const int SizeOf = 2;

			private byte[] buffer;

			public rPlayerWield(PlayerAgent player, byte item)
			{
				buffer = new byte[2];
				slot = (byte)player.PlayerSlotIndex;
				this.item = item;
			}

			public void Serialize(FileStream fs)
			{
				fs.WriteByte(slot);
				fs.WriteByte(item);
			}
		}

		private static List<PlayerAgent> buffer = new List<PlayerAgent>();

		private static List<rPlayerAgent> _players = new List<rPlayerAgent>();

		private static List<rPlayerAgent> playerList = new List<rPlayerAgent>();

		public static Dictionary<int, rPlayerAgent> players = new Dictionary<int, rPlayerAgent>();

		public static void OnPlayerDead(PlayerAgent player)
		{
			APILogger.Debug(player.Owner.NickName + " has died.");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerDead, new rPlayer(player));
		}

		public static void OnPlayerRevive(PlayerAgent player, PlayerAgent source)
		{
			APILogger.Debug(player.Owner.NickName + " was revived by " + source.Owner.NickName + ".");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerRevive, new rPlayerRevive(player, source));
		}

		public static void CheckPlayerWield()
		{
			foreach (rPlayerAgent player in playerList)
			{
				ItemEquippable wieldedItem = player.agent.Inventory.WieldedItem;
				if ((Object)(object)wieldedItem != (Object)(object)player.lastEquipped)
				{
					player.lastEquipped = wieldedItem;
					if ((Object)(object)player.lastEquipped != (Object)null)
					{
						OnPlayerWield(player.agent, player.lastEquipped);
					}
				}
			}
		}

		public static void OnPlayerWield(PlayerAgent player, ItemEquippable item)
		{
			APILogger.Debug($"{player.Owner.NickName} is wielding {((Item)item).PublicName} [{item.ArchetypeID}]");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerWield, new rPlayerWield(player, GTFOSpecification.GetItem(item.ArchetypeID)));
		}

		public static void Init()
		{
			APILogger.Debug("Initializing...");
			playerList.Clear();
			players.Clear();
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerAgent current = enumerator.Current;
				rPlayerAgent rPlayerAgent2 = new rPlayerAgent(current);
				playerList.Add(rPlayerAgent2);
				players.Add(rPlayerAgent2.instanceID, rPlayerAgent2);
				APILogger.Debug(current.Owner.NickName + " has joined.");
				SnapshotManager.AddEvent(GameplayEvent.Type.AddPlayer, new PlayerJoin(rPlayerAgent2));
				SnapshotManager.AddDynamicObject(new SnapshotManager.DynamicObject(rPlayerAgent2.instanceID, new SnapshotManager.rAgent((Agent)(object)current)));
			}
		}

		public static void SpawnPlayer(PlayerAgent agent)
		{
			PlayerAgent agent2 = agent;
			rPlayerAgent rPlayerAgent2 = playerList.Find((rPlayerAgent p) => p.owner.Lookup == agent2.Owner.Lookup);
			if (rPlayerAgent2 != null)
			{
				APILogger.Debug("(SpawnPlayer) " + agent2.Owner.NickName + " was replaced by spawned agent.");
				SnapshotManager.AddEvent(GameplayEvent.Type.RemovePlayer, new PlayerLeave(rPlayerAgent2));
				SnapshotManager.RemoveDynamicObject(rPlayerAgent2.instanceID);
				playerList.Remove(rPlayerAgent2);
				players.Remove(rPlayerAgent2.instanceID);
			}
			else
			{
				APILogger.Debug("(SpawnPlayer) " + agent2.Owner.NickName + " has joined.");
			}
			rPlayerAgent rPlayerAgent3 = new rPlayerAgent(agent2);
			SnapshotManager.AddEvent(GameplayEvent.Type.AddPlayer, new PlayerJoin(rPlayerAgent3));
			SnapshotManager.AddDynamicObject(new SnapshotManager.DynamicObject(rPlayerAgent3.instanceID, new SnapshotManager.rAgent((Agent)(object)agent2)));
			playerList.Add(rPlayerAgent3);
			players.Add(rPlayerAgent3.instanceID, rPlayerAgent3);
		}

		public static void DespawnPlayer(PlayerAgent agent)
		{
			PlayerAgent agent2 = agent;
			rPlayerAgent rPlayerAgent2 = playerList.Find((rPlayerAgent p) => p.owner.Lookup == agent2.Owner.Lookup);
			if (rPlayerAgent2 != null)
			{
				APILogger.Debug(agent2.Owner.NickName + " has left.");
				SnapshotManager.AddEvent(GameplayEvent.Type.RemovePlayer, new PlayerLeave(rPlayerAgent2));
				SnapshotManager.RemoveDynamicObject(rPlayerAgent2.instanceID);
				players.Remove(rPlayerAgent2.instanceID);
				playerList.Remove(rPlayerAgent2);
			}
		}

		private static void CheckPlayersJoined()
		{
			buffer.Clear();
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerAgent current = enumerator.Current;
				buffer.Add(current);
			}
			foreach (rPlayerAgent player in playerList)
			{
				SNet_Player owner = player.owner;
				if (!buffer.Any((PlayerAgent p) => p.Owner.Lookup == owner.Lookup))
				{
					APILogger.Debug("(Tick) " + owner.NickName + " has left.");
					SnapshotManager.AddEvent(GameplayEvent.Type.RemovePlayer, new PlayerLeave(player));
					SnapshotManager.RemoveDynamicObject(player.instanceID);
					players.Remove(player.instanceID);
				}
			}
			_players.Clear();
			foreach (PlayerAgent item in buffer)
			{
				SNet_Player owner2 = item.Owner;
				rPlayerAgent rPlayerAgent2 = playerList.Find((rPlayerAgent p) => p.owner.Lookup == owner2.Lookup);
				if (rPlayerAgent2 == null)
				{
					APILogger.Debug("(Tick) " + owner2.NickName + " has joined.");
					rPlayerAgent2 = new rPlayerAgent(item);
					SnapshotManager.AddEvent(GameplayEvent.Type.AddPlayer, new PlayerJoin(rPlayerAgent2));
					SnapshotManager.AddDynamicObject(new SnapshotManager.DynamicObject(rPlayerAgent2.instanceID, new SnapshotManager.rAgent((Agent)(object)item)));
					players.Add(rPlayerAgent2.instanceID, rPlayerAgent2);
				}
				_players.Add(rPlayerAgent2);
			}
			List<rPlayerAgent> list = _players;
			_players = playerList;
			playerList = list;
		}

		public static void OnTick()
		{
			CheckPlayersJoined();
			CheckPlayerWield();
		}
	}
	internal class PlayerDamage
	{
		public struct rPlayerDamage : ISerializable
		{
			private byte player;

			private int? source;

			private float damage;

			public const int SizeOf = 7;

			public const int SizeOfNoSource = 3;

			private byte[] buffer;

			public rPlayerDamage(PlayerAgent player, float damage, int source)
			{
				this.source = null;
				buffer = new byte[7];
				this.player = (byte)player.PlayerSlotIndex;
				this.source = source;
				this.damage = damage;
			}

			public rPlayerDamage(PlayerAgent player, float damage)
			{
				source = null;
				buffer = new byte[7];
				this.player = (byte)player.PlayerSlotIndex;
				this.damage = damage;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(player, buffer, ref index);
				BitHelper.WriteHalf(damage, buffer, ref index);
				if (source.HasValue)
				{
					BitHelper.WriteBytes(source.Value, buffer, ref index);
					fs.Write(buffer);
				}
				else
				{
					fs.Write(buffer, 0, 3);
				}
			}
		}

		public struct rFriendlyFire : ISerializable
		{
			private byte player;

			private byte source;

			private float damage;

			public const int SizeOf = 4;

			private byte[] buffer;

			public rFriendlyFire(PlayerAgent player, float damage, PlayerAgent source)
			{
				buffer = new byte[4];
				this.player = (byte)player.PlayerSlotIndex;
				this.source = (byte)source.PlayerSlotIndex;
				this.damage = damage;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(player, buffer, ref index);
				BitHelper.WriteHalf(damage, buffer, ref index);
				BitHelper.WriteBytes(source, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public struct rPlayerDodge : ISerializable
		{
			private byte player;

			private int source;

			public const int SizeOf = 5;

			private byte[] buffer;

			public rPlayerDodge(PlayerAgent player, int source)
			{
				buffer = new byte[5];
				this.player = (byte)player.PlayerSlotIndex;
				this.source = source;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(player, buffer, ref index);
				BitHelper.WriteBytes(source, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public static void OnFallDamage(PlayerAgent player, float damage)
		{
			APILogger.Debug($"{player.Owner.NickName} took {damage} fall damage.");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerFallDamage, new rPlayerDamage(player, damage));
		}

		public static void OnMeleeDamage(PlayerAgent player, float damage, EnemyAgent source)
		{
			int instanceID = ((Object)source).GetInstanceID();
			if (!Enemy.enemies.ContainsKey(instanceID))
			{
				APILogger.Error("(PlayerMeleeDamage) Enemy instance was not found.");
				return;
			}
			APILogger.Debug($"{player.Owner.NickName} took {damage} melee damage from [{instanceID}].");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerMeleeDamage, new rPlayerDamage(player, damage, instanceID));
		}

		public static void OnTongueDamage(PlayerAgent player, float damage, EnemyAgent source, MovingEnemyTentacleBase tongue)
		{
			int instanceID = ((Object)source).GetInstanceID();
			if (!Enemy.enemies.ContainsKey(instanceID))
			{
				APILogger.Error("(PlayerMeleeDamage) Enemy instance was not found.");
				return;
			}
			APILogger.Debug($"{player.Owner.NickName} took {damage} tongue damage from [{instanceID}].");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerTongueDamage, new rPlayerDamage(player, damage, instanceID));
			SnapshotManager.AddEvent(GameplayEvent.Type.SetTongue, new Enemy.TongueEvent(tongue));
		}

		public static void OnPelletDamage(PlayerAgent player, float damage, EnemyAgent source)
		{
			int instanceID = ((Object)source).GetInstanceID();
			if (!Enemy.enemies.ContainsKey(instanceID))
			{
				APILogger.Error("(PlayerMeleeDamage) Enemy instance was not found.");
				return;
			}
			APILogger.Debug($"{player.Owner.NickName} took {damage} pellet damage from [{instanceID}].");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerPelletDamage, new rPlayerDamage(player, damage, instanceID));
		}

		public static void OnBulletDamage(PlayerAgent player, float damage, PlayerAgent source)
		{
			APILogger.Debug($"{player.Owner.NickName} took {damage} bullet damage from [{source.Owner.NickName}].");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerBulletDamage, new rFriendlyFire(player, damage, source));
		}

		public static void OnMineDamage(PlayerAgent player, float damage, PlayerAgent source)
		{
			APILogger.Debug($"{player.Owner.NickName} took {damage} mine damage from [{source.Owner.NickName}].");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerMineDamage, new rFriendlyFire(player, damage, source));
		}

		public static void OnPelletDodge(PlayerAgent player, int source)
		{
			APILogger.Debug($"{player.Owner.NickName} dodged projectile from [{source}]");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerPelletDodge, new rPlayerDodge(player, source));
		}

		public static void OnTongueDodge(PlayerAgent player, int source, MovingEnemyTentacleBase tongue)
		{
			APILogger.Debug($"{player.Owner.NickName} dodged tongue from [{source}]");
			SnapshotManager.AddEvent(GameplayEvent.Type.PlayerTongueDodge, new rPlayerDodge(player, source));
			SnapshotManager.AddEvent(GameplayEvent.Type.SetTongue, new Enemy.TongueEvent(tongue));
		}
	}
	internal class PlayerHealth
	{
		public struct rPlayerQuantity : ISerializable
		{
			private byte player;

			private float value;

			public const int SizeOf = 3;

			private byte[] buffer;

			public rPlayerQuantity(PlayerAgent player, float value)
			{
				buffer = new byte[3];
				this.player = (byte)player.PlayerSlotIndex;
				this.value = value;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(player, buffer, ref index);
				BitHelper.WriteHalf(value, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public static void OnHealthChange(PlayerAgent player, float value)
		{
		}

		public static void OnInfectionChange(PlayerAgent player, float value)
		{
		}
	}
	internal class rSentry : ISerializable, SnapshotManager.ITransform
	{
		public SentryGunInstance sentry;

		public int instance;

		public byte slot;

		private Vector3 pos;

		public SNet_Player player;

		public const int SizeOf = 5;

		private static byte[] buffer = new byte[5];

		public bool active => sentry.m_firing != null;

		public byte dimensionIndex => (byte)((Agent)((Item)sentry).Owner).m_dimensionIndex;

		public Vector3 position => pos;

		public Quaternion rotation => Quaternion.LookRotation(sentry.m_firing.MuzzleAlign.forward);

		public float scale => 0f;

		public rSentry(SNet_Player player, SentryGunInstance sentry, Vector3 pos)
		{
			//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)
			this.player = player;
			this.sentry = sentry;
			instance = ((Object)sentry).GetInstanceID();
			slot = (byte)player.PlayerSlotIndex();
			this.pos = pos;
		}

		public void Serialize(FileStream fs)
		{
			int index = 0;
			BitHelper.WriteBytes(slot, buffer, ref index);
			BitHelper.WriteBytes(instance, buffer, ref index);
			fs.Write(buffer);
		}
	}
	internal static class PlayerSentry
	{
		public static string? sentryName = null;

		public static bool sentryShot = false;

		public static Dictionary<ulong, rSentry> sentries = new Dictionary<ulong, rSentry>();

		private static Dictionary<int, rSentry> instances = new Dictionary<int, rSentry>();

		public static void SpawnSentry(SNet_Player player, SentryGunInstance sentry, Vector3 pos)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			APILogger.Debug(player.NickName + " spawned a sentry.");
			int instanceID = ((Object)sentry).GetInstanceID();
			rSentry rSentry2 = new rSentry(player, sentry, pos);
			sentries.Add(rSentry2.player.Lookup, rSentry2);
			instances.Add(instanceID, rSentry2);
			SnapshotManager.AddEvent(GameplayEvent.Type.SpawnSentry, rSentry2);
			SnapshotManager.AddDynamicObject(new SnapshotManager.DynamicObject(instanceID, rSentry2));
		}

		public static void DespawnSentry(SentryGunInstance sentry)
		{
			int instanceID = ((Object)sentry).GetInstanceID();
			if (instances.ContainsKey(instanceID))
			{
				rSentry rSentry2 = instances[instanceID];
				APILogger.Debug("Sentry despawned by " + rSentry2.player.NickName + ".");
				sentries.Remove(rSentry2.player.Lookup);
				instances.Remove(instanceID);
				SnapshotManager.AddEvent(GameplayEvent.Type.DespawnSentry, new rInstance(instanceID));
				SnapshotManager.RemoveDynamicObject(instanceID);
			}
			else
			{
				APILogger.Error("Sentry does not exist to despawn.");
			}
		}

		public static void Reset()
		{
			instances.Clear();
			sentries.Clear();
		}
	}
}
namespace ReplayRecorder.Player.Patches
{
	[HarmonyPatch]
	internal class PlayerDamagePatches
	{
		private static bool wasTargeting;

		private static ulong player;

		private static MovingEnemyTentacleBase? tongue;

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveFallDamage")]
		[HarmonyPrefix]
		private static void ReceiveFallDamage(Dam_PlayerDamageBase __instance, pMiniDamageData data)
		{
			PlayerDamage.OnFallDamage(__instance.Owner, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax));
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveTentacleAttackDamage")]
		[HarmonyPrefix]
		private static void Prefix_ReceiveTentacleAttackDamage(Dam_PlayerDamageBase __instance, pMediumDamageData data)
		{
			//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)
			Agent val = default(Agent);
			if (((pAgent)(ref data.source)).TryGet(ref val))
			{
				EnemyAgent val2 = ((Il2CppObjectBase)val).TryCast<EnemyAgent>();
				if ((Object)(object)val2 == (Object)null)
				{
					AgentType type = val.m_type;
					APILogger.Debug("Could not find EnemyAgent, damage was done by agent of type: " + ((object)(AgentType)(ref type)).ToString() + ".");
					return;
				}
				float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
				num = AgentModifierManager.ApplyModifier(val, (AgentModifier)200, num);
				if ((Object)(object)tongue != (Object)null)
				{
					PlayerDamage.OnTongueDamage(__instance.Owner, num, val2, tongue);
				}
				else if (SNet.IsMaster)
				{
					APILogger.Error("Could not find tongue player was hit by as master, this should not happen.");
				}
			}
			tongue = null;
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveMeleeDamage")]
		[HarmonyPrefix]
		private static void ReceiveMeleeDamage(Dam_PlayerDamageBase __instance, pFullDamageData data)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Agent val = default(Agent);
			if (((pAgent)(ref data.source)).TryGet(ref val))
			{
				EnemyAgent val2 = ((Il2CppObjectBase)val).TryCast<EnemyAgent>();
				if ((Object)(object)val2 == (Object)null)
				{
					AgentType type = val.m_type;
					APILogger.Debug("Could not find EnemyAgent, damage was done by agent of type: " + ((object)(AgentType)(ref type)).ToString() + ".");
				}
				else
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).DamageMax);
					num = AgentModifierManager.ApplyModifier(val, (AgentModifier)200, num);
					PlayerDamage.OnMeleeDamage(__instance.Owner, num, val2);
				}
			}
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveShooterProjectileDamage")]
		[HarmonyPrefix]
		private static void ReceivePelletDamage(Dam_PlayerDamageBase __instance, pMediumDamageData data)
		{
			//IL_002e: 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)
			Agent val = default(Agent);
			if (SNet.IsMaster && ((pAgent)(ref data.source)).TryGet(ref val))
			{
				EnemyAgent val2 = ((Il2CppObjectBase)val).TryCast<EnemyAgent>();
				if ((Object)(object)val2 == (Object)null)
				{
					AgentType type = val.m_type;
					APILogger.Debug("Could not find EnemyAgent, damage was done by agent of type: " + ((object)(AgentType)(ref type)).ToString() + ".");
				}
				else
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					num = AgentModifierManager.ApplyModifier(val, (AgentModifier)70, num);
					PlayerDamage.OnPelletDamage(__instance.Owner, num, val2);
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileTargeting), "Update")]
		[HarmonyPrefix]
		private static void Prefix_Update(ProjectileTargeting __instance)
		{
			if (!SNet.IsMaster)
			{
				return;
			}
			int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
			if (Enemy.pellets.ContainsKey(instanceID))
			{
				wasTargeting = false;
				if (__instance.m_isTargeting && (Object)(object)__instance.m_playerTarget != (Object)null)
				{
					wasTargeting = true;
					player = __instance.m_playerTarget.Owner.Lookup;
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileTargeting), "Update")]
		[HarmonyPostfix]
		private static void Postfix_Update(ProjectileTargeting __instance)
		{
			if (!SNet.IsMaster)
			{
				return;
			}
			int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
			if (Enemy.pellets.ContainsKey(instanceID) && !__instance.m_isTargeting && wasTargeting)
			{
				PlayerAgent playerTarget = __instance.m_playerTarget;
				if ((Object)(object)__instance.m_playerTarget != (Object)null && playerTarget.Owner.Lookup == player)
				{
					PlayerDamage.OnPelletDodge(playerTarget, Enemy.pellets[instanceID].instance);
				}
			}
		}

		[HarmonyPatch(typeof(MovingEnemyTentacleBase), "OnAttackIsOut")]
		[HarmonyPrefix]
		private static void OnAttackIsOut(MovingEnemyTentacleBase __instance)
		{
			//IL_0049: 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_0055: 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_005b: 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)
			if (!SNet.IsMaster)
			{
				return;
			}
			tongue = __instance;
			PlayerAgent playerTarget = __instance.PlayerTarget;
			bool flag = __instance.CheckTargetInAttackTunnel();
			if ((Object)(object)playerTarget != (Object)null && ((Dam_SyncedDamageBase)playerTarget.Damage).IsSetup)
			{
				bool flag2;
				if (__instance.m_owner.EnemyBalancingData.UseTentacleTunnelCheck)
				{
					flag2 = flag;
				}
				else
				{
					Vector3 tipPos = __instance.GetTipPos();
					Vector3 val = ((Agent)playerTarget).TentacleTarget.position - tipPos;
					flag2 = ((Vector3)(ref val)).magnitude < __instance.m_owner.EnemyBalancingData.TentacleAttackDamageRadiusIfNoTunnelCheck;
				}
				if (!flag2)
				{
					int instanceID = ((Object)__instance.m_owner).GetInstanceID();
					PlayerDamage.OnTongueDodge(playerTarget, instanceID, tongue);
				}
			}
		}
	}
	[HarmonyPatch]
	internal class PlayerHealthPatches
	{
	}
	[HarmonyPatch]
	internal class PlayerPatches
	{
		[HarmonyPatch(typeof(PlayerSync), "OnSpawn")]
		[HarmonyPostfix]
		private static void OnSpawn(PlayerSync __instance)
		{
			if (SnapshotManager.active)
			{
				Player.SpawnPlayer(__instance.m_agent);
			}
		}

		[HarmonyPatch(typeof(PlayerSync), "OnDespawn")]
		[HarmonyPostfix]
		private static void OnDespawn(PlayerSync __instance)
		{
			if (SnapshotManager.active)
			{
				Player.DespawnPlayer(__instance.m_agent);
			}
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveSetDead")]
		[HarmonyPostfix]
		private static void OnPlayerDead(Dam_PlayerDamageBase __instance, pSetDeadData data)
		{
			if (SnapshotManager.active)
			{
				Player.OnPlayerDead(__instance.Owner);
			}
		}

		[HarmonyPatch(typeof(AgentReplicatedActions), "DoPlayerRevive")]
		[HarmonyPostfix]
		private static void DoPlayerRevive(pPlayerReviveAction data)
		{
			PlayerAgent val = default(PlayerAgent);
			if (((pPlayerAgent)(ref data.TargetPlayer)).TryGet(ref val) && !((Agent)val).Alive)
			{
				PlayerAgent val2 = default(PlayerAgent);
				if (((pPlayerAgent)(ref data.SourcePlayer)).TryGet(ref val2))
				{
					Player.OnPlayerRevive(val, val2);
					APILogger.Debug(val.Owner.NickName + " was revived by " + val2.Owner.NickName);
				}
				else
				{
					APILogger.Debug("Unable to get source player, this should not happen.");
				}
			}
		}
	}
	[HarmonyPatch]
	internal class PlayerSentryPatches
	{
		private static bool CompatabilityLayer_HelAutoSentryFix_Installed;

		private static bool shotgunSentryShot;

		[HarmonyPatch(typeof(SentryGunInstance), "OnSpawn")]
		[HarmonyPostfix]
		private static void OnSpawn(SentryGunInstance __instance, pGearSpawnData spawnData)
		{
			//IL_0001: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			pPlayer owner = spawnData.owner;
			SNet_Player player = default(SNet_Player);
			if (((pPlayer)(ref owner)).TryGetPlayer(ref player))
			{
				PlayerSentry.SpawnSentry(player, __instance, spawnData.position);
			}
			else
			{
				APILogger.Error("Sentry had no player as owner.");
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance), "OnDespawn")]
		[HarmonyPostfix]
		private static void OnDespawn(SentryGunInstance __instance)
		{
			PlayerSentry.DespawnSentry(__instance);
		}

		public static void CompatabilityLayer_HelAutoSentryFix()
		{
			CompatabilityLayer_HelAutoSentryFix_Installed = true;
		}

		private static void _Prefix_SentryGunFire(SentryGunInstance_Firing_Bullets __instance, bool doDamage, bool targetIsTagged)
		{
			if (doDamage)
			{
				PlayerSentry.sentryName = LocalizedText.op_Implicit(__instance.ArchetypeData.PublicName);
				SentryGunInstance component = ((Component)__instance).GetComponent<SentryGunInstance>();
				if ((Object)(object)component != (Object)null)
				{
					PlayerSentry.sentryName = ((Item)component).PublicName;
				}
				else
				{
					APILogger.Debug("Could not find sentry gun instance, this should not happen.");
				}
				PlayerSentry.sentryShot = true;
			}
		}

		private static void _Postfix_SentryGunFire()
		{
			PlayerSentry.sentryName = null;
			PlayerSentry.sentryShot = false;
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "FireBullet")]
		[HarmonyPrefix]
		private static void Prefix_SentryGunFiringBullet(SentryGunInstance_Firing_Bullets __instance, bool doDamage, bool targetIsTagged)
		{
			if (!CompatabilityLayer_HelAutoSentryFix_Installed)
			{
				_Prefix_SentryGunFire(__instance, doDamage, targetIsTagged);
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "FireBullet")]
		[HarmonyPostfix]
		private static void Postfix_SentryGunFiringBullet()
		{
			if (!CompatabilityLayer_HelAutoSentryFix_Installed)
			{
				_Postfix_SentryGunFire();
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "UpdateFireShotgunSemi")]
		[HarmonyPrefix]
		private static void Prefix_ShotgunSentryFiring(SentryGunInstance_Firing_Bullets __instance, bool isMaster, bool targetIsTagged)
		{
			if (!CompatabilityLayer_HelAutoSentryFix_Installed && isMaster && Clock.Time > __instance.m_fireBulletTimer)
			{
				shotgunSentryShot = true;
				_Postfix_SentryGunFire();
			}
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "UpdateFireShotgunSemi")]
		[HarmonyPostfix]
		private static void Postfix_ShotgunSentryFiring()
		{
			if (!CompatabilityLayer_HelAutoSentryFix_Installed && shotgunSentryShot)
			{
				shotgunSentryShot = false;
				_Postfix_SentryGunFire();
			}
		}
	}
}
namespace ReplayRecorder.Mines
{
	internal class rMine : ISerializable
	{
		public enum Type
		{
			Mine,
			Cfoam
		}

		public byte owner;

		public byte type;

		public byte dimensionIndex;

		public int instance;

		public Vector3 position;

		public Quaternion rotation;

		public const int SizeOf = 26;

		private static byte[] buffer = new byte[26];

		public rMine(SNet_Player owner, int instance, Type type, Vector3 position, Quaternion rotation)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			this.owner = (byte)owner.PlayerSlotIndex();
			this.type = (byte)type;
			dimensionIndex = (byte)((Agent)PlayerManager.PlayerAgentsInLevel[(int)this.owner]).m_dimensionIndex;
			this.instance = instance;
			this.position = position;
			this.rotation = rotation;
		}

		public void Serialize(FileStream fs)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			int index = 0;
			BitHelper.WriteBytes(owner, buffer, ref index);
			BitHelper.WriteBytes(type, buffer, ref index);
			BitHelper.WriteBytes(dimensionIndex, buffer, ref index);
			BitHelper.WriteBytes(instance, buffer, ref index);
			BitHelper.WriteBytes(position, buffer, ref index);
			BitHelper.WriteHalf(rotation, buffer, ref index);
			fs.Write(buffer);
		}
	}
	internal static class Mine
	{
		public struct rTripLine : ISerializable
		{
			public int instance;

			public float length;

			public const int SizeOf = 6;

			private static byte[] buffer = new byte[6];

			public rTripLine(int instance, float length)
			{
				this.instance = instance;
				this.length = length;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(instance, buffer, ref index);
				BitHelper.WriteHalf(length, buffer, ref index);
				fs.Write(buffer);
			}
		}

		private struct rExplodeMine : ISerializable
		{
			private int instance;

			private byte player;

			public const int SizeOf = 5;

			private static byte[] buffer = new byte[5];

			public rExplodeMine(int instance, byte player)
			{
				this.instance = instance;
				this.player = player;
			}

			public void Serialize(FileStream fs)
			{
				int index = 0;
				BitHelper.WriteBytes(instance, buffer, ref index);
				BitHelper.WriteBytes(player, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public static Dictionary<int, rMine> mines = new Dictionary<int, rMine>();

		public static void TripLine(int instance, float length)
		{
			APILogger.Debug($"Mine instance length updated [{instance}]");
			SnapshotManager.AddEvent(GameplayEvent.Type.MineTripLine, new rTripLine(instance, length));
		}

		public static void SpawnMine(SNet_Player owner, int instance, rMine.Type type, Vector3 position, Quaternion rotation)
		{
			//IL_0052: 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)
			APILogger.Debug($"Mine instance spawned by {owner.NickName} - [{instance}]");
			rMine rMine2 = new rMine(owner, instance, type, position, rotation);
			mines.Add(instance, rMine2);
			SnapshotManager.AddEvent(GameplayEvent.Type.SpawnMine, rMine2);
		}

		public static void DespawnMine(int instance)
		{
			APILogger.Debug($"Mine instance [{instance}] was despawned");
			SnapshotManager.AddEvent(GameplayEvent.Type.DespawnMine, new rInstance(instance));
			mines.Remove(instance);
		}

		public static void ExplodeMine(int instance, byte player)
		{
			APILogger.Debug($"Mine instance [{instance}] detonated");
			SnapshotManager.AddEvent(GameplayEvent.Type.ExplodeMine, new rExplodeMine(instance, player));
			mines.Remove(instance);
		}

		public static void Reset()
		{
			mines.Clear();
		}
	}
}
namespace ReplayRecorder.Mines.Patches
{
	[HarmonyPatch]
	internal class MinePatches
	{
		private static rMine? currentMine;

		private static float prevLength;

		private static PlayerAgent? player;

		[HarmonyPatch(typeof(MineDeployerInstance), "FixedUpdate")]
		[HarmonyPrefix]
		private static void Prefix_TripLineUpdate(MineDeployerInstance __instance)
		{
			prevLength = __instance.m_lastDetectionRange;
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "FixedUpdate")]
		[HarmonyPostfix]
		private static void Postfix_TripLineUpdate(MineDeployerInstance __instance)
		{
			if (prevLength != __instance.m_lastDetectionRange)
			{
				int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
				if (Mine.mines.ContainsKey(instanceID))
				{
					Mine.TripLine(instanceID, __instance.m_lastDetectionRange);
				}
				else
				{
					APILogger.Error("Mine did not exist in catalogue, this should not happen.");
				}
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "OnSyncTripLineUpdate")]
		[HarmonyPrefix]
		private static void Prefix_TripLineSyncUpdate(MineDeployerInstance __instance, pTripLineUpdate data)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (data.lineLength != __instance.m_detection.DetectionRange)
			{
				int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
				if (Mine.mines.ContainsKey(instanceID))
				{
					Mine.TripLine(instanceID, data.lineLength);
				}
				else
				{
					APILogger.Error("Mine did not exist in catalogue, this should not happen.");
				}
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "OnSpawn")]
		[HarmonyPostfix]
		private static void Spawn(MineDeployerInstance __instance, pItemSpawnData spawnData)
		{
			//IL_0037: 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_0053: 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_0078: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
			SNet_Player owner = default(SNet_Player);
			if (((pPlayer)(ref spawnData.owner)).TryGetPlayer(ref owner))
			{
				APILogger.Debug($"Mine Spawn ID - {spawnData.itemData.itemID_gearCRC}");
				switch (spawnData.itemData.itemID_gearCRC)
				{
				case 125u:
					Mine.SpawnMine(owner, instanceID, rMine.Type.Mine, spawnData.position, spawnData.rotation);
					break;
				case 139u:
					Mine.SpawnMine(owner, instanceID, rMine.Type.Mine, spawnData.position, spawnData.rotation);
					break;
				case 144u:
					Mine.SpawnMine(owner, instanceID, rMine.Type.Cfoam, spawnData.position, spawnData.rotation);
					break;
				}
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "SyncedPickup")]
		[HarmonyPrefix]
		private static void SyncedPickup(MineDeployerInstance __instance)
		{
			Mine.DespawnMine(((Object)((Component)__instance).gameObject).GetInstanceID());
		}

		[HarmonyPatch(typeof(GenericDamageComponent), "BulletDamage")]
		[HarmonyPrefix]
		private static void Prefix_BulletDamage(float dam, Agent sourceAgent)
		{
			player = ((Il2CppObjectBase)sourceAgent).TryCast<PlayerAgent>();
		}

		[HarmonyPatch(typeof(GenericDamageComponent), "BulletDamage")]
		[HarmonyPostfix]
		private static void Postfix_BulletDamage()
		{
			player = null;
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "SyncedTrigger")]
		[HarmonyPrefix]
		private static void Prefix_SyncedTrigger(MineDeployerInstance __instance)
		{
			int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
			if (Mine.mines.ContainsKey(instanceID))
			{
				currentMine = Mine.mines[instanceID];
				if ((Object)(object)player != (Object)null)
				{
					APILogger.Debug("Player triggered mine: " + player.PlayerName);
					Mine.ExplodeMine(instanceID, (byte)player.PlayerSlotIndex);
				}
				else
				{
					APILogger.Debug("Mine triggered without player.");
					Mine.ExplodeMine(instanceID, byte.MaxValue);
				}
			}
			else
			{
				APILogger.Error("Mine did not exist in catalogue, this should not happen.");
			}
		}

		[HarmonyPatch(typeof(MineDeployerInstance), "SyncedTrigger")]
		[HarmonyPostfix]
		private static void Postfix_SyncedTrigger()
		{
			currentMine = null;
		}
	}
}
namespace ReplayRecorder.Map
{
	internal static class Map
	{
		public class rMap : ISerializable
		{
			public struct Location
			{
				public bool valid;

				public char area;

				public int zone;

				public Location(int zone, char area)
				{
					valid = false;
					this.area = area;
					this.zone = zone;
					valid = true;
				}

				public Location()
				{
					valid = false;
					valid = false;
					area = 'Z';
					zone = 0;
				}
			}

			public class Surface
			{
				public Mesh mesh;

				public Surface(Mesh mesh)
				{
					this.mesh = mesh;
				}
			}

			public eDimensionIndex dimension;

			public Surface[] surfaces;

			private static byte[] buffer = new byte[3];

			public rMap(eDimensionIndex dimension, Surface[] surfaces)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				this.dimension = dimension;
				this.surfaces = surfaces;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_016c: Unknown result type (might be due to invalid IL or missing references)
				int index = 0;
				int num = 3;
				if (buffer.Length < num)
				{
					buffer = new byte[num];
				}
				if (surfaces.Length > 65535)
				{
					APILogger.Error($"There were more than {65535} surfaces");
					return;
				}
				BitHelper.WriteBytes((byte)dimension, buffer, ref index);
				BitHelper.WriteBytes((ushort)surfaces.Length, buffer, ref index);
				for (int i = 0; i < surfaces.Length; i++)
				{
					Surface obj = surfaces[i];
					Vector3[] array = Il2CppArrayBase<Vector3>.op_Implicit((Il2CppArrayBase<Vector3>)(object)obj.mesh.vertices);
					int[] array2 = Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)obj.mesh.triangles);
					if (array.Length > 65535)
					{
						APILogger.Error($"There were more than {65535} vertices");
						return;
					}
					num += 6 + 12 * array.Length + 2 * array2.Length;
					if (buffer.Length < num)
					{
						byte[] destinationArray = new byte[num];
						Array.Copy(buffer, destinationArray, buffer.Length);
						buffer = destinationArray;
					}
					BitHelper.WriteBytes((ushort)array.Length, buffer, ref index);
					BitHelper.WriteBytes((uint)array2.Length, buffer, ref index);
					for (int j = 0; j < array.Length; j++)
					{
						BitHelper.WriteBytes(array[j], buffer, ref index);
					}
					for (int k = 0; k < array2.Length; k++)
					{
						BitHelper.WriteBytes((ushort)array2[k], buffer, ref index);
					}
				}
				fs.Write(buffer, 0, num);
			}
		}

		public class rDoor : ISerializable
		{
			public enum Type
			{
				WeakDoor,
				SecurityDoor,
				BulkheadDoor,
				BulkheadDoorMain,
				ApexDoor
			}

			public static byte _id = 0;

			public Type type;

			public byte id;

			public LG_GateType size;

			public float healthMax;

			public bool isCheckpoint;

			public rMap.Location to;

			public rMap.Location from;

			public LG_Gate gate;

			public GameObject doorObj;

			public const int SizeOf = 23;

			private static byte[] buffer = new byte[23];

			public rDoor(float healthMax, Type type, LG_Gate gate, GameObject doorObj)
			{
				//IL_0007: 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_0080: 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_0015: Invalid comparison between Unknown and I4
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Invalid comparison between Unknown and I4
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				if ((int)gate.Type != 0 && (int)gate.Type != 1 && (int)gate.Type != 2)
				{
					APILogger.Warn($"Weird gate type was created as a door: {gate.Type}");
				}
				id = _id++;
				this.gate = gate;
				this.healthMax = healthMax;
				this.doorObj = doorObj;
				size = gate.Type;
				this.type = type;
				isCheckpoint = gate.IsCheckpointDoor;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: 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)
				int index = 0;
				BitHelper.WriteBytes(id, buffer, ref index);
				BitHelper.WriteBytes((byte)type, buffer, ref index);
				BitHelper.WriteBytes((byte)size, buffer, ref index);
				BitHelper.WriteBytes((byte)healthMax, buffer, ref index);
				BitHelper.WriteBytes(doorObj.transform.position, buffer, ref index);
				BitHelper.WriteHalf(doorObj.transform.rotation, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public struct rDoorID : ISerializable
		{
			public byte id;

			public rDoorID(rDoor door)
			{
				id = door.id;
			}

			public void Serialize(FileStream fs)
			{
				fs.WriteByte(id);
			}
		}

		public struct rDoorState : ISerializable
		{
			public byte id;

			public byte state;

			public rDoorState(rDoor door, eDoorStatus state)
			{
				//IL_000c: 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_0021: Expected I4, but got Unknown
				id = door.id;
				switch (state - 10)
				{
				case 0:
					this.state = 1;
					break;
				case 2:
					this.state = 2;
					break;
				case 1:
					this.state = 3;
					break;
				default:
					this.state = 0;
					break;
				}
			}

			public void Serialize(FileStream fs)
			{
				fs.WriteByte(id);
				fs.WriteByte(state);
			}
		}

		public class rLadder : ISerializable
		{
			public static byte _id = 0;

			private LG_Ladder ladder;

			public byte id;

			public const int SizeOf = 22;

			private static byte[] buffer = new byte[22];

			public Vector3 top => ladder.m_ladderTop;

			public float height => ladder.m_height;

			public Quaternion rotation => ((Component)ladder).gameObject.transform.rotation;

			public rLadder(LG_Ladder ladder)
			{
				id = _id++;
				this.ladder = ladder;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0015: 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)
				int index = 0;
				BitHelper.WriteBytes(id, buffer, ref index);
				BitHelper.WriteBytes(top, buffer, ref index);
				BitHelper.WriteHalf(height, buffer, ref index);
				BitHelper.WriteHalf(rotation, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public class rContainer : ISerializable
		{
			public static byte _id = 0;

			public byte id;

			private LG_ResourceContainer_Storage container;

			public int instance;

			public const int SizeOf = 20;

			private static byte[] buffer = new byte[20];

			public Vector3 position => ((Component)container).transform.position;

			public Quaternion rotation => ((Component)container).transform.rotation;

			public rContainer(LG_ResourceContainer_Storage container)
			{
				id = _id++;
				instance = ((Object)container).GetInstanceID();
				this.container = container;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				int index = 0;
				BitHelper.WriteBytes(id, buffer, ref index);
				BitHelper.WriteBytes(position, buffer, ref index);
				BitHelper.WriteHalf(rotation, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public class rTerminal : ISerializable
		{
			public static byte _id = 0;

			public byte id;

			private LG_ComputerTerminal terminal;

			public const int SizeOf = 20;

			private static byte[] buffer = new byte[20];

			public Vector3 position => terminal.m_position;

			public Quaternion rotation => ((Component)terminal).transform.rotation;

			public rTerminal(LG_ComputerTerminal terminal)
			{
				id = _id++;
				this.terminal = terminal;
			}

			public void Serialize(FileStream fs)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				int index = 0;
				BitHelper.WriteBytes(id, buffer, ref index);
				BitHelper.WriteBytes(position, buffer, ref index);
				BitHelper.WriteHalf(rotation, buffer, ref index);
				fs.Write(buffer);
			}
		}

		public static Dictionary<eDimensionIndex, rMap> map = new Dictionary<eDimensionIndex, rMap>();

		private static HashSet<eDimensionIndex> processed = new HashSet<eDimensionIndex>();

		public static List<rDoor> doors = new List<rDoor>();

		public static Dictionary<eDimensionIndex, List<rLadder>> ladders = new Dictionary<eDimensionIndex, List<rLadder>>();

		public static Dictionary<eDimensionIndex, Dictionary<int, rContainer>> containers = new Dictionary<eDimensionIndex, Dictionary<int, rContainer>>();

		public static Dictionary<eDimensionIndex, List<rTerminal>> terminals = new Dictionary<eDimensionIndex, List<rTerminal>>();

		private static void GenerateMeshSurfaces(Dimension dimension)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			NavMeshTriangulation obj = NavMesh.CalculateTriangulation();
			APILogger.Debug("Merging nearby vertices...");
			Vector3[] vertices = Il2CppArrayBase<Vector3>.op_Implicit((Il2CppArrayBase<Vector3>)(object)obj.vertices);
			int[] indices = Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)obj.indices);
			(v