Changes

→‎Mod data: rewrite, add more info from migration guide
Line 5: Line 5:  
==Storage options==
 
==Storage options==
 
===JSON files===
 
===JSON files===
You can store data in arbitrary <tt>.json</tt> files in your mod folder. Note that these files will be lost if the player deletes them (e.g. when updating your mod), so this is mainly useful for bundled files, cache files, etc.
+
You can store data in arbitrary <samp>.json</samp> files in your mod folder. Note that these files will be lost if the player deletes them (''e.g.,'' when updating your mod), so this is mainly useful for bundled files, cache files, etc.
    
<ol>
 
<ol>
 
<li>[[#Data model|Create your data model]].</li>
 
<li>[[#Data model|Create your data model]].</li>
<li>In your mod code, use the mod helper to read/write a named file. This example assumes you created a class named <tt>ModData</tt>, but you can use different names too.
+
<li>In your mod code, use the mod helper to read/write a named file. This example assumes you created a class named <samp>ModData</samp>, but you can use different names too.
    
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
Line 19: Line 19:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
Note that <tt>ReadJsonFile</tt> will return <tt>null</tt> if the file doesn't exist. The above example will create a default instance if that happens; if you don't want to do that, just remove the <code>?? new ModData()</code> part.</li>
+
Note that <samp>ReadJsonFile</samp> will return <samp>null</samp> if the file doesn't exist. The above example will create a default instance if that happens; if you don't want to do that, just remove the <code>?? new ModData()</code> part.</li>
 
</ol>
 
</ol>
   Line 27: Line 27:     
===Save data===
 
===Save data===
You can store arbitrary data in the current save file. This is mainly useful for save-specific data, like player progression and custom items. This is subject to some restrictions: the save file must be loaded (e.g. it won't work on the title screen), it can't be used by farmhands in multiplayer (you can [[Modding:Modder Guide/APIs/Utilities#Context|check <tt>Context.IsMainPlayer</tt>]]), and it'll be discarded if the player exits without saving. If the data needs to be prepared prior to saving, the [[Modding:Modder Guide/APIs/Events#GameLoop.Saving|<tt>GameLoop.Saving</tt> event]] is a good time to do it.
+
You can store arbitrary data in the current save file. This is mainly useful for save-specific data, like player progression and custom items. This is subject to some restrictions: the save file must be loaded (''e.g.,'' it won't work on the title screen), it can't be used by farmhands in multiplayer (you can [[Modding:Modder Guide/APIs/Utilities#Context|check <samp>Context.IsMainPlayer</samp>]]), and it'll be discarded if the player exits without saving. If the data needs to be prepared prior to saving, the [[Modding:Modder Guide/APIs/Events#GameLoop.Saving|<samp>GameLoop.Saving</samp> event]] is a good time to do it.
    
<ol>
 
<ol>
 
<li>[[#Data model|Create your data model]].</li>
 
<li>[[#Data model|Create your data model]].</li>
 
<li>[[#Data key|Choose your data key]].</li>
 
<li>[[#Data key|Choose your data key]].</li>
<li>In your mod code, use the data API to read/write a named entry. This example assumes your data model is <tt>ModData</tt> and your key is <tt>example-key</tt>, but you can use different values.
+
<li>In your mod code, use the data API to read/write a named entry. This example assumes your data model is <samp>ModData</samp> and your key is <samp>example-key</samp>, but you can use different values.
    
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// read file
+
// read data
 
var model = this.Helper.Data.ReadSaveData<ModData>("example-key");
 
var model = this.Helper.Data.ReadSaveData<ModData>("example-key");
   −
// save file (if needed)
+
// save data (if needed)
 
this.Helper.Data.WriteSaveData("example-key", model);
 
this.Helper.Data.WriteSaveData("example-key", model);
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
Note that <tt>ReadSaveData</tt> will return <tt>null</tt> if the data doesn't exist.</li>
+
Note that <samp>ReadSaveData</samp> will return <samp>null</samp> if the data doesn't exist. Additionally, <samp>ReadSaveData</samp> is scoped to your mod, so you do not need to prepend with your mod's uniqueID</li>
 
</ol>
 
</ol>
   Line 51: Line 51:  
<li>[[#Data model|Create your data model]].</li>
 
<li>[[#Data model|Create your data model]].</li>
 
<li>[[#Data key|Choose your data key]].</li>
 
<li>[[#Data key|Choose your data key]].</li>
<li>In your mod code, use the data API to read/write a named entry. This example assumes your data model is <tt>ModData</tt> and your key is <tt>example-key</tt>, but you can use different values.
+
<li>In your mod code, use the data API to read/write a named entry. This example assumes your data model is <samp>ModData</samp> and your key is <samp>example-key</samp>, but you can use different values.
    
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// read file
+
// read data
 
var model = this.Helper.Data.ReadGlobalData<ModData>("example-key");
 
var model = this.Helper.Data.ReadGlobalData<ModData>("example-key");
   −
// save file (if needed)
+
// save data (if needed)
 
this.Helper.Data.WriteGlobalData("example-key", model);
 
this.Helper.Data.WriteGlobalData("example-key", model);
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
Note that <tt>ReadGlobalData</tt> will return <tt>null</tt> if the data doesn't exist.</li>
+
Note that <samp>ReadGlobalData</samp> will return <samp>null</samp> if the data doesn't exist.</li>
 
</ol>
 
</ol>
   Line 68: Line 68:  
The ''data model'' is a C# class you create, with properties representing the data you want to store. It can contain almost anything from a few boolean fields to a complex object graph. Here's a simple data model:
 
The ''data model'' is a C# class you create, with properties representing the data you want to store. It can contain almost anything from a few boolean fields to a complex object graph. Here's a simple data model:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
class ModData
+
public sealed class ModData
 
{
 
{
 
   public bool ExampleBoolean { get; set; }
 
   public bool ExampleBoolean { get; set; }
Line 82: Line 82:  
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Only public properties and fields will be serialized, and your class needs a zero-parameter constructor. SMAPI uses NewtonSoft to serialize these models, so if you need finer-grained control over what gets serialized, use NewtonSoft annotations.
    
===Default values===
 
===Default values===
Line 111: Line 113:  
==Data key==
 
==Data key==
 
A ''data key'' identifies your data, which lets you access the data again later. It should be unique within your mod, but there's no need to worry about conflicts with other mods (SMAPI will namespace the key internally). A data key can only contain letters, numbers, underscores, hyphens, or dots.
 
A ''data key'' identifies your data, which lets you access the data again later. It should be unique within your mod, but there's no need to worry about conflicts with other mods (SMAPI will namespace the key internally). A data key can only contain letters, numbers, underscores, hyphens, or dots.
 +
 +
==Deletion==
 +
To remove an entry or file, just pass <code>null</code> as the data model. This works with any of the <samp>Write*</samp> methods:
 +
<syntaxhighlight lang="c#">
 +
// delete entry (if present)
 +
this.Helper.Data.WriteSaveData<DataModel>("example-key", null);
 +
</syntaxhighlight>
 +
 +
==See also==
 +
===Mod data===
 +
You can also store custom data for individual game entities which have a <samp>modData</samp> dictionary field. That includes NPCs and players (<samp>Character</samp>), <samp>GameLocation</samp>, <samp>Item</samp>, and <samp>TerrainFeature</samp>. This is persisted to the save file and synchronized in multiplayer.
 +
 +
Usage notes:
 +
* To avoid mod conflicts, prefixing data fields with your mod ID is strongly recommended (see the example below).
 +
* When you split an item stack, the new stack copies the previous one's <samp>modData</samp> field; when merged into another stack, the merged items adopt the target stack's mod data. Otherwise mod data has no effect on item split/merge logic (''e.g.,'' you can still merge items with different mod data).</li>
 +
 +
For example, this writes and then reads a custom 'age' value for an item:
 +
<syntaxhighlight lang="c#">
 +
// write a custom value
 +
item.modData[$"{this.ModManifest.UniqueID}/item-age"] = "30";
 +
 +
// read it
 +
if (item.modData.TryGetValue($"{this.ModManifest.UniqueID}/item-age", out string rawAge) && int.TryParse(rawAge, int age))
 +
  ...
 +
</syntaxhighlight>
translators
8,446

edits