Decompiled source of GTFOReplay v0.2.9
ReplayRecorder.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
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
The result has been truncated due to the large size, download it to view full contents!
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