Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalBodySwap v1.0.0
LethalBodySwap.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("LethalBodySwap")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LethalBodySwap")] [assembly: AssemblyTitle("LethalBodySwap")] [assembly: AssemblyVersion("1.0.0.0")] namespace LethalBodySwap { [BepInPlugin("Dex.LethalBodySwap", "Lethal Body Swap", "1.0.0")] public class LethalBodySwapModBase : BaseUnityPlugin { private const string modGUID = "Dex.LethalBodySwap"; private const string modName = "Lethal Body Swap"; private const string modVersion = "1.0.0"; private readonly Harmony harmony = new Harmony("Dex.LethalBodySwap"); public static LethalBodySwapModBase Instance; internal ManualLogSource Logger; internal static ConfigEntry<Key> SwapKey; internal static ConfigEntry<bool> IncludeDeadPlayers; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; Logger = Logger.CreateLogSource("Dex.LethalBodySwap"); Logger.LogInfo((object)"Initialized Lethal Body Swap!"); SwapKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "SwapKey", (Key)25, "Key that once pressed by the host will force all players to swap."); IncludeDeadPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Experimental", "IncludeDeadPlayers", false, "If true, will include dead bodies as possible teleport destinations (latet anguis in herba)"); harmony.PatchAll(Assembly.GetExecutingAssembly()); } else { Object.Destroy((Object)(object)this); } } } internal static class SwapManager { private const string TeleportMessageName = "RandomSwap_TeleportTo"; private static bool _registered; private static bool _swapInProgress = false; private static float _lastSwapTime = -999f; private const float SwapCooldown = 1f; private static AudioClip teleportSound; internal static void RegisterMessageHandler() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null && !_registered) { singleton.CustomMessagingManager.RegisterNamedMessageHandler("RandomSwap_TeleportTo", new HandleNamedMessageDelegate(OnReceiveTeleportMessage)); _registered = true; LethalBodySwapModBase.Instance.Logger.LogInfo((object)$"RandomSwap message handler registered. IsHost={singleton.IsHost}, IsClient={singleton.IsClient}, LocalClientId={singleton.LocalClientId}"); } } internal static void UnregisterMessageHandler() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.CustomMessagingManager != null && _registered) { singleton.CustomMessagingManager.UnregisterNamedMessageHandler("RandomSwap_TeleportTo"); } _registered = false; } private static void OnReceiveTeleportMessage(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_00d9: 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) float num = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num, default(ForPrimitives)); float num2 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num2, default(ForPrimitives)); float num3 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num3, default(ForPrimitives)); float num4 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num4, default(ForPrimitives)); bool insideFactory = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref insideFactory, default(ForPrimitives)); bool inHangarShipRoom = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref inHangarShipRoom, default(ForPrimitives)); PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null); if ((Object)(object)val == (Object)null) { LethalBodySwapModBase.Instance.Logger.LogWarning((object)"RandomSwap: received teleport message but local player controller is null."); return; } Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(num, num2, num3); try { val.averageVelocity = 0f; val.velocityLastFrame = Vector3.zero; val.TeleportPlayer(val2, true, num4, false, true); RefreshPlayerEnvironment(val, insideFactory, inHangarShipRoom); PlayTeleportSound(val); } catch (Exception arg) { LethalBodySwapModBase.Instance.Logger.LogError((object)$"RandomSwap: teleport failed: {arg}"); } } private static void RefreshPlayerEnvironment(PlayerControllerB player, bool insideFactory, bool inHangarShipRoom) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } player.averageVelocity = 0f; player.velocityLastFrame = Vector3.zero; AudioReverbPresets val = Object.FindObjectOfType<AudioReverbPresets>(); if ((Object)(object)val != (Object)null) { try { int num = (insideFactory ? 2 : 3); val.audioPresets[num].ChangeAudioReverbForPlayer(player); } catch (Exception arg) { LethalBodySwapModBase.Instance.Logger.LogWarning((object)$"RandomSwap: failed to refresh audio reverb: {arg}"); } } player.isInsideFactory = insideFactory; player.isInHangarShipRoom = !insideFactory && inHangarShipRoom; player.isInElevator = false; for (int i = 0; i < player.ItemSlots.Length; i++) { if ((Object)(object)player.ItemSlots[i] != (Object)null) { player.ItemSlots[i].isInFactory = insideFactory; } } if ((Object)(object)player.ItemOnlySlot != (Object)null) { player.ItemOnlySlot.isInFactory = insideFactory; } if ((Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)player && (Object)(object)TimeOfDay.Instance != (Object)null) { bool flag = insideFactory || inHangarShipRoom; TimeOfDay.Instance.insideLighting = flag; TimeOfDay.Instance.SetInsideLightingDimness(true, flag); } } internal static void TriggerRandomSwap(bool includeDead = false) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsHost) { LethalBodySwapModBase.Instance.Logger.LogWarning((object)"RandomSwap: only the host can trigger a swap."); return; } if (_swapInProgress) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)"RandomSwap: ignored because a swap is already in progress."); return; } if (Time.unscaledTime - _lastSwapTime < 1f) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)"RandomSwap: ignored because the swap cooldown is active."); return; } _swapInProgress = true; _lastSwapTime = Time.unscaledTime; try { StartRandomSwapInternal(singleton, includeDead); } finally { _swapInProgress = false; } } private unsafe static void StartRandomSwapInternal(NetworkManager nm, bool includeDead) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { LethalBodySwapModBase.Instance.Logger.LogWarning((object)"RandomSwap: StartOfRound not ready."); return; } List<PlayerControllerB> list = new List<PlayerControllerB>(); PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && (includeDead || !val.isPlayerDead)) { list.Add(val); } } int count = list.Count; if (count < 2) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)"RandomSwap: fewer than 2 eligible players, nothing to swap."); return; } Vector3[] array = (Vector3[])(object)new Vector3[count]; float[] array2 = new float[count]; bool[] array3 = new bool[count]; bool[] array4 = new bool[count]; for (int j = 0; j < count; j++) { PlayerControllerB val2 = list[j]; Transform val3 = (((Object)(object)val2.thisPlayerBody != (Object)null) ? val2.thisPlayerBody : ((Component)val2).transform); array[j] = val3.position; array2[j] = val3.eulerAngles.y; array3[j] = val2.isInsideFactory; array4[j] = val2.isInHangarShipRoom; } int[] array5 = SattoloDerangement(count); for (int k = 0; k < count; k++) { if (array5[k] == k) { LethalBodySwapModBase.Instance.Logger.LogError((object)"RandomSwap: derangement check failed. Aborting."); return; } } int num = 0; FastBufferWriter val6 = default(FastBufferWriter); for (int l = 0; l < count; l++) { PlayerControllerB val4 = list[l]; Vector3 val5 = array[array5[l]]; float num2 = array2[array5[l]]; bool insideFactory = array3[array5[l]]; bool inHangarShipRoom = array4[array5[l]]; if (((NetworkBehaviour)val4).IsOwner) { val4.TeleportPlayer(val5, true, num2, false, true); RefreshPlayerEnvironment(val4, insideFactory, inHangarShipRoom); PlayTeleportSound(val4); num++; } else if (nm.ConnectedClientsIds.Contains(((NetworkBehaviour)val4).OwnerClientId)) { ((FastBufferWriter)(ref val6))..ctor(18, (Allocator)2, -1); try { ((FastBufferWriter)(ref val6)).WriteValueSafe<float>(ref val5.x, default(ForPrimitives)); ((FastBufferWriter)(ref val6)).WriteValueSafe<float>(ref val5.y, default(ForPrimitives)); ((FastBufferWriter)(ref val6)).WriteValueSafe<float>(ref val5.z, default(ForPrimitives)); ((FastBufferWriter)(ref val6)).WriteValueSafe<float>(ref num2, default(ForPrimitives)); ((FastBufferWriter)(ref val6)).WriteValueSafe<bool>(ref insideFactory, default(ForPrimitives)); ((FastBufferWriter)(ref val6)).WriteValueSafe<bool>(ref inHangarShipRoom, default(ForPrimitives)); nm.CustomMessagingManager.SendNamedMessage("RandomSwap_TeleportTo", ((NetworkBehaviour)val4).OwnerClientId, val6, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val6))/*cast due to .constrained prefix*/).Dispose(); } num++; } } LethalBodySwapModBase.Instance.Logger.LogInfo((object)($"RandomSwap: completed ONE {count}-player derangement " + $"({num} teleport instructions dispatched).")); } private static int[] SattoloDerangement(int n) { if (n < 2) { throw new ArgumentException("Derangement requires at least 2 elements.", "n"); } int[] array = new int[n]; for (int i = 0; i < n; i++) { array[i] = i; } Random random = new Random(); for (int num = n - 1; num > 0; num--) { int num2 = random.Next(0, num); ref int reference = ref array[num]; ref int reference2 = ref array[num2]; int num3 = array[num2]; int num4 = array[num]; reference = num3; reference2 = num4; } return array; } private static void PlayTeleportSound(PlayerControllerB player) { FindTeleportSound(); if (!((Object)(object)teleportSound == (Object)null) && !((Object)(object)player == (Object)null) && !((Object)(object)player.movementAudio == (Object)null)) { player.movementAudio.PlayOneShot(teleportSound); } } private static void FindTeleportSound() { if ((Object)(object)teleportSound != (Object)null) { return; } AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>(); AudioClip[] array2 = array; foreach (AudioClip val in array2) { if (!((Object)(object)val == (Object)null) && ((Object)val).name == "ShipTeleporterBeam") { teleportSound = val; LethalBodySwapModBase.Instance.Logger.LogInfo((object)("Found teleporter sound: " + ((Object)val).name)); return; } } LethalBodySwapModBase.Instance.Logger.LogWarning((object)"Could not find ShipTeleporterBeam."); } } } namespace LethalBodySwap.Patches { [HarmonyPatch(typeof(NetworkManager))] internal static class NetworkManagerPatches { [HarmonyPatch("StartClient")] [HarmonyPostfix] private static void StartClient_Postfix() { SwapManager.RegisterMessageHandler(); } [HarmonyPatch("StartHost")] [HarmonyPostfix] private static void StartHost_Postfix() { SwapManager.RegisterMessageHandler(); } [HarmonyPatch("Shutdown")] [HarmonyPrefix] private static void Shutdown_Prefix() { SwapManager.UnregisterMessageHandler(); } } [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerControllerBPatches { private static bool _keyWasPressed; [HarmonyPatch("Update")] [HarmonyPostfix] private static void Update_Postfix(PlayerControllerB __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && Keyboard.current != null && ((ButtonControl)Keyboard.current[LethalBodySwapModBase.SwapKey.Value]).wasPressedThisFrame && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsHost) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)"Swap key pressed."); if ((Object)(object)StartOfRound.Instance == (Object)null) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)"Ignored: no active round."); } else { SwapManager.TriggerRandomSwap(LethalBodySwapModBase.IncludeDeadPlayers.Value); } } } } [HarmonyPatch(typeof(TimeOfDay))] internal static class TimeOfDayPatch { [HarmonyPatch("OnHourChanged")] [HarmonyPostfix] private static void OnHourChanged_Postfix(TimeOfDay __instance) { if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsServer && !((Object)(object)StartOfRound.Instance == (Object)null)) { LethalBodySwapModBase.Instance.Logger.LogInfo((object)$"RandomSwap: hour changed to {__instance.hour}. Triggering player swap."); SwapManager.TriggerRandomSwap(LethalBodySwapModBase.IncludeDeadPlayers.Value); } } } }