Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
292 lines
20 KiB
Markdown
292 lines
20 KiB
Markdown
# Reforger 1.8: native AI delegation feasibility
|
|
|
|
Investigation and paired runtime experiment, 7 October 2026.
|
|
|
|
Follow-up: [worker-local AI and native-query workaround experiments](ai-delegation-workarounds-1.8.md).
|
|
|
|
|
|
**The tested ownership-transfer route does not offload native AI.** A real dedicated
|
|
server and a separate hidden game client completed the five-phase experiment.
|
|
Giving both the soldier and its group to the worker changed ownership, but the
|
|
server kept running soldier decisions, group decisions and native perception.
|
|
The worker did not run those updates, even after explicit activation.
|
|
|
|
An RPC worker can run custom script calculations. That is a different architecture
|
|
from distributing Enfusion's native AI simulation, and this experiment does not
|
|
establish meaningful CPU savings for Escape. There is no demonstrated public-API
|
|
route to an Arma 3-style headless AI worker in the inspected 1.8 interfaces.
|
|
|
|
## Evidence and version scope
|
|
|
|
- Official script source: tag `v1.8.0.10`, commit
|
|
[`b46bdd8f4932f3a256c765f93a44417996a6da73`](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/tree/b46bdd8f4932f3a256c765f93a44417996a6da73).
|
|
- Both measured runtimes identify themselves as **1.8.0.13**, built
|
|
`2026-08-21 14:30:18 UTC`. Thus source inspection and runtime experiment cover
|
|
different patch releases of 1.8; the compiled probe confirms the interfaces it
|
|
uses in .13, not complete source/binary identity with .10.
|
|
- [Standalone addon and reproduction instructions](../tests/native/ai_delegation/README.md).
|
|
- [Server log](evidence/ai-delegation-1.8-2026-10-07/server-console.log.txt),
|
|
[worker log](evidence/ai-delegation-1.8-2026-10-07/client-console.log.txt),
|
|
[counter summary](evidence/ai-delegation-1.8-2026-10-07/summary.json),
|
|
[runtime hashes](evidence/ai-delegation-1.8-2026-10-07/runtime-sha256.json).
|
|
- [Exact executed probe](evidence/ai-delegation-1.8-2026-10-07/executed-probe.c.txt)
|
|
and [executed runner](evidence/ai-delegation-1.8-2026-10-07/executed-runner.py.txt).
|
|
|
|
The test used vanilla Game Master Everon, one ordinary US soldier, one group,
|
|
forced LOD 0, a 30 FPS cap and no Escape code. Dedicated and worker were separate
|
|
processes on the same physical Linux host, with a hidden Proton client and private
|
|
profiles. A loopback bridge connected the worker to an isolated dedicated network
|
|
namespace. This establishes execution locality, **not multi-machine speedup**.
|
|
No production server or mission configuration was modified.
|
|
|
|
The initial loose-addon run did not index/load the script. Workbench indexing fixed
|
|
that. An initial paired run streamed the group but not the soldier; explicit
|
|
observer/streaming setup fixed that. Neither preliminary attempt is treated as a
|
|
negative delegation result. The final run acknowledged both entities before its
|
|
baseline interval and ended with `AID PROBE COMPLETE`; owned-process cleanup passed.
|
|
The full logs also contain vanilla asset-loading warnings/errors and two resupply
|
|
station script errors during shutdown, after `AID PROBE COMPLETE`. This was not an
|
|
error-free engine session; no script error occurred during the measured phases.
|
|
|
|
## 1. What happens when ownership is transferred?
|
|
|
|
Measured stable flags after `GiveExt(workerIdentity, true)` on both hierarchies:
|
|
|
|
| Flag | Dedicated | Worker |
|
|
|---|---:|---:|
|
|
| `Role()` | Authority (`0`) | Proxy (`1`) |
|
|
| `IsOwner()` | false | true |
|
|
| `IsMaster()` | false | false |
|
|
| `IsOwnerProxy()` | false | true |
|
|
| `IsRemoteProxy()` | false | false |
|
|
|
|
Before transfer, the server was owner/master and the worker was a remote proxy.
|
|
Returning ownership restored those flags. Body and group were transferred in
|
|
separate phases; transferring the body alone did not transfer the separate group.
|
|
|
|
`IsMaster()` means **owner AND authority**, not merely authority. Its becoming false
|
|
on the server does not demonstrate a migrated simulation. These meanings match
|
|
[the pinned BaseRplComponent interface](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/GameLib/generated/Components/BaseRplComponent.c).
|
|
[`GiveExt`](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/Components/RplComponent.c)
|
|
also supports ownership-change notifications/custom data; it is not documented as
|
|
an AI-state or authority migration function.
|
|
|
|
## 2. Does any AI computation migrate with ownership?
|
|
|
|
**None of the instrumented AI computations migrated in this experiment.**
|
|
The following are actual counter increases in trimmed steady intervals, not CPU
|
|
milliseconds. Soldier BT refers to `SCR_AIDecideBehavior.EOnTaskSimulate`; group BT
|
|
to `SCR_AIDecideActivity.EOnTaskSimulate`. Soldier utility evaluation matched its
|
|
BT counter. All overrides call the stock implementation once.
|
|
|
|
| Phase | Server interval | Server perception updates | Server soldier BT calls | Server group BT calls | Worker corresponding increases |
|
|
|---|---:|---:|---:|---:|---:|
|
|
| Body owned by worker | 15.100 s | 453 | 25 | 40 | all 0 |
|
|
| Body and group owned by worker | 15.033 s | 451 | 25 | 39 | all 0 |
|
|
| Explicit worker activation | 15.033 s | 451 | 25 | 40 | all 0 |
|
|
| Ownership returned to server | 15.067 s | 452 | 25 | 40 | all 0 |
|
|
|
|
The worker-side windows are approximately the same duration, independently sampled.
|
|
The summary trims the first and last two readings to avoid phase-label RPC and
|
|
ownership notifications arriving on different frames. The server baseline also
|
|
had positive counters. Worker RPC calculations returned `5050` throughout, proving
|
|
that the worker's scripts were executing while its AI counters remained zero.
|
|
|
|
This does not measure every native subsystem. In particular, it does not establish
|
|
whether character prediction or movement networking changes cost with ownership.
|
|
It establishes that ownership did not move the tested decision/perception work.
|
|
|
|
## 3. Can clients execute behavior trees or AILib simulation?
|
|
|
|
For this replicated server-created AI, normal transfer and explicit activation did
|
|
not start the observed soldier/group BT callbacks on the client. The client had an
|
|
`AIControlComponent` but `GetControlAIAgent()` remained null. Its group object existed,
|
|
but its decision callback count stayed zero.
|
|
|
|
This is not proof that a Reforger process running as a client is intrinsically
|
|
incapable of any AI: local/offline entities or a deliberately constructed local AI
|
|
world are different experiments. Creating a parallel local simulation would still
|
|
need world synchronization and an authoritative command/result bridge; it would
|
|
not automatically remove server-native costs.
|
|
|
|
## 4. What does AI “Load balancing” balance?
|
|
|
|
The public 1.8 script tree does not expose the implementation of that diagnostic
|
|
switch, a worker registry, remote AI scheduling queues or a destination identity.
|
|
**Its exact algorithm remains unverified.** Interpreting the menu title as network
|
|
load balancing is unsupported.
|
|
|
|
Evidence points toward local AI scheduling: native diagnostics contain active/LOD
|
|
populations, postponed AI simulation and aggregate AI simulation time. Separately,
|
|
the documented `-AIPartialSim` setting batches AI processing (default four batches).
|
|
Neither the diagnostic switch's exact connection to that flag nor its thread/frame
|
|
scheduling algorithm has been established. Local batching, multithreading and
|
|
cross-machine delegation are distinct mechanisms.
|
|
[Official diagnostic menu](https://community.bistudio.com/wiki/Arma_Reforger:Diag_Menu),
|
|
[official startup parameters](https://community.bistudio.com/wiki/Arma_Reforger:Startup_Parameters).
|
|
|
|
## 5. What does `IsAIActivated` control?
|
|
|
|
It is a **query**, not a command to select an execution machine.
|
|
`ActivateAI`/`DeactivateAI` control native activation state. `AIWorld` exposes active
|
|
population limits and admission checks; agents expose LOD controls, and the pinned
|
|
comment states that maximum LOD disables agents by default.
|
|
[AIControlComponent](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIControlComponent.c),
|
|
[AIAgent](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIAgent.c),
|
|
[AIWorld](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIWorld.c).
|
|
|
|
Crucially, the worker reported `controlActive=1` even with no local control agent
|
|
and no perception updates. Calling `ActivateAI()` returned **true**, but did not
|
|
change those observations. An activation flag or successful return alone therefore
|
|
does not prove simulation execution on that machine.
|
|
|
|
## 6. Which expensive systems are script versus native?
|
|
|
|
“Native” below describes the public call boundary, not a measured cost share.
|
|
|
|
| Subsystem | Inspectable/script portion | Native boundary / missing capability |
|
|
|---|---|---|
|
|
| Behavior trees | Scripted task callbacks, soldier utility scoring, group activities | BT scheduling/execution internals; no public migrate/serialize/resume contract |
|
|
| Navigation/pathfinding | Destination/waypoint choice, high-level route planning | Navmesh queries, path generation/following and movement internals |
|
|
| Perception | Script interpretation/reaction to targets | Perception system, target acquisition/query execution; local simulation counter |
|
|
| Physics | Script requests and collision callbacks | Physics world/integration/queries |
|
|
| Animation | Script commands and state selection | Animation graph evaluation and pose processing |
|
|
| Character simulation | Script behaviors/input decisions | Controller, movement, collision and animation integration |
|
|
| Replication | RPC handlers and authored replicated fields | Transport, relevancy, hierarchy/role handling and replication scheduling |
|
|
| AI group logic | `SCR_AIGroup`, utility activities and formation/waypoint choices | Native group/agent membership, activation, scheduling and movement support |
|
|
| Script execution | Escape VirtualHQ and stock Enforce algorithms | VM execution/native calls; engine jobs invoked by scripts may run elsewhere in time |
|
|
| Entity updates | Authored callbacks | Engine component/system update scheduling |
|
|
|
|
The key exposed boundary is [`AITaskScripted.EOnTaskSimulate`](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AITaskScripted.c):
|
|
the engine calls authored decision code. Activation methods, movement and perception
|
|
queries cross `proto external` into the engine. The generated
|
|
[`PerceptionComponent`](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/Components/PerceptionComponent.c)
|
|
provides counters/target access but no remote executor or complete state-transfer API.
|
|
[`AIBehaviorTreeComponentBase`](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIBehaviorTreeComponentBase.c)
|
|
is empty at the script interface; its derived component exposes a breakpoint setter.
|
|
|
|
## 7. Can native AI simulation authority be migrated?
|
|
|
|
**No supported migration mechanism was found, and the tested mechanism did not
|
|
migrate it.** `RplNode` exposes a role query, not a public setter that moves an
|
|
existing authoritative hierarchy to another process. Creating another local
|
|
entity with authority is not transferring this entity's server authority.
|
|
[The pinned RplNode interface](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Core/generated/Replication/RplNode.c).
|
|
|
|
The engine can, in principle, retain server authority while delegating computation,
|
|
but that requires an explicit compute/state/result protocol. Replication ownership
|
|
alone did not supply that protocol here. Dormancy, despawning and activation limits
|
|
reduce or suspend local work; they do not demonstrate execution elsewhere.
|
|
`AIGroup.GetServerAgentsCount()` mentioning remotely controlled agents is likewise
|
|
not a promise of delegated AI simulation. Our replicated group existed on the
|
|
worker without its server soldier's control agent or active decision callbacks.
|
|
|
|
## 8. Where is the best interception point for a native experiment?
|
|
|
|
There are two distinct candidates:
|
|
|
|
- **Supported script boundary:** snapshot-based custom planning immediately before
|
|
mission/group decision selection. Compute over plain values on the worker and
|
|
apply validated commands on authority. Do not serialize engine pointers,
|
|
`AIAgent` objects or behavior instances and expect them to remain valid remotely.
|
|
- **Native research candidate:** an asynchronous path-query submission/completion
|
|
boundary, if profiling shows pathfinding is a major cost and binary investigation
|
|
locates a separable job contract. Static navmesh data is more tractable to mirror
|
|
than a complete physics/perception/animation world. The public movement interface
|
|
exposes `GetCurrentPath()` and `OnPathSet()` but **not** an API for replacing the
|
|
native solver with externally supplied complete path jobs/results.
|
|
[AIBaseMovementComponent](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIBaseMovementComponent.c),
|
|
[AIPathfindingComponent](https://github.com/BohemiaInteractive/Arma-Reforger-Script-Diff/blob/b46bdd8f4932f3a256c765f93a44417996a6da73/scripts/Game/generated/AI/AIPathfindingComponent.c).
|
|
|
|
The exact **script/native interface boundary** is identified. An exact **binary
|
|
hook address/symbol, replaceable job ABI or safe scheduler interception site** has
|
|
not been identified. Claiming a ready-to-implement native hook would exceed the
|
|
evidence. A whole-AI scheduler hook would also need BT stacks, agent state, sensory
|
|
memory, pending jobs, world updates and command application—not just different
|
|
ownership flags. Perception queries depend on changing world geometry and targets;
|
|
copying that state may consume much of the intended saving.
|
|
|
|
Any job experiment needs immutable inputs, entity generation IDs, a world/navmesh
|
|
revision, deadlines, cancellation, result validation, bounded queues and local
|
|
fallback. Late results must not overwrite newer decisions. Keep authoritative
|
|
character/physics state and final acceptance on the dedicated server.
|
|
|
|
For mod-level Reforger clients, use Enfusion RPC with a dedicated replicated worker
|
|
controller/mailbox. Ownership of the combat soldier is unnecessary for custom jobs;
|
|
the successful PlayerController RPC in the probe already demonstrates that.
|
|
For native extensions/external processes, persistent TCP/UDP is a separate native
|
|
integration task; local shared memory plus synchronization is another option. No
|
|
arbitrary runtime socket/shared-memory transport API was found in the inspected
|
|
script surface. Workbench's `NetApiHandler` is tooling, not evidence of a supported
|
|
dedicated-game native plugin/IPC interface. HTTP belongs only to infrequent,
|
|
latency-tolerant high-level jobs, never per-frame simulation.
|
|
|
|
## 9. What fraction of CPU load can realistically be offloaded?
|
|
|
|
**Not measured; no defensible percentage is available.** This one-soldier experiment
|
|
measures where callbacks run, not their duration or the cost of a large combat scene.
|
|
Zero migrated perception/BT calls does not mean a measured 0% change in all process
|
|
CPU, since other work could change with ownership.
|
|
|
|
The profiler review found:
|
|
|
|
- `System.GetProfileData()` exposes aggregate simulation/frame/render/GPU timing,
|
|
not exclusive AI, BT, nav, perception, physics or animation timings.
|
|
- `PerceptionComponent.GetSimulateCounter()` measures updates, not their cost.
|
|
- The pinned 1.8 Diag binary contains `AI simulation time ms`, postponed AI time
|
|
and per-LOD population display strings near `AILibrary global counts`. That is
|
|
a concrete acquisition lead, **not a captured native CPU breakdown**. The exact
|
|
aggregation/nesting semantics and availability on a dedicated capture remain
|
|
unverified. A joined client's overlay cannot stand in for server-side timing.
|
|
- Official tools document a script profiler and `-scriptExtProfiler`; the installed
|
|
Workbench's Tracy launcher references an executable absent from the installation.
|
|
No compatible complete native profiler capture was acquired. Arma 3's profiler
|
|
commands were deliberately not assumed to work in Reforger.
|
|
- Public DiagMenu functions can change numeric native menu IDs, but no AI-counter
|
|
ID/enumeration/export interface was found. Guessing an ID or a saved-state format
|
|
would not be a valid measurement.
|
|
|
|
The [profiling acquisition notes](evidence/ai-delegation-1.8-2026-10-07/profiling-findings.txt)
|
|
and [binary-string evidence](evidence/ai-delegation-1.8-2026-10-07/diag-binary-string-evidence.txt)
|
|
record those limits and the exact inspected sources. See also the
|
|
[official script profiling documentation](https://community.bistudio.com/wiki/Arma_Reforger:Script_Profiling).
|
|
|
|
The existing [Escape HQ measurements](hq-performance-measurements.md) can identify
|
|
expensive synchronous script scopes. They are wall-time measurements including
|
|
synchronous native calls, not exclusive thread CPU and not async engine-job costs.
|
|
Nested scopes must not be summed as independent work. They alone cannot establish
|
|
what percentage of total native AI simulation is removable.
|
|
|
|
Before building an offload architecture, capture a representative dedicated scene
|
|
with fixed AI count, activation/LOD distribution, player positions, terrain, movement
|
|
and combat. Acquire server-side native timings for BT, navigation, perception,
|
|
physics, animation/character, replication and remaining entity work, plus script
|
|
profiling. Preserve raw captures and distinguish nested and concurrent zones. Then
|
|
compare a matched variant that actually removes the chosen work from the server;
|
|
cap-limited FPS or changed behavior is not sufficient evidence of CPU relief.
|
|
|
|
If the removable fraction of bottleneck work is `f`, ideal speedup with infinitely
|
|
fast workers is bounded by `1/(1-f)` before communication, serialization and
|
|
validation overhead. Here `f` is unknown. Custom planning may be worthwhile only
|
|
if measurement shows it is a substantial part of the bottleneck. There is no basis
|
|
for assuming that moving VirtualHQ yields space for hundreds of additional AI.
|
|
|
|
## 10. Can multiple Reforger instances become headless AI workers?
|
|
|
|
| Architecture | 1.8 finding | What remains on authority |
|
|
|---|---|---|
|
|
| Custom script worker via RPC | Small worker computation/RPC demonstrated; useful planning offload not benchmarked | Native AI and final command application |
|
|
| Native AI worker through `GiveExt` | Tested route failed to migrate observed AI work | Soldier/group decisions and perception continued on server |
|
|
| Worker with separately reconstructed local AI world | Unimplemented research hypothesis; requires state synchronization and replacing server work | At least authoritative validation/character/physics unless much deeper integration |
|
|
| Native engine job offload | No validated hook/ABI or distributed scheduler found | Depends on a future measured, separable job boundary |
|
|
|
|
Two dedicated servers do not automatically join one shared authoritative world.
|
|
The demonstrated worker is a normal connected client running hidden for the test;
|
|
that is not a newly discovered supported headless-client mode.
|
|
|
|
**Recommendation:** do not ship `GiveExt`-based “AI offloading” or reassign Escape
|
|
combat units to workers. Keep the isolated probe for regression/investigation and
|
|
use native profiling as the next gate. Custom RPC planning is feasible as a separate
|
|
optimization if its measured cost justifies it; genuine horizontal native AI scaling
|
|
needs additional engine support or a substantial, still-unproven native integration.
|