Decompiled source of Entanglement Redux v2.0.0

EntanglementRedux.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using Entanglement;
using Entanglement.Compat;
using Entanglement.Compat.Playermodels;
using Entanglement.Data;
using Entanglement.Exceptions;
using Entanglement.Extensions;
using Entanglement.Gamemodes;
using Entanglement.Gamemodes.BuiltIn;
using Entanglement.Managers;
using Entanglement.Modularity;
using Entanglement.Network;
using Entanglement.Objects;
using Entanglement.Patching;
using Entanglement.Representation;
using Entanglement.Sync;
using Entanglement.UI;
using Entanglement.Voice;
using HarmonyLib;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Preferences;
using ModThatIsNotMod;
using ModThatIsNotMod.BoneMenu;
using PuppetMasta;
using Steamworks;
using StressLevelZero;
using StressLevelZero.AI;
using StressLevelZero.Arena;
using StressLevelZero.Combat;
using StressLevelZero.Data;
using StressLevelZero.Interaction;
using StressLevelZero.Player;
using StressLevelZero.Pool;
using StressLevelZero.Props;
using StressLevelZero.Props.Weapons;
using StressLevelZero.Rig;
using StressLevelZero.SFX;
using StressLevelZero.Utilities;
using StressLevelZero.VRMK;
using StressLevelZero.Zones;
using TMPro;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: Guid("490e160d-251d-4ab4-a3bb-f473961ff8a1")]
[assembly: AssemblyTitle("Entanglement Redux")]
[assembly: AssemblyFileVersion("0.4.0")]
[assembly: MelonInfo(typeof(EntanglementMod), "Entanglement Redux", "0.4.0", "willpsdk", null)]
[assembly: MelonGame("Stress Level Zero", "BONEWORKS")]
[assembly: MelonIncompatibleAssemblies(new string[] { "MultiplayerMod" })]
[assembly: MelonPriority(-10000)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.4.0.0")]
namespace Entanglement
{
	public static class EntangleLogger
	{
		public static void Log(string txt, ConsoleColor txt_color = ConsoleColor.White)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Msg(txt_color, txt);
		}

		public static void Log(object obj, ConsoleColor txt_color = ConsoleColor.White)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Msg(txt_color, obj);
		}

		public static void Warn(string txt)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Warning(txt);
		}

		public static void Warn(object obj)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Warning(obj);
		}

		public static void Error(string txt)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Error(txt);
		}

		public static void Error(object obj)
		{
			((MelonBase)EntanglementMod.Instance).LoggerInstance.Error(obj);
		}
	}
	public static class EntangleNotif
	{
		public static void PlayerJoin(string username)
		{
			Notifications.SendNotification(username + " has joined the server!", 4f);
		}

		public static void PlayerLeave(string username)
		{
			Notifications.SendNotification(username + " has left the server!", 4f);
		}

		public static void PlayerDisconnect(DisconnectReason reason)
		{
			Notifications.SendNotification($"You were disconnected for reason {reason}.", 4f);
		}

		public static void LobbyStarted()
		{
			Notifications.SendNotification("Lobby started!", 4f);
		}

		public static void JoinServer(string username)
		{
			Notifications.SendNotification("Joined " + username + "'s server!", 4f);
		}

		public static void LeftServer()
		{
			Notifications.SendNotification("You left the server.", 4f);
		}

		public static void InvalidSteam()
		{
			Notifications.SendNotification("Failed to initialize the Steam API! Continuing without Entanglement!\nMake sure Steam is running, you are logged in, and the game was launched through Steam.", 4f);
		}

		public static void GamemodeStarted(string modeName)
		{
			Notifications.SendNotification(modeName + " has started!", 4f);
		}

		public static void GamemodeEnded(string modeName)
		{
			Notifications.SendNotification(modeName + " round over!", 4f);
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct EntanglementVersion
	{
		public const byte versionMajor = 0;

		public const byte versionMinor = 4;

		public const short versionPatch = 0;

		public const byte minVersionMajorSupported = 0;

		public const byte minVersionMinorSupported = 4;
	}
	public class EntanglementMod : MelonMod
	{
		public static byte? sceneChange;

		public static Assembly entanglementAssembly;

		public static bool hasUnpatched;

		private static float lastUpdateRealtime;

		private const float SUSPEND_GAP_SECONDS = 3f;

		public static EntanglementMod Instance { get; protected set; }

		public static string VersionString { get; protected set; }

		static EntanglementMod()
		{
			sceneChange = null;
			hasUnpatched = false;
			lastUpdateRealtime = 0f;
			AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) => (new AssemblyName(args.Name).Name == "Steamworks.NET") ? Assembly.Load(EmbeddedResource.LoadFromAssembly(Assembly.GetExecutingAssembly(), "Entanglement.resources.Steamworks.NET.dll")) : null;
		}

		public override void OnApplicationStart()
		{
			entanglementAssembly = Assembly.GetExecutingAssembly();
			Instance = this;
			VersionString = $"{(byte)0}.{(byte)4}.{(short)0}";
			EntangleLogger.Log("Current Entanglement version is " + VersionString);
			EntangleLogger.Log($"Minimum supported Entanglement version is {(byte)0}.{(byte)4}.*");
			VersionChecking.CheckModVersion((MelonMod)(object)this, "https://boneworks.thunderstore.io/package/Entanglement/Entanglement/");
			PersistentData.Initialize();
			GameSDK.LoadGameSDK();
			EntangleLogger.Log("Entanglement Debug Build!", ConsoleColor.Blue);
			SteamIntegration.Initialize();
			if (SteamIntegration.isInvalid)
			{
				EntangleNotif.InvalidSteam();
				return;
			}
			Patcher.Initialize();
			NetworkMessage.RegisterHandlersFromAssembly(entanglementAssembly);
			Client.StartClient();
			CustomItemSync.Initialize();
			PlayermodelSync.Initialize();
			GamemodeHandler.Initialize();
			PlayerRepresentation.LoadBundle();
			LoadingScreen.LoadBundle();
			EntanglementUI.CreateUI();
			BanList.PullFromFile();
			EntangleLogger.Log("Welcome to the Entanglement Redux Beta!", ConsoleColor.DarkYellow);
		}

		public override void OnApplicationLateStart()
		{
			if (SteamIntegration.isInvalid)
			{
				((MelonBase)this).HarmonyInstance.UnpatchSelf();
				hasUnpatched = true;
			}
			else
			{
				PlayerDeathManager.Initialize();
			}
		}

		public override void OnUpdate()
		{
			if (SteamIntegration.isInvalid)
			{
				if (!hasUnpatched)
				{
					((MelonBase)this).HarmonyInstance.UnpatchSelf();
					hasUnpatched = true;
				}
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (lastUpdateRealtime > 0f && realtimeSinceStartup - lastUpdateRealtime > 3f)
			{
				EntangleLogger.Log($"App was suspended for {realtimeSinceStartup - lastUpdateRealtime:F1}s, draining the stale network backlog...");
				Node.activeNode?.ClearMessageBuffer();
			}
			lastUpdateRealtime = realtimeSinceStartup;
			TransformSyncBatcher.Flush();
			VoiceManager.Tick();
			ModuleHandler.Update();
			if (Input.GetKeyDown((KeyCode)115))
			{
				Server.StartServer();
			}
			if (Input.GetKeyDown((KeyCode)107))
			{
				Server.instance?.Shutdown();
			}
			if (Input.GetKeyDown((KeyCode)114))
			{
				if (PlayerRepresentation.debugRepresentation == null)
				{
					PlayerRepresentation.debugRepresentation = new PlayerRepresentation("Dummy", 0L);
				}
				else
				{
					PlayerRepresentation.debugRepresentation.CreateRagdoll();
				}
			}
			StatsUI.UpdateUI();
			EntanglementUI.UpdateUI();
			PlayerDeathManager.CheckLethality();
			PlayerRepresentation.SyncPlayerReps();
			FileTransferManager.Tick();
			GamemodeHandler.Tick();
		}

		public override void OnFixedUpdate()
		{
			if (!SteamIntegration.isInvalid)
			{
				ModuleHandler.FixedUpdate();
				PlayerRepresentation.UpdatePlayerReps();
			}
		}

		public override void OnLateUpdate()
		{
			if (!SteamIntegration.isInvalid)
			{
				ModuleHandler.LateUpdate();
				Client.instance?.Tick();
				Server.instance?.Tick();
				SteamIntegration.Tick();
			}
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			if (SteamIntegration.isInvalid)
			{
				return;
			}
			Application.backgroundLoadingPriority = (ThreadPriority)1;
			QualitySettings.asyncUploadTimeSlice = 2;
			QualitySettings.asyncUploadBufferSize = 4;
			ModuleHandler.OnSceneWasInitialized(buildIndex, sceneName);
			SpawnableData.GetData();
			PlayerScripts.GetPlayerScripts();
			PlayerRepresentation.GetPlayerTransforms();
			foreach (PlayerRepresentation value in PlayerRepresentation.representations.Values)
			{
				value.RecreateRepresentations();
			}
			Client.instance.currentScene = (byte)buildIndex;
			if (!LevelChangeAnnouncer.ConsumeAnnounce(buildIndex))
			{
				sceneChange = (byte)buildIndex;
			}
			if (SteamIntegration.hasLobby && !Node.isServer && Node.activeNode != null)
			{
				NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.ClientReady, new EmptyMessageData());
				if (networkMessage != null)
				{
					Node.activeNode.BroadcastMessage(NetworkChannel.Reliable, networkMessage.GetBytes());
				}
			}
			SteamIntegration.targetScene = sceneName.ToLower();
			SteamIntegration.UpdateActivity();
		}

		public override void BONEWORKS_OnLoadingScreen()
		{
			if (!SteamIntegration.isInvalid)
			{
				Application.backgroundLoadingPriority = (ThreadPriority)4;
				QualitySettings.asyncUploadTimeSlice = 8;
				QualitySettings.asyncUploadBufferSize = 16;
				ModuleHandler.OnLoadingScreen();
				LoadingScreen.OverrideScreen();
				ObjectSync.OnCleanup();
				ObjectSync.poolPairs.Clear();
				SceneEventSync.OnSceneCleanup();
				TransformSyncBatcher.Clear();
				Server.instance?.replayedUsers.Clear();
				FileTransferManager.Clear();
				PlayerRepresentation.debugRepresentation = null;
			}
		}

		public override void OnApplicationQuit()
		{
			if (!SteamIntegration.isInvalid)
			{
				ModuleHandler.OnApplicationQuit();
				Node.activeNode.Shutdown();
				SteamIntegration.Shutdown();
			}
		}
	}
}
namespace Entanglement.Voice
{
	public enum VoiceMode : byte
	{
		Proximity,
		Global
	}
	public static class VoiceManager
	{
		private class VoicePlayer
		{
			public AudioSource source;

			public AudioClip clip;

			public int clipSamples;

			public long written;

			public long played;

			public int lastTimeSamples;

			public float lastReceiveTime;
		}

		private struct DelayedVoicePacket
		{
			public byte[] data;

			public int count;

			public float playAt;
		}

		public static bool micEnabled = true;

		public static VoiceMode mode = VoiceMode.Proximity;

		public static int proximityRange = 12;

		public static int outputVolume = 100;

		private const float baseVoiceGain = 2f;

		private static bool recording;

		private static uint sampleRate;

		private static readonly byte[] compressedBuffer = new byte[8192];

		private static readonly byte[] receiveScratch = new byte[8192];

		private static readonly byte[] decompressBuffer = new byte[65536];

		private static float[] sampleBuffer = new float[32768];

		private static readonly Dictionary<int, float[]> chunkPool = new Dictionary<int, float[]>();

		public static float localVoiceTime = -10f;

		private const float speakingWindow = 0.3f;

		private static readonly Dictionary<long, VoicePlayer> players = new Dictionary<long, VoicePlayer>();

		private static readonly HashSet<long> mutedPlayers = new HashSet<long>();

		public static bool debugVoiceOnRep = false;

		private const long debugRepVoiceId = -1337L;

		private const float debugVoiceDelaySeconds = 10f;

		private static readonly Queue<DelayedVoicePacket> debugVoiceQueue = new Queue<DelayedVoicePacket>();

		public static bool IsLocalSpeaking => micEnabled && Time.time - localVoiceTime < 0.3f;

		public static bool IsSpeaking(long userId)
		{
			VoicePlayer value;
			return players.TryGetValue(userId, out value) && Time.time - value.lastReceiveTime < 0.3f;
		}

		public static bool IsMuted(long userId)
		{
			return mutedPlayers.Contains(userId);
		}

		public static void SetMuted(long userId, bool muted)
		{
			if (muted)
			{
				mutedPlayers.Add(userId);
				if (players.TryGetValue(userId, out var value) && Object.op_Implicit((Object)(object)value.source))
				{
					value.source.Stop();
					value.played = value.written;
				}
			}
			else
			{
				mutedPlayers.Remove(userId);
			}
		}

		public static void Tick()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			flag = debugVoiceOnRep && PlayerRepresentation.debugRepresentation != null;
			if (!SteamIntegration.hasLobby && !flag)
			{
				if (recording)
				{
					SteamUser.StopVoiceRecording();
					recording = false;
				}
				if (players.Count > 0)
				{
					Reset();
				}
				return;
			}
			if (sampleRate == 0)
			{
				sampleRate = SteamUser.GetVoiceOptimalSampleRate();
			}
			if (micEnabled && !recording)
			{
				SteamUser.StartVoiceRecording();
				recording = true;
			}
			else if (!micEnabled && recording)
			{
				SteamUser.StopVoiceRecording();
				recording = false;
			}
			if (recording)
			{
				uint num = default(uint);
				EVoiceResult availableVoice = SteamUser.GetAvailableVoice(ref num);
				if ((int)availableVoice == 0 && num != 0)
				{
					uint num2 = default(uint);
					availableVoice = SteamUser.GetVoice(true, compressedBuffer, (uint)compressedBuffer.Length, ref num2);
					if ((int)availableVoice == 0 && num2 != 0)
					{
						if (SteamIntegration.hasLobby)
						{
							VoiceDataMessageHandler.SendVoice(compressedBuffer, (int)num2);
						}
						localVoiceTime = Time.time;
						QueueDebugVoice(compressedBuffer, (int)num2);
					}
				}
			}
			ProcessDebugVoice();
			foreach (VoicePlayer value in players.Values)
			{
				if (Object.op_Implicit((Object)(object)value.source) && value.source.isPlaying)
				{
					int timeSamples = value.source.timeSamples;
					if (timeSamples < value.lastTimeSamples)
					{
						value.played += value.clipSamples - value.lastTimeSamples + timeSamples;
					}
					else
					{
						value.played += timeSamples - value.lastTimeSamples;
					}
					value.lastTimeSamples = timeSamples;
					if (value.played >= value.written)
					{
						value.source.Stop();
					}
				}
			}
		}

		public static void ReceiveVoice(long speakerId, byte[] data, int offset, int count)
		{
			//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)
			if (count <= 0 || count > receiveScratch.Length || mutedPlayers.Contains(speakerId))
			{
				return;
			}
			if (sampleRate == 0)
			{
				sampleRate = SteamUser.GetVoiceOptimalSampleRate();
			}
			Buffer.BlockCopy(data, offset, receiveScratch, 0, count);
			uint num = default(uint);
			EVoiceResult val = SteamUser.DecompressVoice(receiveScratch, (uint)count, decompressBuffer, (uint)decompressBuffer.Length, ref num, sampleRate);
			if ((int)val != 0 || num == 0)
			{
				return;
			}
			VoicePlayer player = GetPlayer(speakerId);
			if (player != null)
			{
				int num2 = (int)num / 2;
				if (sampleBuffer.Length < num2)
				{
					sampleBuffer = new float[num2];
				}
				float num3 = (float)outputVolume / 100f * 2f;
				for (int i = 0; i < num2; i++)
				{
					short num4 = (short)(decompressBuffer[i * 2] | (decompressBuffer[i * 2 + 1] << 8));
					sampleBuffer[i] = Mathf.Clamp((float)num4 / 32768f * num3, -1f, 1f);
				}
				player.lastReceiveTime = Time.time;
				WriteSamples(player, num2);
			}
		}

		private static void WriteSamples(VoicePlayer player, int count)
		{
			int num = (int)(player.written % player.clipSamples);
			int num2 = Math.Min(count, player.clipSamples - num);
			float[] chunk = GetChunk(num2);
			Array.Copy(sampleBuffer, 0, chunk, 0, num2);
			player.clip.SetData(Il2CppStructArray<float>.op_Implicit(chunk), num);
			int num3 = count - num2;
			if (num3 > 0)
			{
				float[] chunk2 = GetChunk(num3);
				Array.Copy(sampleBuffer, num2, chunk2, 0, num3);
				player.clip.SetData(Il2CppStructArray<float>.op_Implicit(chunk2), 0);
			}
			player.written += count;
			if (!player.source.isPlaying && player.written - player.played >= sampleRate / 10)
			{
				int num4 = (int)(player.played % player.clipSamples);
				player.source.timeSamples = num4;
				player.lastTimeSamples = num4;
				player.source.Play();
			}
		}

		private static float[] GetChunk(int size)
		{
			if (!chunkPool.TryGetValue(size, out var value))
			{
				value = new float[size];
				chunkPool[size] = value;
			}
			return value;
		}

		private static VoicePlayer GetPlayer(long speakerId)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			players.TryGetValue(speakerId, out var value);
			if (value != null && Object.op_Implicit((Object)(object)value.source))
			{
				return value;
			}
			PlayerRepresentation playerRepresentation = ResolveRep(speakerId);
			if (playerRepresentation == null || (Object)(object)playerRepresentation.repRoot == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject($"Voice {speakerId}");
			Transform val2 = (Object.op_Implicit((Object)(object)playerRepresentation.repTransforms[0]) ? playerRepresentation.repTransforms[0] : playerRepresentation.repRoot);
			val.transform.SetParent(val2, false);
			AudioSource val3 = val.AddComponent<AudioSource>();
			val3.loop = true;
			val3.playOnAwake = false;
			val3.rolloffMode = (AudioRolloffMode)1;
			val3.dopplerLevel = 0f;
			int num = (int)sampleRate;
			AudioClip clip = (val3.clip = AudioClip.Create($"VoiceClip {speakerId}", num, 1, (int)sampleRate, false));
			value = new VoicePlayer
			{
				source = val3,
				clip = clip,
				clipSamples = num
			};
			players[speakerId] = value;
			ApplySettingsTo(value);
			return value;
		}

		private static PlayerRepresentation ResolveRep(long speakerId)
		{
			if (speakerId == -1337)
			{
				return PlayerRepresentation.debugRepresentation;
			}
			PlayerRepresentation.representations.TryGetValue(speakerId, out var value);
			return value;
		}

		private static void QueueDebugVoice(byte[] compressed, int written)
		{
			if (debugVoiceOnRep && PlayerRepresentation.debugRepresentation != null && written > 0)
			{
				byte[] array = new byte[written];
				Buffer.BlockCopy(compressed, 0, array, 0, written);
				debugVoiceQueue.Enqueue(new DelayedVoicePacket
				{
					data = array,
					count = written,
					playAt = Time.time + 10f
				});
			}
		}

		private static void ProcessDebugVoice()
		{
			if (!debugVoiceOnRep || PlayerRepresentation.debugRepresentation == null)
			{
				if (debugVoiceQueue.Count > 0)
				{
					debugVoiceQueue.Clear();
				}
			}
			else
			{
				while (debugVoiceQueue.Count > 0 && Time.time >= debugVoiceQueue.Peek().playAt)
				{
					DelayedVoicePacket delayedVoicePacket = debugVoiceQueue.Dequeue();
					ReceiveVoice(-1337L, delayedVoicePacket.data, 0, delayedVoicePacket.count);
				}
			}
		}

		public static void ApplySettings()
		{
			foreach (VoicePlayer value in players.Values)
			{
				ApplySettingsTo(value);
			}
		}

		private static void ApplySettingsTo(VoicePlayer player)
		{
			if (Object.op_Implicit((Object)(object)player.source))
			{
				player.source.volume = 1f;
				if (mode == VoiceMode.Global)
				{
					player.source.spatialBlend = 0f;
					return;
				}
				player.source.spatialBlend = 1f;
				player.source.minDistance = 1f;
				player.source.maxDistance = Mathf.Max(2f, (float)proximityRange);
			}
		}

		public static void Reset()
		{
			foreach (VoicePlayer value in players.Values)
			{
				if (Object.op_Implicit((Object)(object)value.source))
				{
					Object.Destroy((Object)(object)((Component)value.source).gameObject);
				}
			}
			players.Clear();
		}
	}
}
namespace Entanglement.Gamemodes
{
	public enum GamemodeEventType : byte
	{
		ReportPlayerKilled = 0,
		RoundStart = 10,
		RoundEnd = 11,
		PlayerKilled = 12,
		PlayerScored = 13,
		PlayerEliminated = 14,
		Custom = 15
	}
	public struct GamemodeState
	{
		public string activeModeId;

		public bool roundActive;

		public float roundTimeRemaining;
	}
	public abstract class EntanglementGamemode
	{
		public abstract string Id { get; }

		public abstract string DisplayName { get; }

		public virtual Color MenuColor => Color.white;

		public virtual bool UsesTeams => false;

		public virtual int TeamCount => 2;

		public virtual bool EliminationMode => false;

		public virtual float DefaultRoundSeconds => 300f;

		public virtual Color GetTeamColor(byte team)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Color.white;
		}

		public virtual void OnModeStart()
		{
		}

		public virtual void OnModeStop()
		{
		}

		public virtual void OnRoundStart()
		{
		}

		public virtual void OnRoundEnd()
		{
		}

		public virtual void HostTick(float deltaTime)
		{
		}

		public virtual void OnPlayerKilled(long killerId, long victimId)
		{
		}

		public virtual void OnPlayerJoined(long userId)
		{
		}

		public virtual void OnPlayerLeft(long userId)
		{
		}

		public virtual void OnStateApplied(GamemodeState state)
		{
		}

		public virtual void OnEventReceived(GamemodeEventType type, long a, long b, int value, string message)
		{
		}

		protected void SetScore(long userId, int score)
		{
			GamemodeHandler.SetScore(userId, score);
		}

		protected void AddScore(long userId, int delta)
		{
			GamemodeHandler.AddScore(userId, delta);
		}

		protected void SetTeam(long userId, byte team)
		{
			GamemodeHandler.SetTeam(userId, team);
		}

		protected void BroadcastEvent(GamemodeEventType type, long a = 0L, long b = 0L, int value = 0, string message = null)
		{
			GamemodeHandler.BroadcastEvent(type, a, b, value, message);
		}

		protected void StartRound()
		{
			GamemodeHandler.StartRound();
		}

		protected void EndRound()
		{
			GamemodeHandler.EndRoundInternal();
		}
	}
	public static class GamemodeHandler
	{
		public static readonly Dictionary<string, EntanglementGamemode> registeredModes = new Dictionary<string, EntanglementGamemode>();

		public static float roundDurationOverrideSeconds = 0f;

		public const int minPlayersToStart = 2;

		public static readonly Dictionary<long, int> scores = new Dictionary<long, int>();

		public static readonly Dictionary<long, byte> teams = new Dictionary<long, byte>();

		public static readonly HashSet<long> eliminated = new HashSet<long>();

		private static long lastAttacker;

		private static float lastAttackTime = -10f;

		private const float attackMemorySeconds = 8f;

		private static float stateBroadcastTimer;

		private const float stateBroadcastInterval = 2f;

		public static EntanglementGamemode ActiveMode { get; private set; }

		public static bool RoundActive { get; private set; }

		public static float RoundTimeRemaining { get; private set; }

		public static int PlayerCount => (Node.activeNode?.connectedUsers.Count ?? 0) + 1;

		public static void RegisterGamemode(EntanglementGamemode mode)
		{
			if (mode != null && !string.IsNullOrEmpty(mode.Id))
			{
				registeredModes[mode.Id] = mode;
			}
		}

		public static void Initialize()
		{
			RegisterGamemode(new DeathmatchGamemode());
			RegisterGamemode(new TeamBattleGamemode());
			RegisterGamemode(new LastManStandingGamemode());
			PlayerAttackMessageHandler.OnDamageReceived += OnLocalDamageReceived;
			PlayerDeathManager.OnLocalPlayerDied += OnLocalPlayerDied;
		}

		public static bool TryStartMatch(string id, out string reason)
		{
			reason = "";
			if (!Node.isServer)
			{
				reason = "Only the host can start a gamemode.";
				return false;
			}
			if (RoundActive)
			{
				reason = "A round is already running. Force stop it first.";
				return false;
			}
			if (PlayerCount < 2)
			{
				reason = $"Need at least {2} players to start.";
				return false;
			}
			if (!registeredModes.ContainsKey(id))
			{
				reason = "That gamemode isn't registered.";
				return false;
			}
			StartMode(id);
			StartRound();
			return true;
		}

		public static bool StartMode(string id)
		{
			if (!Node.isServer)
			{
				return false;
			}
			if (!registeredModes.TryGetValue(id, out var value))
			{
				return false;
			}
			ActiveMode?.OnModeStop();
			scores.Clear();
			teams.Clear();
			eliminated.Clear();
			RoundActive = false;
			ActiveMode = value;
			ActiveMode.OnModeStart();
			BroadcastState();
			EntangleLogger.Log("[Gamemode] Started '" + value.DisplayName + "'");
			return true;
		}

		public static void StopMode()
		{
			if (Node.isServer && ActiveMode != null)
			{
				if (RoundActive)
				{
					RoundActive = false;
					ActiveMode.OnRoundEnd();
					BroadcastEvent(GamemodeEventType.RoundEnd, 0L, 0L);
				}
				ActiveMode.OnModeStop();
				EntangleLogger.Log("[Gamemode] Stopped '" + ActiveMode.DisplayName + "'");
				ActiveMode = null;
				scores.Clear();
				teams.Clear();
				eliminated.Clear();
				BroadcastState();
			}
		}

		public static void StartRound()
		{
			if (Node.isServer && ActiveMode != null)
			{
				RoundActive = true;
				RoundTimeRemaining = ((roundDurationOverrideSeconds > 0f) ? roundDurationOverrideSeconds : ActiveMode.DefaultRoundSeconds);
				eliminated.Clear();
				ActiveMode.OnRoundStart();
				BroadcastEvent(GamemodeEventType.RoundStart, 0L, 0L);
				BroadcastState();
			}
		}

		internal static void EndRoundInternal()
		{
			if (Node.isServer && ActiveMode != null && RoundActive)
			{
				RoundActive = false;
				ActiveMode.OnRoundEnd();
				eliminated.Clear();
				BroadcastEvent(GamemodeEventType.RoundEnd, 0L, 0L);
				BroadcastState();
			}
		}

		public static void SetRoundTimeRemaining(float seconds)
		{
			if (Node.isServer)
			{
				RoundTimeRemaining = Mathf.Max(0f, seconds);
				BroadcastState();
			}
		}

		public static void AddRoundTime(float deltaSeconds)
		{
			SetRoundTimeRemaining(RoundTimeRemaining + deltaSeconds);
		}

		public static void SetRoundDuration(float seconds)
		{
			if (Node.isServer)
			{
				roundDurationOverrideSeconds = Mathf.Max(0f, seconds);
			}
		}

		public static void SetScore(long userId, int score)
		{
			if (Node.isServer)
			{
				scores[userId] = score;
				BroadcastEvent(GamemodeEventType.PlayerScored, userId, 0L, score);
				BroadcastState();
			}
		}

		public static void AddScore(long userId, int delta)
		{
			scores.TryGetValue(userId, out var value);
			SetScore(userId, value + delta);
		}

		public static bool ShouldBlockDamage(long attackerId)
		{
			if (ActiveMode == null || !ActiveMode.UsesTeams)
			{
				return false;
			}
			long currentUserId = SteamIntegration.currentUserId;
			if (!teams.TryGetValue(attackerId, out var value))
			{
				return false;
			}
			if (!teams.TryGetValue(currentUserId, out var value2))
			{
				return false;
			}
			return value == value2;
		}

		public static void SetTeam(long userId, byte team)
		{
			if (Node.isServer)
			{
				teams[userId] = team;
				BroadcastState();
			}
		}

		public static void BroadcastEvent(GamemodeEventType type, long a = 0L, long b = 0L, int value = 0, string message = null)
		{
			if (Node.isServer)
			{
				GamemodeEventData data = new GamemodeEventData
				{
					type = type,
					a = a,
					b = b,
					value = value,
					message = (message ?? "")
				};
				NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.GamemodeEvent, data);
				if (networkMessage != null)
				{
					Node.activeNode?.BroadcastMessage(NetworkChannel.Reliable, networkMessage.GetBytes());
				}
				HandleEventLocally(type, a, b, value, message ?? "");
			}
		}

		private static void HandleEventLocally(GamemodeEventType type, long a, long b, int value, string message)
		{
			switch (type)
			{
			case GamemodeEventType.RoundStart:
				EntangleNotif.GamemodeStarted(ActiveMode?.DisplayName ?? "Gamemode");
				break;
			case GamemodeEventType.RoundEnd:
				EntangleNotif.GamemodeEnded(ActiveMode?.DisplayName ?? "Gamemode");
				break;
			}
			ActiveMode?.OnEventReceived(type, a, b, value, message);
		}

		public static void Tick()
		{
			if (!SteamIntegration.hasLobby || !Node.isServer || ActiveMode == null)
			{
				return;
			}
			ActiveMode.HostTick(Time.deltaTime);
			if (RoundActive)
			{
				RoundTimeRemaining -= Time.deltaTime;
				if (RoundTimeRemaining <= 0f)
				{
					EndRoundInternal();
				}
			}
			stateBroadcastTimer += Time.deltaTime;
			if (stateBroadcastTimer >= 2f)
			{
				stateBroadcastTimer = 0f;
				BroadcastState();
			}
		}

		private static void BroadcastState()
		{
			if (Node.isServer)
			{
				GamemodeStateData data = new GamemodeStateData
				{
					activeModeId = (ActiveMode?.Id ?? ""),
					roundActive = RoundActive,
					roundTimeRemaining = RoundTimeRemaining,
					scores = new Dictionary<long, int>(scores),
					teams = new Dictionary<long, byte>(teams),
					eliminated = new List<long>(eliminated)
				};
				NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.GamemodeState, data);
				if (networkMessage != null)
				{
					Node.activeNode?.BroadcastMessage(NetworkChannel.Reliable, networkMessage.GetBytes());
				}
				ApplyState(data);
			}
		}

		internal static void ApplyState(GamemodeStateData data)
		{
			if (!Node.isServer)
			{
				scores.Clear();
				foreach (KeyValuePair<long, int> score in data.scores)
				{
					scores[score.Key] = score.Value;
				}
				teams.Clear();
				foreach (KeyValuePair<long, byte> team in data.teams)
				{
					teams[team.Key] = team.Value;
				}
				eliminated.Clear();
				foreach (long item in data.eliminated)
				{
					eliminated.Add(item);
				}
				RoundActive = data.roundActive;
				RoundTimeRemaining = data.roundTimeRemaining;
				if (string.IsNullOrEmpty(data.activeModeId))
				{
					ActiveMode = null;
				}
				else if (ActiveMode == null || ActiveMode.Id != data.activeModeId)
				{
					registeredModes.TryGetValue(data.activeModeId, out var value);
					ActiveMode = value;
				}
			}
			ApplyVisuals();
			ActiveMode?.OnStateApplied(new GamemodeState
			{
				activeModeId = data.activeModeId,
				roundActive = data.roundActive,
				roundTimeRemaining = data.roundTimeRemaining
			});
		}

		private static void ApplyVisuals()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<long, PlayerRepresentation> representation in PlayerRepresentation.representations)
			{
				PlayerRepresentation value = representation.Value;
				if (value != null)
				{
					value.SetEliminated(eliminated.Contains(representation.Key));
					if (ActiveMode != null && ActiveMode.UsesTeams && teams.TryGetValue(representation.Key, out var value2))
					{
						value.SetNameColor(ActiveMode.GetTeamColor(value2));
					}
					else
					{
						value.SetNameColor(Color.white);
					}
				}
			}
		}

		internal static void ApplyEvent(long sender, GamemodeEventData data)
		{
			if (Node.isServer && data.type == GamemodeEventType.ReportPlayerKilled)
			{
				ProcessDeath(data.a, sender);
			}
			else if (!Node.isServer)
			{
				HandleEventLocally(data.type, data.a, data.b, data.value, data.message);
			}
		}

		private static void ProcessDeath(long killerId, long victimId)
		{
			if (ActiveMode != null)
			{
				ActiveMode.OnPlayerKilled(killerId, victimId);
				BroadcastEvent(GamemodeEventType.PlayerKilled, killerId, victimId);
				if (RoundActive && ActiveMode.EliminationMode && eliminated.Add(victimId))
				{
					BroadcastEvent(GamemodeEventType.PlayerEliminated, victimId, 0L);
					BroadcastState();
				}
			}
		}

		private static void OnLocalDamageReceived(long attacker, float damage)
		{
			lastAttacker = attacker;
			lastAttackTime = Time.time;
		}

		private static void OnLocalPlayerDied()
		{
			if (ActiveMode == null)
			{
				return;
			}
			long num = ((Time.time - lastAttackTime <= 8f) ? lastAttacker : 0);
			long currentUserId = SteamIntegration.currentUserId;
			if (Node.isServer)
			{
				ProcessDeath(num, currentUserId);
				return;
			}
			GamemodeEventData data = new GamemodeEventData
			{
				type = GamemodeEventType.ReportPlayerKilled,
				a = num,
				b = 0L,
				value = 0,
				message = ""
			};
			NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.GamemodeEvent, data);
			if (networkMessage != null)
			{
				Node.activeNode?.SendMessage(SteamIntegration.lobbyOwnerId, NetworkChannel.Reliable, networkMessage.GetBytes());
			}
		}

		public static void Clear()
		{
			ActiveMode = null;
			RoundActive = false;
			scores.Clear();
			teams.Clear();
			eliminated.Clear();
		}
	}
}
namespace Entanglement.Gamemodes.BuiltIn
{
	public class DeathmatchGamemode : EntanglementGamemode
	{
		public override string Id => "deathmatch";

		public override string DisplayName => "Deathmatch";

		public override Color MenuColor => Color.red;

		public override float DefaultRoundSeconds => 600f;

		public override void OnPlayerKilled(long killerId, long victimId)
		{
			if (killerId != victimId && killerId != 0)
			{
				AddScore(killerId, 1);
			}
		}

		public override void OnRoundEnd()
		{
			EntangleLogger.Log("[Deathmatch] Round over");
		}
	}
	public class TeamBattleGamemode : EntanglementGamemode
	{
		public const int scoreToWin = 25;

		private static readonly Color[] teamColors = (Color[])(object)new Color[4]
		{
			new Color(1f, 0.35f, 0.3f),
			new Color(0.35f, 0.55f, 1f),
			new Color(0.4f, 1f, 0.4f),
			new Color(1f, 0.9f, 0.3f)
		};

		private byte nextTeam;

		public override string Id => "team_battle";

		public override string DisplayName => "Team Battle";

		public override Color MenuColor => Color.blue;

		public override bool UsesTeams => true;

		public override int TeamCount => 2;

		public override float DefaultRoundSeconds => 600f;

		public override Color GetTeamColor(byte team)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return (team < teamColors.Length) ? teamColors[team] : Color.white;
		}

		public override void OnModeStart()
		{
			nextTeam = 0;
			SetTeam(SteamIntegration.currentUserId, nextTeam);
			nextTeam = (byte)((nextTeam + 1) % TeamCount);
			if (Node.activeNode == null)
			{
				return;
			}
			foreach (long connectedUser in Node.activeNode.connectedUsers)
			{
				SetTeam(connectedUser, nextTeam);
				nextTeam = (byte)((nextTeam + 1) % TeamCount);
			}
		}

		public override void OnPlayerJoined(long userId)
		{
			SetTeam(userId, nextTeam);
			nextTeam = (byte)((nextTeam + 1) % TeamCount);
		}

		public override void OnPlayerKilled(long killerId, long victimId)
		{
			if (killerId == victimId || killerId == 0 || !GamemodeHandler.teams.TryGetValue(killerId, out var value))
			{
				return;
			}
			int num = 0;
			foreach (KeyValuePair<long, int> score in GamemodeHandler.scores)
			{
				if (GamemodeHandler.teams.TryGetValue(score.Key, out var value2) && value2 == value)
				{
					num += score.Value;
				}
			}
			AddScore(killerId, 1);
			if (num + 1 >= 25)
			{
				EndRound();
			}
		}

		public override void OnRoundEnd()
		{
			EntangleLogger.Log("[Team Battle] Round over");
		}
	}
	public class LastManStandingGamemode : EntanglementGamemode
	{
		private const int survivalBonus = 5;

		public override string Id => "last_man_standing";

		public override string DisplayName => "Last Man Standing";

		public override Color MenuColor => new Color(1f, 0.55f, 0f);

		public override float DefaultRoundSeconds => 300f;

		public override bool EliminationMode => true;

		private static IEnumerable<long> AllPlayers()
		{
			yield return SteamIntegration.currentUserId;
			if (Node.activeNode == null)
			{
				yield break;
			}
			foreach (long connectedUser in Node.activeNode.connectedUsers)
			{
				yield return connectedUser;
			}
		}

		public override void OnPlayerKilled(long killerId, long victimId)
		{
			if (killerId != victimId && killerId != 0)
			{
				AddScore(killerId, 1);
			}
			int num = 0;
			int num2 = 0;
			long userId = 0L;
			foreach (long item in AllPlayers())
			{
				num++;
				if (item != victimId && !GamemodeHandler.eliminated.Contains(item))
				{
					num2++;
					userId = item;
				}
			}
			if (num > 1 && num2 <= 1)
			{
				if (num2 == 1)
				{
					AddScore(userId, 5);
				}
				EndRound();
			}
		}

		public override void OnRoundEnd()
		{
			EntangleLogger.Log("[Last Man Standing] Round over");
		}
	}
}
namespace Entanglement.UI
{
	public static class BanlistUI
	{
		public static MenuCategory banCategory;

		private const string refreshText = "Refresh";

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			banCategory = category.CreateSubCategory("Banned Users", Color.white);
			banCategory.CreateFunctionElement("Refresh", Color.white, (Action)Refresh);
		}

		public static void ClearPlayers()
		{
			List<string> list = new List<string>();
			foreach (MenuElement element in banCategory.elements)
			{
				if (element.displayText != "Refresh")
				{
					list.Add(element.displayText);
				}
			}
			foreach (string item in list)
			{
				banCategory.RemoveElement(item);
			}
		}

		public static void Refresh()
		{
			ClearPlayers();
			foreach (Tuple<long, string> bannedUser in BanList.bannedUsers)
			{
				AddUser(bannedUser.Item1, bannedUser.Item2);
			}
			UpdateMenu();
		}

		public static void UpdateMenu()
		{
			MenuManager.OpenCategory(banCategory);
		}

		public static void AddUser(long userId, string userName)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = banCategory.CreateSubCategory(userName, Color.white);
			val.CreateFunctionElement("Unban", Color.red, (Action)delegate
			{
				BanList.UnbanUser(userId, userName);
				Refresh();
			});
		}
	}
	public static class ClientUI
	{
		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("Client Menu", Color.white);
			MenuCategory val2 = val.CreateSubCategory("Client Settings", Color.white);
			val2.CreateBoolElement("NameTags", Color.white, true, (Action<bool>)delegate(bool value)
			{
				Client.nameTagsVisible = value;
			});
		}
	}
	public static class DebugUI
	{
		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			MenuCategory val = category.CreateSubCategory("Debug", Color.red);
			val.CreateFunctionElement("Create Debug Representation", Color.white, (Action)delegate
			{
				PlayerRepresentation.debugRepresentation?.DeleteRepresentations();
				PlayerRepresentation.debugRepresentation = new PlayerRepresentation("Dummy", 0L);
			});
			val.CreateFunctionElement("Remove Debug Representation", Color.white, (Action)delegate
			{
				PlayerRepresentation.debugRepresentation?.DeleteRepresentations();
				PlayerRepresentation.debugRepresentation = null;
				VoiceManager.debugVoiceOnRep = false;
			});
			val.CreateBoolElement("Voice Chat Debug On Rep", Color.white, false, (Action<bool>)delegate(bool value)
			{
				if (value && PlayerRepresentation.debugRepresentation == null)
				{
					Notifications.SendNotification("Spawn a debug representation first.", 3f);
					VoiceManager.debugVoiceOnRep = false;
				}
				else
				{
					VoiceManager.debugVoiceOnRep = value;
					if (value)
					{
						Notifications.SendNotification("Speak - you'll hear it back from the dummy in 10s.", 4f);
					}
				}
			});
		}
	}
	public static class LoadingScreen
	{
		public static AssetBundle assetBundle;

		public static void LoadBundle()
		{
			assetBundle = EmebeddedAssetBundle.LoadFromAssembly(EntanglementMod.entanglementAssembly, "Entanglement.resources.logo.eres");
		}

		public static void OverrideScreen()
		{
			Texture2D texture = assetBundle.LoadAsset<Texture2D>("entanglement.png");
			GameObject val = GameObject.Find("Canvas/RawImage (1)");
			val.GetComponent<RawImage>().texture = (Texture)(object)texture;
		}
	}
	public static class LobbiesUI
	{
		private static MenuCategory lobbiesCategory;

		private static CallResult<LobbyMatchList_t> lobbyListResult;

		private const string refreshText = "Refresh";

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			lobbiesCategory = category.CreateSubCategory("Public Lobbies", Color.white);
			lobbiesCategory.CreateFunctionElement("Refresh", Color.white, (Action)Refresh);
			lobbyListResult = CallResult<LobbyMatchList_t>.Create((APIDispatchDelegate<LobbyMatchList_t>)OnSteamLobbySearch);
		}

		public static void Refresh()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			ClearMenuItems();
			SteamMatchmaking.AddRequestLobbyListStringFilter("entanglement", "true", (ELobbyComparison)0);
			SteamMatchmaking.AddRequestLobbyListDistanceFilter((ELobbyDistanceFilter)3);
			lobbyListResult.Set(SteamMatchmaking.RequestLobbyList(), (APIDispatchDelegate<LobbyMatchList_t>)null);
			UpdateMenu();
		}

		public static void OnSteamLobbySearch(LobbyMatchList_t result, bool bIOFailure)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (bIOFailure)
			{
				EntangleLogger.Log("Failed to search for Public Lobbies!");
				return;
			}
			int nLobbiesMatching = (int)result.m_nLobbiesMatching;
			EntangleLogger.Log(string.Format("Searched for {0} Public Lobb{1}.", nLobbiesMatching, (nLobbiesMatching == 1) ? "y" : "ies"));
			for (int i = 0; i < nLobbiesMatching; i++)
			{
				CSteamID lobbyByIndex = SteamMatchmaking.GetLobbyByIndex(i);
				EntangleLogger.Log($"Found Lobby with id {lobbyByIndex.m_SteamID}.");
				AddLobby(lobbyByIndex);
			}
		}

		public static void ClearMenuItems()
		{
			List<string> list = new List<string>();
			foreach (MenuElement element in lobbiesCategory.elements)
			{
				if (element.displayText != "Refresh")
				{
					list.Add(element.displayText);
				}
			}
			foreach (string item in list)
			{
				lobbiesCategory.RemoveElement(item);
			}
		}

		public static void AddLobby(CSteamID lobbyId)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			EntangleLogger.Log($"Trying to add lobby with id {lobbyId.m_SteamID}.");
			string text = SteamMatchmaking.GetLobbyData(lobbyId, "host_name");
			string lobbyData = SteamMatchmaking.GetLobbyData(lobbyId, "scene");
			if (string.IsNullOrEmpty(text))
			{
				text = "Unknown";
			}
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(lobbyId);
			int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(lobbyId);
			string text2 = $"{text}'s Game ({numLobbyMembers}/{lobbyMemberLimit})";
			if (!string.IsNullOrEmpty(lobbyData))
			{
				text2 = text2 + " - " + lobbyData;
			}
			CreateLobbyItem(text2, lobbyId);
		}

		public static void CreateLobbyItem(string name, CSteamID lobbyId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			lobbiesCategory.CreateFunctionElement(name, Color.white, (Action)delegate
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (SteamIntegration.hasLobby)
				{
					EntangleLogger.Error("Already in a server!");
				}
				else
				{
					Client.instance.JoinLobby(lobbyId);
				}
			});
			UpdateMenu();
		}

		public static void UpdateMenu()
		{
			MenuManager.OpenCategory(lobbiesCategory);
		}
	}
	public static class ServerUI
	{
		private static MenuCategory playersCategory;

		private const string refreshText = "Refresh";

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_00a8: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("Server Menu", Color.white);
			val.CreateFunctionElement("Start Server", Color.white, (Action)delegate
			{
				Server.StartServer();
			});
			val.CreateFunctionElement("Stop Server", Color.white, (Action)delegate
			{
				if (Server.instance != null)
				{
					Server.instance.Shutdown();
				}
			});
			val.CreateFunctionElement("Disconnect", Color.white, (Action)delegate
			{
				if (Node.activeNode is Client client)
				{
					client.DisconnectFromServer();
				}
			});
			val.CreateFunctionElement("Invite Friends", Color.white, (Action)delegate
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				if (SteamIntegration.hasLobby)
				{
					SteamFriends.ActivateGameOverlayInviteDialog(SteamIntegration.lobby);
				}
				else
				{
					EntangleLogger.Error("You aren't in a server!");
				}
			});
			MenuCategory val2 = val.CreateSubCategory("Server Settings", Color.white);
			val2.CreateIntElement("Max Players", Color.white, 8, (Action<int>)delegate(int value)
			{
				Server.maxPlayers = (byte)value;
				Server.instance?.UpdateLobbyConfig();
			}, 1, 1, 250, true);
			val2.CreateBoolElement("Locked", Color.white, false, (Action<bool>)delegate(bool value)
			{
				Server.isLocked = value;
				Server.instance?.UpdateLobbyConfig();
			});
			val2.CreateEnumElement("Visibility", Color.white, (Enum)ServerVisibility.Private, (Action<Enum>)delegate(Enum value)
			{
				if (value is ServerVisibility visibility)
				{
					Server.visibility = visibility;
					Server.instance?.UpdateLobbyConfig();
				}
			});
			playersCategory = val.CreateSubCategory("Players", Color.white);
			playersCategory.CreateFunctionElement("Refresh", Color.white, (Action)Refresh);
		}

		public static void ClearPlayers()
		{
			List<string> list = new List<string>();
			foreach (MenuElement element in playersCategory.elements)
			{
				if (element.displayText != "Refresh")
				{
					list.Add(element.displayText);
				}
			}
			foreach (string item in list)
			{
				playersCategory.RemoveElement(item);
			}
		}

		public static void Refresh()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			ClearPlayers();
			if (!SteamIntegration.hasLobby)
			{
				UpdateMenu();
				return;
			}
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(SteamIntegration.lobby);
			for (int i = 0; i < numLobbyMembers; i++)
			{
				long steamID = (long)SteamMatchmaking.GetLobbyMemberByIndex(SteamIntegration.lobby, i).m_SteamID;
				if (steamID != SteamIntegration.currentUserId)
				{
					AddUser(steamID, SteamIntegration.GetUserName(steamID));
				}
			}
			UpdateMenu();
		}

		public static void UpdateMenu()
		{
			MenuManager.OpenCategory(playersCategory);
		}

		public static void AddUser(long userId, string userName)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			string playerName = userName;
			Color val = Color.white;
			if (userId == SteamIntegration.lobbyOwnerId)
			{
				playerName += " (Host)";
				val = Color.yellow;
			}
			MenuCategory val2 = playersCategory.CreateSubCategory(playerName, val);
			if (SteamIntegration.isHost)
			{
				val2.CreateFunctionElement("Kick", Color.red, (Action)delegate
				{
					if (SteamIntegration.isHost)
					{
						Server.instance?.KickUser(userId, playerName);
						Refresh();
					}
				});
				val2.CreateFunctionElement("Ban", Color.red, (Action)delegate
				{
					if (SteamIntegration.isHost)
					{
						BanList.BanUser(userId, userName);
						Server.instance.KickUser(userId, playerName, DisconnectReason.Banned);
						Refresh();
					}
				});
				val2.CreateFunctionElement("Teleport To", Color.yellow, (Action)delegate
				{
					Server.instance?.TeleportTo(userId);
				});
			}
			val2.CreateFunctionElement("View Steam Profile", Color.white, (Action)delegate
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				SteamFriends.ActivateGameOverlayToUser("steamid", new CSteamID((ulong)userId));
			});
		}
	}
	public static class StatsUI
	{
		public static IntElement downElem;

		public static IntElement upElem;

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("Net Stats", Color.white);
			val.CreateIntElement("Bytes Down", Color.white, 0, (Action<int>)null, 1, int.MinValue, int.MaxValue, false);
			val.CreateIntElement("Bytes Up", Color.white, 0, (Action<int>)null, 1, int.MinValue, int.MaxValue, false);
			MenuElement obj = val.elements[0];
			downElem = (IntElement)(object)((obj is IntElement) ? obj : null);
			MenuElement obj2 = val.elements[1];
			upElem = (IntElement)(object)((obj2 is IntElement) ? obj2 : null);
		}

		public static void UpdateUI()
		{
			((GenericElement<int>)(object)downElem).SetValue((int)Node.activeNode.recievedByteCount);
			Node.activeNode.recievedByteCount = 0u;
			((GenericElement<int>)(object)upElem).SetValue((int)Node.activeNode.sentByteCount);
			Node.activeNode.sentByteCount = 0u;
		}
	}
	public static class EntanglementUI
	{
		private static MenuCategory rootCategory;

		private static MenuElement suicideElement;

		private static bool lastInServer;

		public static void CreateUI()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			rootCategory = MenuManager.CreateCategory("Entanglement Redux", Color.white);
			ServerUI.CreateUI(rootCategory);
			ClientUI.CreateUI(rootCategory);
			BanlistUI.CreateUI(rootCategory);
			LobbiesUI.CreateUI(rootCategory);
			VoiceUI.CreateUI(rootCategory);
			SyncUI.CreateUI(rootCategory);
			GamemodeUI.CreateUI(rootCategory);
			StatsUI.CreateUI(rootCategory);
			DebugUI.CreateUI(rootCategory);
			rootCategory.CreateFunctionElement("Suicide", Color.red, (Action)Suicide);
			suicideElement = rootCategory.elements[rootCategory.elements.Count - 1];
		}

		public static void UpdateUI()
		{
			bool hasLobby = SteamIntegration.hasLobby;
			if (hasLobby != lastInServer)
			{
				lastInServer = hasLobby;
				MoveSuicideButton(hasLobby);
			}
		}

		private static void MoveSuicideButton(bool toTop)
		{
			if (rootCategory != null && suicideElement != null)
			{
				rootCategory.elements.Remove(suicideElement);
				if (toTop)
				{
					rootCategory.elements.Insert(0, suicideElement);
				}
				else
				{
					rootCategory.elements.Add(suicideElement);
				}
				if (GetActiveCategory() == rootCategory)
				{
					MenuManager.OpenCategory(rootCategory);
				}
			}
		}

		private static MenuCategory GetActiveCategory()
		{
			object? obj = typeof(MenuManager).GetField("activeCategory", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
			return (MenuCategory)((obj is MenuCategory) ? obj : null);
		}

		private static void Suicide()
		{
			if (!SteamIntegration.hasLobby)
			{
				Notifications.SendNotification("You need to be in a server to do that.", 3f);
			}
			else
			{
				PlayerDeathManager.Suicide();
			}
		}
	}
	public static class VoiceUI
	{
		private static MenuCategory muteCategory;

		private const string refreshText = "Refresh";

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("Voice Settings", Color.cyan);
			val.CreateBoolElement("Voice Chat", Color.white, true, (Action<bool>)delegate(bool value)
			{
				VoiceManager.micEnabled = value;
			});
			val.CreateEnumElement("Mode", Color.white, (Enum)VoiceMode.Proximity, (Action<Enum>)delegate(Enum value)
			{
				if (value is VoiceMode)
				{
					VoiceManager.mode = (VoiceMode)(object)value;
					VoiceManager.ApplySettings();
				}
			});
			val.CreateIntElement("Proximity Range", Color.white, 12, (Action<int>)delegate(int value)
			{
				VoiceManager.proximityRange = value;
				VoiceManager.ApplySettings();
			}, 2, 2, 100, true);
			val.CreateIntElement("Volume %", Color.white, 100, (Action<int>)delegate(int value)
			{
				VoiceManager.outputVolume = value;
				VoiceManager.ApplySettings();
			}, 10, 0, 200, true);
			muteCategory = val.CreateSubCategory("Mute Players", Color.red);
			muteCategory.CreateFunctionElement("Refresh", Color.white, (Action)RefreshMuteList);
			val.CreateFunctionElement("How to change mic", Color.yellow, (Action)delegate
			{
				Notifications.SendNotification("Voice uses your Steam mic.\nChange it in Steam: Settings > Voice > Voice Input Device.\nIn VR, open the Steam overlay (not SteamVR) to reach Steam Settings.", 10f);
			});
		}

		private static void ClearMuteList()
		{
			List<string> list = new List<string>();
			foreach (MenuElement element in muteCategory.elements)
			{
				if (element.displayText != "Refresh")
				{
					list.Add(element.displayText);
				}
			}
			foreach (string item in list)
			{
				muteCategory.RemoveElement(item);
			}
		}

		private static void RefreshMuteList()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			ClearMuteList();
			if (SteamIntegration.hasLobby)
			{
				int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(SteamIntegration.lobby);
				for (int i = 0; i < numLobbyMembers; i++)
				{
					long userId = (long)SteamMatchmaking.GetLobbyMemberByIndex(SteamIntegration.lobby, i).m_SteamID;
					if (userId != SteamIntegration.currentUserId)
					{
						muteCategory.CreateBoolElement("Mute " + SteamIntegration.GetUserName(userId), Color.white, VoiceManager.IsMuted(userId), (Action<bool>)delegate(bool value)
						{
							VoiceManager.SetMuted(userId, value);
						});
					}
				}
			}
			MenuManager.OpenCategory(muteCategory);
		}
	}
	public static class SyncUI
	{
		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("File Sync", Color.green);
			val.CreateBoolElement("Sync Custom Items", Color.white, SyncPrefs.itemSyncEnabled.Value, (Action<bool>)delegate(bool value)
			{
				SyncPrefs.itemSyncEnabled.Value = value;
			});
			val.CreateBoolElement("Sync Playermodels", Color.white, SyncPrefs.playermodelSyncEnabled.Value, (Action<bool>)delegate(bool value)
			{
				SyncPrefs.playermodelSyncEnabled.Value = value;
			});
			val.CreateIntElement("Max File Size (MB)", Color.white, SyncPrefs.maxSyncSizeKB.Value / 1024, (Action<int>)delegate(int value)
			{
				SyncPrefs.maxSyncSizeKB.Value = value * 1024;
			}, 10, 1, 500, true);
		}
	}
	public static class GamemodeUI
	{
		private static MenuCategory scoresCategory;

		private const string refreshText = "Refresh Scores";

		public static void CreateUI(MenuCategory category)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = category.CreateSubCategory("Gamemodes", Color.magenta);
			MenuCategory val2 = val.CreateSubCategory("Host Controls", Color.yellow);
			foreach (EntanglementGamemode mode in GamemodeHandler.registeredModes.Values)
			{
				val2.CreateFunctionElement("Play: " + mode.DisplayName, mode.MenuColor, (Action)delegate
				{
					if (Node.isServer && !GamemodeHandler.TryStartMatch(mode.Id, out var reason))
					{
						Notifications.SendNotification(reason, 4f);
					}
				});
			}
			val2.CreateFunctionElement("Force Stop Gamemode", Color.red, (Action)delegate
			{
				if (Node.isServer)
				{
					GamemodeHandler.StopMode();
				}
			});
			MenuCategory val3 = val2.CreateSubCategory("Round Timer", Color.cyan);
			val3.CreateIntElement("Default Length (s, 0 = mode default)", Color.white, 0, (Action<int>)delegate(int value)
			{
				if (Node.isServer)
				{
					GamemodeHandler.SetRoundDuration(value);
				}
			}, 30, 0, 3600, true);
			val3.CreateIntElement("Set Time Left (s)", Color.white, 0, (Action<int>)delegate(int value)
			{
				if (Node.isServer)
				{
					if (!GamemodeHandler.RoundActive)
					{
						Notifications.SendNotification("No round is running.", 3f);
					}
					else
					{
						GamemodeHandler.SetRoundTimeRemaining(value);
						Notifications.SendNotification($"Time left: {(int)GamemodeHandler.RoundTimeRemaining}s", 3f);
					}
				}
			}, 30, 0, 3600, true);
			val3.CreateFunctionElement("Add 60 seconds", Color.green, (Action)delegate
			{
				AdjustTime(60f);
			});
			val3.CreateFunctionElement("Remove 60 seconds", Color.red, (Action)delegate
			{
				AdjustTime(-60f);
			});
			scoresCategory = val.CreateSubCategory("Scores", Color.white);
			scoresCategory.CreateFunctionElement("Refresh Scores", Color.white, (Action)RefreshScores);
		}

		private static void AdjustTime(float delta)
		{
			if (Node.isServer)
			{
				if (!GamemodeHandler.RoundActive)
				{
					Notifications.SendNotification("No round is running.", 3f);
					return;
				}
				GamemodeHandler.AddRoundTime(delta);
				Notifications.SendNotification($"Time left: {(int)GamemodeHandler.RoundTimeRemaining}s", 3f);
			}
		}

		private static void ClearScores()
		{
			List<string> list = new List<string>();
			foreach (MenuElement element in scoresCategory.elements)
			{
				if (element.displayText != "Refresh Scores")
				{
					list.Add(element.displayText);
				}
			}
			foreach (string item in list)
			{
				scoresCategory.RemoveElement(item);
			}
		}

		private static void RefreshScores()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			ClearScores();
			if (GamemodeHandler.ActiveMode == null)
			{
				scoresCategory.CreateFunctionElement("No gamemode active", Color.grey, (Action)delegate
				{
				});
				MenuManager.OpenCategory(scoresCategory);
				return;
			}
			scoresCategory.CreateFunctionElement("Mode: " + GamemodeHandler.ActiveMode.DisplayName, Color.white, (Action)delegate
			{
			});
			scoresCategory.CreateFunctionElement(GamemodeHandler.RoundActive ? $"Round time left: {(int)GamemodeHandler.RoundTimeRemaining}s" : "No round active", Color.white, (Action)delegate
			{
			});
			foreach (KeyValuePair<long, int> score in GamemodeHandler.scores)
			{
				string userName = SteamIntegration.GetUserName(score.Key);
				string arg = (GamemodeHandler.eliminated.Contains(score.Key) ? " (eliminated)" : "");
				scoresCategory.CreateFunctionElement($"{userName}: {score.Value}{arg}", Color.white, (Action)delegate
				{
				});
			}
			MenuManager.OpenCategory(scoresCategory);
		}
	}
}
namespace Entanglement.Representation
{
	public class PlayerRepresentation
	{
		public static float legJitter = 10f;

		public static Dictionary<long, PlayerRepresentation> representations = new Dictionary<long, PlayerRepresentation>();

		public static Transform[] syncedPoints = (Transform[])(object)new Transform[3];

		public static Transform syncedRoot;

		public Transform[] repTransforms = (Transform[])(object)new Transform[3];

		public Transform repRoot;

		public GameObject repFord;

		public Material repHologram;

		public GameObject repCanvas;

		public Canvas repCanvasComponent;

		public Transform repCanvasTransform;

		public TextMeshProUGUI repNameText;

		public Transform repGeo;

		public Transform repSHJnt;

		public Collider[] colliders = (Collider[])(object)new Collider[0];

		private Renderer[] cachedRenderers;

		public SLZ_Body repBody;

		public SLZ_Body ragdollBody;

		public CharacterAnimationManager repAnimationManager;

		public GunSFX repGunSFX;

		public GunSFX repBalloonSFX;

		public GunSFX repStabSFX;

		public GravGunSFX repPowerPunchSFX;

		public Animator repAnimator;

		public Animator skinAnimator;

		public Animator activeAnimator;

		public GameObject currentSkinObject;

		public AssetBundle currentSkinBundle;

		public string currentSkinPath;

		public bool isCustomSkinned;

		public Vector3 repInputVel = Vector3.zero;

		public Vector3 repSavedVel = Vector3.zero;

		public Vector3 prevRepRootPos = Vector3.zero;

		public string playerName;

		public long playerId;

		public bool isGrounded;

		public bool hasNetTarget = false;

		public Vector3 netRootPosition;

		public Vector3 netRootVelocity;

		public float netReceiveTime;

		public Vector3[] netPositions = (Vector3[])(object)new Vector3[3];

		public Quaternion[] netRotations = (Quaternion[])(object)new Quaternion[3];

		public Vector3[] netLimbVelocities = (Vector3[])(object)new Vector3[3];

		public const float repFollowSharpness = 35f;

		public const float repLimbSharpness = 60f;

		public const float repExtrapolationLimit = 0.2f;

		public const float repSnapDistance = 2f;

		public const float repMaxPredictedSpeed = 25f;

		public static PlayerRepresentation debugRepresentation;

		public static float debugLoopbackHz = 18f;

		private static readonly long debugLoopbackFakeOwner = 1L;

		private static TransformSyncable debugLoopSyncable;

		private static GameObject debugLoopProxy;

		private static GameObject debugLoopSource;

		private static float debugLoopTimer;

		public static AssetBundle playerRepBundle;

		private bool wasTalking;

		private Color baseNameColor = Color.white;

		public bool IsEliminated { get; private set; }

		public void SetEliminated(bool eliminated)
		{
			if (IsEliminated == eliminated)
			{
				return;
			}
			IsEliminated = eliminated;
			if (!Object.op_Implicit((Object)(object)repRoot))
			{
				return;
			}
			if (cachedRenderers == null)
			{
				cachedRenderers = Il2CppArrayBase<Renderer>.op_Implicit(((Component)repRoot).GetComponentsInChildren<Renderer>(true));
			}
			Renderer[] array = cachedRenderers;
			foreach (Renderer val in array)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					val.enabled = !eliminated;
				}
			}
			if (Object.op_Implicit((Object)(object)repCanvas))
			{
				repCanvas.SetActive(!eliminated);
			}
		}

		private static void UpdateDebugHeldLoopback()
		{
			//IL_017c: 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_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			if (debugRepresentation != null)
			{
				if (Object.op_Implicit((Object)(object)PlayerScripts.playerRightHand) && Object.op_Implicit((Object)(object)PlayerScripts.playerRightHand.m_CurrentAttachedObject))
				{
					val = ((Component)PlayerScripts.playerRightHand.m_CurrentAttachedObject.transform.GetJointedRoot()).gameObject;
				}
				else if (Object.op_Implicit((Object)(object)PlayerScripts.playerLeftHand) && Object.op_Implicit((Object)(object)PlayerScripts.playerLeftHand.m_CurrentAttachedObject))
				{
					val = ((Component)PlayerScripts.playerLeftHand.m_CurrentAttachedObject.transform.GetJointedRoot()).gameObject;
				}
			}
			if ((Object)(object)val != (Object)(object)debugLoopSource || ((Object)(object)val != (Object)null && (Object)(object)debugLoopSyncable == (Object)null))
			{
				DestroyDebugLoopback();
				debugLoopSource = val;
				if (Object.op_Implicit((Object)(object)val))
				{
					CreateDebugLoopback(val);
				}
			}
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)debugLoopSyncable == (Object)null)
			{
				return;
			}
			float num = ((debugLoopbackHz > 0f) ? (1f / debugLoopbackHz) : 0f);
			debugLoopTimer += Time.deltaTime;
			if (debugLoopTimer < num)
			{
				return;
			}
			debugLoopTimer = 0f;
			Rigidbody val2 = val.GetComponent<Rigidbody>();
			if (!Object.op_Implicit((Object)(object)val2))
			{
				val2 = val.GetComponentInChildren<Rigidbody>();
			}
			Vector3 velocity = (Object.op_Implicit((Object)(object)val2) ? val2.velocity : Vector3.zero);
			Vector3 angularVelocity = (Object.op_Implicit((Object)(object)val2) ? val2.angularVelocity : Vector3.zero);
			SimplifiedTransform simplifiedTransform = new SimplifiedTransform(val.transform.position + Vector3.forward, val.transform.rotation);
			try
			{
				debugLoopSyncable.ApplyTransform(simplifiedTransform, velocity, angularVelocity);
			}
			catch
			{
				DestroyDebugLoopback();
			}
		}

		private static void CreateDebugLoopback(GameObject held)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_00a3: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				debugLoopProxy = new GameObject("DebugHeldLoopback " + ((Object)held).name);
				debugLoopProxy.transform.position = held.transform.position;
				debugLoopProxy.transform.rotation = held.transform.rotation;
				foreach (MeshFilter componentsInChild in held.GetComponentsInChildren<MeshFilter>(false))
				{
					MeshRenderer component = ((Component)componentsInChild).GetComponent<MeshRenderer>();
					if (!((Object)(object)componentsInChild.sharedMesh == (Object)null) && !((Object)(object)component == (Object)null))
					{
						GameObject val = new GameObject("mesh");
						val.transform.SetParent(debugLoopProxy.transform, false);
						val.transform.position = ((Component)componentsInChild).transform.position;
						val.transform.rotation = ((Component)componentsInChild).transform.rotation;
						val.transform.localScale = ((Component)componentsInChild).transform.lossyScale;
						val.AddComponent<MeshFilter>().sharedMesh = componentsInChild.sharedMesh;
						((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)component).sharedMaterials;
					}
				}
				Transform transform = debugLoopProxy.transform;
				transform.position += Vector3.forward;
				Rigidbody val2 = debugLoopProxy.AddComponent<Rigidbody>();
				val2.useGravity = false;
				debugLoopSyncable = TransformSyncable.CreateSync(debugLoopbackFakeOwner, val2) as TransformSyncable;
				if ((Object)(object)debugLoopSyncable == (Object)null)
				{
					DestroyDebugLoopback();
					return;
				}
				debugLoopSyncable.isValid = true;
				debugLoopSyncable.EnqueueOwner(debugLoopbackFakeOwner);
			}
			catch
			{
				DestroyDebugLoopback();
			}
		}

		private static void DestroyDebugLoopback()
		{
			if ((Object)(object)debugLoopSyncable != (Object)null)
			{
				try
				{
					if (Object.op_Implicit((Object)(object)debugLoopProxy))
					{
						TransformSyncable.cache.Remove(debugLoopProxy);
					}
					debugLoopSyncable.Cleanup();
				}
				catch
				{
				}
				debugLoopSyncable = null;
			}
			if (Object.op_Implicit((Object)(object)debugLoopProxy))
			{
				Object.Destroy((Object)(object)debugLoopProxy);
				debugLoopProxy = null;
			}
			debugLoopSource = null;
			debugLoopTimer = 0f;
		}

		public static void LoadBundle()
		{
			playerRepBundle = EmebeddedAssetBundle.LoadFromAssembly(EntanglementMod.entanglementAssembly, "Entanglement.resources.playerrep.eres");
			if ((Object)(object)playerRepBundle == (Object)null)
			{
				throw new NullReferenceException("playerRepBundle is null! Did you forget to compile the player bundle into the dll?");
			}
		}

		public PlayerRepresentation(string playerName, long playerId)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			this.playerName = playerName;
			this.playerId = playerId;
			RecreateRepresentations();
		}

		public void DeleteRepresentations()
		{
			Object.Destroy((Object)(object)repFord);
			Object.Destroy((Object)(object)repCanvas);
			if (Object.op_Implicit((Object)(object)currentSkinObject))
			{
				Object.Destroy((Object)(object)currentSkinObject);
			}
		}

		public void RecreateRepresentations()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				repCanvas = new GameObject("RepCanvas");
				repCanvasComponent = repCanvas.AddComponent<Canvas>();
				repCanvasComponent.renderMode = (RenderMode)2;
				repCanvasTransform = repCanvas.transform;
				repCanvasTransform.localScale = Vector3.one / 200f;
				repNameText = repCanvas.AddComponent<TextMeshProUGUI>();
				((TMP_Text)repNameText).alignment = (TextAlignmentOptions)4098;
				((TMP_Text)repNameText).enableAutoSizing = true;
				((TMP_Text)repNameText).text = playerName;
				repHologram = Object.Instantiate<Material>(playerRepBundle.LoadAsset<Material>("PlayerHolographic"));
				repFord = Object.Instantiate<GameObject>(playerRepBundle.LoadAsset<GameObject>("PlayerRep"));
				((Object)repFord).name = $"PlayerRep.{playerId}";
				repRoot = repFord.transform;
				repGunSFX = ((Component)repRoot.Find("GunSFX")).GetComponent<GunSFX>();
				repBalloonSFX = ((Component)repRoot.Find("BalloonSFX")).GetComponent<GunSFX>();
				repStabSFX = ((Component)repRoot.Find("StabSFX")).GetComponent<GunSFX>();
				repPowerPunchSFX = ((Component)repRoot.Find("PuncherSFX")).GetComponent<GravGunSFX>();
				Transform val = repRoot.Find("Body");
				repBody = ((Component)val).GetComponent<SLZ_Body>();
				repBody.OnStart();
				ragdollBody = ((Component)repRoot.Find("Ragdoll")).GetComponent<SLZ_Body>();
				Transform val2 = repRoot.Find("Brett@neutral");
				repAnimator = ((Component)val2).GetComponent<Animator>();
				repAnimator.runtimeAnimatorController = PlayerScripts.playerAnimatorController;
				activeAnimator = repAnimator;
				repAnimationManager = ((Component)val2).GetComponent<CharacterAnimationManager>();
				repGeo = val2.Find("geoGrp");
				repSHJnt = val2.Find("SHJntGrp");
				repTransforms[0] = repRoot.Find("Head");
				repTransforms[1] = repRoot.Find("Hand (left)");
				repTransforms[2] = repRoot.Find("Hand (right)");
				colliders = Il2CppArrayBase<Collider>.op_Implicit(((Component)repRoot).GetComponentsInChildren<Collider>());
				if (isCustomSkinned && currentSkinPath != null)
				{
					PlayerSkinLoader.ApplyPlayermodel(this, currentSkinPath);
				}
			}
			catch
			{
				EntangleLogger.Error($"Error caught creating rep from user {playerId}");
			}
		}

		public void CreateRagdoll()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_00ea: 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)
			if (!Object.op_Implicit((Object)(object)activeAnimator))
			{
				return;
			}
			GameObject val = new GameObject($"Ragdoll {playerId}");
			GameObject val2 = Object.Instantiate<GameObject>(((Component)ragdollBody).gameObject);
			val2.transform.parent = val.transform;
			Collider[] array = Il2CppArrayBase<Collider>.op_Implicit(val2.GetComponentsInChildren<Collider>(true));
			Collider[] array2 = array;
			foreach (Collider val3 in array2)
			{
				Collider[] array3 = array;
				foreach (Collider val4 in array3)
				{
					if (!((Object)(object)val3 == (Object)(object)val4))
					{
						Physics.IgnoreCollision(val3, val4, true);
					}
				}
			}
			val2.gameObject.SetActive(true);
			foreach (Rigidbody componentsInChild in val2.GetComponentsInChildren<Rigidbody>(true))
			{
				componentsInChild.velocity = repSavedVel;
				componentsInChild.angularVelocity = Vector3.zero;
			}
			CopyBone(((Component)repBody).transform, val2.transform);
			CopyBones(repBody.references, val2.GetComponent<SLZ_Body>().references);
			val2.gameObject.AddComponent<RagdollBehaviour>();
			if (Node.isServer && SteamIntegration.hasLobby)
			{
				MelonCoroutines.Start(SyncRagdollBones(val2));
			}
		}

		private static IEnumerator SyncRagdollBones(GameObject ragdoll)
		{
			yield return (object)new WaitForSeconds(0.5f);
			if (!Object.op_Implicit((Object)(object)ragdoll) || !SteamIntegration.hasLobby || !Node.isServer)
			{
				yield break;
			}
			foreach (Rigidbody rb in ragdoll.GetComponentsInChildren<Rigidbody>(true))
			{
				if (Object.op_Implicit((Object)(object)rb) && !rb.isKinematic && !Object.op_Implicit((Object)(object)TransformSyncable.cache.Get(((Component)rb).gameObject)))
				{
					SyncUtilities.UpdateBodyAttached(rb, null, -1, -1f);
					SyncUtilities.UpdateBodyDetached(rb);
				}
			}
		}

		public void CopyBones(References from, References to)
		{
			CopyBone(from.skull, to.skull);
			CopyBone(from.c4Vertebra, to.c4Vertebra);
			CopyBone(from.t1Offset, to.t1Offset);
			CopyBone(from.t7Vertebra, to.t7Vertebra);
			CopyBone(from.l1Vertebra, to.l1Vertebra);
			CopyBone(from.l3Vertebra, to.l3Vertebra);
			CopyBone(from.sacrum, to.sacrum);
			CopyBone(from.leftHip, to.leftHip);
			CopyBone(from.leftKnee, to.leftKnee);
			CopyBone(from.leftAnkle, to.leftAnkle);
			CopyBone(from.rightHip, to.rightHip);
			CopyBone(from.rightKnee, to.rightKnee);
			CopyBone(from.rightAnkle, to.rightAnkle);
			CopyBone(from.leftShoulder, to.leftShoulder);
			CopyBone(from.leftElbow, to.leftElbow);
			CopyBone(from.leftWrist, to.leftWrist);
			CopyBone(from.rightShoulder, to.rightShoulder);
			CopyBone(from.rightElbow, to.rightElbow);
			CopyBone(from.rightWrist, to.rightWrist);
		}

		public void CopyBone(Transform from, Transform to)
		{
			//IL_0003: 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)
			to.position = from.position;
			to.rotation = from.rotation;
		}

		public void SetNetTargets(Vector3 rootPosition, Vector3[] positions, Quaternion[] rotations)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00fa: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			if (hasNetTarget)
			{
				float num = Mathf.Clamp(time - netReceiveTime, 0.008f, 0.5f);
				netRootVelocity = Vector3.ClampMagnitude((rootPosition - netRootPosition) / num, 25f);
				for (int i = 0; i < netPositions.Length; i++)
				{
					netLimbVelocities[i] = Vector3.ClampMagnitude((positions[i] - netPositions[i]) / num, 25f);
				}
			}
			else
			{
				netRootVelocity = Vector3.zero;
				for (int j = 0; j < netLimbVelocities.Length; j++)
				{
					netLimbVelocities[j] = Vector3.zero;
				}
			}
			netRootPosition = rootPosition;
			netReceiveTime = time;
			for (int k = 0; k < netPositions.Length; k++)
			{
				netPositions[k] = positions[k];
				netRotations[k] = rotations[k];
			}
			hasNetTarget = true;
		}

		public void ApplyNetSmoothing(float dt)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if (!hasNetTarget || !Object.op_Implicit((Object)(object)repRoot))
			{
				return;
			}
			float num = Mathf.Min(Time.time - netReceiveTime, 0.2f);
			Vector3 val = netRootPosition + netRootVelocity * num;
			float num2 = 1f - Mathf.Exp(-35f * dt);
			float num3 = 1f - Mathf.Exp(-60f * dt);
			Vector3 val2 = repRoot.position - val;
			if (((Vector3)(ref val2)).sqrMagnitude > 4f)
			{
				num2 = (num3 = 1f);
			}
			repRoot.position = Vector3.Lerp(repRoot.position, val, num2);
			for (int i = 0; i < repTransforms.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)repTransforms[i]))
				{
					repTransforms[i].position = Vector3.Lerp(repTransforms[i].position, netPositions[i] + netLimbVelocities[i] * num, num3);
					repTransforms[i].rotation = Quaternion.Slerp(repTransforms[i].rotation, netRotations[i], num3);
				}
			}
			UpdateNametagPosition();
			UpdateTalkingIndicator();
		}

		public void UpdateNametagPosition()
		{
			//IL_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)repCanvasTransform) && !((Object)(object)repTransforms[0] == (Object)null))
			{
				repCanvasTransform.position = repTransforms[0].position + Vector3.up * 0.4f;
				if (Object.op_Implicit((Object)(object)Camera.current))
				{
					repCanvasTransform.rotation = Quaternion.LookRotation(Vector3.Normalize(repCanvasTransform.position - ((Component)Camera.current).transform.position), Vector3.up);
				}
			}
		}

		public void SetNameColor(Color color)
		{
			//IL_0002: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			baseNameColor = color;
			if (!wasTalking && Object.op_Implicit((Object)(object)repNameText))
			{
				((TMP_Text)repNameText).color = baseNameColor;
			}
		}

		private void UpdateTalkingIndicator()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)repNameText))
			{
				bool flag = VoiceManager.IsSpeaking(playerId);
				if (flag != wasTalking)
				{
					wasTalking = flag;
					((TMP_Text)repNameText).text = (flag ? ("● " + playerName) : playerName);
					((TMP_Text)repNameText).color = (Color)(flag ? new Color(0.4f, 1f, 0.5f) : baseNameColor);
				}
			}
		}

		public void SaveVelocity()
		{
			//IL_0007: 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_0015: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = repRoot.position;
			float fixedDeltaTime = Time.fixedDeltaTime;
			repSavedVel = Vector3.Slerp(repInputVel, PhysicsData.GetVelocity(position, prevRepRootPos, fixedDeltaTime), fixedDeltaTime * legJitter);
			if (isGrounded)
			{
				repInputVel = repSavedVel;
			}
			else
			{
				repInputVel = Vector3.zero;
			}
			prevRepRootPos = position;
		}

		public void UpdateIK()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((!Object.op_Implicit((Object)(object)currentSkinBundle) || !Object.op_Implicit((Object)(object)currentSkinObject)) && isCustomSkinned)
				{
					PlayerSkinLoader.ApplyPlayermodel(this, currentSkinPath);
				}
				if (Object.op_Implicit((Object)(object)activeAnimator))
				{
					activeAnimator.Update(Time.fixedDeltaTime);
					repAnimationManager.OnLateUpdate();
					SaveVelocity();
					repBody.FullBodyUpdate(repInputVel, Vector3.zero);
					repBody.ArtToBlender.UpdateBlender();
				}
			}
			catch
			{
			}
		}

		public void UpdatePose(Handedness hand, int index)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Il2CppStringArray playerHandPoses = PlayerScripts.playerHandPoses;
			if (((Il2CppArrayBase<string>)(object)playerHandPoses).Count >= index + 1)
			{
				UpdatePose(hand, ((Il2CppArrayBase<string>)(object)playerHandPoses)[index]);
			}
		}

		public void UpdatePose(Handedness hand, string pose)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			CharacterAnimationManager obj = repAnimationManager;
			if (obj != null)
			{
				obj.SetHandPose(hand, pose);
			}
		}

		public void UpdatePoseRadius(Handedness hand, float radius)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			CharacterAnimationManager obj = repAnimationManager;
			if (obj != null)
			{
				obj.SetCylinderRadius(hand, radius);
			}
		}

		public void UpdateFingers(Handedness hand, float indexCurl = 1f, float middleCurl = 1f, float ringCurl = 1f, float pinkyCurl = 1f, float thumbCurl = 1f)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			repAnimationManager.ApplyFingerCurl(hand, 1f - thumbCurl, 1f - indexCurl, 1f - middleCurl, 1f - ringCurl, 1f - pinkyCurl);
		}

		public void UpdateFingers(Handedness hand, SimplifiedHand handData)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			UpdateFingers(hand, handData.indexCurl, handData.middleCurl, handData.ringCurl, handData.pinkyCurl, handData.thumbCurl);
		}

		public void IgnoreCollision(Rigidbody otherBody, bool ignore)
		{
			Collider[] array = Il2CppArrayBase<Collider>.op_Implicit(((Component)otherBody).GetComponentsInChildren<Collider>());
			Collider[] array2 = colliders;
			foreach (Collider val in array2)
			{
				Collider[] array3 = array;
				foreach (Collider val2 in array3)
				{
					Physics.IgnoreCollision(val, val2, ignore);
				}
			}
		}

		public static void GetPlayerTransforms()
		{
			GameObject val = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
			if (Object.op_Implicit((Object)(object)val))
			{
				syncedRoot = val.transform;
				syncedPoints[0] = syncedRoot.Find("Head");
				syncedPoints[1] = syncedRoot.Find("Hand (left)");
				syncedPoints[2] = syncedRoot.Find("Hand (right)");
			}
		}

		public static PlayerRepSyncData GetPlayerSyncData()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			Transform[] array = syncedPoints;
			foreach (Transform val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
			}
			PlayerRepSyncData playerRepSyncData = new PlayerRepSyncData();
			playerRepSyncData.userId = SteamIntegration.currentUserId;
			for (int j = 0; j < playerRepSyncData.simplifiedTransforms.Length; j++)
			{
				playerRepSyncData.simplifiedTransforms[j].position = syncedPoints[j].position;
				playerRepSyncData.simplifiedTransforms[j].rotation = SimplifiedQuaternion.SimplifyQuat(syncedPoints[j].rotation);
			}
			playerRepSyncData.rootPosition = syncedRoot.position;
			playerRepSyncData.isGrounded = PlayerScripts.playerGrounder.isGrounded;
			playerRepSyncData.simplifiedLeftHand = new SimplifiedHand(PlayerScripts.playerLeftHand.fingerCurl);
			playerRepSyncData.simplifiedRightHand = new SimplifiedHand(PlayerScripts.playerRightHand.fingerCurl);
			try
			{
				if (debugRepresentation != null)
				{
					for (int k = 0; k < playerRepSyncData.simplifiedTransforms.Length; k++)
					{
						playerRepSyncData.simplifiedTransforms[k].Apply(debugRepresentation.repTransforms[k]);
						Transform obj = debugRepresentation.repTransforms[k];
						obj.position += Vector3.forward;
					}
					debugRepresentation.repRoot.position = syncedRoot.position + Vector3.forward;
					debugRepresentation.isGrounded = playerRepSyncData.isGrounded;
					debugRepresentation.UpdateFingers((Handedness)1, playerRepSyncData.simplifiedLeftHand);
					debugRepresentation.UpdateFingers((Handedness)2, playerRepSyncData.simplifiedRightHand);
					debugRepresentation.UpdateNametagPosition();
				}
				UpdateDebugHeldLoopback();
			}
			catch
			{
			}
			return playerRepSyncData;
		}

		public static void SyncPlayerReps()
		{
			if (SteamIntegration.hasLobby)
			{
				PlayerRepSyncData playerSyncData = GetPlayerSyncData();
				if (playerSyncData != null)
				{
					NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.PlayerRepSync, playerSyncData);
					Node.activeNode.BroadcastMessage(NetworkChannel.Unreliable, networkMessage.GetBytes());
				}
				else
				{
					GetPlayerTransforms();
				}
			}
			else if ((debugRepresentation != null || (Object)(object)debugLoopProxy != (Object)null) && GetPlayerSyncData() == null)
			{
				GetPlayerTransforms();
			}
		}

		public static void UpdatePlayerReps()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)syncedRoot))
			{
				return;
			}
			foreach (PlayerRepresentation value in representations.Values)
			{
				if (value == null || !Object.op_Implicit((Object)(object)value.repRoot))
				{
					continue;
				}
				value.ApplyNetSmoothing(Time.fixedDeltaTime);
				Vector3 val = syncedRoot.position - value.repRoot.position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (!(sqrMagnitude < 1000000f))
				{
					continue;
				}
				value.UpdateIK();
				Transform obj = value.repCanvasTransform;
				if (obj != null)
				{
					GameObject gameObject = ((Component)obj).gameObject;
					if (gameObject != null)
					{
						gameObject.SetActive(Client.nameTagsVisible && !value.IsEliminated);
					}
				}
			}
			try
			{
				if (debugRepresentation != null)
				{
					debugRepresentation.UpdateIK();
				}
			}
			catch
			{
			}
		}
	}
}
namespace Entanglement.Patching
{
	public static class Patcher
	{
		public static void Initialize()
		{
			OptionalAssemblyPatch.AttemptPatches();
		}

		public static void Patch(MethodBase method, HarmonyMethod prefix = null, HarmonyMethod postfix = null)
		{
			((MelonBase)EntanglementMod.Instance).HarmonyInstance.Patch(method, prefix, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
	}
	[HarmonyPatch(typeof(Prop_Health), "DESTROYED")]
	public static class PropHealthPatch
	{
		public static bool Prefix(Prop_Health __instance)
		{
			if (!Object.op_Implicit((Object)(object)__instance.impactSFX))
			{
				return false;
			}
			return true;
		}

		public static void Postfix(Prop_Health __instance)
		{
			if (SteamIntegration.hasLobby)
			{
				TransformSyncable transformSyncable = TransformSyncable.DestructCache.Get(((Component)__instance).gameObject);
				if (Object.op_Implicit((Object)(object)transformSyncable) && transformSyncable.IsOwner())
				{
					NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.ObjectDestroy, new ObjectDestroyMessageData
					{
						objectId = transformSyncable.objectId
					});
					byte[] bytes = networkMessage.GetBytes();
					Node.activeNode.BroadcastMessage(NetworkChannel.Reliable, bytes);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDestructable), "TakeDamage")]
	public static class DestructablePatch
	{
		public static void Postfix(ObjectDestructable __instance, Vector3 normal, float damage, bool crit = false, AttackType attackType = (AttackType)0)
		{
			if (SteamIntegration.hasLobby && __instance._isDead)
			{
				TransformSyncable transformSyncable = TransformSyncable.DestructCache.Get(((Component)__instance).gameObject);
				if (Object.op_Implicit((Object)(object)transformSyncable) && transformSyncable.IsOwner())
				{
					NetworkMessage networkMessage = NetworkMessage.CreateMessage(BuiltInMessageType.ObjectDestroy, new ObjectDestroyMessageData
					{
						objectId = transformSyncable.objectId
					});
					byte[] bytes = networkMessage.GetBytes();
					Node.activeNode.BroadcastMessage(NetworkChannel.Reliable, bytes);
				}
			}
		}
	}
	public static class FantasyArena_Settings
	{
		public static bool m_invalidSettings;

		public static void SendEnemyCount(bool isLow)
		{
			NetworkMessage networkMessage = NetworkMessage.CreateMessage(