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 GameNetcodeStuff; using HarmonyLib; 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("TrailerStranded")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Stranded survival mod for Lethal Company")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TrailerStranded")] [assembly: AssemblyTitle("TrailerStranded")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace TrailerStranded; [BepInPlugin("TrailerStranded", "TrailerStranded", "1.6.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "TrailerStranded"); Log.LogInfo((object)"TrailerStranded loaded!"); } private void Start() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("StrandedCore"); val.AddComponent(); Object.DontDestroyOnLoad((Object)(object)val); } } internal static class PluginInfo { internal const string PLUGIN_GUID = "TrailerStranded"; internal const string PLUGIN_NAME = "TrailerStranded"; internal const string PLUGIN_VERSION = "1.6.0"; } public class StrandedPlayerData { public ulong steamId; public string playerName; public string planetName; public int levelID; public float survivalTime; public bool isDead; public float planetHour; public LevelWeatherType weather; public int scrapCollected; } public class SleeperCruiserData { public int levelID; public Vector3 position; public Vector3 rotation; public Color color; public bool exists; } public class StrandedCore : MonoBehaviour { public static StrandedCore Instance; public Dictionary stranded = new Dictionary(); public List strandedList = new List(); public SleeperCruiserData savedCruiser = null; private float survivalTimer; private float enemyTimer; private float weatherTimer; private float planetHour = 8f; private bool survivalActive; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void Update() { if (!survivalActive || strandedList.Count == 0) { return; } float deltaTime = Time.deltaTime; planetHour += deltaTime / 180f; if (planetHour >= 24f) { planetHour -= 24f; } weatherTimer += deltaTime; if (weatherTimer >= 180f) { weatherTimer = 0f; if (Random.value < 0.35f) { RollWeather(); } } enemyTimer += deltaTime; survivalTimer += deltaTime; if (survivalTimer >= 1f) { survivalTimer = 0f; foreach (ulong stranded in strandedList) { if (this.stranded.TryGetValue(stranded, out var value) && !value.isDead) { value.survivalTime += 1f; } } } foreach (ulong stranded2 in strandedList) { if (this.stranded.TryGetValue(stranded2, out var value2)) { value2.planetHour = planetHour; } } } public void StartStranded(ulong sid, string name, string planet, int levelID) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!stranded.ContainsKey(sid)) { stranded[sid] = new StrandedPlayerData { steamId = sid, playerName = name, planetName = planet, levelID = levelID, survivalTime = 0f, isDead = false, planetHour = 8f, weather = (LevelWeatherType)(-1) }; } if (!strandedList.Contains(sid)) { strandedList.Add(sid); } survivalActive = true; planetHour = 8f; enemyTimer = 0f; weatherTimer = 60f; } public void Rescued(ulong sid) { stranded.Remove(sid); strandedList.Remove(sid); if (strandedList.Count == 0) { survivalActive = false; savedCruiser = null; } } public void SetDead(ulong sid) { if (stranded.TryGetValue(sid, out var value)) { value.isDead = true; } } public bool IsStranded(ulong sid) { return strandedList.Contains(sid); } private void RollWeather() { //IL_004a: 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) float value = Random.value; LevelWeatherType weather = (LevelWeatherType)((value < 0.3f) ? (-1) : ((value < 0.5f) ? 1 : ((value < 0.65f) ? 2 : ((value < 0.77f) ? 3 : ((value < 0.88f) ? 4 : ((value < 0.95f) ? 5 : 0)))))); foreach (ulong stranded in strandedList) { if (this.stranded.TryGetValue(stranded, out var value2)) { value2.weather = weather; } } } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] internal static class ShipLeavePatch { [HarmonyPostfix] private static void Postfix(StartOfRound __instance) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00c7: Unknown result type (might be due to invalid IL or missing references) StrandedCore instance = StrandedCore.Instance; if ((Object)(object)instance == (Object)null) { return; } VehicleController[] array = Object.FindObjectsOfType(); VehicleController[] array2 = array; foreach (VehicleController val in array2) { if ((Object)(object)val != (Object)null && (((Object)val).name.Contains("SleeperCruiser") || ((Object)val).name.Contains("StrandedSleeper"))) { SleeperCruiserData obj = new SleeperCruiserData { levelID = (__instance.currentLevel?.levelID ?? 0), position = ((Component)val).transform.position, rotation = ((Component)val).transform.eulerAngles }; MeshRenderer mainBodyMesh = val.mainBodyMesh; obj.color = ((mainBodyMesh != null) ? ((Renderer)mainBodyMesh).material.color : Color.white); obj.exists = true; instance.savedCruiser = obj; } } for (int j = 0; j < __instance.allPlayerScripts.Length; j++) { PlayerControllerB val2 = __instance.allPlayerScripts[j]; if (!((Object)(object)val2 == (Object)null) && val2.isPlayerControlled && !val2.isInHangarShipRoom && !val2.isInElevator) { SelectableLevel currentLevel = __instance.currentLevel; instance.StartStranded(val2.playerSteamId, val2.playerUsername, currentLevel?.PlanetName ?? "Unknown", currentLevel?.levelID ?? 0); val2.isPlayerDead = false; } } } } [HarmonyPatch(typeof(StartOfRound), "OnPlayerDC")] internal static class OnPlayerDCPatch { [HarmonyPrefix] private static bool Prefix(StartOfRound __instance, int playerObjectNumber) { StrandedCore instance = StrandedCore.Instance; if ((Object)(object)instance == (Object)null || instance.strandedList.Count == 0) { return true; } if (playerObjectNumber >= 0 && playerObjectNumber < __instance.allPlayerScripts.Length) { PlayerControllerB val = __instance.allPlayerScripts[playerObjectNumber]; if ((Object)(object)val != (Object)null && instance.IsStranded(val.playerSteamId)) { Plugin.Log.LogInfo((object)("TrailerStranded: Blocked MISSING for " + val.playerUsername)); return false; } } return true; } } [HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")] internal static class ShipLandPatch { [HarmonyPostfix] private static void Postfix(StartOfRound __instance) { StrandedCore core = StrandedCore.Instance; if ((Object)(object)core == (Object)null || (Object)(object)__instance.currentLevel == (Object)null) { return; } int levelID = __instance.currentLevel.levelID; string planet = __instance.currentLevel.PlanetName; StrandedPlayerData value; List list = core.strandedList.Where((ulong sid) => core.stranded.TryGetValue(sid, out value) && value.planetName == planet && !value.isDead).ToList(); foreach (ulong item in list) { core.Rescued(item); } if (list.Count > 0) { EnemyAI[] array = Object.FindObjectsOfType(); foreach (EnemyAI val in array) { if ((Object)(object)val != (Object)null && !val.isEnemyDead && (Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } if (core.savedCruiser != null && core.savedCruiser.exists && core.savedCruiser.levelID == levelID) { ((MonoBehaviour)core).StartCoroutine(RespawnCruiser(core)); } } private static IEnumerator RespawnCruiser(StrandedCore core) { yield return (object)new WaitForSeconds(3f); Terminal terminal = Object.FindObjectOfType(); if ((Object)(object)terminal == (Object)null || terminal.buyableVehicles == null) { yield break; } GameObject prefab = null; BuyableVehicle[] buyableVehicles = terminal.buyableVehicles; foreach (BuyableVehicle bv in buyableVehicles) { if (bv != null && (Object)(object)bv.vehiclePrefab != (Object)null && bv.vehicleDisplayName != null && bv.vehicleDisplayName.ToLower().Contains("cruiser")) { prefab = bv.vehiclePrefab; break; } } if ((Object)(object)prefab == (Object)null) { yield break; } SleeperCruiserData data = core.savedCruiser; GameObject obj = Object.Instantiate(prefab, data.position, Quaternion.Euler(data.rotation)); ((Object)obj).name = "StrandedSleeperCruiser"; Renderer[] componentsInChildren = obj.GetComponentsInChildren(); foreach (Renderer r in componentsInChildren) { if ((Object)(object)r != (Object)null && (Object)(object)r.material != (Object)null) { r.material.color = data.color; } } NetworkObject netObj = obj.GetComponent(); if ((Object)(object)netObj != (Object)null && !netObj.IsSpawned) { netObj.Spawn(false); } core.savedCruiser.exists = false; } private static string FormatTime(float seconds) { return $"{Mathf.FloorToInt(seconds / 3600f):D2}:{Mathf.FloorToInt(seconds % 3600f / 60f):D2}"; } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] internal static class DeathPatch { [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { StrandedCore instance = StrandedCore.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance == (Object)null) && __instance.isPlayerControlled && instance.IsStranded(__instance.playerSteamId)) { instance.SetDead(__instance.playerSteamId); } } } [HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")] internal static class TerminalCommandsPatch { [HarmonyPrefix] private static bool Prefix(Terminal __instance, ref TerminalNode __result) { //IL_01a0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return true; } string text = __instance.screenText.text; string[] array = text.Split('\n'); string text2 = ((array.Length != 0) ? array[^1].Trim().ToLower() : ""); if (text2.StartsWith(">")) { text2 = text2.Substring(1).Trim(); } if (text2 == "stranded" || text2 == "status") { TerminalNode val = ScriptableObject.CreateInstance(); val.clearPreviousText = true; val.maxCharactersToType = 0; StrandedCore instance = StrandedCore.Instance; if ((Object)(object)instance == (Object)null || instance.strandedList.Count == 0) { val.displayText = "> No crew members currently stranded.\n\n"; } else { string text3 = "> STRANDED CREW STATUS:\n"; foreach (ulong stranded in instance.strandedList) { if (instance.stranded.TryGetValue(stranded, out var value)) { string text4 = (value.isDead ? "[DECEASED]" : "[ALIVE]"); string text5 = $"{Mathf.FloorToInt(value.survivalTime / 3600f):D2}:{Mathf.FloorToInt(value.survivalTime % 3600f / 60f):D2}"; text3 += $"\n {value.playerName} {text4}\n Planet: {value.planetName}\n Survived: {text5}\n Weather: {value.weather}\n Hour: {value.planetHour:F1}h\n\n"; } } text3 += "> Land on their planet to rescue them.\n"; val.displayText = text3; } __result = val; return false; } if (text2 == "sleepercruiser") { int num = -1; for (int i = 0; i < __instance.buyableVehicles.Length; i++) { if (__instance.buyableVehicles[i]?.vehicleDisplayName != null && __instance.buyableVehicles[i].vehicleDisplayName.ToLower().Contains("cruiser")) { num = i; break; } } if (num >= 0) { TerminalNode val2 = ScriptableObject.CreateInstance(); val2.displayText = "Ordered Sleeper Cruiser!\nIt will be delivered via dropship.\n\n"; val2.clearPreviousText = true; val2.maxCharactersToType = 0; val2.buyVehicleIndex = num; val2.itemCost = 450; val2.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[0]; __result = val2; } else { TerminalNode val3 = ScriptableObject.CreateInstance(); val3.displayText = "> Could not find cruiser in vehicle list.\n\n"; val3.clearPreviousText = true; val3.maxCharactersToType = 0; __result = val3; } return false; } return true; } } [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] internal static class QuotaPatch { [HarmonyPostfix] private static void Postfix() { if ((Object)(object)StrandedCore.Instance != (Object)null && StrandedCore.Instance.strandedList.Count > 0) { Plugin.Log.LogInfo((object)"TrailerStranded: Stranded players skipped quota"); } } } [HarmonyPatch(typeof(VehicleController), "Start")] internal static class CruiserColorPatch { private static readonly Color[] Colors = (Color[])(object)new Color[6] { new Color(0.15f, 0.35f, 0.85f), new Color(0.1f, 0.65f, 0.3f), new Color(0.85f, 0.65f, 0.1f), new Color(0.5f, 0.2f, 0.75f), new Color(0f, 0.75f, 0.75f), new Color(0.75f, 0.4f, 0.1f) }; [HarmonyPostfix] private static void Postfix(VehicleController __instance) { //IL_0051: 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_0091: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (!((Object)__instance).name.Contains("SleeperCruiser") && !((Object)__instance).name.Contains("StrandedSleeper"))) { return; } Color color = Colors[Random.Range(0, Colors.Length)]; Renderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val != (Object)null && (Object)(object)val.material != (Object)null) { val.material.color = color; } } } }