Decompiled source of TrailerStranded v1.6.0

BepInEx/plugins/TrailerStranded/TrailerStranded.dll

Decompiled an hour ago
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<StrandedCore>();
		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<ulong, StrandedPlayerData> stranded = new Dictionary<ulong, StrandedPlayerData>();

	public List<ulong> strandedList = new List<ulong>();

	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>();
		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<ulong> 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<EnemyAI>();
			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<Terminal>();
		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<GameObject>(prefab, data.position, Quaternion.Euler(data.rotation));
		((Object)obj).name = "StrandedSleeperCruiser";
		Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>();
		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<NetworkObject>();
		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<TerminalNode>();
			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<TerminalNode>();
				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<TerminalNode>();
				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<Renderer>();
		foreach (Renderer val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)val.material != (Object)null)
			{
				val.material.color = color;
			}
		}
	}
}