From 35e730fc4bf5fd3c9ac3b2c87597b66ab981b01d Mon Sep 17 00:00:00 2001 From: StanislausCichocki Date: Mon, 30 Jun 2025 11:18:49 +0200 Subject: [PATCH] template --- .gitattributes | 5 ++ MyFirstMod/MyFirstMod.cs | 47 ++++++++++++++ MyFirstMod/MyFirstMod.csproj | 56 +++++++++++++++++ MyFirstMod/Patches/ExampleTVPatch.cs | 21 +++++++ MyFirstMod/README.md | 93 ++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 .gitattributes create mode 100644 MyFirstMod/MyFirstMod.cs create mode 100644 MyFirstMod/MyFirstMod.csproj create mode 100644 MyFirstMod/Patches/ExampleTVPatch.cs create mode 100644 MyFirstMod/README.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a6de451 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto +*.cs text eol=crlf +*.csproj text eol=crlf +*.md text eol=crlf + diff --git a/MyFirstMod/MyFirstMod.cs b/MyFirstMod/MyFirstMod.cs new file mode 100644 index 0000000..c137aa0 --- /dev/null +++ b/MyFirstMod/MyFirstMod.cs @@ -0,0 +1,47 @@ +using BepInEx; +using BepInEx.Logging; +using HarmonyLib; +using LobbyCompatibility.Attributes; +using LobbyCompatibility.Enums; + +namespace MyFirstMod; + +[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] +[BepInDependency("BMX.LobbyCompatibility", BepInDependency.DependencyFlags.HardDependency)] +[LobbyCompatibility(CompatibilityLevel.ClientOnly, VersionStrictness.None)] +public class MyFirstMod : BaseUnityPlugin +{ + public static MyFirstMod Instance { get; private set; } = null!; + internal new static ManualLogSource Logger { get; private set; } = null!; + internal static Harmony? Harmony { get; set; } + + private void Awake() + { + Logger = base.Logger; + Instance = this; + + Patch(); + + Logger.LogInfo($"{MyPluginInfo.PLUGIN_GUID} v{MyPluginInfo.PLUGIN_VERSION} has loaded!"); + } + + internal static void Patch() + { + Harmony ??= new Harmony(MyPluginInfo.PLUGIN_GUID); + + Logger.LogDebug("Patching..."); + + Harmony.PatchAll(); + + Logger.LogDebug("Finished patching!"); + } + + internal static void Unpatch() + { + Logger.LogDebug("Unpatching..."); + + Harmony?.UnpatchSelf(); + + Logger.LogDebug("Finished unpatching!"); + } +} diff --git a/MyFirstMod/MyFirstMod.csproj b/MyFirstMod/MyFirstMod.csproj new file mode 100644 index 0000000..3ca45ee --- /dev/null +++ b/MyFirstMod/MyFirstMod.csproj @@ -0,0 +1,56 @@ + + + + + LMod.MyFirstMod + MyFirstMod + + 1.0.0 + + + + + netstandard2.1 + MyFirstMod + true + latest + + + + + enable + + + + + + https://api.nuget.org/v3/index.json; + https://nuget.bepinex.dev/v3/index.json + + + + + + true + embedded + + $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))=./ + + + + + + + + + + + + + + + + diff --git a/MyFirstMod/Patches/ExampleTVPatch.cs b/MyFirstMod/Patches/ExampleTVPatch.cs new file mode 100644 index 0000000..eda51f3 --- /dev/null +++ b/MyFirstMod/Patches/ExampleTVPatch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; + +namespace MyFirstMod.Patches; + +[HarmonyPatch(typeof(TVScript))] +public class ExampleTVPatch +{ + [HarmonyPatch("SwitchTVLocalClient")] + [HarmonyPrefix] + private static void SwitchTVPrefix(TVScript __instance) + { + /* + * When the method is called, the TV will be turning off when we want to + * turn the lights on and vice-versa. At that time, the TV's tvOn field + * will be the opposite of what it's doing, ie it'll be on when turning off. + * So, we want to set the lights to what the tv's state was + * when this method is called. + */ + StartOfRound.Instance.shipRoomLights.SetShipLightsBoolean(__instance.tvOn); + } +} diff --git a/MyFirstMod/README.md b/MyFirstMod/README.md new file mode 100644 index 0000000..479883a --- /dev/null +++ b/MyFirstMod/README.md @@ -0,0 +1,93 @@ +# Lethal Company Mod Template + +Thank you for using the mod template! Here are a few tips to help you on your journey: + +## Versioning + +BepInEx uses [semantic versioning, or semver](https://semver.org/), for the mod's version info. +To increment it, you can either modify the version tag in the `.csproj` file directly, or use your IDE's UX to increment the version. Below is an example of modifying the `.csproj` file directly: + +```xml + + + LMod.MyFirstMod + MyFirstMod + + 1.0.0 + +``` + +Your IDE will have the setting in `Package` or `NuGet` under `General` or `Metadata`, respectively. + +## Logging + +A logger is provided to help with logging to the console. +You can access it by doing `Plugin.Logger` in any class outside the `Plugin` class. + +***Please use*** `LogDebug()` ***whenever possible, as any other log method +will be displayed to the console and potentially cause performance issues for users.*** + +If you chose to do so, make sure you change the following line in the `BepInEx.cfg` file to see the Debug messages: + +```toml +[Logging.Console] + +# ... # + +## Which log levels to show in the console output. +# Setting type: LogLevel +# Default value: Fatal, Error, Warning, Message, Info +# Acceptable values: None, Fatal, Error, Warning, Message, Info, Debug, All +# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning) +LogLevels = All +``` + +## Harmony + +This template uses harmony. For more specifics on how to use it, look at +[the HarmonyX GitHub wiki](https://github.com/BepInEx/HarmonyX/wiki) and +[the Harmony docs](https://harmony.pardeike.net/). + +To make a new harmony patch, just use `[HarmonyPatch]` before any class you make that has a patch in it. + +Then in that class, you can use +`[HarmonyPatch(typeof(ClassToPatch), "MethodToPatch")]` +where `ClassToPatch` is the class you're patching (ie `TVScript`), and `MethodToPatch` is the method you're patching (ie `SwitchTVLocalClient`). + +Then you can use +[the appropriate prefix, postfix, transpiler, or finalizer](https://harmony.pardeike.net/articles/patching.html) attribute. + +_While you can use_ `return false;` _in a prefix patch, +it is **HIGHLY DISCOURAGED** as it can **AND WILL** cause compatibility issues with other mods._ + +For example, we want to add a patch that will debug log the current players' position. +We have the following postfix patch patching the `SwitchTVLocalClient` method +in `TVScript`: + +```csharp +using HarmonyLib; + +namespace MyFirstMod.Patches; + +[HarmonyPatch(typeof(TVScript))] +public class ExampleTVPatch +{ + [HarmonyPatch("SwitchTVLocalClient")] + [HarmonyPrefix] + private static void SwitchTvPrefix(TVScript __instance) + { + /* + * When the method is called, the TV will be turning off when we want to + * turn the lights on and vice-versa. At that time, the TV's tvOn field + * will be the opposite of what it's doing, ie it'll be on when turning off. + * So, we want to set the lights to what the tv's state was + * when this method is called. + */ + StartOfRound.Instance.shipRoomLights.SetShipLightsBoolean(__instance.tvOn); + } +} +``` + +In this case we include the type of the class we're patching in the attribute +before our `ExampleTVPatch` class, +as our class will only patch the `TVScript` class.