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 LethalBattleRoyale v0.0.1
baer1.BattleRoyaleMode.dll
Decompiled a year agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using CSync.Extensions; using CSync.Lib; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("baer1.BattleRoyaleMode")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: AssemblyInformationalVersion("0.0.1+f1b228131e4ce2169bc1d3d81aa87b48eaf56681")] [assembly: AssemblyProduct("LethalBattleRoyale")] [assembly: AssemblyTitle("baer1.BattleRoyaleMode")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LethalBattleRoyale { [BepInPlugin("baer1.BattleRoyaleMode", "LethalBattleRoyale", "0.0.1")] [BepInDependency("com.sigurd.csync", "5.0.0")] public class LethalBattleRoyale : BaseUnityPlugin { public enum RoundStartModes { Disabled, Timer, RandomTeleport } public enum RoundStartPositions { Ship, MainEntrance, FireExit, Random } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayerServerRpc")] internal class KillPlayerPatch { private static void Postfix(ref PlayerControllerB __instance, ref int playerId, ref bool spawnBody, ref Vector3 bodyVelocity, ref int causeOfDeath, ref int deathAnimation, ref Vector3 positionOffset) { if (Instance.Enable && Instance.DeathMessages && ((NetworkBehaviour)__instance).IsServer) { HUDManager.Instance.AddTextMessageServerRpc($"<color=#00ffff>Player #{__instance.playerClientId} {__instance.playerUsername} {a((CauseOfDeath)causeOfDeath)}</color>"); } } private static string a(CauseOfDeath causeOfDeath) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected I4, but got Unknown if (1 == 0) { } string result = (causeOfDeath - 1) switch { 0 => "was killed", 1 => "fell from a high place", 2 => "exploded", 3 => "was strangled", 4 => "suffocated", 5 => "was mauled to death", 6 => "was shot", 7 => "was crushed", 8 => "drowned", 9 => "was left behind", 10 => "was electrocuted", 11 => "was kicked to death", 12 => "burned to death", 13 => "was stabbed to death", 14 => "was ripped apart", 15 => "died of inertia", 16 => "was cut in half", _ => "died", }; if (1 == 0) { } return result; } } [HarmonyPatch(typeof(RoundManager), "SpawnEnemyGameObject")] internal class SpawnEnemyGameObjectPatch { private static bool Prefix() { return a(); } internal static bool a() { return !Instance.Enable || Instance.SpawnEnemies; } } [HarmonyPatch(typeof(RoundManager), "SpawnRandomOutsideEnemy")] internal class SpawnRandomOutsideEnemyPatch { private static bool Prefix() { return SpawnEnemyGameObjectPatch.a(); } } [HarmonyPatch(typeof(RoundManager), "SpawnRandomDaytimeEnemy")] internal class SpawnRandomDaytimeEnemyPatch { private static bool Prefix() { return SpawnEnemyGameObjectPatch.a(); } } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] internal class SpawnScrapInLevelPatch { private static bool Prefix() { return !Instance.Enable || Instance.SpawnScrap; } } [HarmonyPatch(typeof(EnemyVent), "Update")] internal class EnemyVentUpdatePatch { private static bool Prefix(ref EnemyVent __instance) { if (!Instance.Enable) { return true; } if (Instance.DisableVents) { __instance.ventAudio.volume = 0f; } return !Instance.DisableVents; } } [HarmonyPatch(typeof(StartOfRound), "Awake")] internal class StartOfRoundAwakePatch { private static void Postfix() { if (roundCoroutine != null) { Logger.LogWarning((object)"roundCoroutine is not null, overwriting"); } roundCoroutine = null; Instance.thisEnable = null; Instance.thisDeathMessages = null; Instance.thisSpawnEnemies = null; Instance.thisSpawnScrap = null; Instance.thisDisableVents = null; Instance.thisRoundStartMode = null; Instance.thisRoundStartTimer = null; Instance.thisRoundStartPosition = null; Instance.thisRoundStartInside = null; } } [HarmonyPatch(typeof(StartOfRound), "OpenShipDoors")] internal class StartGamePatch { private static void Prefix() { Instance.thisEnable = Instance.enable?.Value ?? false; LethalBattleRoyale instance = Instance; SyncedEntry<bool> deathMessages = Instance.deathMessages; bool value = ((deathMessages == null || deathMessages.Value) ? true : false); instance.thisDeathMessages = value; Instance.thisSpawnEnemies = Instance.spawnEnemies?.Value ?? false; Instance.thisSpawnScrap = Instance.spawnScrap?.Value ?? false; LethalBattleRoyale instance2 = Instance; deathMessages = Instance.disableVents; bool value2 = ((deathMessages == null || deathMessages.Value) ? true : false); instance2.thisDisableVents = value2; Instance.thisRoundStartMode = Instance.roundStartMode?.Value ?? RoundStartModes.Timer; Instance.thisRoundStartTimer = Instance.roundStartTimer?.Value ?? 30f; Instance.thisRoundStartPosition = Instance.roundStartPosition?.Value ?? RoundStartPositions.MainEntrance; LethalBattleRoyale instance3 = Instance; deathMessages = Instance.roundStartInside; value = ((deathMessages == null || deathMessages.Value) ? true : false); instance3.thisRoundStartInside = value; if (Instance.Enable) { HUDManager.Instance.AddTextMessageServerRpc("<color=#ffd900>LethalBattleRoyale v0.0.1</color>"); HUDManager.Instance.AddTextMessageServerRpc("<color=#00ffff>Spawning enemies: " + a(Instance.SpawnEnemies) + "\nSpawning scrap: " + a(Instance.SpawnScrap) + "\nVents " + a(Instance.DisableVents) + "\nDeath messages " + a(Instance.DeathMessages) + "\nRound start mode: " + b(Instance.RoundStartMode, Instance.RoundStartTimer, Instance.RoundStartPosition, Instance.RoundStartInside) + "</color>"); } } private static string a(bool b) { return b ? "enabled" : "disabled"; } private static string b(RoundStartModes mode, float timer, RoundStartPositions position, bool inside) { if (1 == 0) { } string result = mode switch { RoundStartModes.Timer => "Timer - " + c(timer) + " from " + d(position, inside), RoundStartModes.RandomTeleport => "Per-player spawn " + e(inside), _ => "Disabled", }; if (1 == 0) { } return result; } private static string c(float timer) { return $"{Math.Round(timer, 2)} seconds"; } private static string d(RoundStartPositions position, bool inside) { if (1 == 0) { } string result = position switch { RoundStartPositions.Ship => "Ship", RoundStartPositions.MainEntrance => "Main Entrance", RoundStartPositions.FireExit => "Fire Exit", RoundStartPositions.Random => "random position " + e(inside), _ => position.ToString(), }; if (1 == 0) { } return result; } private static string e(bool inside) { return inside ? "inside" : "outside"; } } [HarmonyPatch(typeof(StartMatchLever), "EndGame")] internal class EndGamePatch { private static bool Prefix() { if (!Instance.Enable) { return true; } if (StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB i) => i.isPlayerControlled) <= 1 && roundCoroutine == null) { return true; } HUDManager.Instance.DisplayTip("You can't do that", "This game is not over yet", true, false, "LC_Tip1"); return false; } } [HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")] internal class RoundStartPatch { private static void Postfix(ref StartOfRound __instance) { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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) Logger.LogDebug((object)$">> RoundStartPatch({__instance}) Enable:{Instance.Enable} RoundStartMode:{Instance.RoundStartMode} IsServer:{((NetworkBehaviour)__instance).IsServer}"); if (!Instance.Enable || Instance.RoundStartMode == RoundStartModes.Disabled) { return; } switch (Instance.RoundStartMode) { case RoundStartModes.RandomTeleport: RandomTeleportLocalPlayer(StartOfRound.Instance.randomMapSeed + (int)GameNetworkManager.Instance.localPlayerController.playerClientId, Instance.RoundStartInside); RoundStart(ref __instance, 5f); break; case RoundStartModes.Timer: switch (Instance.RoundStartPosition) { case RoundStartPositions.Ship: TeleportLocalPlayer(__instance.GetPlayerSpawnPosition((int)GameNetworkManager.Instance.localPlayerController.playerClientId, true), inside: false); break; case RoundStartPositions.MainEntrance: TeleportLocalPlayer(RoundManager.FindMainEntrancePosition(true, !Instance.RoundStartInside), Instance.RoundStartInside); break; case RoundStartPositions.FireExit: TeleportLocalPlayer(FindFireExitPosition(StartOfRound.Instance.randomMapSeed + (int)GameNetworkManager.Instance.localPlayerController.playerClientId, !Instance.RoundStartInside), Instance.RoundStartInside); break; case RoundStartPositions.Random: RandomTeleportLocalPlayer(StartOfRound.Instance.randomMapSeed, Instance.RoundStartInside); break; } RoundStart(ref __instance, Instance.RoundStartTimer); break; case RoundStartModes.Disabled: RoundStart(ref __instance, 5f); break; } } } private SyncedEntry<bool>? enable; private SyncedEntry<bool>? deathMessages; private SyncedEntry<bool>? spawnEnemies; private SyncedEntry<bool>? spawnScrap; private SyncedEntry<bool>? disableVents; private SyncedEntry<RoundStartModes>? roundStartMode; private SyncedEntry<float>? roundStartTimer; private const float ROUND_START_TIMER = 30f; private SyncedEntry<RoundStartPositions>? roundStartPosition; private SyncedEntry<bool>? roundStartInside; private bool? thisEnable; private bool? thisDeathMessages; private bool? thisSpawnEnemies; private bool? thisSpawnScrap; private bool? thisDisableVents; private RoundStartModes? thisRoundStartMode; private float? thisRoundStartTimer; private RoundStartPositions? thisRoundStartPosition; private bool? thisRoundStartInside; private static Coroutine? roundCoroutine; private const string BEGIN = "<color=#00ff00>BEGIN!</color>"; private const int SHOTGUN_ITEM = 59; private const int GUN_AMMO = 60; public static LethalBattleRoyale Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; set; } public bool Enable => thisEnable.GetValueOrDefault(); public bool DeathMessages => thisDeathMessages.GetValueOrDefault(true); public bool SpawnEnemies => thisSpawnEnemies.GetValueOrDefault(); public bool SpawnScrap => thisSpawnScrap.GetValueOrDefault(); public bool DisableVents => thisDisableVents.GetValueOrDefault(true); public RoundStartModes RoundStartMode => thisRoundStartMode.GetValueOrDefault(RoundStartModes.Timer); public float RoundStartTimer => thisRoundStartTimer.GetValueOrDefault(30f); public RoundStartPositions RoundStartPosition => thisRoundStartPosition.GetValueOrDefault(RoundStartPositions.MainEntrance); public bool RoundStartInside => thisRoundStartInside.GetValueOrDefault(true); private void Awake() { //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_0158: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Instance = this; enable = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "General", "Enable", true, "Global switch for all mod functionality"); deathMessages = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "General", "DeathMessages", true, "Displays death messages in chat"); spawnEnemies = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "Vanilla", "SpawnEnemies", false, "Whether to allow enemy spawning"); spawnScrap = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "Vanilla", "SpawnScrap", false, "Whether to allow scrap spawning"); disableVents = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "Vanilla", "DisableVents", true, "Whether to disable vent sounds"); roundStartMode = SyncedBindingExtensions.BindSyncedEntry<RoundStartModes>(((BaseUnityPlugin)this).Config, "RoundStart", "RoundStartMode", RoundStartModes.Timer, "How the round should start"); roundStartTimer = SyncedBindingExtensions.BindSyncedEntry<float>(((BaseUnityPlugin)this).Config, "RoundStart", "RoundStartTimer", 30f, "How long the timer should be (RoundStartMode Timer)"); roundStartPosition = SyncedBindingExtensions.BindSyncedEntry<RoundStartPositions>(((BaseUnityPlugin)this).Config, "RoundStart", "RoundStartPosition", RoundStartPositions.MainEntrance, "Where the round should start (RoundStartMode Timer)"); roundStartInside = SyncedBindingExtensions.BindSyncedEntry<bool>(((BaseUnityPlugin)this).Config, "RoundStart", "RoundStartInside", true, "Should the round start outside or inside (RoundStartMode Timer or RandomTeleport)"); if (Harmony == null) { Harmony = new Harmony("baer1.BattleRoyaleMode"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); Logger.LogInfo((object)"baer1.BattleRoyaleMode v0.0.1 has loaded!"); } private static void RandomTeleportLocalPlayer(int seed, bool inside) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) GameObject[] array = (inside ? RoundManager.Instance.insideAINodes : RoundManager.Instance.outsideAINodes); TeleportLocalPlayer(array[new Random(seed).Next(array.Length)].transform.position, inside); } private static void TeleportLocalPlayer(Vector3 position, bool inside) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) Logger.LogDebug((object)$">> TeleportLocalPlayer({position}, {inside})"); GameNetworkManager.Instance.localPlayerController.DropAllHeldItems(true, false); if (Object.op_Implicit((Object)(object)Object.FindObjectOfType<AudioReverbPresets>())) { Object.FindObjectOfType<AudioReverbPresets>().audioPresets[2].ChangeAudioReverbForPlayer(GameNetworkManager.Instance.localPlayerController); } GameNetworkManager.Instance.localPlayerController.isInElevator = false; GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom = false; GameNetworkManager.Instance.localPlayerController.isInsideFactory = inside; GameNetworkManager.Instance.localPlayerController.averageVelocity = 0f; GameNetworkManager.Instance.localPlayerController.velocityLastFrame = Vector3.zero; GameNetworkManager.Instance.localPlayerController.TeleportPlayer(position, false, 0f, false, true); HUDManager.Instance.ShakeCamera((ScreenShakeType)1); } private static Vector3 FindFireExitPosition(int seed, bool outside) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_0050: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>(false); EntranceTeleport[] array2 = array; foreach (EntranceTeleport val in array2) { if (val.entranceId == 0) { continue; } if (!outside) { if (!val.isEntranceToBuilding) { list.Add(val.entrancePoint.position); } } else if (val.isEntranceToBuilding) { list.Add(val.entrancePoint.position); } } if (list.Count != 0) { return list[new Random(seed).Next(list.Count)]; } Logger.LogDebug((object)"Fire exit position could not be found. Returning origin."); return Vector3.zero; } internal static void RoundStart(ref StartOfRound __instance, float timer) { if (((NetworkBehaviour)__instance).IsServer) { if (roundCoroutine != null) { Logger.LogWarning((object)"roundCoroutine is not null, skipping"); } else { roundCoroutine = ((MonoBehaviour)__instance).StartCoroutine(StartCountdown(timer)); } } } private static IEnumerator StartCountdown(float timer) { try { Logger.LogDebug((object)$">> StartCountdown({timer})"); int? timerDisplay = null; while (timer > 0f) { if (StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB i) => i.isPlayerControlled) < 1) { RoundEnd(null); yield break; } if (!timerDisplay.HasValue || Mathf.CeilToInt(timer) < timerDisplay) { timerDisplay = Mathf.CeilToInt(timer); HUDManager.Instance.AddTextMessageServerRpc($"Round starts in {timerDisplay} seconds..."); } timer -= Time.deltaTime; yield return null; } GiveShotguns(); do { yield return null; } while (StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB i) => i.isPlayerControlled) > 1); RoundEnd(((IEnumerable<PlayerControllerB>)StartOfRound.Instance.allPlayerScripts).FirstOrDefault((Func<PlayerControllerB, bool>)((PlayerControllerB i) => i.isPlayerControlled))); } finally { roundCoroutine = null; } } private static void GiveShotguns() { //IL_004a: 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_00f1: 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) Logger.LogDebug((object)">> GiveShotguns"); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { GameObject val2 = Object.Instantiate<GameObject>(StartOfRound.Instance.allItemsList.itemsList[59].spawnPrefab, ((Component)val).transform.position, Quaternion.identity, StartOfRound.Instance.propsContainer); Logger.LogDebug((object)$" Spawned shotgun {val2} for player #{val.playerClientId} {val.playerUsername} ({val})"); val2.GetComponent<GrabbableObject>().fallTime = 0f; val2.GetComponent<ShotgunItem>().shellsLoaded = 2; val2.GetComponent<NetworkObject>().Spawn(false); for (int j = 0; j < 2; j++) { val2 = Object.Instantiate<GameObject>(StartOfRound.Instance.allItemsList.itemsList[60].spawnPrefab, ((Component)val).transform.position, Quaternion.identity, StartOfRound.Instance.propsContainer); Logger.LogDebug((object)$" Spawned ammo {val2} for player #{val.playerClientId} {val.playerUsername} ({val})"); val2.GetComponent<GrabbableObject>().fallTime = 0f; val2.GetComponent<NetworkObject>().Spawn(false); } } HUDManager.Instance.AddTextMessageServerRpc("<color=#00ff00>BEGIN!</color>"); } private static void RoundEnd(PlayerControllerB? winner) { HUDManager.Instance.AddTextMessageServerRpc((((Object)(object)winner == (Object)null) ? "<color=#ff0000>Draw!" : $"<color=#22ff00>Player #{winner.playerClientId} {winner.playerUsername} has won!") + "</color>"); if (!TimeOfDay.Instance.shipLeavingAlertCalled) { TimeOfDay.Instance.SetShipLeaveEarlyClientRpc(TimeOfDay.Instance.normalizedTimeOfDay + 0.1f, StartOfRound.Instance.allPlayerScripts.Length); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "baer1.BattleRoyaleMode"; public const string PLUGIN_NAME = "LethalBattleRoyale"; public const string PLUGIN_VERSION = "0.0.1"; } }