feat: Add ICOM usage guide and update related documentation

This commit is contained in:
Jacob Schmidt 2026-05-16 17:05:13 -05:00
parent 264559306d
commit 3cadcce32a
13 changed files with 428 additions and 13 deletions

View File

@ -40,4 +40,5 @@ For install links and Forge-specific setup steps, see
- [API Reference](./api-reference.md)
- [Usage Examples](./usage-examples.md)
- [ICOM Usage Guide](../../../docs/ICOM_USAGE_GUIDE.md)
- [Framework Module Guides](../../../docs/README.md)

View File

@ -27,6 +27,7 @@ Game systems should call the domain APIs instead of raw database operations:
- `store:*`
- `task:*`
- `cad:*`
- `icom:*`
- `owned:garage:*`
- `owned:locker:*`
- `transport:*`
@ -47,3 +48,4 @@ needed by `forge_server_addons_extension_fnc_extCall`.
- [Phone](../../../docs/PHONE_USAGE_GUIDE.md)
- [Store](../../../docs/STORE_USAGE_GUIDE.md)
- [Task](../../../docs/TASK_USAGE_GUIDE.md)
- [ICOM](../../../docs/ICOM_USAGE_GUIDE.md)

View File

@ -212,7 +212,7 @@ client.listen_for_events(|msg| {
The Forge server extension includes full ICOM integration:
1. **Initialization**: Connects to ICOM on extension startup (or manually via `icom:connect`)
1. **Initialization**: Connect with `icom:connect` after the ICOM hub is running.
2. **Event Listener**: Spawns background task to receive events continuously
3. **Callback System**: Forwards events to Arma via CBA event handlers
4. **Extension Commands**: Provides SQF commands to send/receive events
@ -221,7 +221,7 @@ The Forge server extension includes full ICOM integration:
- The extension uses `try_read()` to avoid deadlocks when accessing context from async tasks
- Broadcast events are **not** sent back to the originating server
- Connection can be initiated manually if automatic startup connection fails
- Connection is initiated through the `icom:connect` extension command.
### SQF Usage

195
docs/ICOM_USAGE_GUIDE.md Normal file
View File

@ -0,0 +1,195 @@
# ICOM Usage Guide
ICOM is the Forge inter-server communication helper. It lets multiple Arma 3
servers exchange generic JSON events through a central TCP hub instead of
connecting directly to each other.
## Runtime Shape
```text
Arma server SQF
-> forge_server extension icom:* command
-> ICOM client inside the extension
-> forge-icom TCP hub
-> target server extension
-> forge_icom_event CBA server event
```
The ICOM hub lives in `bin/icom`. The Arma server extension integrates with it
through `arma/server/extension/src/icom.rs`.
## Components
| Component | Path | Role |
| --- | --- | --- |
| ICOM hub binary | `bin/icom` | Standalone TCP router for connected servers. |
| ICOM client library | `bin/icom/src/client.rs` | Rust client used by the Forge server extension and examples. |
| Extension command group | `arma/server/extension/src/icom.rs` | Exposes `icom:*` commands to SQF and forwards inbound events to Arma. |
| SQF callback bridge | `arma/server/addons/main/XEH_preInit.sqf` | Receives extension callbacks and re-emits `forge_icom_event` through CBA. |
## Build and Run the Hub
Build the release binary:
```powershell
cargo build --release -p forge-icom
```
Run it during development:
```powershell
cargo run -p forge-icom
```
The default bind address is `0.0.0.0:9090`.
## Hub Configuration
Copy `bin/icom/config.example.toml` to `config.toml` beside the `forge-icom`
executable or into the working directory used to launch it.
```toml
[server]
host = "0.0.0.0"
port = 9090
```
Use `127.0.0.1` for same-machine testing. Use `0.0.0.0` when remote Arma
servers need to connect, and secure the port at the firewall or host network
layer.
## Extension Commands
ICOM commands are exposed through the `icom` command group in `forge_server`.
| Command | Arguments | Returns |
| --- | --- | --- |
| `icom:connect` | `address`, `server_id` | `Connection initiated` or `ERROR: Already connected`. |
| `icom:send_event` | `target_server`, `event_name`, `data_json` | `OK` or `ERROR: <reason>`. |
| `icom:broadcast` | `event_name`, `data_json` | `OK` or `ERROR: <reason>`. |
The current extension connects when `icom:connect` is called. Start the ICOM hub
first, then connect each Arma server with a unique `server_id`.
```sqf
private _result = "forge_server" callExtension [
"icom:connect",
["127.0.0.1:9090", "server_1"]
];
diag_log format ["[ICOM] Connect result: %1", _result select 0];
```
## Send an Event
Send a targeted event to one connected server:
```sqf
private _data = createHashMapFromArray [
["coords", [1234, 5678, 0]],
["supplies", ["ammo_box", "medical_supplies"]]
];
"forge_server" callExtension [
"icom:send_event",
["server_2", "supply_drop", toJSON _data]
];
```
Broadcast to every connected server except the sender:
```sqf
private _alert = createHashMapFromArray [
["message", "Server restart in 5 minutes"],
["severity", "warning"]
];
"forge_server" callExtension [
"icom:broadcast",
["global_alert", toJSON _alert]
];
```
## Receive Events
Inbound ICOM events are forwarded to SQF as the CBA server event
`forge_icom_event`.
```sqf
["forge_icom_event", {
params ["_eventName", "_data"];
switch (_eventName) do {
case "supply_drop": {
private _coords = _data getOrDefault ["coords", []];
private _supplies = _data getOrDefault ["supplies", []];
diag_log format ["[ICOM] Supply drop at %1: %2", _coords, _supplies];
};
case "global_alert": {
private _message = _data getOrDefault ["message", ""];
if (_message isNotEqualTo "") then {
[_message] remoteExec ["hint", 0];
};
};
default {
diag_log format ["[ICOM] Unhandled event: %1 | %2", _eventName, _data];
};
};
}] call CBA_fnc_addEventHandler;
```
## Message Protocol
The hub uses newline-delimited JSON. The first message from each client is a
registration payload:
```json
{
"type": "register",
"server_id": "server_1"
}
```
Targeted events use `type: "event"`:
```json
{
"type": "event",
"target_server": "server_2",
"event_name": "supply_drop",
"data": {
"coords": [1234, 5678, 0]
}
}
```
Broadcasts use `type: "broadcast"` and are routed to all connected servers
except the sender.
## Operational Notes
- Server IDs must be unique. If the same ID reconnects, the hub replaces the old
connection.
- Event names are mission/application contracts. ICOM only routes them; it does
not validate gameplay meaning.
- Always send valid JSON in the `data_json` argument.
- `icom:send_event` and `icom:broadcast` return quickly after scheduling async
work in the extension. Check extension and ICOM hub logs for delivery errors.
- Keep event payloads small and stable. Use IDs or compact data where possible.
## Testing
Start the hub:
```powershell
cargo run -p forge-icom
```
Run example clients in separate terminals:
```powershell
cargo run -p forge-icom --example server_1_client
cargo run -p forge-icom --example server_2_client
```
For Arma testing, start the hub, connect the server with `icom:connect`, register
a `forge_icom_event` handler, then send an event from another connected server.

View File

@ -203,7 +203,7 @@ See [Owned Storage Usage Guide](./OWNED_STORAGE_USAGE_GUIDE.md) for examples.
| Command Group | Purpose |
| --- | --- |
| `store:checkout` | Run store checkout behavior. |
| `icom:connect`, `icom:broadcast`, `icom:send_event` | ICom connection and event forwarding. |
| `icom:connect`, `icom:broadcast`, `icom:send_event` | ICOM connection and event forwarding. See [ICOM Usage Guide](./ICOM_USAGE_GUIDE.md). |
| `terrain:exportSVG` | Export terrain data as SVG. |
| `transport:invoke`, `transport:invoke_stored` | Invoke commands through transport. |
| `transport:request:append`, `transport:request:clear` | Manage stored request chunks. |

View File

@ -23,6 +23,7 @@ collects framework-level documentation for those pieces.
- [CAD Usage Guide](./CAD_USAGE_GUIDE.md)
- [Economy Usage Guide](./ECONOMY_USAGE_GUIDE.md)
- [Garage Usage Guide](./GARAGE_USAGE_GUIDE.md)
- [ICOM Usage Guide](./ICOM_USAGE_GUIDE.md)
- [Locker Usage Guide](./LOCKER_USAGE_GUIDE.md)
- [Organization Usage Guide](./ORG_USAGE_GUIDE.md)
- [Owned Storage Usage Guide](./OWNED_STORAGE_USAGE_GUIDE.md)

View File

@ -204,7 +204,7 @@ See [Owned Storage Usage Guide](/server-modules/owned-storage) for examples.
| Command Group | Purpose |
| --- | --- |
| `store:checkout` | Run store checkout behavior. |
| `icom:connect`, `icom:broadcast`, `icom:send_event` | ICom connection and event forwarding. |
| `icom:connect`, `icom:broadcast`, `icom:send_event` | ICOM connection and event forwarding. See [ICOM Usage Guide](/server-extension/icom). |
| `terrain:exportSVG` | Export terrain data as SVG. |
| `transport:invoke`, `transport:invoke_stored` | Invoke commands through transport. |
| `transport:request:append`, `transport:request:clear` | Manage stored request chunks. |

View File

@ -39,4 +39,5 @@ For install links and Forge-specific setup steps, see
- [API Reference](/server-extension/api-reference)
- [Usage Examples](/server-extension/usage-examples)
- [ICOM Usage Guide](/server-extension/icom)
- [Framework Module Guides](/getting-started)

View File

@ -26,6 +26,7 @@ Game systems should call the domain APIs instead of raw database operations:
- `store:*`
- `task:*`
- `cad:*`
- `icom:*`
- `owned:garage:*`
- `owned:locker:*`
- `transport:*`
@ -46,3 +47,4 @@ needed by `forge_server_addons_extension_fnc_extCall`.
- [Phone](/server-modules/phone)
- [Store](/server-modules/store)
- [Task](/server-modules/task)
- [ICOM](/server-extension/icom)

View File

@ -0,0 +1,194 @@
---
title: "ICOM Usage Guide"
description: "ICOM is the Forge inter-server communication helper. It lets multiple Arma 3 servers exchange generic JSON events through a central TCP hub instead of connecting directly to each other."
---
## Runtime Shape
```text
Arma server SQF
-> forge_server extension icom:* command
-> ICOM client inside the extension
-> forge-icom TCP hub
-> target server extension
-> forge_icom_event CBA server event
```
The ICOM hub lives in `bin/icom`. The Arma server extension integrates with it
through `arma/server/extension/src/icom.rs`.
## Components
| Component | Path | Role |
| --- | --- | --- |
| ICOM hub binary | `bin/icom` | Standalone TCP router for connected servers. |
| ICOM client library | `bin/icom/src/client.rs` | Rust client used by the Forge server extension and examples. |
| Extension command group | `arma/server/extension/src/icom.rs` | Exposes `icom:*` commands to SQF and forwards inbound events to Arma. |
| SQF callback bridge | `arma/server/addons/main/XEH_preInit.sqf` | Receives extension callbacks and re-emits `forge_icom_event` through CBA. |
## Build and Run the Hub
Build the release binary:
```powershell
cargo build --release -p forge-icom
```
Run it during development:
```powershell
cargo run -p forge-icom
```
The default bind address is `0.0.0.0:9090`.
## Hub Configuration
Copy `bin/icom/config.example.toml` to `config.toml` beside the `forge-icom`
executable or into the working directory used to launch it.
```toml
[server]
host = "0.0.0.0"
port = 9090
```
Use `127.0.0.1` for same-machine testing. Use `0.0.0.0` when remote Arma
servers need to connect, and secure the port at the firewall or host network
layer.
## Extension Commands
ICOM commands are exposed through the `icom` command group in `forge_server`.
| Command | Arguments | Returns |
| --- | --- | --- |
| `icom:connect` | `address`, `server_id` | `Connection initiated` or `ERROR: Already connected`. |
| `icom:send_event` | `target_server`, `event_name`, `data_json` | `OK` or `ERROR: <reason>`. |
| `icom:broadcast` | `event_name`, `data_json` | `OK` or `ERROR: <reason>`. |
The current extension connects when `icom:connect` is called. Start the ICOM hub
first, then connect each Arma server with a unique `server_id`.
```sqf
private _result = "forge_server" callExtension [
"icom:connect",
["127.0.0.1:9090", "server_1"]
];
diag_log format ["[ICOM] Connect result: %1", _result select 0];
```
## Send an Event
Send a targeted event to one connected server:
```sqf
private _data = createHashMapFromArray [
["coords", [1234, 5678, 0]],
["supplies", ["ammo_box", "medical_supplies"]]
];
"forge_server" callExtension [
"icom:send_event",
["server_2", "supply_drop", toJSON _data]
];
```
Broadcast to every connected server except the sender:
```sqf
private _alert = createHashMapFromArray [
["message", "Server restart in 5 minutes"],
["severity", "warning"]
];
"forge_server" callExtension [
"icom:broadcast",
["global_alert", toJSON _alert]
];
```
## Receive Events
Inbound ICOM events are forwarded to SQF as the CBA server event
`forge_icom_event`.
```sqf
["forge_icom_event", {
params ["_eventName", "_data"];
switch (_eventName) do {
case "supply_drop": {
private _coords = _data getOrDefault ["coords", []];
private _supplies = _data getOrDefault ["supplies", []];
diag_log format ["[ICOM] Supply drop at %1: %2", _coords, _supplies];
};
case "global_alert": {
private _message = _data getOrDefault ["message", ""];
if (_message isNotEqualTo "") then {
[_message] remoteExec ["hint", 0];
};
};
default {
diag_log format ["[ICOM] Unhandled event: %1 | %2", _eventName, _data];
};
};
}] call CBA_fnc_addEventHandler;
```
## Message Protocol
The hub uses newline-delimited JSON. The first message from each client is a
registration payload:
```json
{
"type": "register",
"server_id": "server_1"
}
```
Targeted events use `type: "event"`:
```json
{
"type": "event",
"target_server": "server_2",
"event_name": "supply_drop",
"data": {
"coords": [1234, 5678, 0]
}
}
```
Broadcasts use `type: "broadcast"` and are routed to all connected servers
except the sender.
## Operational Notes
- Server IDs must be unique. If the same ID reconnects, the hub replaces the old
connection.
- Event names are mission/application contracts. ICOM only routes them; it does
not validate gameplay meaning.
- Always send valid JSON in the `data_json` argument.
- `icom:send_event` and `icom:broadcast` return quickly after scheduling async
work in the extension. Check extension and ICOM hub logs for delivery errors.
- Keep event payloads small and stable. Use IDs or compact data where possible.
## Testing
Start the hub:
```powershell
cargo run -p forge-icom
```
Run example clients in separate terminals:
```powershell
cargo run -p forge-icom --example server_1_client
cargo run -p forge-icom --example server_2_client
```
For Arma testing, start the hub, connect the server with `icom:connect`, register
a `forge_icom_event` handler, then send an event from another connected server.

View File

@ -146,6 +146,18 @@ Documentation Areas
Extension architecture, command surface, and SQF usage examples.
:::
:::u-page-feature
---
icon: i-lucide-network
to: /server-extension/icom
---
#title
ICOM [Events]{.text-primary}
#description
Inter-server event routing through the Forge ICOM hub and extension commands.
:::
:::u-page-feature
---
icon: i-lucide-layers-3

View File

@ -118,15 +118,6 @@ private _playerJoinData = createHashMapFromArray [
"forge_server" callExtension ["icom:broadcast", ["player_join", (toJSON _playerJoinData)]];
// ============================================================================
// STEP 3: Test the connection
// ============================================================================
// Test if ICOM is working
"forge_server" callExtension ["icom:test_callback", []];
// Should trigger forge_icom_event with a handshake event
// ============================================================================
// TIPS AND BEST PRACTICES
// ============================================================================

View File

@ -39,6 +39,10 @@ const generatedPages = [
source: 'arma/server/addons/common/README.md',
target: '2.server-extension/3.common.md'
},
{
source: 'docs/ICOM_USAGE_GUIDE.md',
target: '2.server-extension/4.icom.md'
},
{
source: 'docs/ACTOR_USAGE_GUIDE.md',
target: '3.server-modules/1.actor.md'
@ -293,6 +297,18 @@ Documentation Areas
Extension architecture, command surface, and SQF usage examples.
:::
:::u-page-feature
---
icon: i-lucide-network
to: /server-extension/icom
---
#title
ICOM [Events]{.text-primary}
#description
Inter-server event routing through the Forge ICOM hub and extension commands.
:::
:::u-page-feature
---
icon: i-lucide-layers-3