Architecture
Load order and ownership
The rules that keep seven PBOs from turning into one tangle: what loads when, which machine decides, and which names you may not rename.
Seven PBOs, one contract. This page is the map you need before you change anything: what loads when, which machine owns which state, and how components talk without creating a dependency cycle.
1. Component map
| Component | PBO prefix | Requires | Owns |
|---|---|---|---|
FF_core | x\FF\addons\core | CBA | Editor categories, module bases, shared UI contracts |
FF_utils | x\FF\addons\utils | Core, CBA, ACE | Wardrobe, circuits, faulty optics, documents, generic items, balancing, recovery, UAVs, ready room, weapon faults, terminals, power, solar |
FF_cinematic | x\FF\addons\cinematic | Core, CBA | Cameras, overlays, pulses, music playback and the music director |
FF_cbrn | x\FF\addons\cbrn | Core, CBA, ACE medical | Hazard simulation, filters, supplies, detector |
FF_zeus_suite | x\FF\addons\zeus_suite | Core, Utils, CBA | Footer, FPS, look orders, volunteer service, feature dialogs |
FF_spectator | x\FF\addons\spectator | Core, Cinematic, CBA | Spectator presets, command broker, camera driver, UI rendering, radio integration |
FF_horror | x\FF\addons\horror | All of the above | Soul, skulls, hordes, atmosphere, scares, themed content, alias entry points |
The dependency direction is one-way: feature components never depend on Horror. Horror depends on them and keeps the same entry points under its own prefix. That is what allows Utils, CBRN, Cinematic or Zeus to be used without Horror installed.
2. Lifecycle
Config
Patches, required addons, editor categories, item classes, modules, respawn
template, faulty optic classes, system CfgFunctions.
PreInit
PREP() compiles every function into a global. CBA events, settings
and the Zeus footer registry are installed. No gameplay starts here.
PostInit
Server loops (spawn scheduler, AI balancing, footer server state) and client bootstrap (wardrobe handlers, shield actions, FPS reporter).
Atmosphere, persistence and scare are not started by postInit. A mission executes their entry scripts. That keeps a server that merely loads the PBOs free of loops it does not use.
3. Function registration
| Style | Used by | Result |
|---|---|---|
PREP(name) in XEH_preInit.sqf | All component functions | FF_<component>_fnc_name global, compiled once per machine |
CfgFunctions with file = | Horror systems (FFATM, FFPP, FFSC) | Same naming pattern, callable by remoteExec name |
| Alias functions | Horror | Horror-prefixed name that calls EFUNC(component,fn) |
Because everything is a compiled global, a mission can call any documented function directly. Remote execution needs the
function to be allowed in CfgRemoteExec; the Zeus-facing system functions already are.
4. Events
CBA events carry request/response traffic. Names are FF_<component>_<event>; Horror keeps
FF_horror_* names for its own systems.
// client requests a shield application
[QGVAR(soulShieldRequest), [_body, _actor]] call CBA_fnc_serverEvent;
// server answers the owner only
[QGVAR(soulShieldResult), [_ok, _message]] call CBA_fnc_ownerEvent;
Use global-JIP events for state a later player must receive (skull registration, active flights, soul-shield results). Use public mission variables for read-mostly shared configuration; never as a high-frequency tick channel.
5. Authority table
| Decision | Decided by | Published as |
|---|---|---|
| Shield consumed | Server | Owner event + corpse receipt |
| Circuit completed | Server | Broadcast object variable + animation |
| Arrival and horde scheduling | Server | JIP events and controller state |
| AI ownership | Server | Engine group ownership + reveal event |
| Atmosphere mood and track | Server | Shared state + client playback |
| Scare audience | Server | Controller logic + client binding |
| Reconnect snapshot | Server | Owner event with restore plan |
| Wardrobe policy | Server | Public mission variable + reset event |
| Faulty optic conversion | Unit owner | Local loadout rewrite |
| CBRN exposure | Each client | Local unit variables |
6. Stable names
Three names are part of the public contract and do not change:
FF_Horror_*item classes — mission scripts and loadouts reference them.FF_horror_fnc_*public functions — mission code calls them.- Object state keys such as
FF_horror_cbrnMinutesandFFPP_*— missions read and write them directly. They are a naming contract, not a dependency.
The name is the API and the implementation behind it is free to change: keep the entry point, change what it calls.
7. Failure philosophy
- Validate inputs, then fail closed: an invalid circuit stays closed, a bad config value falls back to the default.
- Every long-running sequence has a recovery path (corpse deleted, unit replaced, controller stopped, HC gone).
- Cleanup is idempotent: UI, cameras, handlers, particles and JIP events can be cleared twice.
- Cap the work: 32 controllers, 128 jobs, 2 AI moves per pass, 10 Hz gaze tests.