Latest versions of MelonLoader are known to have issues with some games. Use version 0.5.4 until the issue has been fixed!
Decompiled source of Entanglement Redux v2.0.0
EntanglementRedux.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.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(