From 9d789440e04fd313005f781af658a1164aa965a7 Mon Sep 17 00:00:00 2001 From: Jacob Schmidt Date: Sat, 18 Apr 2026 11:55:19 -0500 Subject: [PATCH] Enhance documentation and functionality across various server addons - Updated README.md files for extension, garage, locker, main, organization, phone, store, and task addons to provide clearer overviews, dependencies, main components, and usage notes. - Improved task module documentation to clarify timer semantics and server task flows, ensuring accurate usage of time limits. - Adjusted default values for task time limits and IED timers to enforce positive countdown requirements. - Added new CAD addon for dispatch coordination, including its overview, dependencies, main components, and event handling. --- arma/server/addons/actor/README.md | 33 ++++++- arma/server/addons/bank/README.md | 40 ++++++++- arma/server/addons/cad/README.md | 38 ++++++++ arma/server/addons/common/README.md | 24 +++++- arma/server/addons/economy/README.md | 32 ++++++- arma/server/addons/extension/README.md | 30 ++++++- arma/server/addons/garage/README.md | 31 ++++++- arma/server/addons/locker/README.md | 31 ++++++- arma/server/addons/main/README.md | 30 ++++++- arma/server/addons/org/README.md | 37 +++++++- arma/server/addons/phone/README.md | 42 ++++++--- arma/server/addons/store/README.md | 41 ++++++--- arma/server/addons/task/CfgVehicles.hpp | 12 +-- arma/server/addons/task/README.md | 5 ++ .../addons/task/functions/fnc_attack.sqf | 10 +-- .../task/functions/fnc_attackModule.sqf | 2 +- .../task/functions/fnc_defuseModule.sqf | 4 +- .../addons/task/functions/fnc_delivery.sqf | 10 +-- .../task/functions/fnc_deliveryModule.sqf | 2 +- .../addons/task/functions/fnc_destroy.sqf | 10 +-- .../task/functions/fnc_destroyModule.sqf | 2 +- .../addons/task/functions/fnc_hostage.sqf | 10 +-- .../task/functions/fnc_hostageModule.sqf | 2 +- arma/server/addons/task/functions/fnc_hvt.sqf | 10 +-- .../addons/task/functions/fnc_hvtModule.sqf | 2 +- .../addons/task/functions/fnc_makeIED.sqf | 6 +- .../addons/task/functions/fnc_startTask.sqf | 25 ++---- docs/MODULE_REFERENCE.md | 2 +- docs/TASK_USAGE_GUIDE.md | 86 +++++++++++++++++++ 29 files changed, 507 insertions(+), 102 deletions(-) create mode 100644 arma/server/addons/cad/README.md diff --git a/arma/server/addons/actor/README.md b/arma/server/addons/actor/README.md index 004359b..3a69954 100644 --- a/arma/server/addons/actor/README.md +++ b/arma/server/addons/actor/README.md @@ -1,3 +1,32 @@ -# forge_server_actor +# Forge Server Actor -Description for this addon +## Overview +The actor addon is the server-side bridge for player identity and character +state. It keeps Arma-facing actor snapshots in SQF while durable and hot actor +state are owned by the Rust extension. + +Actor records include UID, name, loadout, position, direction, stance, rank, +life state, phone number, email, organization, and holster state. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for actor extension calls +- `forge_client_actor` for response RPCs + +## Main Components +- `fnc_initActorStore.sqf` initializes `ActorModel` and `ActorStore`. +- `ActorModel` provides defaults, player snapshot conversion, migration, and + validation. +- `ActorStore` wraps extension hot-state calls and exposes event-facing actor + operations. + +## Runtime Behavior +- Missing persistent actors can be created from live player snapshots. +- Hot actor reads are migrated and hydrated before use. +- `saveHotState` in the main addon snapshots and saves actor state on player + disconnect and mission end. + +## Event Surface +The addon handles server events for actor init, get, set, multi-set, save, and +remove requests, then replies to the requesting player through client actor RPCs. diff --git a/arma/server/addons/bank/README.md b/arma/server/addons/bank/README.md index ab01bfc..b1875b8 100644 --- a/arma/server/addons/bank/README.md +++ b/arma/server/addons/bank/README.md @@ -1,3 +1,39 @@ -# forge_server_bank +# Forge Server Bank -Description for this addon +## Overview +The bank addon owns the SQF bridge for player accounts, cash and bank balances, +PIN/session handling, transfers, checkout charging, earnings deposits, and +credit-line repayment. + +Account truth lives in the extension hot cache. SQF handles Arma-facing +validation, client messaging, session state, and payment integration with other +server addons. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for bank extension calls +- `forge_server_org` at runtime for credit-line repayment +- `forge_client_bank` and `forge_client_notifications` for response RPCs + +## Main Components +- `fnc_initBank.sqf` initializes all bank stores and helpers. +- `fnc_initModel.sqf` defines account defaults and migration behavior. +- `fnc_initPayloadBuilder.sqf` builds UI, checkout, and organization payment + context. +- `fnc_initSessionManager.sqf` manages PIN and authorization session state. +- `fnc_initMessenger.sqf` sends account syncs, alerts, and notifications. +- `fnc_initStore.sqf` wraps hot bank calls and account mutations. + +## Supported Operations +- initialize and hydrate player bank state +- deposit, withdraw, transfer, and deposit earnings +- validate PIN-backed sessions +- charge checkout previews and committed purchases +- repay organization credit lines with rollback on failure +- save hot bank state to durable storage + +## Runtime Notes +`forge_server_main_fnc_saveHotState` saves bank hot state on disconnect and +mission shutdown. Store checkout and task rewards use this addon for +authoritative player balance changes. diff --git a/arma/server/addons/cad/README.md b/arma/server/addons/cad/README.md new file mode 100644 index 0000000..3c17a90 --- /dev/null +++ b/arma/server/addons/cad/README.md @@ -0,0 +1,38 @@ +# Forge Server CAD + +## Overview +The CAD addon coordinates dispatch-facing operational state: groups, +assignments, dispatch orders, support requests, task assignment, permissions, +hydrate payloads, and recent activity. + +CAD state is extension-backed but intentionally transient. It is scoped to the +active server or mission lifecycle and starts fresh after restart. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_actor` +- `forge_server_org` +- `forge_server_task` +- `forge_server_extension` at runtime for CAD extension calls +- `forge_client_cad` and `forge_client_notifications` for response RPCs + +## Main Components +- `fnc_initCadStore.sqf` coordinates repositories and request handling. +- `fnc_initActivityRepository.sqf` records recent CAD activity. +- `fnc_initAssignmentRepository.sqf` manages task assignments and dispatch + orders. +- `fnc_initGroupRepository.sqf` manages group membership, role, and status. +- `fnc_initPermissionService.sqf` resolves dispatch permissions. +- `fnc_initPersistenceService.sqf` bridges SQF state to extension hot CAD + storage. +- `fnc_initRequestRepository.sqf` manages support requests. + +## Event Surface +The addon handles hydrate, task assignment, dispatch order, support request, +task acknowledge/decline, and group update events. Successful mutations can +invalidate CAD state globally so clients refresh their views. + +## Notes +CAD hydrate payloads include active task catalog entries from `TaskStore` and +organization context from `ActorStore`. diff --git a/arma/server/addons/common/README.md b/arma/server/addons/common/README.md index 54ae201..a097c6b 100644 --- a/arma/server/addons/common/README.md +++ b/arma/server/addons/common/README.md @@ -1,3 +1,23 @@ -# forge_server_common +# Forge Server Common -Common functionality shared between addons. +## 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_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. diff --git a/arma/server/addons/economy/README.md b/arma/server/addons/economy/README.md index 2522c25..51adab8 100644 --- a/arma/server/addons/economy/README.md +++ b/arma/server/addons/economy/README.md @@ -1,3 +1,31 @@ -# forge_server_economy +# Forge Server Economy -Description for this addon +## Overview +The economy addon contains server-side systems for world economic interactions +that are still implemented in SQF. + +Current stores cover fuel tracking, medical service behavior, and a placeholder +service economy store. + +## Dependencies +- `forge_server_main` +- `forge_server_common` at runtime for logging, formatting, and player lookup +- `forge_server_bank` at runtime for medical service charges +- `forge_client_actor` and `forge_client_notifications` for response RPCs + +## Main Components +- `fnc_initFEconomyStore.sqf` tracks active refueling sessions and reports fuel + totals. +- `fnc_initMEconomyStore.sqf` manages medical spawn occupancy, healing charges, + respawn placement, death inventory handling, and body-bag transfer. +- `fnc_initSEconomyStore.sqf` initializes the service economy placeholder. + +## Event Surface +The addon registers CBA server events for fuel start/tick/stop, player killed, +player respawn, and healing. Medical store initialization runs after post-init +to discover configured medical spawn objects. + +## Notes +The service economy store is currently a stub. Fuel and medical behavior should +stay server-authoritative because they mutate money, inventory, and respawn +state. diff --git a/arma/server/addons/extension/README.md b/arma/server/addons/extension/README.md index bd27353..2d939a3 100644 --- a/arma/server/addons/extension/README.md +++ b/arma/server/addons/extension/README.md @@ -1,3 +1,29 @@ -# forge_server_extension +# Forge Server Extension -Extension functionality shared between addons. +## Overview +The extension addon is the SQF bridge to the `forge_server` arma-rs extension. +It normalizes `callExtension` responses, routes large payloads through the +transport layer, and exposes helper functions used by extension-backed server +addons. + +## Dependencies +- `forge_server_main` + +## Main Components +- `fnc_extCall.sqf` is the primary extension call wrapper. +- `fnc_transport.sqf` stages large requests and assembles chunked responses. +- `fnc_setHandler.sqf` registers local SQF handlers for extension callback + integration. + +## Transport Behavior +Most commands use direct `callExtension`. Commands that can return large +payloads, or requests whose encoded arguments exceed the chunk threshold, are +routed through `transport:invoke` or staged transport requests. + +The wrapper falls back to direct calls if the transport route is unsupported and +the request was not chunked. + +## Notes +Domain addons should call `EFUNC(extension,extCall)` instead of calling the +extension directly. This keeps response handling, chunking, and error logging +consistent. diff --git a/arma/server/addons/garage/README.md b/arma/server/addons/garage/README.md index 6002948..9de1717 100644 --- a/arma/server/addons/garage/README.md +++ b/arma/server/addons/garage/README.md @@ -1,3 +1,30 @@ -# forge_server_garage +# Forge Server Garage -Description for this addon +## Overview +The garage addon is the server-side bridge for player vehicle storage and +owner-scoped vehicle unlock storage. + +Garage hot state is owned by the extension. SQF validates Arma-facing requests, +serializes vehicle payloads, sends client syncs, and marks editor-placed garage +objects. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for garage extension calls +- `forge_client_garage` for response RPCs + +## Main Components +- `fnc_initGarage.sqf` initializes garage world objects. +- `fnc_initGarageStore.sqf` manages player garage hot state. +- `fnc_initVGStore.sqf` manages owner-scoped vehicle unlock state. + +## Supported Operations +- initialize player garage data +- save player and owner-scoped garage state +- store and retrieve player vehicles +- initialize and save owner-scoped vehicle storage + +## Runtime Notes +`forge_server_main_fnc_saveHotState` saves both `GarageStore` and +`VGarageStore` on disconnect and mission shutdown. diff --git a/arma/server/addons/locker/README.md b/arma/server/addons/locker/README.md index b9c2ce7..dc7e8ce 100644 --- a/arma/server/addons/locker/README.md +++ b/arma/server/addons/locker/README.md @@ -1,3 +1,30 @@ -# forge_server_locker +# Forge Server Locker -Description for this addon +## Overview +The locker addon is the server-side bridge for player item storage and +owner-scoped arsenal unlock storage. + +Locker hot state is owned by the extension. SQF handles client events, payload +validation, synchronization, and save calls. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for locker extension calls +- `forge_client_locker` for response RPCs + +## Main Components +- `fnc_initLocker.sqf` initializes locker world objects. +- `fnc_initLockerStore.sqf` manages player locker hot state. +- `fnc_initVAStore.sqf` manages owner-scoped arsenal unlock state. + +## Supported Operations +- initialize player locker data +- save player and owner-scoped locker state +- override locker data from trusted server-side callers +- initialize and save owner-scoped arsenal storage + +## Runtime Notes +`forge_server_main_fnc_saveHotState` saves both `LockerStore` and `VAStore` on +disconnect and mission shutdown. Store checkout and task rewards can grant +assets into organization-owned storage through the org addon. diff --git a/arma/server/addons/main/README.md b/arma/server/addons/main/README.md index 014bc81..bc7d2aa 100644 --- a/arma/server/addons/main/README.md +++ b/arma/server/addons/main/README.md @@ -1,3 +1,29 @@ -# forge_server_main +# Forge Server Main -Main Addon for forge-server +## Overview +The main addon owns server-side bootstrap behavior for Forge. It prepares +functions, wires extension callbacks and ICom events, initializes shared stores, +and flushes hot state when players disconnect or the mission ends. + +## Dependencies +- `cba_main` +- `ace_main` + +## Main Components +- `fnc_initStores.sqf` initializes core server stores in dependency order. +- `fnc_saveHotState.sqf` snapshots and saves extension-backed hot state. +- `fnc_initValidationHarness.sqf` provides targeted runtime smoke checks for + multi-module flows. +- `XEH_preInit.sqf` registers ICom and extension callback handlers. +- `XEH_postInit.sqf` starts store initialization. + +## Store Initialization +The main addon initializes shared base stores, actor, bank, garage, locker, +organization, store, and validation harness state. Some addons initialize their +own state in pre-init or post-init when they are intentionally independent of +the main bootstrap flow. + +## Hot State Flush +On player disconnect, mission ended, and MP ended events, `saveHotState` +persists actor, bank, locker, virtual arsenal, garage, virtual garage, and +organization hot state for the relevant UID or all known UIDs. diff --git a/arma/server/addons/org/README.md b/arma/server/addons/org/README.md index c9c6ab7..730e40c 100644 --- a/arma/server/addons/org/README.md +++ b/arma/server/addons/org/README.md @@ -1,3 +1,36 @@ -# forge_server_org +# Forge Server Organization -Description for this addon +## Overview +The organization addon is the server-side bridge for player organizations, +membership, treasury funds, reputation, credit lines, shared assets, fleet +entries, and invitations. + +Organization hot state is owned by the extension. SQF coordinates Arma-facing +events, UI payloads, membership syncs, and integration with actor, bank, store, +and task flows. + +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for organization extension calls +- `forge_server_actor` at runtime for organization membership lookups +- `forge_client_org` and `forge_client_notifications` for response RPCs + +## Main Components +- `fnc_initOrgStore.sqf` initializes `OrgModel` and `OrgStore`. +- `fnc_initPayloadBuilder.sqf` builds portal, organization, member, asset, and + fleet payloads. + +## Supported Operations +- initialize and hydrate organization portal data +- register, leave, and disband organizations +- invite, accept, and decline members +- assign and repay credit lines +- update funds and reputation +- grant assets and fleet vehicles +- save organization hot state + +## Runtime Notes +The addon ensures the `default` organization exists during store creation. +Task rewards and store checkout both rely on `OrgStore` for authoritative +organization-owned state. diff --git a/arma/server/addons/phone/README.md b/arma/server/addons/phone/README.md index b88555e..2b2398e 100644 --- a/arma/server/addons/phone/README.md +++ b/arma/server/addons/phone/README.md @@ -1,19 +1,33 @@ -forge_server_phone -=================== +# Forge Server Phone -This addon provides the phone user interface and functionality for the in-game phone system. It handles all phone-related features including the UI display, interactions, and core phone operations. +## Overview +The phone addon is the server-side bridge for contacts, SMS messages, and email. +Phone runtime state is owned by the extension. SQF stores preserve the +event-facing API and synchronize client UI state. -Server State ------------- +## Dependencies +- `forge_server_main` +- `forge_server_common` at runtime for online player lookup +- `forge_server_extension` at runtime for phone extension calls +- `forge_client_phone` for response RPCs -Phone contacts, messages, and emails are owned by the server extension. SQF phone stores act as bridge objects for CBA events and UI sync only. +## Main Components +- `fnc_initPhoneStore.sqf` coordinates the phone facade. +- `fnc_initContactStore.sqf` manages contacts. +- `fnc_initMessageStore.sqf` manages SMS messages and threads. +- `fnc_initEmailStore.sqf` manages email messages. +- `fnc_initPlayer.sqf` initializes phone data for a player. -Persistent SurrealDB tables: +## Persistent Extension Tables +- `phone_user`: owner row for an initialized phone profile +- `phone_contact`: per-owner contact rows keyed by owner UID and contact UID +- `phone_message`: shared message records +- `phone_message_index`: per-owner message visibility and read state +- `phone_email`: shared email records +- `phone_email_index`: per-owner email visibility and read state +- `phone_sequence`: global sequence state for generated message and email IDs -- `phone_user`: owner row for an initialized phone profile. -- `phone_contact`: per-owner contact rows keyed by owner UID and contact UID. -- `phone_message`: shared message records. -- `phone_message_index`: per-owner message visibility and read state. -- `phone_email`: shared email records. -- `phone_email_index`: per-owner email visibility and read state. -- `phone_sequence`: global sequence state for generated message and email IDs. +## Event Surface +The addon handles client requests to initialize phone state, add/remove/refresh +contacts, send/read/delete messages, send/read/delete emails, and remove phone +state. diff --git a/arma/server/addons/store/README.md b/arma/server/addons/store/README.md index 08d733a..46feb3c 100644 --- a/arma/server/addons/store/README.md +++ b/arma/server/addons/store/README.md @@ -1,18 +1,35 @@ -# forge_server_store +# Forge Server Store -Server-side SQF module for storefront entities, catalog hydration, and checkout -coordination. +## Overview +The store addon manages server-side storefront entities, catalog hydration, and +checkout coordination. -## Stores and Services +SQF owns Arma-facing storefront discovery and request validation. The Rust +extension owns authoritative checkout calculation through `store:checkout`. -- `StorefrontStore` builds storefront hydrate payloads, validates checkout - requests, calls the Rust `store:checkout` backend, syncs UI patches, and saves - hot state for related modules. -- `StoreCatalogService` scans live Arma config categories, builds catalog - responses, resolves checkout entries, and calculates authoritative prices. +## Dependencies +- `forge_server_main` +- `forge_server_common` +- `forge_server_extension` at runtime for checkout calls +- `forge_server_actor`, `forge_server_bank`, and `forge_server_org` at runtime + for checkout context and payment state +- `forge_client_store` for response RPCs + +## Main Components +- `fnc_initStore.sqf` marks editor-placed store objects with `isStore = true`. +- `fnc_initCatalogService.sqf` scans live Arma config categories, builds + catalog responses, resolves checkout entries, and calculates authoritative + catalog prices. +- `fnc_initStorefrontStore.sqf` builds hydrate payloads, validates checkout + requests, calls `store:checkout`, syncs client patches, and coordinates + related bank/org persistence. ## Editor Entities +`fnc_initStore` matches non-null mission namespace objects whose variable names +contain `store`, mirroring the garage entity initialization pattern. -`fnc_initStore` marks editor-placed store objects with `isStore = true`. It -matches non-null mission namespace objects whose variable names contain -`store`, mirroring the garage entity initialization pattern. +## Checkout Flow +Store checkout can charge cash, bank balance, organization funds, or approved +credit lines depending on the hydrated session context. Checkout results can +grant locker assets, organization assets, and fleet vehicles through the +related domain stores. diff --git a/arma/server/addons/task/CfgVehicles.hpp b/arma/server/addons/task/CfgVehicles.hpp index f045710..dcd25c4 100644 --- a/arma/server/addons/task/CfgVehicles.hpp +++ b/arma/server/addons/task/CfgVehicles.hpp @@ -355,9 +355,9 @@ class CfgVehicles { class TimeLimit: Edit { property = "FORGE_Module_Defuse_TimeLimit"; displayName = "Time Limit"; - tooltip = "Time in seconds before detenation (0 for no limit)"; + tooltip = "Time in seconds before detonation; must be greater than 0"; typeName = "NUMBER"; - defaultValue = 0; + defaultValue = 300; }; }; @@ -608,7 +608,7 @@ class CfgVehicles { class TimeLimit: Edit { property = "FORGE_Module_Hostage_TimeLimit"; displayName = "Time Limit"; - tooltip = "Time in seconds before HVTs escape (0 for no limit)"; + tooltip = "Time in seconds before hostages are executed (0 for no limit)"; typeName = "NUMBER"; defaultValue = 0; }; @@ -730,9 +730,9 @@ class CfgVehicles { class TimeLimit: Edit { property = "FORGE_Module_Delivery_TimeLimit"; displayName = "Time Limit"; - tooltip = "Seconds to complete delivery (-1 for no limit)"; + tooltip = "Seconds to complete delivery (0 for no limit)"; typeName = "NUMBER"; - defaultValue = -1; + defaultValue = 0; }; }; @@ -907,7 +907,7 @@ class CfgVehicles { class TimeLimit: Edit { property = "FORGE_Module_HVT_TimeLimit"; displayName = "Time Limit"; - tooltip = "Time in seconds before HVTs escape (0 for no limit)"; + tooltip = "Time in seconds before the HVT task fails (0 for no limit)"; typeName = "NUMBER"; defaultValue = 0; }; diff --git a/arma/server/addons/task/README.md b/arma/server/addons/task/README.md index ef67658..038449d 100644 --- a/arma/server/addons/task/README.md +++ b/arma/server/addons/task/README.md @@ -16,6 +16,7 @@ system intentionally starts clean after each server or mission restart. - notify task participants and sync org updates to online members ## Dependencies +- `forge_server_extension` - `forge_server_common` - `forge_server_actor` - `forge_server_bank` @@ -58,6 +59,10 @@ Org rewards always go to the bound owner org. Player earnings still use per-play ## Usage +Task time limits use `0` for no limit on attack, destroy, delivery, hostage, +and HVT tasks. Defuse IED timers are different: each IED must have a positive +countdown value. + ### Start Through The Handler Use the handler when you want reputation gating and task ownership binding. diff --git a/arma/server/addons/task/functions/fnc_attack.sqf b/arma/server/addons/task/functions/fnc_attack.sqf index ef91a6e..a4893fc 100644 --- a/arma/server/addons/task/functions/fnc_attack.sqf +++ b/arma/server/addons/task/functions/fnc_attack.sqf @@ -13,7 +13,7 @@ * 5: Amount of rating the company and player recieve if the task is successful (default: 0) * 6: Should the mission end (MissionSuccess) if the task is successful (default: false) * 7: Should the mission end (MissionFailed) if the task is failed (default: false) - * 8: Amount of time before target(s) escape (default: -1) + * 8: Amount of time before target(s) escape (default: 0, 0 = no limit) * 9: Equipment rewards (default: []) * 10: Supply rewards (default: []) * 11: Weapon rewards (default: []) @@ -39,7 +39,7 @@ params [ ["_ratingSuccess", 0, [0]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], - ["_time", -1, [0]], + ["_timeLimit", 0, [0]], ["_equipmentRewards", [], [[]]], ["_supplyRewards", [], [[]]], ["_weaponRewards", [], [[]]], @@ -58,7 +58,7 @@ waitUntil { }; _targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]]; -private _startTime = if (!isNil "_time") then { floor(time) } else { nil }; +private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil }; waitUntil { sleep 1; @@ -66,8 +66,8 @@ waitUntil { private _targetsKilled = ({ !alive _x } count _targets); - if (_time isNotEqualTo -1) then { - private _timeExpired = (floor time - _startTime >= _time); + if (_timeLimit isNotEqualTo 0) then { + private _timeExpired = (floor time - _startTime >= _timeLimit); if (_targetsKilled < _limitSuccess && _timeExpired) then { _result = 1; }; diff --git a/arma/server/addons/task/functions/fnc_attackModule.sqf b/arma/server/addons/task/functions/fnc_attackModule.sqf index e0cd214..17d413e 100644 --- a/arma/server/addons/task/functions/fnc_attackModule.sqf +++ b/arma/server/addons/task/functions/fnc_attackModule.sqf @@ -53,7 +53,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["timeLimit", _logic getVariable ["TimeLimit", -1]] + ["timeLimit", _logic getVariable ["TimeLimit", 0]] ] ] call FUNC(startTask); diff --git a/arma/server/addons/task/functions/fnc_defuseModule.sqf b/arma/server/addons/task/functions/fnc_defuseModule.sqf index e3b8b1e..3324c02 100644 --- a/arma/server/addons/task/functions/fnc_defuseModule.sqf +++ b/arma/server/addons/task/functions/fnc_defuseModule.sqf @@ -36,7 +36,7 @@ private _protectedEntities = if (!isNull _protectedModule) then { synchronizedOb ["INFO", format [ "Defuse Module: TaskID: %1, IEDs: %2, Protected: %3, IED timer: %4s", _taskID, count _iedEntities, count _protectedEntities, - _logic getVariable ["TimeLimit", 0] + _logic getVariable ["TimeLimit", 300] ]] call EFUNC(common,log); private _taskPos = if (_iedEntities isNotEqualTo []) then { @@ -63,7 +63,7 @@ private _taskPos = if (_iedEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["iedTimer", _logic getVariable ["TimeLimit", 0]] + ["iedTimer", _logic getVariable ["TimeLimit", 300]] ] ] call FUNC(startTask); diff --git a/arma/server/addons/task/functions/fnc_delivery.sqf b/arma/server/addons/task/functions/fnc_delivery.sqf index 1088e0f..426e10a 100644 --- a/arma/server/addons/task/functions/fnc_delivery.sqf +++ b/arma/server/addons/task/functions/fnc_delivery.sqf @@ -14,7 +14,7 @@ * 6: Amount of rating the company and player receive if the task is successful (default: 0) * 7: Should the mission end (MissionSuccess) if the task is successful (default: false) * 8: Should the mission end (MissionFailed) if the task is failed (default: false) - * 9: Amount of time to complete delivery (default: -1) + * 9: Amount of time to complete delivery (default: 0) * 10: Equipment rewards (default: []) * 11: Supply rewards (default: []) * 12: Weapon rewards (default: []) @@ -41,7 +41,7 @@ params [ ["_ratingSuccess", 0, [0]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], - ["_time", -1, [0]], + ["_timeLimit", 0, [0]], ["_equipmentRewards", [], [[]]], ["_supplyRewards", [], [[]]], ["_weaponRewards", [], [[]]], @@ -60,7 +60,7 @@ waitUntil { }; _cargo = GVAR(TaskStore) call ["getTaskEntities", ["cargo", _taskID]]; -private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil }; +private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil }; waitUntil { sleep 1; @@ -69,8 +69,8 @@ waitUntil { private _cargoDelivered = ({ _x inArea _deliveryZone && (damage _x) < 0.7 } count _cargo); private _cargoDamaged = ({ damage _x >= 0.7 } count _cargo); - if (_time isNotEqualTo -1) then { - private _timeExpired = (floor time - _startTime >= _time); + if (_timeLimit isNotEqualTo 0) then { + private _timeExpired = (floor time - _startTime >= _timeLimit); if (_cargoDamaged >= _limitFail) then { _result = 1; }; if (_cargoDelivered < _limitSuccess && _timeExpired) then { _result = 1; }; diff --git a/arma/server/addons/task/functions/fnc_deliveryModule.sqf b/arma/server/addons/task/functions/fnc_deliveryModule.sqf index 2a9c151..757a3f4 100644 --- a/arma/server/addons/task/functions/fnc_deliveryModule.sqf +++ b/arma/server/addons/task/functions/fnc_deliveryModule.sqf @@ -63,7 +63,7 @@ private _taskPos = if (_cargoEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["timeLimit", _logic getVariable ["TimeLimit", -1]], + ["timeLimit", _logic getVariable ["TimeLimit", 0]], ["deliveryZone", _logic getVariable ["DeliveryZone", ""]] ] ] call FUNC(startTask); diff --git a/arma/server/addons/task/functions/fnc_destroy.sqf b/arma/server/addons/task/functions/fnc_destroy.sqf index dcb1013..2284dda 100644 --- a/arma/server/addons/task/functions/fnc_destroy.sqf +++ b/arma/server/addons/task/functions/fnc_destroy.sqf @@ -13,7 +13,7 @@ * 5: Amount of rating the company and player recieve if the task is successful (default: 0) * 6: Should the mission end (MissionSuccess) if the task is successful (default: false) * 7: Should the mission end (MissionFailed) if the task is failed (default: false) - * 8: Amount of time before target(s) escape (default: -1) + * 8: Amount of time before target(s) escape (default: 0, 0 = no limit) * 9: Equipment rewards (default: []) * 10: Supply rewards (default: []) * 11: Weapon rewards (default: []) @@ -39,7 +39,7 @@ params [ ["_ratingSuccess", 0, [0]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], - ["_time", -1, [0]], + ["_timeLimit", 0, [0]], ["_equipmentRewards", [], [[]]], ["_supplyRewards", [], [[]]], ["_weaponRewards", [], [[]]], @@ -58,7 +58,7 @@ waitUntil { }; _targets = GVAR(TaskStore) call ["getTaskEntities", ["targets", _taskID]]; -private _startTime = if (!isNil "_time") then { floor(time) } else { nil }; +private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil }; waitUntil { sleep 1; @@ -66,8 +66,8 @@ waitUntil { private _targetsDestroyed = ({ !alive _x } count _targets); - if (!isNil "_time") then { - private _timeExpired = (floor time - _startTime >= _time); + if (_timeLimit isNotEqualTo 0) then { + private _timeExpired = (floor time - _startTime >= _timeLimit); if (_targetsDestroyed < _limitSuccess && _timeExpired) then { _result = 1; }; diff --git a/arma/server/addons/task/functions/fnc_destroyModule.sqf b/arma/server/addons/task/functions/fnc_destroyModule.sqf index b3b2015..499d55d 100644 --- a/arma/server/addons/task/functions/fnc_destroyModule.sqf +++ b/arma/server/addons/task/functions/fnc_destroyModule.sqf @@ -53,7 +53,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["timeLimit", _logic getVariable ["TimeLimit", -1]] + ["timeLimit", _logic getVariable ["TimeLimit", 0]] ] ] call FUNC(startTask); diff --git a/arma/server/addons/task/functions/fnc_hostage.sqf b/arma/server/addons/task/functions/fnc_hostage.sqf index ead6b2a..66c4071 100644 --- a/arma/server/addons/task/functions/fnc_hostage.sqf +++ b/arma/server/addons/task/functions/fnc_hostage.sqf @@ -15,7 +15,7 @@ * 7: Subcategory of task (default: [false, true]) * 8: Should the mission end (MissionSuccess) if the task is successful (default: false) * 9: Should the mission end (MissionFailed) if the task is failed (default: false) - * 10: Amount of time before hostage(s) die (default: -1) + * 10: Amount of time before hostage(s) are executed (default: 0, 0 = no limit) * 11: Marker name for the cbrn zone (default: "") * 12: Equipment rewards (default: []) * 13: Supply rewards (default: []) @@ -45,7 +45,7 @@ params [ ["_type", [["_cbrn", false, [false]], ["_hostage", true, [false]]]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], - ["_time", -1, [0]], + ["_timeLimit", 0, [0]], ["_cbrnZone", "", [""]], ["_equipmentRewards", [], [[]]], ["_supplyRewards", [], [[]]], @@ -75,7 +75,7 @@ waitUntil { _hostages = GVAR(TaskStore) call ["getTaskEntities", ["hostages", _taskID]]; _shooters = GVAR(TaskStore) call ["getTaskEntities", ["shooters", _taskID]]; -private _startTime = if (_time isNotEqualTo -1) then { floor(time) } else { nil }; +private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil }; waitUntil { sleep 1; @@ -86,8 +86,8 @@ waitUntil { private _hostagesKilled = ({ !alive _x } count _hostages); private _shootersAlive = ({ alive _x } count _shooters); - if (_time isNotEqualTo -1) then { - private _timeExpired = (floor time - _startTime >= _time); + if (_timeLimit isNotEqualTo 0) then { + private _timeExpired = (floor time - _startTime >= _timeLimit); if (_hostagesFreed < _limitSuccess && _timeExpired) then { _result = 1; }; if (_hostagesKilled >= _limitFail) then { _result = 1; }; diff --git a/arma/server/addons/task/functions/fnc_hostageModule.sqf b/arma/server/addons/task/functions/fnc_hostageModule.sqf index b40de6c..8a90a5f 100644 --- a/arma/server/addons/task/functions/fnc_hostageModule.sqf +++ b/arma/server/addons/task/functions/fnc_hostageModule.sqf @@ -67,7 +67,7 @@ private _taskPos = if (_hostageEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["timeLimit", _logic getVariable ["TimeLimit", -1]], + ["timeLimit", _logic getVariable ["TimeLimit", 0]], ["extractionZone", _logic getVariable ["ExtZone", ""]], ["cbrn", _logic getVariable ["CBRN", false]], ["execution", _logic getVariable ["Execution", false]], diff --git a/arma/server/addons/task/functions/fnc_hvt.sqf b/arma/server/addons/task/functions/fnc_hvt.sqf index f763300..97f54c8 100644 --- a/arma/server/addons/task/functions/fnc_hvt.sqf +++ b/arma/server/addons/task/functions/fnc_hvt.sqf @@ -15,7 +15,7 @@ * 7: Subcategory of task (default: [true, false]) * 8: Should the mission end (MissionSuccess) if the task is successful (default: false) * 9: Should the mission end (MissionFailed) if the task is failed (default: false) - * 10: Amount of time before hvt(s) die (default: -1) + * 10: Amount of time before HVT task fails (default: 0, 0 = no limit) * 11: Equipment rewards (default: []) * 12: Supply rewards (default: []) * 13: Weapon rewards (default: []) @@ -45,7 +45,7 @@ params [ ["_type", [["_capture", true, [false]], ["_eliminate", false, [false]]]], ["_endSuccess", false, [false]], ["_endFail", false, [false]], - ["_time", -1, [0]], + ["_timeLimit", 0, [0]], ["_equipmentRewards", [], [[]]], ["_supplyRewards", [], [[]]], ["_weaponRewards", [], [[]]], @@ -66,7 +66,7 @@ waitUntil { }; _hvts = GVAR(TaskStore) call ["getTaskEntities", ["hvts", _taskID]]; -private _startTime = if (!isNil "_time") then { floor(time) } else { nil }; +private _startTime = if (_timeLimit isNotEqualTo 0) then { floor(time) } else { nil }; waitUntil { sleep 1; @@ -76,8 +76,8 @@ waitUntil { private _hvtsKilled = ({ !alive _x } count _hvts); private _hvtsInZone = ({ _x inArea _extZone } count _hvts); - if (!isNil "_time") then { - private _timeExpired = (floor time - _startTime >= _time); + if (_timeLimit isNotEqualTo 0) then { + private _timeExpired = (floor time - _startTime >= _timeLimit); if (_capture && _hvtsKilled >= _limitFail) then { _result = 1; }; if (_capture && _hvtsCaptive < _limitSuccess && _timeExpired) then { _result = 1; }; diff --git a/arma/server/addons/task/functions/fnc_hvtModule.sqf b/arma/server/addons/task/functions/fnc_hvtModule.sqf index fdc2672..58f242a 100644 --- a/arma/server/addons/task/functions/fnc_hvtModule.sqf +++ b/arma/server/addons/task/functions/fnc_hvtModule.sqf @@ -59,7 +59,7 @@ private _taskPos = if (_syncedEntities isNotEqualTo []) then { ["ratingSuccess", _logic getVariable ["RatingSuccess", 0]], ["endSuccess", _logic getVariable ["EndSuccess", false]], ["endFail", _logic getVariable ["EndFail", false]], - ["timeLimit", _logic getVariable ["TimeLimit", -1]], + ["timeLimit", _logic getVariable ["TimeLimit", 0]], ["extractionZone", _logic getVariable ["ExtZone", ""]], ["captureHvt", _logic getVariable ["CaptureHVT", true]] ] diff --git a/arma/server/addons/task/functions/fnc_makeIED.sqf b/arma/server/addons/task/functions/fnc_makeIED.sqf index a4489c6..6f185ee 100644 --- a/arma/server/addons/task/functions/fnc_makeIED.sqf +++ b/arma/server/addons/task/functions/fnc_makeIED.sqf @@ -2,12 +2,12 @@ /* * Author: IDSolutions - * Assigns an IED to a task and starts countdown timer + * Assigns an IED to a task and starts its required countdown timer * * Arguments: * 0: The object * 1: ID of the task - * 2: The Countdown Timer + * 2: Countdown timer in seconds (must be greater than 0) * * Return Value: * None @@ -22,7 +22,7 @@ params [["_entity", objNull, [objNull]], ["_taskID", "", [""]], ["_time", 0, [0] if (isNull _entity) exitWith { ["ERROR", "Attempt to create entity from null object"] call EFUNC(common,log); }; if (_taskID == "") exitWith { ["ERROR", "No task ID provided for entity"] call EFUNC(common,log); }; -if (_time < 0) exitWith { ["ERROR", "Invalid time provided for IED"] call EFUNC(common,log); }; +if (_time <= 0) exitWith { ["ERROR", "Invalid time provided for IED"] call EFUNC(common,log); }; ["INFO", format ["Make IED: %1", _this]] call EFUNC(common,log); diff --git a/arma/server/addons/task/functions/fnc_startTask.sqf b/arma/server/addons/task/functions/fnc_startTask.sqf index 761bc9b..b108747 100644 --- a/arma/server/addons/task/functions/fnc_startTask.sqf +++ b/arma/server/addons/task/functions/fnc_startTask.sqf @@ -29,12 +29,12 @@ * "ratingSuccess" (default: 0) * "endSuccess" (default: false) * "endFail" (default: false) - * "timeLimit" (default: -1, -1 = no limit) + * "timeLimit" (default: 0, 0 = no limit) * Reward keys: * "equipment" , "supplies" , "weapons" , * "vehicles" , "special" * Type-specific keys: - * defuse: "iedTimer" -- IED countdown in seconds (default: 0) + * defuse: "iedTimer" -- required IED countdown in seconds (> 0) * delivery: "deliveryZone" -- marker name * hostage: "extractionZone" -- marker name * "cbrn" (default: false) @@ -138,7 +138,7 @@ private _ratingFail = _taskParams getOrDefault ["ratingFail", 0]; private _ratingSuccess = _taskParams getOrDefault ["ratingSuccess", 0]; private _endSuccess = _taskParams getOrDefault ["endSuccess", false]; private _endFail = _taskParams getOrDefault ["endFail", false]; -private _timeLimit = _taskParams getOrDefault ["timeLimit", -1]; +private _timeLimit = _taskParams getOrDefault ["timeLimit", 0]; private _equipRewards = _taskParams getOrDefault ["equipment", []]; private _supplyRewards = _taskParams getOrDefault ["supplies", []]; private _weaponRewards = _taskParams getOrDefault ["weapons", []]; @@ -150,8 +150,7 @@ private _rewardTail = [_equipRewards, _supplyRewards, _weaponRewards, _vehicleRe private _handlerArgs = switch (_taskType) do { case "attack"; case "destroy": { - private _args = [_taskID, _limitFail, _limitSuccess, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail]; - if (_timeLimit >= 0) then { _args pushBack _timeLimit; }; + private _args = [_taskID, _limitFail, _limitSuccess, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit]; _args + _rewardTail }; case "defuse": { @@ -159,8 +158,7 @@ private _handlerArgs = switch (_taskType) do { }; case "delivery": { private _deliveryZone = _taskParams getOrDefault ["deliveryZone", ""]; - private _args = [_taskID, _limitFail, _limitSuccess, _deliveryZone, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail]; - if (_timeLimit >= 0) then { _args pushBack _timeLimit; }; + private _args = [_taskID, _limitFail, _limitSuccess, _deliveryZone, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _timeLimit]; _args + _rewardTail }; case "hostage": { @@ -168,18 +166,14 @@ private _handlerArgs = switch (_taskType) do { private _cbrn = _taskParams getOrDefault ["cbrn", false]; private _execution = _taskParams getOrDefault ["execution", false]; private _cbrnZone = _taskParams getOrDefault ["cbrnZone", ""]; - private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_cbrn, _execution], _endSuccess, _endFail]; - if (_timeLimit >= 0) then { - _args pushBack _timeLimit; - _args pushBack _cbrnZone; - }; + private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_cbrn, _execution], _endSuccess, _endFail, _timeLimit]; + _args pushBack _cbrnZone; _args + _rewardTail }; case "hvt": { private _extZone = _taskParams getOrDefault ["extractionZone", ""]; private _captureHvt = _taskParams getOrDefault ["captureHvt", true]; - private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_captureHvt, !_captureHvt], _endSuccess, _endFail]; - if (_timeLimit >= 0) then { _args pushBack _timeLimit; }; + private _args = [_taskID, _limitFail, _limitSuccess, _extZone, _funds, _ratingFail, _ratingSuccess, [_captureHvt, !_captureHvt], _endSuccess, _endFail, _timeLimit]; _args + _rewardTail }; case "defend": { @@ -188,8 +182,7 @@ private _handlerArgs = switch (_taskType) do { private _waveCount = _taskParams getOrDefault ["waveCount", 3]; private _waveCooldown = _taskParams getOrDefault ["waveCooldown", 300]; private _minBlufor = _taskParams getOrDefault ["minBlufor", 1]; - [_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, - _waveCount, _waveCooldown, _minBlufor] + _rewardTail + [_taskID, _defenseZone, _defendTime, _funds, _ratingFail, _ratingSuccess, _endSuccess, _endFail, _waveCount, _waveCooldown, _minBlufor] + _rewardTail }; default { ["ERROR", format ["startTask: unknown task type '%1'.", _taskType]] call EFUNC(common,log); diff --git a/docs/MODULE_REFERENCE.md b/docs/MODULE_REFERENCE.md index ce417d3..1b9ec1e 100644 --- a/docs/MODULE_REFERENCE.md +++ b/docs/MODULE_REFERENCE.md @@ -29,7 +29,7 @@ docs/ Framework-level documentation | Organization | Player organizations, membership, treasury, credit lines, shared assets, and fleet data. | `arma/client/addons/org` | `arma/server/addons/org` | `lib/models/src/org.rs`, `lib/services/src/org.rs` | `org:*`, `org:hot:*` | | Phone | Contacts, messages, and email state. | `arma/client/addons/phone` | `arma/server/addons/phone` | `lib/models/src/phone.rs`, `lib/services/src/phone.rs` | `phone:*` | | Store | Storefront entity setup, catalog hydration, checkout workflows, and checkout charging integration. | `arma/client/addons/store` | `arma/server/addons/store` | `lib/models/src/store.rs`, `lib/services/src/store.rs` | `store:checkout` | -| Task | Mission/task catalog, ownership, status, reward context, and task counters. | none | `arma/server/addons/task` | `lib/models/src/task.rs`, `lib/services/src/task.rs` | `task:*` | +| Task | Server-owned mission/task flows, catalog, ownership, status, participant tracking, rewards, and defuse counters. | none | `arma/server/addons/task` | `lib/models/src/task.rs`, `lib/services/src/task.rs` | `task:*` | | Owned Garage | Organization or owner-scoped vehicle unlock storage. | via garage/org UI | server extension only | `lib/models/src/v_garage.rs`, `lib/services/src/v_garage.rs` | `owned:garage:*` | | Owned Locker | Organization or owner-scoped arsenal unlock storage. | via locker/org UI | server extension only | `lib/models/src/v_locker.rs`, `lib/services/src/v_locker.rs` | `owned:locker:*` | diff --git a/docs/TASK_USAGE_GUIDE.md b/docs/TASK_USAGE_GUIDE.md index 446a0e8..6003e55 100644 --- a/docs/TASK_USAGE_GUIDE.md +++ b/docs/TASK_USAGE_GUIDE.md @@ -4,6 +4,20 @@ The task module stores transient mission task metadata for active server or mission lifecycle workflows. SQF still owns Arma-only runtime state such as objects and participants. +The server addon at `arma/server/addons/task` also owns task execution: +creating BIS tasks, registering task entities, tracking participants, binding +task ownership, applying player/org rewards, and clearing task state when a +task completes. + +Runtime dependencies: + +- `forge_server_extension` +- `forge_server_common` +- `forge_server_actor` +- `forge_server_bank` +- `forge_server_org` +- `forge_client_notifications` + ## Data Model Catalog entries are flexible JSON objects. The service normalizes these fields @@ -102,6 +116,78 @@ private _context = fromJSON (_result select 0); The reward context contains `requesterUid` and `orgId`. +## Server Task Flows + +The task addon provides these server-owned task flows: + +- `attack` +- `defend` +- `defuse` +- `delivery` +- `destroy` +- `hostage` +- `hvt` + +Use `forge_server_task_fnc_startTask` when creating tasks from modules, +mission scripts, or generated mission-manager content. It registers task +entities, creates the BIS task, stores the catalog entry, then dispatches +through `forge_server_task_fnc_handler`. + +```sqf +[ + "attack", + "compound_attack_01", + getPosATL leader1, + "Attack: East Compound", + "Eliminate all hostile forces.", + createHashMapFromArray [["targets", [unit1, unit2, unit3]]], + createHashMapFromArray [ + ["limitFail", 0], + ["limitSuccess", 3], + ["funds", 50000], + ["ratingFail", -10], + ["ratingSuccess", 20], + ["timeLimit", 900] + ], + 0, + getPlayerUID player, + "script" +] call forge_server_task_fnc_startTask; +``` + +Use `forge_server_task_fnc_handler` directly when the task entities are already +registered and you want reputation gating plus ownership binding: + +```sqf +[ + "delivery", + ["delivery_1", 1, 3, "delivery_zone", 250000, -75, 300, false, false, 900], + 250, + getPlayerUID player +] call forge_server_task_fnc_handler; +``` + +Direct task function calls still work for mission-authored or server-owned +tasks, but they do not provide a requester UID. Ownership falls back to the +`default` org. + +## Timer Semantics + +Task time limits use `0` for no limit: + +- attack `timeLimit` +- destroy `timeLimit` +- delivery `timeLimit` +- hostage `timeLimit` +- HVT `timeLimit` + +Positive values are measured in seconds. Do not pass `-1` as a no-limit value; +the task runtime treats any non-zero task time limit as active. + +Defuse IED timers are different. `iedTimer` must be greater than `0`, because +IEDs are expected to have an active countdown. The Eden defuse module defaults +to `300` seconds. + ## Defuse Counter ```sqf