### Quickstarter Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home The Quickstarter system automates the process of loading or generating a map when the game begins, streamlining the initial game setup for players. ```APIDOC Quickstarter: Automatically load or generate a map at game start. Simplifies initial game setup. ``` -------------------------------- ### Classic Detour Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Detouring Demonstrates classic detouring by directly providing source and destination MethodInfo objects to DetourProvider.CompatibleDetour. This method throws an exception on failure. ```cs var source = typeof(Widgets).GetMethod("ButtonText", Helpers.AllBindingFlags, null, new[]{typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool)}, null); var destination = typeof(Detours).GetMethod("ButtonText", Helpers.AllBindingFlags); DetourProvider.CompatibleDetour(source, destination); ``` -------------------------------- ### HugsLib Detour Conversion Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Illustrates how to convert traditional detours to Harmony patches, referencing examples from the HugsLib Detouring wiki. Assumes the user has a class extending ModBase; otherwise, manual Harmony bootstrapping is required. ```C# // Example conversion from detour to Harmony patch // Requires a class extending ModBase or manual Harmony bootstrapping. // Refer to HugsLib wiki for specific detour examples and their Harmony equivalents. ``` -------------------------------- ### GUI Injection Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Demonstrates how to inject custom GUI elements into existing windows using `WindowInjection`. This example shows how to add a button labeled 'Hello' to the `Dialog_SaveFileList_Load` window. The `DrawSaveDialogButton` method is called by HugsLib when the specified window is opened, receiving the window and its available rectangle. ```cs [WindowInjection(typeof(Dialog_SaveFileList_Load))] private static void DrawSaveDialogButton(Window window, Rect inRect) { var buttonSize = new Vector2(120f, 40f); if (Widgets.ButtonText(new Rect(0, inRect.height - buttonSize.y, buttonSize.x, buttonSize.y), "Hello")) { // do stuff } } ``` -------------------------------- ### Basic Postfix Patch Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Demonstrates how to create a postfix patch to execute code after a method completes. This example hooks into the `Page_ModsConfig.PreOpen` method to log when the Mods dialog opens. Patches must be in separate static classes, and the patch method must be static. The `__instance` parameter provides a reference to the object the method was called on. ```cs // original method: public override void PreOpen() [HarmonyPatch(typeof(Page_ModsConfig), "PreOpen")] public static class ModsConfig_PreOpen_Patch { [HarmonyPostfix] public static void DetectModsDialogOpening(Page_ModsConfig __instance) { Log.Message("Dialog opened: " + __instance); } } ``` -------------------------------- ### UtilityWorldObject to WorldComponent Migration Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide Demonstrates the conversion process from using `UtilityWorldObject` to the recommended `WorldComponent` for storing world-specific data in Rimworld mods using HugsLib. It shows both the definition and access patterns for the old and new methods. ```C# ```csharp // definition public class WorldData : UtilityWorldObject { private int data; public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref data, "data"); } } // access var worldData = UtilityWorldObjectManager.GetUtilityWorldObject(); ``` Becomes: ```csharp" // definition public class WorldData : WorldComponent { private int data; public WorldData(World world) : base(world) { } public override void ExposeData() { Scribe_Values.Look(ref data, "data"); } } // access var worldData = Find.World.GetComponent() ``` ``` -------------------------------- ### Quickstarter Functionality Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Quickstarter The Quickstarter system automatically loads a save file or generates a new map upon game startup, significantly speeding up the development cycle for Rimworld mods. It is only active in Dev mode and integrates with the vanilla 'quicktest' command-line argument for map generation. -------------------------------- ### Detour Instance Method Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Detouring This example shows how to detour an instance method using HugsLib. It modifies the inspect string displayed for pawns. The target method must be static, declared as an extension method of the original method's parent type, and include an additional first argument for the instance reference (similar to 'this'). ```cs [DetourMethod(typeof(Pawn), "GetInspectString")] private static string GetInspectString(this Pawn self) { return self.Label + " test"; } ``` -------------------------------- ### Introduction to Patching Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home This guide explains how to hook into and modify game methods using HugsLib's patching system. It's essential for altering game behavior or adding new functionality. ```APIDOC Patching: Hook into and modify game methods. Replaces Detouring system (A16). See also: Detouring (A16), GUI Injection (A16). ``` -------------------------------- ### UpdateFeatureDef XML Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Mod-Update-News Example of an XML file defining update news items for a mod using HugsLib's UpdateFeatureDef. It includes a base definition and specific items for different versions, showcasing content formatting and versioning. ```XML Mod Name ModName https://ludeon.com/forums/index.php?topic=17218 ModName_1_1_0 1.1.0 A basic news item with text content only. ModName_1_2_0 1.2.0 First paragraph.|img:Things/Item/Meal/Fine,Things/Item/Meal/Lavish,Things/Item/Meal/Simple|caption:This is a caption.|Another paragraph with <b>rich text</b>. ``` -------------------------------- ### WorldComponent Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/World-Data-Storage Demonstrates how to define and access a WorldComponent for storing world-specific data. WorldComponent is the recommended approach for new Rimworld versions. ```C# // definition public class WorldData : WorldComponent { private int data; public WorldData(World world) : base(world) { } public override void ExposeData() { Scribe_Values.Look(ref data, "data"); } } // access var worldData = Find.World.GetComponent() ``` -------------------------------- ### Harmony Patch Types Explained Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Explains the different types of patches available in the Harmony library for modifying RimWorld's base game methods. Covers Prefix, Postfix, and Infix patches, their execution order, capabilities, and compatibility considerations. ```APIDOC Patch Types: - Prefix: - Executes before the original method. - Can modify method arguments and cancel original method execution. - Can be prevented from executing by other prefixes on the same method. - Postfix: - Executes after the original method. - Can modify the return value. - Always executes, regardless of prefixes. - Preferred for hooking into execution flow without altering behavior. - Infix (Transpiler): - Modifies the method's code instruction by instruction. - Advanced topic requiring knowledge of .NET CIL. - Neither affects nor is affected by prefixes and postfixes. ``` -------------------------------- ### Handling Key Input with OnGUI Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/ModBase-Reference Provides an example of how to listen for key press events within the OnGUI method of a ModBase class. This is useful for custom key bindings. ```cs public override void OnGUI() { base.OnGUI(); if (Event.current.type == EventType.KeyDown) { if (KeyBindingDefOf.Misc1.JustPressed) { // Your action here when Misc1 key is pressed Logger.Message("Misc1 key pressed!"); } } } ``` -------------------------------- ### Detour Static Method Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Detouring This example demonstrates how to detour a static method in Rimworld using HugsLib. It replaces the text of a button drawn by Widgets.ButtonText. The target method must match the original's argument count, types, and return type. It's recommended to declare target methods in a separate static class. ```cs [DetourMethod(typeof(Widgets), "ButtonText")] public static bool ButtonText(Rect rect, string label, bool drawBackground, bool doMouseoverSound, bool active) { const string newLabel = "Test"; return Widgets.ButtonText(rect, newLabel, drawBackground, doMouseoverSound, Widgets.NormalOptionColor, active); } ``` -------------------------------- ### Postfix Patch for Dialog_FileList Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching This example demonstrates how to use a Harmony postfix to add a button to the file list dialog. It targets the parent class `Dialog_FileList` and checks if the current instance is `Dialog_SaveFileList_Load` to ensure the button is only drawn in the correct context. The original method `DoWindowContents` is patched. ```cs // orginal method: public override void DoWindowContents(Rect inRect) [HarmonyPatch(typeof (Dialog_FileList), "DoWindowContents")] public static class FileList_DoWindowContents_Patch { [HarmonyPostfix] public static void DrawHelloButton(Dialog_FileList __instance, Rect inRect) { if (!(__instance is Dialog_SaveFileList_Load)) return; var buttonSize = new Vector2(120f, 40f); if (Widgets.ButtonText(new Rect(0, inRect.height - buttonSize.y, buttonSize.x, buttonSize.y), "Hello")) { // do stuff } } } ``` -------------------------------- ### Replacing GUI Elements Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/GUI-Injection Demonstrates how to draw a new element over an existing one by matching size and position, ensuring only the last drawn element is interactable. Includes an example of drawing a background texture. ```cs var prevGuiColor = GUI.color; GUI.color = new ColorInt(21, 25, 29).ToColor; // window background color GUI.DrawTexture(targetRect, BaseContent.WhiteTex); GUI.color = prevGuiColor; ``` -------------------------------- ### Logging with HugsLib Logger Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/ModBase-Reference Shows how to use the Logger property provided by ModBase to write messages to the Rimworld console. Includes examples for Message, Error, Warning, and Trace methods. ```cs public override void Initialize() { base.Initialize(); Logger.Message("This is a regular message."); Logger.Warning("This is a warning message."); Logger.Error("This is an error message."); // Logger.Trace("This message only appears in Dev mode."); } ``` -------------------------------- ### ModBase Reference Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home ModBase is the foundational class for all mods utilizing the HugsLib library. It serves as the starting point for integrating library functionalities into your mod. ```APIDOC ModBase: A base class for mods using HugsLib. Provides access to library facilities. ``` -------------------------------- ### UtilityWorldObject Example Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/World-Data-Storage Illustrates the usage of UtilityWorldObject for storing map-independent mod data. It shows how to create a custom UWO, override ExposeData for saving, and use PostAdd for initial setup. ```C# public class StorageTest : ModBase { public override string ModIdentifier { get { return "StorageTest"; } } public override void WorldLoaded() { var obj = UtilityWorldObjectManager.GetUtilityWorldObject(); Logger.Message(obj.testInt.ToString()); Logger.Message(obj.testString); obj.testInt++; obj.testString += "+"; } private class WorldDataStore : UtilityWorldObject { public int testInt; public string testString; public override void PostAdd() { base.PostAdd(); testInt = 1; testString = "+"; } public override void ExposeData() { base.ExposeData(); Scribe_Values.LookValue(ref testInt, "testInt", 0); Scribe_Values.LookValue(ref testString, "testString", ""); } } } ``` -------------------------------- ### Requiring a Minimum HugsLib Version Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home This guide explains how to ensure your mod uses a compatible version of HugsLib, allowing you to safely leverage newer library features and avoid potential conflicts. ```APIDOC Minimum HugsLib Version: Safely use new library features. Ensures compatibility with HugsLib. ``` -------------------------------- ### Custom Context Menu Entries Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Illustrates how to add custom entries to a setting's context menu. These entries, often used for presets, allow users to quickly set predefined values by clicking on menu items. The example shows setting an integer value within a specified range. ```cs var dangerLevel = Settings.GetHandle("dangerLevel", "Danger level", "Description here...", 0, Validators.IntRangeValidator(0, 100)); dangerLevel.ContextMenuEntries = new[] { new ContextMenuEntry("Preset: Low", () => dangerLevel.Value = 10), new ContextMenuEntry("Preset: Medium", () => dangerLevel.Value = 50), new ContextMenuEntry("Preset: High", () => dangerLevel.Value = 80) }; ``` -------------------------------- ### GUI Injection (A16) Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home This guide explains GUI Injection for Alpha 16, a method for adding callbacks to the drawing routines of any game window. This functionality has been replaced by patching. ```APIDOC GUI Injection (A16): Add callbacks to the drawing method of any window. Replaced by patching. See also: Introduction to Patching. ``` -------------------------------- ### Postfix Patch for Property Getters Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Illustrates how to patch property getters using `HarmonyPatch` with `PropertyMethod.Getter`. This example modifies the `CanLayNow` property of `CompEggLayer` to make chickens lay eggs 100 times faster. It uses reflection via `AccessTools` to access a private field. The `__result` parameter, when marked with `ref`, allows modification of the property's return value. ```cs // original property: public bool CanLayNow [HarmonyPatch(typeof(CompEggLayer))] [HarmonyPatch("CanLayNow", PropertyMethod.Getter)] public static class EggLayer_CanLayNow_Patch { private static readonly FieldInfo eggProgressField = AccessTools.Field(typeof(CompEggLayer), "eggProgress"); [HarmonyPostfix] public static void ExtraFastEggs(CompEggLayer __instance, ref bool __result) { __result = (float)eggProgressField.GetValue(__instance) * 100f > 1f; } } ``` -------------------------------- ### HugsLib API: Mod Settings Events Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide Details the `ModSettingManager.BeforeModSettingsSaved` and `AfterModSettingsSaved` events. Explains their utility for tracking settings changes, identifying saving mods, and confirming when settings have been flushed to disk. ```APIDOC ModSettingManager.BeforeModSettingsSaved: event Raised before mod settings are saved. Useful for identifying mods saving settings and their handles. Properties to access: ModSettingManager.ModSettingsPacks, ModSettingsPack.Handles. Event is raised only if SettingHandle.HasUnsavedChanges is true for at least one handle. ModSettingManager.AfterModSettingsSaved: event Raised after the settings XML file has been flushed to disk. All handles will have their HasUnsavedChanges property reset to false after this event. ``` -------------------------------- ### HugsLib API: ModBase Identifiers Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide Explains the usage of `ModBase.LogIdentifier` and `ModBase.SettingsIdentifier` for uniquely identifying mods in logs and settings. Covers optional usage and fallback to `ModBase.ModIdentifier` or `PackageId`. ```APIDOC ModBase.LogIdentifier: string (optional) Used to identify ModBase mods in the logs. ModBase.SettingsIdentifier: string (optional) Used to uniquely identify HugsLib mod settings. ModBase.ModIdentifier: string (optional) Can be used as a fallback for both LogIdentifier and SettingsIdentifier. If none of the above are defined, the mod's PackageId is used as the identifier. ``` -------------------------------- ### HugsLib Version Check Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.2-Update-Notes Enables mods to declare a minimum required version of HugsLib. If the player's version is lower, an update prompt is displayed. See the wiki for setup. ```C# // Example of specifying a minimum HugsLib version in About/About.xml // 1.0.0 // Example of checking the version programmatically (conceptual) // HugsLib.Core.HugsLibController.Instance.CheckVersion("1.0.0"); ``` -------------------------------- ### Indestructible Property Detour Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Detouring Detours the 'HitPoints' property of the 'Thing' class to prevent it from going below 1, making things indestructible. This example uses reflection and demonstrates property detouring. ```cs public class Indestructible : Thing { public static FieldInfo hitPointsIntField = typeof(Thing).GetField("hitPointsInt", Helpers.AllBindingFlags); [DetourProperty(typeof (Thing), "HitPoints", DetourProperty.Both)] public int _HitPoints { get { return (int)hitPointsIntField.GetValue(this); } set { if (value < 1) value = 1; hitPointsIntField.SetValue(this, value); } } } ``` -------------------------------- ### HugsLib Events Overview Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/ModBase-Reference Illustrates the different event methods that can be overridden in a ModBase class to hook into HugsLib's lifecycle. Includes EarlyInitalize, Initialize, DefsLoaded, Update, FixedUpdate, and OnGUI. ```cs // Optional: For early initialization, requires [EarlyInit] attribute // public override void EarlyInitalize() { // base.EarlyInitalize(); // } public override void Initialize() { base.Initialize(); // Called once on mod initialization } public override void DefsLoaded() { base.DefsLoaded(); // Called after all Defs are loaded } public override void Update() { base.Update(); // Called every frame } public override void FixedUpdate() { base.FixedUpdate(); // Called on each physics update } public override void OnGUI() { base.OnGUI(); // Called when the Unity GUI system redraws or receives an input event } ``` -------------------------------- ### Adding Mod Settings Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home This section details how to implement custom settings for your mod, allowing players to modify various aspects of your mod's behavior through an in-game interface. ```APIDOC Mod Settings: Easily add custom settings to your mod. Allows player modification of mod behavior. ``` -------------------------------- ### Mod Spotter Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Home Mod Spotter helps identify players who are experiencing your mod for the first time. This can be useful for providing tailored onboarding experiences. ```APIDOC Mod Spotter: Identify first-time players of your mod. Facilitates tailored onboarding. ``` -------------------------------- ### Prefix Patch to Modify Arguments Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Introduction-to-Patching Shows how to create a prefix patch to modify method arguments before the original method executes. This example patches `Widgets.ButtonText` to change the button label to 'Test'. When patching overloaded methods, parameter types must be specified in the `HarmonyPatch` attribute. The `ref` keyword allows modification of the argument passed to the original method. Prefix methods must return a boolean; `true` allows execution, `false` cancels it. ```cs // original method: public static bool ButtonText(Rect rect, string label, bool drawBackground = true, bool doMouseoverSound = false, bool active = true) [HarmonyPatch(typeof(Widgets), "ButtonText", new []{typeof(Rect), typeof(string), typeof(bool), typeof(bool), typeof(bool)})] public static class Widgets_ButtonText_Patch { [HarmonyPrefix] public static bool ReplaceAllButtonLabels(ref string label) { label = "Test"; return true; } } ``` -------------------------------- ### Optional HugsLib Integration for Settings Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Demonstrates how to implement settings that only load if HugsLib is present by catching TypeLoadException. This allows mods to have configurable options without a hard dependency. ```cs [StaticConstructorOnStartup] public class TestMod { private static Func getSettingValue; static TestMod() { // load order does not matter- HugsLib initializes before StaticConstructorOnStartup InitializeSetting(); Log.Message("Setting value: " + getSettingValue()); } private static void InitializeSetting() { const bool defaultValue = true; // Need a wrapper method/lambda to be able to catch the TypeLoadException when HugsLib isn't present try { ((Action) (() => { var settings = HugsLibController.Instance.Settings.GetModSettings("TestModIdentifier"); // add a mod name to display in the Mods Settings menu settings.EntryName = "Test Mod"; // handle can't be saved as a SettingHandle<> type; otherwise the compiler generated closure class will throw a typeloadexception object handle = settings.GetHandle("testSetting", "Setting label", "Setting description", defaultValue); getSettingValue = () => (SettingHandle) handle; }))(); return; } catch (TypeLoadException) { } getSettingValue = () => defaultValue; } } ``` -------------------------------- ### EarlyInit Attribute Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/ModBase-Reference An attribute to instantiate a `ModBase` class at the earliest possible time during game startup. This also allows Harmony patches to be applied earlier, making it suitable for patching vanilla loading and Def generation code. ```csharp [EarlyInit] public class YourModController : ModBase { public override string ModIdentifier { get { return "MyModId"; } } public override void EarlyInitalize() { Logger.Message("I am early!"); } } ``` -------------------------------- ### Detour Fallback Handler for Pawn_RelationsTracker Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Detouring Provides a fallback mechanism for detouring the 'Notify_RescuedBy' method in 'Pawn_RelationsTracker'. If the detour fails (e.g., already taken), it displays a message box to the player. ```cs public static class DetourFallbackTest { [DetourMethod(typeof(Pawn_RelationsTracker), "Notify_RescuedBy")] internal static void _Notify_RescuedBy(this Pawn_RelationsTracker t, Pawn rescuer) { // do usual detour stuff } [DetourFallback("_Notify_RescuedBy")] public static void DetourFallbackHandler(MemberInfo attemptedDestination, MethodInfo existingDestination, Exception detourException) { if (existingDestination != null) { LongEventHandler.QueueLongEvent(() => { Find.WindowStack.Add(new Dialog_MessageBox(string.Format("ModName: a required method was already detoured to {0}", existingDestination.FullName()))); }, null, false, null); } } } ``` -------------------------------- ### HugsLib Mod Foundation and Events Source: https://github.com/unlimitedhugs/rimworldhugslib/blob/master/README.md This C# snippet outlines the core functionality provided by HugsLib as a mod foundation. It lists the events that extending classes can receive from the library controller, such as Initialize, DefsLoaded, Tick, Update, and various map/scene-related events. This allows mods to hook into different stages of the Rimworld game loop. ```csharp // Extending classes have access to custom logging, settings, and receive the following events from the library controller: // Initialize, DefsLoaded, Tick, Update, FixedUpdate, OnGUI, WorldLoaded, MapGenerated, MapComponentsInitializing, MapLoaded, MapDiscarded, SceneLoaded, SettingsChanged. ``` -------------------------------- ### Basic Window Injection Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/GUI-Injection Adds a button to the 'Load game' dialog using the `WindowInjection` attribute. The method receives the window and its content area as parameters. ```cs [WindowInjection(typeof(Dialog_SaveFileList_Load))] private static void DrawSaveDialogButton(Window window, Rect inRect) { var buttonSize = new Vector2(120f, 40f); if (Widgets.ButtonText(new Rect(0, inRect.height - buttonSize.y, buttonSize.x, buttonSize.y), "Hello")) { // do stuff } } ``` -------------------------------- ### SettingHandleConvertibleUtility Namespace Change Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-9.0-for-Rimworld-1.3-API-Changes The XML serialization methods for custom SettingHandles have been moved from the `HugsLib.Source.Settings` namespace to the `HugsLib.Settings` namespace. ```csharp namespace HugsLib.Settings { // XML serialization methods for custom SettingHandles } ``` -------------------------------- ### Vanilla Tick Method Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Custom-Tick-Scheduling Demonstrates the standard Rimworld method for executing code at specific tick intervals within a Thing. It uses the Tick() method and HashOffset to distribute work, but can degrade performance with many instances. ```cs public override void Tick() { if ((Find.TickManager.TicksGame + thingIDNumber.HashOffset()) % 60 == 0) { // logic here } } ``` -------------------------------- ### Mod Settings - Custom Context Menu Entries Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.2-Update-Notes Enables the assignment of custom entries to the context menu for `SettingHandle` and `ModSettingsPack`. This allows for more interactive and informative settings menus. ```csharp public class SettingHandle { // ... other fields public List customContextMenuEntries; // ... } public class ModSettingsPack { // ... other fields public List customContextMenuEntries; // ... } public class ContextAction { public string label; public Action action; } ``` -------------------------------- ### Custom Setting Type with Manual Serialization Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Demonstrates creating a custom setting type by extending SettingHandleConvertible and manually handling string conversion for a List. ```cs public override void DefsLoaded() { var custom = Settings.GetHandle("customType", "Label", null); if(custom .Value == null) custom.Value = new CustomHandleType(); } private class CustomHandleType : SettingHandleConvertible { public List nums = new List(); public override bool ShouldBeSaved { get { return nums.Count > 0; } } public override void FromString(string settingValue) { nums = settingValue.Split('|').Select(int.Parse).ToList(); Log.Message(nums.Join(",")); } public override string ToString() { return nums != null ? nums.Join("|") : ""; } } ``` -------------------------------- ### Create Enum Setting Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Shows how to create an enum setting with multiple options. It requires a string identifier prefix for translating the enum values in the settings dialog. ```cs private enum HandleEnum { DefaultValue, ValueOne, ValueTwo } public override void DefsLoaded() { var enumHandle = Settings.GetHandle("enumThing", "enumSetting_title".Translate(), "enumSetting_desc".Translate(), HandleEnum.DefaultValue, null, "enumSetting_"); } ``` -------------------------------- ### Specify Minimum HugsLib Version Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Requiring-a-Minimum-HugsLib-Version This XML snippet defines the minimum required version for HugsLib. When your mod starts, HugsLib checks this version and notifies the player if an update is necessary, preventing potential loading issues. ```xml 8.0.0 ``` -------------------------------- ### SettingHandle.NeverVisible Reset Behavior Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide The `SettingHandle.NeverVisible` property no longer prevents a setting from being reset. To achieve reset immunity, use `SettingHandle.CanBeReset = false`. This also disables the right-click reset option in the Mod Settings window. ```C# SettingHandle.CanBeReset = false ``` -------------------------------- ### Harmony ID for HugsLib Patched Mods Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide The Harmony ID for automatically-patched HugsLib mods is now the mod's PackageId. Previously, it was `HugsLib.ModIdentifier`. Developers can still override this by returning false in `ModBase.HarmonyAutoPatch` and providing a custom identifier. ```C# public override bool HarmonyAutoPatch() => false; // Use your own identifier here ``` -------------------------------- ### HugsLib Mod Spotter API Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Mod-Spotter Provides methods to interact with the HugsLib Mod Spotter. Use `HugsLibController.instance.ModSpotter` to access these functionalities. PackageIds are case-insensitive. ```APIDOC ModSpotter: FirstTimeSeen(packageId: string): bool Checks if the specified mod PackageId has been seen for the first time in the current game run. Parameters: packageId: The unique identifier of the mod (case-insensitive). Returns: true if this is the first time the mod is loaded with HugsLib, false otherwise. SetFirstTimeSeen(packageId: string, seen: bool): void Manually sets the 'first time seen' status for a given mod PackageId. This change is temporary and lasts only until the game restarts. Parameters: packageId: The unique identifier of the mod (case-insensitive). seen: A boolean value indicating whether to mark the mod as seen (true) or not (false). Usage: Primarily useful for testing purposes. ``` -------------------------------- ### Manual Saving of SettingHandle Values Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide Custom setting values within SettingHandle now require manual saving. If no other settings are modified, calling ModSettingsManager.SaveChanges() will not persist these custom values. Use SettingHandle.ForceSaveChanges() to ensure changes are saved. ```C# SettingHandle.ForceSaveChanges() ``` -------------------------------- ### ModSettingsPack Methods Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Details key methods available on the ModSettingsPack object, which is returned by ModBase.Settings or obtained via HugsLibController.SettingsManager.GetModSettings. These include GetHandle for retrieving existing handles, ValueExists to check for setting availability, and PeekValue to read setting values. ```APIDOC ModSettingsPack: GetHandle(string name) - Returns an existing SettingHandle with the specified name, or null if none exists. ValueExists(string name) - Returns true if a setting value is available for the given name. This includes values claimed by handles or loaded but not yet claimed. PeekValue(string name) - Returns the string value of a setting. If the value is claimed by a handle, it returns the handle's value; otherwise, it returns the loaded value. ContextMenuEntries: - Allows assigning custom actions to a settings category's context menu, similar to SettingHandle.ContextMenuEntries. ``` -------------------------------- ### Manual Window Injection Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/GUI-Injection Shows how to add a window injection manually using `WindowInjectionManager.AddInjection`. This method requires a unique `injectionId` for identification and debugging purposes. ```cs WindowInjectionManager.AddInjection("namespace.typeName.methodName", typeof(TargetWindow), YourInjectionMethod); ``` -------------------------------- ### Mod Update News Defs Location Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.0-for-Rimworld-1.1-update-guide Mod Update News defs must now be placed in the `/News` folder within the mod's root directory for processing. This change allows non-HugsLib mods to utilize the update news system. Images referenced in UpdateFeatureDef are first searched in `/News` and then in `/Textures`. ```XML img:images/fancy ``` -------------------------------- ### Dialog_VanillaModSettings Namespace Change Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-9.0-for-Rimworld-1.3-API-Changes The Dialog_VanillaModSettings class has been moved from the `Rimworld` namespace to the `HugsLib.Settings` namespace. ```csharp namespace HugsLib.Settings { public class Dialog_VanillaModSettings : Dialog_ModSettings { // ... } } ``` -------------------------------- ### Requesting ModSettingsPack for Non-Library Mods Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Shows how mods that do not extend ModBase can still implement custom settings by requesting a ModSettingsPack. This involves using HugsLibController.SettingsManager.GetModSettings with a unique mod identifier and an optional label for the Mod Settings dialog. ```cs HugsLibController.SettingsManager.GetModSettings("modIdentifier", modLabel); ``` -------------------------------- ### ModBase Class Structure Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/ModBase-Reference Demonstrates the basic structure of a Rimworld mod class extending HugsLib's ModBase. It includes overriding the ModIdentifier property and the Initialize method. ```cs using HugsLib; using HugsLib.Utils; namespace YourModName { public class YourMod : ModBase { public override string ModIdentifier { get { return "YourModName"; } } public override void Initialize() { base.Initialize(); // Your initialization code here } } } ``` -------------------------------- ### Mod Update News - Target Audience Customization Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/HugsLib-7.2-Update-Notes Allows customization of when mod update news is shown to players. By default, news is not shown to first-time players. This can be controlled using the `targetAudience` field in `UpdateFeatureDef`s. ```csharp public class UpdateFeatureDef { // ... other fields public TargetAudience targetAudience; // ... } public enum TargetAudience { FirstTimePlayer, ReturningPlayer, All } ``` -------------------------------- ### Create Boolean Setting Source: https://github.com/unlimitedhugs/rimworldhugslib/wiki/Adding-Mod-Settings Demonstrates how to create a boolean toggle setting using HugsLib's ModBase. The setting is identified by a unique name, has a translatable title and description, and a default value. ```cs public class SettingTest : ModBase { public override string ModIdentifier { get { return "SettingTest"; } } private SettingHandle toggle; public override void DefsLoaded() { toggle = Settings.GetHandle< bool>( "myToggle", "toggleSetting_title".Translate(), "toggleSetting_desc".Translate(), false); } } ```