Backport framework docs and store filter updates
This commit is contained in:
parent
d61cb86d3a
commit
4f54edf467
@ -152,6 +152,12 @@ option {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.timer-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.95fr) minmax(0, 0.95fr);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
label {
|
||||
color: var(--text-subtle);
|
||||
font-size: 0.62rem;
|
||||
@ -261,6 +267,10 @@ select {
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
select:focus,
|
||||
button:focus-visible {
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
reputationMax: 100,
|
||||
penaltyMin: -5,
|
||||
penaltyMax: -25,
|
||||
timeLimitEnabled: true,
|
||||
timeLimitMin: 600,
|
||||
timeLimitMax: 900,
|
||||
medicalSpawnCost: 100,
|
||||
@ -41,6 +42,8 @@
|
||||
}
|
||||
|
||||
function readSettings() {
|
||||
const timeLimitEnabled = document.getElementById("timeLimitEnabled")?.checked !== false;
|
||||
|
||||
return {
|
||||
enemyFaction: String(document.getElementById("enemyFaction")?.value || "IND_G_F"),
|
||||
maxConcurrentMissions: fieldNumber("maxConcurrentMissions"),
|
||||
@ -52,8 +55,9 @@
|
||||
reputationMax: fieldNumber("reputationMax"),
|
||||
penaltyMin: fieldNumber("penaltyMin"),
|
||||
penaltyMax: fieldNumber("penaltyMax"),
|
||||
timeLimitMin: fieldNumber("timeLimitMin"),
|
||||
timeLimitMax: fieldNumber("timeLimitMax"),
|
||||
timeLimitEnabled,
|
||||
timeLimitMin: timeLimitEnabled ? fieldNumber("timeLimitMin") : 0,
|
||||
timeLimitMax: timeLimitEnabled ? fieldNumber("timeLimitMax") : 0,
|
||||
medicalSpawnCost: fieldNumber("medicalSpawnCost"),
|
||||
medicalHealCost: fieldNumber("medicalHealCost"),
|
||||
serviceRepairCost: fieldNumber("serviceRepairCost"),
|
||||
@ -74,6 +78,16 @@
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function normalizeSettings(settings) {
|
||||
const next = Object.assign({}, settings);
|
||||
next.timeLimitMin = Number(next.timeLimitMin || 0);
|
||||
next.timeLimitMax = Number(next.timeLimitMax || 0);
|
||||
if (typeof next.timeLimitEnabled !== "boolean") {
|
||||
next.timeLimitEnabled = next.timeLimitMax > 0;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function apply() {
|
||||
const settings = readSettings();
|
||||
if (settings.moneyMax < settings.moneyMin) {
|
||||
@ -94,10 +108,18 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.timeLimitMax < settings.timeLimitMin) {
|
||||
state.error = "Time limit max must be greater than or equal to time limit min.";
|
||||
render();
|
||||
return;
|
||||
if (settings.timeLimitEnabled) {
|
||||
if (settings.timeLimitMin < 1 || settings.timeLimitMax < 1) {
|
||||
state.error = "Time limits must be positive seconds when task timers are enabled.";
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.timeLimitMax < settings.timeLimitMin) {
|
||||
state.error = "Time limit max must be greater than or equal to time limit min.";
|
||||
render();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const costFields = [
|
||||
@ -134,6 +156,15 @@
|
||||
const factionLabel = faction ? faction.display : settings.enemyFaction;
|
||||
const generatorProviderLabel = settings.generatorProvider === "custom" ? "Custom" : "Built-in";
|
||||
const generatorProviderChecked = settings.generatorProvider === "custom" ? " checked" : "";
|
||||
const timeLimitEnabled = settings.timeLimitEnabled !== false;
|
||||
const timeLimitChecked = timeLimitEnabled ? " checked" : "";
|
||||
const timeLimitDisabled = timeLimitEnabled ? "" : " disabled";
|
||||
const timeLimitLabel = timeLimitEnabled ? "Enabled" : "No Limit";
|
||||
const timeLimitMinValue = timeLimitEnabled ? settings.timeLimitMin : 600;
|
||||
const timeLimitMaxValue = timeLimitEnabled ? settings.timeLimitMax : 900;
|
||||
const timeLimitSummary = timeLimitEnabled
|
||||
? `${settings.timeLimitMin}s - ${settings.timeLimitMax}s`
|
||||
: "No limit";
|
||||
|
||||
document.getElementById("app").innerHTML = `
|
||||
<div class="shell">
|
||||
@ -204,13 +235,26 @@
|
||||
<label for="penaltyMax">Max Rep Hit</label>
|
||||
<input id="penaltyMax" type="number" max="0" step="1" value="${settings.penaltyMax}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="timeLimitMin">Min Time</label>
|
||||
<input id="timeLimitMin" type="number" min="1" step="60" value="${settings.timeLimitMin}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="timeLimitMax">Max Time</label>
|
||||
<input id="timeLimitMax" type="number" min="1" step="60" value="${settings.timeLimitMax}" />
|
||||
<div class="timer-row wide">
|
||||
<div class="field">
|
||||
<label for="timeLimitEnabled">Task Timer</label>
|
||||
<label class="provider-toggle" for="timeLimitEnabled">
|
||||
<input id="timeLimitEnabled" type="checkbox"${timeLimitChecked} />
|
||||
<span class="switch" aria-hidden="true"></span>
|
||||
<span class="provider-copy">
|
||||
<strong>${timeLimitLabel}</strong>
|
||||
<small>Time Limits</small>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="timeLimitMin">Min Time</label>
|
||||
<input id="timeLimitMin" type="number" min="1" step="60" value="${timeLimitMinValue}"${timeLimitDisabled} />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="timeLimitMax">Max Time</label>
|
||||
<input id="timeLimitMax" type="number" min="1" step="60" value="${timeLimitMaxValue}"${timeLimitDisabled} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -222,7 +266,7 @@
|
||||
</div>
|
||||
<div class="form compact">
|
||||
<div class="field">
|
||||
<label for="medicalSpawnCost">Medical Spawn</label>
|
||||
<label for="medicalSpawnCost">Medical Respawn</label>
|
||||
<input id="medicalSpawnCost" type="number" min="0" step="50" value="${settings.medicalSpawnCost}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -266,10 +310,10 @@
|
||||
<div class="summary-row"><span>Reward Range</span><strong>$${Number(settings.moneyMin).toLocaleString()} - $${Number(settings.moneyMax).toLocaleString()}</strong></div>
|
||||
<div class="summary-row"><span>Reputation</span><strong>${settings.reputationMin} - ${settings.reputationMax}</strong></div>
|
||||
<div class="summary-row"><span>Reputation Hit</span><strong>${settings.penaltyMin} to ${settings.penaltyMax}</strong></div>
|
||||
<div class="summary-row"><span>Time Limit</span><strong>${settings.timeLimitMin}s - ${settings.timeLimitMax}s</strong></div>
|
||||
<div class="summary-row"><span>Time Limit</span><strong>${timeLimitSummary}</strong></div>
|
||||
<div class="summary-row"><span>Repair / Rearm</span><strong>$${Number(settings.serviceRepairCost).toLocaleString()} / $${Number(settings.serviceRearmCost).toLocaleString()}</strong></div>
|
||||
<div class="summary-row"><span>Fuel</span><strong>$${Number(settings.fuelCost).toLocaleString()} / L</strong></div>
|
||||
<div class="summary-row"><span>Medical</span><strong>$${Number(settings.medicalSpawnCost).toLocaleString()} spawn / $${Number(settings.medicalHealCost).toLocaleString()} heal</strong></div>
|
||||
<div class="summary-row"><span>Medical Billing</span><strong>$${Number(settings.medicalSpawnCost).toLocaleString()} respawn / $${Number(settings.medicalHealCost).toLocaleString()} heal</strong></div>
|
||||
${state.error ? `<div class="notice">${state.error}</div>` : ""}
|
||||
</div>
|
||||
</aside>
|
||||
@ -315,7 +359,7 @@
|
||||
return true;
|
||||
});
|
||||
state.factions = factions;
|
||||
state.settings = Object.assign({}, state.settings, payload.data?.settings || {});
|
||||
state.settings = normalizeSettings(Object.assign({}, state.settings, payload.data?.settings || {}));
|
||||
render();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ GVAR(ActorModel) = compileFinal createHashMapObject [[
|
||||
|
||||
if (isArray _loadoutConfig) exitWith { getArray _loadoutConfig };
|
||||
|
||||
[[],[],[],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2]]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]
|
||||
[[],[],["hgun_P07_F","","","",["16Rnd_9x21_Mag",4,17],[],""],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2],["ACE_EarPlugs",1]]],["V_Rangemaster_belt",[["16Rnd_9x21_Mag",4]]],[],"H_Cap_blk_ION","",["Binocular","","","",[],[],""],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]
|
||||
}],
|
||||
["defaults", compileFinal {
|
||||
private _actor = createHashMap;
|
||||
@ -116,13 +116,11 @@ GVAR(ActorModel) = compileFinal createHashMapObject [[
|
||||
}]
|
||||
]];
|
||||
|
||||
GVAR(ActorBaseStore) = compileFinal ([
|
||||
EGVAR(common,BaseStore),
|
||||
createHashMapFromArray [
|
||||
GVAR(ActorBaseStore) = compileFinal createHashMapFromArray [
|
||||
["#base", EGVAR(common,BaseStore)],
|
||||
["#type", "ActorBaseStore"],
|
||||
["#create", compileFinal {
|
||||
["INFO", "Actor Store Initialized!"] call EFUNC(common,log);
|
||||
true
|
||||
}],
|
||||
["cacheActor", compileFinal {
|
||||
params [["_uid", "", [""]], ["_actor", createHashMap, [createHashMap]]];
|
||||
@ -574,13 +572,7 @@ GVAR(ActorBaseStore) = compileFinal ([
|
||||
|
||||
_self call ["override", [_uid, _finalActor, false]]
|
||||
}]
|
||||
]] call {
|
||||
params ["_base", "_child"];
|
||||
];
|
||||
|
||||
private _merged = +_base;
|
||||
{ _merged set [_x, _y]; } forEach _child;
|
||||
_merged
|
||||
});
|
||||
|
||||
GVAR(ActorStore) = createHashMapObject [GVAR(ActorBaseStore), []];
|
||||
true
|
||||
GVAR(ActorStore) = createHashMapObject [GVAR(ActorBaseStore)];
|
||||
GVAR(ActorStore)
|
||||
|
||||
@ -4,6 +4,8 @@ PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
|
||||
if (isServer) then { "forge_server" callExtension ["surreal:reconnect", []]; };
|
||||
|
||||
GVAR(PlayerBootstrapRegistry) = createHashMap;
|
||||
|
||||
["forge_icom_event", {
|
||||
|
||||
@ -72,12 +72,13 @@ listed for the requested category. `denylist` removes listed classnames from the
|
||||
generated category. Overrides are applied server-side, so checkout validation
|
||||
uses the same prices and descriptions the UI displays.
|
||||
|
||||
`modMode` applies before category filtering. `allowlist` only keeps generated
|
||||
entries that match one of the configured `mods[]`; `denylist` removes matching
|
||||
entries. Each `ModSources` child can define `patches[]` to detect whether the
|
||||
mod is loaded, `addons[]` for config source addon/source mod names or classname
|
||||
prefixes, and `prefixes[]` for classname prefixes. If a mod source defines no
|
||||
patches, it is treated as available and only the source/prefix checks are used.
|
||||
`modMode` applies before category filtering. `dynamic` means no mod-source
|
||||
filtering. `allowlist` only keeps generated entries that match one of the
|
||||
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
|
||||
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
|
||||
for exact config source addon/source mod names, and `prefixes[]` for classname,
|
||||
source addon, or source mod prefixes. If a mod source defines no patches, it is
|
||||
treated as available and only the source/prefix checks are used.
|
||||
|
||||
`units[]` follows the same `dynamic`, `allowlist`, and `denylist` behavior as
|
||||
item and vehicle categories. Unit purchases are immediate spawn grants, not
|
||||
|
||||
@ -111,17 +111,18 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
private _sourceMod = _item getOrDefault ["sourceMod", ""];
|
||||
private _addons = (_self call ["getMissionStoreModSourceValues", [_modID, "addons"]]) apply { toLowerANSI _x };
|
||||
private _prefixes = (_self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]]) apply { toLowerANSI _x };
|
||||
private _matchPrefixes = _addons + _prefixes;
|
||||
private _sourceModLower = toLowerANSI _sourceMod;
|
||||
|
||||
if (_sourceModLower in _addons) exitWith { true };
|
||||
private _sourceAddonMatched = false;
|
||||
{
|
||||
if (_x in _addons) exitWith { _sourceAddonMatched = true; };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_x, _addons]]) exitWith { _sourceAddonMatched = true; };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_x, _matchPrefixes]]) exitWith { _sourceAddonMatched = true; };
|
||||
} forEach _sourceAddons;
|
||||
if (_sourceAddonMatched) exitWith { true };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_className, _addons + _prefixes]]) exitWith { true };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _addons]]) exitWith { true };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_className, _matchPrefixes]]) exitWith { true };
|
||||
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _matchPrefixes]]) exitWith { true };
|
||||
|
||||
false
|
||||
}],
|
||||
|
||||
@ -154,7 +154,7 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
_penMin = _penMin min 0;
|
||||
_penMax = _penMax min 0;
|
||||
|
||||
_timeMin = _timeMin max 1;
|
||||
_timeMin = _timeMin max 0;
|
||||
_timeMax = _timeMax max _timeMin;
|
||||
_medicalSpawnCost = _medicalSpawnCost max 0;
|
||||
_medicalHealCost = _medicalHealCost max 0;
|
||||
|
||||
@ -164,9 +164,13 @@ airports, bus stops, teleport terminals, or any other mission transport system.
|
||||
The framework owns the menu, billing, cargo scan, and movement logic. The
|
||||
mission only needs placed objects and optional arrival markers.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Place transport node objects with these variable names:
|
||||
|
||||
@ -188,7 +192,9 @@ transport_arrival_2
|
||||
transport_arrival_10
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
Objects that should be excluded from the nearby cargo scan, such as the actual
|
||||
boat or transport vehicle used as set dressing, should use:
|
||||
@ -201,7 +207,9 @@ transport_vehicle_2
|
||||
transport_vehicle_10
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
Minimum Eden setup:
|
||||
|
||||
@ -759,6 +767,11 @@ provider preference. It also exposes service pricing for medical spawn, heal,
|
||||
repair, rearm, refuel, and transport defaults. It does not enable or disable
|
||||
generated missions; use the CBA setting for that policy.
|
||||
|
||||
Task time limits can be disabled from the setup UI by turning off the task
|
||||
timer. That stores `timeLimitMin = 0` and `timeLimitMax = 0`, which generated
|
||||
tasks treat as no timer. Positive min/max values enable task timers and are
|
||||
rolled in seconds.
|
||||
|
||||
If mission setup is enabled, the mission manager waits until the setup operator
|
||||
applies settings. Cancel, X, and Escape apply default values from CBA, mission
|
||||
parameters, and `CfgMissions`. There is no timeout that auto-applies defaults.
|
||||
|
||||
@ -227,7 +227,7 @@ Player workflow:
|
||||
1. Stand near a transport point.
|
||||
2. Open the actor interaction menu.
|
||||
3. Select Transport.
|
||||
4. Select a destination from the transport submenu, or select Back to return
|
||||
4. Select a destination from the transport submenu, or select Close to return
|
||||
to the default interaction menu.
|
||||
|
||||

|
||||
|
||||
@ -72,12 +72,24 @@ listed for each category. `denylist` removes listed classnames. Overrides are
|
||||
server-side and are used by both the UI payload and checkout validation.
|
||||
`units[]` uses the same filter behavior as every other category.
|
||||
|
||||
`modMode` applies before category filtering. `allowlist` only keeps generated
|
||||
entries that match one of the configured `mods[]`; `denylist` removes matching
|
||||
entries. Each `ModSources` child can define `patches[]` to detect whether the
|
||||
mod is loaded, `addons[]` for config source addon/source mod names or classname
|
||||
prefixes, and `prefixes[]` for classname prefixes. If a mod source defines no
|
||||
patches, it is treated as available and only the source/prefix checks are used.
|
||||
`modMode` applies before category filtering. `dynamic` means no mod-source
|
||||
filtering. `allowlist` only keeps generated entries that match one of the
|
||||
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
|
||||
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
|
||||
for exact config source addon/source mod names, and `prefixes[]` for classname,
|
||||
source addon, or source mod prefixes. If a mod source defines no patches, it is
|
||||
treated as available and only the source/prefix checks are used.
|
||||
|
||||
For example, to show only RHS-sourced generated inventory:
|
||||
|
||||
```cpp
|
||||
modMode = "allowlist";
|
||||
mods[] = {"rhs"};
|
||||
```
|
||||
|
||||
The matching `class rhs` must exist under `ModSources`. Category `mode` is still
|
||||
applied afterward, so leave `mode = "dynamic"` if the mod filter should be the
|
||||
only inventory filter.
|
||||
|
||||
The current filter is global for the mission. Revisit per-store profile support
|
||||
if individual vendors need different inventories.
|
||||
|
||||
@ -631,6 +631,10 @@ Task time limits use `0` for no limit:
|
||||
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.
|
||||
|
||||
The mission setup UI uses the same rule. Turning off the task timer stores
|
||||
`timeLimitMin = 0` and `timeLimitMax = 0`; turning it on uses the configured
|
||||
positive min/max range for generated tasks.
|
||||
|
||||
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.
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
The transport service provides paid point-to-point travel for players and
|
||||
nearby vehicles or passengers. It is framework-owned: missions only need placed
|
||||
transport objects and arrival markers with the expected variable names.
|
||||
transport objects and optional arrival markers with the expected variable names.
|
||||
|
||||
## Mission Contract
|
||||
|
||||
@ -117,9 +117,9 @@ this setVariable ["transportIncludeCargo", true, true];
|
||||
Only use overrides when the default `transport*` convention or mission-level
|
||||
pricing is not appropriate.
|
||||
|
||||
## Reference Images
|
||||
## Image Checklist
|
||||
|
||||
These screenshots show the default transport setup and player workflow:
|
||||
Replace these placeholder image references after screenshots are captured:
|
||||
|
||||

|
||||
|
||||
@ -142,3 +142,9 @@ These screenshots show the default transport setup and player workflow:
|
||||

|
||||
|
||||

|
||||
|
||||
## Mission-Side Code Requirement
|
||||
|
||||
No mission-side transport service, addAction script, or server event bridge is
|
||||
required. The framework handles menu discovery, destination selection, pricing,
|
||||
billing, cargo movement, and EventBus notifications.
|
||||
|
||||
@ -164,9 +164,13 @@ airports, bus stops, teleport terminals, or any other mission transport system.
|
||||
The framework owns the menu, billing, cargo scan, and movement logic. The
|
||||
mission only needs placed objects and optional arrival markers.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Place transport node objects with these variable names:
|
||||
|
||||
@ -188,7 +192,9 @@ transport_arrival_2
|
||||
transport_arrival_10
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
Objects that should be excluded from the nearby cargo scan, such as the actual
|
||||
boat or transport vehicle used as set dressing, should use:
|
||||
@ -201,7 +207,9 @@ transport_vehicle_2
|
||||
transport_vehicle_10
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
Minimum Eden setup:
|
||||
|
||||
|
||||
@ -226,7 +226,7 @@ Player workflow:
|
||||
1. Stand near a transport point.
|
||||
2. Open the actor interaction menu.
|
||||
3. Select Transport.
|
||||
4. Select a destination from the transport submenu, or select Back to return
|
||||
4. Select a destination from the transport submenu, or select Close to return
|
||||
to the default interaction menu.
|
||||
|
||||

|
||||
|
||||
158
docus/content/1.getting-started/8.git-workflow.md
Normal file
158
docus/content/1.getting-started/8.git-workflow.md
Normal file
@ -0,0 +1,158 @@
|
||||
---
|
||||
title: "Git Workflow"
|
||||
description: "This repository uses `master` as the clean framework branch. Mission folders are kept off `master` so the framework can be versioned without bundling local test missions or playable mission copies."
|
||||
---
|
||||
|
||||
## Workflow Helper
|
||||
|
||||
The repository includes a small helper for the common branch checks and branch
|
||||
switching commands:
|
||||
|
||||
```powershell
|
||||
npm run workflow -- status
|
||||
npm run workflow -- doctor
|
||||
npm run workflow -- switch dev
|
||||
npm run workflow -- switch missions
|
||||
npm run workflow -- start-feature cad-task-request
|
||||
npm run workflow -- release-check
|
||||
```
|
||||
|
||||
The helper refuses branch switches and feature branch creation when the working
|
||||
tree has uncommitted changes. Use the manual Git commands below when you need
|
||||
more control.
|
||||
|
||||
## Branch Roles
|
||||
|
||||
- `master`: framework source, addon code, Rust extension code, docs, tooling,
|
||||
and release tags.
|
||||
- `missions/local-mission-copies`: local mission folders used for testing and
|
||||
mission iteration. This branch is not pushed unless intentionally needed.
|
||||
- `archive/pre-v0.1-history`: read-only archive of the previous full `master`
|
||||
history before the `v0.1.0` baseline cleanup.
|
||||
|
||||
## Daily Framework Work
|
||||
|
||||
Start from the clean framework branch.
|
||||
|
||||
```powershell
|
||||
git switch master
|
||||
git pull
|
||||
git status --short --branch
|
||||
```
|
||||
|
||||
Create a short-lived feature branch for framework work.
|
||||
|
||||
```powershell
|
||||
git switch -c feature/garage-marker-selection
|
||||
```
|
||||
|
||||
Make the change, validate it, then commit.
|
||||
|
||||
```powershell
|
||||
git status --short --branch
|
||||
git add arma/client/addons/garage/functions/fnc_initContextService.sqf
|
||||
git commit -m "Improve garage spawn marker selection"
|
||||
```
|
||||
|
||||
Merge the work back into `master`. Squash merges keep future `master` history
|
||||
compact.
|
||||
|
||||
```powershell
|
||||
git switch master
|
||||
git merge --squash feature/garage-marker-selection
|
||||
git commit -m "Improve garage spawn marker selection"
|
||||
git push
|
||||
```
|
||||
|
||||
Remove the local feature branch when it is no longer needed.
|
||||
|
||||
```powershell
|
||||
git branch -D feature/garage-marker-selection
|
||||
```
|
||||
|
||||
## Mission Work
|
||||
|
||||
Switch to the local mission branch before editing mission folders.
|
||||
|
||||
```powershell
|
||||
git switch missions/local-mission-copies
|
||||
git status --short --branch
|
||||
```
|
||||
|
||||
Mission folders currently tracked on that branch:
|
||||
|
||||
```text
|
||||
arma/forge_framework.Malden
|
||||
arma/forge_pmc_simulator.Tanoa
|
||||
arma/forge_pmc_simulator_v2.Tanoa
|
||||
```
|
||||
|
||||
Commit mission-only changes on the mission branch.
|
||||
|
||||
```powershell
|
||||
git add arma/forge_pmc_simulator.Tanoa
|
||||
git commit -m "Update PMC simulator mission setup"
|
||||
```
|
||||
|
||||
Do not merge the mission branch into `master`. If a mission change becomes
|
||||
framework code, copy only the reusable files or logic onto a framework feature
|
||||
branch created from `master`.
|
||||
|
||||
Example:
|
||||
|
||||
```powershell
|
||||
git switch master
|
||||
git switch -c feature/cad-on-demand-task-request
|
||||
|
||||
# Bring over only the framework files needed from the mission branch.
|
||||
git checkout missions/local-mission-copies -- arma/client/addons/cad/functions/fnc_initUIBridge.sqf
|
||||
git checkout missions/local-mission-copies -- arma/server/addons/cad/XEH_preInit.sqf
|
||||
|
||||
git add arma/client/addons/cad/functions/fnc_initUIBridge.sqf arma/server/addons/cad/XEH_preInit.sqf
|
||||
git commit -m "Add CAD on-demand mission task request bridge"
|
||||
```
|
||||
|
||||
## Release Versioning
|
||||
|
||||
Use tags to mark framework releases.
|
||||
|
||||
Version guideline:
|
||||
|
||||
- Patch, such as `v0.1.1`: fixes and small compatible changes.
|
||||
- Minor, such as `v0.2.0`: new modules or features.
|
||||
- Major, such as `v1.0.0`: stable release line or breaking changes.
|
||||
|
||||
Create a release tag from `master`.
|
||||
|
||||
```powershell
|
||||
git switch master
|
||||
git pull
|
||||
git status --short --branch
|
||||
git tag -a v0.1.1 -m "v0.1.1"
|
||||
git push origin master
|
||||
git push origin v0.1.1
|
||||
```
|
||||
|
||||
## Safety Checks
|
||||
|
||||
Before committing on `master`, check that no mission folders are staged.
|
||||
|
||||
```powershell
|
||||
git status --short --branch
|
||||
```
|
||||
|
||||
On `master`, these paths should not appear:
|
||||
|
||||
```text
|
||||
arma/forge_framework.Malden
|
||||
arma/forge_pmc_simulator.Tanoa
|
||||
arma/forge_pmc_simulator_v2.Tanoa
|
||||
```
|
||||
|
||||
If mission files appear while on `master`, stop and switch to the mission
|
||||
branch before continuing.
|
||||
|
||||
```powershell
|
||||
git switch missions/local-mission-copies
|
||||
```
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "Transport Service Guide"
|
||||
description: "The transport service provides paid point-to-point travel for players and nearby vehicles or passengers. It is framework-owned: missions only need placed transport objects and arrival markers with the expected variable names."
|
||||
description: "The transport service provides paid point-to-point travel for players and nearby vehicles or passengers. It is framework-owned: missions only need placed transport objects and optional arrival markers with the expected variable names."
|
||||
---
|
||||
|
||||
## Mission Contract
|
||||
@ -109,9 +109,9 @@ this setVariable ["transportIncludeCargo", true, true];
|
||||
|
||||
Only use overrides when the default `transport*` convention is not appropriate.
|
||||
|
||||
## Reference Images
|
||||
## Image Checklist
|
||||
|
||||
These screenshots show the default transport setup and player workflow:
|
||||
Replace these placeholder image references after screenshots are captured:
|
||||
|
||||

|
||||
|
||||
@ -134,3 +134,9 @@ These screenshots show the default transport setup and player workflow:
|
||||

|
||||
|
||||

|
||||
|
||||
## Mission-Side Code Requirement
|
||||
|
||||
No mission-side transport service, addAction script, or server event bridge is
|
||||
required. The framework handles menu discovery, destination selection, pricing,
|
||||
billing, cargo movement, and EventBus notifications.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user