This commit is contained in:
2023-04-07 01:39:41 -07:00
parent deb145a7ce
commit 44a353a24b
13 changed files with 694 additions and 245 deletions

View File

@@ -4,7 +4,7 @@ class CfgPatches {
weapons[] = {};
requiredVersion = 0.1;
requiredAddons[] = {};
author[] = {"EagleTrooper and Gary"};
author[] = {"EagleTrooper","Gary","IndigoFox"};
authorUrl = "http://example.com";
};
};
@@ -14,9 +14,11 @@ class CfgFunctions {
class Common {
file = "\RangerMetrics\functions";
class postInit { postInit = 1;};
class log {};
class gather {};
class queue {};
class send {};
class run {};
class checkResults {};
class log {};
};
};
};

View File

@@ -1,13 +1,22 @@
private _threadsToCheck = RangerMetrics_activeThreads;
{
private _threadId = _x;
private _finished = ["RangerMetrics.influx.has_call_finished", [_threadId]] call py3_fnc_callExtension;
if (_finished) then {
_threadsToCheck = _threadsToCheck - [_threadId];
// systemChat str _finished;
if (isNil "_finished") exitWith {
RangerMetrics_activeThreads = RangerMetrics_activeThreads - [_threadId];
[format ["[%1]: Thread %2 not found", RangerMetrics_logPrefix, _threadId], "WARN"] call RangerMetrics_fnc_log;
};
if (_finished isEqualTo []) exitWith {
RangerMetrics_activeThreads = RangerMetrics_activeThreads - [_threadId];
[format ["[%1]: Thread %2 not found", RangerMetrics_logPrefix, _threadId], "WARN"] call RangerMetrics_fnc_log;
};
if (_finished isEqualTo true) then {
RangerMetrics_activeThreads = RangerMetrics_activeThreads - [_threadId];
if (missionNamespace getVariable ["RangerMetrics_debug",false]) then {
private _return = ["RangerMetrics.influx.get_call_value", [_threadId]] call py3_fnc_callExtension;
[format ["Thread result: %1", _extSend], "DEBUG"] call RangerMetrics_fnc_log;
[format ["%1", _return], "DEBUG"] call RangerMetrics_fnc_log;
};
};
} forEach _threadsToCheck;
} forEach RangerMetrics_activeThreads;

View File

@@ -0,0 +1,107 @@
/* ----------------------------------------------------------------------------
Function: CBA_fnc_encodeJSON
Description:
Serializes input to a JSON string. Can handle
- ARRAY
- BOOL
- CONTROL
- GROUP
- LOCATION
- NAMESPACE
- NIL (ANY)
- NUMBER
- OBJECT
- STRING
- TASK
- TEAM_MEMBER
- HASHMAP
- Everything else will simply be stringified.
Parameters:
_object - Object to serialize. <ARRAY, ...>
Returns:
_json - JSON string containing serialized object.
Examples:
(begin example)
private _settings = call CBA_fnc_createNamespace;
_settings setVariable ["enabled", true];
private _json = [_settings] call CBA_fnc_encodeJSON;
(end)
Author:
BaerMitUmlaut
---------------------------------------------------------------------------- */
params ["_object"];
if (isNil "_object") exitWith { "null" };
switch (typeName _object) do {
case "SCALAR";
case "BOOL": {
str _object;
};
case "STRING": {
{
_object = [_object, _x#0, _x#1] call CBA_fnc_replace;
} forEach [
["\", "\\"],
["""", "\"""],
[toString [8], "\b"],
[toString [12], "\f"],
[endl, "\n"],
[toString [10], "\n"],
[toString [13], "\r"],
[toString [9], "\t"]
];
// Stringify without escaping inter string quote marks.
"""" + _object + """"
};
case "ARRAY": {
if ([_object] call CBA_fnc_isHash) then {
private _json = (([_object] call CBA_fnc_hashKeys) apply {
private _name = _x;
private _value = [_object, _name] call CBA_fnc_hashGet;
format ["%1: %2", [_name] call CBA_fnc_encodeJSON, [_value] call CBA_fnc_encodeJSON]
}) joinString ", ";
"{" + _json + "}"
} else {
private _json = (_object apply {[_x] call CBA_fnc_encodeJSON}) joinString ", ";
"[" + _json + "]"
};
};
case "HASHMAP": {
private _json = ((_object toArray false) apply {
_x params ["_key", ["_value", objNull]];
if !(_key isEqualType "") then {
_key = str _key;
};
format ["%1: %2", [_key] call CBA_fnc_encodeJSON, [_value] call CBA_fnc_encodeJSON]
}) joinString ", ";
"{" + _json + "}"
};
default {
if !(typeName _object in (supportInfo "u:allVariables*" apply {_x splitString " " select 1})) exitWith {
[str _object] call CBA_fnc_encodeJSON
};
if (isNull _object) exitWith { "null" };
private _json = ((allVariables _object) apply {
private _name = _x;
private _value = _object getVariable [_name, objNull];
format ["%1: %2", [_name] call CBA_fnc_encodeJSON, [_value] call CBA_fnc_encodeJSON]
}) joinString ", ";
"{" + _json + "}"
};
};

View File

@@ -0,0 +1,83 @@
// function adapted from YAINA by MartinCo at http://yaina.eu
params [["_cba",false,[true]]];
if(missionNamespace getVariable ["RangerMetrics_run",false]) then {
private _startTime = diag_tickTime;
// Mission name
["server", "mission_name", [["source", "onLoadName"]], nil, "string", getMissionConfigValue ["onLoadName", ""]] call RangerMetrics_fnc_queue;
["server", "mission_name", [["source", "missionName"]], nil, "string", missionName] call RangerMetrics_fnc_queue;
["server", "mission_name", [["source", "missionNameSource"]], nil, "string", missionNameSource] call RangerMetrics_fnc_queue;
["server", "mission_name", [["source", "briefingName"]], nil, "string", briefingName] call RangerMetrics_fnc_queue;
["server", "server_uptime", nil, nil, "float", diag_tickTime toFixed 2] call RangerMetrics_fnc_queue;
// Number of local units
["simulation", "entity_count", [["entity_type", "unit"], ["only_local", true]], nil, "int", { local _x } count allUnits] call RangerMetrics_fnc_queue;
["simulation", "entity_count", [["entity_type", "group"], ["only_local", true]], nil, "int", { local _x } count allGroups] call RangerMetrics_fnc_queue;
["simulation", "entity_count", [["entity_type", "vehicles"], ["only_local", true]], nil, "int", { local _x} count vehicles] call RangerMetrics_fnc_queue;
// Server Stats
["simulation", "fps", [["metric", "avg"]], nil, "float", diag_fps toFixed 2] call RangerMetrics_fnc_queue;
["simulation", "fps", [["metric", "avg_min"]], nil, "float", diag_fpsMin toFixed 2] call RangerMetrics_fnc_queue;
["simulation", "mission_time", nil, nil, "float", time toFixed 2] call RangerMetrics_fnc_queue;
// Scripts
private _activeScripts = diag_activeScripts;
["simulation", "script_count", [["execution", "spawn"]], nil, "int", _activeScripts select 0] call RangerMetrics_fnc_queue;
["simulation", "script_count", [["execution", "execVM"]], nil, "int", _activeScripts select 1] call RangerMetrics_fnc_queue;
["simulation", "script_count", [["execution", "exec"]], nil, "int", _activeScripts select 2] call RangerMetrics_fnc_queue;
["simulation", "script_count", [["execution", "execFSM"]], nil, "int", _activeScripts select 3] call RangerMetrics_fnc_queue;
private _pfhCount = if(_cba) then {count CBA_common_perFrameHandlerArray} else {0};
["simulation", "script_count", [["execution", "pfh"]], nil, "int", _pfhCount] call RangerMetrics_fnc_queue;
// Globals if server
if (isServer) then {
// Number of global units
["simulation", "entity_count", [["entity_type", "unit"], ["only_local", false]], nil, "int", count allUnits] call RangerMetrics_fnc_queue;
["simulation", "entity_count", [["entity_type", "group"], ["only_local", false]], nil, "int", count allGroups] call RangerMetrics_fnc_queue;
["simulation", "entity_count", [["entity_type", "vehicle"], ["only_local", false]], nil, "int", count vehicles] call RangerMetrics_fnc_queue;
["simulation", "entity_count", [["entity_type", "player"], ["only_local", false]], nil, "int", count allPlayers] call RangerMetrics_fnc_queue;
};
private _headlessClients = entities "HeadlessClient_F";
{
{
private _stats_fps = diag_fps toFixed 2;
private _stats_fps_min = diag_fpsMin toFixed 2;
["simulation", "fps_hc", [["metric", "avg"]], nil, "float", _stats_fps] remoteExec ["RangerMetrics_fnc_queue", 2];
["simulation", "fps_hc", [["metric", "avg_min"]], nil, "float", _stats_fps_min] remoteExec ["RangerMetrics_fnc_queue", 2];
} remoteExecCall ["bis_fnc_call", owner _x];
} foreach _headlessClients;
/** WORKING HEADLESS CODE COMMENTED OUT TO TRY SOMETHING DIFFERNT
// Headless Clients FPS
// Thanks to CPL.Brostrom.A
private _headlessClients = entities "HeadlessClient_F";
{
{
private _stats_fps = round diag_fps;
["stats.HCfps", _stats_fps] remoteExec ["RangerMetrics_fnc_queue", 2];
} remoteExecCall ["bis_fnc_call", owner _x];
} foreach _headlessClients;
*/
// log the runtime and switch off debug so it doesn't flood the log
if(missionNamespace getVariable ["RangerMetrics_debug",false]) then {
[format ["Run time: %1", diag_tickTime - _startTime], "DEBUG"] call RangerMetrics_fnc_log;
// missionNamespace setVariable ["RangerMetrics_debug",false];
};
};

View File

@@ -1,5 +1,9 @@
params [["_text","Log text invalid",[""]], ["_type","INFO",[""]]];
private _textFormatted = format ["[RangerMetrics] %1: %2", _type, _text];
private _textFormatted = format [
"[%1] %2: %3",
RangerMetrics_logPrefix,
_type,
_text];
if(isServer) then {
diag_log text _textFormatted;

View File

@@ -1,47 +1,74 @@
// function adapted from YAINA by MartinCo at http://yaina.eu
// if (!isServer) exitWith {};
_cba = (isClass(configFile >> "CfgPatches" >> "cba_main"));
RangerMetrics_logPrefix = "RangerMetrics";
RangerMetrics_debug = true;
RangerMetrics_activeThreads = [];
RangerMetrics_messageQueue = createHashMap;
[format ["Instance name: %1", profileName]] call RangerMetrics_fnc_log;
[format ["CBA detected: %1", _cba]] call RangerMetrics_fnc_log;
["Initializing v1.1"] call RangerMetrics_fnc_log;
// _extData = "RangerMetrics" callExtension "loadSettings";
// if (_extData == "0") exitWith {
// ["Extension not found, disabling"] call RangerMetrics_fnc_log;
// RangerMetrics_run = false;
// };
// _extData = parseSimpleArray _extData;
// RangerMetrics_settingsDir = _extData select 0;
// RangerMetrics_settingsLoaded = _extData select 1;
// RangerMetrics_influxURL = _extData select 2;
// [format["InfluxDB URL: %1", RangerMetrics_influxURL]] call RangerMetrics_fnc_log;
// _extVersion = "RangerMetrics" callExtension "version";
// ["Extension version: " + _extVersion] call RangerMetrics_fnc_log;
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if (_name == "RangerMetrics") then {
[parseSimpleArray _data] call RangerMetrics_fnc_log;
private _settingsLoaded = ["RangerMetrics.influx.load_settings", []] call py3_fnc_callExtension;
if (isNil "_settingsLoaded") exitWith {
["Extension not found, disabling"] call RangerMetrics_fnc_log;
RangerMetrics_run = false;
};
if (_settingsLoaded isEqualTo []) then {
if (count _settingsLoaded == 0) exitWith {
["Settings not loaded, disabling"] call RangerMetrics_fnc_log;
RangerMetrics_run = false;
};
}];
if (_settingsLoaded#0 isEqualTo 1) exitWith {
[
format["Settings not loaded, disabling. %1", _settingsLoaded#1],
"ERROR"
] call RangerMetrics_fnc_log;
RangerMetrics_run = false;
};
};
format["Settings loaded: %1", _settingsLoaded#2] call RangerMetrics_fnc_log;
RangerMetrics_settings = _settingsLoaded#2;
// RangerMetrics_settings = createHashMap;
// private _top = createHashMapFromArray _settingsLoaded#2;
// RangerMetrics_settings set [
// "influxDB",
// createHashMapFromArray (_top get "influxDB")
// ];
// RangerMetrics_settings set [
// "arma3",
// createHashMapFromArray (_top get "refreshRateMs")
// ];
["RangerMetrics.influx.connect_to_influx", []] call py3_fnc_callExtension;
// RangerMetrics_run = true;
RangerMetrics_run = true;
// if(_cba) then { // CBA is running, use PFH
// [RangerMetrics_fnc_run, 10, [_cba]] call CBA_fnc_addPerFrameHandler;
// } else { // CBA isn't running, use sleep
// [_cba] spawn {
// params ["_cba"];
// while{true} do {
// [[_cba]] call RangerMetrics_fnc_run; // nested to match CBA PFH signature
// sleep 10;
// };
// addMissionEventHandler ["ExtensionCallback", {
// params ["_name", "_function", "_data"];
// if (_name == "RangerMetrics") then {
// [parseSimpleArray _data] call RangerMetrics_fnc_log;
// };
// };
// }];
if(_cba) then { // CBA is running, use PFH
[{
params ["_args", "_idPFH"];
_args params [["_cba", false]];
[_cba] call RangerMetrics_fnc_gather;
call RangerMetrics_fnc_checkResults;
call RangerMetrics_fnc_send;
// }, (RangerMetrics_settings get "arma3" get "refreshRateMs"), [_cba]] call CBA_fnc_addPerFrameHandler;
}, 1, [_cba]] call CBA_fnc_addPerFrameHandler;
} else { // CBA isn't running, use sleep
[_cba] spawn {
params ["_cba"];
while {true} do {
[_cba] call RangerMetrics_fnc_gather; // nested to match CBA PFH signature
call RangerMetrics_fnc_checkResults;
call RangerMetrics_fnc_send;
// sleep (RangerMetrics_settings get "arma3" get "refreshRateMs");
sleep 1;
};
};
};

View File

@@ -0,0 +1,48 @@
params [
["_bucket", "default", [""]],
"_measurement",
["_tags", nil, [[], nil]],
["_fields", nil, [[], nil]],
"_valueType",
"_value"
];
private _profileName = profileName;
private _prefix = "Arma3";
private _extSend = [
_measurement, // metric name
_valueType, // float or int or bool
];
private _outTags = [ // tags
["profile", _profileName],
["world", toLower worldName]
];
if (!isNil "_tags") then {
{
_outTags pushBack [_x#0, _x#1];
} forEach _tags;
};
_extSend pushBack (_outTags apply {format["tag|%1|%2", _x#0, _x#1]});
_outFields = [ // fields
["server", serverName],
["mission", missionName],
["value", _value]
];
if (!isNil "_fields") then {
{
_outFields pushBack [_x#0, _x#1];
} forEach _fields;
};
_extSend pushBack (_outFields apply {format["field|%1|%2", _x#0, _x#1]});
// add to queue
(RangerMetrics_messageQueue getOrDefault [_bucket, [], true]) pushBack (flatten _extSend);
true

View File

@@ -1,80 +0,0 @@
// function adapted from YAINA by MartinCo at http://yaina.eu
params ["_args"];
_args params [["_cba",false,[true]]];
if(missionNamespace getVariable ["RangerMetrics_run",false]) then {
private _startTime = diag_tickTime;
// Number of local units
["count.units", "int", { local _x } count allUnits] call RangerMetrics_fnc_send;
["count.groups", "int", { local _x } count allGroups] call RangerMetrics_fnc_send;
["count.vehicles", "int", { local _x} count vehicles] call RangerMetrics_fnc_send;
// Server Stats
["stats.fps", "float", diag_fps toFixed 2] call RangerMetrics_fnc_send;
["stats.fpsMin", "float", diag_fpsMin toFixed 2] call RangerMetrics_fnc_send;
["stats.uptime", "float", diag_tickTime toFixed 2] call RangerMetrics_fnc_send;
["stats.missionTime", "float", time toFixed 2] call RangerMetrics_fnc_send;
// Scripts
private _activeScripts = diag_activeScripts;
["scripts.spawn", "int", _activeScripts select 0] call RangerMetrics_fnc_send;
["scripts.execVM", "int", _activeScripts select 1] call RangerMetrics_fnc_send;
["scripts.exec", "int", _activeScripts select 2] call RangerMetrics_fnc_send;
["scripts.execFSM", "int", _activeScripts select 3] call RangerMetrics_fnc_send;
private _pfhCount = if(_cba) then {count CBA_common_perFrameHandlerArray} else {0};
["scripts.pfh", "int", _pfhCount] call RangerMetrics_fnc_send;
// Globals if server
if (isServer) then {
// Number of local units
["count.units", "float", count allUnits, true] call RangerMetrics_fnc_send;
["count.groups", "float", count allGroups, true] call RangerMetrics_fnc_send;
["count.vehicles", "float", count vehicles, true] call RangerMetrics_fnc_send;
["count.players", "float", count allPlayers, true] call RangerMetrics_fnc_send;
};
private _headlessClients = entities "HeadlessClient_F";
{
{
private _stats_fps = diag_fps;
["stats.HCfps", "float", _stats_fps] remoteExec ["RangerMetrics_fnc_send", 2];
} remoteExecCall ["bis_fnc_call", owner _x];
} foreach _headlessClients;
/** WORKING HEADLESS CODE COMMENTED OUT TO TRY SOMETHING DIFFERNT
// Headless Clients FPS
// Thanks to CPL.Brostrom.A
private _headlessClients = entities "HeadlessClient_F";
{
{
private _stats_fps = round diag_fps;
["stats.HCfps", _stats_fps] remoteExec ["RangerMetrics_fnc_send", 2];
} remoteExecCall ["bis_fnc_call", owner _x];
} foreach _headlessClients;
*/
// log the runtime and switch off debug so it doesn't flood the log
if(missionNamespace getVariable ["RangerMetrics_debug",false]) then {
[format ["Run time: %1", diag_tickTime - _startTime], "DEBUG"] call RangerMetrics_fnc_log;
missionNamespace setVariable ["RangerMetrics_debug",false];
};
};

View File

@@ -1,55 +1,54 @@
params ["_metric", "_valueType", "_value", ["_global", false]];
private _profileName = profileName;
private _prefix = "Arma3";
private _locality = [profileName, "global"] select _global;
// InfluxDB settings
// private _connection = "http://indifox.info:8086";
// private _token = "BwOzapPBLZ-lhtrcs3PC2Jk2p7plCC0UckHKxe8AxulYkk9St1q2aloXMW2rDD4X2ufIkx3fwSbEe6ZeJo8ljg==";
// private _org = "ranger-metrics";
// private _bucket = "ranger-metrics";
// private _extSend = format["%1,%2", format["%1,%2,%3,%4,%5,%6", _connection, _token, _org, _bucket, _metricPath, _metric], _value];
private _extSend = [
// _connection,
// _token,
// _org,
// _bucket,
_profileName,
_locality,
missionName,
worldName,
serverName,
_metric,
_valueType,
_value
];
if(missionNamespace getVariable ["RangerMetrics_debug",false]) then {
[format ["Sending a3influx data: %1", _extSend], "DEBUG"] call RangerMetrics_fnc_log;
};
// send the data
private _return = "RangerMetrics" callExtension ["sendToInflux", _extSend];
[{
if(missionNamespace getVariable ["RangerMetrics_debug",false]) then {
[format ["Sending a3influx data: %1", RangerMetrics_messageQueue], "DEBUG"] call RangerMetrics_fnc_log;
};
// shouldn't be possible, the extension should always return even if error
if(isNil "_return") exitWith {
[format ["return was nil (%1)", _extSend], "ERROR"] call RangerMetrics_fnc_log;
false
};
// duplicate the message queue so we can clear it before sending the data
private _extSend = + RangerMetrics_messageQueue;
RangerMetrics_messageQueue = createHashMap;
// extension error codes
// if(_return in ["invalid metric value","malformed, could not find separator"] ) exitWith {
// [format ["%1 (%2)", _return, _extSend], "ERROR"] call RangerMetrics_fnc_log;
// false
// };
{
// for each bucket, send data to extension
private _bucketName = _x;
private _bucketData = _y;
// if (true) exitWith {
// [format ["bucketName: %1", _bucketName], "DEBUG"] call RangerMetrics_fnc_log;
// [format ["bucketData: %1", _bucketData], "DEBUG"] call RangerMetrics_fnc_log;
// };
// success, only show if debug is set
if(missionNamespace getVariable ["RangerMetrics_debug",false]) then {
// _returnArgs = _return splitString (toString [10,32]);
_returnArgs = parseSimpleArray _return;
[format ["a3influx return data: %1",_returnArgs], "DEBUG"] call RangerMetrics_fnc_log;
};
{
_thisItem = _x;
private _return = "RangerMetrics" callExtension ["sendToInflux", flatten [_bucketName, _thisItem]];
true
// shouldn't be possible, the extension should always return even if error
if(isNil "_return") exitWith {
[format ["return was nil (%1)", _extSend], "ERROR"] call RangerMetrics_fnc_log;
false
};
if (typeName _return != "ARRAY") exitWith {
[format ["return was not an array (%1)", _extSend], "ERROR"] call RangerMetrics_fnc_log;
false
};
if (count _return == 0) exitWith {
[format ["return was empty (%1)", _extSend], "ERROR"] call RangerMetrics_fnc_log;
false
};
if (count _return == 2) exitWith {
[format ["return was error (%1)", _extSend], "ERROR"] call RangerMetrics_fnc_log;
false
};
// success, add to list of active threads
// RangerMetrics_activeThreads pushBack (_return select 0);
// success, only show if debug is set
if (missionNamespace getVariable ["RangerMetrics_debug",false]) then {
[format ["a3influx threadId: %1", _return], "DEBUG"] call RangerMetrics_fnc_log;
};
} forEach _bucketData;
} forEach _extSend;
}] call CBA_fnc_execNextFrame;

View File

@@ -0,0 +1,164 @@
// get basic config properties
private _properties = [
["settings_mission_info", [
"author",
"onLoadName",
"onLoadMission",
"loadScreen",
"header",
"onLoadIntro",
"onLoadMissionTime",
"onLoadIntroTime",
"briefingName",
"overviewPicture",
"overviewText",
"overviewTextLocked",
"onBriefingGear",
"onBriefingGroup",
"onBriefingPlan"
]],
["settings_respawn", [
"respawn",
"respawnButton",
"respawnDelay",
"respawnVehicleDelay",
"respawnDialog",
"respawnOnStart",
"respawnTemplates",
"respawnWeapons",
"respawnMagazines",
"reviveMode",
"reviveUnconsciousStateMode",
"reviveRequiredTrait",
"reviveRequiredItems",
"reviveRequiredItemsFakConsumed",
"reviveMedicSpeedMultiplier",
"reviveDelay",
"reviveForceRespawnDelay",
"reviveBleedOutDelay",
"enablePlayerAddRespawn"
]],
["settings_player_ui", [
"overrideFeedback",
"showHUD",
"showCompass",
"showGPS",
"showGroupIndicator",
"showMap",
"showNotePad",
"showPad",
"showWatch",
"showUAVFeed",
"showSquadRadar"
]],
["settings_corpse_and_wreck", [
"corpseManagerMode",
"corpseLimit",
"corpseRemovalMinTime",
"corpseRemovalMaxTime",
"wreckManagerMode",
"wreckLimit",
"wreckRemovalMinTime",
"wreckRemovalMaxTime",
"minPlayerDistance"
]],
["settings_mission_general", [
"aiKills",
"briefing",
"debriefing",
"disableChannels",
"disabledAI",
"disableRandomization",
"enableDebugConsole",
"enableItemsDropping",
"enableTeamSwitch",
"forceRotorLibSimulation",
"joinUnassigned",
"minScore",
"avgScore",
"maxScore",
"onCheat",
"onPauseScript",
"saving",
"scriptedPlayer",
"skipLobby",
"HostDoesNotSkipLobby",
"missionGroup"
]
]
];
private _propertyValues = createHashMap;
{
private _category = _x#0;
private _values = _x#1;
{
private _property = _x;
private _value = (missionConfigFile >> _property) call BIS_fnc_getCfgData;
hint str [_category, _property, _value];
if (!isNil "_value") then {
if (typeName _value == "ARRAY") then {
_value = _value joinString ",";
};
if (isNil {_propertyValues get _category}) then {
_propertyValues set [_category, createHashMap];
};
_propertyValues get _category set [_property, _value];
};
} forEach _values;
} forEach _properties;
// Take the generated hashmap and queue metrics
{
private _measurementCategory = _x;
private _fields = _y;
["config", _measurementCategory, nil, _fields, "int", 0] call RangerMetrics_fnc_queue;
} forEach _propertyValues;
// get all properties in missionConfigFile (recursive)
// private _nextCfgClasses = "true" configClasses (missionConfigFile);
// private _nextCfgProperties = configProperties [missionConfigFile];
// private _cfgProperties = createHashMap;
// while {count _nextCfgClasses > 0} do {
// {
// private _thisConfig = _x;
// private _thisConfigClasses = "true" configClasses _thisConfig;
// _thisCfgProperties = configProperties [_thisConfig, "!isClass _x"];
// _saveHash = createHashMap;
// {
// _propertyCfg = _x;
// _saveHash set [configName _propertyCfg, (_propertyCfg) call BIS_fnc_getCfgData];
// } forEach _thisCfgProperties;
// _hierarchy = (configHierarchy _thisConfig);
// _hierarchy deleteAt 0;
// _hierarchy = _hierarchy apply {configName _x};
// _hierarchyStr = _hierarchy joinString ".";
// _hierarchyStrParent = (_hierarchy select [0, count _hierarchy - 2]) joinString ".";
// systemChat _hierarchyStrParent;
// // if (_cfgProperties get _hierarchyStrParent == nil) then {
// // _cfgProperties set [_hierarchyStrParent, createHashMap];
// // };
// _cfgProperties set [_hierarchyStr, _saveHash];
// // _cfgProperties set [_hierarchy, _saveHash];
// _nextCfgClasses append _thisConfigClasses;
// } forEach _nextCfgClasses;
// _nextCfgClasses = _nextCfgClasses - _cfgClasses;
// };
// text ([_cfgProperties] call RangerMetrics_fnc_encodeJSON);
// iterate through _cfgProperties hashmap and queue metrics
// {
// } forEach _cfgProperties;