forge/arma/client/addons/garage/functions/fnc_initContextService.sqf
Jacob Schmidt 32a0baf697 Prioritize explicit garage spawn lanes
- Reduce lane discovery radius to 25
- Separate explicit marker matches from fallback lanes so named lanes win
2026-05-23 08:54:31 -05:00

299 lines
14 KiB
Plaintext

#include "..\script_component.hpp"
/*
* File: fnc_initContextService.sqf
* Author: IDSolutions
* Date: 2026-03-27
* Public: No
*
* Description:
* Initializes the garage context service for local garage context and nearby state.
*
* Arguments:
* None
*
* Return Value:
* Garage context service object [HASHMAP OBJECT]
*
* Example:
* call forge_client_garage_fnc_initContextService;
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(GarageContextServiceBaseClass) = compileFinal createHashMapFromArray [
["#type", "GarageContextServiceBaseClass"],
["#create", compileFinal {
_self set ["lastContext", createHashMap];
_self set ["activeGarageObject", objNull];
}],
["#delete", compileFinal {
_self set ["lastContext", createHashMap];
_self set ["activeGarageObject", objNull];
}],
["setActiveGarageObject", compileFinal {
params [["_garageObject", objNull, [objNull]]];
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) exitWith {
_self set ["activeGarageObject", objNull];
false
};
_self set ["activeGarageObject", _garageObject];
true
}],
["getActiveGarageObject", compileFinal {
private _garageObject = _self getOrDefault ["activeGarageObject", objNull];
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) exitWith { objNull };
if ((player distance2D _garageObject) > 12) exitWith {
_self set ["activeGarageObject", objNull];
objNull
};
_garageObject
}],
["createDefaultContext", compileFinal {
createHashMapFromArray [
["name", "Vehicle Garage"],
["anchorPosition", getPosATL player],
["sourceObject", objNull],
["garageType", ""],
["spawnHeading", getDir player],
["spawnPosition", player getPos [8, getDir player]],
["spawnLanes", createHashMap],
["spawnRadius", 6],
["nearbyRadius", 30],
["laneRadius", 25]
]
}],
["findNearbyGarageObject", compileFinal {
private _nearestGarage = objNull;
private _nearestDistance = 1e10;
{
if (isNull _x || { !(_x getVariable ["isGarage", false]) }) then { continue; };
private _distance = player distance2D _x;
if (_distance < _nearestDistance) then {
_nearestDistance = _distance;
_nearestGarage = _x;
};
} forEach (player nearObjects 12);
_nearestGarage
}],
["resolveGarageName", compileFinal {
params [["_garageObject", objNull, [objNull]]];
if (isNull _garageObject) exitWith { "Vehicle Garage" };
private _displayName = _garageObject getVariable ["garageName", ""];
if (_displayName isNotEqualTo "") exitWith { _displayName };
private _varName = vehicleVarName _garageObject;
if (_varName isEqualTo "") exitWith { "Vehicle Garage" };
_varName
}],
["buildMarkerLane", compileFinal {
params [["_markerName", "", [""]], ["_garageObject", objNull, [objNull]]];
if (_markerName isEqualTo "" || { markerShape _markerName isEqualTo "" }) exitWith { createHashMap };
private _spawnCategory = GVAR(GarageHelperService) call ["inferGarageCategory", [_markerName]];
if (_spawnCategory isEqualTo "") exitWith { createHashMap };
private _spawnPosition = markerPos _markerName;
private _interactionPosition = if (isNull _garageObject) then { _spawnPosition } else { getPosATL _garageObject };
private _markerDistance = if (isNull _garageObject) then { player distance2D _spawnPosition } else { _garageObject distance2D _spawnPosition };
private _garageVarName = if (isNull _garageObject) then { "" } else { toLowerANSI (vehicleVarName _garageObject) };
private _markerKey = toLowerANSI _markerName;
private _isExplicitMatch = _garageVarName isNotEqualTo "" && { (_markerKey find _garageVarName) >= 0 };
createHashMapFromArray [
["name", _markerName],
["isExplicitMatch", _isExplicitMatch],
["interactionPosition", _interactionPosition],
["sourceObject", _garageObject],
["spawnCategory", _spawnCategory],
["spawnHeading", markerDir _markerName],
["spawnPosition", _spawnPosition],
["score", _markerDistance]
]
}],
["discoverSpawnLanes", compileFinal {
params [["_garageObject", objNull, [objNull]]];
private _laneRadius = (_self call ["createDefaultContext", []]) getOrDefault ["laneRadius", 25];
private _explicitLanes = createHashMap;
private _fallbackLanes = createHashMap;
{
private _markerName = _x;
if ((toLowerANSI _markerName find "garage") < 0) then { continue; };
private _entry = _self call ["buildMarkerLane", [_markerName, _garageObject]];
if (_entry isEqualTo createHashMap) then { continue; };
private _spawnPosition = _entry getOrDefault ["spawnPosition", []];
if (_spawnPosition isEqualTo []) then { continue; };
private _distance = if (isNull _garageObject) then { player distance2D _spawnPosition } else { _garageObject distance2D _spawnPosition };
if (_distance > _laneRadius) then { continue; };
private _spawnCategory = _entry getOrDefault ["spawnCategory", ""];
private _laneSet = _fallbackLanes;
if (_entry getOrDefault ["isExplicitMatch", false]) then {
_laneSet = _explicitLanes;
};
private _currentEntry = _laneSet getOrDefault [_spawnCategory, createHashMap];
if (_currentEntry isEqualTo createHashMap || { (_entry getOrDefault ["score", 1e10]) < (_currentEntry getOrDefault ["score", 1e10]) }) then {
_laneSet set [_spawnCategory, _entry];
};
} forEach allMapMarkers;
private _lanes = createHashMap;
{ _lanes set [_x, _y]; } forEach _fallbackLanes;
{ _lanes set [_x, _y]; } forEach _explicitLanes;
_lanes
}],
["selectSpawnLane", compileFinal {
params [
["_lanes", createHashMap, [createHashMap]],
["_preferredCategory", "", [""]],
["_defaultPosition", [], [[]]],
["_defaultHeading", 0, [0]]
];
private _normalizedCategory = GVAR(GarageHelperService) call ["normalizeGarageCategory", [_preferredCategory]];
private _lane = createHashMap;
if (_normalizedCategory isNotEqualTo "") then {
_lane = _lanes getOrDefault [_normalizedCategory, createHashMap];
};
if (_lane isEqualTo createHashMap) then {
{
private _candidate = _lanes getOrDefault [_x, createHashMap];
if (_candidate isNotEqualTo createHashMap) exitWith { _lane = _candidate; };
} forEach ["cars", "armor", "helis", "planes", "naval", "other"];
};
if (_lane isEqualTo createHashMap) then {
_lane = createHashMapFromArray [
["spawnCategory", _normalizedCategory],
["spawnHeading", _defaultHeading],
["spawnPosition", _defaultPosition]
];
};
_lane
}],
["getSpawnLane", compileFinal {
params [["_category", "", [""]], ["_context", createHashMap, [createHashMap]]];
private _resolvedContext = _context;
if (_resolvedContext isEqualTo createHashMap) then {
_resolvedContext = _self call ["getContext", []];
};
private _spawnLanes = _resolvedContext getOrDefault ["spawnLanes", createHashMap];
private _defaultPosition = _resolvedContext getOrDefault ["spawnPosition", getPosATL player];
private _defaultHeading = _resolvedContext getOrDefault ["spawnHeading", getDir player];
_self call ["selectSpawnLane", [_spawnLanes, _category, _defaultPosition, _defaultHeading]]
}],
["getExactSpawnLane", compileFinal {
params [["_category", "", [""]], ["_context", createHashMap, [createHashMap]]];
private _resolvedContext = _context;
if (_resolvedContext isEqualTo createHashMap) then {
_resolvedContext = _self call ["getContext", []];
};
private _normalizedCategory = GVAR(GarageHelperService) call ["normalizeGarageCategory", [_category]];
if (_normalizedCategory isEqualTo "") exitWith { createHashMap };
private _spawnLanes = _resolvedContext getOrDefault ["spawnLanes", createHashMap];
_spawnLanes getOrDefault [_normalizedCategory, createHashMap]
}],
["resolveContext", compileFinal {
params [["_preferredGarageObject", objNull, [objNull]]];
private _context = _self call ["createDefaultContext", []];
private _garageObject = _preferredGarageObject;
if (isNull _garageObject || { !(_garageObject getVariable ["isGarage", false]) }) then {
_garageObject = _self call ["getActiveGarageObject", []];
};
if (isNull _garageObject) then {
_garageObject = _self call ["findNearbyGarageObject", []];
};
private _garageName = _self call ["resolveGarageName", [_garageObject]];
private _garageType = "";
private _anchorPosition = getPosATL player;
private _spawnHeading = getDir player;
private _spawnPosition = player getPos [8, _spawnHeading];
private _spawnLanes = createHashMap;
if (!isNull _garageObject) then {
_garageType = GVAR(GarageHelperService) call ["normalizeGarageCategory", [_garageObject getVariable ["garageType", ""]]];
_anchorPosition = getPosATL _garageObject;
_spawnHeading = getDir _garageObject;
_spawnPosition = _garageObject getPos [8, _spawnHeading];
_spawnLanes = _self call ["discoverSpawnLanes", [_garageObject]];
};
private _selectedLane = _self call ["selectSpawnLane", [_spawnLanes, _garageType, _spawnPosition, _spawnHeading]];
_spawnHeading = _selectedLane getOrDefault ["spawnHeading", _spawnHeading];
_spawnPosition = _selectedLane getOrDefault ["spawnPosition", _spawnPosition];
_context set ["name", _garageName];
_context set ["anchorPosition", _anchorPosition];
_context set ["sourceObject", _garageObject];
_context set ["garageType", _garageType];
_context set ["spawnHeading", _spawnHeading];
_context set ["spawnPosition", _spawnPosition];
_context set ["spawnLanes", _spawnLanes];
_self set ["lastContext", _context];
_context
}],
["getContext", compileFinal {
params [["_preferredGarageObject", objNull, [objNull]]];
_self call ["resolveContext", [_preferredGarageObject]]
}],
["buildNearbyState", compileFinal {
private _context = _self call ["getContext", []];
private _anchorPosition = _context getOrDefault ["anchorPosition", []];
private _spawnPosition = _context getOrDefault ["spawnPosition", getPosATL player];
private _spawnRadius = _context getOrDefault ["spawnRadius", 6];
private _nearbyRadius = _context getOrDefault ["nearbyRadius", 30];
private _nearbyOrigin = [_anchorPosition, _spawnPosition] select (_anchorPosition isEqualTo []);
private _nearbyVehicles = [];
private _nearbyEntities = [];
private _candidateVehicles = [];
{ _candidateVehicles pushBackUnique _x; } forEach (_nearbyOrigin nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]);
{ _candidateVehicles pushBackUnique _x; } forEach ((getPosATL player) nearEntities [["Car", "Tank", "Air", "Ship"], _nearbyRadius]);
{ _candidateVehicles pushBackUnique _x; } forEach (nearestObjects [_nearbyOrigin, ["AllVehicles"], _nearbyRadius]);
{ _candidateVehicles pushBackUnique _x; } forEach (nearestObjects [getPosATL player, ["AllVehicles"], _nearbyRadius]);
{
if (isNull _x) then { continue; };
if (_x isKindOf "CAManBase") then { continue; };
if !(_x isKindOf "Car" || _x isKindOf "Tank" || _x isKindOf "Air" || _x isKindOf "Ship") then { continue; };
_nearbyEntities pushBackUnique _x;
} forEach _candidateVehicles;
{
if (isNull _x) then { continue; };
private _builtVehicle = GVAR(GarageHelperService) call ["buildNearbyVehicle", [_x, _nearbyOrigin]];
if (_builtVehicle isEqualTo createHashMap) then { continue; };
_nearbyVehicles pushBack _builtVehicle;
} forEach _nearbyEntities;
private _nearbyVehiclePairs = _nearbyVehicles apply { [_x getOrDefault ["distance", 0], _x] };
_nearbyVehiclePairs sort true;
_nearbyVehicles = _nearbyVehiclePairs apply { _x param [1, createHashMap] };
private _spawnBlocked = ((_spawnPosition nearEntities [["Car", "Tank", "Air", "Ship"], _spawnRadius]) + (nearestObjects [_spawnPosition, ["Car", "Tank", "Air", "Ship"], _spawnRadius])) isNotEqualTo [];
createHashMapFromArray [["session", createHashMapFromArray [["garageName", _context getOrDefault ["name", "Vehicle Garage"]], ["nearbyCount", count _nearbyVehicles], ["spawnBlocked", _spawnBlocked], ["spawnStatus", ["Ready", "Blocked"] select _spawnBlocked]]], ["nearby", createHashMapFromArray [["vehicles", _nearbyVehicles]]]]
}]
];
GVAR(GarageContextService) = createHashMapObject [GVAR(GarageContextServiceBaseClass)];
GVAR(GarageContextService)