Another SMAPI mod can add NPCs at run time through NPC Helper 2's public API. Use it when your NPCs are generated by code or come from your mod's own data. For a fixed set of NPCs, a content pack is simpler.
Step 1: Depend on NPC Helper 2#
In your mod's manifest.json, list NPC Helper 2 as a required dependency so SMAPI loads it first and warns players if it is missing:
"Dependencies": [
{ "UniqueID": "Framework.Mod.NpcHelper", "MinimumVersion": "2.4.0" }
]
Step 2: Get the API#
Add the INpcHelperApi interface to your mod (the C# SDK includes it), then request it:
var api = helper.ModRegistry.GetApi<INpcHelperApi>("Framework.Mod.NpcHelper");
Call it from GameLaunched or later. NPCs registered after the game has loaded its data are picked up because NPC Helper 2 refreshes the affected assets.
The interface#
public interface INpcHelperApi
{
bool RegisterNpcFromToml(string name, string toml, string sourceDirectory);
void RegisterNpc(string name, NpcDefinition data);
bool IsNpcRegistered(string name);
IReadOnlyList<string> GetRegisteredNpcNames();
}
RegisterNpcFromToml (recommended)#
Registers an NPC from TOML text.
| Argument | Meaning |
|---|---|
name |
The NPC's name. It overrides any Name key in the text. |
toml |
The NPC definition, in the same format as an NPC file (NPC definition). It can contain [Dialogue], [Schedule], and [Marriage] data inline. |
sourceDirectory |
A folder with the NPC's side files, or null if there are none. |
When you pass a sourceDirectory, NPC Helper 2 looks there for the side files it finds by name in any NPC folder: Dialogue.toml, Schedule.toml, and Marriage.toml, images under sprites/ and portraits/, and translations under locale/. There are no path settings in the TOML.
The method returns false and logs the reasons if the NPC is rejected. The same validation applies as for a content pack.
string toml = "Name = \"Rei\"\nDisplayName = \"Rei\"\n[Personality]\nGender = \"Female\"\n";
bool ok = api.RegisterNpcFromToml("Rei", toml, null);
If the NPC has side files, pass its folder:
string folder = Path.Combine(helper.DirectoryPath, "NPCs", "Rei");
bool ok = api.RegisterNpcFromToml("Rei", File.ReadAllText(Path.Combine(folder, "Rei.toml")), folder);
Because only strings cross the mod boundary, this works with SMAPI's API proxying without sharing any types between mods.
RegisterNpc#
Registers an NpcDefinition built in code. The definition is validated and copied, so changing it afterwards has no effect.
SMAPI can only proxy interfaces and basic types, so this works only if your mod and NPC Helper 2 share the same NpcDefinition type. Prefer RegisterNpcFromToml.
IsNpcRegistered and GetRegisteredNpcNames#
bool known = api.IsNpcRegistered("Rei");
IReadOnlyList<string> names = api.GetRegisteredNpcNames();
They report what NPC Helper 2 has registered. Names are compared without regard to case.
Behaviour to know#
- A name that is already registered is replaced, and a warning names both sources.
- NPCs from
RegisterNpcFromTomlare rebuilt when the game language changes, and alocale/folder insidesourceDirectoryis used. NPCs fromRegisterNpcstay as registered. - Invalid names and invalid NPC content are reported and rejected. Check the return value and the SMAPI log. As with any SMAPI API call, this does not guard against unrelated errors in the calling mod.