mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Merge remote-tracking branch 'origin/performance-optimization' into 326-add-advanced-rts-options
This commit is contained in:
@@ -12,6 +12,7 @@ class AirUnit : public Unit
|
||||
public:
|
||||
AirUnit(json::value json, unsigned int ID);
|
||||
|
||||
virtual void setDefaults(bool force = false);
|
||||
virtual void setState(unsigned char newState);
|
||||
|
||||
virtual void changeSpeed(string change) = 0;
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
|
||||
private:
|
||||
const string color;
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
priority = immediate? CommandPriority::IMMEDIATE: CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return immediate? 1: 100; }
|
||||
virtual unsigned int getLoad() { return immediate? 1: 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 100; }
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -209,7 +209,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 100; }
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 100; }
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -258,7 +258,7 @@ public:
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 100; }
|
||||
virtual unsigned int getLoad() { return 30; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
@@ -278,7 +278,7 @@ public:
|
||||
immediate = immediate;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return immediate? 1: 20; }
|
||||
virtual unsigned int getLoad() { return immediate? 1: 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
@@ -297,7 +297,7 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -362,7 +362,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -383,7 +383,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -401,7 +401,7 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString(lua_State* L);
|
||||
virtual unsigned int getLoad() { return 10; }
|
||||
virtual unsigned int getLoad() { return 4; }
|
||||
|
||||
private:
|
||||
const Coords location;
|
||||
|
||||
@@ -9,10 +9,11 @@ public:
|
||||
GroundUnit(json::value json, unsigned int ID);
|
||||
|
||||
virtual void setState(unsigned char newState);
|
||||
virtual void setDefaults(bool force = false);
|
||||
|
||||
virtual void changeSpeed(string change);
|
||||
virtual void setOnOff(bool newOnOff);
|
||||
virtual void setFollowRoads(bool newFollowRoads);
|
||||
virtual void setOnOff(bool newOnOff, bool force = false);
|
||||
virtual void setFollowRoads(bool newFollowRoads, bool force = false);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
|
||||
@@ -10,12 +10,16 @@ public:
|
||||
~Scheduler();
|
||||
|
||||
void appendCommand(Command* command);
|
||||
int getCurrentLoad();
|
||||
void execute(lua_State* L);
|
||||
void handleRequest(string key, json::value value);
|
||||
|
||||
int getLoad();
|
||||
void setFrameRate(double newFrameRate) { frameRate = newFrameRate; }
|
||||
int getFrameRate() { return frameRate; };
|
||||
|
||||
private:
|
||||
list<Command*> commands;
|
||||
unsigned int load;
|
||||
double frameRate;
|
||||
};
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace DataIndex {
|
||||
ammo,
|
||||
contacts,
|
||||
activePath,
|
||||
isLeader,
|
||||
lastIndex,
|
||||
endOfData = 255
|
||||
};
|
||||
@@ -86,14 +87,12 @@ public:
|
||||
|
||||
/********** Methods **********/
|
||||
void initialize(json::value json);
|
||||
void setDefaults(bool force = false);
|
||||
virtual void setDefaults(bool force = false);
|
||||
|
||||
void runAILoop();
|
||||
|
||||
void updateExportData(json::value json, double dt = 0);
|
||||
void updateMissionData(json::value json);
|
||||
void update(json::value json, double dt);
|
||||
|
||||
unsigned int getDataPacket(char*& data);
|
||||
unsigned int getID() { return ID; }
|
||||
void getData(stringstream& ss, unsigned long long time);
|
||||
Coords getActiveDestination() { return activeDestination; }
|
||||
@@ -144,8 +143,8 @@ public:
|
||||
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
|
||||
virtual void setIsTanker(bool newValue);
|
||||
virtual void setIsAWACS(bool newValue);
|
||||
virtual void setOnOff(bool newValue) { updateValue(onOff, newValue, DataIndex::onOff); };
|
||||
virtual void setFollowRoads(bool newValue) { updateValue(followRoads, newValue, DataIndex::followRoads); };
|
||||
virtual void setOnOff(bool newValue, bool force = false) { updateValue(onOff, newValue, DataIndex::onOff); };
|
||||
virtual void setFollowRoads(bool newValue, bool force = false) { updateValue(followRoads, newValue, DataIndex::followRoads); };
|
||||
virtual void setFuel(unsigned short newValue) { updateValue(fuel, newValue, DataIndex::fuel); }
|
||||
virtual void setDesiredSpeed(double newValue);
|
||||
virtual void setDesiredSpeedType(string newValue);
|
||||
@@ -164,6 +163,7 @@ public:
|
||||
virtual void setAmmo(vector<DataTypes::Ammo> newValue);
|
||||
virtual void setContacts(vector<DataTypes::Contact> newValue);
|
||||
virtual void setActivePath(list<Coords> newValue);
|
||||
virtual void setIsLeader(bool newValue) { updateValue(isLeader, newValue, DataIndex::isLeader); }
|
||||
|
||||
/********** Getters **********/
|
||||
virtual string getCategory() { return category; };
|
||||
@@ -191,7 +191,7 @@ public:
|
||||
virtual double getDesiredAltitude() { return desiredAltitude; };
|
||||
virtual bool getDesiredAltitudeType() { return desiredAltitudeType; };
|
||||
virtual unsigned int getLeaderID() { return leaderID; }
|
||||
virtual Offset getFormationoffset() { return formationOffset; }
|
||||
virtual Offset getFormationOffset() { return formationOffset; }
|
||||
virtual unsigned int getTargetID() { return targetID; }
|
||||
virtual Coords getTargetPosition() { return targetPosition; }
|
||||
virtual unsigned char getROE() { return ROE; }
|
||||
@@ -203,6 +203,7 @@ public:
|
||||
virtual vector<DataTypes::Ammo> getAmmo() { return ammo; }
|
||||
virtual vector<DataTypes::Contact> getTargets() { return contacts; }
|
||||
virtual list<Coords> getActivePath() { return activePath; }
|
||||
virtual bool getIsLeader() { return isLeader; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@@ -244,13 +245,14 @@ protected:
|
||||
vector<DataTypes::Ammo> ammo;
|
||||
vector<DataTypes::Contact> contacts;
|
||||
list<Coords> activePath;
|
||||
bool isLeader = false;
|
||||
Coords activeDestination = Coords(NULL);
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
Coords activeDestination = Coords(NULL);
|
||||
double initialFuel = 0;
|
||||
Coords oldPosition = Coords(0);
|
||||
map<unsigned char, unsigned long long> updateTimeMap;
|
||||
unsigned long long lastLoopTime = 0;
|
||||
|
||||
/********** Private methods **********/
|
||||
virtual void AIloop() = 0;
|
||||
|
||||
@@ -13,14 +13,13 @@ public:
|
||||
map<unsigned int, Unit*>& getUnits() { return units; };
|
||||
Unit* getUnit(unsigned int ID);
|
||||
bool isUnitInGroup(Unit* unit);
|
||||
bool isUnitGroupLeader(Unit* unit);
|
||||
bool isUnitGroupLeader(Unit* unit, Unit*& leader);
|
||||
Unit* getGroupLeader(unsigned int ID);
|
||||
Unit* getGroupLeader(Unit* unit);
|
||||
vector<Unit*> getGroupMembers(string groupName);
|
||||
void updateExportData(lua_State* L, double dt = 0);
|
||||
void updateMissionData(json::value missionData);
|
||||
void update(json::value& missionData, double dt);
|
||||
void runAILoop();
|
||||
string getUnitData(stringstream &ss, unsigned long long time);
|
||||
void getUnitData(stringstream &ss, unsigned long long time);
|
||||
void deleteUnit(unsigned int ID, bool explosion, bool immediate);
|
||||
void acquireControl(unsigned int ID);
|
||||
|
||||
|
||||
@@ -18,6 +18,26 @@ AirUnit::AirUnit(json::value json, unsigned int ID) : Unit(json, ID)
|
||||
|
||||
};
|
||||
|
||||
void AirUnit::setDefaults(bool force)
|
||||
{
|
||||
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
|
||||
|
||||
/* 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(position.alt);
|
||||
|
||||
/* Set the default options */
|
||||
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);
|
||||
setGeneralSettings(generalSettings, force);
|
||||
}
|
||||
|
||||
void AirUnit::setState(unsigned char newState)
|
||||
{
|
||||
/************ Perform any action required when LEAVING a state ************/
|
||||
|
||||
@@ -18,9 +18,7 @@ Server* server = nullptr;
|
||||
Scheduler* scheduler = nullptr;
|
||||
|
||||
/* Data jsons */
|
||||
json::value airbases;
|
||||
json::value bullseyes;
|
||||
json::value mission;
|
||||
json::value missionData = json::value::object();
|
||||
|
||||
mutex mutexLock;
|
||||
string sessionHash;
|
||||
@@ -28,7 +26,6 @@ string sessionHash;
|
||||
bool initialized = false;
|
||||
|
||||
unsigned int frameCounter = 0;
|
||||
double frameRate = 30;
|
||||
|
||||
/* Called when DCS simulation stops. All singleton instances are deleted. */
|
||||
extern "C" DllExport int coreDeinit(lua_State* L)
|
||||
@@ -72,38 +69,46 @@ extern "C" DllExport int coreFrame(lua_State* L)
|
||||
|
||||
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> updateDuration = std::chrono::system_clock::now() - lastUpdate;
|
||||
double updateTimeInterval = max(UPDATE_TIME_INTERVAL, UPDATE_TIME_INTERVAL * (60.0 / frameRate));
|
||||
if (updateDuration.count() > updateTimeInterval)
|
||||
{
|
||||
/* Lock for thread safety */
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
if (updateDuration.count() > 0)
|
||||
frameRate = frameCounter / updateDuration.count();
|
||||
frameCounter = 0;
|
||||
|
||||
if (unitsManager != nullptr) {
|
||||
unitsManager->updateExportData(L, updateDuration.count());
|
||||
unitsManager->runAILoop();
|
||||
|
||||
}
|
||||
lastUpdate = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
const std::chrono::duration<double> executionDuration = std::chrono::system_clock::now() - lastExecution;
|
||||
double executionTimeInterval = max(EXECUTION_TIME_INTERVAL, EXECUTION_TIME_INTERVAL * (60.0 / frameRate));
|
||||
if (executionDuration.count() > executionTimeInterval) {
|
||||
if (scheduler != nullptr)
|
||||
if (executionDuration.count() > EXECUTION_TIME_INTERVAL) {
|
||||
if (scheduler != nullptr) {
|
||||
scheduler->execute(L);
|
||||
lastExecution = std::chrono::system_clock::now();
|
||||
|
||||
if (executionDuration.count() > 0) {
|
||||
scheduler->setFrameRate(frameCounter / executionDuration.count());
|
||||
frameCounter = 0;
|
||||
}
|
||||
|
||||
lastExecution = std::chrono::system_clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern "C" DllExport int coreUnitsData(lua_State * L)
|
||||
{
|
||||
if (!initialized)
|
||||
return (0);
|
||||
|
||||
/* Lock for thread safety */
|
||||
json::value unitsData = json::value::object();
|
||||
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
lua_getglobal(L, "Olympus");
|
||||
lua_getfield(L, -1, "unitsData");
|
||||
luaTableToJSON(L, -1, unitsData);
|
||||
|
||||
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUpdate;
|
||||
if (unitsData.has_object_field(L"units")) {
|
||||
unitsManager->update(unitsData[L"units"], updateDuration.count());
|
||||
}
|
||||
lastUpdate = std::chrono::system_clock::now();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
extern "C" DllExport int coreMissionData(lua_State * L)
|
||||
{
|
||||
if (!initialized)
|
||||
@@ -113,17 +118,7 @@ extern "C" DllExport int coreMissionData(lua_State * L)
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
lua_getglobal(L, "Olympus");
|
||||
lua_getfield(L, -1, "missionData");
|
||||
json::value missionData = luaTableToJSON(L, -1);
|
||||
|
||||
if (missionData.has_object_field(L"unitsData")) {
|
||||
unitsManager->updateMissionData(missionData[L"unitsData"]);
|
||||
}
|
||||
if (missionData.has_object_field(L"airbases"))
|
||||
airbases = missionData[L"airbases"];
|
||||
if (missionData.has_object_field(L"bullseyes"))
|
||||
bullseyes = missionData[L"bullseyes"];
|
||||
if (missionData.has_object_field(L"mission"))
|
||||
mission = missionData[L"mission"];
|
||||
luaTableToJSON(L, -1, missionData);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,19 @@ GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID)
|
||||
setDesiredSpeed(10);
|
||||
};
|
||||
|
||||
void GroundUnit::setDefaults(bool force)
|
||||
{
|
||||
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
|
||||
|
||||
/* Set the default IDLE state */
|
||||
setState(State::IDLE);
|
||||
|
||||
/* Set the default options */
|
||||
setROE(ROE::OPEN_FIRE_WEAPON_FREE, force);
|
||||
setOnOff(onOff, force);
|
||||
setFollowRoads(followRoads, force);
|
||||
}
|
||||
|
||||
void GroundUnit::setState(unsigned char newState)
|
||||
{
|
||||
/************ Perform any action required when LEAVING a state ************/
|
||||
@@ -61,7 +74,8 @@ void GroundUnit::setState(unsigned char newState)
|
||||
break;
|
||||
}
|
||||
|
||||
resetTask();
|
||||
if (newState != state)
|
||||
resetTask();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
@@ -132,15 +146,19 @@ void GroundUnit::changeSpeed(string change)
|
||||
setDesiredSpeed(0);
|
||||
}
|
||||
|
||||
void GroundUnit::setOnOff(bool newOnOff)
|
||||
void GroundUnit::setOnOff(bool newOnOff, bool force)
|
||||
{
|
||||
Unit::setOnOff(newOnOff);
|
||||
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
|
||||
scheduler->appendCommand(command);
|
||||
if (newOnOff != onOff || force) {
|
||||
Unit::setOnOff(newOnOff, force);
|
||||
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
void GroundUnit::setFollowRoads(bool newFollowRoads)
|
||||
void GroundUnit::setFollowRoads(bool newFollowRoads, bool force)
|
||||
{
|
||||
Unit::setFollowRoads(newFollowRoads);
|
||||
resetActiveDestination(); /* Reset active destination to apply option*/
|
||||
if (newFollowRoads != followRoads || force) {
|
||||
Unit::setFollowRoads(newFollowRoads, force);
|
||||
resetActiveDestination(); /* Reset active destination to apply option*/
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ void Scheduler::appendCommand(Command* command)
|
||||
commands.push_back(command);
|
||||
}
|
||||
|
||||
int Scheduler::getCurrentLoad()
|
||||
int Scheduler::getLoad()
|
||||
{
|
||||
int currentLoad = 0;
|
||||
for (auto command : commands) {
|
||||
@@ -51,7 +51,7 @@ void Scheduler::execute(lua_State* L)
|
||||
if (dostring_in(L, "server", (commandString)))
|
||||
log("Error executing command " + commandString);
|
||||
else
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(getCurrentLoad()));
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(getLoad()));
|
||||
load = command->getLoad();
|
||||
commands.remove(command);
|
||||
return;
|
||||
@@ -468,7 +468,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
if (command != nullptr)
|
||||
{
|
||||
appendCommand(command);
|
||||
log("New command appended correctly to stack. Current server load: " + to_string(getCurrentLoad()));
|
||||
log("New command appended correctly to stack. Current server load: " + to_string(getLoad()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ using namespace base64;
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
extern Scheduler* scheduler;
|
||||
extern json::value airbases;
|
||||
extern json::value bullseyes;
|
||||
extern json::value mission;
|
||||
extern json::value missionData;
|
||||
extern mutex mutexLock;
|
||||
extern string sessionHash;
|
||||
|
||||
@@ -70,7 +68,6 @@ void Server::handle_get(http_request request)
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
|
||||
string password = extractPassword(request);
|
||||
@@ -81,24 +78,25 @@ void Server::handle_get(http_request request)
|
||||
auto answer = json::value::object();
|
||||
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
|
||||
|
||||
/* If present, extract the request reference time. This is used for updates, and it specifies the last time that request has been performed */
|
||||
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
|
||||
unsigned long long time = 0;
|
||||
if (query.find(L"time") != query.end())
|
||||
{
|
||||
try {
|
||||
time = stoull((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.size() > 0)
|
||||
{
|
||||
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;
|
||||
if (query.find(L"time") != query.end())
|
||||
{
|
||||
try {
|
||||
time = stoll((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
unsigned long long updateTime = ms.count();
|
||||
|
||||
stringstream ss;
|
||||
ss.write((char*)&updateTime, sizeof(updateTime));
|
||||
unitsManager->getUnitData(ss, time);
|
||||
@@ -108,26 +106,28 @@ void Server::handle_get(http_request request)
|
||||
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
|
||||
getLogsJSON(logs, time);
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (URI.compare(AIRBASES_URI) == 0)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (URI.compare(BULLSEYE_URI) == 0)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (URI.compare(MISSION_URI) == 0) {
|
||||
mission[L"RTSOptions"] = json::value::object();
|
||||
|
||||
else if (URI.compare(AIRBASES_URI) == 0 && missionData.has_object_field(L"airbases"))
|
||||
answer[L"airbases"] = missionData[L"airbases"];
|
||||
else if (URI.compare(BULLSEYE_URI) == 0 && missionData.has_object_field(L"bullseyes"))
|
||||
answer[L"bullseyes"] = missionData[L"bullseyes"];
|
||||
else if (URI.compare(MISSION_URI) == 0 && missionData.has_object_field(L"mission")) {
|
||||
answer[L"mission"] = missionData[L"mission"];
|
||||
if (password.compare(gameMasterPassword) == 0)
|
||||
mission[L"RTSOptions"][L"commandMode"] = json::value(L"Game master");
|
||||
answer[L"mission"][L"visibilityMode"] = json::value(L"Game master");
|
||||
else if (password.compare(blueCommanderPassword) == 0)
|
||||
mission[L"RTSOptions"][L"commandMode"] = json::value(L"Blue commander");
|
||||
answer[L"mission"][L"visibilityMode"] = json::value(L"Blue commander");
|
||||
else if (password.compare(redCommanderPassword) == 0)
|
||||
mission[L"RTSOptions"][L"commandMode"] = json::value(L"Red commander");
|
||||
answer[L"mission"] = mission;
|
||||
answer[L"mission"][L"visibilityMode"] = json::value(L"Red commander");
|
||||
}
|
||||
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
answer[L"load"] = scheduler->getLoad();
|
||||
answer[L"frameRate"] = scheduler->getFrameRate();
|
||||
response.set_body(answer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,104 +28,58 @@ Unit::~Unit()
|
||||
|
||||
void Unit::initialize(json::value json)
|
||||
{
|
||||
if (json.has_string_field(L"Name"))
|
||||
setName(to_string(json[L"Name"]));
|
||||
if (json.has_string_field(L"UnitName"))
|
||||
setUnitName(to_string(json[L"UnitName"]));
|
||||
if (json.has_string_field(L"GroupName"))
|
||||
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"))
|
||||
setCoalition(json[L"CoalitionID"].as_number().to_int32());
|
||||
if (json.has_string_field(L"name"))
|
||||
setName(to_string(json[L"name"]));
|
||||
|
||||
if (json.has_object_field(L"Flags"))
|
||||
setHuman(json[L"Flags"][L"Human"].as_bool());
|
||||
if (json.has_string_field(L"unitName"))
|
||||
setUnitName(to_string(json[L"unitName"]));
|
||||
|
||||
if (json.has_string_field(L"groupName"))
|
||||
setGroupName(to_string(json[L"groupName"]));
|
||||
|
||||
if (json.has_number_field(L"coalitionID"))
|
||||
setCoalition(json[L"coalitionID"].as_number().to_int32());
|
||||
|
||||
//if (json.has_number_field(L"Country"))
|
||||
// setCountry(json[L"Country"].as_number().to_int32());
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
if (getUnitName().find("Olympus") != string::npos)
|
||||
setControlled(true);
|
||||
|
||||
updateExportData(json);
|
||||
update(json, 0);
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
void Unit::setDefaults(bool force)
|
||||
|
||||
void Unit::update(json::value json, double dt)
|
||||
{
|
||||
if (!getControlled()) return;
|
||||
if (!unitsManager->isUnitGroupLeader(this)) return;
|
||||
if (!(getAlive() || unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this))) return;
|
||||
if (getHuman()) return;
|
||||
|
||||
/* 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(position.alt);
|
||||
|
||||
/* Set the default options */
|
||||
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);
|
||||
setGeneralSettings(generalSettings, force);
|
||||
}
|
||||
|
||||
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 (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 */
|
||||
const bool isUnitAlive = getAlive();
|
||||
const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this);
|
||||
if (!(isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits)) return;
|
||||
|
||||
if (checkTaskFailed() && state != State::IDLE && state != State::LAND)
|
||||
setState(State::IDLE);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void Unit::updateExportData(json::value json, double dt)
|
||||
{
|
||||
Coords newPosition = Coords(NULL);
|
||||
double newHeading = 0;
|
||||
double newSpeed = 0;
|
||||
|
||||
if (json.has_object_field(L"LatLongAlt"))
|
||||
if (json.has_object_field(L"position"))
|
||||
{
|
||||
setPosition({
|
||||
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()
|
||||
json[L"position"][L"lat"].as_number().to_double(),
|
||||
json[L"position"][L"lng"].as_number().to_double(),
|
||||
json[L"position"][L"alt"].as_number().to_double()
|
||||
});
|
||||
}
|
||||
if (json.has_number_field(L"Heading"))
|
||||
setHeading(json[L"Heading"].as_number().to_double());
|
||||
|
||||
/* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */
|
||||
if (oldPosition != NULL)
|
||||
{
|
||||
double dist = 0;
|
||||
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, oldPosition.lat, oldPosition.lng, dist);
|
||||
if (dt > 0)
|
||||
setSpeed(getSpeed() * 0.95 + (dist / dt) * 0.05);
|
||||
}
|
||||
if (json.has_number_field(L"heading"))
|
||||
setHeading(json[L"heading"].as_number().to_double());
|
||||
|
||||
oldPosition = position;
|
||||
}
|
||||
if (json.has_number_field(L"speed"))
|
||||
setSpeed(json[L"speed"].as_number().to_double());
|
||||
|
||||
if (json.has_boolean_field(L"isAlive"))
|
||||
setAlive(json[L"isAlive"].as_bool());
|
||||
|
||||
if (json.has_object_field(L"isHuman"))
|
||||
setHuman(json[L"isHuman"].as_bool());
|
||||
|
||||
void Unit::updateMissionData(json::value json)
|
||||
{
|
||||
if (json.has_number_field(L"fuel")) {
|
||||
setFuel(short(json[L"fuel"].as_number().to_double() * 100));
|
||||
}
|
||||
|
||||
if (json.has_object_field(L"ammo")) {
|
||||
|
||||
if (json.has_object_field(L"ammo")) {
|
||||
vector<DataTypes::Ammo> ammo;
|
||||
for (auto const& el : json[L"ammo"].as_object()) {
|
||||
DataTypes::Ammo ammoItem;
|
||||
@@ -146,16 +100,16 @@ void Unit::updateMissionData(json::value json)
|
||||
}
|
||||
setAmmo(ammo);
|
||||
}
|
||||
|
||||
|
||||
if (json.has_object_field(L"contacts")) {
|
||||
vector<DataTypes::Contact> contacts;
|
||||
for (auto const& el : json[L"contacts"].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") == 0) contactItem.detectionMethod = 1;
|
||||
if (detectionMethod.compare("VISUAL") == 0) contactItem.detectionMethod = 1;
|
||||
else if (detectionMethod.compare("OPTIC") == 0) contactItem.detectionMethod = 2;
|
||||
else if (detectionMethod.compare("RADAR") == 0) contactItem.detectionMethod = 4;
|
||||
else if (detectionMethod.compare("IRST") == 0) contactItem.detectionMethod = 8;
|
||||
@@ -168,8 +122,68 @@ void Unit::updateMissionData(json::value json)
|
||||
|
||||
if (json.has_boolean_field(L"hasTask"))
|
||||
setHasTask(json[L"hasTask"].as_bool());
|
||||
|
||||
runAILoop();
|
||||
}
|
||||
|
||||
void Unit::setDefaults(bool force)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Unit::runAILoop() {
|
||||
/* Set isLeader */
|
||||
Unit* leader = nullptr;
|
||||
setIsLeader(unitsManager->isUnitGroupLeader(this, leader));
|
||||
|
||||
/* When units are in a group, most data comes from the group leader. If new data is available, align it from the leader */
|
||||
if (!getIsLeader()) {
|
||||
if (leader != nullptr) {
|
||||
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
||||
{
|
||||
if (leader->checkFreshness(datumIndex, lastLoopTime)) {
|
||||
switch (datumIndex) {
|
||||
case DataIndex::controlled: updateValue(controlled, leader->controlled, datumIndex); break;
|
||||
case DataIndex::state: updateValue(state, leader->state, datumIndex); break;
|
||||
case DataIndex::task: updateValue(task, leader->task, datumIndex); break;
|
||||
case DataIndex::hasTask: updateValue(hasTask, leader->hasTask, datumIndex); break;
|
||||
case DataIndex::isTanker: updateValue(isTanker, leader->isTanker, datumIndex); break;
|
||||
case DataIndex::isAWACS: updateValue(isAWACS, leader->isAWACS, datumIndex); break;
|
||||
case DataIndex::onOff: updateValue(onOff, leader->onOff, datumIndex); break;
|
||||
case DataIndex::followRoads: updateValue(followRoads, leader->followRoads, datumIndex); break;
|
||||
case DataIndex::desiredSpeed: updateValue(desiredSpeed, leader->desiredSpeed, datumIndex); break;
|
||||
case DataIndex::desiredSpeedType: updateValue(desiredSpeedType, leader->desiredSpeedType, datumIndex); break;
|
||||
case DataIndex::desiredAltitude: updateValue(desiredAltitude, leader->desiredAltitude, datumIndex); break;
|
||||
case DataIndex::desiredAltitudeType: updateValue(desiredAltitudeType, leader->desiredAltitudeType, datumIndex); break;
|
||||
case DataIndex::leaderID: updateValue(leaderID, leader->leaderID, datumIndex); break;
|
||||
case DataIndex::formationOffset: updateValue(formationOffset, leader->formationOffset, datumIndex); break;
|
||||
case DataIndex::targetID: updateValue(targetID, leader->targetID, datumIndex); break;
|
||||
case DataIndex::targetPosition: updateValue(targetPosition, leader->targetPosition, datumIndex); break;
|
||||
case DataIndex::ROE: updateValue(ROE, leader->ROE, datumIndex); break;
|
||||
case DataIndex::reactionToThreat: updateValue(reactionToThreat, leader->reactionToThreat, datumIndex); break;
|
||||
case DataIndex::emissionsCountermeasures: updateValue(emissionsCountermeasures, leader->emissionsCountermeasures, datumIndex); break;
|
||||
case DataIndex::TACAN: updateValue(TACAN, leader->TACAN, datumIndex); break;
|
||||
case DataIndex::radio: updateValue(radio, leader->radio, datumIndex); break;
|
||||
case DataIndex::generalSettings: updateValue(generalSettings, leader->generalSettings, datumIndex); break;
|
||||
case DataIndex::activePath: updateValue(activePath, leader->activePath, datumIndex); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
|
||||
if (getAlive() && getControlled() && !getHuman() && getIsLeader()) {
|
||||
if (checkTaskFailed() && state != State::IDLE && state != State::LAND)
|
||||
setState(State::IDLE);
|
||||
AIloop();
|
||||
}
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
lastLoopTime = ms.count();
|
||||
}
|
||||
|
||||
|
||||
bool Unit::checkFreshness(unsigned char datumIndex, unsigned long long time) {
|
||||
auto it = updateTimeMap.find(datumIndex);
|
||||
if (it == updateTimeMap.end())
|
||||
@@ -187,55 +201,51 @@ bool Unit::hasFreshData(unsigned long long time) {
|
||||
|
||||
void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
{
|
||||
Unit* leader = this;
|
||||
if (unitsManager->isUnitInGroup(this) && !unitsManager->isUnitGroupLeader(this))
|
||||
leader = unitsManager->getGroupLeader(this);
|
||||
|
||||
if (leader == nullptr || (!leader->hasFreshData(time) && !hasFreshData(time))) return;
|
||||
|
||||
const unsigned char endOfData = DataIndex::endOfData;
|
||||
ss.write((const char*)&ID, sizeof(ID));
|
||||
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
||||
{
|
||||
/* When units are in a group, most data comes from the group leader */
|
||||
switch (datumIndex) {
|
||||
case DataIndex::category: if (checkFreshness(datumIndex, time)) appendString(ss, datumIndex, category); break;
|
||||
case DataIndex::alive: if (checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, alive); break;
|
||||
case DataIndex::human: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->human); break;
|
||||
case DataIndex::controlled: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->controlled); break;
|
||||
case DataIndex::coalition: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->coalition); break;
|
||||
case DataIndex::country: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->country); break;
|
||||
case DataIndex::name: if (checkFreshness(datumIndex, time)) appendString(ss, datumIndex, name); break;
|
||||
case DataIndex::unitName: if (checkFreshness(datumIndex, time)) appendString(ss, datumIndex, unitName); break;
|
||||
case DataIndex::groupName: if (leader->checkFreshness(datumIndex, time)) appendString(ss, datumIndex, leader->groupName); break;
|
||||
case DataIndex::state: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->state); break;
|
||||
case DataIndex::task: if (leader->checkFreshness(datumIndex, time)) appendString(ss, datumIndex, leader->task); break;
|
||||
case DataIndex::hasTask: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->hasTask); break;
|
||||
case DataIndex::position: if (checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, position); break;
|
||||
case DataIndex::speed: if (checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, speed); break;
|
||||
case DataIndex::heading: if (checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, heading); break;
|
||||
case DataIndex::isTanker: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->isTanker); break;
|
||||
case DataIndex::isAWACS: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->isAWACS); break;
|
||||
case DataIndex::onOff: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->onOff); break;
|
||||
case DataIndex::followRoads: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->followRoads); break;
|
||||
case DataIndex::fuel: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, fuel); break;
|
||||
case DataIndex::desiredSpeed: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->desiredSpeed); break;
|
||||
case DataIndex::desiredSpeedType: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->desiredSpeedType); break;
|
||||
case DataIndex::desiredAltitude: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->desiredAltitude); break;
|
||||
case DataIndex::desiredAltitudeType: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->desiredAltitudeType); break;
|
||||
case DataIndex::leaderID: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->leaderID); break;
|
||||
case DataIndex::formationOffset: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->formationOffset); break;
|
||||
case DataIndex::targetID: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->targetID); break;
|
||||
case DataIndex::targetPosition: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->targetPosition); break;
|
||||
case DataIndex::ROE: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->ROE); break;
|
||||
case DataIndex::reactionToThreat: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->reactionToThreat); break;
|
||||
case DataIndex::emissionsCountermeasures: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->emissionsCountermeasures); break;
|
||||
case DataIndex::TACAN: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->TACAN); break;
|
||||
case DataIndex::radio: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->radio); break;
|
||||
case DataIndex::generalSettings: if (leader->checkFreshness(datumIndex, time)) appendNumeric(ss, datumIndex, leader->generalSettings); break;
|
||||
case DataIndex::ammo: if (checkFreshness(datumIndex, time)) appendVector(ss, datumIndex, ammo); break;
|
||||
case DataIndex::contacts: if (checkFreshness(datumIndex, time)) appendVector(ss, datumIndex, contacts); break;
|
||||
case DataIndex::activePath: if (leader->checkFreshness(datumIndex, time)) appendList(ss, datumIndex, leader->activePath); break;
|
||||
if (checkFreshness(datumIndex, time)) {
|
||||
switch (datumIndex) {
|
||||
case DataIndex::category: appendString(ss, datumIndex, category); break;
|
||||
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
|
||||
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
|
||||
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
|
||||
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
|
||||
case DataIndex::country: appendNumeric(ss, datumIndex, country); break;
|
||||
case DataIndex::name: appendString(ss, datumIndex, name); break;
|
||||
case DataIndex::unitName: appendString(ss, datumIndex, unitName); break;
|
||||
case DataIndex::groupName: appendString(ss, datumIndex, groupName); break;
|
||||
case DataIndex::state: appendNumeric(ss, datumIndex, state); break;
|
||||
case DataIndex::task: appendString(ss, datumIndex, task); break;
|
||||
case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break;
|
||||
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
|
||||
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
|
||||
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
|
||||
case DataIndex::isTanker: appendNumeric(ss, datumIndex, isTanker); break;
|
||||
case DataIndex::isAWACS: appendNumeric(ss, datumIndex, isAWACS); break;
|
||||
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
|
||||
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break;
|
||||
case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break;
|
||||
case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break;
|
||||
case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break;
|
||||
case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break;
|
||||
case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break;
|
||||
case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break;
|
||||
case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break;
|
||||
case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break;
|
||||
case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break;
|
||||
case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break;
|
||||
case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break;
|
||||
case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break;
|
||||
case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break;
|
||||
case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break;
|
||||
case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break;
|
||||
case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break;
|
||||
case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break;
|
||||
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
|
||||
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ss.write((const char*)&endOfData, sizeof(endOfData));
|
||||
@@ -537,8 +547,8 @@ void Unit::setRadio(DataTypes::Radio newRadio, bool force)
|
||||
commandSS << "{"
|
||||
<< "id = 'SetCallsign',"
|
||||
<< "params = {"
|
||||
<< "callname = " << radio.callsign << ","
|
||||
<< "number = " << radio.callsignNumber << ","
|
||||
<< "callname = " << to_string(radio.callsign) << ","
|
||||
<< "number = " << to_string(radio.callsignNumber) << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
|
||||
@@ -572,46 +582,54 @@ void Unit::setGeneralSettings(DataTypes::GeneralSettings newGeneralSettings, boo
|
||||
|
||||
void Unit::setDesiredSpeed(double newDesiredSpeed)
|
||||
{
|
||||
desiredSpeed = newDesiredSpeed;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
if (desiredSpeed != newDesiredSpeed) {
|
||||
desiredSpeed = newDesiredSpeed;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeed);
|
||||
triggerUpdate(DataIndex::desiredSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setDesiredAltitude(double newDesiredAltitude)
|
||||
{
|
||||
desiredAltitude = newDesiredAltitude;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
if (desiredAltitude != newDesiredAltitude) {
|
||||
desiredAltitude = newDesiredAltitude;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitude);
|
||||
triggerUpdate(DataIndex::desiredAltitude);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setDesiredSpeedType(string newDesiredSpeedType)
|
||||
{
|
||||
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
if (desiredSpeedType != (newDesiredSpeedType.compare("GS") == 0)) {
|
||||
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeedType);
|
||||
triggerUpdate(DataIndex::desiredSpeedType);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
|
||||
{
|
||||
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
if (desiredAltitudeType != (newDesiredAltitudeType.compare("AGL") == 0)) {
|
||||
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitudeType);
|
||||
triggerUpdate(DataIndex::desiredAltitudeType);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::goToDestination(string enrouteTask)
|
||||
|
||||
@@ -42,33 +42,33 @@ bool UnitsManager::isUnitInGroup(Unit* unit)
|
||||
if (groupName.length() == 0) return false;
|
||||
for (auto const& p : units)
|
||||
{
|
||||
if (p.second->getGroupName().compare(groupName) == 0 && p.second != unit)
|
||||
if (p.second->getGroupName().compare(groupName) == 0 && p.second != unit && p.second->getAlive())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnitsManager::isUnitGroupLeader(Unit* unit)
|
||||
/* Returns true if unit is group leader. Else, returns false, and leader will be equal to the group leader */
|
||||
bool UnitsManager::isUnitGroupLeader(Unit* unit, Unit*& leader)
|
||||
{
|
||||
if (unit != nullptr) {
|
||||
Unit* leader = getGroupLeader(unit);
|
||||
return leader == nullptr? false: unit == getGroupLeader(unit);
|
||||
leader = getGroupLeader(unit);
|
||||
return leader == nullptr? false: unit == leader;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// The group leader is the unit with the lowest ID that is part of the group. This is different from DCS's concept of leader, which will change if the leader is destroyed
|
||||
Unit* UnitsManager::getGroupLeader(Unit* unit)
|
||||
{
|
||||
if (unit != nullptr) {
|
||||
string groupName = unit->getGroupName();
|
||||
if (groupName.length() == 0) return nullptr;
|
||||
/* Find the first unit that has the same groupName */
|
||||
/* Find the first alive unit that has the same groupName */
|
||||
for (auto const& p : units)
|
||||
{
|
||||
if (p.second->getGroupName().compare(groupName) == 0)
|
||||
if (p.second->getAlive() && p.second->getGroupName().compare(groupName) == 0)
|
||||
return p.second;
|
||||
}
|
||||
}
|
||||
@@ -92,63 +92,42 @@ Unit* UnitsManager::getGroupLeader(unsigned int ID)
|
||||
return getGroupLeader(unit);
|
||||
}
|
||||
|
||||
void UnitsManager::updateExportData(lua_State* L, double dt)
|
||||
void UnitsManager::update(json::value& json, double dt)
|
||||
{
|
||||
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)
|
||||
for (auto const& p : json.as_object())
|
||||
{
|
||||
unsigned int ID = p.first;
|
||||
unsigned int ID = std::stoi(p.first);
|
||||
if (units.count(ID) == 0)
|
||||
{
|
||||
json::value type = static_cast<json::value>(p.second)[L"Type"];
|
||||
if (type.has_number_field(L"level1"))
|
||||
{
|
||||
if (type[L"level1"].as_number().to_int32() == 1)
|
||||
{
|
||||
if (type[L"level2"].as_number().to_int32() == 1)
|
||||
units[ID] = dynamic_cast<Unit*>(new Aircraft(p.second, ID));
|
||||
else if (type[L"level2"].as_number().to_int32() == 2)
|
||||
units[ID] = dynamic_cast<Unit*>(new Helicopter(p.second, ID));
|
||||
}
|
||||
else if (type[L"level1"].as_number().to_int32() == 2)
|
||||
json::value value = p.second;
|
||||
if (value.has_string_field(L"category")) {
|
||||
string category = to_string(value[L"category"].as_string());
|
||||
if (category.compare("Aircraft") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new Aircraft(p.second, ID));
|
||||
else if (category.compare("Helicopter") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new Helicopter(p.second, ID));
|
||||
else if (category.compare("GroundUnit") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new GroundUnit(p.second, ID));
|
||||
else if (type[L"level1"].as_number().to_int32() == 3)
|
||||
else if (category.compare("NavyUnit") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new NavyUnit(p.second, ID));
|
||||
else if (type[L"level1"].as_number().to_int32() == 4)
|
||||
{
|
||||
if (type[L"level2"].as_number().to_int32() == 4)
|
||||
units[ID] = dynamic_cast<Unit*>(new Missile(p.second, ID));
|
||||
else if (type[L"level2"].as_number().to_int32() == 5)
|
||||
units[ID] = dynamic_cast<Unit*>(new Bomb(p.second, ID));
|
||||
else if (category.compare("Missile") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new Missile(p.second, ID));
|
||||
else if (category.compare("Bomb") == 0)
|
||||
units[ID] = dynamic_cast<Unit*>(new Bomb(p.second, ID));
|
||||
|
||||
/* Initialize the unit if creation was successfull */
|
||||
if (units.count(ID) != 0) {
|
||||
units[ID]->update(p.second, dt);
|
||||
units[ID]->initialize(p.second);
|
||||
}
|
||||
}
|
||||
/* Initialize the unit if creation was successfull */
|
||||
if (units.count(ID) != 0)
|
||||
units[ID]->initialize(p.second);
|
||||
}
|
||||
else {
|
||||
/* Update the unit if present*/
|
||||
if (units.count(ID) != 0)
|
||||
units[ID]->updateExportData(p.second, dt);
|
||||
units[ID]->update(p.second, dt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the units that are not present in the JSON as dead (probably have been destroyed) */
|
||||
for (auto const& unit : units)
|
||||
unit.second->setAlive(unitJSONs.find(unit.first) != unitJSONs.end());
|
||||
}
|
||||
|
||||
void UnitsManager::updateMissionData(json::value missionData)
|
||||
{
|
||||
/* Update all units */
|
||||
for (auto const& p : units)
|
||||
{
|
||||
unsigned int ID = p.first;
|
||||
if (missionData.has_field(to_wstring(ID)))
|
||||
p.second->updateMissionData(missionData[to_wstring(ID)]);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitsManager::runAILoop() {
|
||||
@@ -157,11 +136,10 @@ void UnitsManager::runAILoop() {
|
||||
unit.second->runAILoop();
|
||||
}
|
||||
|
||||
string UnitsManager::getUnitData(stringstream &ss, unsigned long long time)
|
||||
void UnitsManager::getUnitData(stringstream &ss, unsigned long long time)
|
||||
{
|
||||
for (auto const& p : units)
|
||||
p.second->getData(ss, time);
|
||||
return to_base64(ss.str());
|
||||
}
|
||||
|
||||
void UnitsManager::deleteUnit(unsigned int ID, bool explosion, bool immediate)
|
||||
@@ -174,16 +152,12 @@ void UnitsManager::deleteUnit(unsigned int ID, bool explosion, bool immediate)
|
||||
}
|
||||
|
||||
void UnitsManager::acquireControl(unsigned int ID) {
|
||||
Unit* unit = getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
for (auto const& groupMember : getGroupMembers(unit->getGroupName())) {
|
||||
if (!groupMember->getControlled()) {
|
||||
groupMember->setControlled(true);
|
||||
groupMember->setState(State::IDLE);
|
||||
groupMember->setDefaults(true);
|
||||
}
|
||||
Unit* leader = getGroupLeader(ID);
|
||||
if (leader != nullptr) {
|
||||
if (!leader->getControlled()) {
|
||||
leader->setControlled(true);
|
||||
leader->setDefaults(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user