using System;
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.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using LethalWorkingConditions.Classes.ChatCommand;
using LethalWorkingConditions.Classes.ChatCommand.Commands;
using LethalWorkingConditions.Helpers;
using LethalWorkingConditions.Patches;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LethalWorkingCondition")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LethalWorkingCondition")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6efab151-7ff3-4bb1-a345-7f43604d9c10")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LethalWorkingConditions
{
public class LWCConfig
{
public readonly string Name = "LethalChat";
public static readonly bool PlayerControllerUnlimitedSprintDefault = false;
public static ConfigEntry<bool> PlayerControllerUnlimitedSprint;
public static readonly string TerminalCommandPrefixDefault = "----";
public static ConfigEntry<string> TerminalCommandPrefix;
public static readonly bool TerminalCommandDisableChatDefault = false;
public static ConfigEntry<bool> TerminalCommandDisableChat;
public static readonly bool AllowSpawnCommandIfNotHostDefault = false;
public static ConfigEntry<bool> AllowSpawnCommandIfNotHost;
public static readonly bool MonsterEventsEnabledDefault = false;
public static ConfigEntry<bool> MonsterEventsEnabled;
public LWCConfig(ConfigFile cfg)
{
AllowSpawnCommandIfNotHost = cfg.Bind<bool>(Name, "AllowSpawnCommandIfNotHost", AllowSpawnCommandIfNotHostDefault, "If enabled, you can use the spawn command even when you are not the host");
}
}
internal class Content
{
private static LWCLogger logger = new LWCLogger("Content");
public static AssetBundle MainAssetsBundle;
private static readonly string mainAssetBundleName = "lethalworkingconditions";
public static Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();
private static void TryLoadAssets()
{
MainAssetsBundle = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), mainAssetBundleName));
if ((Object)(object)MainAssetsBundle != (Object)null)
{
logger.LogInfo("AssetBundle " + mainAssetBundleName + " loaded successfully");
}
else
{
logger.LogError("Could not load AssetBundle from " + mainAssetBundleName);
}
}
private static void LoadPatches()
{
LethalWorkingConditions.harmony.PatchAll(typeof(RoundManagerBPatch));
LethalWorkingConditions.harmony.PatchAll(typeof(HUDManagerBPatch));
logger.LogInfo("Done loading patches");
}
private static void LoadEnemies()
{
}
private static void LoadEnemy(string name, int rarity, LevelTypes levelType, SpawnType spawnType)
{
//IL_005d: 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)
logger.LogInfo("Loading enemy " + name);
EnemyType val = MainAssetsBundle.LoadAsset<EnemyType>(name);
TerminalNode val2 = MainAssetsBundle.LoadAsset<TerminalNode>(name + "TN");
TerminalKeyword val3 = MainAssetsBundle.LoadAsset<TerminalKeyword>(name + "TK");
NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab);
Enemies.RegisterEnemy(val, rarity, levelType, spawnType, val2, val3);
logger.LogInfo("Loaded " + name);
}
public static void Load()
{
LethalWorkingConditions.harmony.PatchAll(typeof(LethalWorkingConditions));
LoadPatches();
foreach (KeyValuePair<string, GameObject> prefab in Prefabs)
{
GameObject value = prefab.Value;
string key = prefab.Key;
AudioSource[] componentsInChildren = value.GetComponentsInChildren<AudioSource>();
if (componentsInChildren.Length != 0)
{
AudioSource[] array = componentsInChildren;
foreach (AudioSource val in array)
{
val.volume *= 1f;
}
}
}
logger.LogInfo("Content loaded");
}
}
[BepInPlugin("Trebossa.LethalChat", "Lethal Chat", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class LethalWorkingConditions : BaseUnityPlugin
{
public const string modGUID = "Trebossa.LethalChat";
public const string modName = "Lethal Chat";
public const string modVersion = "1.1.0";
public static readonly Harmony harmony = new Harmony("Trebossa.LethalChat");
public static LethalWorkingConditions Instance;
private static LWCLogger logger;
public static LWCConfig Config { get; internal set; }
private void Awake()
{
if ((Object)(object)Instance == (Object)null)
{
Instance = this;
}
Config = new LWCConfig(((BaseUnityPlugin)this).Config);
LWCLogger.Init();
logger = new LWCLogger("LWC");
Content.Load();
logger.LogInfo("Done loading config");
AllowNetworkPrefabs();
}
private void AllowNetworkPrefabs()
{
Type[] types = Assembly.GetExecutingAssembly().GetTypes();
Type[] array = types;
foreach (Type type in array)
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo[] array2 = methods;
foreach (MethodInfo methodInfo in array2)
{
object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
if (customAttributes.Length != 0)
{
methodInfo.Invoke(null, null);
}
}
}
}
}
}
namespace LethalWorkingConditions.Patches
{
[HarmonyPatch(typeof(HUDManager))]
internal class HUDManagerBPatch
{
private static bool chatDisabled = LWCConfig.TerminalCommandDisableChat.Value;
[HarmonyPatch("SubmitChat_performed")]
[HarmonyPrefix]
private static bool HUDManager_SubmitChat_performed_Prefix(ref HUDManager __instance)
{
string text = __instance.chatTextField.text;
if (!text.ToLower().StartsWith(ChatCommand.CommandPrefix) && !chatDisabled)
{
return true;
}
CommandStatus commandStatus = HandleCommandLogic(text, ref __instance);
CleanupGUI(ref __instance);
if (commandStatus == CommandStatus.NOT_SET && !chatDisabled)
{
return true;
}
return false;
}
private static CommandStatus HandleCommandLogic(string text, ref HUDManager __instance)
{
CommandStatus result = CommandStatus.NOT_SET;
if (text.ToLower().StartsWith(ChatCommand.CommandPrefix + "spawn"))
{
SpawnCommand spawnCommand = new SpawnCommand(ref __instance);
result = spawnCommand.ExecuteCommand();
}
return result;
}
private static void CleanupGUI(ref HUDManager __instance)
{
PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
localPlayerController.isTypingChat = false;
__instance.chatTextField.text = "";
EventSystem.current.SetSelectedGameObject((GameObject)null);
__instance.PingHUDElement(__instance.Chat, 2f, 1f, 0.2f);
((Behaviour)__instance.typingIndicator).enabled = false;
}
}
[HarmonyPatch(typeof(RoundManager))]
internal class RoundManagerBPatch
{
internal static bool isHost;
internal static RoundManager currentRound;
internal static SelectableLevel currentLevel;
internal static EnemyVent[] currentLevelVents;
[HarmonyPatch("Start")]
[HarmonyPrefix]
private static void RoundManagerBPatch_Start_Prefix(ref float ___mapSizeMultiplier)
{
___mapSizeMultiplier = 2f;
isHost = ((NetworkBehaviour)RoundManager.Instance).NetworkManager.IsHost;
}
[HarmonyPatch("AdvanceHourAndSpawnNewBatchOfEnemies")]
[HarmonyPrefix]
private static void RoundManagerBPatch_AdvanceHourAndSpawnNewBatchOfEnemies_Prefix(ref EnemyVent[] ___allEnemyVents, ref SelectableLevel ___currentLevel)
{
currentLevel = ___currentLevel;
currentLevelVents = ___allEnemyVents;
}
[HarmonyPatch("LoadNewLevel")]
[HarmonyPrefix]
private static void RoundManagerBPatch_LoadNewLevel_Prefix(ref SelectableLevel newLevel)
{
currentRound = RoundManager.Instance;
}
}
}
namespace LethalWorkingConditions.Helpers
{
internal class LWCLogger
{
public static ManualLogSource mls;
public readonly string source;
public LWCLogger(string source)
{
this.source = source;
}
public static void Init()
{
mls = Logger.CreateLogSource("Trebossa.LethalChat");
}
public void LogInfo(string message)
{
if (mls != null)
{
mls.LogInfo((object)("[" + source + "] " + message));
}
}
public void LogWarning(string message)
{
if (mls != null)
{
mls.LogWarning((object)("[" + source + "] " + message));
}
}
public void LogError(string message)
{
if (mls != null)
{
mls.LogError((object)("[" + source + "] " + message));
}
}
}
internal class ObjectFinder
{
public static List<T> FindObjectsInRadius<T>(Transform transform, float radius)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
List<T> list = new List<T>();
Collider[] array = Physics.OverlapSphere(transform.position, radius);
Collider[] array2 = array;
foreach (Collider val in array2)
{
T component = ((Component)val).GetComponent<T>();
if (component != null)
{
list.Add(component);
}
}
return list;
}
public static T[] FindObjectsOfType<T>() where T : Object
{
return Object.FindObjectsOfType<T>();
}
}
}
namespace LethalWorkingConditions.Classes
{
internal enum EnemySpawnLocation
{
Auto,
Inside,
Outside
}
internal class EnemySpawner
{
private static LWCLogger logger = new LWCLogger("EnemySpawner");
public static List<SpawnableEnemyWithRarity> EnemiesInside => RoundManagerBPatch.currentLevel.Enemies;
public static List<SpawnableEnemyWithRarity> EnemiesOutside => RoundManagerBPatch.currentLevel.OutsideEnemies;
public static bool SpawnEnemy(SpawnableEnemyWithRarity enemy, int amount, EnemySpawnLocation spawnLocation = EnemySpawnLocation.Auto)
{
if (!RoundManagerBPatch.isHost)
{
logger.LogInfo("Could not spawn enemies because user is not host");
return false;
}
switch (spawnLocation)
{
case EnemySpawnLocation.Auto:
if (FindEnemy(EnemiesInside, enemy.enemyType.enemyName) != null)
{
return SpawnEnemyAtRandomVent(enemy, amount);
}
return SpawnEnemyAtRandomOutsidePosition(enemy, amount);
case EnemySpawnLocation.Inside:
return SpawnEnemyAtRandomVent(enemy, amount);
case EnemySpawnLocation.Outside:
return SpawnEnemyAtRandomOutsidePosition(enemy, amount);
default:
return false;
}
}
private static bool SpawnEnemyAtRandomVent(SpawnableEnemyWithRarity enemy, int amount)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0064: Unknown result type (might be due to invalid IL or missing references)
try
{
int num = RoundManagerBPatch.currentLevel.Enemies.IndexOf(enemy);
for (int i = 0; i < amount; i++)
{
int num2 = Random.Range(0, RoundManagerBPatch.currentRound.allEnemyVents.Length);
Vector3 position = RoundManagerBPatch.currentRound.allEnemyVents[num2].floorNode.position;
float y = RoundManagerBPatch.currentRound.allEnemyVents[i].floorNode.eulerAngles.y;
RoundManagerBPatch.currentRound.SpawnEnemyOnServer(position, y, RoundManagerBPatch.currentLevel.Enemies.IndexOf(enemy));
}
}
catch (Exception ex)
{
logger.LogError("Failed to spawn enemies: " + ex.ToString());
return false;
}
return true;
}
private static bool SpawnEnemyAtRandomOutsidePosition(SpawnableEnemyWithRarity enemy, int amount)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: 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)
try
{
for (int i = 0; i < amount - 1; i++)
{
GameObject val = Object.Instantiate<GameObject>(RoundManagerBPatch.currentLevel.OutsideEnemies[RoundManagerBPatch.currentLevel.OutsideEnemies.IndexOf(enemy)].enemyType.enemyPrefab, GameObject.FindGameObjectsWithTag("OutsideAINode")[Random.Range(0, GameObject.FindGameObjectsWithTag("OutsideAINode").Length - 1)].transform.position, Quaternion.Euler(Vector3.zero));
val.gameObject.GetComponentInChildren<NetworkObject>().Spawn(true);
}
}
catch (Exception ex)
{
logger.LogError("Failed to spawn enemies: " + ex.ToString());
return false;
}
return true;
}
public static SpawnableEnemyWithRarity FindEnemy(List<SpawnableEnemyWithRarity> list, string search)
{
return list.Find((SpawnableEnemyWithRarity e) => e.enemyType.enemyName.ToLower().Contains(search.ToLower()));
}
}
}
namespace LethalWorkingConditions.Classes.ChatCommand
{
public enum CommandStatus
{
NOT_SET,
PREQUISITES_NOT_MET,
PARAMS_INCOMPLETE,
OK
}
internal abstract class ChatCommand
{
protected LWCLogger logger;
public static string CommandPrefix = LWCConfig.TerminalCommandPrefix.Value ?? LWCConfig.TerminalCommandPrefixDefault;
protected HUDManager hudManager;
protected readonly string text;
protected string[] parameters;
protected string commandName = "N/A";
protected string noticeTitle => "Command: " + CommandPrefix + commandName;
protected virtual string GetFullCommandSyntax()
{
return CommandPrefix + commandName;
}
protected virtual void OnInterception()
{
}
protected abstract bool CanBeCalled();
protected abstract bool ParseParameters();
protected abstract void Execute();
public ChatCommand(string commandname, ref HUDManager hudManager)
{
this.hudManager = hudManager;
commandName = commandname;
logger = new LWCLogger(commandName ?? "");
text = hudManager.chatTextField.text;
parameters = text.Split(new char[1] { ' ' }).Skip(1).ToArray();
}
protected void IssueNotification(string message, bool isWarning = false)
{
HUDManager.Instance.DisplayTip(noticeTitle, message, isWarning, false, "LC_Tip1");
logger.LogInfo(noticeTitle + ": " + message);
}
protected void IssueCommandSyntax()
{
IssueNotification("Wrong Syntax: " + GetFullCommandSyntax());
}
public CommandStatus ExecuteCommand()
{
if (!CanBeCalled())
{
return CommandStatus.PREQUISITES_NOT_MET;
}
if (!ParseParameters())
{
IssueCommandSyntax();
return CommandStatus.PARAMS_INCOMPLETE;
}
Execute();
return CommandStatus.OK;
}
}
}
namespace LethalWorkingConditions.Classes.ChatCommand.Commands
{
internal class SpawnCommand : ChatCommand
{
private string targetEnemyNameParam = "";
private int targetEnemyAmountParam = 1;
private EnemySpawnLocation spawnLocation = EnemySpawnLocation.Auto;
private bool targetEnemyFound = false;
private string targetEnemyName;
private string creaturesAvailableString => string.Join("|", EnemySpawner.EnemiesInside.Select((SpawnableEnemyWithRarity e) => e.enemyType.enemyName).ToArray()) + "|" + string.Join("|", EnemySpawner.EnemiesOutside.Select((SpawnableEnemyWithRarity e) => e.enemyType.enemyName).ToArray());
public SpawnCommand(ref HUDManager hudManager)
: base("Spawn", ref hudManager)
{
}
protected override string GetFullCommandSyntax()
{
return base.GetFullCommandSyntax() + " <" + creaturesAvailableString + "> [amount=1] [inside|outside]";
}
protected override bool CanBeCalled()
{
if (!RoundManagerBPatch.isHost)
{
IssueNotification("Only the host is allowed to use this comand");
return false;
}
try
{
List<SpawnableEnemyWithRarity> enemiesOutside = EnemySpawner.EnemiesOutside;
List<SpawnableEnemyWithRarity> enemiesInside = EnemySpawner.EnemiesInside;
if (enemiesOutside.Count <= 0 || enemiesInside.Count <= 0)
{
throw new Exception();
}
}
catch
{
IssueNotification("You need to start the game before spawning enemies");
return false;
}
return true;
}
protected override bool ParseParameters()
{
if (parameters.Length < 1)
{
return false;
}
targetEnemyNameParam = parameters[0].ToLower();
if (parameters.Length > 1)
{
int.TryParse(parameters[1], out targetEnemyAmountParam);
}
if (parameters.Length > 2)
{
string text = parameters[2].ToLower();
if (text.StartsWith("in"))
{
spawnLocation = EnemySpawnLocation.Inside;
}
if (text.StartsWith("out"))
{
spawnLocation = EnemySpawnLocation.Outside;
}
}
return true;
}
protected override void Execute()
{
List<SpawnableEnemyWithRarity> outsideEnemies = RoundManagerBPatch.currentLevel.OutsideEnemies;
List<SpawnableEnemyWithRarity> enemies = RoundManagerBPatch.currentLevel.Enemies;
List<SpawnableEnemyWithRarity> availableEnemies = outsideEnemies.Concat(enemies).ToList();
HandleSpawnEnemies(availableEnemies);
if (!targetEnemyFound)
{
IssueCommandSyntax();
}
}
private void HandleSpawnEnemies(List<SpawnableEnemyWithRarity> availableEnemies)
{
foreach (SpawnableEnemyWithRarity availableEnemy in availableEnemies)
{
if (!targetEnemyFound && availableEnemy.enemyType.enemyName.ToLower().Contains(targetEnemyNameParam))
{
targetEnemyFound = true;
targetEnemyName = availableEnemy.enemyType.enemyName;
if (EnemySpawner.SpawnEnemy(availableEnemy, targetEnemyAmountParam, spawnLocation))
{
IssueNotification($"Spawned {targetEnemyAmountParam} {targetEnemyName}");
}
else
{
IssueNotification("Could not spawn enemies because an unknown error occured. Check console");
}
}
}
}
}
}