Decompiled source of GTFOReplay v0.2.9

ReplayRecorder.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using API;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GameData;
using Globals;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using ReplayRecorder.API;
using ReplayRecorder.API.Attributes;
using ReplayRecorder.BepInEx;
using ReplayRecorder.Core;
using ReplayRecorder.Exceptions;
using ReplayRecorder.Snapshot;
using ReplayRecorder.Snapshot.Exceptions;
using ReplayRecorder.Snapshot.Types;
using SNetwork;
using TMPro;
using UnityEngine;
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+1ce592b4a73a011d2f8b04df1c44cd0ef8bbeaa9")]
[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 API
{
	[HarmonyPatch(typeof(GameDataInit))]
	internal class GameDataInit_Patches
	{
		[HarmonyPatch("Initialize")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		public static void Initialize_Postfix()
		{
			Analytics.enabled = false;
		}
	}
	internal static class APILogger
	{
		private static readonly ManualLogSource logger;

		static APILogger()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			logger = new ManualLogSource("Rand-API");
			Logger.Sources.Add((ILogSource)(object)logger);
		}

		private static string Format(string module, object msg)
		{
			return $"[{module}]: {msg}";
		}

		public static void Info(string module, object data)
		{
			logger.LogMessage((object)Format(module, data));
		}

		public static void Verbose(string module, object data)
		{
		}

		public static void Log(object data)
		{
			logger.LogDebug((object)Format("ReplayRecorder", data));
		}

		public static void Debug(object data)
		{
			if (ConfigManager.Debug)
			{
				Log(data);
			}
		}

		public static void Warn(object data)
		{
			logger.LogWarning((object)Format("ReplayRecorder", data));
		}

		public static void Error(object data)
		{
			logger.LogError((object)Format("ReplayRecorder", data));
		}
	}
}
namespace ReplayRecorder
{
	internal class BufferPool
	{
		private Stack<ByteBuffer> pool = new Stack<ByteBuffer>();

		private readonly object lockObj = new object();

		private int size;

		private int inUse;

		public int Size => size;

		public int InUse => inUse;

		public void Shrink(int count)
		{
			while (pool.Count > count)
			{
				pool.Pop();
				size--;
			}
		}

		public ByteBuffer Checkout()
		{
			lock (lockObj)
			{
				inUse++;
				if (pool.Count == 0)
				{
					size++;
					return new ByteBuffer();
				}
				ByteBuffer byteBuffer = pool.Pop();
				byteBuffer.Clear();
				return byteBuffer;
			}
		}

		public void Release(ByteBuffer buffer)
		{
			lock (lockObj)
			{
				if (inUse != 0)
				{
					inUse--;
				}
				else
				{
					size++;
				}
				pool.Push(buffer);
			}
		}
	}
	internal static class Net
	{
		public delegate void onConnect(EndPoint endpoint);

		public delegate void onAccept(EndPoint endpoint);

		public delegate void onReceive(ArraySegment<byte> buffer, EndPoint endpoint);

		public delegate void onDisconnect(EndPoint endpoint);

		public delegate void onClose();

		public enum MessageType
		{
			StartGame,
			EndGame,
			LiveBytes,
			Acknowledgement
		}
	}
	internal class TCPServer : IDisposable
	{
		private class Connection : IDisposable
		{
			public enum State
			{
				waiting,
				reading
			}

			public Socket socket;

			public readonly EndPoint remoteEP;

			public byte[] recvBuffer;

			public byte[] sendBuffer;

			public byte[] messageBuffer;

			public SemaphoreSlim semaphoreSend = new SemaphoreSlim(1);

			public State state;

			public int messageSize;

			public int bytesWritten;

			public Connection(Socket socket, int bufferSize)
			{
				this.socket = socket;
				remoteEP = socket.RemoteEndPoint;
				messageBuffer = new byte[bufferSize];
				recvBuffer = new byte[bufferSize];
				sendBuffer = new byte[bufferSize];
			}

			public void Dispose()
			{
				semaphoreSend.Dispose();
				socket.Dispose();
			}
		}

		private readonly int bufferSize;

		private Socket? socket;

		public Net.onAccept? onAccept;

		public Net.onReceive? onReceive;

		public Net.onDisconnect? onDisconnect;

		public Net.onClose? onClose;

		private ConcurrentDictionary<EndPoint, Connection> acceptedConnections = new ConcurrentDictionary<EndPoint, Connection>();

		public ICollection<EndPoint> Connections => acceptedConnections.Keys;

		public TCPServer(int bufferSize = 8192)
		{
			if (bufferSize < 4)
			{
				throw new ArgumentException("Buffer size cannot be smaller than a message header [sizeof(int)].");
			}
			this.bufferSize = bufferSize;
		}

		private void Open()
		{
			if (socket != null)
			{
				Dispose();
			}
			socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, optionValue: true);
		}

		public EndPoint Bind(EndPoint remoteEP, int backlog = 5)
		{
			Open();
			socket.Bind(remoteEP);
			socket.Listen(backlog);
			Listen();
			return socket.LocalEndPoint;
		}

		private async Task Listen()
		{
			if (socket == null)
			{
				return;
			}
			Socket incoming = await socket.AcceptAsync().ConfigureAwait(continueOnCapturedContext: false);
			EndPoint remoteEndPoint = incoming.RemoteEndPoint;
			if (remoteEndPoint != null)
			{
				Connection connection = new Connection(incoming, bufferSize);
				acceptedConnections.AddOrUpdate(remoteEndPoint, connection, delegate(EndPoint key, Connection old)
				{
					incoming.Dispose();
					return old;
				});
				onAccept?.Invoke(remoteEndPoint);
				ListenTo(connection);
			}
			else
			{
				incoming.Dispose();
			}
			Listen();
		}

		private async Task ListenTo(Connection connection)
		{
			try
			{
				int num = await connection.socket.ReceiveAsync(connection.recvBuffer, SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false);
				if (num > 0)
				{
					int num2 = num;
					int index = 0;
					do
					{
						switch (connection.state)
						{
						case Connection.State.waiting:
							connection.messageSize = BitHelper.ReadInt(connection.recvBuffer, ref index);
							connection.bytesWritten = 0;
							if (connection.messageSize > 0)
							{
								connection.state = Connection.State.reading;
							}
							break;
						case Connection.State.reading:
						{
							int num3 = num2;
							if (connection.bytesWritten + num2 > connection.messageSize)
							{
								num3 = connection.messageSize - connection.bytesWritten;
							}
							Array.Copy(connection.recvBuffer, index, connection.messageBuffer, connection.bytesWritten, num3);
							connection.bytesWritten += num3;
							index += num3;
							APILogger.Debug($"read: {connection.bytesWritten} {connection.messageSize}");
							if (connection.bytesWritten == connection.messageSize)
							{
								connection.state = Connection.State.waiting;
								onReceive?.Invoke(new ArraySegment<byte>(connection.messageBuffer, 0, connection.messageSize), connection.remoteEP);
							}
							break;
						}
						}
						num2 = num - index;
					}
					while (num2 > 0);
					ListenTo(connection);
				}
				else
				{
					Dispose(connection);
					onDisconnect?.Invoke(connection.remoteEP);
				}
			}
			catch (ObjectDisposedException)
			{
				Dispose(connection);
				onDisconnect?.Invoke(connection.remoteEP);
			}
		}

		private void Dispose(Connection connection)
		{
			acceptedConnections.Remove(connection.socket.RemoteEndPoint, out var _);
			connection.Dispose();
		}

		public async Task Send(ArraySegment<byte> data)
		{
			List<Task> list = new List<Task>();
			foreach (EndPoint key in acceptedConnections.Keys)
			{
				list.Add(SendTo(data, key));
			}
			await Task.WhenAll(list).ConfigureAwait(continueOnCapturedContext: false);
		}

		public async Task RawSendTo(ArraySegment<byte> data, EndPoint remoteEP)
		{
			if (!acceptedConnections.TryGetValue(remoteEP, out Connection connection))
			{
				return;
			}
			await connection.semaphoreSend.WaitAsync().ConfigureAwait(continueOnCapturedContext: false);
			try
			{
				int num = await connection.socket.SendAsync(data, SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false);
				while (num < data.Count)
				{
					int num2 = num;
					num = num2 + await connection.socket.SendAsync(new ArraySegment<byte>(data.Array, data.Offset + num, data.Count - num), SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false);
				}
			}
			catch (SocketException)
			{
			}
			finally
			{
				connection.semaphoreSend.Release();
			}
		}

		public async Task SendTo(ArraySegment<byte> data, EndPoint remoteEP)
		{
			if (!acceptedConnections.TryGetValue(remoteEP, out Connection connection))
			{
				return;
			}
			await connection.semaphoreSend.WaitAsync().ConfigureAwait(continueOnCapturedContext: false);
			try
			{
				if (data.Count <= int.MaxValue)
				{
					int size = 4 + data.Count;
					int num;
					for (num = connection.sendBuffer.Length; num < size; num *= 2)
					{
					}
					if (num > connection.sendBuffer.Length)
					{
						connection.sendBuffer = new byte[num];
					}
					int index = 0;
					BitHelper.WriteBytes(data.Count, (ArraySegment<byte>)connection.sendBuffer, ref index);
					Array.Copy(data.Array, data.Offset, connection.sendBuffer, index, data.Count);
					int num2 = await connection.socket.SendAsync(new ArraySegment<byte>(connection.sendBuffer, 0, size), SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false);
					while (num2 < size)
					{
						int num3 = num2;
						num2 = num3 + await connection.socket.SendAsync(new ArraySegment<byte>(connection.sendBuffer, num2, size - num2), SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
			}
			catch (SocketException)
			{
			}
			finally
			{
				connection.semaphoreSend.Release();
			}
		}

		public void Disconnect()
		{
			Dispose();
		}

		public void DisconnectClients()
		{
			foreach (Connection value in acceptedConnections.Values)
			{
				value.Dispose();
			}
			acceptedConnections.Clear();
		}

		public void Dispose()
		{
			if (socket != null)
			{
				DisconnectClients();
				socket.Dispose();
				socket = null;
				onClose?.Invoke();
			}
		}
	}
	[HarmonyPatch]
	internal class GameEventManager
	{
		[HarmonyPatch(typeof(ElevatorRide), "StartElevatorRide")]
		[HarmonyPostfix]
		private static void StartElevatorRide()
		{
			APILogger.Debug("Entered elevator!");
			SnapshotManager.OnElevatorStart();
			Replay.OnExpeditionStart?.Invoke();
		}

		[HarmonyPatch(typeof(RundownManager), "EndGameSession")]
		[HarmonyPrefix]
		private static void EndGameSession()
		{
			APILogger.Debug("Level ended!");
			SnapshotManager.OnExpeditionEnd();
		}

		[HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")]
		[HarmonyPrefix]
		private static void LeaveHub()
		{
			APILogger.Debug("Level ended!");
			SnapshotManager.OnExpeditionEnd();
		}

		[HarmonyPatch(typeof(GS_ReadyToStopElevatorRide), "Enter")]
		[HarmonyPostfix]
		private static void StopElevatorRide()
		{
			APILogger.Debug("Stop elevator!");
			Replay.OnElevatorStop?.Invoke();
		}

		[HarmonyPatch(typeof(PUI_LocalPlayerStatus), "UpdateBPM")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		public static void Initialize_Postfix(PUI_LocalPlayerStatus __instance)
		{
			if (ConfigManager.PerformanceDebug)
			{
				SnapshotInstance instance = SnapshotManager.GetInstance();
				TextMeshPro pulseText = __instance.m_pulseText;
				((TMP_Text)pulseText).text = ((TMP_Text)pulseText).text + $" | ({instance.pool.InUse}/{instance.pool.Size}) {Mathf.RoundToInt(instance.tickTime)}({Mathf.RoundToInt(instance.waitForWrite)})ms";
			}
		}
	}
	public static class Raudy
	{
		public static long Now => ((DateTimeOffset)DateTime.Now).ToUnixTimeMilliseconds();
	}
	public class BitHelperBufferTooLarge : Exception
	{
		public BitHelperBufferTooLarge(string message)
			: base(message)
		{
		}
	}
	public class ByteBuffer
	{
		internal ArraySegment<byte> _array = new byte[1024];

		internal int count;

		internal ArraySegment<byte> Array => new ArraySegment<byte>(_array.Array, _array.Offset, count);

		internal byte this[int index]
		{
			get
			{
				return _array[index];
			}
			set
			{
				_array[index] = value;
			}
		}

		public int Count => count;

		public ByteBuffer()
		{
			_array = new byte[1024];
		}

		public ByteBuffer(ArraySegment<byte> array)
		{
			_array = array;
		}

		internal void Clear()
		{
			count = 0;
		}

		internal void Reserve(int size, bool increment = false)
		{
			if (_array.Count - count < size)
			{
				byte[] array = new byte[Mathf.Max(_array.Count * 2, count + size)];
				System.Array.Copy(_array.Array, _array.Offset, array, 0, _array.Count);
				_array = array;
			}
			if (increment)
			{
				count += size;
			}
		}

		internal void Flush(FileStream fs)
		{
			APILogger.Debug($"Flushed snapshot: {count} bytes.");
			BitHelper.WriteBytes(count, fs);
			fs.Write(Array);
			count = 0;
		}

		internal async Task AsyncFlush(FileStream fs)
		{
			APILogger.Debug($"Async Flushed snapshot: {count} bytes.");
			BitHelper.WriteBytes(count, fs);
			await fs.WriteAsync(Array).ConfigureAwait(continueOnCapturedContext: false);
			count = 0;
		}

		internal void Shrink()
		{
			_array = new byte[1024];
			GC.Collect();
		}
	}
	public interface BufferWriteable
	{
		void Write(ByteBuffer buffer);
	}
	public 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)]
		private static long ReverseEndianness(long value)
		{
			return (long)ReverseEndianness((ulong)value);
		}

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

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private 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, ArraySegment<byte> destination, ref int index)
		{
			int num = 0;
			while (num < size)
			{
				destination[index++] = source[num++];
			}
		}

		public static void WriteBytes(byte value, ArraySegment<byte> destination, ref int index)
		{
			destination[index++] = value;
		}

		public static void WriteBytes(bool value, ArraySegment<byte> destination, ref int index)
		{
			WriteBytes(value ? ((byte)1) : ((byte)0), destination, ref index);
		}

		public unsafe static void WriteBytes(ulong value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, destination, ref index);
		}

		public unsafe static void WriteBytes(uint value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, destination, ref index);
		}

		public unsafe static void WriteBytes(ushort value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, destination, ref index);
		}

		public unsafe static void WriteBytes(long value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, destination, ref index);
		}

		public unsafe static void WriteBytes(int value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, destination, ref index);
		}

		public unsafe static void WriteBytes(short value, ArraySegment<byte> destination, ref int index)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, destination, ref index);
		}

		public unsafe static void WriteBytes(float value, ArraySegment<byte> destination, ref int index)
		{
			int value2 = *(int*)(&value);
			if (!BitConverter.IsLittleEndian)
			{
				value2 = ReverseEndianness(value2);
			}
			_WriteBytes((byte*)(&value2), 4, destination, ref index);
		}

		public static void WriteBytes(string value, ArraySegment<byte> destination, ref int index)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(value);
			if (bytes.Length > 65535)
			{
				throw new BitHelperBufferTooLarge($"String value is too large, byte length must be smaller than {65535}.");
			}
			WriteBytes((ushort)bytes.Length, destination, ref index);
			Array.Copy(bytes, 0, destination.Array, destination.Offset + index, bytes.Length);
			index += bytes.Length;
		}

		public static int SizeOfString(string value)
		{
			return 2 + Encoding.UTF8.GetBytes(value).Length;
		}

		public static void WriteBytes(ArraySegment<byte> buffer, ArraySegment<byte> destination, ref int index)
		{
			WriteBytes(buffer.Count, destination, ref index);
			Array.Copy(buffer.Array, buffer.Offset, destination.Array, destination.Offset + index, buffer.Count);
			index += buffer.Count;
		}

		public static void WriteHalf(float value, ArraySegment<byte> destination, ref int index)
		{
			WriteBytes(FloatToHalf(value), destination, ref index);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private unsafe static void _WriteBytes(byte* bytes, int size, ByteBuffer buffer)
		{
			buffer.Reserve(size);
			for (int i = 0; i < size; i++)
			{
				buffer[buffer.count++] = bytes[i];
			}
		}

		public static void WriteBytes(byte value, ByteBuffer buffer)
		{
			buffer.Reserve(1);
			buffer[buffer.count++] = value;
		}

		public static void WriteBytes(bool value, ByteBuffer buffer)
		{
			WriteBytes(value ? ((byte)1) : ((byte)0), buffer);
		}

		public unsafe static void WriteBytes(ulong value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, buffer);
		}

		public unsafe static void WriteBytes(uint value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, buffer);
		}

		public unsafe static void WriteBytes(ushort value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, buffer);
		}

		public unsafe static void WriteBytes(long value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, buffer);
		}

		public unsafe static void WriteBytes(int value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, buffer);
		}

		public unsafe static void WriteBytes(short value, ByteBuffer buffer)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, buffer);
		}

		public unsafe static void WriteBytes(float value, ByteBuffer buffer)
		{
			int value2 = *(int*)(&value);
			if (!BitConverter.IsLittleEndian)
			{
				value2 = ReverseEndianness(value2);
			}
			_WriteBytes((byte*)(&value2), 4, buffer);
		}

		public static void WriteBytes(string value, ByteBuffer buffer)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(value);
			if (value.Length > 65535)
			{
				throw new BitHelperBufferTooLarge($"String value is too large, length must be smaller than {65535}.");
			}
			WriteBytes((ushort)bytes.Length, buffer);
			buffer.Reserve(bytes.Length);
			Array.Copy(bytes, 0, buffer._array.Array, buffer._array.Offset + buffer.count, bytes.Length);
			buffer.count += bytes.Length;
		}

		public static void WriteBytes(ArraySegment<byte> bytes, ByteBuffer buffer, bool includeCount = true)
		{
			if (includeCount)
			{
				WriteBytes(bytes.Count, buffer);
			}
			buffer.Reserve(bytes.Count);
			Array.Copy(bytes.Array, bytes.Offset, buffer._array.Array, buffer._array.Offset + buffer.count, bytes.Count);
			buffer.count += bytes.Count;
		}

		public static void WriteBytes(BufferWriteable writeable, ByteBuffer buffer)
		{
			writeable.Write(buffer);
		}

		public static void WriteHalf(float value, ByteBuffer buffer)
		{
			WriteBytes(FloatToHalf(value), buffer);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private unsafe static void _WriteBytes(byte* bytes, int size, FileStream fs)
		{
			for (int i = 0; i < size; i++)
			{
				fs.WriteByte(bytes[i]);
			}
		}

		public static void WriteBytes(byte value, FileStream fs)
		{
			fs.WriteByte(value);
		}

		public static void WriteBytes(bool value, FileStream fs)
		{
			WriteBytes(value ? ((byte)1) : ((byte)0), fs);
		}

		public unsafe static void WriteBytes(ulong value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, fs);
		}

		public unsafe static void WriteBytes(uint value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, fs);
		}

		public unsafe static void WriteBytes(ushort value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, fs);
		}

		public unsafe static void WriteBytes(long value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 8, fs);
		}

		public unsafe static void WriteBytes(int value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 4, fs);
		}

		public unsafe static void WriteBytes(short value, FileStream fs)
		{
			if (!BitConverter.IsLittleEndian)
			{
				value = ReverseEndianness(value);
			}
			_WriteBytes((byte*)(&value), 2, fs);
		}

		public unsafe static void WriteBytes(float value, FileStream fs)
		{
			int value2 = *(int*)(&value);
			if (!BitConverter.IsLittleEndian)
			{
				value2 = ReverseEndianness(value2);
			}
			_WriteBytes((byte*)(&value2), 4, fs);
		}

		public static void WriteBytes(string value, FileStream fs)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(value);
			if (value.Length > 65535)
			{
				throw new BitHelperBufferTooLarge($"String value is too large, length must be smaller than {65535}.");
			}
			WriteBytes((ushort)bytes.Length, fs);
			fs.Write(bytes);
		}

		public static void WriteBytes(byte[] buffer, FileStream fs)
		{
			WriteBytes(buffer.Length, fs);
			fs.Write(buffer);
		}

		public static void WriteHalf(float value, FileStream fs)
		{
			WriteBytes(FloatToHalf(value), fs);
		}

		[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)]
		private 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)]
		private 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 float Quantize(float x)
		{
			return HalfToFloat(FloatToHalf(x));
		}

		public static byte ReadByte(ArraySegment<byte> source, ref int index)
		{
			return source[index++];
		}

		public static bool ReadBool(ArraySegment<byte> source, ref int index)
		{
			return ReadByte(source, ref index) != 0;
		}

		public unsafe static ulong ReadULong(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 8;
				ulong num2 = *(ulong*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public unsafe static long ReadLong(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 8;
				long num2 = *(long*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public unsafe static uint ReadUInt(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 4;
				uint num2 = *(uint*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public unsafe static int ReadInt(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 4;
				int num2 = *(int*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public unsafe static ushort ReadUShort(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 2;
				ushort num2 = *(ushort*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public unsafe static short ReadShort(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* num = ptr + source.Offset + index;
				index += 2;
				short num2 = *(short*)num;
				if (!BitConverter.IsLittleEndian)
				{
					num2 = ReverseEndianness(num2);
				}
				return num2;
			}
		}

		public static float ReadHalf(ArraySegment<byte> source, ref int index)
		{
			return HalfToFloat(ReadUShort(source, ref index));
		}

		public unsafe static float ReadFloat(ArraySegment<byte> source, ref int index)
		{
			fixed (byte* ptr = source.Array)
			{
				byte* ptr2 = ptr + source.Offset + index;
				index += 4;
				if (!BitConverter.IsLittleEndian)
				{
					int num = ReverseEndianness(*(int*)ptr2);
					return *(float*)(&num);
				}
				return *(float*)ptr2;
			}
		}

		public static string ReadString(ArraySegment<byte> source, ref int index)
		{
			int num = ReadUShort(source, ref index);
			string @string = Encoding.UTF8.GetString(source.Array, source.Offset + index, num);
			index += num;
			return @string;
		}

		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_0012: 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)
			WriteBytes(value.x, (ArraySegment<byte>)destination, ref index);
			WriteBytes(value.y, (ArraySegment<byte>)destination, ref index);
			WriteBytes(value.z, (ArraySegment<byte>)destination, ref index);
		}

		public static void WriteBytes(Quaternion value, byte[] destination, ref int index)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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, (ArraySegment<byte>)destination, ref index);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteBytes(value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.z, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.w, (ArraySegment<byte>)destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.z, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.w, (ArraySegment<byte>)destination, ref index);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteBytes(value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.z, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.w, (ArraySegment<byte>)destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.z, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.w, (ArraySegment<byte>)destination, ref index);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteBytes(value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.w, (ArraySegment<byte>)destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.w, (ArraySegment<byte>)destination, ref index);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteBytes(value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(value.z, (ArraySegment<byte>)destination, ref index);
				}
				else
				{
					WriteBytes(0f - value.x, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.y, (ArraySegment<byte>)destination, ref index);
					WriteBytes(0f - value.z, (ArraySegment<byte>)destination, ref index);
				}
				break;
			}
		}

		public static void WriteBytes(Vector3 value, ByteBuffer buffer)
		{
			//IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			WriteBytes(value.x, buffer);
			WriteBytes(value.y, buffer);
			WriteBytes(value.z, buffer);
		}

		public static void WriteBytes(Quaternion value, ByteBuffer buffer)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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, buffer);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteBytes(value.y, buffer);
					WriteBytes(value.z, buffer);
					WriteBytes(value.w, buffer);
				}
				else
				{
					WriteBytes(0f - value.y, buffer);
					WriteBytes(0f - value.z, buffer);
					WriteBytes(0f - value.w, buffer);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteBytes(value.x, buffer);
					WriteBytes(value.z, buffer);
					WriteBytes(value.w, buffer);
				}
				else
				{
					WriteBytes(0f - value.x, buffer);
					WriteBytes(0f - value.z, buffer);
					WriteBytes(0f - value.w, buffer);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteBytes(value.x, buffer);
					WriteBytes(value.y, buffer);
					WriteBytes(value.w, buffer);
				}
				else
				{
					WriteBytes(0f - value.x, buffer);
					WriteBytes(0f - value.y, buffer);
					WriteBytes(0f - value.w, buffer);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteBytes(value.x, buffer);
					WriteBytes(value.y, buffer);
					WriteBytes(value.z, buffer);
				}
				else
				{
					WriteBytes(0f - value.x, buffer);
					WriteBytes(0f - value.y, buffer);
					WriteBytes(0f - value.z, buffer);
				}
				break;
			}
		}

		public static void WriteBytes(Vector3 value, FileStream fs)
		{
			//IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			WriteBytes(value.x, fs);
			WriteBytes(value.y, fs);
			WriteBytes(value.z, fs);
		}

		public static void WriteBytes(Quaternion value, FileStream fs)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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, fs);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteBytes(value.y, fs);
					WriteBytes(value.z, fs);
					WriteBytes(value.w, fs);
				}
				else
				{
					WriteBytes(0f - value.y, fs);
					WriteBytes(0f - value.z, fs);
					WriteBytes(0f - value.w, fs);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteBytes(value.x, fs);
					WriteBytes(value.z, fs);
					WriteBytes(value.w, fs);
				}
				else
				{
					WriteBytes(0f - value.x, fs);
					WriteBytes(0f - value.z, fs);
					WriteBytes(0f - value.w, fs);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteBytes(value.x, fs);
					WriteBytes(value.y, fs);
					WriteBytes(value.w, fs);
				}
				else
				{
					WriteBytes(0f - value.x, fs);
					WriteBytes(0f - value.y, fs);
					WriteBytes(0f - value.w, fs);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteBytes(value.x, fs);
					WriteBytes(value.y, fs);
					WriteBytes(value.z, fs);
				}
				else
				{
					WriteBytes(0f - value.x, fs);
					WriteBytes(0f - value.y, fs);
					WriteBytes(0f - value.z, fs);
				}
				break;
			}
		}

		public static Vector3 ReadVector3(ArraySegment<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(ArraySegment<byte> source, ref int index)
		{
			//IL_0124: 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(Mathf.Clamp01(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(Mathf.Clamp01(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(Mathf.Clamp01(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(Mathf.Clamp01(1f - num * num - num2 * num2 - num3 * num3));
				break;
			}
			return new Quaternion(num, num2, num3, num4);
		}

		public static void WriteHalf(Vector3 value, ArraySegment<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, ArraySegment<byte> destination, ref int index)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_016a: 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_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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 void WriteHalf(Vector3 value, ByteBuffer buffer)
		{
			//IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			WriteHalf(value.x, buffer);
			WriteHalf(value.y, buffer);
			WriteHalf(value.z, buffer);
		}

		public static void WriteHalf(Quaternion value, ByteBuffer buffer)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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, buffer);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteHalf(value.y, buffer);
					WriteHalf(value.z, buffer);
					WriteHalf(value.w, buffer);
				}
				else
				{
					WriteHalf(0f - value.y, buffer);
					WriteHalf(0f - value.z, buffer);
					WriteHalf(0f - value.w, buffer);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteHalf(value.x, buffer);
					WriteHalf(value.z, buffer);
					WriteHalf(value.w, buffer);
				}
				else
				{
					WriteHalf(0f - value.x, buffer);
					WriteHalf(0f - value.z, buffer);
					WriteHalf(0f - value.w, buffer);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteHalf(value.x, buffer);
					WriteHalf(value.y, buffer);
					WriteHalf(value.w, buffer);
				}
				else
				{
					WriteHalf(0f - value.x, buffer);
					WriteHalf(0f - value.y, buffer);
					WriteHalf(0f - value.w, buffer);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteHalf(value.x, buffer);
					WriteHalf(value.y, buffer);
					WriteHalf(value.z, buffer);
				}
				else
				{
					WriteHalf(0f - value.x, buffer);
					WriteHalf(0f - value.y, buffer);
					WriteHalf(0f - value.z, buffer);
				}
				break;
			}
		}

		public static void WriteHalf(Vector3 value, FileStream fs)
		{
			//IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			WriteHalf(value.x, fs);
			WriteHalf(value.y, fs);
			WriteHalf(value.z, fs);
		}

		public static void WriteHalf(Quaternion value, FileStream fs)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0024: 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_0036: 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_003f: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			value = ((Quaternion)(ref value)).normalized;
			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, fs);
			switch (b)
			{
			case 0:
				if (value.x >= 0f)
				{
					WriteHalf(value.y, fs);
					WriteHalf(value.z, fs);
					WriteHalf(value.w, fs);
				}
				else
				{
					WriteHalf(0f - value.y, fs);
					WriteHalf(0f - value.z, fs);
					WriteHalf(0f - value.w, fs);
				}
				break;
			case 1:
				if (value.y >= 0f)
				{
					WriteHalf(value.x, fs);
					WriteHalf(value.z, fs);
					WriteHalf(value.w, fs);
				}
				else
				{
					WriteHalf(0f - value.x, fs);
					WriteHalf(0f - value.z, fs);
					WriteHalf(0f - value.w, fs);
				}
				break;
			case 2:
				if (value.z >= 0f)
				{
					WriteHalf(value.x, fs);
					WriteHalf(value.y, fs);
					WriteHalf(value.w, fs);
				}
				else
				{
					WriteHalf(0f - value.x, fs);
					WriteHalf(0f - value.y, fs);
					WriteHalf(0f - value.w, fs);
				}
				break;
			case 3:
				if (value.w >= 0f)
				{
					WriteHalf(value.x, fs);
					WriteHalf(value.y, fs);
					WriteHalf(value.z, fs);
				}
				else
				{
					WriteHalf(0f - value.x, fs);
					WriteHalf(0f - value.y, fs);
					WriteHalf(0f - value.z, fs);
				}
				break;
			}
		}

		public static Vector3 ReadHalfVector3(ArraySegment<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(ArraySegment<byte> source, ref int index)
		{
			//IL_0124: 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(Mathf.Clamp01(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(Mathf.Clamp01(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(Mathf.Clamp01(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(Mathf.Clamp01(1f - num * num - num2 * num2 - num3 * num3));
				break;
			}
			return new Quaternion(num, num2, num3, num4);
		}
	}
	public static class Replay
	{
		public static Action? OnExpeditionEnd;

		public static Action? OnExpeditionStart;

		public static Action? OnElevatorStop;

		public static Action? OnGameplayStart;

		public static Action? OnHeaderCompletion;

		public static Action? OnTick;

		public static float tickRate => SnapshotManager.GetInstance().tickRate;

		public static bool Ready => SnapshotManager.Ready;

		public static bool Active => SnapshotManager.Active;

		private static void RegisterMethods(Type t)
		{
			foreach (MethodInfo item in from m in t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.GetCustomAttribute<ReplayReset>() != null || m.GetCustomAttribute<ReplayInit>() != null || m.GetCustomAttribute<ReplayTick>() != null || m.GetCustomAttribute<ReplayOnHeaderCompletion>() != null || m.GetCustomAttribute<ReplayOnGameplayStart>() != null || m.GetCustomAttribute<ReplayOnElevatorStop>() != null
				select m)
			{
				if (item.IsStatic)
				{
					try
					{
						string value = "ReplayReset";
						if (item.GetCustomAttribute<ReplayInit>() != null)
						{
							value = "ReplayInit";
							OnExpeditionStart = (Action)Delegate.Combine(OnExpeditionStart, (Action)item.CreateDelegate(typeof(Action)));
						}
						else if (item.GetCustomAttribute<ReplayOnHeaderCompletion>() != null)
						{
							value = "ReplayOnHeaderCompletion";
							OnHeaderCompletion = (Action)Delegate.Combine(OnHeaderCompletion, (Action)item.CreateDelegate(typeof(Action)));
						}
						else if (item.GetCustomAttribute<ReplayOnGameplayStart>() != null)
						{
							value = "ReplayOnGameplayStart";
							OnGameplayStart = (Action)Delegate.Combine(OnGameplayStart, (Action)item.CreateDelegate(typeof(Action)));
						}
						else if (item.GetCustomAttribute<ReplayTick>() != null)
						{
							value = "ReplayTick";
							OnTick = (Action)Delegate.Combine(OnTick, (Action)item.CreateDelegate(typeof(Action)));
						}
						else if (item.GetCustomAttribute<ReplayOnElevatorStop>() != null)
						{
							value = "ReplayOnElevatorStop";
							OnElevatorStop = (Action)Delegate.Combine(OnElevatorStop, (Action)item.CreateDelegate(typeof(Action)));
						}
						else
						{
							OnExpeditionEnd = (Action)Delegate.Combine(OnExpeditionEnd, (Action)item.CreateDelegate(typeof(Action)));
						}
						APILogger.Debug($"Registered {value}: '{t.FullName}.{item.Name}'");
					}
					catch (Exception value2)
					{
						APILogger.Error($"Failed to register method: {value2}");
					}
				}
				else
				{
					APILogger.Error($"Replay attributes can only be applied to static methods. '{item}' is not static.");
				}
			}
		}

		public static void RegisterAll()
		{
			Type[] types = Assembly.GetCallingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttribute<ReplayData>() != null)
				{
					RegisterType(type);
				}
				RegisterMethods(type);
			}
		}

		public static void RegisterAll(Type type)
		{
			Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (Type type2 in nestedTypes)
			{
				if (type.GetCustomAttribute<ReplayData>() != null)
				{
					RegisterType(type2);
				}
				RegisterMethods(type2);
				RegisterAll(type2);
			}
		}

		public static void RegisterType(Type type)
		{
			ReplayData customAttribute = type.GetCustomAttribute<ReplayData>();
			if (customAttribute == null)
			{
				throw new ReplayTypeNotCompatible($"Type '{type}' is not a valid ReplayData type.");
			}
			SnapshotManager.types.RegisterType(customAttribute, type);
		}

		[HideFromIl2Cpp]
		public static void Configure<T>(int tickRate = 1, int max = int.MaxValue) where T : ReplayDynamic
		{
			SnapshotManager.GetInstance().Configure<T>(tickRate, max);
		}

		[HideFromIl2Cpp]
		public static bool Trigger(ReplayEvent e)
		{
			return SnapshotManager.GetInstance().Trigger(e);
		}

		[HideFromIl2Cpp]
		public static void Trigger(ReplayHeader header)
		{
			SnapshotManager.GetInstance().Trigger(header);
		}

		[HideFromIl2Cpp]
		public static bool Has(ReplayDynamic dynamic)
		{
			return SnapshotManager.GetInstance().Has(dynamic);
		}

		[HideFromIl2Cpp]
		public static bool Has<T>(int id) where T : ReplayDynamic
		{
			return SnapshotManager.GetInstance().Has(typeof(T), id);
		}

		[HideFromIl2Cpp]
		public static T Get<T>(int id) where T : ReplayDynamic
		{
			return (T)SnapshotManager.GetInstance().Get(typeof(T), id);
		}

		[HideFromIl2Cpp]
		public static bool TryGet<T>(int id, [NotNullWhen(true)] out T dynamic) where T : ReplayDynamic
		{
			if (Has<T>(id))
			{
				dynamic = Get<T>(id);
				return true;
			}
			dynamic = null;
			return false;
		}

		[HideFromIl2Cpp]
		public static void Clear<T>() where T : ReplayDynamic
		{
			SnapshotManager.GetInstance().Clear(typeof(T));
		}

		[HideFromIl2Cpp]
		public static void Spawn(ReplayDynamic dynamic, bool errorOnDuplicate = true)
		{
			SnapshotManager.GetInstance().Spawn(dynamic, errorOnDuplicate);
		}

		[HideFromIl2Cpp]
		public static void Despawn(ReplayDynamic dynamic, bool errorOnNotFound = true)
		{
			SnapshotManager.GetInstance().Despawn(dynamic, errorOnNotFound);
		}

		[HideFromIl2Cpp]
		public static bool TryDespawn<T>(int id) where T : ReplayDynamic
		{
			if (Has<T>(id))
			{
				Despawn(Get<T>(id));
				return true;
			}
			return false;
		}
	}
	public static class Utils
	{
		public const BindingFlags AnyBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		public static string RemoveInvalidCharacters(string content, char replace = '_', bool isFullPath = true)
		{
			if (string.IsNullOrEmpty(content))
			{
				return content;
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			int num = content.IndexOfAny(invalidFileNameChars);
			if (num >= 0)
			{
				StringBuilder stringBuilder = new StringBuilder(content);
				while (num >= 0)
				{
					if (!isFullPath || (stringBuilder[num] != ':' && stringBuilder[num] != '\\' && stringBuilder[num] != '/'))
					{
						stringBuilder[num] = replace;
					}
					num = content.IndexOfAny(invalidFileNameChars, num + 1);
				}
				return stringBuilder.ToString();
			}
			return content;
		}
	}
}
namespace ReplayRecorder.SNetUtils
{
	public class SNetUtils
	{
		internal static ushort currentRepKey;

		internal static int currentPacketIndex;

		internal static SNet_Player? currentSender;

		public static bool TryGetSender(SNet_Packet packet, [MaybeNullWhen(false)] out SNet_Player player)
		{
			if ((Object)(object)currentSender != (Object)null && packet.Replicator.Key == currentRepKey && packet.Index == currentPacketIndex)
			{
				player = currentSender;
				return true;
			}
			player = null;
			return false;
		}
	}
	[HarmonyPatch]
	internal class Patches
	{
		[HarmonyPatch(typeof(SNet_Replication), "RecieveBytes")]
		[HarmonyWrapSafe]
		[HarmonyPriority(700)]
		[HarmonyPrefix]
		private static void Prefix_RecieveBytes(Il2CppStructArray<byte> bytes, uint size, ulong messagerID)
		{
			IReplicator val = default(IReplicator);
			int currentPacketIndex = default(int);
			SNet_Player currentSender = default(SNet_Player);
			if (SNet.Replication.TryGetReplicator(bytes, ref val, ref currentPacketIndex) && SNet.Core.TryGetPlayer(messagerID, ref currentSender, false))
			{
				SNetUtils.currentSender = currentSender;
				SNetUtils.currentRepKey = val.Key;
				SNetUtils.currentPacketIndex = currentPacketIndex;
			}
		}

		[HarmonyPatch(typeof(SNet_Replication), "RecieveBytes")]
		[HarmonyWrapSafe]
		[HarmonyPriority(100)]
		[HarmonyPostfix]
		private static void Postfix_RecieveBytes(Il2CppStructArray<byte> bytes, uint size, ulong messagerID)
		{
			SNetUtils.currentSender = null;
			SNetUtils.currentRepKey = 0;
			SNetUtils.currentPacketIndex = 0;
		}
	}
}
namespace ReplayRecorder.Snapshot
{
	internal class SnapshotInstance : MonoBehaviour
	{
		private class EventWrapper
		{
			private ushort id;

			private ReplayEvent eventObj;

			internal ByteBuffer? eventBuffer;

			internal long now;

			public string? Debug => eventObj.Debug;

			public EventWrapper(long now, ReplayEvent e, ByteBuffer buffer)
			{
				this.now = now;
				eventObj = e;
				eventBuffer = buffer;
				e.Write(eventBuffer);
				id = SnapshotManager.types[e.GetType()];
			}

			~EventWrapper()
			{
				Dispose();
			}

			public void Dispose()
			{
				if (eventBuffer != null)
				{
					if ((Object)(object)SnapshotManager.instance != (Object)null)
					{
						SnapshotManager.instance.pool.Release(eventBuffer);
					}
					eventBuffer = null;
				}
			}

			public void Write(ByteBuffer buffer)
			{
				if (eventBuffer == null)
				{
					throw new Exception("Memory Buffer was disposed too early...");
				}
				if (ConfigManager.Debug && ConfigManager.DebugDynamics)
				{
					APILogger.Debug($"[Event: {eventObj.GetType().FullName}({SnapshotManager.types[eventObj.GetType()]})]{((eventObj.Debug != null) ? (": " + eventObj.Debug) : "")}");
				}
				BitHelper.WriteBytes(id, buffer);
				BitHelper.WriteBytes(eventBuffer.Array, buffer, includeCount: false);
			}
		}

		private class DynamicCollection : IEnumerable<ReplayDynamic>, IEnumerable
		{
			public int max = int.MaxValue;

			private int cycle;

			public int tickRate = 1;

			private int tick;

			private List<ReplayDynamic> _dynamics = new List<ReplayDynamic>();

			private List<ReplayDynamic> dynamics = new List<ReplayDynamic>();

			private Dictionary<int, ReplayDynamic> mapOfDynamics = new Dictionary<int, ReplayDynamic>();

			private SnapshotInstance instance;

			private bool handleRemoval;

			public Type Type { get; private set; }

			public ushort Id { get; private set; }

			public bool Tick
			{
				get
				{
					tick = (tick + 1) % Mathf.Clamp(tickRate, 1, int.MaxValue);
					return tick == 0;
				}
			}

			public DynamicCollection(Type type, SnapshotInstance instance)
			{
				this.instance = instance;
				if (!SnapshotManager.types.Contains(type))
				{
					throw new ReplayTypeDoesNotExist("Could not create DynamicCollection of type '" + type.FullName + "'.");
				}
				Type = type;
				Id = SnapshotManager.types[type];
			}

			public IEnumerator<ReplayDynamic> GetEnumerator()
			{
				foreach (ReplayDynamic value in mapOfDynamics.Values)
				{
					yield return value;
				}
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			[HideFromIl2Cpp]
			public bool Has(ReplayDynamic dynamic)
			{
				Type type = dynamic.GetType();
				if (!Type.IsAssignableFrom(type))
				{
					throw new ReplayIncompatibleType($"Cannot add '{type.FullName}' to DynamicCollection of type '{Type.FullName}'.");
				}
				return mapOfDynamics.ContainsKey(dynamic.id);
			}

			[HideFromIl2Cpp]
			public bool Has(int id)
			{
				return mapOfDynamics.ContainsKey(id);
			}

			[HideFromIl2Cpp]
			public ReplayDynamic Get(int id)
			{
				if (!mapOfDynamics.ContainsKey(id))
				{
					throw new ReplayDynamicDoesNotExist($"Cannot get dynamic of id '{id}'. Type: '{Type.FullName}'.");
				}
				return mapOfDynamics[id];
			}

			[HideFromIl2Cpp]
			public void Add(ReplayDynamic dynamic, bool errorOnDuplicate = true)
			{
				Type type = dynamic.GetType();
				if (!Type.IsAssignableFrom(type))
				{
					throw new ReplayIncompatibleType($"Cannot add '{type.FullName}' to DynamicCollection of type '{Type.FullName}'.");
				}
				if (mapOfDynamics.ContainsKey(dynamic.id))
				{
					if (errorOnDuplicate)
					{
						throw new ReplayDynamicAlreadyExists($"Dynamic [{dynamic.id}] already exists in DynamicCollection of type '{Type.FullName}'.");
					}
				}
				else
				{
					dynamics.Add(dynamic);
					mapOfDynamics.Add(dynamic.id, dynamic);
				}
			}

			[HideFromIl2Cpp]
			public void Remove(int id, bool errorOnNotFound = true)
			{
				if (!mapOfDynamics.ContainsKey(id))
				{
					if (errorOnNotFound)
					{
						throw new ReplayDynamicDoesNotExist($"Dynamic [{id}] does not exist in DynamicCollection of type '{Type.FullName}'.");
					}
				}
				else
				{
					handleRemoval = true;
					mapOfDynamics[id].remove = true;
					mapOfDynamics.Remove(id);
				}
			}

			[HideFromIl2Cpp]
			public void Remove(ReplayDynamic dynamic)
			{
				Type type = dynamic.GetType();
				if (!Type.IsAssignableFrom(type))
				{
					throw new ReplayIncompatibleType($"Cannot remove dynamic of type '{type.FullName}' from DynamicCollection of type '{Type.FullName}'.");
				}
				Remove(dynamic.id);
			}

			public int Write(ByteBuffer buffer)
			{
				if (tick != 0)
				{
					return 0;
				}
				int count = buffer.count;
				int num = 0;
				BitHelper.WriteBytes(Id, buffer);
				int index = buffer.count;
				buffer.Reserve(4, increment: true);
				bool flag = handleRemoval;
				handleRemoval = false;
				if (flag)
				{
					_dynamics.Clear();
				}
				for (int i = 0; i < dynamics.Count; i++)
				{
					cycle %= dynamics.Count;
					ReplayDynamic dynamic = dynamics[cycle++];
					bool active = dynamic.Active;
					if (num < max && (!dynamic.remove || tickRate == 1) && active && dynamic.IsDirty)
					{
						if (ConfigManager.Debug && ConfigManager.DebugDynamics)
						{
							APILogger.Debug($"[Dynamic: {dynamic.GetType().FullName}({SnapshotManager.types[dynamic.GetType()]})]{((dynamic.Debug != null) ? (": " + dynamic.Debug) : "")}");
						}
						int count2 = buffer.count;
						try
						{
							dynamic._Write(buffer);
							dynamic.Write(buffer);
							num++;
						}
						catch (Exception ex)
						{
							buffer.count = count2;
							if (!dynamic.remove)
							{
								instance.Despawn(dynamic);
								APILogger.Warn($"[DynamicCollection] Despawning due to Error {Type} {dynamic.id}");
								APILogger.Error($"Unexpected error occured whilst trying to write Dynamic[{Type}]({dynamic.id}) at [{instance.Now}ms]:\n{ex}\n{ex.StackTrace}");
							}
						}
					}
					if (!active && !dynamic.remove)
					{
						if (dynamics.Any((ReplayDynamic d) => (object)d != dynamic && d == dynamic && d.Active && !d.remove))
						{
							dynamic.remove = true;
							handleRemoval = true;
							APILogger.Warn($"[DynamicCollection] Silent Removal {Type} {dynamic.id}");
						}
						else
						{
							instance.Despawn(dynamic);
							APILogger.Warn($"[DynamicCollection] Forced Despawn {Type} {dynamic.id}");
						}
					}
					if (flag && !dynamic.remove)
					{
						_dynamics.Add(dynamic);
					}
				}
				if (flag)
				{
					List<ReplayDynamic> list = dynamics;
					dynamics = _dynamics;
					_dynamics = list;
				}
				if (num == 0)
				{
					buffer.count = count;
					return 0;
				}
				BitHelper.WriteBytes(num, buffer._array, ref index);
				if (ConfigManager.Debug)
				{
					APILogger.Debug($"[DynamicCollection: {Type.FullName}({SnapshotManager.types[Type]})]: {num} dynamics serialized.");
				}
				return num;
			}
		}

		private class DeltaState
		{
			internal List<EventWrapper> events = new List<EventWrapper>();

			internal Dictionary<Type, DynamicCollection> dynamics = new Dictionary<Type, DynamicCollection>();

			internal void Clear()
			{
				events.Clear();
				dynamics.Clear();
			}

			internal bool Write(long now, ByteBuffer bs)
			{
				BitHelper.WriteBytes((uint)now, bs);
				BitHelper.WriteBytes(events.Count, bs);
				for (int i = 0; i < events.Count; i++)
				{
					EventWrapper eventWrapper = events[i];
					long num = now - eventWrapper.now;
					if (num < 0)
					{
						num = 0L;
					}
					if (num > 65535)
					{
						APILogger.Warn($"Delta time of {num}ms is invalid. Max is {65535}ms.");
						num = 65535L;
					}
					BitHelper.WriteBytes((ushort)num, bs);
					eventWrapper.Write(bs);
					eventWrapper.Dispose();
				}
				bool flag = events.Count != 0;
				APILogger.Debug($"[Events] {events.Count} events written.");
				events.Clear();
				int num2 = 0;
				int index = bs.count;
				bs.Reserve(2, increment: true);
				foreach (DynamicCollection value in dynamics.Values)
				{
					try
					{
						if (value.Write(bs) > 0)
						{
							num2++;
						}
					}
					catch (Exception ex)
					{
						APILogger.Error($"Unexpected error occured whilst trying to write DynamicCollection[{value.Type}] at [{now}ms]:\n{ex}\n{ex.StackTrace}");
					}
				}
				BitHelper.WriteBytes((ushort)num2, bs._array, ref index);
				if (ConfigManager.Debug && ConfigManager.DebugDynamics)
				{
					APILogger.Debug($"Flushed {num2} dynamic collections.");
				}
				if (!flag)
				{
					return num2 != 0;
				}
				return true;
			}
		}

		private FileStream? fs;

		private int byteOffset;

		private DeltaState state = new DeltaState();

		private ByteBuffer buffer = new ByteBuffer();

		private ByteBuffer _buffer = new ByteBuffer();

		internal BufferPool pool = new BufferPool();

		private Task? writeTask;

		private long start;

		private bool completedHeader;

		private HashSet<Type> unwrittenHeaders = new HashSet<Type>();

		internal string fullpath = "replay.gtfo";

		internal string filename = "replay.gtfo";

		private Stopwatch stopwatch = new Stopwatch();

		private int bufferShrinkTick;

		private int peakInUse;

		internal float tickTime = 1f;

		internal float waitForWrite = 1f;

		private HashSet<ulong> alertedPlayers = new HashSet<ulong>();

		public float tickRate = 0.05f;

		private float timer;

		public bool Ready
		{
			get
			{
				if (Active)
				{
					return completedHeader;
				}
				return false;
			}
		}

		public bool Active => fs != null;

		private long Now => Raudy.Now - start;

		internal void Init()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (fs != null)
			{
				throw new ReplaySnapshotAlreadyInitialized();
			}
			start = Raudy.Now;
			pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
			RundownDataBlock block = GameDataBlockBase<RundownDataBlock>.GetBlock(Global.RundownIdToLoad);
			ExpeditionInTierData expeditionData = block.GetExpeditionData(activeExpeditionData.tier, activeExpeditionData.expeditionIndex);
			string shortName = expeditionData.GetShortName(activeExpeditionData.expeditionIndex);
			string publicName = expeditionData.Descriptive.PublicName;
			DateTime now = DateTime.Now;
			filename = string.Format(ConfigManager.ReplayFileName, shortName, now, publicName);
			string text = ConfigManager.ReplayFolder;
			filename = Utils.RemoveInvalidCharacters(filename, '_', isFullPath: false);
			if (!Directory.Exists(text))
			{
				text = "./";
			}
			string text2;
			if (ConfigManager.SeparateByRundown)
			{
				text2 = Path.Combine(text, Utils.RemoveInvalidCharacters(((GameDataBlockBase<RundownDataBlock>)(object)block).name));
				fullpath = Path.Combine(text2, filename);
			}
			else
			{
				text2 = Utils.RemoveInvalidCharacters(text);
				fullpath = Path.Combine(text2, filename);
			}
			APILogger.Warn("REPLAY LOCATION: " + fullpath);
			try
			{
				Directory.CreateDirectory(text2);
				fs = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.Read);
			}
			catch (Exception ex)
			{
				APILogger.Error("Failed to create filestream, falling back to 'replay.gtfo': " + ex.Message);
				fs = new FileStream("replay.gtfo", FileMode.Create, FileAccess.Write, FileShare.Read);
			}
			alertedPlayers.Clear();
			alertedPlayers.Add(PlayerManager.GetLocalPlayerAgent().Owner.Lookup);
			pool = new BufferPool();
			byteOffset = 0;
			buffer.Clear();
			SnapshotManager.types.Write(buffer);
			foreach (Type header in SnapshotManager.types.headers)
			{
				unwrittenHeaders.Add(header);
			}
			state.Clear();
			foreach (Type dynamic in SnapshotManager.types.dynamics)
			{
				state.dynamics.Add(dynamic, new DynamicCollection(dynamic, this));
			}
		}

		[HideFromIl2Cpp]
		internal void Trigger(ReplayHeader header)
		{
			if (fs == null)
			{
				throw new ReplaySnapshotNotInitialized();
			}
			Type type = header.GetType();
			if (completedHeader || unwrittenHeaders.Count == 0)
			{
				completedHeader = true;
				throw new ReplayAllHeadersAlreadyWritten("Cannot write header '" + type.FullName + "' as all headers have been written already.");
			}
			unwrittenHeaders.Remove(type);
			ushort value = SnapshotManager.types[type];
			APILogger.Debug($"[Header: {type.FullName}({value})]{((header.Debug != null) ? (": " + header.Debug) : "")}");
			BitHelper.WriteBytes(value, buffer);
			header.Write(buffer);
			if (unwrittenHeaders.Count == 0)
			{
				completedHeader = true;
				OnHeaderComplete();
			}
		}

		[HideFromIl2Cpp]
		private void SendBufferOverNetwork(ByteBuffer buffer)
		{
			if (Plugin.acknowledged.Count > 0)
			{
				ByteBuffer packet = pool.Checkout();
				BitHelper.WriteBytes(14 + buffer.count, packet);
				BitHelper.WriteBytes((ushort)2, packet);
				BitHelper.WriteBytes(byteOffset, packet);
				BitHelper.WriteBytes(4 + buffer.count, packet);
				BitHelper.WriteBytes(buffer.Array, packet);
				Send(packet);
			}
			byteOffset += 4 + buffer.count;
		}

		private void OnHeaderComplete()
		{
			if (fs == null)
			{
				throw new ReplaySnapshotNotInitialized();
			}
			EndOfHeader endOfHeader = new EndOfHeader();
			APILogger.Debug($"[Header: {typeof(EndOfHeader).FullName}({SnapshotManager.types[typeof(EndOfHeader)]})]{((endOfHeader.Debug != null) ? (": " + endOfHeader.Debug) : "")}");
			endOfHeader.Write(buffer);
			APILogger.Debug($"Acknowledged Clients: {Plugin.acknowledged.Count}");
			SendBufferOverNetwork(buffer);
			buffer.Flush(fs);
			buffer.Shrink();
			Replay.OnHeaderCompletion?.Invoke();
		}

		[HideFromIl2Cpp]
		internal void Configure<T>(int tickRate, int max) where T : ReplayDynamic
		{
			Type typeFromHandle = typeof(T);
			if (!state.dynamics.ContainsKey(typeFromHandle))
			{
				throw new ReplayTypeDoesNotExist("Type '" + typeFromHandle.FullName + "' does not exist.");
			}
			state.dynamics[typeFromHandle].max = max;
			state.dynamics[typeFromHandle].tickRate = tickRate;
		}

		[HideFromIl2Cpp]
		internal bool Trigger(ReplayEvent e)
		{
			try
			{
				EventWrapper item = new EventWrapper(Now, e, pool.Checkout());
				state.events.Add(item);
				return true;
			}
			catch (Exception ex)
			{
				APILogger.Error($"Unexpected error occured whilst trying to write Event[{e.GetType()}] at [{Raudy.Now}ms]:\n{ex}\n{ex.StackTrace}");
			}
			return false;
		}

		[HideFromIl2Cpp]
		internal bool Has(ReplayDynamic dynamic)
		{
			Type type = dynamic.GetType();
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			return state.dynamics[type].Has(dynamic);
		}

		[HideFromIl2Cpp]
		internal bool Has(Type type, int id)
		{
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			return state.dynamics[type].Has(id);
		}

		[HideFromIl2Cpp]
		internal ReplayDynamic Get(Type type, int id)
		{
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			return state.dynamics[type].Get(id);
		}

		[HideFromIl2Cpp]
		internal void Clear(Type type)
		{
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			foreach (ReplayDynamic item in state.dynamics[type])
			{
				Despawn(item);
			}
		}

		[HideFromIl2Cpp]
		internal void Spawn(ReplayDynamic dynamic, bool errorOnDuplicate = true)
		{
			Type type = dynamic.GetType();
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			if (!Trigger(new ReplaySpawn(dynamic)))
			{
				APILogger.Error($"Unable to spawn '{type}' as spawn event failed.");
			}
			else
			{
				state.dynamics[type].Add(dynamic, errorOnDuplicate);
			}
		}

		[HideFromIl2Cpp]
		internal void Despawn(ReplayDynamic dynamic, bool errorOnNotFound = true)
		{
			Type type = dynamic.GetType();
			if (!state.dynamics.ContainsKey(type))
			{
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
			if (!Trigger(new ReplayDespawn(dynamic)))
			{
				APILogger.Error($"Unable to despawn '{type}' as despawn event failed.");
			}
			else
			{
				state.dynamics[type].Remove(dynamic.id, errorOnNotFound);
			}
		}

		[HideFromIl2Cpp]
		private async Task Send(ByteBuffer packet)
		{
			foreach (EndPoint item in Plugin.acknowledged)
			{
				if (Plugin.server.Connections.Contains(item))
				{
					await Plugin.server.RawSendTo(packet.Array, item);
				}
			}
			pool.Release(packet);
		}

		private void Tick()
		{
			if (pool.InUse > peakInUse)
			{
				peakInUse = pool.InUse;
			}
			if (++bufferShrinkTick > 100)
			{
				bufferShrinkTick = 0;
				pool.Shrink(Mathf.Max(50, peakInUse));
				peakInUse = 0;
			}
			stopwatch.Restart();
			if (fs == null)
			{
				throw new ReplaySnapshotNotInitialized();
			}
			Replay.OnTick?.Invoke();
			long now = Now;
			if (now > uint.MaxValue)
			{
				Dispose();
				throw new ReplayInvalidTimestamp($"ReplayRecorder does not support replays longer than {-1}ms.");
			}
			buffer.Clear();
			bool flag;
			try
			{
				flag = state.Write(now, buffer);
			}
			catch (Exception ex)
			{
				flag = false;
				APILogger.Error($"Unexpected error occured whilst trying to write tick at [{now}ms]:\n{ex}\n{ex.StackTrace}");
			}
			if (flag)
			{
				SendBufferOverNetwork(buffer);
				float num = stopwatch.ElapsedMilliseconds;
				if (writeTask != null)
				{
					writeTask.Wait();
				}
				waitForWrite = (float)stopwatch.ElapsedMilliseconds - num;
				writeTask = buffer.AsyncFlush(fs);
				ByteBuffer byteBuffer = _buffer;
				_buffer = buffer;
				buffer = byteBuffer;
			}
			stopwatch.Stop();
			tickTime = 0.9f * tickTime + 0.100000024f * (float)stopwatch.ElapsedMilliseconds;
		}

		internal void Dispose()
		{
			APILogger.Debug("Ending Replay...");
			if (fs != null)
			{
				fs.Flush();
				fs.Dispose();
				fs = null;
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private void Update()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			if (fs == null || !completedHeader)
			{
				return;
			}
			DRAMA_State currentStateEnum = DramaManager.CurrentStateEnum;
			float num = ((currentStateEnum - 5 > 3) ? 0.1f : 0.05f);
			if (tickRate != num)
			{
				timer = 0f;
				tickRate = num;
			}
			timer += Time.deltaTime;
			if (!(timer > tickRate))
			{
				return;
			}
			timer = 0f;
			if (Plugin.acknowledged.Count > 0 && PlayerManager.PlayerAgentsInLevel.Count > 1)
			{
				bool flag = true;
				Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
				while (enumerator.MoveNext())
				{
					PlayerAgent current = enumerator.Current;
					if (!alertedPlayers.Contains(current.Owner.Lookup) && current.Owner.IsInGame)
					{
						flag = false;
						break;
					}
				}
				if (!flag)
				{
					enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
					while (enumerator.MoveNext())
					{
						PlayerAgent current2 = enumerator.Current;
						if (!alertedPlayers.Contains(current2.Owner.Lookup) && current2.Owner.IsInGame)
						{
							alertedPlayers.Add(current2.Owner.Lookup);
						}
					}
					string text = "GTFOReplay Live View is in use. This allows the spectating user to see all item and enemy locations which may be considered cheating.";
					while (text.Length > 50)
					{
						PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text.Substring(0, 50).Trim(), (PlayerAgent)null);
						text = text.Substring(50).Trim();
					}
					PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text, (PlayerAgent)null);
				}
			}
			Tick();
		}
	}
	internal static class SnapshotManager
	{
		internal static SnapshotTypeManager types = new SnapshotTypeManager();

		internal static SnapshotInstance? instance;

		internal static bool Ready
		{
			get
			{
				if ((Object)(object)instance != (Object)null)
				{
					return instance.Ready;
				}
				return false;
			}
		}

		internal static bool Active
		{
			get
			{
				if ((Object)(object)instance != (Object)null)
				{
					return instance.Active;
				}
				return false;
			}
		}

		internal static void OnElevatorStart()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance == (Object)null)
			{
				instance = new GameObject().AddComponent<SnapshotInstance>();
				instance.Init();
				return;
			}
			throw new ReplaySnapshotAlreadyInitialized();
		}

		internal static SnapshotInstance GetInstance()
		{
			if ((Object)(object)instance == (Object)null)
			{
				throw new ReplaySnapshotNotInitialized();
			}
			return instance;
		}

		internal static void OnExpeditionEnd()
		{
			if ((Object)(object)instance != (Object)null)
			{
				instance.Dispose();
				instance = null;
				Replay.OnExpeditionEnd?.Invoke();
			}
		}
	}
}
namespace ReplayRecorder.Snapshot.Types
{
	internal class SnapshotTypeManager
	{
		public readonly HashSet<Type> dynamics = new HashSet<Type>();

		public readonly HashSet<Type> events = new HashSet<Type>();

		public readonly HashSet<Type> headers = new HashSet<Type>();

		private Dictionary<string, Type> typenameMap = new Dictionary<string, Type>();

		private Dictionary<Type, ushort> typeMap = new Dictionary<Type, ushort>();

		private Dictionary<Type, string> versionMap = new Dictionary<Type, string>();

		private ushort staticType;

		public ushort this[Type type]
		{
			get
			{
				if (typeMap.ContainsKey(type))
				{
					return typeMap[type];
				}
				throw new ReplayTypeDoesNotExist("Type '" + type.FullName + "' does not exist.");
			}
		}

		public ushort this[string typename]
		{
			get
			{
				if (typenameMap.ContainsKey(typename))
				{
					return typeMap[typenameMap[typename]];
				}
				throw new ReplayTypeDoesNotExist("Type '" + typename + "' does not exist.");
			}
		}

		public bool Contains(Type type)
		{
			return typeMap.ContainsKey(type);
		}

		public void RegisterType(ReplayData data, Type type)
		{
			if (data.Typename == string.Empty)
			{
				throw new ReplayEmptyTypename("Typename cannot be a blank string.");
			}
			if (typenameMap.ContainsKey(data.Typename))
			{
				throw new ReplayDuplicateTypeName("Typename '" + data.Typename + "' already exists.");
			}
			if (typeMap.ContainsKey(type))
			{
				throw new ReplayDuplicateType("Type '" + type.FullName + "' already exists.");
			}
			if (staticType == ushort.MaxValue)
			{
				throw new ReplayTypeOverflow("Could not assign type '" + data.Typename + "' as there are no more indicies that can be assigned.");
			}
			string value;
			if (typeof(ReplayDynamic).IsAssignableFrom(type))
			{
				value = "Dynamic";
				dynamics.Add(type);
			}
			else if (typeof(ReplayEvent).IsAssignableFrom(type))
			{
				value = "Event";
				events.Add(type);
			}
			else
			{
				if (!typeof(ReplayHeader).IsAssignableFrom(type))
				{
					throw new ReplayIncompatibleType("Type '" + type.FullName + "' is not a Dynamic, Event or Header.");
				}
				value = "Header";
				headers.Add(type);
			}
			ushort value2 = staticType++;
			typenameMap.Add(data.Typename, type);
			typeMap.Add(type, value2);
			versionMap.Add(type, data.Version);
			APILogger.Debug($"Registered {value}: '{data.Typename}' => {type.FullName}[{value2}]");
		}

		public void Write(ByteBuffer buffer)
		{
			StringBuilder stringBuilder = new StringBuilder();
			BitHelper.WriteBytes("0.0.1", buffer);
			BitHelper.WriteBytes((ushort)typenameMap.Count, buffer);
			StringBuilder stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder3 = stringBuilder2;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(12, 1, stringBuilder2);
			handler.AppendLiteral("\n\tTypeMap[");
			handler.AppendFormatted(typenameMap.Count);
			handler.AppendLiteral("]:");
			stringBuilder3.AppendLine(ref handler);
			foreach (KeyValuePair<string, Type> item in typenameMap)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(10, 4, stringBuilder2);
				handler.AppendLiteral("\t");
				handler.AppendFormatted(typeMap[item.Value]);
				handler.AppendLiteral(" => ");
				handler.AppendFormatted(item.Key);
				handler.AppendLiteral("(");
				handler.AppendFormatted(versionMap[item.Value]);
				handler.AppendLiteral(") [");
				handler.AppendFormatted(item.Value.FullName);
				handler.AppendLiteral("]");
				stringBuilder4.AppendLine(ref handler);
				BitHelper.WriteBytes(typeMap[item.Value], buffer);
				BitHelper.WriteBytes(item.Key, buffer);
				BitHelper.WriteBytes(versionMap[item.Value], buffer);
			}
			APILogger.Debug(stringBuilder.ToString());
		}
	}
}
namespace ReplayRecorder.Snapshot.Exceptions
{
	public class ReplaySnapshotAlreadyInitialized : Exception
	{
		public ReplaySnapshotAlreadyInitialized()
			: base("Snapshot has already been initialized.")
		{
		}
	}
	public class ReplaySnapshotNotInitialized : Exception
	{
		public ReplaySnapshotNotInitialized()
			: base("Snapshot has not been initialized yet.")
		{
		}
	}
	public class ReplayAllHeadersAlreadyWritten : Exception
	{
		public ReplayAllHeadersAlreadyWritten(string message)
			: base(message)
		{
		}
	}
	public class ReplayHeaderAlreadyWritten : Exception
	{
		public ReplayHeaderAlreadyWritten(string message)
			: base(message)
		{
		}
	}
	public class ReplayDynamicDoesNotExist : Exception
	{
		public ReplayDynamicDoesNotExist(string message)
			: base(message)
		{
		}
	}
	public class ReplayDynamicAlreadyExists : Exception
	{
		public ReplayDynamicAlreadyExists(string message)
			: base(message)
		{
		}
	}
	public class ReplayInvalidDeltaTime : Exception
	{
		public ReplayInvalidDeltaTime(string message)
			: base(message)
		{
		}
	}
	public class ReplayInvalidTimestamp : Exception
	{
		public ReplayInvalidTimestamp(string message)
			: base(message)
		{
		}
	}
	public class ReplayEmptyTypename : Exception
	{
		public ReplayEmptyTypename(string message)
			: base(message)
		{
		}
	}
	public class ReplayIncompatibleType : Exception
	{
		public ReplayIncompatibleType(string message)
			: base(message)
		{
		}
	}
	public class ReplayTypeDoesNotExist : Exception
	{
		public ReplayTypeDoesNotExist(string message)
			: base(message)
		{
		}
	}
	public class ReplayDuplicateTypeName : Exception
	{
		public ReplayDuplicateTypeName(string message)
			: base(message)
		{
		}
	}
	public class ReplayDuplicateType : Exception
	{
		public ReplayDuplicateType(string message)
			: base(message)
		{
		}
	}
	public class ReplayTypeOverflow : Exception
	{
		public ReplayTypeOverflow(string message)
			: base(message)
		{
		}
	}
}
namespace ReplayRecorder.BepInEx
{
	public static class Module
	{
		public const string GUID = "randomuserhi.ReplayRecorder";

		public const string Name = "ReplayRecorder";

		public const string Version = "0.0.1";
	}
	public static class ConfigManager
	{
		public static ConfigFile configFile;

		private static ConfigEntry<bool> debug;

		private static ConfigEntry<bool> performanceDebug;

		private static ConfigEntry<bool> debugDynamics;

		private static ConfigEntry<string> replayFolder;

		private static ConfigEntry<string> replayFilename;

		private static ConfigEntry<bool> separateByRundown;

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

		public static bool PerformanceDebug
		{
			get
			{
				return performanceDebug.Value;
			}
			set
			{
				performanceDebug.Value = value;
			}
		}

		public static bool DebugDynamics
		{
			get
			{
				return debugDynamics.Value;
			}
			set
			{
				debugDynamics.Value = value;
			}
		}

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

Vanilla.dll

Decompiled 2 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 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 HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using Player;
using ReplayRecorder;
using ReplayRecorder.API;
using ReplayRecorder.API.Attributes;
using ReplayRecorder.Core;
using ReplayRecorder.SNetUtils;
using SNetwork;
using StateMachines;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Analytics;
using Vanilla.BepInEx;
using Vanilla.Enemy;
using Vanilla.Map;
using Vanilla.Metadata;
using Vanilla.Mines;
using Vanilla.Noises;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Vanilla")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+debd8a94d3643dac2b85e0b1dc717cf8d68a4e9c")]
[assembly: AssemblyProduct("Vanilla")]
[assembly: AssemblyTitle("Vanilla")]
[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 API
{
	[HarmonyPatch(typeof(GameDataInit))]
	internal class GameDataInit_Patches
	{
		[HarmonyPatch("Initialize")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		public static void Initialize_Postfix()
		{
			Analytics.enabled = false;
		}
	}
	internal static class APILogger
	{
		private static readonly ManualLogSource logger;

		static APILogger()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			logger = new ManualLogSource("Rand-API");
			Logger.Sources.Add((ILogSource)(object)logger);
		}

		private static string Format(string module, object msg)
		{
			return $"[{module}]: {msg}";
		}

		public static void Info(string module, object data)
		{
			logger.LogMessage((object)Format(module, data));
		}

		public static void Verbose(string module, object data)
		{
		}

		public static void Log(object data)
		{
			logger.LogDebug((object)Format("ReplayRecorder.Vanilla", data));
		}

		public static void Debug(object data)
		{
			if (ConfigManager.Debug)
			{
				Log(data);
			}
		}

		public static void Warn(object data)
		{
			logger.LogWarning((object)Format("ReplayRecorder.Vanilla", data));
		}

		public static void Error(object data)
		{
			logger.LogError((object)Format("ReplayRecorder.Vanilla", data));
		}
	}
}
namespace Vanilla
{
	public struct Identifier : BufferWriteable, IEquatable<Identifier>
	{
		private enum Type
		{
			Unknown,
			Gear,
			Alias_Gear,
			Item,
			Enemy,
			Vanity
		}

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

		private static Dictionary<string, ushort> GearTable = new Dictionary<string, ushort>();

		private static HashSet<ushort> WrittenGears = new HashSet<ushort>();

		public static Identifier unknown = new Identifier
		{
			type = Type.Unknown
		};

		private static ushort _id = 0;

		private string stringKey;

		private ushort id;

		private Type type;

		[ReplayInit]
		private static void Init()
		{
			_id = 0;
			GearTable.Clear();
			GearCache.Clear();
			WrittenGears.Clear();
		}

		public override string ToString()
		{
			return $"{stringKey}({id})[{type}]";
		}

		private static ushort AssignId()
		{
			return _id++;
		}

		public void Write(ByteBuffer buffer)
		{
			switch (type)
			{
			case Type.Gear:
				throw new Exception("GearKey is an internal type that gets written when a new Gear Alias is created. Should not be written directly.");
			case Type.Alias_Gear:
				if (WrittenGears.Contains(id))
				{
					BitHelper.WriteBytes((byte)2, buffer);
					BitHelper.WriteBytes(id, buffer);
					break;
				}
				WrittenGears.Add(id);
				BitHelper.WriteBytes((byte)1, buffer);
				BitHelper.WriteBytes(stringKey, buffer);
				BitHelper.WriteBytes(id, buffer);
				break;
			case Type.Item:
			case Type.Enemy:
			case Type.Vanity:
				BitHelper.WriteBytes((byte)type, buffer);
				BitHelper.WriteBytes(id, buffer);
				break;
			case Type.Unknown:
				BitHelper.WriteBytes((byte)0, buffer);
				break;
			default:
				throw new NotImplementedException();
			}
		}

		public static bool operator ==(Identifier lhs, Identifier rhs)
		{
			return lhs.Equals(rhs);
		}

		public static bool operator !=(Identifier lhs, Identifier rhs)
		{
			return !(lhs == rhs);
		}

		public override bool Equals(object? obj)
		{
			if (obj != null && obj is Identifier)
			{
				return Equals(obj);
			}
			return false;
		}

		public bool Equals(Identifier other)
		{
			switch (type)
			{
			case Type.Unknown:
				return other.type == Type.Unknown;
			case Type.Gear:
				if (other.type == Type.Gear)
				{
					return stringKey == other.stringKey;
				}
				if (stringKey != null && GearTable.ContainsKey(stringKey))
				{
					return other.id == GearTable[stringKey];
				}
				return false;
			case Type.Alias_Gear:
				if (other.type == Type.Alias_Gear)
				{
					return id == other.id;
				}
				if (other.stringKey != null && GearTable.ContainsKey(other.stringKey))
				{
					return id == GearTable[other.stringKey];
				}
				return false;
			case Type.Item:
			case Type.Enemy:
			case Type.Vanity:
				if (type == other.type)
				{
					return id == other.id;
				}
				return false;
			default:
				throw new NotImplementedException();
			}
		}

		public override int GetHashCode()
		{
			if (type == Type.Unknown)
			{
				return type.GetHashCode();
			}
			return type.GetHashCode() ^ stringKey.GetHashCode() ^ id.GetHashCode();
		}

		private static void From(GearIDRange gear, ref Identifier identifier)
		{
			int hashCode = ((Object)gear).GetHashCode();
			if (GearCache.ContainsKey(hashCode))
			{
				identifier.stringKey = GearCache[hashCode];
			}
			else
			{
				identifier.stringKey = gear.ToJSON();
				GearCache.Add(hashCode, identifier.stringKey);
			}
			identifier.type = Type.Alias_Gear;
			if (GearTable.ContainsKey(identifier.stringKey))
			{
				identifier.id = GearTable[identifier.stringKey];
				return;
			}
			identifier.id = AssignId();
			GearTable.Add(identifier.stringKey, identifier.id);
		}

		public static Identifier From(ItemEquippable? item)
		{
			Identifier identifier = default(Identifier);
			identifier.type = Type.Unknown;
			if ((Object)(object)item != (Object)null)
			{
				if (item.GearIDRange != null)
				{
					From(item.GearIDRange, ref identifier);
				}
				else if (((Item)item).ItemDataBlock != null)
				{
					identifier.type = Type.Item;
					identifier.id = (ushort)((GameDataBlockBase<ItemDataBlock>)(object)((Item)item).ItemDataBlock).persistentID;
				}
			}
			return identifier;
		}

		public static Identifier From(BackpackItem? item)
		{
			Identifier identifier = default(Identifier);
			identifier.type = Type.Unknown;
			if (item != null && item.GearIDRange != null)
			{
				From(item.GearIDRange, ref identifier);
			}
			return identifier;
		}

		public static Identifier From(Item? item)
		{
			Identifier result = default(Identifier);
			result.type = Type.Unknown;
			if ((Object)(object)item != (Object)null && item.ItemDataBlock != null)
			{
				result.type = Type.Item;
				result.id = (ushort)((GameDataBlockBase<ItemDataBlock>)(object)item.ItemDataBlock).persistentID;
			}
			return result;
		}

		public static Identifier From(pItemData item)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Identifier result = default(Identifier);
			result.type = Type.Item;
			result.id = (ushort)item.itemID_gearCRC;
			return result;
		}

		public static Identifier From(EnemyAgent enemy)
		{
			Identifier result = default(Identifier);
			result.type = Type.Enemy;
			result.id = (ushort)((GameDataBlockBase<EnemyDataBlock>)(object)enemy.EnemyData).persistentID;
			return result;
		}

		public static Identifier Vanity(uint id)
		{
			Identifier result = default(Identifier);
			result.type = Type.Vanity;
			result.id = (ushort)id;
			return result;
		}

		public static Identifier Item(uint id)
		{
			Identifier result = default(Identifier);
			result.type = Type.Item;
			result.id = (ushort)id;
			return result;
		}
	}
}
namespace Vanilla.StatTracker
{
	[HarmonyPatch]
	[ReplayData("Vanilla.StatTracker.Damage", "0.0.1")]
	internal class rDamage : ReplayEvent
	{
		[HarmonyPatch]
		private static class Patches
		{
			private static bool sentry;

			[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "FireBullet")]
			[HarmonyPrefix]
			private static void Prefix_SentryGunFire(SentryGunInstance_Firing_Bullets __instance, bool doDamage, bool targetIsTagged)
			{
				sentry = true;
			}

			[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "FireBullet")]
			[HarmonyPostfix]
			private static void Postfix_SentryGunFire()
			{
				sentry = false;
			}

			[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "UpdateFireShotgunSemi")]
			[HarmonyPrefix]
			private static void Prefix_SentryShotgunFire(SentryGunInstance_Firing_Bullets __instance, bool isMaster, bool targetIsTagged)
			{
				sentry = true;
			}

			[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "UpdateFireShotgunSemi")]
			[HarmonyPostfix]
			private static void Postfix_SentryShotgunFire()
			{
				sentry = false;
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveFallDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveFallDamage(Dam_PlayerDamageBase __instance, pMiniDamageData data)
			{
				if (SNet.IsMaster)
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, (Agent)(object)__instance.Owner, Type.Fall, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveTentacleAttackDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveTentacleAttackDamage(Dam_PlayerDamageBase __instance, pMediumDamageData data)
			{
				if (SNet.IsMaster && ((Agent)__instance.Owner).Alive)
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					Agent val = default(Agent);
					if (((pAgent)(ref data.source)).TryGet(ref val))
					{
						num = AgentModifierManager.ApplyModifier(val, (AgentModifier)200, num);
					}
					num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)6, num);
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Tongue, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveShooterProjectileDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveShooterProjectileDamage(Dam_PlayerDamageBase __instance, pMediumDamageData data)
			{
				if (SNet.IsMaster && ((Agent)__instance.Owner).Alive)
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					Agent val = default(Agent);
					if (((pAgent)(ref data.source)).TryGet(ref val))
					{
						num = AgentModifierManager.ApplyModifier(val, (AgentModifier)70, num);
					}
					num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)7, num);
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, (Agent)(object)__instance.Owner, Type.Projectile, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveExplosionDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveExplosionDamage(Dam_PlayerDamageBase __instance, pExplosionDamageData data)
			{
				if (SNet.IsMaster && ((Agent)__instance.Owner).Alive && MineManager.currentDetonateEvent != null)
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, ((Id)MineManager.currentDetonateEvent).id, Type.Explosive, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveMeleeDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveMeleeDamage(Dam_PlayerDamageBase __instance, pFullDamageData data)
			{
				Agent val = default(Agent);
				if (SNet.IsMaster && ((Agent)__instance.Owner).Alive && ((pAgent)(ref data.source)).TryGet(ref val))
				{
					float num = AgentModifierManager.ApplyModifier(val, (AgentModifier)200, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).DamageMax));
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Melee, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveBulletDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerReceiveBulletDamage(Dam_PlayerDamageBase __instance, pBulletDamageData data)
			{
				Agent val = default(Agent);
				if (!SNet.IsMaster || !((Agent)__instance.Owner).Alive || !((pAgent)(ref data.source)).TryGet(ref val))
				{
					return;
				}
				Identifier gear = Identifier.unknown;
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				if ((Object)(object)val2 != (Object)null)
				{
					if (!sentry)
					{
						ItemEquippable wieldedItem = val2.Inventory.WieldedItem;
						if (wieldedItem.IsWeapon && wieldedItem.CanReload)
						{
							gear = Identifier.From(wieldedItem);
						}
					}
					else
					{
						gear = Identifier.From(PlayerBackpackManager.GetItem(val2.Owner, (InventorySlot)3));
					}
				}
				float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
				APILogger.Debug($"{__instance.Owner.Owner.NickName} was hit by {((Il2CppObjectBase)val).Cast<PlayerAgent>().Owner.NickName} -> {num}");
				Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Bullet, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num), gear, sentry));
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageLocal), "ReceiveBulletDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerLocalReceiveBulletDamage(Dam_PlayerDamageBase __instance, pBulletDamageData data)
			{
				Agent val = default(Agent);
				if (!SNet.IsMaster || !((Agent)__instance.Owner).Alive || !((pAgent)(ref data.source)).TryGet(ref val))
				{
					return;
				}
				Identifier gear = Identifier.unknown;
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				if ((Object)(object)val2 != (Object)null)
				{
					if (!sentry)
					{
						ItemEquippable wieldedItem = val2.Inventory.WieldedItem;
						if (wieldedItem.IsWeapon && wieldedItem.CanReload)
						{
							gear = Identifier.From(wieldedItem);
						}
					}
					else
					{
						gear = Identifier.From(PlayerBackpackManager.GetItem(val2.Owner, (InventorySlot)3));
					}
				}
				float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
				APILogger.Debug($"{__instance.Owner.Owner.NickName} was hit by {((Il2CppObjectBase)val).Cast<PlayerAgent>().Owner.NickName} -> {num}");
				Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Bullet, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num), gear, sentry));
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageLocal), "ReceiveExplosionDamage")]
			[HarmonyPrefix]
			public static void Prefix_PlayerLocalReceiveExplosionDamage(Dam_PlayerDamageBase __instance, pExplosionDamageData data)
			{
				if (SNet.IsMaster && ((Agent)__instance.Owner).Alive)
				{
					APILogger.Debug("local explosive");
					if (MineManager.currentDetonateEvent != null)
					{
						float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
						Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, ((Id)MineManager.currentDetonateEvent).id, Type.Explosive, Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num)));
					}
				}
			}

			[HarmonyPatch(typeof(Dam_EnemyDamageBase), "ReceiveExplosionDamage")]
			[HarmonyPrefix]
			public static void Prefix_EnemyReceiveExplosionDamage(Dam_EnemyDamageBase __instance, pExplosionDamageData data)
			{
				if (!SNet.IsMaster || !((Agent)__instance.Owner).Alive)
				{
					return;
				}
				if (MineManager.currentDetonateEvent != null)
				{
					float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
					float num2 = num;
					float num3 = __instance.Owner.EnemyBalancingData.Health.DamageUntilHitreact - __instance.m_damBuildToHitreact;
					if (num3 < 0f)
					{
						num3 = 0f;
					}
					num = Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num);
					num2 = HandlePouncerStagger(__instance, num, Mathf.Min(num3, num2));
					Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, ((Id)MineManager.currentDetonateEvent).id, Type.Explosive, num, sentry: false, num2));
				}
				else
				{
					APILogger.Error("Unable to find detonation event. This should not happen.");
				}
			}

			[HarmonyPatch(typeof(Dam_EnemyDamageBase), "ReceiveMeleeDamage")]
			[HarmonyPrefix]
			public static void Prefix_EnemyReceiveMeleeDamage(Dam_EnemyDamageBase __instance, pFullDamageData data)
			{
				Agent val = default(Agent);
				if (!SNet.IsMaster || !((Agent)__instance.Owner).Alive || !((pAgent)(ref data.source)).TryGet(ref val))
				{
					return;
				}
				Identifier gear = Identifier.unknown;
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				if ((Object)(object)val2 != (Object)null)
				{
					ItemEquippable wieldedItem = val2.Inventory.WieldedItem;
					if (wieldedItem.IsWeapon && wieldedItem.CanReload)
					{
						gear = Identifier.From(wieldedItem);
					}
				}
				float num = AgentModifierManager.ApplyModifier(val, (AgentModifier)200, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).DamageMax));
				float num2 = num * ((UFloat16)(ref data.staggerMulti)).Get(10f);
				float num3 = __instance.Owner.EnemyBalancingData.Health.DamageUntilHitreact - __instance.m_damBuildToHitreact;
				if (num3 < 0f)
				{
					num3 = 0f;
				}
				num = Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num);
				num2 = HandlePouncerStagger(__instance, num, Mathf.Min(num3, num2));
				Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Melee, num, gear, sentry: false, num2));
			}

			[HarmonyPatch(typeof(Dam_EnemyDamageBase), "ReceiveBulletDamage")]
			[HarmonyPrefix]
			public static void Prefix_EnemyReceiveBulletDamage(Dam_EnemyDamageBase __instance, pBulletDamageData data)
			{
				Agent val = default(Agent);
				if (!SNet.IsMaster || !((Agent)__instance.Owner).Alive || !((pAgent)(ref data.source)).TryGet(ref val))
				{
					return;
				}
				Identifier gear = Identifier.unknown;
				PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
				if ((Object)(object)val2 != (Object)null)
				{
					if (!sentry)
					{
						ItemEquippable wieldedItem = val2.Inventory.WieldedItem;
						if (wieldedItem.IsWeapon && wieldedItem.CanReload)
						{
							gear = Identifier.From(wieldedItem);
						}
					}
					else
					{
						gear = Identifier.From(PlayerBackpackManager.GetItem(val2.Owner, (InventorySlot)3));
					}
				}
				float num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)7, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax));
				float num2 = num * ((UFloat16)(ref data.staggerMulti)).Get(10f);
				float num3 = __instance.Owner.EnemyBalancingData.Health.DamageUntilHitreact - __instance.m_damBuildToHitreact;
				if (num3 < 0f)
				{
					num3 = 0f;
				}
				num = Mathf.Min(((Dam_SyncedDamageBase)__instance).Health, num);
				num2 = HandlePouncerStagger(__instance, num, Mathf.Min(num3, num2));
				Replay.Trigger((ReplayEvent)(object)new rDamage((Agent)(object)__instance.Owner, val, Type.Bullet, num, gear, sentry, num2));
			}

			private static float HandlePouncerStagger(Dam_EnemyDamageBase __instance, float damage, float stagger)
			{
				PouncerBehaviour component = ((Component)__instance.Owner).GetComponent<PouncerBehaviour>();
				if ((Object)(object)component == (Object)null)
				{
					return stagger;
				}
				if (((MachineState<EB_StateBase>)(object)((StateMachine<EB_StateBase>)(object)component).CurrentState).ENUM_ID == ((MachineState<EB_StateBase>)(object)component.Dash).ENUM_ID)
				{
					return Mathf.Min(damage + component.Dash.m_damageReceivedDuringState, component.m_data.DashStaggerDamageThreshold) - component.Dash.m_damageReceivedDuringState;
				}
				if (((MachineState<EB_StateBase>)(object)((StateMachine<EB_StateBase>)(object)component).CurrentState).ENUM_ID == ((MachineState<EB_StateBase>)(object)component.Charge).ENUM_ID)
				{
					return Mathf.Min(damage + component.Charge.m_damageReceivedDuringState, component.m_data.ChargeStaggerDamageThreshold) - component.Charge.m_damageReceivedDuringState;
				}
				return 0f;
			}
		}

		public enum Type
		{
			Bullet,
			Explosive,
			Melee,
			Projectile,
			Tongue,
			Fall
		}

		private Type type;

		private int source;

		private ushort target;

		private Identifier gear;

		private bool sentry;

		private float damage;

		private float staggerDamage;

		public rDamage(Agent target, Agent source, Type type, float damage, Identifier gear, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source.GlobalID;
			this.target = target.GlobalID;
			this.gear = gear;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public rDamage(Agent target, int source, Type type, float damage, Identifier gear, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source;
			this.target = target.GlobalID;
			this.gear = gear;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public rDamage(ushort target, int source, Type type, float damage, Identifier gear, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source;
			this.target = target;
			this.gear = gear;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public rDamage(Agent target, Agent source, Type type, float damage, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source.GlobalID;
			this.target = target.GlobalID;
			gear = Identifier.unknown;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public rDamage(Agent target, int source, Type type, float damage, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source;
			this.target = target.GlobalID;
			gear = Identifier.unknown;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public rDamage(ushort target, int source, Type type, float damage, bool sentry = false, float staggerMulti = 0f)
		{
			this.type = type;
			this.source = source;
			this.target = target;
			gear = Identifier.unknown;
			this.damage = damage;
			staggerDamage = staggerMulti;
			this.sentry = sentry;
		}

		public override void Write(ByteBuffer buffer)
		{
			BitHelper.WriteBytes((byte)type, buffer);
			BitHelper.WriteBytes(source, buffer);
			BitHelper.WriteBytes(target, buffer);
			BitHelper.WriteHalf(damage, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)gear, buffer);
			BitHelper.WriteBytes(sentry, buffer);
			BitHelper.WriteHalf(staggerDamage, buffer);
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.StatTracker.Revive", "0.0.1")]
	internal class rRevive : ReplayEvent
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(AgentReplicatedActions), "DoPlayerRevive")]
			[HarmonyPostfix]
			public static void DoPlayerRevive(pPlayerReviveAction data)
			{
				PlayerAgent val = default(PlayerAgent);
				PlayerAgent val2 = default(PlayerAgent);
				if (((pPlayerAgent)(ref data.TargetPlayer)).TryGet(ref val) && !((Agent)val).Alive && ((pPlayerAgent)(ref data.SourcePlayer)).TryGet(ref val2))
				{
					APILogger.Debug($"Player {val.Owner.NickName} was revived by {val2.Owner.NickName}.");
					Replay.Trigger((ReplayEvent)(object)new rRevive(val, val2));
				}
			}
		}

		private ushort source;

		private ushort target;

		public rRevive(PlayerAgent target, PlayerAgent source)
		{
			this.source = ((Agent)source).GlobalID;
			this.target = ((Agent)target).GlobalID;
		}

		public override void Write(ByteBuffer buffer)
		{
			BitHelper.WriteBytes(source, buffer);
			BitHelper.WriteBytes(target, buffer);
		}
	}
}
namespace Vanilla.StatTracker.Dodges
{
	[HarmonyPatch]
	[ReplayData("Vanilla.StatTracker.TongueDodge", "0.0.1")]
	internal class rTongueDodge : ReplayEvent
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(MovingEnemyTentacleBase), "AttackIn")]
			[HarmonyPrefix]
			private static void AttackIn(MovingEnemyTentacleBase __instance)
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (Replay.Has<rEnemyTongue>(instanceID))
				{
					rEnemyTongue rEnemyTongue = Replay.Get<rEnemyTongue>(instanceID);
					if (!rEnemyTongue.attackOut && (Object)(object)rEnemyTongue.target != (Object)null)
					{
						Replay.Trigger((ReplayEvent)(object)new rTongueDodge(__instance.m_owner, rEnemyTongue.target));
					}
					rEnemyTongue.attackOut = false;
				}
			}

			[HarmonyPatch(typeof(MovingEnemyTentacleBase), "OnAttackIsOut")]
			[HarmonyPrefix]
			private static void OnAttackIsOut(MovingEnemyTentacleBase __instance)
			{
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				if (!SNet.IsMaster)
				{
					return;
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!Replay.Has<rEnemyTongue>(instanceID))
				{
					return;
				}
				rEnemyTongue rEnemyTongue = Replay.Get<rEnemyTongue>(instanceID);
				rEnemyTongue.attackOut = true;
				PlayerAgent val = __instance.PlayerTarget;
				if ((Object)(object)val == (Object)null)
				{
					val = rEnemyTongue.target;
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				bool flag = __instance.CheckTargetInAttackTunnel();
				bool flag2 = false;
				if (__instance.m_hasStaticTargetPos)
				{
					RaycastHit val2 = default(RaycastHit);
					if (Physics.Linecast(((Agent)__instance.m_owner).EyePosition, __instance.m_staticTargetPos, ref val2, LayerManager.MASK_DEFAULT) && ((Component)((RaycastHit)(ref val2)).collider).GetComponent<IDamageable>() != null)
					{
						flag2 = true;
					}
				}
				else if ((Object)(object)__instance.PlayerTarget != (Object)null && ((Dam_SyncedDamageBase)__instance.PlayerTarget.Damage).IsSetup)
				{
					bool flag3;
					if (__instance.m_owner.EnemyBalancingData.UseTentacleTunnelCheck)
					{
						flag3 = flag;
					}
					else
					{
						Vector3 tipPos = __instance.GetTipPos();
						Vector3 val3 = ((Agent)__instance.PlayerTarget).TentacleTarget.position - tipPos;
						flag3 = ((Vector3)(ref val3)).magnitude < __instance.m_owner.EnemyBalancingData.TentacleAttackDamageRadiusIfNoTunnelCheck;
					}
					if (flag3)
					{
						flag2 = true;
					}
				}
				if (!flag2)
				{
					Replay.Trigger((ReplayEvent)(object)new rTongueDodge(__instance.m_owner, val));
				}
			}
		}

		private ushort source;

		private ushort target;

		public rTongueDodge(EnemyAgent source, PlayerAgent target)
		{
			this.source = ((Agent)source).GlobalID;
			this.target = ((Agent)target).GlobalID;
		}

		public override void Write(ByteBuffer buffer)
		{
			BitHelper.WriteBytes(source, buffer);
			BitHelper.WriteBytes(target, buffer);
		}
	}
}
namespace Vanilla.StatTracker.Consumable
{
	[HarmonyPatch]
	[ReplayData("Vanilla.StatTracker.Pack", "0.0.1")]
	internal class rPack : ReplayEvent
	{
		[HarmonyPatch]
		private class Patches
		{
			private static PlayerAgent? sourcePackUser;

			[HarmonyPatch(typeof(ResourcePackFirstPerson), "ApplyPackBot")]
			[HarmonyPrefix]
			public static void ApplyPackBot(PlayerAgent ownerAgent, PlayerAgent receiverAgent, ItemEquippable resourceItem)
			{
				if (SNet.IsMaster)
				{
					uint persistentID = ((GameDataBlockBase<ItemDataBlock>)(object)((Item)resourceItem).ItemDataBlock).persistentID;
					if (persistentID - 101 <= 1 || persistentID == 127 || persistentID == 132)
					{
						sourcePackUser = ownerAgent;
					}
				}
			}

			[HarmonyPatch(typeof(ResourcePackFirstPerson), "ApplyPack")]
			[HarmonyPrefix]
			public static void ApplyPackFirstPerson(ResourcePackFirstPerson __instance)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Invalid comparison between Unknown and I4
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				if (SNet.IsMaster)
				{
					eResourceContainerSpawnType packType = __instance.m_packType;
					if ((int)packType <= 2 || (int)packType == 9)
					{
						sourcePackUser = ((Item)__instance).Owner;
					}
				}
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveAddHealth")]
			[HarmonyPrefix]
			public static void Postfix_ReceiveAddHealth(Dam_PlayerDamageBase __instance, pAddHealthData data)
			{
				if (!SNet.IsMaster)
				{
					return;
				}
				float num = ((SFloat16)(ref data.health)).Get(((Dam_SyncedDamageBase)__instance).HealthMax);
				if (Mathf.Min(((Dam_SyncedDamageBase)__instance).Health + num, ((Dam_SyncedDamageBase)__instance).HealthMax) - ((Dam_SyncedDamageBase)__instance).Health > 0f)
				{
					Agent val = default(Agent);
					if ((Object)(object)sourcePackUser == (Object)null)
					{
						((pAgent)(ref data.source)).TryGet(ref val);
					}
					else
					{
						val = (Agent)(object)sourcePackUser;
					}
					if ((Object)(object)val != (Object)null)
					{
						PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
						if ((Object)(object)val2 != (Object)null)
						{
							APILogger.Debug($"Player {val2.Owner.NickName} used healing item on {__instance.Owner.Owner.NickName}.");
							Replay.Trigger((ReplayEvent)(object)new rPack(Type.HealingItem, val, (Agent)(object)__instance.Owner));
						}
					}
				}
				sourcePackUser = null;
			}

			[HarmonyPatch(typeof(PlayerBackpackManager), "ReceiveAmmoGive")]
			[HarmonyPostfix]
			public static void ReceiveAmmoGive(PlayerBackpackManager __instance, pAmmoGive data)
			{
				//IL_0022: 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)
				if (!SNet.IsMaster)
				{
					return;
				}
				SNet_Player val = default(SNet_Player);
				if (((pPlayer)(ref data.targetPlayer)).TryGetPlayer(ref val))
				{
					PlayerDataBlock block = GameDataBlockBase<PlayerDataBlock>.GetBlock(1u);
					float num = data.ammoStandardRel * (float)block.AmmoStandardResourcePackMaxCap;
					float num2 = data.ammoSpecialRel * (float)block.AmmoSpecialResourcePackMaxCap;
					Type type = ((!(num > 0f) || !(num2 > 0f)) ? Type.Tool : Type.Ammo);
					PlayerAgent val2 = ((Il2CppObjectBase)val.PlayerAgent).Cast<PlayerAgent>();
					SNet_Player val3 = default(SNet_Player);
					if ((Object)(object)sourcePackUser != (Object)null)
					{
						APILogger.Debug($"Player {sourcePackUser.Owner.NickName} used {type} on {val2.Owner.NickName}.");
						Replay.Trigger((ReplayEvent)(object)new rPack(type, (Agent)(object)sourcePackUser, (Agent)(object)val2));
					}
					else if (SNetUtils.TryGetSender((SNet_Packet)(object)((SNet_SyncedAction<pAmmoGive>)(object)__instance.m_giveAmmoPacket).m_packet, ref val3))
					{
						APILogger.Debug($"Player {val3.NickName} used {type} on {val2.Owner.NickName}.");
						Replay.Trigger((ReplayEvent)(object)new rPack(type, (Agent)(object)((Il2CppObjectBase)val3.PlayerAgent).Cast<PlayerAgent>(), (Agent)(object)val2));
					}
					else
					{
						APILogger.Debug($"Player {val2.Owner.NickName} used {type}.");
						Replay.Trigger((ReplayEvent)(object)new rPack(type, (Agent)(object)val2, (Agent)(object)val2));
					}
				}
				sourcePackUser = null;
			}

			[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ModifyInfection")]
			[HarmonyPostfix]
			public static void ModifyInfection(Dam_PlayerDamageBase __instance, pInfection data, bool sync, bool updatePageMap)
			{
				//IL_0008: 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_000f: Invalid comparison between Unknown and I4
				if (!SNet.IsMaster)
				{
					return;
				}
				if ((int)data.effect == 1)
				{
					PlayerAgent owner = __instance.Owner;
					SNet_Player val = default(SNet_Player);
					if ((Object)(object)sourcePackUser != (Object)null)
					{
						APILogger.Debug($"Player {sourcePackUser.Owner.NickName} used disinfect pack on {owner.Owner.NickName}.");
						Replay.Trigger((ReplayEvent)(object)new rPack(Type.Disinfect, (Agent)(object)sourcePackUser, (Agent)(object)owner));
					}
					else if (SNetUtils.TryGetSender((SNet_Packet)(object)__instance.m_receiveModifyInfectionPacket, ref val))
					{
						APILogger.Debug($"Player {val.NickName} used disinfect pack on {owner.Owner.NickName}.");
						Replay.Trigger((ReplayEvent)(object)new rPack(Type.Disinfect, (Agent)(object)((Il2CppObjectBase)val.PlayerAgent).Cast<PlayerAgent>(), (Agent)(object)owner));
					}
					else
					{
						APILogger.Debug("Player " + owner.Owner.NickName + " used disinfect pack.");
						Replay.Trigger((ReplayEvent)(object)new rPack(Type.Disinfect, (Agent)(object)owner, (Agent)(object)owner));
					}
				}
				sourcePackUser = null;
			}
		}

		public enum Type
		{
			Ammo,
			Tool,
			HealingItem,
			Disinfect
		}

		private Type type;

		private ushort source;

		private ushort target;

		public rPack(Type type, Agent source, Agent target)
		{
			this.type = type;
			this.source = source.GlobalID;
			this.target = target.GlobalID;
		}

		public override void Write(ByteBuffer buffer)
		{
			BitHelper.WriteBytes((byte)type, buffer);
			BitHelper.WriteBytes(source, buffer);
			BitHelper.WriteBytes(target, buffer);
		}
	}
}
namespace Vanilla.StaticItems
{
	internal class rBulkheadController
	{
		public LG_BulkheadDoorController_Core core;

		public int id;

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

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

		public byte dimensionIndex => (byte)core.SpawnNode.m_dimension.DimensionIndex;

		public ushort serialNumber => (ushort)core.m_serialNumber;

		public rBulkheadController(LG_BulkheadDoorController_Core controller)
		{
			id = ((Object)controller).GetInstanceID();
			core = controller;
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.BulkheadControllers", "0.0.1")]
	internal class rBulkheadControllers : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_BulkheadDoorController_Core), "Setup")]
			[HarmonyPostfix]
			private static void Setup(LG_BulkheadDoorController_Core __instance)
			{
				rBulkheadController rBulkheadController2 = new rBulkheadController(__instance);
				bulkheadControllers.Add(rBulkheadController2.id, rBulkheadController2);
			}
		}

		internal static Dictionary<int, rBulkheadController> bulkheadControllers = new Dictionary<int, rBulkheadController>();

		private static LG_LayerType[] layers = (LG_LayerType[])(object)new LG_LayerType[3]
		{
			default(LG_LayerType),
			(LG_LayerType)1,
			(LG_LayerType)2
		};

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rBulkheadControllers());
			bulkheadControllers.Clear();
		}

		[ReplayInit]
		private static void Init()
		{
			bulkheadControllers.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			BitHelper.WriteBytes((ushort)bulkheadControllers.Count, buffer);
			foreach (rBulkheadController value in bulkheadControllers.Values)
			{
				BitHelper.WriteBytes(value.id, buffer);
				BitHelper.WriteBytes(value.dimensionIndex, buffer);
				BitHelper.WriteBytes(value.position, buffer);
				BitHelper.WriteHalf(value.rotation, buffer);
				BitHelper.WriteBytes(value.serialNumber, buffer);
				Dictionary<LG_LayerType, LG_SecurityDoor> connectedBulkheadDoors = value.core.m_connectedBulkheadDoors;
				LG_LayerType[] array = layers;
				foreach (LG_LayerType val in array)
				{
					if (connectedBulkheadDoors.ContainsKey(val))
					{
						BitHelper.WriteBytes(true, buffer);
						BitHelper.WriteBytes(((Object)connectedBulkheadDoors[val].Gate).GetInstanceID(), buffer);
					}
					else
					{
						BitHelper.WriteBytes(false, buffer);
					}
				}
			}
		}
	}
	internal class rDisinfectStation
	{
		public LG_DisinfectionStation core;

		public int id;

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

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

		public byte dimensionIndex => (byte)core.SpawnNode.m_dimension.DimensionIndex;

		public ushort serialNumber => (ushort)core.m_serialNumber;

		public rDisinfectStation(LG_DisinfectionStation disinfectStation)
		{
			id = ((Object)disinfectStation).GetInstanceID();
			core = disinfectStation;
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.DisinfectStations", "0.0.1")]
	internal class rDisinfectStations : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_DisinfectionStation), "Setup")]
			[HarmonyPostfix]
			private static void Setup(LG_DisinfectionStation __instance)
			{
				rDisinfectStation rDisinfectStation2 = new rDisinfectStation(__instance);
				disinfectStations.Add(rDisinfectStation2.id, rDisinfectStation2);
			}
		}

		internal static Dictionary<int, rDisinfectStation> disinfectStations = new Dictionary<int, rDisinfectStation>();

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rDisinfectStations());
			disinfectStations.Clear();
		}

		[ReplayInit]
		private static void Init()
		{
			disinfectStations.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0043: 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)
			BitHelper.WriteBytes((ushort)disinfectStations.Count, buffer);
			foreach (rDisinfectStation value in disinfectStations.Values)
			{
				BitHelper.WriteBytes(value.id, buffer);
				BitHelper.WriteBytes(value.dimensionIndex, buffer);
				BitHelper.WriteBytes(value.position, buffer);
				BitHelper.WriteHalf(value.rotation, buffer);
				BitHelper.WriteBytes(value.serialNumber, buffer);
			}
		}
	}
	internal class rDoor
	{
		public enum Type
		{
			WeakDoor,
			SecurityDoor,
			BulkheadDoor,
			BulkheadDoorMain,
			ApexDoor
		}

		private int id;

		private LG_Gate gate;

		private MonoBehaviourExtended mono;

		private ushort serialNumber;

		private bool isCheckpoint;

		private Type type;

		private byte size;

		public rDoor(Type type, LG_Gate gate, MonoBehaviourExtended mono, int serialNumber, bool isCheckpoint = false)
		{
			//IL_0073: 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_007b: Invalid comparison between Unknown and I4
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Invalid comparison between Unknown and I4
			id = ((Object)gate).GetInstanceID();
			this.gate = gate;
			this.mono = mono;
			this.serialNumber = (ushort)serialNumber;
			this.type = type;
			this.isCheckpoint = isCheckpoint;
			if (this.type == Type.SecurityDoor)
			{
				if (gate.ForceApexGate)
				{
					this.type = Type.ApexDoor;
				}
				else if (gate.ForceBulkheadGate)
				{
					this.type = Type.BulkheadDoor;
				}
				else if (gate.ForceBulkheadGateMainPath)
				{
					this.type = Type.BulkheadDoorMain;
				}
			}
			LG_GateType val = gate.Type;
			if ((int)val != 1)
			{
				if ((int)val == 2)
				{
					size = 2;
				}
				else
				{
					size = 0;
				}
			}
			else
			{
				size = 1;
			}
		}

		public void Write(ByteBuffer buffer)
		{
			//IL_0021: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			BitHelper.WriteBytes(id, buffer);
			BitHelper.WriteBytes((byte)gate.m_progressionSourceArea.m_courseNode.m_dimension.DimensionIndex, buffer);
			BitHelper.WriteBytes(((Component)mono).transform.position, buffer);
			BitHelper.WriteHalf(((Component)mono).transform.rotation, buffer);
			BitHelper.WriteBytes(serialNumber, buffer);
			BitHelper.WriteBytes(isCheckpoint, buffer);
			BitHelper.WriteBytes((byte)type, buffer);
			BitHelper.WriteBytes(size, buffer);
		}
	}
	[ReplayData("Vanilla.Map.Doors", "0.0.1")]
	internal class rDoors : ReplayHeader
	{
		private List<rDoor> doors;

		public rDoors(List<rDoor> doors)
		{
			this.doors = doors;
		}

		public override void Write(ByteBuffer buffer)
		{
			if (doors.Count > 65535)
			{
				throw new TooManyDoors($"There were too many doors! {doors.Count} doors were found.");
			}
			BitHelper.WriteBytes((ushort)doors.Count, buffer);
			foreach (rDoor door in doors)
			{
				door.Write(buffer);
			}
		}
	}
	public class NoDoorDestructionComp : Exception
	{
		public NoDoorDestructionComp(string message)
			: base(message)
		{
		}
	}
	public class TooManyDoors : Exception
	{
		public TooManyDoors(string message)
			: base(message)
		{
		}
	}
	internal static class DoorReplayManager
	{
		internal static List<rDoor> doors = new List<rDoor>();

		internal static List<rWeakDoor> weakDoors = new List<rWeakDoor>();

		[ReplayInit]
		private static void Init()
		{
			doors.Clear();
			weakDoors.Clear();
		}

		[ReplayOnHeaderCompletion]
		private static void WriteWeakDoors()
		{
			foreach (rWeakDoor weakDoor in weakDoors)
			{
				Replay.Spawn((ReplayDynamic)(object)weakDoor, true);
			}
		}

		public static byte doorStatus(eDoorStatus status)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected I4, but got Unknown
			return (status - 10) switch
			{
				0 => 1, 
				2 => 2, 
				1 => 3, 
				_ => 0, 
			};
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.DoorStatusChange", "0.0.1")]
	internal class rDoorStatusChange : Id
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_WeakDoor), "OnSyncDoorStateChange")]
			[HarmonyPrefix]
			private static void Weak_DoorStateChange(LG_WeakDoor __instance, pDoorState state)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: 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)
				if (DoorReplayManager.doorStatus(__instance.LastStatus) != DoorReplayManager.doorStatus(state.status))
				{
					Replay.Trigger((ReplayEvent)(object)new rDoorStatusChange(((Object)__instance.Gate).GetInstanceID(), state.status));
				}
			}

			[HarmonyPatch(typeof(LG_SecurityDoor), "OnSyncDoorStatusChange")]
			[HarmonyPrefix]
			private static void Security_DoorStateChange(LG_SecurityDoor __instance, pDoorState state)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: 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)
				if (DoorReplayManager.doorStatus(__instance.LastStatus) != DoorReplayManager.doorStatus(state.status))
				{
					Replay.Trigger((ReplayEvent)(object)new rDoorStatusChange(((Object)__instance.Gate).GetInstanceID(), state.status));
				}
			}
		}

		private byte status;

		public rDoorStatusChange(int id, eDoorStatus status)
			: base(id)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			this.status = DoorReplayManager.doorStatus(status);
		}

		public override void Write(ByteBuffer buffer)
		{
			((Id)this).Write(buffer);
			BitHelper.WriteBytes(status, buffer);
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.WeakDoor.Punch", "0.0.1")]
	internal class rDoorPunch : Id
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_WeakDoor_Destruction), "TriggerPunchEffect")]
			[HarmonyPostfix]
			private static void WeakDoor_Punch(LG_WeakDoor_Destruction __instance)
			{
				LG_WeakDoor val = ((Il2CppObjectBase)__instance.m_core).TryCast<LG_WeakDoor>();
				if (!((Object)(object)val == (Object)null))
				{
					Replay.Trigger((ReplayEvent)(object)new rDoorPunch(((Object)val.Gate).GetInstanceID()));
				}
			}
		}

		public rDoorPunch(int id)
			: base(id)
		{
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.WeakDoor", "0.0.1")]
	internal class rWeakDoor : ReplayDynamic
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_WeakDoor), "Setup")]
			[HarmonyPostfix]
			private static void WeakDoor_Setup(LG_WeakDoor __instance, LG_Gate gate)
			{
				DoorReplayManager.doors.Add(new rDoor(rDoor.Type.WeakDoor, gate, (MonoBehaviourExtended)(object)__instance, __instance.m_serialNumber, __instance.IsCheckpointDoor));
				DoorReplayManager.weakDoors.Add(new rWeakDoor(__instance));
			}

			[HarmonyPatch(typeof(LG_SecurityDoor), "Setup")]
			[HarmonyPostfix]
			private static void SecurityDoor_Setup(LG_SecurityDoor __instance, LG_Gate gate)
			{
				DoorReplayManager.doors.Add(new rDoor(rDoor.Type.SecurityDoor, gate, (MonoBehaviourExtended)(object)__instance, __instance.m_serialNumber, __instance.IsCheckpointDoor));
			}

			[HarmonyPatch(typeof(GS_ReadyToStopElevatorRide), "Enter")]
			[HarmonyPostfix]
			private static void StopElevatorRide()
			{
				Replay.Trigger((ReplayHeader)(object)new rDoors(DoorReplayManager.doors));
			}
		}

		private enum LockType
		{
			None,
			Melee,
			Hackable
		}

		private LG_WeakDoor door;

		private LG_WeakDoor_Destruction destruction;

		private float damageTaken;

		private byte prevHealth = byte.MaxValue;

		private byte _lock0;

		private byte _lock1;

		public override string? Debug => $"{base.id} - {destruction.m_health}/{door.m_healthMax}";

		public override bool Active => (Object)(object)door != (Object)null;

		public override bool IsDirty
		{
			get
			{
				if (health == prevHealth && _lock0 == lock0)
				{
					return _lock1 != lock1;
				}
				return true;
			}
		}

		private byte health
		{
			get
			{
				if (SNet.IsMaster)
				{
					return (byte)(255f * destruction.m_health / door.m_healthMax);
				}
				return (byte)(255f * Mathf.Max(door.m_healthMax - damageTaken, 0f) / door.m_healthMax);
			}
		}

		private byte lock0 => (byte)GetLockType(0);

		private byte lock1 => (byte)GetLockType(1);

		private LockType GetLockType(int slot)
		{
			//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_0054: Invalid comparison between Unknown and I4
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			if (door.m_weakLocks == null || slot < 0 || slot >= ((Il2CppArrayBase<LG_WeakLock>)(object)door.m_weakLocks).Length)
			{
				return LockType.None;
			}
			LG_WeakLock val = ((Il2CppArrayBase<LG_WeakLock>)(object)door.m_weakLocks)[slot];
			LockType result = LockType.None;
			if ((Object)(object)val != (Object)null && (int)val.m_stateReplicator.State.status != 3 && (int)val.m_stateReplicator.State.status != 2)
			{
				eWeakLockType lockType = val.m_lockType;
				if ((int)lockType != 1)
				{
					if ((int)lockType == 2)
					{
						result = LockType.Hackable;
					}
				}
				else
				{
					result = LockType.Melee;
				}
			}
			return result;
		}

		public rWeakDoor(LG_WeakDoor door)
			: base(((Object)door.Gate).GetInstanceID())
		{
			this.door = door;
			damageTaken = door.m_healthMax;
			LG_WeakDoor_Destruction val = ((Il2CppObjectBase)door.m_destruction).TryCast<LG_WeakDoor_Destruction>();
			if ((Object)(object)val == (Object)null)
			{
				throw new NoDoorDestructionComp("Failed to get 'LG_WeakDoor_Destruction'.");
			}
			destruction = val;
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			prevHealth = health;
			_lock0 = lock0;
			_lock1 = lock1;
			BitHelper.WriteBytes(prevHealth, buffer);
			if (((Component)((Il2CppArrayBase<Transform>)(object)door.m_buttonAligns)[0]).transform.localPosition.z < 0f)
			{
				BitHelper.WriteBytes(_lock0, buffer);
				BitHelper.WriteBytes(_lock1, buffer);
			}
			else
			{
				BitHelper.WriteBytes(_lock1, buffer);
				BitHelper.WriteBytes(_lock0, buffer);
			}
		}

		public override void Spawn(ByteBuffer buffer)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			_lock0 = lock0;
			_lock1 = lock1;
			BitHelper.WriteHalf(door.m_healthMax, buffer);
			if (((Component)((Il2CppArrayBase<Transform>)(object)door.m_buttonAligns)[0]).transform.localPosition.z < 0f)
			{
				BitHelper.WriteBytes(_lock0, buffer);
				BitHelper.WriteBytes(_lock1, buffer);
			}
			else
			{
				BitHelper.WriteBytes(_lock1, buffer);
				BitHelper.WriteBytes(_lock0, buffer);
			}
		}
	}
	[ReplayData("Vanilla.Map.Generators.State", "0.0.1")]
	internal class rGenerator : ReplayDynamic
	{
		public LG_PowerGenerator_Core core;

		private bool _powered;

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

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

		public byte dimensionIndex => (byte)core.SpawnNode.m_dimension.DimensionIndex;

		public ushort serialNumber => (ushort)core.m_serialNumber;

		public override bool Active => (Object)(object)core != (Object)null;

		public override bool IsDirty => _powered != powered;

		private bool powered => (int)core.m_stateReplicator.State.status == 0;

		public rGenerator(LG_PowerGenerator_Core generator)
			: base(((Object)generator).GetInstanceID())
		{
			core = generator;
		}

		public override void Write(ByteBuffer buffer)
		{
			_powered = powered;
			BitHelper.WriteBytes(_powered, buffer);
		}

		public override void Spawn(ByteBuffer buffer)
		{
			((ReplayDynamic)this).Write(buffer);
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.Generators", "0.0.1")]
	internal class rGenerators : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_PowerGenerator_Core), "Setup")]
			[HarmonyPostfix]
			private static void Setup(LG_PowerGenerator_Core __instance)
			{
				rGenerator rGenerator2 = new rGenerator(__instance);
				generators.Add(((ReplayDynamic)rGenerator2).id, rGenerator2);
			}
		}

		internal static Dictionary<int, rGenerator> generators = new Dictionary<int, rGenerator>();

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rGenerators());
			foreach (rGenerator value in generators.Values)
			{
				if (((Behaviour)((Il2CppObjectBase)value.core.m_powerCellInteraction).Cast<LG_GenericCarryItemInteractionTarget>()).isActiveAndEnabled)
				{
					Replay.Spawn((ReplayDynamic)(object)value, true);
				}
			}
			generators.Clear();
		}

		[ReplayInit]
		private static void Init()
		{
			generators.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0043: 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)
			BitHelper.WriteBytes((ushort)generators.Count, buffer);
			foreach (rGenerator value in generators.Values)
			{
				BitHelper.WriteBytes(((ReplayDynamic)value).id, buffer);
				BitHelper.WriteBytes(value.dimensionIndex, buffer);
				BitHelper.WriteBytes(value.position, buffer);
				BitHelper.WriteHalf(value.rotation, buffer);
				BitHelper.WriteBytes(value.serialNumber, buffer);
			}
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.Items", "0.0.1")]
	internal class rItem : ReplayDynamic
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_PickupItem_Sync), "Setup")]
			[HarmonyPostfix]
			private static void Postfix_Setup(LG_PickupItem_Sync __instance)
			{
				Replay.Spawn((ReplayDynamic)(object)new rItem(__instance), true);
			}
		}

		private LG_PickupItem_Sync item;

		private byte _dimensionIndex;

		private Vector3 _position;

		private Quaternion _rotation;

		private bool _onGround;

		private bool _linkedToMachine;

		private byte _player = byte.MaxValue;

		private ushort _serialNumber = ushort.MaxValue;

		public override bool Active => (Object)(object)item != (Object)null;

		public override bool IsDirty
		{
			get
			{
				//IL_000f: 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_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				if (dimensionIndex == _dimensionIndex && !(position != _position) && !(rotation != _rotation) && onGround == _onGround && linkedToMachine == _linkedToMachine)
				{
					return serialNumber != _serialNumber;
				}
				return true;
			}
		}

		private byte dimensionIndex
		{
			get
			{
				//IL_000b: 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_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				pPickupItemState state = item.m_stateReplicator.State;
				AIG_CourseNode val = default(AIG_CourseNode);
				if (((pCourseNode)(ref state.placement.node)).TryGet(ref val))
				{
					return (byte)val.m_dimension.DimensionIndex;
				}
				return (byte)Dimension.GetDimensionFromPos(position).DimensionIndex;
			}
		}

		private Vector3 position => item.m_stateReplicator.State.placement.position;

		private Quaternion rotation => item.m_stateReplicator.State.placement.rotation;

		private bool onGround
		{
			get
			{
				//IL_000b: 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_0022: 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)
				if ((int)item.m_stateReplicator.State.status != 0)
				{
					return item.m_stateReplicator.State.placement.droppedOnFloor;
				}
				return true;
			}
		}

		private bool linkedToMachine => item.m_stateReplicator.State.placement.linkedToMachine;

		private byte player
		{
			get
			{
				//IL_000b: 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)
				pPickupItemState state = item.m_stateReplicator.State;
				SNet_Player val = default(SNet_Player);
				if (((pPlayer)(ref state.pPlayer)).TryGetPlayer(ref val))
				{
					return (byte)val.PlayerSlotIndex();
				}
				return byte.MaxValue;
			}
		}

		private ushort serialNumber
		{
			get
			{
				CarryItemPickup_Core val = ((Il2CppObjectBase)item.item).TryCast<CarryItemPickup_Core>();
				if ((Object)(object)val != (Object)null)
				{
					if (((Item)val).ItemDataBlock.addSerialNumberToName)
					{
						return (ushort)val.m_serialNumber;
					}
					return ushort.MaxValue;
				}
				ResourcePackPickup val2 = ((Il2CppObjectBase)item.item).TryCast<ResourcePackPickup>();
				if ((Object)(object)val2 != (Object)null)
				{
					if (((Item)val2).ItemDataBlock.addSerialNumberToName)
					{
						return (ushort)val2.m_serialNumber;
					}
					return ushort.MaxValue;
				}
				GenericSmallPickupItem_Core val3 = ((Il2CppObjectBase)item.item).TryCast<GenericSmallPickupItem_Core>();
				if ((Object)(object)val3 != (Object)null)
				{
					if (((Item)val3).ItemDataBlock.addSerialNumberToName)
					{
						return (ushort)val3.m_serialNumber1;
					}
					return ushort.MaxValue;
				}
				KeyItemPickup_Core val4 = ((Il2CppObjectBase)item.item).TryCast<KeyItemPickup_Core>();
				if ((Object)(object)val4 != (Object)null && val4.m_keyItem != null)
				{
					if (((Item)val4).ItemDataBlock.addSerialNumberToName)
					{
						return (ushort)val4.m_keyItem.m_keyNum;
					}
					return ushort.MaxValue;
				}
				return ushort.MaxValue;
			}
		}

		public rItem(LG_PickupItem_Sync item)
			: base((int)item.m_stateReplicator.Replicator.Key)
		{
			this.item = item;
		}

		public override void Write(ByteBuffer buffer)
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			_dimensionIndex = dimensionIndex;
			_position = position;
			_rotation = rotation;
			_onGround = onGround;
			_linkedToMachine = linkedToMachine;
			_player = player;
			_serialNumber = serialNumber;
			BitHelper.WriteBytes(_dimensionIndex, buffer);
			BitHelper.WriteBytes(_position, buffer);
			BitHelper.WriteHalf(_rotation, buffer);
			BitHelper.WriteBytes(_onGround, buffer);
			BitHelper.WriteBytes(_linkedToMachine, buffer);
			BitHelper.WriteBytes(_player, buffer);
			BitHelper.WriteBytes(_serialNumber, buffer);
		}

		public override void Spawn(ByteBuffer buffer)
		{
			((ReplayDynamic)this).Write(buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)Identifier.From(item.item), buffer);
		}
	}
	internal class rLadder
	{
		public readonly byte dimension;

		private LG_Ladder ladder;

		public Vector3 top => ladder.m_ladderTop;

		public float height => ladder.m_height;

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

		public rLadder(byte dimension, LG_Ladder ladder)
		{
			this.dimension = dimension;
			this.ladder = ladder;
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.Ladders", "0.0.1")]
	internal class rLadders : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_BuildLadderAIGNodeJob), "Build")]
			[HarmonyPostfix]
			private static void Ladder_OnBuild(LG_BuildLadderAIGNodeJob __instance)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				LG_Ladder ladder = __instance.m_ladder;
				if (!ladder.m_enemyClimbingOnly)
				{
					ladders.Add(new rLadder((byte)__instance.m_dimensionIndex, ladder));
				}
			}
		}

		internal static List<rLadder> ladders = new List<rLadder>();

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rLadders());
		}

		[ReplayInit]
		private static void Init()
		{
			ladders.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			BitHelper.WriteBytes((ushort)ladders.Count, buffer);
			foreach (rLadder ladder in ladders)
			{
				BitHelper.WriteBytes(ladder.dimension, buffer);
				BitHelper.WriteBytes(ladder.top, buffer);
				BitHelper.WriteHalf(ladder.rotation, buffer);
				BitHelper.WriteHalf(ladder.height, buffer);
			}
			ladders.Clear();
		}
	}
	[ReplayData("Vanilla.Map.ResourceContainers.State", "0.0.1")]
	internal class rContainer : ReplayDynamic
	{
		private LG_ResourceContainer_Storage container;

		private LG_WeakResourceContainer core;

		private LG_ResourceContainer_Sync sync;

		public bool registered = true;

		public Identifier consumableType = Identifier.unknown;

		public eWeakLockType assignedLock;

		public bool isLocker;

		public byte dimension;

		public Vector3 position;

		public Quaternion rotation;

		private bool _closed = true;

		public ushort serialNumber => (ushort)core.m_serialNumber;

		public override bool Active => (Object)(object)core != (Object)null;

		public override bool IsDirty => _closed != closed;

		private bool closed => (int)sync.m_stateReplicator.State.status != 3;

		private bool weaklock
		{
			get
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Invalid comparison between Unknown and I4
				if ((Object)(object)core.m_weakLock != (Object)null)
				{
					return (int)core.m_weakLock.Status == 0;
				}
				return false;
			}
		}

		private bool hacklock
		{
			get
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Invalid comparison between Unknown and I4
				if ((Object)(object)core.m_weakLock != (Object)null)
				{
					return (int)core.m_weakLock.Status == 1;
				}
				return false;
			}
		}

		public rContainer(LG_ResourceContainer_Storage container, bool isLocker, byte dimension)
			: base(((Object)container).GetInstanceID())
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			this.container = container;
			this.isLocker = isLocker;
			this.dimension = dimension;
			core = ((Il2CppObjectBase)container.m_core).Cast<LG_WeakResourceContainer>();
			sync = ((Il2CppObjectBase)core.m_sync).Cast<LG_ResourceContainer_Sync>();
			position = ((Component)container).transform.position;
			rotation = ((Component)container).transform.rotation;
		}

		public override void Write(ByteBuffer buffer)
		{
			_closed = closed;
			BitHelper.WriteBytes(_closed, buffer);
		}

		public override void Spawn(ByteBuffer buffer)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			((ReplayDynamic)this).Write(buffer);
			eWeakLockType val = (eWeakLockType)0;
			if ((Object)(object)core.m_weakLock != (Object)null)
			{
				eWeakLockStatus status = core.m_weakLock.Status;
				if ((int)status != 0)
				{
					if ((int)status == 1)
					{
						val = (eWeakLockType)2;
					}
				}
				else
				{
					val = (eWeakLockType)1;
				}
			}
			BitHelper.WriteBytes((byte)val, buffer);
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.ResourceContainers", "0.0.3")]
	internal class rContainers : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			private static void SetupContainer(AIG_CourseNode node, rContainer container)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				container.dimension = (byte)node.m_dimension.DimensionIndex;
			}

			[HarmonyPatch(typeof(LG_ResourceContainerBuilder), "SetupFunctionGO")]
			[HarmonyPostfix]
			private static void OnBuild(LG_ResourceContainerBuilder __instance, LG_LayerType layer, GameObject GO)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Invalid comparison between Unknown and I4
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Expected O, but got Unknown
				if ((int)((LG_FunctionMarkerBuilder)__instance).m_function != 10)
				{
					return;
				}
				LG_WeakResourceContainer componentInChildren = GO.GetComponentInChildren<LG_WeakResourceContainer>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					return;
				}
				LG_ResourceContainer_Storage val = ((Il2CppObjectBase)componentInChildren.m_storage).Cast<LG_ResourceContainer_Storage>();
				int instanceID = ((Object)val).GetInstanceID();
				if (!containers.ContainsKey(instanceID))
				{
					containers.Add(instanceID, new rContainer(val, isLocker: false, 0));
				}
				rContainer rContainer2 = containers[instanceID];
				rContainer2.assignedLock = (eWeakLockType)((!(__instance.m_lockRandom < 0.5f)) ? 1 : 2);
				ConsumableDistributionDataBlock block = GameDataBlockBase<ConsumableDistributionDataBlock>.GetBlock(((LG_FunctionMarkerBuilder)__instance).m_node.m_zone.m_settings.m_zoneData.ConsumableDistributionInZone);
				if (block != null)
				{
					Random.InitState(__instance.m_randomSeed);
					float[] array = new float[block.SpawnData.Count];
					for (int i = 0; i < block.SpawnData.Count; i++)
					{
						array[i] = block.SpawnData[i].Weight;
					}
					BuilderWeightedRandom val2 = new BuilderWeightedRandom();
					val2.Setup(Il2CppStructArray<float>.op_Implicit(array));
					rContainer2.consumableType = Identifier.Item(block.SpawnData[val2.GetRandomIndex(Random.value)].ItemID);
				}
			}

			[HarmonyPatch(typeof(AIG_CourseNode), "RegisterContainer")]
			[HarmonyPostfix]
			private static void ResourceContainer_Add(AIG_CourseNode __instance, LG_ResourceContainer_Storage container)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				int instanceID = ((Object)container).GetInstanceID();
				if (!containers.ContainsKey(instanceID))
				{
					containers.Add(instanceID, new rContainer(container, isLocker: false, (byte)__instance.m_dimension.DimensionIndex));
				}
				SetupContainer(__instance, containers[instanceID]);
			}

			[HarmonyPatch(typeof(AIG_CourseNode), "UnregisterContainer")]
			[HarmonyPostfix]
			private static void ResourceContainer_Remove(AIG_CourseNode __instance, LG_ResourceContainer_Storage container)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				int instanceID = ((Object)container).GetInstanceID();
				if (!containers.ContainsKey(instanceID))
				{
					containers.Add(instanceID, new rContainer(container, isLocker: false, (byte)__instance.m_dimension.DimensionIndex));
				}
				SetupContainer(__instance, containers[instanceID]);
				containers[instanceID].registered = false;
			}

			[HarmonyPatch(typeof(LG_ResourceContainer_Storage), "Setup")]
			[HarmonyPostfix]
			private static void Resource_Setup(LG_ResourceContainer_Storage __instance, iLG_ResourceContainer_Core core, bool isLocker)
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!containers.ContainsKey(instanceID))
				{
					containers.Add(instanceID, new rContainer(__instance, isLocker: false, 0));
				}
				containers[instanceID].isLocker = isLocker;
			}
		}

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

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rContainers());
			foreach (rContainer value in containers.Values)
			{
				Replay.Spawn((ReplayDynamic)(object)value, true);
			}
			containers.Clear();
		}

		[ReplayInit]
		private static void Init()
		{
			containers.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0043: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			BitHelper.WriteBytes((ushort)containers.Count, buffer);
			foreach (rContainer value in containers.Values)
			{
				BitHelper.WriteBytes(((ReplayDynamic)value).id, buffer);
				BitHelper.WriteBytes(value.dimension, buffer);
				BitHelper.WriteBytes(value.position, buffer);
				BitHelper.WriteHalf(value.rotation, buffer);
				BitHelper.WriteBytes(value.serialNumber, buffer);
				BitHelper.WriteBytes(value.isLocker, buffer);
				BitHelper.WriteBytes((BufferWriteable)(object)value.consumableType, buffer);
				BitHelper.WriteBytes(value.registered, buffer);
				BitHelper.WriteBytes((byte)value.assignedLock, buffer);
			}
		}
	}
	internal class rTerminal
	{
		public readonly byte dimension;

		public readonly int id;

		public readonly ushort serialNumber;

		private LG_ComputerTerminal terminal;

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

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

		public rTerminal(byte dimension, LG_ComputerTerminal terminal)
		{
			id = ((Object)terminal).GetInstanceID();
			this.dimension = dimension;
			this.terminal = terminal;
			serialNumber = (ushort)terminal.m_serialNumber;
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Map.Terminals", "0.0.2")]
	internal class rTerminals : ReplayHeader
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(LG_ComputerTerminal), "Setup")]
			[HarmonyPostfix]
			private static void Terminal_Setup(LG_ComputerTerminal __instance)
			{
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!terminals.ContainsKey(instanceID))
				{
					if (__instance.SpawnNode == null)
					{
						terminals.Add(instanceID, new rTerminal((byte)Dimension.GetDimensionFromPos(((Component)__instance).transform.position).DimensionIndex, __instance));
					}
					else
					{
						terminals.Add(instanceID, new rTerminal((byte)__instance.SpawnNode.m_dimension.DimensionIndex, __instance));
					}
				}
			}
		}

		internal static Dictionary<int, rTerminal> terminals = new Dictionary<int, rTerminal>();

		[ReplayOnElevatorStop]
		private static void Trigger()
		{
			Replay.Trigger((ReplayHeader)(object)new rTerminals());
		}

		[ReplayInit]
		private static void Init()
		{
			terminals.Clear();
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_0043: 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)
			BitHelper.WriteBytes((ushort)terminals.Count, buffer);
			foreach (rTerminal value in terminals.Values)
			{
				BitHelper.WriteBytes(value.id, buffer);
				BitHelper.WriteBytes(value.dimension, buffer);
				BitHelper.WriteBytes(value.position, buffer);
				BitHelper.WriteHalf(value.rotation, buffer);
				BitHelper.WriteBytes(value.serialNumber, buffer);
			}
			terminals.Clear();
		}
	}
}
namespace Vanilla.Sentries
{
	internal struct SentryTransform : IReplayTransform
	{
		private SentryGunInstance sentry;

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

		public byte dimensionIndex => (byte)sentry.CourseNode.m_dimension.DimensionIndex;

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

		public Quaternion rotation
		{
			get
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if (sentry.m_firing != null)
				{
					return Quaternion.LookRotation(sentry.m_firing.MuzzleAlign.forward);
				}
				return ((Component)sentry).transform.rotation;
			}
		}

		public SentryTransform(SentryGunInstance sentry)
		{
			this.sentry = sentry;
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Sentry", "0.0.1")]
	internal class rSentry : DynamicRotation
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPatch(typeof(SentryGunInstance), "OnSpawn")]
			[HarmonyPostfix]
			private static void Postfix_OnSpawn(SentryGunInstance __instance, pGearSpawnData spawnData)
			{
				Replay.Spawn((ReplayDynamic)(object)new rSentry(__instance), true);
			}

			[HarmonyPatch(typeof(SentryGunInstance), "OnDespawn")]
			[HarmonyPostfix]
			private static void Postfix_OnDespawn(SentryGunInstance __instance)
			{
				Replay.Despawn((ReplayDynamic)(object)Replay.Get<rSentry>(((Object)__instance).GetInstanceID()), true);
			}
		}

		private SentryGunInstance sentry;

		private Vector3 spawnPosition;

		private byte spawnDimension;

		public rSentry(SentryGunInstance sentry)
			: base(((Object)sentry).GetInstanceID(), (IReplayTransform)(object)new SentryTransform(sentry))
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			this.sentry = sentry;
			spawnPosition = base.transform.position;
			spawnDimension = base.transform.dimensionIndex;
		}

		public override void Spawn(ByteBuffer buffer)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			BitHelper.WriteBytes(spawnDimension, buffer);
			BitHelper.WriteBytes(spawnPosition, buffer);
			((DynamicRotation)this).Spawn(buffer);
			BitHelper.WriteBytes(((Agent)((Item)sentry).Owner).GlobalID, buffer);
		}
	}
}
namespace Vanilla.Player
{
	[HarmonyPatch]
	internal static class PlayerReplayManager
	{
		[HarmonyPatch]
		private static class SpawningPatches
		{
			[HarmonyPatch(typeof(PlayerSync), "OnSpawn")]
			[HarmonyPostfix]
			private static void OnSpawn(PlayerSync __instance)
			{
				Spawn(__instance.m_agent);
			}

			[HarmonyPatch(typeof(PlayerSync), "OnDespawn")]
			[HarmonyPostfix]
			private static void OnDespawn(PlayerSync __instance)
			{
				Despawn(__instance.m_agent);
			}
		}

		private static List<rPlayer> players = new List<rPlayer>();

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

		[ReplayOnHeaderCompletion]
		private static void Init()
		{
			players.Clear();
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Spawn(enumerator.Current);
			}
		}

		[ReplayTick]
		private static void Tick()
		{
			PlayerAgent[] array = Il2CppArrayBase<PlayerAgent>.op_Implicit(PlayerManager.PlayerAgentsInLevel.ToArray());
			_players.Clear();
			foreach (rPlayer player in players)
			{
				if (!array.Any((PlayerAgent p) => ((Agent)p).GlobalID == ((ReplayDynamic)player).id))
				{
					Despawn(player);
				}
				else
				{
					_players.Add(player);
				}
			}
			List<rPlayer> list = players;
			players = _players;
			_players = list;
			PlayerAgent[] array2 = array;
			foreach (PlayerAgent player2 in array2)
			{
				if (!players.Any((rPlayer p) => ((ReplayDynamic)p).id == ((Agent)player2).GlobalID))
				{
					Spawn(player2);
				}
			}
		}

		private static void Spawn(PlayerAgent agent)
		{
			if (Replay.Ready)
			{
				RemoveAll(agent);
				APILogger.Debug("(SpawnPlayer) " + agent.Owner.NickName + " has joined.");
				rPlayer rPlayer2 = new rPlayer(agent);
				Replay.Spawn((ReplayDynamic)(object)rPlayer2, true);
				Replay.Spawn((ReplayDynamic)(object)new rPlayerAnimation(agent), true);
				Replay.Spawn((ReplayDynamic)(object)new rPlayerBackpack(agent), true);
				Replay.Spawn((ReplayDynamic)(object)new rPlayerStats(agent), true);
				players.Add(rPlayer2);
			}
		}

		private static void Despawn(PlayerAgent agent)
		{
			if (Replay.Ready && Replay.Has<rPlayer>((int)((Agent)agent).GlobalID))
			{
				APILogger.Debug(agent.Owner.NickName + " has left.");
				RemoveAll(agent);
			}
		}

		private static void RemoveAll(PlayerAgent agent)
		{
			PlayerAgent agent2 = agent;
			players.RemoveAll(delegate(rPlayer player)
			{
				int num;
				if (!((Object)(object)player.agent == (Object)null) && !((Object)(object)player.agent.Owner == (Object)null))
				{
					num = ((player.agent.Owner.Lookup == agent2.Owner.Lookup) ? 1 : 0);
					if (num == 0)
					{
						goto IL_004f;
					}
				}
				else
				{
					num = 1;
				}
				Despawn(player);
				goto IL_004f;
				IL_004f:
				return (byte)num != 0;
			});
		}

		private static void Despawn(rPlayer player)
		{
			APILogger.Debug("Despawn duplicate player.");
			Replay.TryDespawn<rPlayerAnimation>(((ReplayDynamic)player).id);
			Replay.TryDespawn<rPlayerBackpack>(((ReplayDynamic)player).id);
			Replay.TryDespawn<rPlayerStats>(((ReplayDynamic)player).id);
			Replay.TryDespawn<rPlayer>(((ReplayDynamic)player).id);
		}
	}
	[ReplayData("Vanilla.Player", "0.0.1")]
	internal class rPlayer : DynamicTransform
	{
		public PlayerAgent agent;

		private Identifier lastEquipped = Identifier.unknown;

		private Identifier equipped => Identifier.From(agent.Inventory.WieldedItem);

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

		public override bool IsDirty
		{
			get
			{
				if (!((DynamicTransform)this).IsDirty)
				{
					return equipped != lastEquipped;
				}
				return true;
			}
		}

		public rPlayer(PlayerAgent player)
			: base((int)((Agent)player).GlobalID, (IReplayTransform)(object)new AgentTransform((Agent)(object)player))
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			agent = player;
		}

		public override void Write(ByteBuffer buffer)
		{
			((DynamicTransform)this).Write(buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)equipped, buffer);
			lastEquipped = equipped;
		}

		public override void Spawn(ByteBuffer buffer)
		{
			((DynamicTransform)this).Spawn(buffer);
			BitHelper.WriteBytes(agent.Owner.Lookup, buffer);
			BitHelper.WriteBytes((byte)agent.PlayerSlotIndex, buffer);
			BitHelper.WriteBytes(agent.Owner.NickName, buffer);
		}
	}
	[ReplayData("Vanilla.Player.Animation.MeleeSwing", "0.0.1")]
	internal class rMeleeSwing : Id
	{
		private bool charged;

		public rMeleeSwing(PlayerAgent player, bool charged = false)
			: base((int)((Agent)player).GlobalID)
		{
			this.charged = charged;
		}

		public override void Write(ByteBuffer buffer)
		{
			((Id)this).Write(buffer);
			BitHelper.WriteBytes(charged, buffer);
		}
	}
	[ReplayData("Vanilla.Player.Animation.MeleeShove", "0.0.1")]
	internal class rMeleeShove : Id
	{
		public rMeleeShove(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
		}
	}
	[ReplayData("Vanilla.Player.Animation.ConsumableThrow", "0.0.1")]
	internal class rConsumableThrow : Id
	{
		public rConsumableThrow(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
		}
	}
	[ReplayData("Vanilla.Player.Animation.Revive", "0.0.1")]
	internal class rRevive : Id
	{
		public rRevive(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
		}
	}
	[ReplayData("Vanilla.Player.Animation.Downed", "0.0.1")]
	internal class rDowned : Id
	{
		public rDowned(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
		}
	}
	[HarmonyPatch]
	[ReplayData("Vanilla.Player.Animation", "0.0.1")]
	internal class rPlayerAnimation : ReplayDynamic
	{
		[HarmonyPatch]
		private static class Patches
		{
			private static bool swingTrigger;

			private static void Trigger(Id e)
			{
				if (Replay.Has<rPlayerAnimation>(e.id))
				{
					Replay.Trigger((ReplayEvent)(object)e);
				}
			}

			[HarmonyPatch(typeof(PLOC_Downed), "OnPlayerRevived")]
			[HarmonyPrefix]
			private static void Prefix_OnPlayerRevived(PLOC_Downed __instance)
			{
				Trigger((Id)(object)new rRevive(((PLOC_Base)__instance).m_owner));
			}

			[HarmonyPatch(typeof(PLOC_Downed), "CommonEnter")]
			[HarmonyPrefix]
			private static void Prefix_CommonEnter(PLOC_Downed __instance)
			{
				Trigger((Id)(object)new rDowned(((PLOC_Base)__instance).m_owner));
			}

			[HarmonyPatch(typeof(PlayerSync), "SendThrowStatus")]
			[HarmonyPrefix]
			private static void Prefix_SendThrowStatus(PlayerSync __instance, StatusEnum status, bool applyLocally)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				if (!applyLocally)
				{
					HandleThrowState(__instance.m_agent, status);
				}
			}

			[HarmonyPatch(typeof(PlayerInventorySynced), "SyncThrowState")]
			[HarmonyPrefix]
			private static void Prefix_SyncThrowState(PlayerInventorySynced __instance, StatusEnum status)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				HandleThrowState(((PlayerInventoryBase)__instance).Owner, status);
			}

			private static void HandleThrowState(PlayerAgent player, StatusEnum status)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Invalid comparison between Unknown and I4
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Invalid comparison between Unknown and I4
				rPlayerAnimation rPlayerAnimation2 = default(rPlayerAnimation);
				if (!Replay.TryGet<rPlayerAnimation>((int)((Agent)player).GlobalID, ref rPlayerAnimation2))
				{
					return;
				}
				rPlayerAnimation rPlayerAnimation3 = rPlayerAnimation2;
				if ((int)status != 1)
				{
					if ((int)status == 2)
					{
						rPlayerAnimation3._chargingThrow = false;
						Trigger((Id)(object)new rConsumableThrow(player));
					}
				}
				else
				{
					rPlayerAnimation3._chargingThrow = true;
				}
			}

			[HarmonyPatch(typeof(MWS_ChargeUp), "Enter")]
			[HarmonyPostfix]
			private static void Postfix_MWS_ChargeUp(MWS_ChargeUp __instance)
			{
				rPlayerAnimation rPlayerAnimation2 = default(rPlayerAnimation);
				if (Replay.TryGet<rPlayerAnimation>((int)((Agent)((Item)((MWS_Base)__instance).m_weapon).Owner).GlobalID, ref rPlayerAnimation2))
				{
					rPlayerAnimation2._chargingMelee = true;
				}
			}

			[HarmonyPatch(typeof(MWS_ChargeUp), "Exit")]
			[HarmonyPostfix]
			private static void Postfix_ReceiveClassItemSync(MWS_ChargeUp __instance)
			{
				rPlayerAnimation rPlayerAnimation2 = default(rPlayerAnimation);
				if (Replay.TryGet<rPlayerAnimation>((int)((Agent)((Item)((MWS_Base)__instance).m_weapon).Owner).GlobalID, ref rPlayerAnimation2))
				{
					rPlayerAnimation2._chargingMelee = false;
				}
			}

			[HarmonyPatch(typeof(MWS_AttackLight), "Enter")]
			[HarmonyPostfix]
			private static void Postfix_MWS_AttackLight_Enter(MWS_AttackLight __instance)
			{
				swingTrigger = false;
			}

			[HarmonyPatch(typeof(MWS_AttackLight), "UpdateStateInput")]
			[HarmonyPostfix]
			private static void Postfix_MWS_AttackLight(MWS_AttackLight __instance)
			{
				if ((!__instance.m_canCharge || !((ItemEquippable)((MWS_Base)__instance).m_weapon).FireButton) && !swingTrigger)
				{
					Trigger((Id)(object)new rMeleeSwing(((Item)((MWS_Base)__instance).m_weapon).Owner));
					swingTrigger = true;
				}
			}

			[HarmonyPatch(typeof(MWS_AttackHeavy), "Enter")]
			[HarmonyPostfix]
			private static void Postfix_MWS_AttackHeavy(MWS_AttackHeavy __instance)
			{
				Trigger((Id)(object)new rMeleeSwing(((Item)((MWS_Base)__instance).m_weapon).Owner, charged: true));
			}

			[HarmonyPatch(typeof(MeleeWeaponThirdPerson), "OnWield")]
			[HarmonyPrefix]
			private static void Prefix_ReceiveClassItemSync(MeleeWeaponThirdPerson __instance)
			{
				rPlayerAnimation rPlayerAnimation2 = default(rPlayerAnimation);
				if (Replay.TryGet<rPlayerAnimation>((int)((Agent)((Item)__instance).Owner).GlobalID, ref rPlayerAnimation2))
				{
					rPlayerAnimation obj = rPlayerAnimation2;
					obj.meleeWeaponThirdPerson = __instance;
					obj._chargingMelee = false;
				}
			}

			[HarmonyPatch(typeof(MeleeWeaponThirdPerson), "ReceiveClassItemSync")]
			[HarmonyPrefix]
			private static void Prefix_ReceiveClassItemSync(MeleeWeaponThirdPerson __instance, pSimpleItemSyncData data)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				rPlayerAnimation rPlayerAnimation2 = default(rPlayerAnimation);
				if (!Replay.TryGet<rPlayerAnimation>((int)((Agent)((Item)__instance).Owner).GlobalID, ref rPlayerAnimation2))
				{
					return;
				}
				rPlayerAnimation rPlayerAnimation3 = rPlayerAnimation2;
				rPlayerAnimation3.meleeWeaponThirdPerson = __instance;
				if (data.inFireMode)
				{
					rPlayerAnimation3._chargingMelee = false;
					if (__instance.m_inChargeAnim)
					{
						Trigger((Id)(object)new rMeleeSwing(((Item)__instance).Owner, charged: true));
					}
					else
					{
						Trigger((Id)(object)new rMeleeSwing(((Item)__instance).Owner));
					}
				}
				else if (data.inAimMode)
				{
					rPlayerAnimation3._chargingMelee = true;
				}
			}

			[HarmonyPatch(typeof(MWS_Push), "Enter")]
			[HarmonyPostfix]
			private static void Postfix_MWS_Push(MWS_Push __instance)
			{
				Trigger((Id)(object)new rMeleeShove(((Item)((MWS_Base)__instance).m_weapon).Owner));
			}

			[HarmonyPatch(typeof(PlayerInventorySynced), "SyncGenericInteract")]
			[HarmonyPrefix]
			private static void Prefix_SyncGenericInteract(PlayerInventorySynced __instance, TypeEnum type)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Invalid comparison between Unknown and I4
				if ((int)type == 7)
				{
					Trigger((Id)(object)new rMeleeShove(((PlayerInventoryBase)__instance).Owner));
				}
			}
		}

		public PlayerAgent player;

		private Animator animator;

		private MeleeWeaponThirdPerson? meleeWeaponThirdPerson;

		private byte velFwd;

		private byte velRight;

		private byte crouch;

		private Vector3 targetLookDir;

		private const long landAnimDuration = 867L;

		private long landTriggered;

		private byte _state;

		private byte state;

		private bool _chargingMelee;

		private bool chargingMelee;

		private bool _chargingThrow;

		private bool chargingThrow;

		private bool isReloading;

		private float reloadTime;

		private Identifier lastEquipped = Identifier.unknown;

		public override bool Active => (Object)(object)player != (Object)null;

		public override bool IsDirty
		{
			get
			{
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Invalid comparison between I4 and Unknown
				if (equipped != lastEquipped)
				{
					_chargingMelee = false;
					_chargingThrow = false;
					lastEquipped = equipped;
				}
				if ((Object)(object)meleeWeaponThirdPerson != (Object)null)
				{
					_chargingMelee = meleeWeaponThirdPerson.m_inChargeAnim;
				}
				bool num = velFwd != compress(_velFwd, 10f) || velRight != compress(_velRight, 10f);
				bool flag = crouch != (byte)(_crouch * 255f);
				bool flag2 = targetLookDir != ((Agent)player).TargetLookDir;
				if (!(num || flag || flag2) && state == (int)player.Locomotion.m_currentStateEnum && chargingMelee == _chargingMelee && chargingThrow == _chargingThrow)
				{
					return isReloading != _isReloading;
				}
				return true;
			}
		}

		private float _velFwd => animator.GetFloat("MoveBackwardForward");

		private float _velRight => animator.GetFloat("MoveLeftRight");

		private float _crouch => animator.GetFloat("Crouch");

		private bool _isReloading
		{
			get
			{
				if ((Object)(object)player.Inventory == (Object)null)
				{
					return false;
				}
				if ((Object)(object)player.Inventory.m_wieldedItem == (Object)null)
				{
					return false;
				}
				if (!player.Inventory.m_wieldedItem.CanReload)
				{
					return false;
				}
				return player.Inventory.m_wieldedItem.IsReloading;
			}
		}

		private float _reloadTime
		{
			get
			{
				if ((Object)(object)player.Inventory == (Object)null)
				{
					return 0f;
				}
				if ((Object)(object)player.Inventory.m_wieldedItem == (Object)null)
				{
					return 0f;
				}
				if (!player.Inventory.m_wieldedItem.CanReload)
				{
					return 0f;
				}
				return player.Inventory.m_wieldedItem.ReloadTime;
			}
		}

		private Identifier equipped => Identifier.From(player.Inventory.WieldedItem);

		private static byte compress(float value, float max)
		{
			value /= max;
			value = Mathf.Clamp(value, -1f, 1f);
			value = Mathf.Clamp01((value + 1f) / 2f);
			return (byte)(value * 255f);
		}

		public rPlayerAnimation(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
			this.player = player;
			animator = player.AnimatorBody;
		}

		public override void Write(ByteBuffer buffer)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected I4, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Invalid comparison between Unknown and I4
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			velRight = compress(_velRight, 10f);
			velFwd = compress(_velFwd, 10f);
			BitHelper.WriteBytes(velRight, buffer);
			BitHelper.WriteBytes(velFwd, buffer);
			crouch = (byte)(_crouch * 255f);
			BitHelper.WriteBytes(crouch, buffer);
			targetLookDir = ((Agent)player).TargetLookDir;
			BitHelper.WriteHalf(targetLookDir, buffer);
			if (Raudy.Now - landTriggered > 867 || state != 5 || (int)player.Locomotion.m_currentStateEnum == 3 || (int)player.Locomotion.m_currentStateEnum == 4)
			{
				state = (byte)(int)player.Locomotion.m_currentStateEnum;
				if ((_state == 3 || _state == 4) && state != 3 && state != 4)
				{
					landTriggered = Raudy.Now;
					state = 5;
				}
			}
			_state = state;
			BitHelper.WriteBytes(state, buffer);
			chargingMelee = _chargingMelee;
			BitHelper.WriteBytes(chargingMelee, buffer);
			chargingThrow = _chargingThrow;
			BitHelper.WriteBytes(chargingThrow, buffer);
			isReloading = _isReloading;
			BitHelper.WriteBytes(isReloading, buffer);
			reloadTime = _reloadTime;
			BitHelper.WriteHalf(reloadTime, buffer);
		}

		public override void Spawn(ByteBuffer buffer)
		{
			((ReplayDynamic)this).Write(buffer);
		}
	}
	[ReplayData("Vanilla.Player.Backpack", "0.0.2")]
	internal class rPlayerBackpack : ReplayDynamic
	{
		public PlayerAgent agent;

		private Identifier lastMelee = Identifier.unknown;

		private Identifier lastPrimary = Identifier.unknown;

		private Identifier lastSpecial = Identifier.unknown;

		private Identifier lastTool = Identifier.unknown;

		private Identifier lastPack = Identifier.unknown;

		private Identifier lastConsumable = Identifier.unknown;

		private Identifier lastHeavyItem = Identifier.unknown;

		private Identifier lastHackingTool = Identifier.unknown;

		private Identifier lastVanityHelmet = Identifier.unknown;

		private Identifier lastVanityTorso = Identifier.unknown;

		private Identifier lastVanityLegs = Identifier.unknown;

		private Identifier lastVanityBackpack = Identifier.unknown;

		private Identifier lastVanityPallete = Identifier.unknown;

		private Identifier melee => GetSlotId((InventorySlot)10);

		private Identifier primary => GetSlotId((InventorySlot)1);

		private Identifier special => GetSlotId((InventorySlot)2);

		private Identifier tool => GetSlotId((InventorySlot)3);

		private Identifier pack => GetSlotId((InventorySlot)4);

		private Identifier consumable => GetSlotId((InventorySlot)5);

		private Identifier heavyItem => GetSlotId((InventorySlot)8);

		private Identifier hackingTool => GetSlotId((InventorySlot)11);

		private Identifier vanityHelmet => GetVanityItem((ClothesType)0);

		private Identifier vanityTorso => GetVanityItem((ClothesType)1);

		private Identifier vanityLegs => GetVanityItem((ClothesType)2);

		private Identifier vanityBackpack => GetVanityItem((ClothesType)3);

		private Identifier vanityPallete => GetVanityItem((ClothesType)4);

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

		public override bool IsDirty
		{
			get
			{
				if (!(melee != lastMelee) && !(primary != lastPrimary) && !(special != lastSpecial) && !(tool != lastTool) && !(pack != lastPack) && !(consumable != lastConsumable) && !(heavyItem != lastHeavyItem) && !(hackingTool != lastHackingTool) && !(vanityHelmet != lastVanityHelmet) && !(vanityTorso != lastVanityTorso) && !(vanityLegs != lastVanityLegs) && !(vanityBackpack != lastVanityBackpack))
				{
					return vanityPallete != lastVanityPallete;
				}
				return true;
			}
		}

		private Identifier GetSlotId(InventorySlot slot)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				BackpackItem val = default(BackpackItem);
				if (PlayerBackpackManager.TryGetItem(agent.Owner, slot, ref val) && (Object)(object)val.Instance != (Object)null)
				{
					return Identifier.From(((Il2CppObjectBase)val.Instance).Cast<ItemEquippable>());
				}
			}
			catch
			{
			}
			return Identifier.unknown;
		}

		private Identifier GetVanityItem(ClothesType type)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected I4, but got Unknown
			try
			{
				PlayerBackpack backpack = PlayerBackpackManager.GetBackpack(agent.Owner);
				if (backpack != null)
				{
					return Identifier.Vanity(((Il2CppArrayBase<uint>)(object)backpack.m_vanityItems)[(int)type]);
				}
			}
			catch
			{
			}
			return Identifier.unknown;
		}

		public rPlayerBackpack(PlayerAgent player)
			: base((int)((Agent)player).GlobalID)
		{
			agent = player;
		}

		public override void Write(ByteBuffer buffer)
		{
			lastMelee = melee;
			lastPrimary = primary;
			lastSpecial = special;
			lastTool = tool;
			lastPack = pack;
			lastConsumable = consumable;
			lastHeavyItem = heavyItem;
			lastHackingTool = hackingTool;
			lastVanityHelmet = vanityHelmet;
			lastVanityTorso = vanityTorso;
			lastVanityLegs = vanityLegs;
			lastVanityBackpack = vanityBackpack;
			lastVanityPallete = vanityPallete;
			BitHelper.WriteBytes((BufferWriteable)(object)lastMelee, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastPrimary, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastSpecial, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastTool, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastPack, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastConsumable, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastHeavyItem, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastHackingTool, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastVanityHelmet, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastVanityTorso, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastVanityLegs, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastVanityBackpack, buffer);
			BitHelper.WriteBytes((BufferWriteable)(object)lastVanityPallete, buffer);
		}

		public override void Spawn(ByteBuffer buffer)
		{
			((ReplayDynamic)this).Write(buffer);
		}
	}
	[ReplayData("Vanilla.Player.Stats", "0.0.2")]
	internal class rPlayerStats : ReplayDynamic
	{
		public PlayerAgent player;

		private PlayerBackpack backpack;

		private byte oldHealth = byte.MaxValue;

		private byte oldInfection = byte.MaxValue;

		private byte oldPrimaryAmmo = byte.MaxValue;

		private byte oldSecondaryAmmo = byte.MaxValue;

		private byte oldToolAmmo = byte.MaxValue;

		private byte oldConsumableAmmo = byte.MaxValue;

		private byte oldResourceAmmo = byte.MaxValue;

		public override bool Active => (Object)(object)player != (Object)null;

		public override bool IsDirty
		{
			get
			{
				if (health == oldHealth && infection == oldInfection && primaryAmmo == oldPrimaryAmmo && secondaryAmmo == oldSecondaryAmmo && toolAmmo == oldToolAmmo && consumableAmmo == oldConsumableAmmo)
				{
					return resourceAmmo != oldResourceAmmo;
				}
				return true;
			}
		}

		private byte health => (byte)(255f * ((Dam_SyncedDamageBase)player.Damage).Health / ((Dam_SyncedDamageBase)player.Damage).HealthMax);

		private byte infection => (byte)(255f * player.Damage.Infection);

		private byte primaryAmmo
		{
			get
			{
				InventorySlotAmmo inventorySlotAmmo = backpack.AmmoStorage.GetInventorySlotAmmo((AmmoType)0);
				BackpackItem val = default(BackpackItem);
				if (backpack.TryGetBackpackItem((InventorySlot)1, ref val))
				{
					ItemEquippable val2 = ((Il2CppObjectBase)val.Instance).TryCast<ItemEquippable>();
					if ((Object)(object)val2 != (Object)null)
					{
						return (byte)(255f * (float)(inventorySlotAmmo.BulletsInPack + val2.GetCurrentClip()) * inventorySlotAmmo.BulletsToRelConv);
					}
				}
				return (byte)(255f * inventorySlotAmmo.RelInPack);
			}
		}

		private byte secondaryAmmo
		{
			get
			{
				InventorySlotAmmo inventorySlotAmmo = backpack.AmmoStorage.GetInventor