-
Notifications
You must be signed in to change notification settings - Fork 58
ModBase Reference
The easiest way to access the facilities and events HugsLib provides is to create a class that extends HugsLib.ModBase
.
To access the type in Visual Studio the HugsLib dll must be added as a reference to your project. It's also recommended to add add the checker assembly to your mod to make sure the library is installed when the mod is loaded.
When a type extends ModBase, it will be automatically instantiated by HugsLib on game start. Make sure that your class has a parameterless constructor, which can be private if you prefer.
Each ModBase class needs to have a unique identifier. Provide yours by overriding the ModIdentifier
property. The identifier will be used in the settings XML to store your settings, so avoid spaces and special characters. You will get an exception if you provide an improper identifier.
The Logger property allows a mod to write identifiable messages to the console. Error and Warning methods are also available. Calling:
Logger.Message("test");
will result in the following console output:
[ModIdentifier] test
Additionally, the Trace method of the logger will write a console message only if Rimworld is in Dev mode.
Returns true if the mod is enabled in the Mods dialog. Disabled mods would not be loaded or instantiated, but if a mod was enabled, and then disabled in the Mods dialog this property will return false.
This property is no longer useful as of A17, since the game restarts when the mod configuration changes.
Returns the ModSettingsPack
for your mod, from where you can get your SettingsHandle
s. See the wiki page of creating configurable settings for more information.
Returns the ModContentPack
for your mod. This can be used to access the name and PackageId, as well as loading custom files from your mod's directory.
All assemblies that declare a class that extends ModBase are automatically assigned a HarmonyInstance
and their Harmony patches are applied. This is where the Harmony instance for each ModBase instance is stored.
Override this and return false
if you don't want a HarmonyInstance
to be automatically created and the patches in your assembly applied. Having multiple ModBase classes in your assembly will produce warnings if their HarmonyAutoPatch
is not disabled, but your assembly will only be patched once.
To receive events from the HugsLib controller the extending class must override the methods provided by ModBase
. The following are the events that can be received:
Called during Verse.Mod
instantiation, and only if your class has the [EarlyInit]
attribute.
Nothing is yet loaded at this point, so you might want to place your initialization code in Initialize
, instead- this method is mostly used for custom patching.
You will not receive any callbacks on Update
, FixedUpdate
, OnGUI
and SettingsChanged
until after the Initialize
callback comes through.
Initialize
will still be called at the normal time, regardless of the [EarlyInit]
attribute.
Called once when the mod is first initialized, closely after it is instantiated.
If the mods configuration changes, or Defs are reloaded, this method is not called again.
Called after all Defs are loaded.
This happens when game loading has completed, after Initialize
is called. This is a good time to inject any procedural defs. Make sure you call HugsLib.InjectedDefHasher.GiveShortHasToDef
on any defs you manually instantiate to avoid def collisions (it's a vanilla thing).
Since A17 it no longer matters where you initialize your settings handles, since the game automatically restarts both when the mod configuration or the language changes. This means that both Initialize
and DefsLoaded
are only ever called once per ModBase
instance.
Called on each frame.
Keep in mind that frame rate varies significantly, so this callback is recommended only to do any custom drawing.
Called on each physics update by Unity.
This is like Update
, but independent of frame rate.
Called when the Unity GUI system is redrawn or receives an input event.
This is a good time to draw custom GUI overlays and controls.
Also useful for listening for input events, such as key strokes. Here's an example of a key binding listener:
if (Event.current.type == EventType.KeyDown) {
if (KeyBindingDefOf.Misc1.JustPressed) {
// do things
}
}
Since A17 OnGUI
will no longer be called during loading screens and will have UI scaling automatically applied.
Called after a Unity scene change. Receives a UnityEngine.SceneManagement.Scene
type argument.
There are two scenes in Rimworld- Entry
and Play
, which stand for the menu, and the game itself. Use Verse.GenScene
to check which scene has been loaded.
Note, that not everything may be initialized after the scene change, and the game may be in the middle of map loading or generation.
Called after the game has started and the world has been initialized.
Any maps may not have been initialized at this point.
This is a good place to get your UtilityWorldObject
s with the data you store in the save file. See the appropriate wiki page on how to use those.
This is only called after the game has started, not on the "select landing spot" world map.
Called during the initialization of a map, more exactly right after Verse.Map.ConstructComponents()
. Receives a Verse.Map
type argument.
This is a good place for sneaky business and getting access to data that is unavailable after map loading has completed.
This is right before the map is populated with data from a save file.
Called right after a new map has finished generating. This is the equivalent of creating a MapComponent
and overriding its MapGenerated
method, but without the need to pollute save files with unnecessary map components.
Called after map loading and generation is complete and after Verse.MapDrawer.RegenerateEverythingNow
was executed. Receives a Verse.Map
type argument.
This is a good place to run initialization code specific to a game map.
Note, that this method may be called zero or multiple times after loading a save, depending on how many maps the player has active at the moment.
Called after a map has been abandoned or otherwise made inaccessible. Works on player bases, encounter maps, destroyed faction bases, etc. This is a good place to clean up any map-related data in your World
and UtilityWorldObject
s to avoid bloating the save file.
Called during each tick, when a game is loaded. Receives an int
argument, which is the number of the current tick.
Will be called even if the player is on the world map and no map is currently loaded.
Will not be called on the "select landing spot" world map.
Called after the player closes the Mod Settings dialog after changing any setting.
Note, that the setting changed may belong to another mod.
Called before the game process shuts down. This is a good place to update any non-critical mod setting values or write any custom data files.
"Quit to OS", clicking the "X" button on the window, and pressing Alt+F4 all execute this event. There are still ways to forcibly terminate the game process, as well as the possibility of a crash, so this callback is not 100% reliable.
Modified mod settings are automatically saved after this call.
Adding this attribute to you ModBase
class will cause it to be instantiated at the earliest possible time- when Verse.Mod
instances are being created. This also causes your Harmony patches to be applied earlier (assuming, your HarmonyAutoPatch is true
), which makes this a great way to patch vanilla loading and Def
generation code.
The EarlyInitalize
method is called immediately after, but implementing it is optional.
Keep in mind, that pretty much nothing outside of HugsLib is yet loaded at this point. You can already access your Settings
object, but it might not be a good idea to create SettingHandle
s here, since translation strings have not been loaded yet. Instead, you can make use of ValueExists
and PeekValue
if you need to read one of your settings.
[EarlyInit]
public class YourModController : ModBase {
public override string ModIdentifier {
get { return "MyModId"; }
}
public override void EarlyInitalize() {
Logger.Message("I am early!");
}
}