diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a1fae2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vs/ +.idea/ +bin/ +obj/ +*.csproj.user \ No newline at end of file diff --git a/NonLethalCompany-Mod.sln b/NonLethalCompany-Mod.sln new file mode 100644 index 0000000..792893c --- /dev/null +++ b/NonLethalCompany-Mod.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NonLethalCompany-Mod", "NonLethalCompany-Mod\NonLethalCompany-Mod.csproj", "{2D758D98-47E8-44C8-8B35-78BD64AB4821}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2D758D98-47E8-44C8-8B35-78BD64AB4821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D758D98-47E8-44C8-8B35-78BD64AB4821}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D758D98-47E8-44C8-8B35-78BD64AB4821}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D758D98-47E8-44C8-8B35-78BD64AB4821}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5F65C091-312D-4E12-9039-2A76A7BF6782} + EndGlobalSection +EndGlobal diff --git a/NonLethalCompany-Mod/Main.cs b/NonLethalCompany-Mod/Main.cs new file mode 100644 index 0000000..b27838b --- /dev/null +++ b/NonLethalCompany-Mod/Main.cs @@ -0,0 +1,447 @@ +using System.Collections; +using BepInEx; +using HarmonyLib; +using GameNetcodeStuff; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace NonLethalCompany_Mod +{ + [BepInPlugin(PluginInfo.PLUGIN_ID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] + public class Main : BaseUnityPlugin + { + #region GUI Properties + + private bool _showMenu = false; + private Vector2 _scrollPosition = Vector2.zero; + + private float _movementSpeed = 4.6f; + + private float _noClipSpeed = 5.0f; + private bool _setNoClip = false; + // private bool _hasDisabledCollider = false; + + public static bool SetNoFallDamage = false; + + private bool _setUnlimitedSprint = false; + + private bool _setNoWeight = false; + + public static bool SetGodMode = false; + + private float _grabDistance = 5.0f; + + private string _credits = "0"; + + #endregion + + private void Awake() + { + Logger.LogMessage("\u001b[31mMOD LOADED WOW!!!!!!!!!!!!!!\u001b[0m"); + Harmony.CreateAndPatchAll(typeof(PlayerControllerBPatch)); + // Screen.SetResolution(1920, 1080, FullScreenMode.Windowed, 60); + } + + private void Update() + { + if (_showMenu) + Focused = false; + + UpdateInput(); + + HandleNoClip(); + HandleUnlimitedSprint(); + HandleNoWeight(); + HandleGodMode(); + HandleGrabDistance(); + } + + private void OnGUI() + { + if (!_showMenu) + return; + + GUI.Box(new Rect(0, 0, 400, 700), "Non-Lethal Company Mod Menu"); + + GUILayout.BeginArea(new Rect(10, 40, 380, 700)); + + #region Movement Speed + + GUILayout.Label("Movement Speed: " + _movementSpeed); + _movementSpeed = GUILayout.HorizontalSlider(_movementSpeed, 4.6f, 100.0f); + if (GUILayout.Button("Set Movement Speed")) + HandleMovementSpeed(); + + #endregion + + #region No Clip + + _setNoClip = GUILayout.Toggle(_setNoClip, "No Clip"); + if (_setNoClip) + { + GUILayout.Label("No Clip Speed: " + _noClipSpeed); + _noClipSpeed = GUILayout.HorizontalSlider(_noClipSpeed, 1, 50); + } + + #endregion + + #region No Fall Damage + + SetNoFallDamage = GUILayout.Toggle(SetNoFallDamage, "No Fall Damage"); + + #endregion + + #region Unlimited Sprint + + _setUnlimitedSprint = GUILayout.Toggle(_setUnlimitedSprint, "Unlimited Sprint"); + + #endregion + + #region No Weight + + _setNoWeight = GUILayout.Toggle(_setNoWeight, "No Weight"); + + #endregion + + #region God Mode + + SetGodMode = GUILayout.Toggle(SetGodMode, "God Mode"); + + #endregion + + #region Grab Distance + + GUILayout.Label("Grab Distance: " + _grabDistance); + _grabDistance = GUILayout.HorizontalSlider(_grabDistance, 5, 100); + + #endregion + + #region Credits + + GUILayout.Label("Current Credits: " + Credits); + _credits = GUILayout.TextField(_credits); + if (GUILayout.Button("Set Credits")) + HandleCredits(); + + #endregion + + GUILayout.Space(10.0f); + GUILayout.Label("Scrap Lists: (T: Teleport), (+/-: Change Value)"); + + _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, GUILayout.Height(300)); + GUILayout.BeginVertical(); + DrawTable(); + GUILayout.EndVertical(); + GUILayout.EndScrollView(); + GUILayout.Space(10.0f); + + GUILayout.EndArea(); + } + + private void DrawTable() + { + GUILayout.BeginHorizontal(); + GUILayout.Label("Name", GUILayout.MinWidth(60)); + GUILayout.Label("Distance(m)", GUILayout.MinWidth(20)); + GUILayout.Label("Value", GUILayout.MinWidth(30)); + GUILayout.EndHorizontal(); + + // GUILayout.BeginHorizontal("Options"); + // _showInShip = GUILayout.Toggle(_showInShip, "Show In Ship"); + // _showHeld = GUILayout.Toggle(_showHeld, "Show Held"); + // GUILayout.EndHorizontal(); + + var propList = GameObject.FindGameObjectsWithTag("PhysicsProp"); + if (propList == null || propList.Length == 0) + return; + + foreach (var prop in propList) + { + if (prop == null) + continue; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + continue; + + var physicsPropComp = prop.GetComponent(); + if (physicsPropComp == null) + continue; + + var scanNodeComp = prop.GetComponentInChildren(); + if (scanNodeComp == null) + continue; + + var grabbableObj = physicsPropComp as GrabbableObject; + if (grabbableObj == null) + continue; + + var actualName = scanNodeComp.headerText; + var distance = Vector3.Distance(prop.transform.position, player.transform.position); + var scrapValue = grabbableObj.scrapValue; + if (scrapValue == 1 || !grabbableObj.grabbable || grabbableObj.isHeld) + continue; + + GUILayout.BeginHorizontal(); + GUILayout.Label(actualName, GUILayout.MinWidth(120)); + GUILayout.Label(distance.ToString("F2"), GUILayout.MinWidth(50)); + GUILayout.Label(scrapValue.ToString(), GUILayout.MinWidth(30)); + if (GUILayout.Button("T")) + TeleportPlayer(prop.transform.position); + if (GUILayout.Button("+")) + grabbableObj.SetScrapValue(scrapValue + 1); + if (GUILayout.Button("-")) + grabbableObj.SetScrapValue(scrapValue - 1); + + GUILayout.EndHorizontal(); + } + + // Seems like collider must be disabled and player must go through the door for items to be dropped. + if (GUILayout.Button("Teleport to Ship")) + TeleportPlayer(StartOfRound.Instance.shipDoorNode.transform.position);// StartCoroutine(TeleportToShipCoroutine()); + } + + private void HandleMovementSpeed() + { + if (!IsInGameScene()) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.movementSpeed = _movementSpeed; + } + + private void HandleNoClip() + { + if (!IsInGameScene()) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + var camera = player.gameplayCamera.transform; + if (camera == null) + return; + + var collider = player.GetComponent() as Collider; + if (collider == null) + return; + + if (_setNoClip) + { + // switch (_hasDisabledCollider) + // { + // case false: + // collider.enabled = false; + // _hasDisabledCollider = true; + // break; + // case true when !collider.enabled: + // collider.enabled = false; + // break; + // } + collider.enabled = false; + var dir = new Vector3(); + + // Horizontal + if (UnityInput.Current.GetKey(KeyCode.W)) + dir = dir + camera.forward; + if (UnityInput.Current.GetKey(KeyCode.S)) + dir = dir + (camera.forward * -1); + if (UnityInput.Current.GetKey(KeyCode.D)) + dir = dir + camera.right; + if (UnityInput.Current.GetKey(KeyCode.A)) + dir = dir + (camera.right * -1); + + // Vertical + if (UnityInput.Current.GetKey(KeyCode.Space)) + dir.y = dir.y + camera.up.y; + if (UnityInput.Current.GetKey(KeyCode.LeftControl)) + dir.y = dir.y + (camera.up.y * -1); + + var prevPos = player.transform.localPosition; + if (prevPos.Equals(Vector3.zero)) + return; + + var newPos = prevPos + dir * (_noClipSpeed * Time.deltaTime); + player.transform.localPosition = newPos; + } + else + { + // if (!_hasDisabledCollider) + // return; + + collider.enabled = true; + // _hasDisabledCollider = false; + + } + } + + private void HandleUnlimitedSprint() + { + if (!IsInGameScene()) + return; + + if (!_setUnlimitedSprint) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.sprintMeter = 100.0f; + player.isExhausted = false; + } + + private void HandleNoWeight() + { + if (!IsInGameScene()) + return; + + if (!_setNoWeight) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.carryWeight = 1.0f; + } + + private void HandleGodMode() + { + if (!IsInGameScene()) + return; + + if (!SetGodMode) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.isPlayerDead = false; + } + + private void HandleGrabDistance() + { + if (!IsInGameScene()) + return; + + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.grabDistance = _grabDistance; + } + + private void HandleCredits() + { + if (!IsInGameScene()) + return; + + if (!int.TryParse(_credits, out var credits)) + return; + + Credits = credits; + } + + private void UpdateInput() + { + if (UnityInput.Current.GetKeyUp(KeyCode.Insert)) + _showMenu = !_showMenu; + } + + private Terminal? GetTerminal() + { + if (!IsInGameScene()) + return null; + + var obj = GameObject.FindObjectOfType(); + return obj == null ? null : obj.GetComponent(); + } + + private int Credits + { + get + { + var terminal = GetTerminal(); + if (terminal == null) + return 0; + + return terminal.groupCredits; + } + set + { + var terminal = GetTerminal(); + if (terminal == null) + return; + + terminal.groupCredits = value; + } + } + + private static bool IsInGameScene() => SceneManager.GetActiveScene().name == "SampleSceneRelay"; + + private static void TeleportPlayer(Vector3 position) + { + var player = GameNetworkManager.Instance.localPlayerController; + if (player == null) + return; + + player.transform.position = position; + } + + private static bool Focused + { + get => Cursor.lockState == CursorLockMode.Locked; + set + { + Cursor.lockState = value ? CursorLockMode.Locked : CursorLockMode.None; + Cursor.visible = value == false; + } + } + } + + [HarmonyPatch(typeof(PlayerControllerB))] + public class PlayerControllerBPatch + { + [HarmonyPatch(nameof(PlayerControllerB.DamagePlayer))] + [HarmonyPrefix] + private static void DamagePlayerPrefix(ref int damageNumber, ref CauseOfDeath causeOfDeath, ref bool fallDamage) + { + if (!Main.SetNoFallDamage) + return; + + if (!fallDamage && causeOfDeath != CauseOfDeath.Gravity) + return; + + damageNumber = 0; + } + + [HarmonyPatch(nameof(PlayerControllerB.KillPlayer))] + [HarmonyPrefix] + private static void KillPlayerPrefix(ref CauseOfDeath causeOfDeath) + { + if (Main.SetGodMode && causeOfDeath is CauseOfDeath.Suffocation or CauseOfDeath.Drowning) + return; + } + + [HarmonyPatch("AllowPlayerDeath")] + [HarmonyPrefix] + private static bool AllowPlayerDeathPrefix(PlayerControllerB __instance) + { + if (Main.SetGodMode) + return false; + + // var originalMethod = AccessTools.Method(typeof(PlayerControllerB), "AllowPlayerDeath"); + // if (originalMethod != null) + // return (bool)originalMethod.Invoke(__instance, null)!; + + return true; + } + } +} + diff --git a/NonLethalCompany-Mod/NonLethalCompany-Mod.csproj b/NonLethalCompany-Mod/NonLethalCompany-Mod.csproj new file mode 100644 index 0000000..b5c0106 --- /dev/null +++ b/NonLethalCompany-Mod/NonLethalCompany-Mod.csproj @@ -0,0 +1,48 @@ + + + + netstandard2.1 + NonLethalCompany_Mod + enable + enable + 10 + + + + D:\SteamLibrary\steamapps\common\Lethal Company\BepInEx\plugins + + + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\BepInEx\core\0Harmony.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Assembly-CSharp.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\BepInEx\core\BepInEx.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\BepInEx\core\BepInEx.Harmony.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\System.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\UnityEngine.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\UnityEngine.CoreModule.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\UnityEngine.IMGUIModule.dll + + + ..\..\..\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\UnityEngine.PhysicsModule.dll + + + + diff --git a/NonLethalCompany-Mod/PluginInfo.cs b/NonLethalCompany-Mod/PluginInfo.cs new file mode 100644 index 0000000..f180896 --- /dev/null +++ b/NonLethalCompany-Mod/PluginInfo.cs @@ -0,0 +1,50 @@ +using System.Reflection; +using NonLethalCompany_Mod; + +#region Assembly attributes +/* + * These attributes define various metainformation of the generated DLL. + * In general, you don't need to touch these. Instead, edit the values in PluginInfo. + */ +[assembly:AssemblyVersion(PluginInfo.PLUGIN_VERSION)] +[assembly:AssemblyTitle(PluginInfo.PLUGIN_NAME + " (" + PluginInfo.PLUGIN_ID + ")")] +[assembly:AssemblyProduct(PluginInfo.PLUGIN_NAME)] +[assembly:AssemblyCopyright("Created by Taiga741647")] +[assembly:AssemblyTrademark("")] +[assembly:AssemblyCulture("")] +#endregion + +namespace NonLethalCompany_Mod +{ + /// + /// The main metadata of the plugin. + /// This information is used for BepInEx plugin metadata. + /// + /// + /// See also description of BepInEx metadata: + /// https://bepinex.github.io/bepinex_docs/master/articles/dev_guide/plugin_tutorial/2_plugin_start.html#basic-information-about-the-plug-in + /// + internal static class PluginInfo + { + /// + /// Human-readable name of the plugin. In general, it should be short and concise. + /// This is the name that is shown to the users who run BepInEx and to modders that inspect BepInEx logs. + /// + public const string PLUGIN_NAME = "Non-Lethal Company Mod"; + + /// + /// Unique ID of the plugin. + /// This must be a unique string that contains only characters a-z, 0-9 underscores (_) and dots (.) + /// Prefer using the reverse domain name notation: https://eqdn.tech/reverse-domain-notation/ + /// + /// When creating Harmony patches, prefer using this ID for Harmony instances as well. + /// + public const string PLUGIN_ID = "com.taiga741647.nonlethalcompany.mod"; + + /// + /// Version of the plugin. Must be in form .... + /// Major and minor versions are mandatory, but build and revision can be left unspecified. + /// + public const string PLUGIN_VERSION = "1.0.0"; + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c98d35 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Non-Lethal-Company-Mod + + +### Requirements: +- [BepInEx](https://github.com/BepInEx/BepInEx) + +### Usage: +1. Put DLL inside `\BepInEx\plugins` + +### Features: +- Movement Speed +- No Clip +- No Fall Damage +- Unlimited Sprint +- No Weight +- God Mode +- Grab Distance +- Credits +- Teleport to scraps / Change scrap value \ No newline at end of file