mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Splitted weapons and units managers
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
21
src/core/include/weaponsmanager.h
Normal file
21
src/core/include/weaponsmanager.h
Normal 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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
65
src/core/src/weaponsmanager.cpp
Normal file
65
src/core/src/weaponsmanager.cpp
Normal 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user