Splitted weapons and units managers

This commit is contained in:
Pax1601
2023-07-27 16:27:59 +02:00
parent 875f3ebe68
commit 0150ae9df1
38 changed files with 5616 additions and 4883 deletions

View File

@@ -1,6 +1,73 @@
#pragma once
#include "framework.h"
namespace DataIndex {
enum DataIndexes {
startOfData = 0,
category,
alive,
human,
controlled,
coalition,
country,
name,
unitName,
groupName,
state,
task,
hasTask,
position,
speed,
heading,
isTanker,
isAWACS,
onOff,
followRoads,
fuel,
desiredSpeed,
desiredSpeedType,
desiredAltitude,
desiredAltitudeType,
leaderID,
formationOffset,
targetID,
targetPosition,
ROE,
reactionToThreat,
emissionsCountermeasures,
TACAN,
radio,
generalSettings,
ammo,
contacts,
activePath,
isLeader,
lastIndex,
endOfData = 255
};
}
namespace State
{
enum States
{
NONE = 0,
IDLE,
REACH_DESTINATION,
ATTACK,
FOLLOW,
LAND,
REFUEL,
AWACS,
TANKER,
BOMB_POINT,
CARPET_BOMB,
BOMB_BUILDING,
FIRE_AT_AREA
};
};
#pragma pack(push, 1)
namespace DataTypes {
struct TACAN

View File

@@ -13,72 +13,6 @@ using namespace std::chrono;
#define TASK_CHECK_INIT_VALUE 10
namespace DataIndex {
enum DataIndexes {
startOfData = 0,
category,
alive,
human,
controlled,
coalition,
country,
name,
unitName,
groupName,
state,
task,
hasTask,
position,
speed,
heading,
isTanker,
isAWACS,
onOff,
followRoads,
fuel,
desiredSpeed,
desiredSpeedType,
desiredAltitude,
desiredAltitudeType,
leaderID,
formationOffset,
targetID,
targetPosition,
ROE,
reactionToThreat,
emissionsCountermeasures,
TACAN,
radio,
generalSettings,
ammo,
contacts,
activePath,
isLeader,
lastIndex,
endOfData = 255
};
}
namespace State
{
enum States
{
NONE = 0,
IDLE,
REACH_DESTINATION,
ATTACK,
FOLLOW,
LAND,
REFUEL,
AWACS,
TANKER,
BOMB_POINT,
CARPET_BOMB,
BOMB_BUILDING,
FIRE_AT_AREA
};
};
class Unit
{
public:

View File

@@ -1,13 +1,107 @@
#pragma once
#include "unit.h"
#include "framework.h"
#include "utils.h"
#include "dcstools.h"
#include "luatools.h"
#include "measure.h"
#include "logger.h"
#include "commands.h"
#include "datatypes.h"
class Weapon : public Unit
#include <chrono>
using namespace std::chrono;
class Weapon
{
public:
Weapon(json::value json, unsigned int ID);
~Weapon();
/********** Methods **********/
void initialize(json::value json);
void update(json::value json, double dt);
unsigned int getID() { return ID; }
void getData(stringstream& ss, unsigned long long time);
void triggerUpdate(unsigned char datumIndex);
bool hasFreshData(unsigned long long time);
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
/********** Setters **********/
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); }
virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); }
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
/********** Getters **********/
virtual string getCategory() { return category; };
virtual bool getAlive() { return alive; }
virtual unsigned char getCoalition() { return coalition; }
virtual string getName() { return name; }
virtual Coords getPosition() { return position; }
virtual double getSpeed() { return speed; }
virtual double getHeading() { return heading; }
protected:
/* Weapons are not controllable and have no AIloop */
virtual void AIloop() {};
unsigned int ID;
string category;
bool alive = false;
unsigned char coalition = NULL;
string name = "";
Coords position = Coords(NULL);
double speed = NULL;
double heading = NULL;
/********** Other **********/
map<unsigned char, unsigned long long> updateTimeMap;
/********** Private methods **********/
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
const unsigned short size = datumValue.size();
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
ss << datumValue;
}
/********** Template methods **********/
template <typename T>
void updateValue(T& value, T& newValue, unsigned char datumIndex)
{
if (newValue != value)
{
triggerUpdate(datumIndex);
value = newValue;
}
}
template <typename T>
void appendNumeric(stringstream& ss, const unsigned char& datumIndex, T& datumValue) {
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&datumValue, sizeof(T));
}
template <typename T>
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
const unsigned short size = datumValue.size();
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el : datumValue)
ss.write((const char*)&el, sizeof(T));
}
template <typename T>
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
const unsigned short size = datumValue.size();
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el : datumValue)
ss.write((const char*)&el, sizeof(T));
}
};
class Missile : public Weapon

View File

@@ -0,0 +1,21 @@
#pragma once
#include "framework.h"
#include "dcstools.h"
class Weapon;
class WeaponsManager
{
public:
WeaponsManager(lua_State* L);
~WeaponsManager();
map<unsigned int, Weapon*>& getWeapons() { return weapons; };
Weapon* getWeapon(unsigned int ID);
void update(json::value& missionData, double dt);
void getWeaponData(stringstream& ss, unsigned long long time);
private:
map<unsigned int, Weapon*> weapons;
};

View File

@@ -2,6 +2,7 @@
#include "logger.h"
#include "defines.h"
#include "unitsManager.h"
#include "weaponsManager.h"
#include "server.h"
#include "scheduler.h"
#include "scriptLoader.h"
@@ -9,11 +10,13 @@
#include <chrono>
using namespace std::chrono;
auto lastUpdate = std::chrono::system_clock::now();
auto lastUnitsUpdate = std::chrono::system_clock::now();
auto lastWeaponsUpdate = std::chrono::system_clock::now();
auto lastExecution = std::chrono::system_clock::now();
/* Singleton objects */
UnitsManager* unitsManager = nullptr;
WeaponsManager* weaponsManager = nullptr;
Server* server = nullptr;
Scheduler* scheduler = nullptr;
@@ -38,6 +41,7 @@ extern "C" DllExport int coreDeinit(lua_State* L)
server->stop(L);
delete unitsManager;
delete weaponsManager;
delete server;
delete scheduler;
@@ -51,6 +55,7 @@ extern "C" DllExport int coreInit(lua_State* L)
{
sessionHash = random_string(16);
unitsManager = new UnitsManager(L);
weaponsManager = new WeaponsManager(L);
server = new Server(L);
scheduler = new Scheduler(L);
@@ -101,15 +106,36 @@ extern "C" DllExport int coreUnitsData(lua_State * L)
lua_getfield(L, -1, "unitsData");
luaTableToJSON(L, -1, unitsData);
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUpdate;
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUnitsUpdate;
if (unitsData.has_object_field(L"units")) {
unitsManager->update(unitsData[L"units"], updateDuration.count());
}
lastUpdate = std::chrono::system_clock::now();
lastUnitsUpdate = std::chrono::system_clock::now();
return(0);
}
extern "C" DllExport int coreWeaponssData(lua_State * L)
{
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
json::value weaponsData = json::value::object();
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "weaponsData");
luaTableToJSON(L, -1, weaponsData);
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastWeaponsUpdate;
if (weaponsData.has_object_field(L"weapons")) {
weaponsManager->update(weaponsData[L"weapons"], updateDuration.count());
}
lastWeaponsUpdate = std::chrono::system_clock::now();
return(0);
}
extern "C" DllExport int coreMissionData(lua_State * L)
{

View File

@@ -2,6 +2,7 @@
#include "logger.h"
#include "defines.h"
#include "unitsManager.h"
#include "weaponsManager.h"
#include "scheduler.h"
#include "luatools.h"
#include <exception>
@@ -13,6 +14,7 @@ using namespace std::chrono;
using namespace base64;
extern UnitsManager* unitsManager;
extern WeaponsManager* weaponsManager;
extern Scheduler* scheduler;
extern json::value missionData;
extern mutex mutexLock;
@@ -94,7 +96,7 @@ void Server::handle_get(http_request request)
if (path.size() > 0)
{
string URI = to_string(path[0]);
/* Units data. This is the only binary format data transmitted, all others are transmitted as text json for simplicity */
/* Units data */
if (URI.compare(UNITS_URI) == 0)
{
unsigned long long updateTime = ms.count();
@@ -103,8 +105,16 @@ void Server::handle_get(http_request request)
unitsManager->getUnitData(ss, time);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
else if (URI.compare(WEAPONS_URI) == 0)
{
unsigned long long updateTime = ms.count();
stringstream ss;
ss.write((char*)&updateTime, sizeof(updateTime));
weaponsManager->getWeaponData(ss, time);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
else {
/* Logs data*/
/* Logs data */
if (URI.compare(LOGS_URI) == 0)
{
auto logs = json::value::object();

View File

@@ -17,7 +17,7 @@ extern Scheduler* scheduler;
UnitsManager::UnitsManager(lua_State* L)
{
LogInfo(L, "Units Factory constructor called successfully");
LogInfo(L, "Units Manager constructor called successfully");
}
UnitsManager::~UnitsManager()

View File

@@ -4,19 +4,94 @@
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsmanager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
#include <chrono>
using namespace std::chrono;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
Weapon::Weapon(json::value json, unsigned int ID) :
ID(ID)
{
log("Creating weapon with ID: " + to_string(ID));
}
/* Weapon */
Weapon::Weapon(json::value json, unsigned int ID) : Unit(json, ID)
Weapon::~Weapon()
{
};
}
void Weapon::initialize(json::value json)
{
if (json.has_string_field(L"name"))
setName(to_string(json[L"name"]));
if (json.has_number_field(L"coalitionID"))
setCoalition(json[L"coalitionID"].as_number().to_int32());
update(json, 0);
}
void Weapon::update(json::value json, double dt)
{
if (json.has_object_field(L"position"))
{
setPosition({
json[L"position"][L"lat"].as_number().to_double(),
json[L"position"][L"lng"].as_number().to_double(),
json[L"position"][L"alt"].as_number().to_double()
});
}
if (json.has_number_field(L"heading"))
setHeading(json[L"heading"].as_number().to_double());
if (json.has_number_field(L"speed"))
setSpeed(json[L"speed"].as_number().to_double());
if (json.has_boolean_field(L"isAlive"))
setAlive(json[L"isAlive"].as_bool());
}
bool Weapon::checkFreshness(unsigned char datumIndex, unsigned long long time) {
auto it = updateTimeMap.find(datumIndex);
if (it == updateTimeMap.end())
return false;
else
return it->second > time;
}
bool Weapon::hasFreshData(unsigned long long time) {
for (auto it : updateTimeMap)
if (it.second > time)
return true;
return false;
}
void Weapon::getData(stringstream& ss, unsigned long long time)
{
const unsigned char endOfData = DataIndex::endOfData;
ss.write((const char*)&ID, sizeof(ID));
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
{
if (checkFreshness(datumIndex, time)) {
switch (datumIndex) {
case DataIndex::category: appendString(ss, datumIndex, category); break;
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
case DataIndex::name: appendString(ss, datumIndex, name); break;
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
}
}
}
ss.write((const char*)&endOfData, sizeof(endOfData));
}
void Weapon::triggerUpdate(unsigned char datumIndex) {
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
/* Missile */
Missile::Missile(json::value json, unsigned int ID) : Weapon(json, ID)

View File

@@ -0,0 +1,65 @@
#include "framework.h"
#include "weaponsManager.h"
#include "logger.h"
#include "weapon.h"
#include "scheduler.h"
#include "base64.hpp"
using namespace base64;
WeaponsManager::WeaponsManager(lua_State* L)
{
LogInfo(L, "Weapons Manager constructor called successfully");
}
WeaponsManager::~WeaponsManager()
{
}
Weapon* WeaponsManager::getWeapon(unsigned int ID)
{
if (weapons.find(ID) == weapons.end()) {
return nullptr;
}
else {
return weapons[ID];
}
}
void WeaponsManager::update(json::value& json, double dt)
{
for (auto const& p : json.as_object())
{
unsigned int ID = std::stoi(p.first);
if (weapons.count(ID) == 0)
{
json::value value = p.second;
if (value.has_string_field(L"category")) {
string category = to_string(value[L"category"].as_string());
if (category.compare("Missile") == 0)
weapons[ID] = dynamic_cast<Weapon*>(new Missile(p.second, ID));
else if (category.compare("Bomb") == 0)
weapons[ID] = dynamic_cast<Weapon*>(new Bomb(p.second, ID));
/* Initialize the weapon if creation was successfull */
if (weapons.count(ID) != 0) {
weapons[ID]->update(p.second, dt);
weapons[ID]->initialize(p.second);
}
}
}
else {
/* Update the weapon if present*/
if (weapons.count(ID) != 0)
weapons[ID]->update(p.second, dt);
}
}
}
void WeaponsManager::getWeaponData(stringstream& ss, unsigned long long time)
{
for (auto const& p : weapons)
p.second->getData(ss, time);
}

View File

@@ -9,11 +9,13 @@ typedef int(__stdcall* f_coreInit)(lua_State* L);
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
typedef int(__stdcall* f_coreFrame)(lua_State* L);
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
typedef int(__stdcall* f_coreWeaponsData)(lua_State* L);
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
f_coreInit coreInit = nullptr;
f_coreDeinit coreDeinit = nullptr;
f_coreFrame coreFrame = nullptr;
f_coreUnitsData coreUnitsData = nullptr;
f_coreWeaponsData coreWeaponsData = nullptr;
f_coreMissionData coreMissionData = nullptr;
static int onSimulationStart(lua_State* L)
@@ -74,6 +76,13 @@ static int onSimulationStart(lua_State* L)
goto error;
}
coreWeaponsData = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreWeaponsData");
if (!coreWeaponsData)
{
LogError(L, "Error getting coreWeaponsData ProcAddress from DLL");
goto error;
}
coreMissionData = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreMissionData");
if (!coreMissionData)
{
@@ -126,6 +135,7 @@ static int onSimulationStop(lua_State* L)
coreDeinit = nullptr;
coreFrame = nullptr;
coreUnitsData = nullptr;
coreWeaponsData = nullptr;
coreMissionData = nullptr;
}
@@ -147,6 +157,15 @@ static int setUnitsData(lua_State* L)
return 0;
}
static int setWeaponsData(lua_State* L)
{
if (coreWeaponsData)
{
coreWeaponsData(L);
}
return 0;
}
static int setMissionData(lua_State* L)
{
if (coreMissionData)
@@ -161,6 +180,7 @@ static const luaL_Reg Map[] = {
{"onSimulationFrame", onSimulationFrame},
{"onSimulationStop", onSimulationStop},
{"setUnitsData", setUnitsData },
{"setWeaponsData", setWeaponsData },
{"setMissionData", setMissionData },
{NULL, NULL}
};

View File

@@ -5,6 +5,7 @@
#define REST_ADDRESS "http://localhost:30000"
#define REST_URI "olympus"
#define UNITS_URI "units"
#define WEAPONS_URI "weapons"
#define LOGS_URI "logs"
#define AIRBASES_URI "airbases"
#define BULLSEYE_URI "bullseyes"