addons.json

LitheraRP uses the official s&box Addon Project flow. A creator builds an Addon Project targeting LitheraRP, creates a Lithera RP Addon Manifest custom resource, publishes it as a .lraddon package, and lists any required model, material or entity packages in the manifest. The manifest can patch configs, mount assets and carry C# gameplay code. See the code addon guide for the creator SDK.

Install only trusted addons

Data patches modify server gameplay data; applying enabled addons creates backups for changed config files. A failed apply restores the previous files, install ledger, verified package set, active code plan and addon host health when those parts were changed. Code stays unloaded unless you enable allowCodeAddons globally and allowCode on the entry. Approved code can call public gameplay APIs inside the s&box sandbox, so treat allowCode as a trust decision.

Workflow

Use the in-game Admin Console → Addons tab for routine addon work: add an addon package ident, toggle entries, save the file, then use Apply Enabled. The same managed editor is also available from Admin Console → Config → Addons for advanced config workflows.

Common fields

FieldMeaning
enabledMaster switch for addon importing.
settings.mountAddonPackageMount the manifest package before loading the resource. Should stay true.
settings.mountRequiredPackagesMount packages declared by the manifest with withCode: false.
settings.allowedRequiredPackageTypesAllowlist for required asset package types.
settings.maxPatchBytesMaximum UTF-8 JSON payload size for one manifest patch. Clamped from 1,024 to 512,000 bytes.
settings.allowCodeAddonsGlobal switch for addon C# code. Defaults to false: packages mount assets-only and patches still apply, but no addon code loads.
settings.blockConnectionsUntilCodeAddonsReadyRefuse joins while enabled code addons are still booting. Defaults to true, so players never enter a half-initialized ruleset.
settings.blockConnectionsOnCodeAddonFailureKeep joins closed after a required code addon fails activation. Defaults to true; fix or disable the failing entry, then apply again.
settings.clientReadinessTimeoutSecondsSeconds allowed for a remote client to mount and activate the exact required snapshot. Clamped from 15 to 300; default 90.
entries[].idLocal server id for this addon entry. For a code addon it must match the AddonId declared by the addon class.
entries[].packageIdentPublished .lraddon package ident, for example creator.police_pack. local.* idents work during development only.
entries[].enabledWhether /config → Addons → Apply Enabled processes this entry.
entries[].allowCodePer-entry switch for addon C# code. Defaults to false. Both this and settings.allowCodeAddons must be true for code from this entry to load.
entries[].grantedCapabilitiesOperator-approved sensitive capabilities. Effective access is the intersection with the manifest request; empty by default.
entries[].capabilityGrantPackageIdentSystem-managed provenance for grantedCapabilities. Grants are effective only while this normalized ident matches packageIdent; an apply clears stale or unproven grants when the package identity changes.
entries[].manifestAddonId, manifestTitle, manifestVersion, packageRevisionManifest identity and exact package revision recorded by the importer.
entries[].protocolVersion, realm, failurePolicyImported code protocol, execution realm and required or optional failure behavior.
entries[].dependsOn, optionalDependsOn, conflictsWithImported dependency graph used for deterministic activation planning.
entries[].requestedCapabilities, requiredPackages, requiredPackageRevisionsImported capability requests and exact required asset package plan.
entries[].lastStatus, lastMessage, lastAppliedAtUtcResult metadata written after an apply attempt.

The code gate

An addon package published against LitheraRP can carry C# gameplay code. That code loads only when all of the following hold:

  1. settings.allowCodeAddons is true (global opt-in, default off).
  2. The entry has allowCode: true (per-addon opt-in, default off).
  3. The package was actually published against LitheraRP. The publish pipeline writes the parent marker; it cannot be faked by a manifest.

When the gate fails, the apply can still mount assets and import config patches; only the code stays unloaded. When it passes, callbacks run according to the manifest realm: Shared, Server or Client. Remote clients receive the exact client package and code snapshot, then acknowledge its fingerprint before initial pawn creation when required. Setup and API reference: Code addons.

Manifest patch modes

ModePurpose
MergeObjectDeep-merge an object into the object at jsonPath.
UpsertArrayByIdAdd or update one object, or each object in an array, inside the target array using idField. Preferred idempotent mode.
AppendArrayAppend payload values to an array. Avoid for repeatable installs unless duplicates are intended.

Supported target paths are the same safe config files exposed by /config, except configs/addons.json itself. The importer backs up every changed target under configs/addon_backups/ and reloads affected sections. If validation, durable-state persistence or code activation fails, the transaction restores the previous config layer and any live code plan it changed. The previous addon host health is restored only after all rollback steps succeed; an incomplete rollback keeps new connections blocked.

Clean uninstall and re-apply

Each successful apply records a managed layer in configs/addon_install_state.json. Before the next apply, LitheraRP removes that old layer first. Disabling or removing an entry therefore removes its unchanged object values, id-based rows and appended values instead of leaving stale config behind.

The cleanup is a three-way merge: original baseline, previous addon result, and the operator's current file. If an operator edited an addon-owned value after install, LitheraRP preserves that edit and reports the conflict in the apply message. A re-enabled pack then applies from the clean result, so stable ids do not duplicate.

Assets need a restart to leave engine memory

Config layers, code activation and context-managed registrations are removed immediately. Managed resource scans and spawn lookups filter resources owned only by inactive packages. A code addon must still track objects it creates outside a registry. s&box does not expose a safe in-process package-byte unload, so mounted bytes can remain resident until restart even though inactive managed resources are filtered.

Data addons vs asset addons

A simple data-only addon usually patches one or more safe config arrays with stable ids, such as configs/phone.json GPS locations, configs/social.json links, or configs/rules.json sections.

An asset addon can also publish models, materials, prefabs, or sound events through the s&box Addon Project and list any extra cloud packages in RequiredPackages. The manifest still only patches safe config files; the published assets are referenced from those configs using package-local paths.

C# gameplay code: supported since s&box 26.07.08

An Addon Project that targets LitheraRP compiles its C# against the gamemode and ships it in the published package. On servers that pass the code gate above, the addon can add jobs, items, native consumables, weed/meth dealer products, native phone apps, complete NPC replacements, chat/moderation/VIP rules, HUD panels, custom Toolgun modes and full production systems. It can also gate every player balance change and every Toolgun action before commit.

The creator guide is split into focused pages for lifecycle, the complete Context API, every hook payload, networking, persistence, services, registries, UI and security. Start at Code addons.

Example patch payload

Adding a community Discord link to configs/social.json:

1{
2 "TargetPath": "configs/social.json",
3 "JsonPath": "extraLinks",
4 "Mode": "UpsertArrayById",
5 "IdField": "id",
6 "PayloadJson": "{ \"enabled\": true, \"id\": \"northside_discord\", \"label\": \"Discord\", \"icon\": \"discord\", \"url\": \"https://discord.gg/example\", \"accentColor\": \"#5865F2\" }"
7}

Adding a GPS point to configs/phone.json:

1{
2 "TargetPath": "configs/phone.json",
3 "JsonPath": "gps.locations",
4 "Mode": "UpsertArrayById",
5 "IdField": "id",
6 "PayloadJson": "{ \"id\": \"northside_notice_board\", \"name\": \"Community Notice Board\", \"icon\": \"campaign\", \"category\": \"Community\", \"position\": \"-650 300 64\" }"
7}

Reload and apply

  • litherarp.addons_reload: reload configs/addons.json after a manual edit.
  • litherarp.addons_apply: remove the previous managed layer, fetch enabled .lraddon manifests, mount declared packages, import fresh config patches, and reconcile C# activation. Rolls back config changes on failure.
  • litherarp.addons_reset: reset addon entries to shipped defaults.

See also Install an addon and Create an addon manifest in the workflows.