forge/docs/ICOM_USAGE_GUIDE.md
2026-05-23 09:23:12 -05:00

196 lines
5.1 KiB
Markdown

# 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.