implement CBA macros, fix for prod

- using a3go 0.3.2, no longer relies on ext callback for anything except RPT logging and waiting DB connect at postinit
- tested and functional
This commit is contained in:
2023-10-12 15:41:22 -07:00
parent 62fbe8b24c
commit 6cf76d1019
29 changed files with 487 additions and 452 deletions

View File

@@ -1,7 +1,7 @@
#include "script_mod.hpp"
#include "script_component.hpp"
class CfgPatches {
class AttendanceTracker {
class ADDON {
units[] = {};
weapons[] = {};
requiredVersion = 2.10;
@@ -17,20 +17,17 @@ class CfgPatches {
};
class CfgFunctions {
class attendanceTracker {
class ADDON {
class functions {
file = "x\addons\attendancetracker\main\functions";
class postInit {postInit = 1;};
class callbackHandler {postInit = 1;};
class getMissionHash {};
class getMissionInfo {};
class getSettings {};
class getWorldInfo {};
class log {};
class missionLoaded {};
class onPlayerConnected {};
class timestamp {};
class writePlayer {};
class postInit {
file = QPATHTOF(DOUBLES(fnc,postInit).sqf);
postInit = 1;
};
PATHTO_FNC(getMissionInfo);
PATHTO_FNC(getWorldInfo);
PATHTO_FNC(log);
PATHTO_FNC(missionLoaded);
PATHTO_FNC(onPlayerConnected);
};
};
};

View File

@@ -0,0 +1,13 @@
#include "script_component.hpp"
[
["missionName", missionName],
["missionStart", GVAR(missionStart)],
["missionHash", GVAR(missionHash)],
["briefingName", briefingName],
["missionNameSource", missionNameSource],
["onLoadName", getMissionConfigValue ["onLoadName", "Unknown"]],
["author", getMissionConfigValue ["author", "Unknown"]],
["serverName", serverName],
["serverProfile", profileName],
["worldName", toLower worldName]
];

View File

@@ -1,3 +1,5 @@
#include "script_component.hpp"
_world = ( configfile >> "CfgWorlds" >> worldName );
_author = getText( _world >> "author" );
_name = getText ( _world >> "description" );
@@ -5,7 +7,6 @@ _name = getText ( _world >> "description" );
_source = configSourceMod ( _world );
_workshopID = '';
{
if ( ( _x#1 ) == _source ) then {
_workshopID = _x#7;
@@ -13,8 +14,12 @@ _workshopID = '';
};
} foreach getLoadedModsInfo;
if (_workshopID isEqualTo "") then {
_workshopID = "0";
};
// [_name, _author, _workshopID];
_return = createHashMapFromArray [
_return = [
["author", _author],
["workshopID", _workshopID],
["displayName", _name],
@@ -24,5 +29,5 @@ _return = createHashMapFromArray [
["latitude", -1 * getNumber( _world >> "latitude" )],
["longitude", getNumber( _world >> "longitude" )]
];
[format["WorldInfo is: %1", _return]] call attendanceTracker_fnc_log;
["DEBUG", format["WorldInfo is: %1", _return]] call FUNC(log);
_return

31
addons/main/fnc_log.sqf Normal file
View File

@@ -0,0 +1,31 @@
#include "script_component.hpp"
if (!isServer) exitWith {};
if (typeName _this != "ARRAY") exitWith {
diag_log format ["[%1]: Invalid log params: %2", GVAR(logPrefix), _this];
};
params [
["_level", "INFO", [""]],
["_text", "", ["", []]]
];
if (_text isEqualType []) then {
_text = format ["%1", _text];
};
if (
_level == "DEBUG" &&
!GVAR(debug)
) exitWith {};
if (_text isEqualTo "") exitWith {};
diag_log formatText [
"[%1] %2: %3",
GVAR(logPrefix),
_level,
_text
];

View File

@@ -1 +1,3 @@
#include "script_component.hpp"
!(getClientStateNumber <= 5 || getClientStateNumber isEqualTo 11);

View File

@@ -0,0 +1,84 @@
#include "script_component.hpp"
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
["DEBUG", format ["(EventHandler) PlayerConnected fired: %1", _this]] call FUNC(log);
if !(call FUNC(missionLoaded)) exitWith {
["DEBUG", format ["(EventHandler) PlayerConnected: Server is in Mission Asked, likely mission selection state. Skipping.."]] call FUNC(log);
};
private _userInfo = (getUserInfo _idstr);
if ((count _userInfo) isEqualTo 0) exitWith {
["DEBUG", format ["(EventHandler) PlayerConnected: No user info found for %1", _idstr]] call FUNC(log);
};
_userInfo params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"];
if (_isHC) exitWith {
[
"DEBUG",
format [
"(EventHandler) PlayerConnected: %1 is HC, skipping",
_playerID
]
] call FUNC(log);
};
// start CBA PFH
[
"DEBUG",
format [
"(EventHandler) PlayerConnected: Starting CBA PFH for %1",
_playerID
]
] call FUNC(log);
[{
params ["_args", "_handle"];
// every dbUpdateInterval, queue a wait for the mission to be logged
// times out after 30 seconds
// used to ensure joins at start of mission (during db connect) are logged
[{GVAR(missionLogged)}, {
// check if player is still connected
private _hash = _this;
private _clientStateNumber = 0;
private _userInfo = getUserInfo (_hash get "playerId");
if (_userInfo isEqualTo []) exitWith {
["DEBUG", format ["(EventHandler) PlayerConnected: %1 (UID) is no longer connected to the mission, exiting CBA PFH", _hash get "playerUID"]] call FUNC(log);
[_handle] call CBA_fnc_removePerFrameHandler;
};
_clientStateNumber = _userInfo select 6;
if (_clientStateNumber < 6) exitWith {
["DEBUG", format ["(EventHandler) PlayerConnected: %1 (UID) is no longer connected to the mission, exiting CBA PFH", _hash get "playerUID"]] call FUNC(log);
[_handle] call CBA_fnc_removePerFrameHandler;
};
["DEBUG", format [
"(EventHandler) PlayerConnected: %1 (UID) is connected to the mission, logging. data: %2",
_hash get "playerUID",
_hash
]] call FUNC(log);
GVAR(extensionName) callExtension [
":LOG:PRESENCE:", [
_hash
]];
},
_args, // args
30 // timeout
] call CBA_fnc_waitUntilAndExecute;
},
GVAR(updateInterval),
(createHashMapFromArray [ // args
["playerId", _playerID],
["playerUID", _playerUID],
["profileName", _profileName],
["steamName", _steamName],
["isJIP", _jip],
["roleDescription", if (roleDescription _unit isEqualTo "") then {"None"} else {roleDescription _unit}],
["missionHash", GVAR(missionHash)]
])
] call CBA_fnc_addPerFrameHandler;

View File

@@ -0,0 +1,94 @@
#include "script_component.hpp"
if (!isServer) exitWith {};
GVAR(attendanceTracker) = true;
GVAR(debug) = true;
GVAR(logPrefix) = "AttendanceTracker";
GVAR(extensionName) = "AttendanceTracker";
GVAR(missionLogged) = false;
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if !(_name isEqualTo GVAR(extensionName)) exitWith {};
_dataArr = parseSimpleArray _data;
if (count _dataArr isEqualTo 0) exitWith {};
switch (_function) do {
case ":LOG:MISSION:SUCCESS:": {
GVAR(missionLogged) = true;
};
case ":LOG:": {
diag_log formatText[
"[%1] %2",
GVAR(logPrefix),
_dataArr select 0
];
};
default {
["DEBUG", format["%1", _dataArr]] call FUNC(log);
};
};
}];
// LOAD EXTENSION
GVAR(extensionName) callExtension ":START:";
// GET MISSION START TIMESTAMP AND UNIQUE HASH
private _missionHashData = parseSimpleArray ("AttendanceTracker" callExtension ":MISSION:HASH:");
if (count _missionHashData isEqualTo 0) exitWith {
["ERROR", "Failed to get mission hash, exiting"] call FUNC(log);
};
_missionHashData params ["_timestamp", "_hash"];
GVAR(missionStart) = _timestamp;
GVAR(missionHash) = _hash;
// PARSE SETTINGS
private _settings = parseSimpleArray (GVAR(extensionName) callExtension ":GET:SETTINGS:");
if (count _settings isEqualTo 0) exitWith {
["ERROR", "Failed to get settings, exiting"] call FUNC(log);
};
GVAR(settings) = createHashMapFromArray (_settings#0);
GVAR(debug) = GVAR(settings) getOrDefault ["debug", GVAR(debug)];
private _updateInterval = GVAR(settings) getOrDefault ["dbupdateinterval", 90];
// remove duration by removing the last index
_updateInterval = _updateInterval select [0, count _updateInterval - 1];
GVAR(updateInterval) = parseNumber _updateInterval;
// add player connected (to mission) handler
addMissionEventHandler ["PlayerConnected", {
_this call FUNC(onPlayerConnected);
}];
// we'll wait for the end of init (DB connect included) of the extension
// then we'll log the world and mission
// the response to THAT is handled above in the extension callback
// and will set GVAR(missionLogged) true
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if !(_name isEqualTo GVAR(extensionName)) exitWith {};
if !(_function isEqualTo ":READY:") exitWith {};
// LOAD WORLD AND MISSION INFO
GVAR(worldInfo) = call FUNC(getWorldInfo);
GVAR(missionInfo) = call FUNC(getMissionInfo);
["INFO", (GVAR(extensionName) callExtension [
":LOG:MISSION:",
[
GVAR(worldInfo),
GVAR(missionInfo)
]
]) select 0] call FUNC(log);
// remove the handler
removeMissionEventHandler ["ExtensionCallback", _thisEventHandler];
}];

View File

@@ -1,24 +0,0 @@
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if !(_name isEqualTo "AttendanceTracker") exitWith {};
if (ATDebug && _function isNotEqualTo ":LOG:") then {
diag_log format ["Raw callback: %1 _ %2", _function, _data];
};
_dataArr = parseSimpleArray _data;
if (count _dataArr < 1) exitWith {};
switch (_function) do {
case ":LOG:": {
diag_log formatText[
"[Attendance Tracker] %1",
_dataArr select 0
];
};
default {
[format["%1", _dataArr]] call attendanceTracker_fnc_log;
};
};
true;
}];

View File

@@ -1,19 +0,0 @@
addMissionEventHandler ["ExtensionCallback", {
params ["_extension", "_function", "_data"];
if !(_extension isEqualTo "AttendanceTracker") exitWith {};
if !(_function isEqualTo ":MISSION:HASH:") exitWith {};
_dataArr = parseSimpleArray _data;
if (count _dataArr < 1) exitWith {};
_dataArr params ["_startTime", "_hash"];
ATNamespace setVariable ["missionStartTime", call attendanceTracker_fnc_timestamp];
ATNamespace setVariable ["missionHash", _hash];
removeMissionEventHandler [
"ExtensionCallback",
_thisEventHandler
];
}];
"AttendanceTracker" callExtension ":MISSION:HASH:";

View File

@@ -1,12 +0,0 @@
createHashMapFromArray [
["missionName", missionName],
["missionStart", ATNamespace getVariable "missionStartTime"],
["missionHash", ATNamespace getVariable "missionHash"],
["briefingName", briefingName],
["missionNameSource", missionNameSource],
["onLoadName", getMissionConfigValue ["onLoadName", ""]],
["author", getMissionConfigValue ["author", ""]],
["serverName", serverName],
["serverProfile", profileName],
["worldName", toLower worldName]
];

View File

@@ -1,27 +0,0 @@
addMissionEventHandler ["ExtensionCallback", {
params ["_extension", "_function", "_data"];
if !(_extension isEqualTo "AttendanceTracker") exitWith {};
if !(_function isEqualTo ":GET:SETTINGS:") exitWith {};
_dataArr = parseSimpleArray _data;
diag_log format ["AT: Settings received: %1", _dataArr];
if (count _dataArr < 1) exitWith {};
private _settingsJSON = _dataArr select 0;
private _settingsNamespace = [_settingsJSON] call CBA_fnc_parseJSON;
{
ATNamespace setVariable [_x, _settingsNamespace getVariable _x];
} forEach (allVariables _settingsNamespace);
ATDebug = ATNamespace getVariable "debug";
ATUpdateDelay = ATNamespace getVariable "dbUpdateInterval";
// remove last character (unit of time) and parse to number
ATUpdateDelay = parseNumber (ATUpdateDelay select [0, count ATUpdateDelay - 1]);
removeMissionEventHandler [
"ExtensionCallback",
_thisEventHandler
];
}];
"AttendanceTracker" callExtension ":GET:SETTINGS:";

View File

@@ -1,17 +0,0 @@
#include "..\script_mod.hpp"
params [
["_message", "", [""]],
["_level", "INFO", [""]],
"_function"
];
if (isNil "_message") exitWith {false};
if (
missionNamespace getVariable ["ATDebug", true] &&
_level != "WARN" && _level != "ERROR"
) exitWith {};
LOG_SYS(_level, _message);
true;

View File

@@ -1,63 +0,0 @@
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
[format ["(EventHandler) PlayerConnected fired: %1", _this], "DEBUG"] call attendanceTracker_fnc_log;
if !(call attendanceTracker_fnc_missionLoaded) exitWith {
[format ["(EventHandler) PlayerConnected: Server is in Mission Asked, likely mission selection state. Skipping.."], "DEBUG"] call attendanceTracker_fnc_log;
};
private _userInfo = (getUserInfo _idstr);
if ((count _userInfo) isEqualTo 0) exitWith {
[format ["(EventHandler) PlayerConnected: No user info found for %1", _idstr], "DEBUG"] call attendanceTracker_fnc_log;
};
_userInfo params ["_playerID", "_ownerId", "_playerUID", "_profileName", "_displayName", "_steamName", "_clientState", "_isHC", "_adminState", "_networkInfo", "_unit"];
if (_isHC) exitWith {
[
format [
"(EventHandler) PlayerConnected: %1 is HC, skipping",
_playerID
],
"DEBUG"
] call attendanceTracker_fnc_log;
};
// start CBA PFH
[
format [
"(EventHandler) PlayerConnected: Starting CBA PFH for %1",
_playerID
],
"DEBUG"
] call attendanceTracker_fnc_log;
[
{
params ["_args", "_handle"];
// check if player is still connected
_args params ["_playerID", "_playerUID", "_profileName", "_steamName", "_jip", "_roleDescription"];
private _userInfo = getUserInfo _playerID;
private _clientStateNumber = 0;
if (_userInfo isEqualTo []) exitWith {
[_handle] call CBA_fnc_removePerFrameHandler;
};
_clientStateNumber = _userInfo select 6;
if (_clientStateNumber < 6) exitWith {
[format ["(EventHandler) PlayerConnected: %1 (UID) is no longer connected to the mission, exiting CBA PFH", _playerID], "DEBUG"] call attendanceTracker_fnc_log;
[_handle] call CBA_fnc_removePerFrameHandler;
};
_args call attendanceTracker_fnc_writePlayer;
},
ATUpdateDelay,
[
_playerID,
_playerUID,
_profileName,
_steamName,
_jip,
roleDescription _unit
]
] call CBA_fnc_addPerFrameHandler;

View File

@@ -1,61 +0,0 @@
#include "..\script_mod.hpp"
if (!isServer) exitWith {};
ATNamespace = false call CBA_fnc_createNamespace;
ATDebug = true;
"AttendanceTracker" callExtension ":START:";
// we'll wait for the asynchronous init steps of the extension to finish, to confirm we have a DB connection and our config was loaded. If there are errors with either, the extension won't reply and initiate further during this mission.
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if !(_name isEqualTo "AttendanceTracker") exitWith {};
if !(_function isEqualTo ":READY:") exitWith {};
call attendanceTracker_fnc_getMissionHash;
call attendanceTracker_fnc_getSettings;
[
{// wait until settings have been loaded from extension
!isNil {ATNamespace getVariable "missionHash"} &&
!isNil {ATDebug}
},
{
// get world and mission context
ATNamespace setVariable [
"worldContext",
call attendanceTracker_fnc_getWorldInfo
];
ATNamespace setVariable [
"missionContext",
call attendanceTracker_fnc_getMissionInfo
];
// write them to establish DB rows
"AttendanceTracker" callExtension [
":LOG:MISSION:",
[
[ATNamespace getVariable "missionContext"] call CBA_fnc_encodeJSON,
[ATNamespace getVariable "worldContext"] call CBA_fnc_encodeJSON
]
];
// add player connected (to mission) handler
addMissionEventHandler ["PlayerConnected", {
_this call attendanceTracker_fnc_onPlayerConnected;
}];
},
[],
10, // 10 second timeout
{ // timeout code
["Failed to load settings", "ERROR"] call attendanceTracker_fnc_log;
}
] call CBA_fnc_waitUntilAndExecute;
removeMissionEventHandler [
"ExtensionCallback",
_thisEventHandler
];
}];

View File

@@ -1,24 +0,0 @@
// (parseSimpleArray ("AttendanceTracker" callExtension "getTimestamp")) select 0;
// const time.RFC3339 untyped string = "2006-01-02T15:04:05Z07:00"
systemTimeUTC apply {if (_x < 10) then {"0" + str _x} else {str _x}} params [
"_year",
"_month",
"_day",
"_hour",
"_minute",
"_second",
"_millisecond"
];
format[
"%1-%2-%3T%4:%5:%6Z",
_year,
_month,
_day,
_hour,
_minute,
_second
];

View File

@@ -1,21 +0,0 @@
params [
["_playerId", ""],
["_playerUID", ""],
["_profileName", ""],
["_steamName", ""],
["_isJIP", false, [true, false]],
["_roleDescription", ""]
];
private _hash = +(ATNamespace getVariable ["missionContext", createHashMap]);
_hash set ["playerId", _playerId];
_hash set ["playerUID", _playerUID];
_hash set ["profileName", _profileName];
_hash set ["steamName", _steamName];
_hash set ["isJIP", _isJIP];
_hash set ["roleDescription", _roleDescription];
"AttendanceTracker" callExtension [":LOG:PRESENCE:", [[_hash] call CBA_fnc_encodeJSON]];
true;

View File

@@ -0,0 +1,4 @@
#define COMPONENT main
#define COMPONENT_BEAUTIFIED Main
#include "\x\attendancetracker\addons\main\script_mod.hpp"

View File

@@ -1,10 +1,8 @@
#include "script_version.hpp"
#define COMPONENT main
#define COMPONENT_BEAUTIFIED Main
#define MAINPREFIX x
#define PREFIX AttendanceTracker
#define PREFIX attendancetracker
#define PREFIX_BEAUTIFIED AttendanceTracker
#define SUBPREFIX addons
#include "\x\cba\addons\main\script_macros_common.hpp"

View File

@@ -1,7 +1,7 @@
#define MAJOR 1
#define MINOR 1
#define PATCH 0
#define BUILD 20231003
#define BUILD 20231012
#define VERSION 1.1
#define VERSION_STR MAJOR##.##MINOR##.##PATCH##.##BUILD