Transition to json to binary data transfers

This commit is contained in:
Pax1601 2023-06-22 17:28:40 +02:00
parent 9d0e2239e4
commit 1d62b4c115
35 changed files with 827 additions and 862 deletions

View File

@ -4,10 +4,10 @@
class Aircraft : public AirUnit
{
public:
Aircraft(json::value json, int ID);
Aircraft(json::value json, unsigned int ID);
virtual wstring getCategory() { return L"Aircraft"; };
virtual string getCategory() { return "Aircraft"; };
virtual void changeSpeed(wstring change);
virtual void changeAltitude(wstring change);
virtual void changeSpeed(string change);
virtual void changeAltitude(string change);
};

View File

@ -5,18 +5,18 @@
#include "luatools.h"
#include "Unit.h"
#define AIR_DEST_DIST_THR 2000
#define AIR_DEST_DIST_THR 2000 // Meters
class AirUnit : public Unit
{
public:
AirUnit(json::value json, int ID);
AirUnit(json::value json, unsigned int ID);
virtual void setState(int newState);
virtual void setState(unsigned char newState);
virtual wstring getCategory() = 0;
virtual void changeSpeed(wstring change) = 0;
virtual void changeAltitude(wstring change) = 0;
virtual string getCategory() = 0;
virtual void changeSpeed(string change) = 0;
virtual void changeAltitude(string change) = 0;
protected:
virtual void AIloop();

View File

@ -54,6 +54,15 @@ namespace ReactionToThreat {
};
}
namespace EmissionCountermeasure {
enum ReactionsToThreat {
SILENT = 0,
ATTACK = 1,
DEFEND = 2,
FREE = 3
};
}
namespace RadarUse {
enum RadarUses {
NEVER = 0,
@ -85,19 +94,19 @@ namespace ECMUse {
class Command
{
public:
int getPriority() { return priority; }
virtual wstring getString(lua_State* L) = 0;
virtual int getLoad() = 0;
unsigned int getPriority() { return priority; }
virtual string getString(lua_State* L) = 0;
virtual unsigned int getLoad() = 0;
protected:
int priority = CommandPriority::LOW;
unsigned int priority = CommandPriority::LOW;
};
/* Simple low priority move command (from user click) */
class Move : public Command
{
public:
Move(wstring groupName, Coords destination, double speed, wstring speedType, double altitude, wstring altitudeType, wstring taskOptions, wstring category):
Move(string groupName, Coords destination, double speed, string speedType, double altitude, string altitudeType, string taskOptions, string category):
groupName(groupName),
destination(destination),
speed(speed),
@ -109,35 +118,35 @@ public:
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 5; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 5; }
private:
const wstring groupName;
const string groupName;
const Coords destination;
const double speed;
const wstring speedType;
const string speedType;
const double altitude;
const wstring altitudeType;
const wstring taskOptions;
const wstring category;
const string altitudeType;
const string taskOptions;
const string category;
};
/* Smoke command */
class Smoke : public Command
{
public:
Smoke(wstring color, Coords location) :
Smoke(string color, Coords location) :
color(color),
location(location)
{
priority = CommandPriority::LOW;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 5; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 5; }
private:
const wstring color;
const string color;
const Coords location;
};
@ -145,7 +154,7 @@ private:
class SpawnGroundUnit : public Command
{
public:
SpawnGroundUnit(wstring coalition, wstring unitType, Coords location, bool immediate) :
SpawnGroundUnit(string coalition, string unitType, Coords location, bool immediate) :
coalition(coalition),
unitType(unitType),
location(location),
@ -153,12 +162,12 @@ public:
{
priority = immediate? CommandPriority::IMMEDIATE: CommandPriority::LOW;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100 * !immediate; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 100 * !immediate; }
private:
const wstring coalition;
const wstring unitType;
const string coalition;
const string unitType;
const Coords location;
const bool immediate;
};
@ -167,7 +176,7 @@ private:
class SpawnAircraft : public Command
{
public:
SpawnAircraft(wstring coalition, wstring unitType, Coords location, wstring payloadName, wstring airbaseName, bool immediate) :
SpawnAircraft(string coalition, string unitType, Coords location, string payloadName, string airbaseName, bool immediate) :
coalition(coalition),
unitType(unitType),
location(location),
@ -177,15 +186,15 @@ public:
{
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100 * !immediate; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 100 * !immediate; }
private:
const wstring coalition;
const wstring unitType;
const string coalition;
const string unitType;
const Coords location;
const wstring payloadName;
const wstring airbaseName;
const string payloadName;
const string airbaseName;
const bool immediate;
};
@ -193,17 +202,17 @@ private:
class Clone : public Command
{
public:
Clone(int ID, Coords location) :
Clone(unsigned int ID, Coords location) :
ID(ID),
location(location)
{
priority = CommandPriority::LOW;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 100; }
private:
const int ID;
const unsigned int ID;
const Coords location;
};
@ -211,17 +220,17 @@ private:
class Delete : public Command
{
public:
Delete(int ID, bool explosion) :
Delete(unsigned int ID, bool explosion) :
ID(ID),
explosion(explosion)
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 20; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 20; }
private:
const int ID;
const unsigned int ID;
const bool explosion;
};
@ -229,59 +238,59 @@ private:
class SetTask : public Command
{
public:
SetTask(wstring groupName, wstring task) :
SetTask(string groupName, string task) :
groupName(groupName),
task(task)
{
priority = CommandPriority::MEDIUM;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 2; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 2; }
private:
const wstring groupName;
const wstring task;
const string groupName;
const string task;
};
/* Reset task command */
class ResetTask : public Command
{
public:
ResetTask(wstring groupName) :
ResetTask(string groupName) :
groupName(groupName)
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 2; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 2; }
private:
const wstring groupName;
const string groupName;
};
/* Set command */
class SetCommand : public Command
{
public:
SetCommand(wstring groupName, wstring command) :
SetCommand(string groupName, string command) :
groupName(groupName),
command(command)
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 2; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 2; }
private:
const wstring groupName;
const wstring command;
const string groupName;
const string command;
};
/* Set option command */
class SetOption : public Command
{
public:
SetOption(wstring groupName, int optionID, int optionValue) :
SetOption(string groupName, unsigned int optionID, unsigned int optionValue) :
groupName(groupName),
optionID(optionID),
optionValue(optionValue),
@ -291,7 +300,7 @@ public:
priority = CommandPriority::HIGH;
};
SetOption(wstring groupName, int optionID, bool optionBool) :
SetOption(string groupName, unsigned int optionID, bool optionBool) :
groupName(groupName),
optionID(optionID),
optionValue(0),
@ -300,13 +309,13 @@ public:
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 2; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 2; }
private:
const wstring groupName;
const int optionID;
const int optionValue;
const string groupName;
const unsigned int optionID;
const unsigned int optionValue;
const bool optionBool;
const bool isBoolean;
};
@ -315,17 +324,17 @@ private:
class SetOnOff : public Command
{
public:
SetOnOff(wstring groupName, bool onOff) :
SetOnOff(string groupName, bool onOff) :
groupName(groupName),
onOff(onOff)
{
priority = CommandPriority::HIGH;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 2; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 2; }
private:
const wstring groupName;
const string groupName;
const bool onOff;
};
@ -333,16 +342,16 @@ private:
class Explosion : public Command
{
public:
Explosion(int intensity, Coords location) :
Explosion(unsigned int intensity, Coords location) :
location(location),
intensity(intensity)
{
priority = CommandPriority::MEDIUM;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 10; }
virtual string getString(lua_State* L);
virtual unsigned int getLoad() { return 10; }
private:
const Coords location;
const int intensity;
const unsigned int intensity;
};

View File

@ -6,12 +6,12 @@
class GroundUnit : public Unit
{
public:
GroundUnit(json::value json, int ID);
virtual wstring getCategory() { return L"GroundUnit"; };
GroundUnit(json::value json, unsigned int ID);
virtual string getCategory() { return "GroundUnit"; };
virtual void setState(int newState);
virtual void setState(unsigned char newState);
virtual void changeSpeed(wstring change);
virtual void changeSpeed(string change);
virtual void setOnOff(bool newOnOff);
virtual void setFollowRoads(bool newFollowRoads);

View File

@ -4,10 +4,10 @@
class Helicopter : public AirUnit
{
public:
Helicopter(json::value json, int ID);
Helicopter(json::value json, unsigned int ID);
virtual wstring getCategory() { return L"Helicopter"; };
virtual string getCategory() { return "Helicopter"; };
virtual void changeSpeed(wstring change);
virtual void changeAltitude(wstring change);
virtual void changeSpeed(string change);
virtual void changeAltitude(string change);
};

View File

@ -4,10 +4,10 @@
class NavyUnit : public Unit
{
public:
NavyUnit(json::value json, int ID);
NavyUnit(json::value json, unsigned int ID);
virtual void AIloop();
virtual wstring getCategory() { return L"NavyUnit"; };
virtual void changeSpeed(wstring change);
virtual string getCategory() { return "NavyUnit"; };
virtual void changeSpeed(string change);
};

View File

@ -11,10 +11,10 @@ public:
void appendCommand(Command* command);
void execute(lua_State* L);
void handleRequest(wstring key, json::value value);
void handleRequest(string key, json::value value);
private:
list<Command*> commands;
int load;
unsigned int load;
};

View File

@ -15,8 +15,6 @@ public:
void start(lua_State* L);
void stop(lua_State* L);
json::value& getUpdateJson() { return updateJson; }
json::value& getRefreshJson() { return refreshJson; }
private:
std::thread* serverThread;
@ -29,9 +27,7 @@ private:
void task();
atomic<bool> runListener;
json::value updateJson;
json::value refreshJson;
wstring password = L"";
string password = "";
};

View File

@ -5,6 +5,7 @@
#include "luatools.h"
#include "measure.h"
#include "logger.h"
#include "commands.h"
#define TASK_CHECK_INIT_VALUE 10
@ -32,16 +33,16 @@ namespace Options {
struct TACAN
{
bool isOn = false;
int channel = 40;
wstring XY = L"X";
wstring callsign = L"TKR";
unsigned char channel = 40;
char XY = 'X';
char callsign[4];
};
struct Radio
{
int frequency = 124000000; // MHz
int callsign = 1;
int callsignNumber = 1;
unsigned int frequency = 124000000; // MHz
unsigned char callsign = 1;
unsigned char callsignNumber = 1;
};
struct GeneralSettings
@ -54,116 +55,145 @@ namespace Options {
};
}
namespace DataTypes {
struct Ammo {
unsigned short quantity = 0;
string name;
unsigned char guidance = 0;
unsigned char category = 0;
unsigned char missileCategory = 0;
};
struct Contact {
unsigned int ID = 0;
unsigned char detectionMethod = 0;
};
struct DataPacket {
unsigned int ID;
unsigned int bitmask;
Coords position;
double speed;
double heading;
unsigned short fuel;
double desiredSpeed;
double desiredAltitude;
unsigned int targetID;
Coords targetPosition;
unsigned char state;
unsigned char ROE;
unsigned char reactionToThreat;
unsigned char emissionsCountermeasures;
Options::TACAN TACAN;
Options::Radio Radio;
};
}
class Unit
{
public:
Unit(json::value json, int ID);
Unit(json::value json, unsigned int ID);
~Unit();
/********** Public methods **********/
void initialize(json::value json);
void setDefaults(bool force = false);
int getID() { return ID; }
unsigned int getID() { return ID; }
void runAILoop();
void updateExportData(json::value json, double dt = 0);
void updateMissionData(json::value json);
json::value getData(long long time, bool getAll = false);
virtual wstring getCategory() { return L"No category"; };
DataTypes::DataPacket getDataPacket();
string getData(bool refresh);
virtual string getCategory() { return "No category"; };
/********** Base data **********/
void setControlled(bool newControlled) { controlled = newControlled; addMeasure(L"controlled", json::value(newControlled)); }
void setName(wstring newName) { name = newName; addMeasure(L"name", json::value(newName));}
void setUnitName(wstring newUnitName) { unitName = newUnitName; addMeasure(L"unitName", json::value(newUnitName));}
void setGroupName(wstring newGroupName) { groupName = newGroupName; addMeasure(L"groupName", json::value(newGroupName));}
void setAlive(bool newAlive) { alive = newAlive; addMeasure(L"alive", json::value(newAlive));}
void setType(json::value newType) { type = newType; addMeasure(L"type", newType);}
void setCountry(int newCountry) { country = newCountry; addMeasure(L"country", json::value(newCountry));}
void setControlled(bool newControlled) { controlled = newControlled; }
void setName(string newName) { name = newName; }
void setUnitName(string newUnitName) { unitName = newUnitName; }
void setGroupName(string newGroupName) { groupName = newGroupName; }
void setAlive(bool newAlive) { alive = newAlive; }
void setCountry(unsigned int newCountry) { country = newCountry; }
void setHuman(bool newHuman) { human = newHuman; }
bool getControlled() { return controlled; }
wstring getName() { return name; }
wstring getUnitName() { return unitName; }
wstring getGroupName() { return groupName; }
string getName() { return name; }
string getUnitName() { return unitName; }
string getGroupName() { return groupName; }
bool getAlive() { return alive; }
json::value getType() { return type; }
int getCountry() { return country; }
unsigned int getCountry() { return country; }
bool getHuman() { return human; }
/********** Flight data **********/
void setLatitude(double newLatitude) {latitude = newLatitude; addMeasure(L"latitude", json::value(newLatitude));}
void setLongitude(double newLongitude) {longitude = newLongitude; addMeasure(L"longitude", json::value(newLongitude));}
void setAltitude(double newAltitude) {altitude = newAltitude; addMeasure(L"altitude", json::value(newAltitude));}
void setHeading(double newHeading) {heading = newHeading; addMeasure(L"heading", json::value(newHeading));}
void setSpeed(double newSpeed) {speed = newSpeed; addMeasure(L"speed", json::value(newSpeed));}
void setPosition(Coords newPosition) { position = newPosition; }
void setHeading(double newHeading) {heading = newHeading; }
void setSpeed(double newSpeed) {speed = newSpeed; }
double getLatitude() { return latitude; }
double getLongitude() { return longitude; }
double getAltitude() { return altitude; }
Coords getPosition() { return position; }
double getHeading() { return heading; }
double getSpeed() { return speed; }
/********** Mission data **********/
void setFuel(double newFuel) { fuel = newFuel; addMeasure(L"fuel", json::value(newFuel));}
void setAmmo(json::value newAmmo) { ammo = newAmmo; addMeasure(L"ammo", json::value(newAmmo));}
void setContacts(json::value newContacts) {contacts = newContacts; addMeasure(L"contacts", json::value(newContacts));}
void setFuel(short newFuel) { fuel = newFuel; }
void setAmmo(vector<DataTypes::Ammo> newAmmo) { ammo = newAmmo; }
void setContacts(vector<DataTypes::Contact> newContacts) {contacts = newContacts; }
void setHasTask(bool newHasTask);
void setCoalitionID(int newCoalitionID);
void setFlags(json::value newFlags) { flags = newFlags; addMeasure(L"flags", json::value(newFlags));}
void setCoalitionID(unsigned int newCoalitionID);
double getFuel() { return fuel; }
json::value getAmmo() { return ammo; }
json::value getTargets() { return contacts; }
vector<DataTypes::Ammo> getAmmo() { return ammo; }
vector<DataTypes::Contact> getTargets() { return contacts; }
bool getHasTask() { return hasTask; }
wstring getCoalition() { return coalition; }
int getCoalitionID();
json::value getFlags() { return flags; }
string getCoalition() { return coalition; }
unsigned int getCoalitionID();
/********** Formation data **********/
void setLeaderID(int newLeaderID) { leaderID = newLeaderID; addMeasure(L"leaderID", json::value(newLeaderID)); }
void setLeaderID(unsigned int newLeaderID) { leaderID = newLeaderID; }
void setFormationOffset(Offset formationOffset);
int getLeaderID() { return leaderID; }
unsigned int getLeaderID() { return leaderID; }
Offset getFormationoffset() { return formationOffset; }
/********** Task data **********/
void setCurrentTask(wstring newCurrentTask) { currentTask = newCurrentTask; addMeasure(L"currentTask", json::value(newCurrentTask)); }
void setCurrentTask(string newCurrentTask) { currentTask = newCurrentTask; }
void setDesiredSpeed(double newDesiredSpeed);
void setDesiredAltitude(double newDesiredAltitude);
void setDesiredSpeedType(wstring newDesiredSpeedType);
void setDesiredAltitudeType(wstring newDesiredAltitudeType);
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; addMeasure(L"activeDestination", json::value("")); } // TODO fix
void setDesiredSpeedType(string newDesiredSpeedType);
void setDesiredAltitudeType(string newDesiredAltitudeType);
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; }
void setActivePath(list<Coords> newActivePath);
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
void setTargetLocation(Coords newTargetLocation);
void setTargetID(unsigned int newTargetID) { targetID = newTargetID; }
void setTargetPosition(Coords newTargetPosition);
void setIsTanker(bool newIsTanker);
void setIsAWACS(bool newIsAWACS);
virtual void setOnOff(bool newOnOff) { onOff = newOnOff; addMeasure(L"onOff", json::value(newOnOff));};
virtual void setFollowRoads(bool newFollowRoads) { followRoads = newFollowRoads; addMeasure(L"followRoads", json::value(newFollowRoads)); };
virtual void setOnOff(bool newOnOff) { onOff = newOnOff; };
virtual void setFollowRoads(bool newFollowRoads) { followRoads = newFollowRoads; };
wstring getCurrentTask() { return currentTask; }
string getCurrentTask() { return currentTask; }
virtual double getDesiredSpeed() { return desiredSpeed; };
virtual double getDesiredAltitude() { return desiredAltitude; };
virtual wstring getDesiredSpeedType() { return desiredSpeedType; };
virtual wstring getDesiredAltitudeType() { return desiredAltitudeType; };
virtual bool getDesiredSpeedType() { return desiredSpeedType; };
virtual bool getDesiredAltitudeType() { return desiredAltitudeType; };
Coords getActiveDestination() { return activeDestination; }
list<Coords> getActivePath() { return activePath; }
int getTargetID() { return targetID; }
Coords getTargetLocation() { return targetLocation; }
unsigned int getTargetID() { return targetID; }
Coords getTargetPosition() { return targetPosition; }
bool getIsTanker() { return isTanker; }
bool getIsAWACS() { return isAWACS; }
bool getOnOff() { return onOff; };
bool getFollowRoads() { return followRoads; };
/********** Options data **********/
void setROE(wstring newROE, bool force = false);
void setReactionToThreat(wstring newReactionToThreat, bool force = false);
void setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force = false);
void setROE(unsigned char newROE, bool force = false);
void setReactionToThreat(unsigned char newReactionToThreat, bool force = false);
void setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures, bool force = false);
void setTACAN(Options::TACAN newTACAN, bool force = false);
void setRadio(Options::Radio newradio, bool force = false);
void setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force = false);
void setEPLRS(bool newEPLRS, bool force = false);
wstring getROE() { return ROE; }
wstring getReactionToThreat() { return reactionToThreat; }
wstring getEmissionsCountermeasures() { return emissionsCountermeasures; };
unsigned char getROE() { return ROE; }
unsigned char getReactionToThreat() { return reactionToThreat; }
unsigned char getEmissionsCountermeasures() { return emissionsCountermeasures; };
Options::TACAN getTACAN() { return TACAN; }
Options::Radio getRadio() { return radio; }
Options::GeneralSettings getGeneralSettings() { return generalSettings; }
@ -171,10 +201,10 @@ public:
/********** Control functions **********/
void landAt(Coords loc);
virtual void changeSpeed(wstring change) {};
virtual void changeAltitude(wstring change) {};
virtual void changeSpeed(string change) {};
virtual void changeAltitude(string change) {};
void resetActiveDestination();
virtual void setState(int newState) { state = newState; };
virtual void setState(unsigned char newState) { state = newState; };
void resetTask();
void clearActivePath();
void pushActivePathFront(Coords newActivePathFront);
@ -182,81 +212,77 @@ public:
void popActivePathFront();
protected:
int ID;
unsigned int ID;
map<wstring, Measure*> measures;
int taskCheckCounter = 0;
map<string, Measure*> measures;
unsigned int taskCheckCounter = 0;
/********** Base data **********/
bool controlled = false;
wstring name = L"undefined";
wstring unitName = L"undefined";
wstring groupName = L"undefined";
string name = "undefined";
string unitName = "undefined";
string groupName = "undefined";
bool alive = true;
json::value type = json::value::null();
int country = NULL;
bool human = false;
unsigned int country = NULL;
/********** Flight data **********/
double latitude = NULL;
double longitude = NULL;
double altitude = NULL;
Coords position = Coords(NULL);
double speed = NULL;
double heading = NULL;
/********** Mission data **********/
double fuel = 0;
unsigned short fuel = 0;
double initialFuel = 0; // Used internally to detect refueling completed
json::value ammo = json::value::null();
json::value contacts = json::value::null();
vector<DataTypes::Ammo> ammo;
vector<DataTypes::Contact> contacts;
bool hasTask = false;
wstring coalition = L"";
json::value flags = json::value::null();
string coalition = "";
/********** Formation data **********/
int leaderID = NULL;
unsigned int leaderID = NULL;
Offset formationOffset = Offset(NULL);
/********** Task data **********/
wstring currentTask = L"";
string currentTask = "";
double desiredSpeed = 0;
double desiredAltitude = 0;
wstring desiredSpeedType = L"GS";
wstring desiredAltitudeType = L"AGL";
bool desiredSpeedType = 0;
bool desiredAltitudeType = 0;
list<Coords> activePath;
Coords activeDestination = Coords(NULL);
int targetID = NULL;
Coords targetLocation = Coords(NULL);
unsigned int targetID = NULL;
Coords targetPosition = Coords(NULL);
bool isTanker = false;
bool isAWACS = false;
bool onOff = true;
bool followRoads = false;
/********** Options data **********/
wstring ROE = L"Designated";
wstring reactionToThreat = L"Evade";
wstring emissionsCountermeasures = L"Defend";
unsigned char ROE = ROE::OPEN_FIRE_WEAPON_FREE;
unsigned char reactionToThreat = ReactionToThreat::EVADE_FIRE;
unsigned char emissionsCountermeasures = EmissionCountermeasure::DEFEND;
Options::TACAN TACAN;
Options::Radio radio;
Options::GeneralSettings generalSettings;
bool EPLRS = false;
/********** State machine **********/
int state = State::NONE;
unsigned char state = State::NONE;
/********** Other **********/
Coords oldPosition = Coords(0); // Used to approximate speed
/********** Functions **********/
wstring getTargetName();
wstring getLeaderName();
string getTargetName();
string getLeaderName();
bool isTargetAlive();
bool isLeaderAlive();
virtual void AIloop() = 0;
void addMeasure(wstring key, json::value value);
bool isDestinationReached(double threshold);
bool setActiveDestination();
bool updateActivePath(bool looping);
void goToDestination(wstring enrouteTask = L"nil");
void goToDestination(string enrouteTask = "nil");
bool checkTaskFailed();
void resetTaskFailedCounter();
};

View File

@ -10,23 +10,22 @@ public:
UnitsManager(lua_State* L);
~UnitsManager();
map<int, Unit*>& getUnits() { return units; };
Unit* getUnit(int ID);
map<unsigned int, Unit*>& getUnits() { return units; };
Unit* getUnit(unsigned int ID);
bool isUnitInGroup(Unit* unit);
bool isUnitGroupLeader(Unit* unit);
Unit* getGroupLeader(int ID);
Unit* getGroupLeader(unsigned int ID);
Unit* getGroupLeader(Unit* unit);
vector<Unit*> getGroupMembers(wstring groupName);
vector<Unit*> getGroupMembers(string groupName);
void updateExportData(lua_State* L, double dt = 0);
void updateMissionData(json::value missionData);
void runAILoop();
void getUnitData(json::value& answer, long long time);
void appendUnitData(int ID, json::value& answer, long long time);
void deleteUnit(int ID, bool explosion);
void acquireControl(int ID);
string getUnitData(bool refresh);
void deleteUnit(unsigned int ID, bool explosion);
void acquireControl(unsigned int ID);
private:
map<int, Unit*> units;
map<unsigned int, Unit*> units;
json::value missionDB;
};

View File

@ -4,9 +4,9 @@
class Weapon : public Unit
{
public:
Weapon(json::value json, int ID);
Weapon(json::value json, unsigned int ID);
virtual wstring getCategory() = 0;
virtual string getCategory() = 0;
protected:
/* Weapons are not controllable and have no AIloop */
@ -16,15 +16,15 @@ protected:
class Missile : public Weapon
{
public:
Missile(json::value json, int ID);
Missile(json::value json, unsigned int ID);
virtual wstring getCategory() { return L"Missile"; };
virtual string getCategory() { return "Missile"; };
};
class Bomb : public Weapon
{
public:
Bomb(json::value json, int ID);
Bomb(json::value json, unsigned int ID);
virtual wstring getCategory() { return L"Bomb"; };
virtual string getCategory() { return "Bomb"; };
};

View File

@ -13,10 +13,9 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Aircraft */
Aircraft::Aircraft(json::value json, int ID) : AirUnit(json, ID)
Aircraft::Aircraft(json::value json, unsigned int ID) : AirUnit(json, ID)
{
log("New Aircraft created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
double desiredSpeed = knotsToMs(300);
double desiredAltitude = ftToM(20000);
@ -24,13 +23,13 @@ Aircraft::Aircraft(json::value json, int ID) : AirUnit(json, ID)
setDesiredAltitude(desiredAltitude);
};
void Aircraft::changeSpeed(wstring change)
void Aircraft::changeSpeed(string change)
{
if (change.compare(L"stop") == 0)
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare(L"slow") == 0)
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(25));
else if (change.compare(L"fast") == 0)
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(25));
if (getDesiredSpeed() < knotsToMs(50))
@ -42,16 +41,16 @@ void Aircraft::changeSpeed(wstring change)
goToDestination(); /* Send the command to reach the destination */
}
void Aircraft::changeAltitude(wstring change)
void Aircraft::changeAltitude(string change)
{
if (change.compare(L"descend") == 0)
if (change.compare("descend") == 0)
{
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() - ftToM(2500));
else if (getDesiredAltitude() > 0)
setDesiredAltitude(getDesiredAltitude() - ftToM(500));
}
else if (change.compare(L"climb") == 0)
else if (change.compare("climb") == 0)
{
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() + ftToM(2500));

View File

@ -13,12 +13,12 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Air unit */
AirUnit::AirUnit(json::value json, int ID) : Unit(json, ID)
AirUnit::AirUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
};
void AirUnit::setState(int newState)
void AirUnit::setState(unsigned char newState)
{
/************ Perform any action required when LEAVING a state ************/
if (newState != state) {
@ -46,7 +46,7 @@ void AirUnit::setState(int newState)
case State::BOMB_POINT:
case State::CARPET_BOMB:
case State::BOMB_BUILDING: {
setTargetLocation(Coords(NULL));
setTargetPosition(Coords(NULL));
break;
}
default:
@ -59,12 +59,10 @@ void AirUnit::setState(int newState)
case State::IDLE: {
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Idle"));
break;
}
case State::REACH_DESTINATION: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Reach destination"));
break;
}
case State::ATTACK: {
@ -74,42 +72,35 @@ void AirUnit::setState(int newState)
clearActivePath();
pushActivePathFront(targetPosition);
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Attack"));
}
break;
}
case State::FOLLOW: {
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Follow"));
break;
}
case State::LAND: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Land"));
break;
}
case State::REFUEL: {
initialFuel = fuel;
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Refuel"));
break;
}
case State::BOMB_POINT: {
addMeasure(L"currentState", json::value(L"Bombing point"));
clearActivePath();
resetActiveDestination();
break;
}
case State::CARPET_BOMB: {
addMeasure(L"currentState", json::value(L"Carpet bombing"));
clearActivePath();
resetActiveDestination();
break;
}
case State::BOMB_BUILDING: {
addMeasure(L"currentState", json::value(L"Bombing building"));
clearActivePath();
resetActiveDestination();
break;
@ -120,7 +111,7 @@ void AirUnit::setState(int newState)
resetTask();
log(unitName + L" setting state from " + to_wstring(state) + L" to " + to_wstring(newState));
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
}
@ -129,11 +120,11 @@ void AirUnit::AIloop()
/* State machine */
switch (state) {
case State::IDLE: {
currentTask = L"Idle";
currentTask = "Idle";
if (!getHasTask())
{
std::wostringstream taskSS;
std::ostringstream taskSS;
if (isTanker) {
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }";
}
@ -150,23 +141,23 @@ void AirUnit::AIloop()
break;
}
case State::REACH_DESTINATION: {
wstring enrouteTask = L"";
string enrouteTask = "";
bool looping = false;
if (isTanker)
{
enrouteTask = L"{ id = 'Tanker' }";
currentTask = L"Tanker";
enrouteTask = "{ id = 'Tanker' }";
currentTask = "Tanker";
}
else if (isAWACS)
{
enrouteTask = L"{ id = 'AWACS' }";
currentTask = L"AWACS";
enrouteTask = "{ id = 'AWACS' }";
currentTask = "AWACS";
}
else
{
enrouteTask = L"nil";
currentTask = L"Reaching destination";
enrouteTask = "nil";
currentTask = "Reaching destination";
}
if (activeDestination == NULL || !getHasTask())
@ -187,8 +178,8 @@ void AirUnit::AIloop()
break;
}
case State::LAND: {
wstring enrouteTask = L"{ id = 'Land' }";
currentTask = L"Landing";
string enrouteTask = "{ id = 'Land' }";
currentTask = "Landing";
if (activeDestination == NULL)
{
@ -206,13 +197,13 @@ void AirUnit::AIloop()
/* Attack state is an "enroute" task, meaning the unit will keep trying to attack even if a new destination is set. This is useful to
manoeuvre the unit so that it can detect and engage the target. */
std::wostringstream enrouteTaskSS;
std::ostringstream enrouteTaskSS;
enrouteTaskSS << "{"
<< "id = 'EngageUnit'" << ","
<< "targetID = " << targetID << ","
<< "}";
wstring enrouteTask = enrouteTaskSS.str();
currentTask = L"Attacking " + getTargetName();
string enrouteTask = enrouteTaskSS.str();
currentTask = "Attacking " + getTargetName();
if (!getHasTask())
{
@ -232,13 +223,13 @@ void AirUnit::AIloop()
break;
}
currentTask = L"Following " + getTargetName();
currentTask = "Following " + getTargetName();
Unit* leader = unitsManager->getUnit(leaderID);
if (!getHasTask()) {
if (leader != nullptr && leader->getAlive() && formationOffset != NULL)
{
std::wostringstream taskSS;
std::ostringstream taskSS;
taskSS << "{"
<< "id = 'FollowUnit'" << ", "
<< "leaderID = " << leader->getID() << ","
@ -256,11 +247,11 @@ void AirUnit::AIloop()
break;
}
case State::REFUEL: {
currentTask = L"Refueling";
currentTask = "Refueling";
if (!getHasTask()) {
if (fuel <= initialFuel) {
std::wostringstream taskSS;
std::ostringstream taskSS;
taskSS << "{"
<< "id = 'Refuel'"
<< "}";
@ -274,22 +265,22 @@ void AirUnit::AIloop()
}
}
case State::BOMB_POINT: {
currentTask = L"Bombing point";
currentTask = "Bombing point";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'Bombing', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
std::ostringstream taskSS;
taskSS << "{id = 'Bombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
}
case State::CARPET_BOMB: {
currentTask = L"Carpet bombing";
currentTask = "Carpet bombing";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'CarpetBombing', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
std::ostringstream taskSS;
taskSS << "{id = 'CarpetBombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
@ -297,11 +288,11 @@ void AirUnit::AIloop()
break;
}
case State::BOMB_BUILDING: {
currentTask = L"Bombing building";
currentTask = "Bombing building";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'AttackMapObject', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
std::ostringstream taskSS;
taskSS << "{id = 'AttackMapObject', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
@ -311,6 +302,4 @@ void AirUnit::AIloop()
default:
break;
}
addMeasure(L"currentTask", json::value(currentTask));
}

View File

@ -7,10 +7,10 @@
extern UnitsManager* unitsManager;
/* Move command */
wstring Move::getString(lua_State* L)
string Move::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.move, "
<< "\"" << groupName << "\"" << ", "
@ -26,9 +26,9 @@ wstring Move::getString(lua_State* L)
}
/* Smoke command */
wstring Smoke::getString(lua_State* L)
string Smoke::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.smoke, "
<< "\"" << color << "\"" << ", "
@ -38,9 +38,9 @@ wstring Smoke::getString(lua_State* L)
}
/* Spawn ground command */
wstring SpawnGroundUnit::getString(lua_State* L)
string SpawnGroundUnit::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnGroundUnit, "
<< "\"" << coalition << "\"" << ", "
@ -51,16 +51,16 @@ wstring SpawnGroundUnit::getString(lua_State* L)
}
/* Spawn air command */
wstring SpawnAircraft::getString(lua_State* L)
string SpawnAircraft::getString(lua_State* L)
{
std::wostringstream optionsSS;
std::ostringstream optionsSS;
optionsSS.precision(10);
optionsSS << "{"
<< "payloadName = \"" << payloadName << "\", "
<< "airbaseName = \"" << airbaseName << "\", "
<< "}";
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnAircraft, "
<< "\"" << coalition << "\"" << ", "
@ -73,12 +73,12 @@ wstring SpawnAircraft::getString(lua_State* L)
}
/* Clone unit command */
wstring Clone::getString(lua_State* L)
string Clone::getString(lua_State* L)
{
Unit* unit = unitsManager->getUnit(ID);
if (unit != nullptr)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.clone, "
<< ID << ", "
@ -89,14 +89,14 @@ wstring Clone::getString(lua_State* L)
}
else
{
return L"";
return "";
}
}
/* Delete unit command */
wstring Delete::getString(lua_State* L)
string Delete::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.delete, "
<< ID << ", "
@ -105,9 +105,9 @@ wstring Delete::getString(lua_State* L)
}
/* Set task command */
wstring SetTask::getString(lua_State* L)
string SetTask::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setTask, "
<< "\"" << groupName << "\"" << ", "
@ -117,9 +117,9 @@ wstring SetTask::getString(lua_State* L)
}
/* Reset task command */
wstring ResetTask::getString(lua_State* L)
string ResetTask::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.resetTask, "
<< "\"" << groupName << "\"";
@ -128,9 +128,9 @@ wstring ResetTask::getString(lua_State* L)
}
/* Set command command */
wstring SetCommand::getString(lua_State* L)
string SetCommand::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setCommand, "
<< "\"" << groupName << "\"" << ", "
@ -140,9 +140,9 @@ wstring SetCommand::getString(lua_State* L)
}
/* Set option command */
wstring SetOption::getString(lua_State* L)
string SetOption::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
if (!isBoolean) {
@ -160,9 +160,9 @@ wstring SetOption::getString(lua_State* L)
}
/* Set onOff command */
wstring SetOnOff::getString(lua_State* L)
string SetOnOff::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setOnOff, "
@ -173,9 +173,9 @@ wstring SetOnOff::getString(lua_State* L)
}
/* Explosion command */
wstring Explosion::getString(lua_State* L)
string Explosion::getString(lua_State* L)
{
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.explosion, "
<< intensity << ", "

View File

@ -10,19 +10,24 @@
using namespace std::chrono;
auto before = std::chrono::system_clock::now();
/* Singleton objects */
UnitsManager* unitsManager = nullptr;
Server* server = nullptr;
Scheduler* scheduler = nullptr;
/* Data jsons */
json::value airbases;
json::value bullseyes;
json::value mission;
mutex mutexLock;
bool initialized = false;
string sessionHash;
int lastUpdateIndex = 0;
int frameCounter = 0;
bool initialized = false;
unsigned int frameCounter = 0;
double frameRate = 30;
long long lastUpdateTime = 0;
/* Called when DCS simulation stops. All singleton instances are deleted. */
extern "C" DllExport int coreDeinit(lua_State* L)
@ -64,48 +69,29 @@ extern "C" DllExport int coreFrame(lua_State* L)
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
frameCounter++;
/* Slow down the update rate if the frameRate is very low since it means DCS is struggling to keep up */
const std::chrono::duration<double> duration = std::chrono::system_clock::now() - before;
if (unitsManager != nullptr) {
// TODO put in a function
vector<int> IDs;
for (auto iter = unitsManager->getUnits().begin(); iter != unitsManager->getUnits().end(); ++iter)
IDs.push_back(iter->first);
int updateChunk = 20;
int finalUpdateIndex = lastUpdateIndex + updateChunk;
/* Get all the new data (with some margin) */
while (lastUpdateIndex < unitsManager->getUnits().size() && lastUpdateIndex <= finalUpdateIndex)
unitsManager->appendUnitData(IDs[lastUpdateIndex++], server->getUpdateJson(), lastUpdateTime - 1000);
}
if (duration.count() > UPDATE_TIME_INTERVAL && lastUpdateIndex == unitsManager->getUnits().size())
if (duration.count() > UPDATE_TIME_INTERVAL * (60.0 / frameRate))
{
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
lastUpdateTime = ms.count();
frameRate = frameCounter / duration.count();
frameCounter = 0;
if (unitsManager != nullptr)
if (unitsManager != nullptr) {
unitsManager->updateExportData(L, duration.count());
unitsManager->runAILoop();
}
before = std::chrono::system_clock::now();
/* Restart the update counter */
lastUpdateIndex = 0;
}
if (scheduler != nullptr)
scheduler->execute(L);
if (duration.count() > UPDATE_TIME_INTERVAL && unitsManager != nullptr)
unitsManager->runAILoop();
return(0);
}

View File

@ -13,16 +13,15 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Ground unit */
GroundUnit::GroundUnit(json::value json, int ID) : Unit(json, ID)
GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
log("New Ground Unit created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
double desiredSpeed = 10;
setDesiredSpeed(desiredSpeed);
};
void GroundUnit::setState(int newState)
void GroundUnit::setState(unsigned char newState)
{
/************ Perform any action required when LEAVING a state ************/
if (newState != state) {
@ -34,7 +33,7 @@ void GroundUnit::setState(int newState)
break;
}
case State::FIRE_AT_AREA: {
setTargetLocation(Coords(NULL));
setTargetPosition(Coords(NULL));
break;
}
default:
@ -47,16 +46,13 @@ void GroundUnit::setState(int newState)
case State::IDLE: {
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Idle"));
break;
}
case State::REACH_DESTINATION: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Reach destination"));
break;
}
case State::FIRE_AT_AREA: {
addMeasure(L"currentState", json::value(L"Firing at area"));
clearActivePath();
resetActiveDestination();
break;
@ -67,7 +63,7 @@ void GroundUnit::setState(int newState)
resetTask();
log(unitName + L" setting state from " + to_wstring(state) + L" to " + to_wstring(newState));
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
}
@ -75,16 +71,16 @@ void GroundUnit::AIloop()
{
switch (state) {
case State::IDLE: {
currentTask = L"Idle";
currentTask = "Idle";
if (getHasTask())
resetTask();
break;
}
case State::REACH_DESTINATION: {
wstring enrouteTask = L"";
string enrouteTask = "";
bool looping = false;
std::wostringstream taskSS;
std::ostringstream taskSS;
taskSS << "{ id = 'FollowRoads', value = " << (getFollowRoads() ? "true" : "false") << " }";
enrouteTask = taskSS.str();
@ -106,11 +102,11 @@ void GroundUnit::AIloop()
break;
}
case State::FIRE_AT_AREA: {
currentTask = L"Firing at area";
currentTask = "Firing at area";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'FireAtPoint', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << ", radius = 1000}";
std::ostringstream taskSS;
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
@ -119,17 +115,15 @@ void GroundUnit::AIloop()
default:
break;
}
addMeasure(L"currentTask", json::value(currentTask));
}
void GroundUnit::changeSpeed(wstring change)
void GroundUnit::changeSpeed(string change)
{
if (change.compare(L"stop") == 0)
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare(L"slow") == 0)
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
else if (change.compare(L"fast") == 0)
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
if (getDesiredSpeed() < 0)

View File

@ -13,10 +13,9 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Helicopter */
Helicopter::Helicopter(json::value json, int ID) : AirUnit(json, ID)
Helicopter::Helicopter(json::value json, unsigned int ID) : AirUnit(json, ID)
{
log("New Helicopter created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
double desiredSpeed = knotsToMs(100);
double desiredAltitude = ftToM(5000);
@ -24,16 +23,16 @@ Helicopter::Helicopter(json::value json, int ID) : AirUnit(json, ID)
setDesiredAltitude(desiredAltitude);
};
void Helicopter::changeSpeed(wstring change)
void Helicopter::changeSpeed(string change)
{
if (change.compare(L"stop") == 0)
if (change.compare("stop") == 0)
{
/* Air units can't hold a position, so we can only set them to hold. At the moment, this will erase any other command. TODO: helicopters should be able to hover in place */
clearActivePath();
}
else if (change.compare(L"slow") == 0)
else if (change.compare("slow") == 0)
desiredSpeed -= knotsToMs(10);
else if (change.compare(L"fast") == 0)
else if (change.compare("fast") == 0)
desiredSpeed += knotsToMs(10);
if (desiredSpeed < 0)
desiredSpeed = 0;
@ -41,16 +40,16 @@ void Helicopter::changeSpeed(wstring change)
goToDestination(); /* Send the command to reach the destination */
}
void Helicopter::changeAltitude(wstring change)
void Helicopter::changeAltitude(string change)
{
if (change.compare(L"descend") == 0)
if (change.compare("descend") == 0)
{
if (desiredAltitude > 100)
desiredAltitude -= ftToM(100);
else if (desiredAltitude > 0)
desiredAltitude -= ftToM(10);
}
else if (change.compare(L"climb") == 0)
else if (change.compare("climb") == 0)
{
if (desiredAltitude > 100)
desiredAltitude += ftToM(100);

View File

@ -13,10 +13,9 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Navy Unit */
NavyUnit::NavyUnit(json::value json, int ID) : Unit(json, ID)
NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
log("New Navy Unit created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
double desiredSpeed = 10;
setDesiredSpeed(desiredSpeed);
@ -27,17 +26,17 @@ void NavyUnit::AIloop()
/* TODO */
}
void NavyUnit::changeSpeed(wstring change)
void NavyUnit::changeSpeed(string change)
{
if (change.compare(L"stop") == 0)
if (change.compare("stop") == 0)
{
}
else if (change.compare(L"slow") == 0)
else if (change.compare("slow") == 0)
{
}
else if (change.compare(L"fast") == 0)
else if (change.compare("fast") == 0)
{
}

View File

@ -32,16 +32,16 @@ void Scheduler::execute(lua_State* L)
return;
}
int priority = CommandPriority::IMMEDIATE;
unsigned int priority = CommandPriority::IMMEDIATE;
while (priority >= CommandPriority::LOW)
{
for (auto command : commands)
{
if (command->getPriority() == priority)
{
wstring commandString = L"Olympus.protectedCall(" + command->getString(L) + L")";
if (dostring_in(L, "server", to_string(commandString)))
log(L"Error executing command " + commandString);
string commandString = "Olympus.protectedCall(" + command->getString(L) + ")";
if (dostring_in(L, "server", (commandString)))
log("Error executing command " + commandString);
load = command->getLoad();
commands.remove(command);
return;
@ -51,81 +51,81 @@ void Scheduler::execute(lua_State* L)
}
}
void Scheduler::handleRequest(wstring key, json::value value)
void Scheduler::handleRequest(string key, json::value value)
{
Command* command = nullptr;
log(L"Received request with ID: " + key);
if (key.compare(L"setPath") == 0)
log("Received request with ID: " + key);
if (key.compare("setPath") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
wstring unitName = unit->getUnitName();
string unitName = unit->getUnitName();
json::value path = value[L"path"];
list<Coords> newPath;
for (int i = 1; i <= path.as_object().size(); i++)
for (unsigned int i = 1; i <= path.as_object().size(); i++)
{
wstring WP = to_wstring(i);
double lat = path[WP][L"lat"].as_double();
double lng = path[WP][L"lng"].as_double();
log(unitName + L" set path destination " + WP + L" (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
string WP = to_string(i);
double lat = path[to_wstring(i)][L"lat"].as_double();
double lng = path[to_wstring(i)][L"lng"].as_double();
log(unitName + " set path destination " + WP + " (" + to_string(lat) + ", " + to_string(lng) + ")");
Coords dest; dest.lat = lat; dest.lng = lng;
newPath.push_back(dest);
}
unit->setActivePath(newPath);
unit->setState(State::REACH_DESTINATION);
log(unitName + L" new path set successfully");
log(unitName + " new path set successfully");
}
}
else if (key.compare(L"smoke") == 0)
else if (key.compare("smoke") == 0)
{
wstring color = value[L"color"].as_string();
string color = to_string(value[L"color"]);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
log(L"Adding " + color + L" smoke at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
log("Adding " + color + " smoke at (" + to_string(lat) + ", " + to_string(lng) + ")");
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new Smoke(color, loc));
}
else if (key.compare(L"spawnGround") == 0)
else if (key.compare("spawnGround") == 0)
{
bool immediate = value[L"immediate"].as_bool();
wstring coalition = value[L"coalition"].as_string();
wstring type = value[L"type"].as_string();
string coalition = to_string(value[L"coalition"]);
string type = to_string(value[L"type"]);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
log(L"Spawning " + coalition + L" ground unit of type " + type + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
log("Spawning " + coalition + " ground unit of type " + type + " at (" + to_string(lat) + ", " + to_string(lng) + ")");
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new SpawnGroundUnit(coalition, type, loc, immediate));
}
else if (key.compare(L"spawnAir") == 0)
else if (key.compare("spawnAir") == 0)
{
bool immediate = value[L"immediate"].as_bool();
wstring coalition = value[L"coalition"].as_string();
wstring type = value[L"type"].as_string();
string coalition = to_string(value[L"coalition"]);
string type = to_string(value[L"type"]);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
double altitude = value[L"altitude"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = altitude;
wstring payloadName = value[L"payloadName"].as_string();
wstring airbaseName = value[L"airbaseName"].as_string();
log(L"Spawning " + coalition + L" air unit of type " + type + L" with payload " + payloadName + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L" " + airbaseName + L")");
string payloadName = to_string(value[L"payloadName"]);
string airbaseName = to_string(value[L"airbaseName"]);
log("Spawning " + coalition + " air unit of type " + type + " with payload " + payloadName + " at (" + to_string(lat) + ", " + to_string(lng) + " " + airbaseName + ")");
command = dynamic_cast<Command*>(new SpawnAircraft(coalition, type, loc, payloadName, airbaseName, immediate));
}
else if (key.compare(L"attackUnit") == 0)
else if (key.compare("attackUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
int targetID = value[L"targetID"].as_integer();
unsigned int targetID = value[L"targetID"].as_integer();
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* target = unitsManager->getUnit(targetID);
wstring unitName;
wstring targetName;
string unitName;
string targetName;
if (unit != nullptr)
unitName = unit->getUnitName();
@ -137,24 +137,24 @@ void Scheduler::handleRequest(wstring key, json::value value)
else
return;
log(L"Unit " + unitName + L" attacking unit " + targetName);
log("Unit " + unitName + " attacking unit " + targetName);
unit->setTargetID(targetID);
unit->setState(State::ATTACK);
}
else if (key.compare(L"followUnit") == 0)
else if (key.compare("followUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
int leaderID = value[L"targetID"].as_integer();
int offsetX = value[L"offsetX"].as_integer();
int offsetY = value[L"offsetY"].as_integer();
int offsetZ = value[L"offsetZ"].as_integer();
unsigned int leaderID = value[L"targetID"].as_integer();
unsigned int offsetX = value[L"offsetX"].as_integer();
unsigned int offsetY = value[L"offsetY"].as_integer();
unsigned int offsetZ = value[L"offsetZ"].as_integer();
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* leader = unitsManager->getUnit(leaderID);
wstring unitName;
wstring leaderName;
string unitName;
string leaderName;
if (unit != nullptr)
unitName = unit->getUnitName();
@ -166,95 +166,95 @@ void Scheduler::handleRequest(wstring key, json::value value)
else
return;
log(L"Unit " + unitName + L" following unit " + leaderName);
log("Unit " + unitName + " following unit " + leaderName);
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
unit->setLeaderID(leaderID);
unit->setState(State::FOLLOW);
}
else if (key.compare(L"changeSpeed") == 0)
else if (key.compare("changeSpeed") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->changeSpeed(value[L"change"].as_string());
unit->changeSpeed(to_string(value[L"change"]));
}
else if (key.compare(L"changeAltitude") == 0)
else if (key.compare("changeAltitude") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->changeAltitude(value[L"change"].as_string());
unit->changeAltitude(to_string(value[L"change"]));
}
else if (key.compare(L"setSpeed") == 0)
else if (key.compare("setSpeed") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredSpeed(value[L"speed"].as_double());
}
else if (key.compare(L"setSpeedType") == 0)
else if (key.compare("setSpeedType") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredSpeedType(value[L"speedType"].as_string());
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
}
else if (key.compare(L"setAltitude") == 0)
else if (key.compare("setAltitude") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredAltitude(value[L"altitude"].as_double());
}
else if (key.compare(L"setAltitudeType") == 0)
else if (key.compare("setAltitudeType") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredAltitudeType(value[L"altitudeType"].as_string());
unit->setDesiredAltitudeType(to_string(value[L"altitudeType"]));
}
else if (key.compare(L"cloneUnit") == 0)
else if (key.compare("cloneUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new Clone(ID, loc));
log(L"Cloning unit " + to_wstring(ID));
log("Cloning unit " + to_string(ID));
}
else if (key.compare(L"setROE") == 0)
else if (key.compare("setROE") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring ROE = value[L"ROE"].as_string();
unsigned char ROE = value[L"ROE"].as_number().is_uint32();
unit->setROE(ROE);
}
else if (key.compare(L"setReactionToThreat") == 0)
else if (key.compare("setReactionToThreat") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring reactionToThreat = value[L"reactionToThreat"].as_string();
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().is_uint32();
unit->setReactionToThreat(reactionToThreat);
}
else if (key.compare(L"setEmissionsCountermeasures") == 0)
else if (key.compare("setEmissionsCountermeasures") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring emissionsCountermeasures = value[L"emissionsCountermeasures"].as_string();
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().is_uint32();
unit->setEmissionsCountermeasures(emissionsCountermeasures);
}
else if (key.compare(L"landAt") == 0)
else if (key.compare("landAt") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
double lat = value[L"location"][L"lat"].as_double();
@ -262,22 +262,22 @@ void Scheduler::handleRequest(wstring key, json::value value)
Coords loc; loc.lat = lat; loc.lng = lng;
unit->landAt(loc);
}
else if (key.compare(L"deleteUnit") == 0)
else if (key.compare("deleteUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
bool explosion = value[L"explosion"].as_bool();
unitsManager->deleteUnit(ID, explosion);
}
else if (key.compare(L"refuel") == 0)
else if (key.compare("refuel") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::REFUEL);
}
else if (key.compare(L"setAdvancedOptions") == 0)
else if (key.compare("setAdvancedOptions") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
@ -287,18 +287,21 @@ void Scheduler::handleRequest(wstring key, json::value value)
unit->setIsAWACS(value[L"isAWACS"].as_bool());
/* TACAN Options */
auto TACAN = value[L"TACAN"];
unit->setTACAN({ TACAN[L"isOn"].as_bool(),
TACAN[L"channel"].as_number().to_int32(),
TACAN[L"XY"].as_string(),
TACAN[L"callsign"].as_string()
});
Options::TACAN TACAN;
TACAN.isOn = value[L"TACAN"][L"isOn"].as_bool();
TACAN.channel = static_cast<unsigned char>(value[L"TACAN"][L"channel"].as_number().to_uint32());
TACAN.XY = to_string(value[L"TACAN"][L"XY"]).at(0);
string callsign = to_string(value[L"TACAN"][L"callsign"]);
if (callsign.length() > 3)
callsign = callsign.substr(0, 3);
strcpy_s(TACAN.callsign, 4, callsign.c_str());
unit->setTACAN(TACAN);
/* Radio Options */
auto radio = value[L"radio"];
unit->setRadio({ radio[L"frequency"].as_number().to_int32(),
radio[L"callsign"].as_number().to_int32(),
radio[L"callsignNumber"].as_number().to_int32()
unit->setRadio({ radio[L"frequency"].as_number().to_uint32(),
static_cast<unsigned char>(radio[L"callsign"].as_number().to_uint32()),
static_cast<unsigned char>(radio[L"callsignNumber"].as_number().to_uint32())
});
/* General Settings */
@ -313,78 +316,78 @@ void Scheduler::handleRequest(wstring key, json::value value)
unit->resetActiveDestination();
}
}
else if (key.compare(L"setFollowRoads") == 0)
else if (key.compare("setFollowRoads") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool followRoads = value[L"followRoads"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setFollowRoads(followRoads);
}
else if (key.compare(L"setOnOff") == 0)
else if (key.compare("setOnOff") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool onOff = value[L"onOff"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setOnOff(onOff);
}
else if (key.compare(L"explosion") == 0)
else if (key.compare("explosion") == 0)
{
int intensity = value[L"intensity"].as_integer();
unsigned int intensity = value[L"intensity"].as_integer();
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
log(L"Adding " + to_wstring(intensity) + L" explosion at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
log("Adding " + to_string(intensity) + " explosion at (" + to_string(lat) + ", " + to_string(lng) + ")");
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new Explosion(intensity, loc));
}
else if (key.compare(L"bombPoint") == 0)
else if (key.compare("bombPoint") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng;
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::BOMB_POINT);
unit->setTargetLocation(loc);
unit->setTargetPosition(loc);
}
else if (key.compare(L"carpetBomb") == 0)
else if (key.compare("carpetBomb") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng;
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::CARPET_BOMB);
unit->setTargetLocation(loc);
unit->setTargetPosition(loc);
}
else if (key.compare(L"bombBuilding") == 0)
else if (key.compare("bombBuilding") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng;
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::BOMB_BUILDING);
unit->setTargetLocation(loc);
unit->setTargetPosition(loc);
}
else if (key.compare(L"fireAtArea") == 0)
else if (key.compare("fireAtArea") == 0)
{
int ID = value[L"ID"].as_integer();
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng;
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::FIRE_AT_AREA);
unit->setTargetLocation(loc);
unit->setTargetPosition(loc);
}
else
{
log(L"Unknown command: " + key);
log("Unknown command: " + key);
}
if (command != nullptr)

View File

@ -13,10 +13,12 @@ bool executeLuaScript(lua_State* L, string path)
if (dostring_in(L, "server", str.c_str()) != 0)
{
log("Error registering " + path);
return false;
}
else
{
log(path + " registered successfully");
return true;
}
}

View File

@ -36,8 +36,7 @@ Server::Server(lua_State* L):
serverThread(nullptr),
runListener(true)
{
refreshJson = json::value::object();
updateJson = json::value::object();
}
void Server::start(lua_State* L)
@ -71,8 +70,8 @@ void Server::handle_get(http_request request)
lock_guard<mutex> guard(mutexLock);
http_response response(status_codes::OK);
string authorization = to_base64("admin:" + to_string(password));
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
string authorization = to_base64("admin:" + password);
if (password == "" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
{
std::exception_ptr eptr;
try {
@ -81,7 +80,8 @@ void Server::handle_get(http_request request)
if (path.size() > 0)
{
if (path[0] == UNITS_URI)
string URI = to_string(path[0]);
if (URI.compare(UNITS_URI) == 0)
{
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
long long time = 0;
@ -94,22 +94,21 @@ void Server::handle_get(http_request request)
time = 0;
}
}
if (time == 0)
unitsManager->getUnitData(answer, 0);
else
answer[L"units"] = updateJson;
// TODO would be nice to optimize this
answer[L"units"] = json::value(to_wstring(unitsManager->getUnitData(time == 0)));
}
else if (path[0] == LOGS_URI)
else if (URI.compare(LOGS_URI) == 0)
{
auto logs = json::value::object();
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
answer[L"logs"] = logs;
}
else if (path[0] == AIRBASES_URI)
else if (URI.compare(AIRBASES_URI) == 0)
answer[L"airbases"] = airbases;
else if (path[0] == BULLSEYE_URI)
else if (URI.compare(BULLSEYE_URI) == 0)
answer[L"bullseyes"] = bullseyes;
else if (path[0] == MISSION_URI)
else if (URI.compare(MISSION_URI) == 0)
answer[L"mission"] = mission;
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
@ -139,8 +138,8 @@ void Server::handle_get(http_request request)
void Server::handle_request(http_request request, function<void(json::value const&, json::value&)> action)
{
http_response response(status_codes::OK);
string authorization = to_base64("admin:" + to_string(password));
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
string authorization = to_base64("admin:" + password);
if (password == "" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization))))
{
auto answer = json::value::object();
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
@ -148,11 +147,8 @@ void Server::handle_request(http_request request, function<void(json::value cons
try
{
auto const& jvalue = task.get();
if (!jvalue.is_null())
{
action(jvalue, answer);
}
}
catch (http_exception const& e)
{
@ -188,7 +184,7 @@ void Server::handle_put(http_request request)
auto value = e.second;
std::exception_ptr eptr;
try {
scheduler->handleRequest(key, value);
scheduler->handleRequest(to_string(key), value);
}
catch (...) {
eptr = std::current_exception(); // capture
@ -200,8 +196,8 @@ void Server::handle_put(http_request request)
void Server::task()
{
wstring address = wstring(REST_ADDRESS);
wstring modLocation;
string address = REST_ADDRESS;
string modLocation;
char* buf = nullptr;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
@ -210,31 +206,31 @@ void Server::task()
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
json::value config = json::value::parse(to_wstring(ss.str()), errorCode);
json::value config = json::value::parse(ss.str(), errorCode);
if (config.is_object() && config.has_object_field(L"server") &&
config[L"server"].has_string_field(L"address") && config[L"server"].has_number_field(L"port"))
{
address = L"http://" + config[L"server"][L"address"].as_string() + L":" + to_wstring(config[L"server"][L"port"].as_number().to_int32());
log(L"Starting server on " + address);
address = "http://" + to_string(config[L"server"][L"address"]) + ":" + to_string(config[L"server"][L"port"].as_number().to_int32());
log("Starting server on " + address);
}
else
log(L"Error reading configuration file. Starting server on " + address);
log("Error reading configuration file. Starting server on " + address);
if (config.is_object() && config.has_object_field(L"authentication") &&
config[L"authentication"].has_string_field(L"password"))
{
password = config[L"authentication"][L"password"].as_string();
password = to_string(config[L"authentication"][L"password"]);
}
else
log(L"Error reading configuration file. No password set.");
log("Error reading configuration file. No password set.");
free(buf);
}
else
{
log(L"DCSOLYMPUS_PATH environment variable is missing, starting server on " + address);
log("DCSOLYMPUS_PATH environment variable is missing, starting server on " + address);
}
http_listener listener(address + L"/" + wstring(REST_URI));
http_listener listener(to_wstring(address + "/" + REST_URI));
std::function<void(http_request)> handle_options = std::bind(&Server::handle_options, this, std::placeholders::_1);
std::function<void(http_request)> handle_get = std::bind(&Server::handle_get, this, std::placeholders::_1);

View File

@ -6,6 +6,9 @@
#include "defines.h"
#include "unitsmanager.h"
#include "base64.hpp"
using namespace base64;
#include <chrono>
using namespace std::chrono;
@ -32,7 +35,7 @@ bool operator==(const Options::GeneralSettings& lhs, const Options::GeneralSetti
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
}
Unit::Unit(json::value json, int ID) :
Unit::Unit(json::value json, unsigned int ID) :
ID(ID)
{
log("Creating unit with ID: " + to_string(ID));
@ -55,18 +58,19 @@ void Unit::setDefaults(bool force)
const bool isUnitAlive = getAlive();
const bool isUnitLeader = unitsManager->isUnitGroupLeader(this);
const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this);
const bool isUnitHuman = getFlags()[L"Human"].as_bool();
if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !isUnitHuman) {
if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !human) {
/* Set the default IDLE state */
setState(State::IDLE);
/* Set desired altitude to be equal to current altitude so the unit does not climb/descend after spawn */
setDesiredAltitude(altitude);
setDesiredAltitude(position.alt);
/* Set the default options (these are all defaults so will only affect the export data, no DCS command will be sent) */
setROE(L"Designated", force);
setReactionToThreat(L"Evade", force);
setEmissionsCountermeasures(L"Defend", force);
setROE(ROE::OPEN_FIRE_WEAPON_FREE, force);
setReactionToThreat(ReactionToThreat::EVADE_FIRE, force);
setEmissionsCountermeasures(EmissionCountermeasure::DEFEND, force);
strcpy_s(TACAN.callsign, 4, "TKR");
setTACAN(TACAN, force);
setRadio(radio, force);
setEPLRS(EPLRS, force);
@ -76,28 +80,13 @@ void Unit::setDefaults(bool force)
}
}
void Unit::addMeasure(wstring key, json::value value)
{
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
if (measures.find(key) == measures.end())
measures[key] = new Measure(value, ms.count());
else
{
if (measures[key]->getValue() != value)
{
measures[key]->setValue(value);
measures[key]->setTime(ms.count());
}
}
}
void Unit::runAILoop() {
/* If the unit is alive, controlled and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
if (!getControlled()) return;
if (!unitsManager->isUnitGroupLeader(this)) return;
if (getFlags()[L"Human"].as_bool()) return;
if (human) return;
// Keep running the AI loop even if the unit is dead if it is the leader of a group which has other members in it
/* Keep running the AI loop even if the unit is dead if it is the leader of a group which has other members in it */
const bool isUnitAlive = getAlive();
const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this);
if (!(isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits)) return;
@ -114,146 +103,182 @@ void Unit::updateExportData(json::value json, double dt)
if (oldPosition != NULL)
{
double dist = 0;
Geodesic::WGS84().Inverse(latitude, longitude, oldPosition.lat, oldPosition.lng, dist);
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, oldPosition.lat, oldPosition.lng, dist);
if (dt > 0)
setSpeed(getSpeed() * 0.95 + (dist / dt) * 0.05);
}
oldPosition = Coords(latitude, longitude, altitude);
oldPosition = position;
if (json.has_string_field(L"Name"))
setName(json[L"Name"].as_string());
setName(to_string(json[L"Name"]));
if (json.has_string_field(L"UnitName"))
setUnitName(json[L"UnitName"].as_string());
setUnitName(to_string(json[L"UnitName"]));
if (json.has_string_field(L"GroupName"))
setGroupName(json[L"GroupName"].as_string());
if (json.has_object_field(L"Type"))
setType(json[L"Type"]);
setGroupName(to_string(json[L"GroupName"]));
if (json.has_number_field(L"Country"))
setCountry(json[L"Country"].as_number().to_int32());
if (json.has_number_field(L"CoalitionID"))
setCoalitionID(json[L"CoalitionID"].as_number().to_int32());
if (json.has_object_field(L"LatLongAlt"))
{
setLatitude(json[L"LatLongAlt"][L"Lat"].as_number().to_double());
setLongitude(json[L"LatLongAlt"][L"Long"].as_number().to_double());
setAltitude(json[L"LatLongAlt"][L"Alt"].as_number().to_double());
Coords position = {
json[L"LatLongAlt"][L"Lat"].as_number().to_double(),
json[L"LatLongAlt"][L"Long"].as_number().to_double(),
json[L"LatLongAlt"][L"Alt"].as_number().to_double()
};
setPosition(position);
}
if (json.has_number_field(L"Heading"))
setHeading(json[L"Heading"].as_number().to_double());
if (json.has_object_field(L"Flags"))
setFlags(json[L"Flags"]);
setHuman(json[L"Flags"][L"Human"].as_bool());
/* All units which contain the name "Olympus" are automatically under AI control */
if (getUnitName().find(L"Olympus") != wstring::npos)
if (getUnitName().find("Olympus") != string::npos)
setControlled(true);
}
void Unit::updateMissionData(json::value json)
{
if (json.has_number_field(L"fuel"))
setFuel(int(json[L"fuel"].as_number().to_double() * 100));
if (json.has_object_field(L"ammo"))
setAmmo(json[L"ammo"]);
if (json.has_object_field(L"contacts"))
setContacts(json[L"contacts"]);
setFuel(short(json[L"fuel"].as_number().to_double() * 100));
if (json.has_object_field(L"ammo")) {
vector<DataTypes::Ammo> ammo;
for (auto const& el : json[L"ammo"].as_object()) {
DataTypes::Ammo ammoItem;
auto ammoJson = el.second;
ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
ammoItem.name = to_string(ammoJson[L"desc"][L"displayName"]);
ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
ammo.push_back(ammoItem);
}
setAmmo(ammo);
}
if (json.has_object_field(L"contacts")) {
vector<DataTypes::Contact> contacts;
for (auto const& el : json[L"ammo"].as_object()) {
DataTypes::Contact contactItem;
auto contactJson = el.second;
contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
string detectionMethod = to_string(contactJson[L"detectionMethod"]);
if (detectionMethod.compare("VISUAL")) contactItem.detectionMethod = 1;
else if (detectionMethod.compare("OPTIC")) contactItem.detectionMethod = 2;
else if (detectionMethod.compare("RADAR")) contactItem.detectionMethod = 4;
else if (detectionMethod.compare("IRST")) contactItem.detectionMethod = 8;
else if (detectionMethod.compare("RWR")) contactItem.detectionMethod = 16;
else if (detectionMethod.compare("DLINK")) contactItem.detectionMethod = 32;
contacts.push_back(contactItem);
}
setContacts(contacts);
}
if (json.has_boolean_field(L"hasTask"))
setHasTask(json[L"hasTask"].as_bool());
}
json::value Unit::getData(long long time, bool getAll)
DataTypes::DataPacket Unit::getDataPacket()
{
auto json = json::value::object();
unsigned int bitmask = 0;
bitmask |= alive << 0;
bitmask |= human << 1;
bitmask |= controlled << 2;
bitmask |= hasTask << 3;
bitmask |= desiredAltitudeType << 16;
bitmask |= desiredSpeedType << 17;
bitmask |= isTanker << 18;
bitmask |= isAWACS << 19;
bitmask |= onOff << 19;
bitmask |= followRoads << 19;
bitmask |= EPLRS << 20;
bitmask |= generalSettings.prohibitAA << 21;
bitmask |= generalSettings.prohibitAfterburner << 22;
bitmask |= generalSettings.prohibitAG << 23;
bitmask |= generalSettings.prohibitAirWpn << 24;
bitmask |= generalSettings.prohibitJettison << 25;
/* If the unit is in a group, task & option data is given by the group leader */
if (unitsManager->isUnitInGroup(this) && !unitsManager->isUnitGroupLeader(this))
json = unitsManager->getGroupLeader(this)->getData(time, true);
DataTypes::DataPacket datapacket{
ID,
bitmask,
position,
speed,
heading,
fuel,
desiredSpeed,
desiredAltitude,
targetID,
targetPosition,
state,
ROE,
reactionToThreat,
emissionsCountermeasures,
TACAN,
radio
};
return datapacket;
}
string Unit::getData(bool refresh)
{
/* Prepare the data in a stringstream */
stringstream ss;
/* Reserve data for:
1) DataPacket;
2) Length of active path;
3) Active path;
*/
char* data = (char*)malloc(sizeof(DataTypes::DataPacket) + sizeof(unsigned short) + activePath.size() * sizeof(Coords));
unsigned int offset = 0;
/* Prepare the data packet and copy it to memory */
DataTypes::DataPacket dataPacket;
/* If the unit is in a group, get the datapacket from the group leader and only replace the position, speed and heading */
if (unitsManager->isUnitInGroup(this) && !unitsManager->isUnitGroupLeader(this)) {
dataPacket = unitsManager->getGroupLeader(this)->getDataPacket();
dataPacket.position = position;
dataPacket.speed = speed;
dataPacket.heading = heading;
}
else
dataPacket = getDataPacket();
/********** Base data **********/
json[L"baseData"] = json::value::object();
for (auto key : { L"controlled", L"name", L"unitName", L"groupName", L"alive", L"category"})
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"baseData"][key] = measures[key]->getValue();
}
if (json[L"baseData"].size() == 0)
json.erase(L"baseData");
memcpy(data + offset, &dataPacket, sizeof(dataPacket));
offset += sizeof(dataPacket);
if (alive || getAll) {
/********** Flight data **********/
json[L"flightData"] = json::value::object();
for (auto key : { L"latitude", L"longitude", L"altitude", L"speed", L"heading" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"flightData"][key] = measures[key]->getValue();
}
if (json[L"flightData"].size() == 0)
json.erase(L"flightData");
/* Prepare the path memory and copy it to memory */
std::vector<Coords> path;
for (const Coords& c : activePath)
path.push_back(c);
unsigned short pathLength = activePath.size();
/********** Mission data **********/
json[L"missionData"] = json::value::object();
for (auto key : { L"fuel", L"ammo", L"contacts", L"hasTask", L"coalition", L"flags" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"missionData"][key] = measures[key]->getValue();
}
if (json[L"missionData"].size() == 0)
json.erase(L"missionData");
memcpy(data + offset, &pathLength, sizeof(unsigned short));
offset += sizeof(unsigned short);
memcpy(data + offset, &path, activePath.size() * sizeof(Coords));
offset += sizeof(unsigned short);
/********** Formation data **********/
json[L"formationData"] = json::value::object();
for (auto key : { L"leaderID" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"formationData"][key] = measures[key]->getValue();
}
if (json[L"formationData"].size() == 0)
json.erase(L"formationData");
ss << to_base64(data, offset);
/* If the unit is in a group, task & option data is given by the group leader */
if (unitsManager->isUnitGroupLeader(this)) {
/********** Task data **********/
json[L"taskData"] = json::value::object();
for (auto key : { L"currentState", L"currentTask", L"desiredSpeed", L"desiredAltitude", L"desiredSpeedType", L"desiredAltitudeType", L"activePath", L"isTanker", L"isAWACS", L"onOff", L"followRoads", L"targetID", L"targetLocation" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"taskData"][key] = measures[key]->getValue();
}
if (json[L"taskData"].size() == 0)
json.erase(L"taskData");
/********** Options data **********/
json[L"optionsData"] = json::value::object();
for (auto key : { L"ROE", L"reactionToThreat", L"emissionsCountermeasures", L"TACAN", L"radio", L"generalSettings" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"optionsData"][key] = measures[key]->getValue();
}
if (json[L"optionsData"].size() == 0)
json.erase(L"optionsData");
}
if (refresh) {
ss << name;
ss << unitName;
ss << groupName;
ss << getCategory();
ss << coalition;
}
return json;
return ss.str();
}
void Unit::setActivePath(list<Coords> newPath)
{
activePath = newPath;
resetActiveDestination();
auto path = json::value::object();
if (activePath.size() > 0) {
int count = 1;
for (auto& destination : activePath)
{
auto json = json::value::object();
json[L"lat"] = destination.lat;
json[L"lng"] = destination.lng;
json[L"alt"] = destination.alt;
path[to_wstring(count++)] = json;
}
}
addMeasure(L"activePath", path);
}
void Unit::clearActivePath()
@ -283,28 +308,27 @@ void Unit::popActivePathFront()
setActivePath(path);
}
void Unit::setCoalitionID(int newCoalitionID)
void Unit::setCoalitionID(unsigned int newCoalitionID)
{
if (newCoalitionID == 0)
coalition = L"neutral";
coalition = "neutral";
else if (newCoalitionID == 1)
coalition = L"red";
coalition = "red";
else
coalition = L"blue";
addMeasure(L"coalition", json::value(coalition));
coalition = "blue";
}
int Unit::getCoalitionID()
unsigned int Unit::getCoalitionID()
{
if (coalition == L"neutral")
if (coalition == "neutral")
return 0;
else if (coalition == L"red")
else if (coalition == "red")
return 1;
else
return 2;
}
wstring Unit::getTargetName()
string Unit::getTargetName()
{
if (isTargetAlive())
{
@ -312,7 +336,7 @@ wstring Unit::getTargetName()
if (target != nullptr)
return target->getUnitName();
}
return L"";
return "";
}
bool Unit::isTargetAlive()
@ -327,7 +351,7 @@ bool Unit::isTargetAlive()
return false;
}
wstring Unit::getLeaderName()
string Unit::getLeaderName()
{
if (isLeaderAlive())
{
@ -335,7 +359,7 @@ wstring Unit::getLeaderName()
if (leader != nullptr)
return leader->getUnitName();
}
return L"";
return "";
}
bool Unit::isLeaderAlive()
@ -369,84 +393,52 @@ void Unit::setFormationOffset(Offset newFormationOffset)
resetTask();
}
void Unit::setROE(wstring newROE, bool force) {
addMeasure(L"ROE", json::value(newROE));
void Unit::setROE(unsigned char newROE, bool force)
{
if (ROE != newROE || force) {
ROE = newROE;
int ROEEnum;
if (ROE.compare(L"Free") == 0)
ROEEnum = ROE::WEAPON_FREE;
else if (ROE.compare(L"Designated free") == 0)
ROEEnum = ROE::OPEN_FIRE_WEAPON_FREE;
else if (ROE.compare(L"Designated") == 0)
ROEEnum = ROE::OPEN_FIRE;
else if (ROE.compare(L"Return") == 0)
ROEEnum = ROE::RETURN_FIRE;
else if (ROE.compare(L"Hold") == 0)
ROEEnum = ROE::WEAPON_HOLD;
else
return;
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, ROEEnum));
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, ROE));
scheduler->appendCommand(command);
}
}
void Unit::setReactionToThreat(wstring newReactionToThreat, bool force) {
addMeasure(L"reactionToThreat", json::value(newReactionToThreat));
void Unit::setReactionToThreat(unsigned char newReactionToThreat, bool force)
{
if (reactionToThreat != newReactionToThreat || force) {
reactionToThreat = newReactionToThreat;
int reactionToThreatEnum;
if (reactionToThreat.compare(L"None") == 0)
reactionToThreatEnum = ReactionToThreat::NO_REACTION;
else if (reactionToThreat.compare(L"Passive") == 0)
reactionToThreatEnum = ReactionToThreat::PASSIVE_DEFENCE;
else if (reactionToThreat.compare(L"Evade") == 0)
reactionToThreatEnum = ReactionToThreat::EVADE_FIRE;
else if (reactionToThreat.compare(L"Escape") == 0)
reactionToThreatEnum = ReactionToThreat::BYPASS_AND_ESCAPE;
else if (reactionToThreat.compare(L"Abort") == 0)
reactionToThreatEnum = ReactionToThreat::ALLOW_ABORT_MISSION;
else
return;
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, reactionToThreat));
scheduler->appendCommand(command);
}
}
void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force) {
addMeasure(L"emissionsCountermeasures", json::value(newEmissionsCountermeasures));
void Unit::setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures, bool force)
{
if (emissionsCountermeasures != newEmissionsCountermeasures || force) {
emissionsCountermeasures = newEmissionsCountermeasures;
int radarEnum;
int flareEnum;
int ECMEnum;
if (emissionsCountermeasures.compare(L"Silent") == 0)
unsigned int radarEnum;
unsigned int flareEnum;
unsigned int ECMEnum;
if (emissionsCountermeasures == EmissionCountermeasure::SILENT)
{
radarEnum = RadarUse::NEVER;
flareEnum = FlareUse::NEVER;
ECMEnum = ECMUse::NEVER_USE;
}
else if (emissionsCountermeasures.compare(L"Attack") == 0)
else if (emissionsCountermeasures == EmissionCountermeasure::ATTACK)
{
radarEnum = RadarUse::FOR_ATTACK_ONLY;
flareEnum = FlareUse::AGAINST_FIRED_MISSILE;
ECMEnum = ECMUse::USE_IF_ONLY_LOCK_BY_RADAR;
}
else if (emissionsCountermeasures.compare(L"Defend") == 0)
else if (emissionsCountermeasures == EmissionCountermeasure::DEFEND)
{
radarEnum = RadarUse::FOR_SEARCH_IF_REQUIRED;
flareEnum = FlareUse::WHEN_FLYING_IN_SAM_WEZ;
ECMEnum = ECMUse::USE_IF_DETECTED_LOCK_BY_RADAR;
}
else if (emissionsCountermeasures.compare(L"Free") == 0)
else if (emissionsCountermeasures == EmissionCountermeasure::FREE)
{
radarEnum = RadarUse::FOR_CONTINUOUS_SEARCH;
flareEnum = FlareUse::WHEN_FLYING_NEAR_ENEMIES;
@ -468,42 +460,37 @@ void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool
}
}
void Unit::landAt(Coords loc) {
void Unit::landAt(Coords loc)
{
clearActivePath();
pushActivePathBack(loc);
setState(State::LAND);
}
void Unit::setIsTanker(bool newIsTanker) {
void Unit::setIsTanker(bool newIsTanker)
{
isTanker = newIsTanker;
resetTask();
addMeasure(L"isTanker", json::value(newIsTanker));
}
void Unit::setIsAWACS(bool newIsAWACS) {
void Unit::setIsAWACS(bool newIsAWACS)
{
isAWACS = newIsAWACS;
resetTask();
addMeasure(L"isAWACS", json::value(newIsAWACS));
setEPLRS(isAWACS);
}
void Unit::setTACAN(Options::TACAN newTACAN, bool force) {
auto json = json::value();
json[L"isOn"] = json::value(newTACAN.isOn);
json[L"channel"] = json::value(newTACAN.channel);
json[L"XY"] = json::value(newTACAN.XY);
json[L"callsign"] = json::value(newTACAN.callsign);
addMeasure(L"TACAN", json);
void Unit::setTACAN(Options::TACAN newTACAN, bool force)
{
if (TACAN != newTACAN || force)
{
TACAN = newTACAN;
if (TACAN.isOn) {
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS << "{"
<< "id = 'ActivateBeacon',"
<< "params = {"
<< "type = " << ((TACAN.XY.compare(L"X") == 0) ? 4 : 5) << ","
<< "type = " << ((TACAN.XY == 'X' == 0) ? 4 : 5) << ","
<< "system = 3,"
<< "name = \"Olympus_TACAN\","
<< "callsign = \"" << TACAN.callsign << "\", "
@ -514,7 +501,7 @@ void Unit::setTACAN(Options::TACAN newTACAN, bool force) {
scheduler->appendCommand(command);
}
else {
std::wostringstream commandSS;
std::ostringstream commandSS;
commandSS << "{"
<< "id = 'DeactivateBeacon',"
<< "params = {"
@ -526,19 +513,13 @@ void Unit::setTACAN(Options::TACAN newTACAN, bool force) {
}
}
void Unit::setRadio(Options::Radio newRadio, bool force) {
auto json = json::value();
json[L"frequency"] = json::value(newRadio.frequency);
json[L"callsign"] = json::value(newRadio.callsign);
json[L"callsignNumber"] = json::value(newRadio.callsignNumber);
addMeasure(L"radio", json);
void Unit::setRadio(Options::Radio newRadio, bool force)
{
if (radio != newRadio || force)
{
radio = newRadio;
std::wostringstream commandSS;
std::ostringstream commandSS;
Command* command;
commandSS << "{"
@ -552,7 +533,7 @@ void Unit::setRadio(Options::Radio newRadio, bool force) {
scheduler->appendCommand(command);
// Clear the stringstream
commandSS.str(wstring());
commandSS.str(string(""));
commandSS << "{"
<< "id = 'SetCallsign',"
@ -568,12 +549,12 @@ void Unit::setRadio(Options::Radio newRadio, bool force) {
void Unit::setEPLRS(bool newEPLRS, bool force)
{
//addMeasure(L"EPLRS", json::value(newEPLRS));
//addMeasure("EPLRS", json::value(newEPLRS));
//
//if (EPLRS != newEPLRS || force) {
// EPLRS = newEPLRS;
//
// std::wostringstream commandSS;
// std::ostringstream commandSS;
// commandSS << "{"
// << "id = 'EPLRS',"
// << "params = {"
@ -585,16 +566,8 @@ void Unit::setEPLRS(bool newEPLRS, bool force)
//}
}
void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force) {
auto json = json::value();
json[L"prohibitJettison"] = json::value(newGeneralSettings.prohibitJettison);
json[L"prohibitAA"] = json::value(newGeneralSettings.prohibitAA);
json[L"prohibitAG"] = json::value(newGeneralSettings.prohibitAG);
json[L"prohibitAfterburner"] = json::value(newGeneralSettings.prohibitAfterburner);
json[L"prohibitAirWpn"] = json::value(newGeneralSettings.prohibitAirWpn);
addMeasure(L"generalSettings", json);
void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force)
{
if (generalSettings != newGeneralSettings)
{
generalSettings = newGeneralSettings;
@ -613,47 +586,47 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool
}
}
void Unit::setDesiredSpeed(double newDesiredSpeed) {
void Unit::setDesiredSpeed(double newDesiredSpeed)
{
desiredSpeed = newDesiredSpeed;
addMeasure(L"desiredSpeed", json::value(newDesiredSpeed));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredAltitude(double newDesiredAltitude) {
void Unit::setDesiredAltitude(double newDesiredAltitude)
{
desiredAltitude = newDesiredAltitude;
addMeasure(L"desiredAltitude", json::value(newDesiredAltitude));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredSpeedType(wstring newDesiredSpeedType) {
desiredSpeedType = newDesiredSpeedType;
addMeasure(L"desiredSpeedType", json::value(newDesiredSpeedType));
void Unit::setDesiredSpeedType(string newDesiredSpeedType)
{
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredAltitudeType(wstring newDesiredAltitudeType) {
desiredAltitudeType = newDesiredAltitudeType;
addMeasure(L"desiredAltitudeType", json::value(newDesiredAltitudeType));
void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
{
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::goToDestination(wstring enrouteTask)
void Unit::goToDestination(string enrouteTask)
{
if (activeDestination != NULL)
{
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType(), getDesiredAltitude(), getDesiredAltitudeType(), enrouteTask, getCategory()));
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType()? "GS": "CAS", getDesiredAltitude(), getDesiredAltitudeType()? "AGL" : "ASL", enrouteTask, getCategory()));
scheduler->appendCommand(command);
setHasTask(true);
}
@ -667,16 +640,17 @@ bool Unit::isDestinationReached(double threshold)
for (auto const& p: unitsManager->getGroupMembers(groupName))
{
double dist = 0;
Geodesic::WGS84().Inverse(p->getLatitude(), p->getLongitude(), activeDestination.lat, activeDestination.lng, dist);
Geodesic::WGS84().Inverse(p->getPosition().lat, p->getPosition().lng, activeDestination.lat, activeDestination.lng, dist);
if (dist < threshold)
{
log(unitName + L" destination reached");
log(unitName + " destination reached");
return true;
}
else {
return false;
}
}
}
return false;
}
else
return true;
@ -687,13 +661,13 @@ bool Unit::setActiveDestination()
if (activePath.size() > 0)
{
activeDestination = activePath.front();
log(unitName + L" active destination set to queue front");
log(unitName + " active destination set to queue front");
return true;
}
else
{
activeDestination = Coords(0);
log(unitName + L" active destination set to NULL");
log(unitName + " active destination set to NULL");
return false;
}
}
@ -706,7 +680,7 @@ bool Unit::updateActivePath(bool looping)
if (looping)
pushActivePathBack(activePath.front());
popActivePathFront();
log(unitName + L" active path front popped");
log(unitName + " active path front popped");
return true;
}
else {
@ -714,15 +688,13 @@ bool Unit::updateActivePath(bool looping)
}
}
void Unit::setTargetLocation(Coords newTargetLocation) {
targetLocation = newTargetLocation;
auto json = json::value();
json[L"latitude"] = json::value(newTargetLocation.lat);
json[L"longitude"] = json::value(newTargetLocation.lng);
addMeasure(L"targetLocation", json::value(json));
void Unit::setTargetPosition(Coords newTargetPosition)
{
targetPosition = newTargetPosition;
}
bool Unit::checkTaskFailed() {
bool Unit::checkTaskFailed()
{
if (getHasTask())
return false;
else {
@ -736,7 +708,7 @@ void Unit::resetTaskFailedCounter() {
taskCheckCounter = TASK_CHECK_INIT_VALUE;
}
void Unit::setHasTask(bool newHasTask) {
void Unit::setHasTask(bool newHasTask)
{
hasTask = newHasTask;
addMeasure(L"hasTask", json::value(newHasTask));
}

View File

@ -22,7 +22,7 @@ UnitsManager::~UnitsManager()
}
Unit* UnitsManager::getUnit(int ID)
Unit* UnitsManager::getUnit(unsigned int ID)
{
if (units.find(ID) == units.end()) {
return nullptr;
@ -35,7 +35,7 @@ Unit* UnitsManager::getUnit(int ID)
bool UnitsManager::isUnitInGroup(Unit* unit)
{
if (unit != nullptr) {
wstring groupName = unit->getGroupName();
string groupName = unit->getGroupName();
for (auto const& p : units)
{
if (p.second->getGroupName().compare(groupName) == 0 && p.second != unit)
@ -57,7 +57,7 @@ bool UnitsManager::isUnitGroupLeader(Unit* unit)
Unit* UnitsManager::getGroupLeader(Unit* unit)
{
if (unit != nullptr) {
wstring groupName = unit->getGroupName();
string groupName = unit->getGroupName();
/* Find the first unit that has the same groupName */
for (auto const& p : units)
@ -69,7 +69,7 @@ Unit* UnitsManager::getGroupLeader(Unit* unit)
return nullptr;
}
vector<Unit*> UnitsManager::getGroupMembers(wstring groupName)
vector<Unit*> UnitsManager::getGroupMembers(string groupName)
{
vector<Unit*> members;
for (auto const& p : units)
@ -80,7 +80,7 @@ vector<Unit*> UnitsManager::getGroupMembers(wstring groupName)
return members;
}
Unit* UnitsManager::getGroupLeader(int ID)
Unit* UnitsManager::getGroupLeader(unsigned int ID)
{
Unit* unit = getUnit(ID);
return getGroupLeader(unit);
@ -88,12 +88,12 @@ Unit* UnitsManager::getGroupLeader(int ID)
void UnitsManager::updateExportData(lua_State* L, double dt)
{
map<int, json::value> unitJSONs = getAllUnits(L);
map<unsigned int, json::value> unitJSONs = getAllUnits(L);
/* Update all units, create them if needed TODO: move code to get constructor in dedicated function */
for (auto const& p : unitJSONs)
{
int ID = p.first;
unsigned int ID = p.first;
if (units.count(ID) == 0)
{
json::value type = static_cast<json::value>(p.second)[L"Type"];
@ -139,7 +139,7 @@ void UnitsManager::updateMissionData(json::value missionData)
/* Update all units */
for (auto const& p : units)
{
int ID = p.first;
unsigned int ID = p.first;
if (missionData.has_field(to_wstring(ID)))
p.second->updateMissionData(missionData[to_wstring(ID)]);
}
@ -151,29 +151,15 @@ void UnitsManager::runAILoop() {
unit.second->runAILoop();
}
void UnitsManager::getUnitData(json::value& answer, long long time)
string UnitsManager::getUnitData(bool refresh)
{
auto unitsJson = json::value::object();
stringstream ss;
for (auto const& p : units)
{
auto unitJson = p.second->getData(time);
if (unitJson.size() > 0)
unitsJson[to_wstring(p.first)] = unitJson;
}
answer[L"units"] = unitsJson;
ss << p.second->getData(refresh);
return ss.str();
}
void UnitsManager::appendUnitData(int ID, json::value& answer, long long time)
{
Unit* unit = getUnit(ID);
if (unit != nullptr) {
auto unitJson = unit->getData(time);
if (unitJson.size() > 0)
answer[to_wstring(ID)] = unitJson;
}
}
void UnitsManager::deleteUnit(int ID, bool explosion)
void UnitsManager::deleteUnit(unsigned int ID, bool explosion)
{
if (getUnit(ID) != nullptr)
{
@ -182,7 +168,7 @@ void UnitsManager::deleteUnit(int ID, bool explosion)
}
}
void UnitsManager::acquireControl(int ID) {
void UnitsManager::acquireControl(unsigned int ID) {
Unit* unit = getUnit(ID);
if (unit != nullptr) {
for (auto const& groupMember : getGroupMembers(unit->getGroupName())) {

View File

@ -13,21 +13,19 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Weapon */
Weapon::Weapon(json::value json, int ID) : Unit(json, ID)
Weapon::Weapon(json::value json, unsigned int ID) : Unit(json, ID)
{
};
/* Missile */
Missile::Missile(json::value json, int ID) : Weapon(json, ID)
Missile::Missile(json::value json, unsigned int ID) : Weapon(json, ID)
{
log("New Missile created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
};
/* Bomb */
Bomb::Bomb(json::value json, int ID) : Weapon(json, ID)
Bomb::Bomb(json::value json, unsigned int ID) : Weapon(json, ID)
{
log("New Bomb created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
};

View File

@ -5,8 +5,8 @@
void DllExport LogInfo(lua_State* L, string message);
void DllExport LogWarning(lua_State* L, string message);
void DllExport LogError(lua_State* L, string message);
void DllExport Log(lua_State* L, string message, int level);
void DllExport Log(lua_State* L, string message, unsigned int level);
int DllExport dostring_in(lua_State* L, string target, string command);
map<int, json::value> DllExport getAllUnits(lua_State* L);
int DllExport TACANChannelToFrequency(int channel, wstring XY);
map<unsigned int, json::value> DllExport getAllUnits(lua_State* L);
unsigned int DllExport TACANChannelToFrequency(unsigned int channel, char XY);

View File

@ -42,7 +42,7 @@ void LogError(lua_State* L, string message)
Log(L, message, errorLevel);
}
void Log(lua_State* L, string message, int level)
void Log(lua_State* L, string message, unsigned int level)
{
STACK_INIT;
@ -56,10 +56,10 @@ void Log(lua_State* L, string message, int level)
STACK_CLEAN;
}
map<int, json::value> getAllUnits(lua_State* L)
map<unsigned int, json::value> getAllUnits(lua_State* L)
{
int res = 0;
map<int, json::value> units;
unsigned int res = 0;
map<unsigned int, json::value> units;
STACK_INIT;
@ -83,7 +83,8 @@ map<int, json::value> getAllUnits(lua_State* L)
lua_pushnil(L);
while (lua_next(L, 2) != 0)
{
int ID = lua_tonumber(L, -2);
unsigned int ID = lua_tonumber(L, -2);
// TODO more efficient method can be used, converting all the lua data to a json object may be overkill
units[ID] = luaTableToJSON(L, -1);
STACK_POP(1)
}
@ -103,8 +104,8 @@ int dostring_in(lua_State* L, string target, string command)
return lua_pcall(L, 2, 0, 0);
}
int TACANChannelToFrequency(int channel, wstring XY)
unsigned int TACANChannelToFrequency(unsigned int channel, char XY)
{
int basef = (XY == L"X" && channel > 63) || (XY == L"Y" && channel < 64) ? 1087: 961;
unsigned int basef = (XY == 'X' && channel > 63) || (XY == 'Y' && channel < 64) ? 1087 : 961;
return (basef + channel) * 1000000;
}

View File

@ -3,4 +3,4 @@
void DllExport log(const std::string& sMessage);
void DllExport log(const std::wstring& sMessage);
void DllExport getLogsJSON(json::value& json, int logsNumber = NULL);
void DllExport getLogsJSON(json::value& json, unsigned int logsNumber = NULL);

View File

@ -7,7 +7,7 @@ class Logger
public:
void log(const string& sMessage);
void log(const wstring& sMessage);
void toJSON(json::value& json, int logsNumber = NULL);
void toJSON(json::value& json, unsigned int logsNumber = NULL);
static Logger* GetLogger();

View File

@ -14,7 +14,7 @@ void log(const wstring& message)
LOGGER->log(message);
}
void getLogsJSON(json::value& json, int logsNumber)
void getLogsJSON(json::value& json, unsigned int logsNumber)
{
LOGGER->toJSON(json, logsNumber);
}

View File

@ -32,10 +32,10 @@ void Logger::Close()
m_Logfile.close();
}
void Logger::toJSON(json::value& json, int logsNumber)
void Logger::toJSON(json::value& json, unsigned int logsNumber)
{
lock_guard<mutex> guard(mutexLock);
int i = 0;
unsigned int i = 0;
for (auto itr = m_logs.end(); itr != m_logs.begin(); --itr)
{
json[to_wstring(m_logs.size() - 1 - i)] = json::value::string(to_wstring(*itr));

View File

@ -2,12 +2,12 @@
#define VERSION "v0.2.1"
#define LOG_NAME "Olympus_log.txt"
#define REST_ADDRESS L"http://localhost:30000"
#define REST_URI L"olympus"
#define UNITS_URI L"units"
#define LOGS_URI L"logs"
#define AIRBASES_URI L"airbases"
#define BULLSEYE_URI L"bullseyes"
#define MISSION_URI L"mission"
#define REST_ADDRESS "http://localhost:30000"
#define REST_URI "olympus"
#define UNITS_URI "units"
#define LOGS_URI "logs"
#define AIRBASES_URI "airbases"
#define BULLSEYE_URI "bullseyes"
#define MISSION_URI "mission"
#define UPDATE_TIME_INTERVAL 0.25

View File

@ -20,6 +20,7 @@
#include <codecvt>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <cpprest/streams.h>
#include <set>
using namespace std;

View File

@ -16,18 +16,19 @@ struct Offset {
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const DllExport std::string CurrentDateTime();
std::wstring DllExport to_wstring(const std::string& str);
std::string DllExport to_string(json::value& value);
std::string DllExport to_string(const std::wstring& wstr);
std::string DllExport random_string(size_t length);
bool DllExport operator== (const Coords& a, const Coords& b);
bool DllExport operator!= (const Coords& a, const Coords& b);
bool DllExport operator== (const Coords& a, const int& b);
bool DllExport operator!= (const Coords& a, const int& b);
bool DllExport operator== (const Coords& a, const double& b);
bool DllExport operator!= (const Coords& a, const double& b);
bool DllExport operator== (const Offset& a, const Offset& b);
bool DllExport operator!= (const Offset& a, const Offset& b);
bool DllExport operator== (const Offset& a, const int& b);
bool DllExport operator!= (const Offset& a, const int& b);
bool DllExport operator== (const Offset& a, const double& b);
bool DllExport operator!= (const Offset& a, const double& b);
double DllExport knotsToMs(const double knots);
double DllExport msToKnots(const double ms);

View File

@ -14,12 +14,16 @@ const std::string CurrentDateTime()
std::wstring to_wstring(const std::string& str)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
unsigned int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (unsigned int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (unsigned int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
std::string to_string(json::value value) {
return to_string(value.as_string());
}
std::string to_string(const std::wstring& wstr)
{
if (wstr.empty())
@ -27,14 +31,14 @@ std::string to_string(const std::wstring& wstr)
return "";
}
const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (int)wstr.size(), nullptr, 0, nullptr, nullptr);
const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (unsigned int)wstr.size(), nullptr, 0, nullptr, nullptr);
if (size_needed <= 0)
{
throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed));
}
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (int)wstr.size(), &result.at(0), size_needed, nullptr, nullptr);
WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (unsigned int)wstr.size(), &result.at(0), size_needed, nullptr, nullptr);
return result;
}
@ -56,13 +60,13 @@ std::string random_string(size_t length)
bool operator== (const Coords& a, const Coords& b) { return a.lat == b.lat && a.lng == b.lng && a.alt == b.alt; }
bool operator!= (const Coords& a, const Coords& b) { return !(a == b); }
bool operator== (const Coords& a, const int& b) { return a.lat == b && a.lng == b && a.alt == b; }
bool operator!= (const Coords& a, const int& b) { return !(a == b); }
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b; }
bool operator!= (const Coords& a, const double& b) { return !(a == b); }
bool operator== (const Offset& a, const Offset& b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
bool operator!= (const Offset& a, const Offset& b) { return !(a == b); }
bool operator== (const Offset& a, const int& b) { return a.x == b && a.y == b && a.z == b; }
bool operator!= (const Offset& a, const int& b) { return !(a == b); }
bool operator== (const Offset& a, const double& b) { return a.x == b && a.y == b && a.z == b; }
bool operator!= (const Offset& a, const double& b) { return !(a == b); }
double knotsToMs(const double knots) {
@ -79,4 +83,4 @@ double ftToM(const double ft) {
double mToFt(const double m) {
return m / 0.3048;
}
}

View File

@ -6,76 +6,81 @@
namespace base64 {
inline std::string get_base64_chars() {
static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return base64_chars;
}
inline std::string get_base64_chars() {
static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return base64_chars;
}
inline std::string to_base64(std::string const& data) {
return to_base64(data.c_str(), data.length());
}
inline std::string to_base64(std::string const &data) {
int counter = 0;
uint32_t bit_stream = 0;
const std::string base64_chars = get_base64_chars();
std::string encoded;
int offset = 0;
for (unsigned char c : data) {
auto num_val = static_cast<unsigned int>(c);
offset = 16 - counter % 3 * 8;
bit_stream += num_val << offset;
if (offset == 16) {
encoded += base64_chars.at(bit_stream >> 18 & 0x3f);
}
if (offset == 8) {
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
}
if (offset == 0 && counter != 3) {
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
encoded += base64_chars.at(bit_stream & 0x3f);
bit_stream = 0;
}
counter++;
}
if (offset == 16) {
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
encoded += "==";
}
if (offset == 8) {
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
encoded += '=';
}
return encoded;
}
inline std::string from_base64(std::string const &data) {
int counter = 0;
uint32_t bit_stream = 0;
std::string decoded;
int offset = 0;
const std::string base64_chars = get_base64_chars();
for (unsigned char c : data) {
auto num_val = base64_chars.find(c);
if (num_val != std::string::npos) {
offset = 18 - counter % 4 * 6;
bit_stream += num_val << offset;
if (offset == 12) {
decoded += static_cast<char>(bit_stream >> 16 & 0xff);
}
if (offset == 6) {
decoded += static_cast<char>(bit_stream >> 8 & 0xff);
}
if (offset == 0 && counter != 4) {
decoded += static_cast<char>(bit_stream & 0xff);
bit_stream = 0;
}
} else if (c != '=') {
return std::string();
}
counter++;
}
return decoded;
}
inline std::string to_base64(const char* data, size_t size) {
int counter = 0;
uint32_t bit_stream = 0;
const std::string base64_chars = get_base64_chars();
std::string encoded;
encoded.reserve(ceil(4.0 / 3.0 * size));
int offset = 0;
for (unsigned int idx = 0; idx < size; idx++) {
unsigned char c = data[idx];
auto num_val = static_cast<unsigned int>(c);
offset = 16 - counter % 3 * 8;
bit_stream += num_val << offset;
if (offset == 16) {
encoded += base64_chars.at(bit_stream >> 18 & 0x3f);
}
if (offset == 8) {
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
}
if (offset == 0 && counter != 3) {
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
encoded += base64_chars.at(bit_stream & 0x3f);
bit_stream = 0;
}
counter++;
}
if (offset == 16) {
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
encoded += "==";
}
if (offset == 8) {
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
encoded += '=';
}
return encoded;
}
inline std::string from_base64(std::string const& data) {
int counter = 0;
uint32_t bit_stream = 0;
std::string decoded;
int offset = 0;
const std::string base64_chars = get_base64_chars();
for (unsigned char c : data) {
auto num_val = base64_chars.find(c);
if (num_val != std::string::npos) {
offset = 18 - counter % 4 * 6;
bit_stream += num_val << offset;
if (offset == 12) {
decoded += static_cast<char>(bit_stream >> 16 & 0xff);
}
if (offset == 6) {
decoded += static_cast<char>(bit_stream >> 8 & 0xff);
}
if (offset == 0 && counter != 4) {
decoded += static_cast<char>(bit_stream & 0xff);
bit_stream = 0;
}
}
else if (c != '=') {
return std::string();
}
counter++;
}
return decoded;
}
}
#endif // BASE_64_HPP