# Forge Server Common

## Overview
The common addon provides shared SQF utilities used by server-side Forge
addons. It contains lightweight helpers only; gameplay domain state belongs in
the specific domain addons or the Rust extension.

## Dependencies
- `forge_server_main`

## Main Components
- `fnc_baseStore.sqf` provides shared hash-map object behavior such as JSON
  conversion.
- `fnc_eventBus.sqf` provides a framework-wide in-process event bus for
  cross-addon notifications.
- `fnc_log.sqf` standardizes server log messages.
- `fnc_getPlayer.sqf` resolves online players by UID.
- `fnc_formatNumber.sqf` formats numeric values for notifications and UI text.
- `fnc_generateHash.sqf` and `fnc_generateSecureData.sqf` provide hashing and
  random data helpers.
- `fnc_timeToSeconds.sqf` converts time values into seconds.

## Notes
Keep this addon free of domain-specific behavior. If a helper needs actor,
bank, org, task, store, or CAD state, it belongs in that addon instead.

## Event Bus
The event bus is initialized as `forge_server_common_EventBus` during store
bootstrap. It is synchronous and in-process: listeners run immediately when an
event is emitted.

### Event Naming
Use lower-case dot-separated names:

- `<domain>.<entity>.<action>` for domain events, such as `cad.assignment.assigned`
- `<domain>.<action>` for simple lifecycle events, such as `task.started`

Prefer past-tense action names for events that report completed state changes:
`created`, `started`, `assigned`, `acknowledged`, `declined`, `completed`,
`failed`, `cleared`, `updated`, `closed`.

Payloads should be hash maps and should include stable identifiers first:
`taskID`, `requestID`, `groupID`, `uid`, `orgID`, or `accountID` as appropriate.
The event bus adds `event`, `source`, and `timestamp` when the event is emitted.

### Current Events
Task lifecycle:
- `task.created`
- `task.started`
- `task.completed`
- `task.failed`
- `task.cleared`

Task rewards and notifications:
- `task.reward.requested`
- `task.reward.applied`
- `task.reward.failed`
- `task.rating.applied`
- `task.rating.failed`
- `task.notification.requested`
- `task.reward.notification.requested`

CAD state:
- `cad.assignment.assigned`
- `cad.assignment.created`
- `cad.assignment.acknowledged`
- `cad.assignment.declined`
- `cad.assignment.closed`
- `cad.request.submitted`
- `cad.request.closed`
- `cad.group.updated`

Client sync and notification requests:
- `notification.requested`
- `bank.account.sync.requested`
- `org.sync.requested`
- `locker.sync.requested`
- `locker.va.sync.requested`
- `garage.vgarage.sync.requested`

### Example

Register a listener, emit an event, then remove the listener when it is no longer needed:

```sqf
private _token = EGVAR(common,EventBus) call ["on", [
    "task.completed",
    {
        params ["_event"];
        ["INFO", format ["Task completed: %1", _event getOrDefault ["taskID", ""]]] call EFUNC(common,log);
    },
    "example"
]];

EGVAR(common,EventBus) call ["emit", [
    "task.completed",
    createHashMapFromArray [["taskID", "task_001"]],
    createHashMapFromArray [["source", "task"]]
]];

EGVAR(common,EventBus) call ["off", [_token]];
```
