HugsLib 7.0 for Rimworld 1.1 update guide - UnlimitedHugs/RimworldHugsLib GitHub Wiki
This is a brief guide to ease the transition to HugsLib 7.0 for Rimworld 1.1.
Despite the earlier warning about pending breaking changes, this HugsLib update should still be fully API-compatible with all dependent mods. Despite not breaking outright, to work correctly with the new version, mods may need minor changes- which I'd like to highlight in this document.
The various HugsLib wiki pages will be updated with the new changes eventually, but for now this page should serve as a reference.
Due to critical compatibility issues, the Harmony assembly file can no longer be distributed with HugsLib. Harmony is now available as a separate mod that must be installed by the players along with HugsLib.
If your mod has a dependency on HugsLib, you can add another dependency on the Harmony mod, but that is not strictly necessary- HugsLib already takes care of that. When publishing, it's not recommended to include the Harmony dll file with your mod, as it would not be used anyway.
Harmony in standalone mod form can be downloaded here: https://github.com/pardeike/HarmonyRimWorld/releases
This used to be the case before, but now simply calling ModSettingsManager.SaveChanges()
will not save custom handle values- assuming no other setting values were modified. This happens because SettingHandle
has no way to detect changes in a reference-type value.
Long story short- call SettingHandle.ForceSaveChanges()
on the handle that contains your custom setting value type after making changes to it.
Ownership, in this case, means the ModBase
instance that was given the ModSettingsPack
(assigned to the ModBase.Settings
property) from which the modified handles were created. As a reminder, SettingsChanged
is called both when the Mod Settings window closes, as well as when settings are manually saved using ModSettingsManager.SaveChanges()
.
See the Additions section below if you need to be notified of settings changes in any HugsLib mod, like before.
Due to the update news system becoming available to non-HugsLib mods, all news defs must now be loaded from the /News
folder in the root folder of your mod (Rimworld/Mods/YourMod/News
). I recommend copying, rather than moving, the def XML files there to allow your news to be displayed on both the 1.0 and 1.1 versions of your mod- assuming you are making use of the new versioned folders system.
News item images should also be moved to the /News
folder- more on that below.
This used to be HugsLib.ModIdentifier
before, but the new package ids are a much better fit for a unique identifier. You can still return false in ModBase.HarmonyAutoPatch
and use your own identifier, if you like.
Note: the original, non-lowercase, ModContentPack.PackageIdPlayerFacing
, is used.
If you want reset immunity, set SettingHandle.CanBeReset
to false
. This also works for visible settings and disables their reset option via the right-click menu.
The only way to reset a NeverVisible
setting from the game is by using the Reset All button in the Mod Settings window.
While optional, this is a good idea, because images in the Textures folder are always loaded on game startup in their entirety. When it comes to update news images, 99 times out of 100 that is wasted memory and CPU time. Placing images under /News
, however, results in them being loaded only when the update news window is opened, and unloaded after the window is closed.
When referencing an image (e.g. <content>img:images/fancy</content>
) in an UpdateFeatureDef
, it will first be looked for under the /News
folder (Mods/YourMod/News/images/fancy.png
) and if not found, under the /Textures
folder (Mods/YourMod/Textures/images/fancy.png
). This way you can reuse some asset that is used elsewhere in your mod, or even the base game.
When moving images used in news items available in the 1.0 version of your mod, it's a good idea to remove them from the news content, so they won't be replaced with "missing texture" images when those news items are displayed. Alternatively, you could leave the 1.0 news images under /Textures
and put any new ones under /News
.
This makes writing news content more comfortable, as you can add line breaks and indents between your sections. These are automatically removed when loaded, unless you specify <trimWhitespace>false</trimWhitespace>
in the news def. This can be useful if you are using whitespace to affect the layout of a news item.
The UpdateFeatureDef.assemblyVersion
is still present, but us used only to sort news items and remember the latest version displayed to the player.
Did you know we had that? I bet you didn't. I was not using it and apparently no one else was, so- good riddance.
Some things have been marked as deprecated. These still fully work, but should be replaced when possible, as they will be removed during the next major update (Rimworld 1.2).
-
ModBase.EarlyInitalize
Added a new method to fix the typo. -
MapComponentUtility.EnsureIsActive
Map components are now automatically injected by the game, including the ones added after map creation. -
MapComponentUtility.GetMapComponent
Base game now hasVerse.Map.GetComponent<T>()
which does the same thing. -
UtilityWorldObject
Yes, I think it is time for that. The idea is to transition toGameComponent
andWorldComponent
added by the base game. They are inherently better suited for the task, and should be slightly faster to access. Not to mention thatUtilityWorldObject
is just a hack added back in the Alpha 16 days to allow us to store data common to all maps. Here is a basic conversion example:// 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<WorldData>();
Becomes:
// 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<WorldData>()
GameComponent
is instantiated at the storyteller selection screen, whileWorldComponent
is created when the world map is generated. Both save and load properly, as far as my testing shows. Slight gotcha: YourGameComponent
constructor must declare aGame
parameter, despite its base class having a parameterless constructor. Let me know if you have any issues with the transition- we could make tweaks to address them.
The first is now used to identify ModBase
mods in the logs, and the second to uniquely identify their HugsLib mod settings. Both properties are optional and can be replaced with ModBase.ModIdentifier
(which is now optional, as well). If neither is defined, the mods PackageId
is used as the identifier.
The Before
event is useful for identifying the mods that are saving settings and the specific handles that are being saved. Use ModSettingManager.ModSettingsPacks
and ModSettingsPack.Handles
to enumerate them. When SettingHandle.HasUnsavedChanges
is set to true
, it is part of the reason settings are being saved, as ``ModSettingManagerwould not raise the event if none of the handles had unsaved changes. The
After` event is raised when the settings XML file has been flushed to disk, and all of the handles will have had their `HasUnsavedChanges` property reset to false.
Very useful for dependencies and load order. The Harmony Id of a mod might differ from its Package Id- consult the "Harmony versions present" line of the log for a list of all Harmony Ids.
This should about cover it. Please report any issues you find and feel free to ask if you have any questions- I am happy to talk to you about stuff (and things). You can find me on Discord, post on the forum, or even email me if you like.
Also, if you would like any hooks added to the library, feel free to tell me. Patching the library with Harmony is a good start to get your thing working, but patches (and reflection) are liable to break when I change the internals of the library. However, anything added to the public API will still work after I update things on my end.
Take care, and thank you for your time.
-Hugs