-
Notifications
You must be signed in to change notification settings - Fork 59
World Data Storage
The recent versions of Rimworld now offer more convenient and performant ways of storing world-specific data: WorldComponent
and GameComponent
. It is recommend to transition your stored data to one of those, as UtilityWorldObject
s will be removed in the next major HugsLib update (to Rimworld 1.2, presumably).
Here's a WorldComponent
Example:
// 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>()
UtilityWorldObject
-s are a convenient and reliable way to store map-independent mod data within a save file.
Before A16 MapComponent
-s used to be the go-to method for receiving events and storing mod data. With the advent of simultaneously active maps, however, they are no longer reliable- every active map will create its own instance of a component and any components are lost when the player abandons a map.
Enter UtilityWorldObject
- an invisible object attached to the world map, that is reliably loaded and saved with the game. When requesting a UWO from the library, either the existing object of the matching type is returned, or a new one is created and injected into the world.
To allow the custom object to save its data, ExposeData
must be overridden and the necessary fields exposed using Scribe
methods, as usual. ExposeData
will be called when the game is loaded and saved.
Example:
public class StorageTest : ModBase {
public override string ModIdentifier {
get { return "StorageTest"; }
}
public override void WorldLoaded() {
var obj = UtilityWorldObjectManager.GetUtilityWorldObject<WorldDataStore>();
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", "");
}
}
}
WorldObject.PostAdd
is an optional override and is called the first time the object is added to the world.
WorldObjects, however, are not necessarily the ultimate storage solution- MapComponent
-s are still useful for storing data that should live and die with a Map
. The library adds some extension methods to make working with them easier:
A extension method for MapComponent
, designed to be called in its constructor. It injects the map component into the map if it is not already present. This is useful for allowing a mod to work on saved games where it was not active at the moment of map creation. At the moment, Rimworld will instantiate a MapComponent
, but it will not be added to the map if the map is being loaded from a save.
Calling this method ensures that the MapComponent
will receive calls and is saved with the map.
public class InjectedMapComponent : MapComponent {
public InjectedMapComponent(Map map) : base(map) {
this.EnsureIsActive();
}
}
An extension method for Map
that is useful during the ModBase.MapLoaded
event. It retrieves the first MapComponent
of the provided type from the map.