The mod context

Every mod gets a ModContext in Load. It's how the mod registers everything it adds to the game, and what StoneForge uses to take it all back when the mod is switched off.

using StoneForge;

namespace MyMod;

public class MyMod : IStoneMod
{
    public void Load(ModContext context)
    {
        context.Log($"Hello from {context.Name} {context.Manifest.Version}");
    }

    public void Unload() { }
}

Lifecycle

Load(context) Runs once, as the game starts (or when the player switches the mod on). Register items, buffs, skills, objects, hooks, UI and settings here. The game isn't running frames yet: do things that touch the game in events, Tick or UI callbacks.
Unload() The player switched the mod off while the game runs. Undo anything you changed that you didn't register through the context: globals you set, instances you made, files. Everything registered through the context is taken back for you afterwards. Not called when the game quits.

What's taken back for you: event and script hooks, ITickables, DrawGui handlers, UI and windows, main menu buttons, settings (saved first), and your items, buffs and skills (removed from the game; a save from before still has them for when the mod is back).

Every frame: ITickable

A mod class that implements ITickable is ticked every frame from when it's loaded:

public class MyMod : IStoneMod, ITickable
{
    public void Tick(double deltaTime)   // seconds since the last frame
    {
        if (Keyboard.Pressed(Keyboard.F7))
            _context.Items.Give(_blade);
    }
    ...
}

Reading keys and the mouse: Keyboard and mouse.

Anything else can be ticked with context.AddTickable(thing) (and stopped with RemoveTickable). Items and buffs that implement ITickable are ticked once they're added.

What the context has

Member
Manifest, Id, Name The mod's mod.json.
Log(text) A line in the loader's log, tagged with the mod's name.
Items, Buffs, Skills, Objects Registering items, buffs, skills and game objects, and using them.
ContentId(key) The full id of your content: "mymod:key".
Settings Settings the player can change in the Mods window.
UI Screens to put UI on.
DrawGui, DrawHud Events to draw every frame: over everything, or with the game's HUD under its windows.
OnScript, OnCode Hooks by name.
LoadSprite, LoadSound Pictures and sounds from your Assets folder.
Files Reading and writing files.
Mods The other mods running: see Using other mods.
Localization The mod's translations: see Localization.
Quests, Contracts Custom quests and contracts.
Dialogues NPC dialogues.
Failed An event: one of the mod's handlers threw. See When a handler fails.
IsContributor Whether the current Steam account is in the mod's contributors.
AddTickable, RemoveTickable Ticking things other than the mod class.

When a handler fails

When one of a mod's handlers throws, StoneForge logs it, shows its error box and carries on without that handler's work. context.Failed tells the mod, the first time each handler throws: where it was ("Tick", "scr_effect_create (script after)"...) and the exception. Use it to look after your players' data: warn them, or keep a copy of their save.

context.Failed += (where, error) =>
{
    SaveBackups.Keep("mymod-error");
    context.Log($"{where} failed: {error.Message}");
};

It runs on the game thread. A Failed handler that throws is only logged. See also Save backups.

Values of your own: ModData

A mod's own values, kept in what the game keeps (an item's data, the save data, an instance's variables), go under keys only that mod uses: two mods' "kills" are two values, and neither touches the game's.

var mine = item.ModData(context);              // an InventoryItem, an Item or a GroundItem
mine["kills"] = mine["kills"].AsInt + 1;

SaveData.ModData(context)["visits"] = 3;        // saved with the game
player.Instance.ModData(context)["marked"] = true;   // a variable on an instance
Where Kept
InventoryItem.ModData, Item.ModData, GroundItem.ModData In the item's data: with it and saved with it wherever it goes (a chest, the ground, a save).
SaveData.ModData In the save data: saved with the game, back when it's loaded. Nothing's kept with no game.
Instance.ModData As variables on the instance, for as long as it's there. Not saved.
ModData
this[key] A value; undefined if it hasn't been set. Setting it sets it.
Has(key), Remove(key) Whether it's set; take it away (a variable is left undefined).
Keys The keys this mod has set here.
GameKey(key) The key as the game holds it: "mymod:kills" in a map, "mymod__kills" as a variable.

Pictures and sounds

int icon = context.LoadSprite("icon.png");                       // Assets\icon.png
int strip = context.LoadSprite("fx/spark.png", frames: 6);       // 6 frames side by side
int music = context.LoadSound("theme.ogg");                      // an OGG stream

Paths are relative to the mod's Assets folder. The sprite is owned by the mod: loading the same path again reuses it, and it's retired when the mod unloads (don't delete it yourself). Both return -1 if the file is missing or can't be loaded.

Files

Mods can't use System.IO. context.Files is their file access:

var files = context.Files;
string names = files.ReadAllText(files.AssetPath("names.txt"));
files.WriteAllText("notes.txt", "...");                                  // mods\MyMod\notes.txt
string[] logs = files.ListFiles(files.ModFolder, "*.txt");                // full paths
Relative paths In the mod's own folder (mods\<mod>\).
Reading Anywhere in the game's folder (ModFiles.GameFolder) or Stoneshard's data folder (ModFiles.DataFolder, %LOCALAPPDATA%\StoneShard: saves, settings).
Writing Only in the data folder or the mod's own folder: never the game's files, the loader or other mods.

Exists, DirectoryExists, ReadAllText, ReadAllLines, ReadAllBytes, ListFiles, WriteAllText, AppendAllText, WriteAllBytes, Delete, CreateDirectory. A path outside what's allowed throws UnauthorizedAccessException.

Trusted mods

A mod can ask for full access with "trusted": true in its mod.json: its own DLLs, the whole of .NET (networking, threads, files, reflection) and Game.CallBuiltinUnrestricted. It runs only once the player allows it in the Mods window, warned that it can do anything a program on their PC can. Ask for it only when a mod truly needs it, such as for multiplayer networking.

results matching ""

    No results matching ""