Skip to content

Modding Overview

Softfire supports community modifications via the .sfpak archive format and a sandboxed Lua scripting runtime. Mods can replace assets, add new content definitions, and execute scripts — all within a declared permission model that players review before installing.

Mod types

Asset overrides replace or supplement existing engine assets: textures, audio files, sprite atlases, prefabs, and UI layouts. An asset override mod bundles replacement files into a .sfpak archive alongside a manifest that maps each file to the original content key it replaces. Asset mods require no scripting and no special permissions — they only affect the visual or audio presentation of the game.

Content mods add new items, species, resource node types, faction definitions, or zone configurations. These are structured JSON definition files that the engine merges into the content registry at load time. Content mods can declare new species for The Wild or new resource types for The Flow, but they cannot alter the simulation logic itself.

Script mods include Lua files that run in the sandbox at defined hook points. Script mods can respond to game events, manipulate local UI state, and read world state — but they cannot perform I/O, call arbitrary C# code, or directly emit Echo events (the ModifyWorldInfluence permission is required for any path that reaches The Echo).

A single .sfpak archive can combine all three mod types.

The SFPak archive format

.sfpak is a ZIP-compatible container with a ModManifest.json at its root:

{
"id": "com.example.highland_overhaul",
"displayName": "Highland Overhaul",
"version": "1.2.0",
"gameId": "your-game-id-here",
"engineMinVersion": "1.0.0",
"author": "Example Modder",
"description": "Replaces Highland zone textures and adds 3 new species.",
"permissions": [
"ReadEntityState",
"ReadWorldState"
],
"entryPoints": {
"onSceneLoad": "scripts/on_load.lua",
"onUpdate": "scripts/update.lua"
}
}

Archives are loaded by the in-game mod browser, which validates the manifest signature before activating the mod. Unsigned mods are flagged to players but can still be installed — the lack of a signature means the mod has not been submitted to Softfire for review, not that it is malicious.

The permission system

Every mod declares the permissions it needs in ModManifest.permissions. When a player installs a mod, the mod browser shows a plain-language summary of each permission.

Permissions are enforced at runtime by the Lua sandbox: if a script attempts to call an API that requires a permission not declared in the manifest, the call throws a LuaSandboxPermissionException inside the script — it does not crash the game.

See the full Mod Permissions reference for all available permissions and what each grants.

The sandbox model

Mod Lua scripts run inside a LuaScriptSandbox instance. The sandbox:

  • Starts with an empty global environment — no standard Lua libraries are pre-loaded
  • Grants access only to modules explicitly listed as available to the declared permissions
  • Prohibits reflection, file I/O, networking, and direct access to C# types
  • Has a per-script instruction budget (default 500,000 instructions per Update call) to prevent infinite loops from stalling the game

Scripts that exceed the instruction budget are terminated for that tick and log a warning. Scripts that throw unhandled exceptions are disabled after three consecutive failures, and the player is notified via the mod browser.

Where mods live

Mods are stored in the platform’s mod directory:

  • Windows: %APPDATA%\Softfire\Mods\<gameId>\
  • Linux: ~/.local/share/Softfire/Mods/<gameId>/
  • macOS: ~/Library/Application Support/Softfire/Mods/<gameId>/

Players install mods via the in-game mod browser (accessible from the game’s main menu if the developer has not disabled it) or by dropping .sfpak files directly into the mod directory. The mod browser reads the directory on startup and after hot-drop installs.

For developers: designing your mod API surface

The permission system is only as useful as the action API you expose to mods. By designing your game’s IScriptActionHandler implementations carefully, you control exactly what script mods can trigger — mods cannot reach engine internals they are not given access to.

See Lua Scripting for how to register action handlers and Mod Permissions for how to design a minimal, secure permission surface.