6.1 KiB
Development Guide
This guide covers the usual path for adding or changing a Forge module.
Repository Workflow
Use Git Workflow as the source of truth for branch roles, release tags, and mission branch handling. The short version is:
- Use
pre-v0.2for framework development after thev0.1.0baseline. - Keep
masteras the clean release baseline branch. - Keep mission folders off
master; mission work belongs onmissions/local-mission-copies. - Keep
archive/pre-v0.1-historyread-only unless recovering old work. - Bring reusable mission logic back to framework branches by copying only the needed framework files or code, not by merging the mission branch.
Use the workflow helper for the routine checks:
npm run workflow -- status
npm run workflow -- doctor
npm run workflow -- switch dev
npm run workflow -- switch missions
Example framework workflow:
git switch pre-v0.2
git pull
git switch -c feature/cad-task-request
# make framework changes
git status --short --branch
git add arma/client/addons/cad arma/server/addons/cad
git commit -m "Add CAD task request workflow"
Example mission workflow:
git switch missions/local-mission-copies
# make mission changes
git status --short --branch
git add arma/forge_pmc_simulator.Tanoa
git commit -m "Update PMC simulator mission setup"
Local Checks
Before running storage-backed workflows locally, complete
SurrealDB Setup. A local or dedicated server launch must
have SurrealDB running and a config.toml beside forge_server_x64.dll that
matches the running database.
Run these before pushing Rust or extension changes:
cargo fmt --check
cargo check
cargo test
cargo build
cargo clippy --all-targets --all-features -- -D warnings
Run this after changing browser UI sources:
npm run build:webui
Build Arma packages with:
.\build-arma.ps1
Module Boundaries
Keep each layer responsible for one kind of work:
| Layer | Owns | Avoid |
|---|---|---|
lib/models |
Data structures, serde defaults, validation helpers. | Database calls, SQF-specific context. |
lib/repositories |
Repository traits and in-memory stores. | SurrealDB-specific code. |
lib/services |
Business rules, workflow orchestration, structured results. | Arma engine calls, extension transport details. |
arma/server/extension |
Command parsing, context resolution, SurrealDB implementations, serialization to SQF. | Business rules that belong in services. |
arma/server/addons |
Server SQF lifecycle, game-object integration, calls into forge_server. |
Direct database logic. |
arma/client/addons |
Client UI, keybinds, local UI events. | Authoritative persistence. |
Adding a Domain Module
- Add the model in
lib/models/src/<module>.rs. - Export the model from
lib/models/src/lib.rs. - Add repository traits in
lib/repositories/src/<module>.rs. - Add in-memory repository support if the service needs tests or hot state.
- Export the traits from
lib/repositories/src/lib.rs. - Add service logic in
lib/services/src/<module>.rs. - Add focused unit tests for service behavior.
- Export the service from
lib/services/src/lib.rs. - Add a SurrealDB schema module under
arma/server/extension/src/schema. - Add the concrete storage adapter under
arma/server/extension/src/storage. - Register the storage adapter in
arma/server/extension/src/storage.rs. - Add an extension command group under
arma/server/extension/src/<module>.rs. - Register the command group in
arma/server/extension/src/lib.rs. - Add server addon functions under
arma/server/addons/<module>if SQF needs a module-level API. - Add client addon or browser UI files under
arma/client/addons/<module>if the module has player-facing UI. - Add documentation in
docs/and module-level READMEs.
Extension Command Rules
Commands should return one of these forms:
- JSON string for structured results.
"true"or"false"for simple existence and boolean operations."OK"for successful destructive operations with no response body."Error: <message>"for failures.
Prefer stable JSON shapes over ad hoc strings. SQF callers should always check
for the "Error:" prefix before parsing JSON.
Example:
private _result = "forge_server" callExtension ["actor:get", [getPlayerUID player]];
private _payload = _result select 0;
if (_payload find "Error:" == 0) exitWith {
systemChat format ["Actor request failed: %1", _payload];
};
private _actor = fromJSON _payload;
Persistence Rules
SurrealDB is the durable store. Keep database-specific mapping in the extension storage adapters, not in services or repository traits.
When changing persisted data:
- Update or add the matching
.surqlschema module. - Update the concrete storage adapter.
- Preserve existing records when possible through serde defaults or migration logic.
- Add tests at the service level for behavior, and add storage tests only when database mapping is the risk.
Hot-State Rules
Use hot state for data that is read or mutated frequently during a player session. Hot-state modules usually provide:
initto load durable state into memory.getto read the runtime copy.overrideor focused mutation commands to update the runtime copy.saveto write the runtime copy back to SurrealDB.removeto evict the runtime copy.
Do not assume hot state is durable until save succeeds.
Web UI Rules
Browser UI source files live under each client addon. Built assets usually land
under that addon's ui/_site directory.
Use the existing common bridge in arma/client/addons/common when a UI needs
to send events back to SQF. Keep UI state and rendering in JavaScript, and keep
server-authoritative decisions in server SQF or Rust services.
Documentation Checklist
When adding or changing a module, update:
docs/MODULE_REFERENCE.mdfor framework-level inventory.- A module-specific README in the addon directory when SQF or UI usage changes.
arma/server/docs/api-reference.mdwhen extension commands change.- Existing usage guides when payload shapes or workflows change.