diff --git a/addons/aar/config.cpp b/addons/aar/config.cpp index bda1a0e..9a6d378 100644 --- a/addons/aar/config.cpp +++ b/addons/aar/config.cpp @@ -40,6 +40,8 @@ class CfgFunctions class reportVehiclePositions {}; class sendEvent {}; class sendJson {}; + class sendUnitPosition {}; + class sendVehiclePosition {}; class serializeJson {}; class serializeMission {}; class serializePlayer {}; diff --git a/addons/aar/functions/fn_init.sqf b/addons/aar/functions/fn_init.sqf index 084376c..c395a25 100644 --- a/addons/aar/functions/fn_init.sqf +++ b/addons/aar/functions/fn_init.sqf @@ -72,11 +72,6 @@ addMissionEventHandler ["MPEnded", { [] call anrop_aar_fnc_eventMissionEnded }]; // Periodically send unit positions if (anrop_aar_position_reporting > 0) then { - [] spawn { - anrop_aar_position_reporting call anrop_aar_fnc_reportUnitPositions; - }; - - [] spawn { - anrop_aar_position_reporting call anrop_aar_fnc_reportVehiclePositions; - }; + [anrop_aar_fnc_reportUnitPositions, anrop_aar_position_reporting, []] call CBA_fnc_addPerFrameHandler; + [anrop_aar_fnc_reportVehiclePositions, anrop_aar_position_reporting, []] call CBA_fnc_addPerFrameHandler; }; diff --git a/addons/aar/functions/fn_reportUnitPositions.sqf b/addons/aar/functions/fn_reportUnitPositions.sqf index 5419b27..0e9a6e0 100644 --- a/addons/aar/functions/fn_reportUnitPositions.sqf +++ b/addons/aar/functions/fn_reportUnitPositions.sqf @@ -1,39 +1,6 @@ -private "_unitCacheKey"; -_unitCacheKey = "anrop_aar_unit_cache"; +private _allUnits = allUnits; +_allUnits append allDead; -while { true } do { - private _reportUnit = { - params ["_reportedUnit"]; - - private _name = _reportedUnit call anrop_aar_fnc_getUnitName; - private _uid = ""; - if (isPlayer _reportedUnit) then { - _uid = getPlayerUID _reportedUnit; - }; - private _player = [_name, _uid] call anrop_aar_fnc_serializePlayer; - private _unit = _reportedUnit call anrop_aar_fnc_serializeUnit; - - private _arr = ["object", - ["type", ["string", "UnitPosition"]], - ["player", _player], - ["unit", _unit] - ]; - - private _cached = _reportedUnit getVariable [_unitCacheKey, ""]; - - private _serialized = _arr call anrop_aar_fnc_serializeJson; - if (_serialized != _cached) then { - _reportedUnit setVariable [_unitCacheKey, _serialized]; - _serialized call anrop_aar_fnc_sendJson; - }; - }; - - private _allUnits = allUnits; - _allUnits append allDead; - - { - [_x] call _reportUnit; - } forEach _allUnits; - - sleep _this; -}; +{ + [_x] call anrop_aar_fnc_sendUnitPosition; +} forEach _allUnits; diff --git a/addons/aar/functions/fn_reportVehiclePositions.sqf b/addons/aar/functions/fn_reportVehiclePositions.sqf index 23fb8fc..f1955eb 100644 --- a/addons/aar/functions/fn_reportVehiclePositions.sqf +++ b/addons/aar/functions/fn_reportVehiclePositions.sqf @@ -1,29 +1,3 @@ -private "_vehicleCacheKey"; -_vehicleCacheKey = "anrop_aar_vehicle_cache"; - -while { true } do { - private _reportVehicle = { - params ["_reportedVehicle"]; - - private _vehicle = _reportedVehicle call anrop_aar_fnc_serializeVehicle; - - private "_arr"; - _arr = ["object", - ["type", ["string", "VehiclePosition"]], - ["vehicle", _vehicle] - ]; - - private _cached = _reportedVehicle getVariable [_vehicleCacheKey, ""];; - - private _serialized = _arr call anrop_aar_fnc_serializeJson; - if (_serialized != _cached) then { - _reportedVehicle setVariable [_vehicleCacheKey, _serialized]; - _serialized call anrop_aar_fnc_sendJson; - }; - }; - - { - _x call _reportVehicle - } forEach vehicles; - sleep _this; -}; +{ + [_x] call anrop_aar_fnc_sendVehiclePosition; +} forEach vehicles; diff --git a/addons/aar/functions/fn_sendUnitPosition.sqf b/addons/aar/functions/fn_sendUnitPosition.sqf new file mode 100644 index 0000000..a947dec --- /dev/null +++ b/addons/aar/functions/fn_sendUnitPosition.sqf @@ -0,0 +1,21 @@ +params ["_unit"]; + +private _id = netId _unit; +private _lifeState = lifeState _unit; +private _name = _unit call anrop_aar_fnc_getUnitName; +private _dir = direction _unit; +(getPosASL _unit) params ["_posX", "_posY", "_posZ"]; +private _side = side _unit; + +private _uid = ""; +if (isPlayer _unit) then { + _uid = getPlayerUID _unit; +}; + +private _vehicleId = ""; +if (vehicle _unit != _unit) then { + _vehicleId = netId vehicle _unit; +}; + +anrop_aar_extension callExtension ["unitPosition", [_id, _lifeState, _name, _dir, _posX, _posY, _posZ, _side, _uid, _vehicleId]]; + diff --git a/addons/aar/functions/fn_sendVehiclePosition.sqf b/addons/aar/functions/fn_sendVehiclePosition.sqf new file mode 100644 index 0000000..ea2f19a --- /dev/null +++ b/addons/aar/functions/fn_sendVehiclePosition.sqf @@ -0,0 +1,10 @@ +params ["_vehicle"]; + +private _id = netId _vehicle; +private _name = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "displayName"); +private _dir = direction _vehicle; +(getPosASL _vehicle) params ["_posX", "_posY", "_posZ"]; +private _side = str side _vehicle; +private _simulation = getText (configFile >> "CfgVehicles" >> typeOf _vehicle >> "simulation"); + +anrop_aar_extension callExtension ["vehiclePosition", [_id, _name, _dir, _posX, _posY, _posZ, _side, _simulation]]; diff --git a/src/lib/ArgsProcessor.cpp b/src/lib/ArgsProcessor.cpp new file mode 100644 index 0000000..338355d --- /dev/null +++ b/src/lib/ArgsProcessor.cpp @@ -0,0 +1,112 @@ +#include "ArgsProcessor.hpp" +#include "Utils.hpp" + +ArgsProcessor::ArgsProcessor(Organizer *organizer) { + this->organizer = organizer; +} + +ArgsProcessor::argsProcessed ArgsProcessor::processUnitPosition(const char **argv, int argc) { + std::string id(*argv++); + std::string lifeState(*argv++); + std::string name(*argv++); + auto dir = atof(*argv++); + auto posX = atof(*argv++); + auto posY = atof(*argv++); + auto posZ = atof(*argv++); + std::string side(*argv++); + std::string uid(*argv++); + std::string vehicleId(*argv++); + + Utils::unquoteArmaString(&id); + Utils::unquoteArmaString(&lifeState); + Utils::unquoteArmaString(&name); + Utils::unquoteArmaString(&side); + Utils::unquoteArmaString(&uid); + Utils::unquoteArmaString(&vehicleId); + + nlohmann::json j; + j["type"] = "UnitPosition"; + j["player"]["name"] = name; + j["player"]["uid"] = uid; + j["unit"]["id"] = id; + j["unit"]["life_state"] = lifeState; + j["unit"]["name"] = name; + j["unit"]["position"]["dir"] = dir; + j["unit"]["position"]["x"] = posX; + j["unit"]["position"]["y"] = posY; + j["unit"]["position"]["z"] = posZ; + j["unit"]["side"] = side; + + if (!vehicleId.empty()) { + j["unit"]["vehicle_id"] = vehicleId; + } + + auto json_str = j.dump(); + + auto cacheLookup = unitsCache.find(id); + if (cacheLookup != unitsCache.end()) { + auto cached = cacheLookup->second; + + if (json_str.compare(cached) == 0) { + return ArgsProcessor::EVENT_CACHED; + } + } + + unitsCache[id] = json_str; + + EventManager::event_added result = this->organizer->addEvent(json_str); + + if (result == EventManager::EVENT_OK) { + return ArgsProcessor::EVENT_OK; + } else { + return ArgsProcessor::EVENT_ERROR; + } +} + +ArgsProcessor::argsProcessed ArgsProcessor::processVehiclePosition(const char **argv, int argc) { + std::string id(*argv++); + std::string name(*argv++); + auto dir = atof(*argv++); + auto posX = atof(*argv++); + auto posY = atof(*argv++); + auto posZ = atof(*argv++); + std::string side(*argv++); + std::string simulation(*argv++); + + Utils::unquoteArmaString(&id); + Utils::unquoteArmaString(&name); + Utils::unquoteArmaString(&side); + Utils::unquoteArmaString(&simulation); + + nlohmann::json j; + j["type"] = "VehiclePosition"; + j["vehicle"]["id"] = id; + j["vehicle"]["name"] = name; + j["vehicle"]["position"]["dir"] = dir; + j["vehicle"]["position"]["x"] = posX; + j["vehicle"]["position"]["y"] = posY; + j["vehicle"]["position"]["z"] = posZ; + j["vehicle"]["side"] = side; + j["vehicle"]["simulation"] = simulation; + + auto json_str = j.dump(); + + auto cacheLookup = vehicleCache.find(id); + if (cacheLookup != vehicleCache.end()) { + auto cached = cacheLookup->second; + + if (json_str.compare(cached) == 0) { + return ArgsProcessor::EVENT_CACHED; + } + } + + vehicleCache[id] = json_str; + + EventManager::event_added result = this->organizer->addEvent(json_str); + + if (result == EventManager::EVENT_OK) { + return ArgsProcessor::EVENT_OK; + } else { + return ArgsProcessor::EVENT_ERROR; + } +} diff --git a/src/lib/ArgsProcessor.hpp b/src/lib/ArgsProcessor.hpp new file mode 100644 index 0000000..8731e09 --- /dev/null +++ b/src/lib/ArgsProcessor.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "Organizer.hpp" + +class ArgsProcessor { +public: + enum argsProcessed {EVENT_OK, EVENT_ERROR, EVENT_CACHED}; + + ArgsProcessor(Organizer *organizer); + + ArgsProcessor::argsProcessed processUnitPosition(const char **argv, int argc); + ArgsProcessor::argsProcessed processVehiclePosition(const char **argv, int argc); +private: + Organizer *organizer; + std::map unitsCache; + std::map vehicleCache; +}; diff --git a/src/lib/Utils.cpp b/src/lib/Utils.cpp new file mode 100644 index 0000000..ac103b0 --- /dev/null +++ b/src/lib/Utils.cpp @@ -0,0 +1,31 @@ +#include "Utils.hpp" + +void Utils::unquoteArmaString(std::string *s) { + if (s->size() > 0) { + if (s->front() == '"') + s->erase(0, 1); + } + + if (s->size() > 0) { + if (s->back() == '"') { + s->erase(s->size() - 1); + } + } + + if (s->size() > 0) { + bool lastQuote = false; + for (std::string::iterator it = s->begin(); it != s->end(); it++) { + if (*it == '"') { + if (!lastQuote) { + lastQuote = true; + } else { + s->erase(it); + it--; + lastQuote = false; + } + } else { + lastQuote = false; + } + } + } +}; diff --git a/src/lib/Utils.hpp b/src/lib/Utils.hpp new file mode 100644 index 0000000..afb1963 --- /dev/null +++ b/src/lib/Utils.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +class Utils { +public: + static void unquoteArmaString(std::string *s); +}; diff --git a/src/lib/main.cpp b/src/lib/main.cpp index f087184..9b08180 100755 --- a/src/lib/main.cpp +++ b/src/lib/main.cpp @@ -1,18 +1,24 @@ #include +#include #include "Config.hpp" +#include "ArgsProcessor.hpp" #include "Organizer.hpp" +#include "Utils.hpp" using namespace std; Config config; Organizer organizer; +ArgsProcessor eventProcessor(&organizer); extern "C" { #ifdef WIN32 __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function); + __declspec (dllexport) int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **argv, int argc); #else void RVExtension(char *output, int outputSize, const char *function); + int RVExtensionArgs(char *output, int outputSize, const char *function, const char **argv, int argc); #endif } @@ -68,3 +74,35 @@ void RVExtension(char *output, int outputSize, const char *function) } } } + +#ifdef WIN32 +int __stdcall RVExtensionArgs(char *output, int outputSize, const char *function, const char **argv, int argc) +#else +int RVExtensionArgs(char *output, int outputSize, const char *function, const char **argv, int argc) +#endif +{ + std::string s_function(function); + if (s_function == "unitPosition") { + auto status = eventProcessor.processUnitPosition(argv, argc); + + if (status == ArgsProcessor::EVENT_OK) { + strncpy(output, "OK", outputSize); + } else if (status == ArgsProcessor::EVENT_CACHED) { + strncpy(output, "CACHED", outputSize); + } else if (status == ArgsProcessor::EVENT_ERROR) { + strncpy(output, "ERROR", outputSize); + } + } else if (s_function == "vehiclePosition") { + auto status = eventProcessor.processVehiclePosition(argv, argc); + + if (status == ArgsProcessor::EVENT_OK) { + strncpy(output, "OK", outputSize); + } else if (status == ArgsProcessor::EVENT_CACHED) { + strncpy(output, "CACHED", outputSize); + } else if (status == ArgsProcessor::EVENT_ERROR) { + strncpy(output, "ERROR", outputSize); + } + } + + return 0; +}