Fixed update error and added update trigger

This commit is contained in:
Pax1601
2023-06-25 19:04:12 +02:00
parent dd2e858db4
commit 1989219579
18 changed files with 385 additions and 318 deletions

View File

@@ -52,8 +52,8 @@ interface UnitData {
human: boolean,
controlled: boolean,
hasTask: boolean,
desiredAltitudeType: boolean,
desiredSpeedType: boolean,
desiredAltitudeType: string,
desiredSpeedType: string,
isTanker: boolean,
isAWACS: boolean,
onOff: boolean,

View File

@@ -671,7 +671,7 @@ export class Map extends L.Map {
/* Show the active cursor depending on the active state */
if (this.#state === IDLE || this.#state === COALITIONAREA_INTERACT) this.#showDefaultCursor();
else if (this.#state === MOVE_UNIT) this.#showDestinationCursors(!e.originalEvent.shiftKey);
else if (this.#state === MOVE_UNIT) this.#showDestinationCursors(e && e.originaleEvent && !e.originalEvent.shiftKey);
else if ([BOMBING, CARPET_BOMBING, FIRE_AT_AREA].includes(this.#state)) this.#showTargetCursor();
else if (this.#state === COALITIONAREA_DRAW_POLYGON) this.#showDrawingCursor();
}

View File

@@ -2,6 +2,7 @@ import { LatLng } from 'leaflet';
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getUnitDataTable, getUnitsManager, setConnectionStatus } from '..';
import { SpawnOptions } from '../controls/mapcontextmenu';
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
var connected: boolean = false;
var paused: boolean = false;
@@ -38,19 +39,21 @@ export function GET(callback: CallableFunction, uri: string, options?: { time?:
if (options?.time != undefined)
optionsString = `time=${options.time}`;
xmlHttp.open("GET", `${demoEnabled ? DEMO_ADDRESS : REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ''}`, true);
if (credentials)
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
if (uri === UNITS_URI)
xmlHttp.responseType = "arraybuffer";
xmlHttp.onload = function (e) {
if (xmlHttp.status == 200) {
var data = JSON.parse(xmlHttp.responseText);
if (uri !== UNITS_URI || (options?.time == 0) || parseInt(data.time) > lastUpdateTime) {
setConnected(true);
if (xmlHttp.responseType == 'arraybuffer')
callback(xmlHttp.response);
else {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
lastUpdateTime = parseInt(data.time);
if (isNaN(lastUpdateTime))
lastUpdateTime = 0;
setConnected(true);
}
} else if (xmlHttp.status == 401) {
console.error("Incorrect username/password");
@@ -96,6 +99,10 @@ export function setAddress(address: string, port: number) {
console.log(`Setting REST address to ${REST_ADDRESS}`)
}
export function setLastUpdateTime(newLastUpdateTime: number) {
lastUpdateTime = newLastUpdateTime;
}
export function getAirbases(callback: CallableFunction) {
GET(callback, AIRBASES_URI);
}
@@ -223,19 +230,19 @@ export function createFormation(ID: number, isLeader: boolean, wingmenIDs: numbe
}
export function setROE(ID: number, ROE: string) {
var command = { "ID": ID, "ROE": ROE }
var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) }
var data = { "setROE": command }
POST(data, () => { });
}
export function setReactionToThreat(ID: number, reactionToThreat: string) {
var command = { "ID": ID, "reactionToThreat": reactionToThreat }
var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) }
var data = { "setReactionToThreat": command }
POST(data, () => { });
}
export function setEmissionsCountermeasures(ID: number, emissionCountermeasure: string) {
var command = { "ID": ID, "emissionsCountermeasures": emissionCountermeasure }
var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) }
var data = { "setEmissionsCountermeasures": command }
POST(data, () => { });
}
@@ -300,8 +307,11 @@ export function startUpdate() {
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => { getMissionData()?.update(data) });
getUnits((data: UnitsData) => getUnitsManager()?.update(data.units), true /* Does a full refresh */);
getMission((data: any) => {
getMissionData()?.update(data);
checkSessionHash(data.sessionHash);
});
getUnits((buffer: ArrayBuffer) => getUnitsManager()?.update(buffer), true /* Does a full refresh */);
requestUpdate();
requestRefresh();
@@ -309,10 +319,9 @@ export function startUpdate() {
export function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
getUnits((data: UnitsData) => {
getUnits((buffer: ArrayBuffer) => {
if (!getPaused()) {
getUnitsManager()?.update(data.units);
checkSessionHash(data.sessionHash);
getUnitsManager()?.update(buffer);
}
}, false);
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);

View File

@@ -17,85 +17,81 @@ export class DataExtractor {
extractData(offset: number) {
this.#offset = offset;
const ID = this.#extractUInt32();
const bitmask = this.#extractUInt32();
const ID = this.extractUInt32();
const bitmask = this.extractUInt32();
const unitData: UnitData = {
ID: ID,
alive: this.#extractFromBitmask(bitmask, 0),
human: this.#extractFromBitmask(bitmask, 1),
controlled: this.#extractFromBitmask(bitmask, 2),
hasTask: this.#extractFromBitmask(bitmask, 3),
desiredAltitudeType: this.#extractFromBitmask(bitmask, 16),
desiredSpeedType: this.#extractFromBitmask(bitmask, 17),
isTanker: this.#extractFromBitmask(bitmask, 18),
isAWACS: this.#extractFromBitmask(bitmask, 19),
onOff: this.#extractFromBitmask(bitmask, 20),
followRoads: this.#extractFromBitmask(bitmask, 21),
EPLRS: this.#extractFromBitmask(bitmask, 22),
alive: this.extractFromBitmask(bitmask, 0),
human: this.extractFromBitmask(bitmask, 1),
controlled: this.extractFromBitmask(bitmask, 2),
hasTask: this.extractFromBitmask(bitmask, 3),
desiredAltitudeType: this.extractFromBitmask(bitmask, 16)? "AGL": "ASL",
desiredSpeedType: this.extractFromBitmask(bitmask, 17)? "GS": "CAS",
isTanker: this.extractFromBitmask(bitmask, 18),
isAWACS: this.extractFromBitmask(bitmask, 19),
onOff: this.extractFromBitmask(bitmask, 20),
followRoads: this.extractFromBitmask(bitmask, 21),
EPLRS: this.extractFromBitmask(bitmask, 22),
generalSettings: {
prohibitAA: this.#extractFromBitmask(bitmask, 23),
prohibitAfterburner: this.#extractFromBitmask(bitmask, 24),
prohibitAG: this.#extractFromBitmask(bitmask, 25),
prohibitAirWpn: this.#extractFromBitmask(bitmask, 26),
prohibitJettison: this.#extractFromBitmask(bitmask, 27),
prohibitAA: this.extractFromBitmask(bitmask, 23),
prohibitAfterburner: this.extractFromBitmask(bitmask, 24),
prohibitAG: this.extractFromBitmask(bitmask, 25),
prohibitAirWpn: this.extractFromBitmask(bitmask, 26),
prohibitJettison: this.extractFromBitmask(bitmask, 27),
},
position: new LatLng(
this.#extractFloat64(),
this.#extractFloat64(),
this.#extractFloat64()
this.extractFloat64(),
this.extractFloat64(),
this.extractFloat64()
),
speed: this.#extractFloat64(),
heading: this.#extractFloat64(),
fuel: this.#extractUInt16(),
desiredSpeed: this.#extractFloat64(),
desiredAltitude: this.#extractFloat64(),
targetID: this.#extractUInt32(),
leaderID: 0,
speed: this.extractFloat64(),
heading: this.extractFloat64(),
fuel: this.extractUInt16(),
desiredSpeed: this.extractFloat64(),
desiredAltitude: this.extractFloat64(),
leaderID: this.extractUInt32(),
targetID: this.extractUInt32(),
targetPosition: new LatLng(
this.#extractFloat64(),
this.#extractFloat64(),
this.#extractFloat64()
this.extractFloat64(),
this.extractFloat64(),
this.extractFloat64()
),
state: this.#getState(this.#extractUint8()),
ROE: this.#getROE(this.#extractUint8()),
reactionToThreat: this.#getReactionToThreat(this.#extractUint8()),
emissionsCountermeasures: this.#getEmissionCountermeasure(this.#extractUint8()),
state: this.#getState(this.extractUInt8()),
ROE: this.#getROE(this.extractUInt8()),
reactionToThreat: this.#getReactionToThreat(this.extractUInt8()),
emissionsCountermeasures: this.#getEmissionCountermeasure(this.extractUInt8()),
coalition: this.#getCoalition(this.extractUInt8()),
TACAN: {
isOn: this.#extractBool(),
channel: this.#extractUint8(),
XY: this.#extractChar(),
callsign: this.#extractString(4)
isOn: this.extractBool(),
channel: this.extractUInt8(),
XY: this.extractChar(),
callsign: this.extractString(4)
},
radio: {
frequency: this.#extractUInt32(),
callsign: this.#extractUint8(),
callsignNumber: this.#extractUint8()
frequency: this.extractUInt32(),
callsign: this.extractUInt8(),
callsignNumber: this.extractUInt8()
},
activePath: [],
ammo: [],
contacts: [],
task: "",
name: "",
unitName: "",
groupName: "",
category: "",
coalition: "",
task: ""
}
const pathLength = this.#extractUInt16();
const ammoLength = this.#extractUInt16();
const contactsLength = this.#extractUInt16();
const nameLength = this.#extractUInt16();
const unitNameLength = this.#extractUInt16();
const groupNameLength = this.#extractUInt16();
const categoryLength = this.#extractUInt16();
const coalitionLength = this.#extractUInt16();
const pathLength = this.extractUInt16();
const ammoLength = this.extractUInt16();
const contactsLength = this.extractUInt16();
const taskLength = this.extractUInt8();
if (pathLength > 0) {
unitData.activePath = [];
for (let idx = 0; idx < pathLength; idx++) {
unitData.activePath.push(new LatLng(this.#extractFloat64(), this.#extractFloat64(), this.#extractFloat64()));
unitData.activePath.push(new LatLng(this.extractFloat64(), this.extractFloat64(), this.extractFloat64()));
}
}
@@ -103,11 +99,11 @@ export class DataExtractor {
unitData.ammo = [];
for (let idx = 0; idx < pathLength; idx++) {
unitData.ammo.push({
quantity: this.#extractUInt16(),
name: this.#extractString(32),
guidance: this.#extractUint8(),
category: this.#extractUint8(),
missileCategory: this.#extractUint8()
quantity: this.extractUInt16(),
name: this.extractString(32),
guidance: this.extractUInt8(),
category: this.extractUInt8(),
missileCategory: this.extractUInt8()
});
}
}
@@ -116,77 +112,92 @@ export class DataExtractor {
unitData.contacts = [];
for (let idx = 0; idx < pathLength; idx++) {
unitData.contacts.push({
ID: this.#extractUInt32(),
detectionMethod: this.#extractUint8()
ID: this.extractUInt32(),
detectionMethod: this.extractUInt8()
});
}
}
if (taskLength > 0) {
unitData.task = this.extractString(taskLength);
}
const nameLength = this.extractUInt16();
const unitNameLength = this.extractUInt16();
const groupNameLength = this.extractUInt16();
const categoryLength = this.extractUInt16();
if (nameLength > 0) {
unitData.name = this.#extractString(nameLength);
unitData.name = this.extractString(nameLength);
}
if (unitNameLength > 0) {
unitData.unitName = this.#extractString(unitNameLength);
unitData.unitName = this.extractString(unitNameLength);
}
if (groupNameLength > 0) {
unitData.groupName = this.#extractString(groupNameLength);
unitData.groupName = this.extractString(groupNameLength);
}
if (categoryLength > 0) {
unitData.category = this.#extractString(categoryLength);
}
if (coalitionLength > 0) {
unitData.coalition = this.#extractString(coalitionLength);
unitData.category = this.extractString(categoryLength);
}
return {data: unitData, offset: this.#offset};
}
#extractBool() {
extractBool() {
const value = this.#dataview.getUint8(this.#offset);
this.#offset += 1;
return value > 0;
}
#extractUint8() {
extractUInt8() {
const value = this.#dataview.getUint8(this.#offset);
this.#offset += 1;
return value;
}
#extractUInt16() {
const value = this.#dataview.getUint16(this.#offset);
extractUInt16() {
const value = this.#dataview.getUint16(this.#offset, true);
this.#offset += 2;
return value;
}
#extractUInt32() {
const value = this.#dataview.getUint32(this.#offset);
extractUInt32() {
const value = this.#dataview.getUint32(this.#offset, true);
this.#offset += 4;
return value;
}
#extractFloat64() {
const value = this.#dataview.getFloat64(this.#offset);
extractUInt64() {
const value = this.#dataview.getBigUint64(this.#offset, true);
this.#offset += 8;
return value;
}
#extractFromBitmask(bitmask: number, position: number) {
return (bitmask >> position & 1) > 0;
extractFloat64() {
const value = this.#dataview.getFloat64(this.#offset, true);
this.#offset += 8;
return value;
}
#extractString(length: number) {
const value = this.#decoder.decode(this.#buffer.slice(this.#offset, length));
extractFromBitmask(bitmask: number, position: number) {
return ((bitmask >> position) & 1) > 0;
}
extractString(length: number) {
const value = this.#decoder.decode(this.#buffer.slice(this.#offset, this.#offset +length));
this.#offset += length;
return value;
}
#extractChar() {
return this.#extractString(1);
extractChar() {
return this.extractString(1);
}
getOffset() {
return this.#offset;
}
#getState(state: number) {
@@ -216,4 +227,13 @@ export class DataExtractor {
else
return emissionsCountermeasures[0];
}
#getCoalition(coalitionID: number) {
switch (coalitionID){
case 0: return "neutral";
case 1: return "red";
case 2: return "blue";
}
return "";
}
}

View File

@@ -24,8 +24,8 @@ export class Unit extends CustomMarker {
human: false,
controlled: false,
hasTask: false,
desiredAltitudeType: false,
desiredSpeedType: false,
desiredAltitudeType: "AGL",
desiredSpeedType: "GS",
isTanker: false,
isAWACS: false,
onOff: false,
@@ -222,7 +222,6 @@ export class Unit extends CustomMarker {
var updateMarker = positionChanged || headingChanged || aliveChanged || stateChanged || controlledChanged || !getMap().hasLayer(this);
/* Assign the data */
/* TODO Allow for partial updates */
this.#data = data;
/* Fire an event when a unit dies */
@@ -406,10 +405,10 @@ export class Unit extends CustomMarker {
var path: any = {};
if (this.getData().activePath.length > 0) {
path = this.getData().activePath;
path[(Object.keys(path).length + 1).toString()] = latlng;
path[(Object.keys(path).length).toString()] = latlng;
}
else {
path = { "1": latlng };
path = [latlng];
}
addDestination(this.ID, path);
}
@@ -779,7 +778,7 @@ export class Unit extends CustomMarker {
/* Update the position of the existing markers (to avoid creating markers uselessly) */
for (let WP in this.getData().activePath) {
var destination = this.getData().activePath[WP];
this.#pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
this.#pathMarkers[parseInt(WP)].setLatLng([destination.lat, destination.lng]);
points.push(new LatLng(destination.lat, destination.lng));
this.#pathPolyline.setLatLngs(points);
}

View File

@@ -1,8 +1,8 @@
import { LatLng, LatLngBounds } from "leaflet";
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler } from "..";
import { Unit } from "./unit";
import { cloneUnit, spawnGroundUnit } from "../server/server";
import { base64ToBytes, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polygonArea, randomPointInPoly, randomUnitBlueprintByRole } from "../other/utils";
import { cloneUnit, setLastUpdateTime, spawnGroundUnit } from "../server/server";
import { deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polygonArea, randomPointInPoly, randomUnitBlueprintByRole } from "../other/utils";
import { CoalitionArea } from "../map/coalitionarea";
import { Airbase } from "../missionhandler/airbase";
import { groundUnitsDatabase } from "./groundunitsdatabase";
@@ -70,13 +70,13 @@ export class UnitsManager {
}
update(encodedData: string) {
update(buffer: ArrayBuffer) {
var updatedUnits: Unit[] = [];
var buffer = base64ToBytes(encodedData);
var dataExtractor = new DataExtractor(buffer);
var data: {[key: string]: UnitData} = {};
var offset = 0;
var updateTime = Number(dataExtractor.extractUInt64());
var offset = dataExtractor.getOffset();
while (offset < buffer.byteLength) {
const result = dataExtractor.extractData(offset);
data[result.data.ID] = result.data;
@@ -106,6 +106,8 @@ export class UnitsManager {
// if (!updatedUnits.includes(unit))
// unit.setData(null);
//});
setLastUpdateTime(updateTime);
}
setHiddenType(key: string, value: boolean) {

View File

@@ -1,6 +1,6 @@
local version = "v0.3.0-alpha"
local debug = false
local debug = FALSE
Olympus.unitCounter = 1
Olympus.payloadRegistry = {}

View File

@@ -1,8 +0,0 @@
{
"files.associations": {
"*.ejs": "html",
"xstring": "cpp",
"vector": "cpp",
"list": "cpp"
}
}

View File

@@ -7,6 +7,9 @@
#include "logger.h"
#include "commands.h"
#include <chrono>
using namespace std::chrono;
#define TASK_CHECK_INIT_VALUE 10
namespace State
@@ -79,8 +82,10 @@ namespace DataTypes {
unsigned short fuel;
double desiredSpeed;
double desiredAltitude;
unsigned int leaderID;
unsigned int targetID;
Coords targetPosition;
unsigned char coalition;
unsigned char state;
unsigned char ROE;
unsigned char reactionToThreat;
@@ -90,11 +95,7 @@ namespace DataTypes {
unsigned short pathLength;
unsigned short ammoLength;
unsigned short contactsLength;
unsigned char nameLength;
unsigned char unitNameLength;
unsigned char groupNameLength;
unsigned char categoryLength;
unsigned char coalitionLength;
unsigned char taskLength;
};
}
#pragma pack(pop)
@@ -112,18 +113,18 @@ public:
void runAILoop();
void updateExportData(json::value json, double dt = 0);
void updateMissionData(json::value json);
unsigned int getUpdateData(char* &data);
void getData(stringstream &ss, bool refresh);
unsigned int getDataPacket(char* &data);
void getData(stringstream &ss, unsigned long long time, bool refresh);
virtual string getCategory() { return "No category"; };
/********** Base data **********/
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; }
void setControlled(bool newValue) { updateValue(controlled, newValue); }
void setName(string newValue) { updateValue(name, newValue); }
void setUnitName(string newValue) { updateValue(unitName, newValue); }
void setGroupName(string newValue) { updateValue(groupName, newValue); }
void setAlive(bool newValue) { updateValue(alive, newValue); }
void setCountry(unsigned int newValue) { updateValue(country, newValue); }
void setHuman(bool newValue) { updateValue(human, newValue); }
bool getControlled() { return controlled; }
string getName() { return name; }
@@ -134,51 +135,50 @@ public:
bool getHuman() { return human; }
/********** Flight data **********/
void setPosition(Coords newPosition) { position = newPosition; }
void setHeading(double newHeading) {heading = newHeading; }
void setSpeed(double newSpeed) {speed = newSpeed; }
void setPosition(Coords newValue) { updateValue(position, newValue); }
void setHeading(double newValue) { updateValue(heading, newValue); }
void setSpeed(double newValue) { updateValue(speed, newValue); }
Coords getPosition() { return position; }
double getHeading() { return heading; }
double getSpeed() { return speed; }
/********** Mission data **********/
void setFuel(short newFuel) { fuel = newFuel; }
void setFuel(unsigned short newValue) { updateValue(fuel, newValue); }
void setAmmo(vector<DataTypes::Ammo> newAmmo) { ammo = newAmmo; }
void setContacts(vector<DataTypes::Contact> newContacts) {contacts = newContacts; }
void setHasTask(bool newHasTask);
void setCoalitionID(unsigned int newCoalitionID);
void setContacts(vector<DataTypes::Contact> newContacts) { contacts = newContacts; }
void setHasTask(bool newValue) { updateValue(hasTask, newValue); }
void setCoalition(unsigned char newValue) { updateValue(coalition, newValue);}
double getFuel() { return fuel; }
vector<DataTypes::Ammo> getAmmo() { return ammo; }
vector<DataTypes::Contact> getTargets() { return contacts; }
bool getHasTask() { return hasTask; }
string getCoalition() { return coalition; }
unsigned int getCoalitionID();
unsigned int getCoalition() { return coalition; }
/********** Formation data **********/
void setLeaderID(unsigned int newLeaderID) { leaderID = newLeaderID; }
void setLeaderID(unsigned int newValue) { updateValue(leaderID, newValue); }
void setFormationOffset(Offset formationOffset);
unsigned int getLeaderID() { return leaderID; }
Offset getFormationoffset() { return formationOffset; }
/********** Task data **********/
void setCurrentTask(string newCurrentTask) { currentTask = newCurrentTask; }
void setDesiredSpeed(double newDesiredSpeed);
void setDesiredAltitude(double newDesiredAltitude);
void setDesiredSpeedType(string newDesiredSpeedType);
void setDesiredAltitudeType(string newDesiredAltitudeType);
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; }
void setActivePath(list<Coords> newActivePath);
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; };
virtual void setFollowRoads(bool newFollowRoads) { followRoads = newFollowRoads; };
void setTask(string newValue) { updateValue(task, newValue); }
void setDesiredSpeed(double newValue);
void setDesiredAltitude(double newValue);
void setDesiredSpeedType(string newValue);
void setDesiredAltitudeType(string newValue);
void setActiveDestination(Coords newValue) { updateValue(activeDestination, newValue); }
void setActivePath(list<Coords> newValue);
void setTargetID(unsigned int newValue) { updateValue(targetID, newValue); }
void setTargetPosition(Coords newValue) { updateValue(targetPosition, newValue); }
void setIsTanker(bool newValue);
void setIsAWACS(bool newValue);
virtual void setOnOff(bool newValue) { updateValue(onOff, newValue); };
virtual void setFollowRoads(bool newValue) { updateValue(followRoads, newValue); };
string getCurrentTask() { return currentTask; }
string getTask() { return task; }
virtual double getDesiredSpeed() { return desiredSpeed; };
virtual double getDesiredAltitude() { return desiredAltitude; };
virtual bool getDesiredSpeedType() { return desiredSpeedType; };
@@ -193,13 +193,13 @@ public:
bool getFollowRoads() { return followRoads; };
/********** Options data **********/
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);
void setROE(unsigned char newValue, bool force = false);
void setReactionToThreat(unsigned char newValue, bool force = false);
void setEmissionsCountermeasures(unsigned char newValue, bool force = false);
void setTACAN(Options::TACAN newValue, bool force = false);
void setRadio(Options::Radio newValue, bool force = false);
void setGeneralSettings(Options::GeneralSettings newValue, bool force = false);
void setEPLRS(bool newValue, bool force = false);
unsigned char getROE() { return ROE; }
unsigned char getReactionToThreat() { return reactionToThreat; }
@@ -220,6 +220,8 @@ public:
void pushActivePathFront(Coords newActivePathFront);
void pushActivePathBack(Coords newActivePathBack);
void popActivePathFront();
void triggerUpdate() { lastUpdateTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); }
unsigned long long getLastUpdateTime() { return lastUpdateTime; };
protected:
unsigned int ID;
@@ -247,18 +249,18 @@ protected:
vector<DataTypes::Ammo> ammo;
vector<DataTypes::Contact> contacts;
bool hasTask = false;
string coalition = "";
unsigned char coalition;
/********** Formation data **********/
unsigned int leaderID = NULL;
Offset formationOffset = Offset(NULL);
/********** Task data **********/
string currentTask = "";
string task = "";
double desiredSpeed = 0;
double desiredAltitude = 0;
bool desiredSpeedType = 0;
bool desiredAltitudeType = 0;
bool desiredSpeedType = 1;
bool desiredAltitudeType = 1;
list<Coords> activePath;
Coords activeDestination = Coords(NULL);
unsigned int targetID = NULL;
@@ -277,10 +279,14 @@ protected:
Options::GeneralSettings generalSettings;
bool EPLRS = false;
/********** Data packet **********/
DataTypes::DataPacket dataPacket;
/********** State machine **********/
unsigned char state = State::NONE;
/********** Other **********/
unsigned long long lastUpdateTime = 0;
Coords oldPosition = Coords(0); // Used to approximate speed
/********** Functions **********/
@@ -295,4 +301,14 @@ protected:
void goToDestination(string enrouteTask = "nil");
bool checkTaskFailed();
void resetTaskFailedCounter();
template <typename T>
void updateValue(T& value, T& newValue)
{
if (newValue != value)
{
triggerUpdate();
*(&value) = newValue;
}
}
};

View File

@@ -20,7 +20,7 @@ public:
void updateExportData(lua_State* L, double dt = 0);
void updateMissionData(json::value missionData);
void runAILoop();
string getUnitData(bool refresh);
string getUnitData(stringstream &ss, unsigned long long time, bool refresh);
void deleteUnit(unsigned int ID, bool explosion);
void acquireControl(unsigned int ID);

View File

@@ -120,7 +120,7 @@ void AirUnit::AIloop()
/* State machine */
switch (state) {
case State::IDLE: {
currentTask = "Idle";
setTask("Idle");
if (!getHasTask())
{
@@ -147,17 +147,17 @@ void AirUnit::AIloop()
if (isTanker)
{
enrouteTask = "{ id = 'Tanker' }";
currentTask = "Tanker";
setTask("Tanker");
}
else if (isAWACS)
{
enrouteTask = "{ id = 'AWACS' }";
currentTask = "AWACS";
setTask("AWACS");
}
else
{
enrouteTask = "nil";
currentTask = "Reaching destination";
setTask("Reaching destination");
}
if (activeDestination == NULL || !getHasTask())
@@ -179,7 +179,7 @@ void AirUnit::AIloop()
}
case State::LAND: {
string enrouteTask = "{ id = 'Land' }";
currentTask = "Landing";
setTask("Landing");
if (activeDestination == NULL)
{
@@ -203,7 +203,7 @@ void AirUnit::AIloop()
<< "targetID = " << targetID << ","
<< "}";
string enrouteTask = enrouteTaskSS.str();
currentTask = "Attacking " + getTargetName();
setTask("Attacking " + getTargetName());
if (!getHasTask())
{
@@ -223,7 +223,7 @@ void AirUnit::AIloop()
break;
}
currentTask = "Following " + getTargetName();
setTask("Following " + getTargetName());
Unit* leader = unitsManager->getUnit(leaderID);
if (!getHasTask()) {
@@ -247,7 +247,7 @@ void AirUnit::AIloop()
break;
}
case State::REFUEL: {
currentTask = "Refueling";
setTask("Refueling");
if (!getHasTask()) {
if (fuel <= initialFuel) {
@@ -265,7 +265,7 @@ void AirUnit::AIloop()
}
}
case State::BOMB_POINT: {
currentTask = "Bombing point";
setTask("Bombing point");
if (!getHasTask()) {
std::ostringstream taskSS;
@@ -276,7 +276,7 @@ void AirUnit::AIloop()
}
}
case State::CARPET_BOMB: {
currentTask = "Carpet bombing";
setTask("Carpet bombing");
if (!getHasTask()) {
std::ostringstream taskSS;
@@ -288,7 +288,7 @@ void AirUnit::AIloop()
break;
}
case State::BOMB_BUILDING: {
currentTask = "Bombing building";
setTask("Bombing building");
if (!getHasTask()) {
std::ostringstream taskSS;

View File

@@ -85,13 +85,14 @@ extern "C" DllExport int coreFrame(lua_State* L)
if (unitsManager != nullptr) {
unitsManager->updateExportData(L, duration.count());
//unitsManager->runAILoop();
unitsManager->runAILoop();
}
before = std::chrono::system_clock::now();
}
if (scheduler != nullptr)
//scheduler->execute(L);
scheduler->execute(L);
return(0);
}

View File

@@ -71,7 +71,7 @@ void GroundUnit::AIloop()
{
switch (state) {
case State::IDLE: {
currentTask = "Idle";
setTask("Idle");
if (getHasTask())
resetTask();
break;
@@ -102,7 +102,7 @@ void GroundUnit::AIloop()
break;
}
case State::FIRE_AT_AREA: {
currentTask = "Firing at area";
setTask("Firing at area");
if (!getHasTask()) {
std::ostringstream taskSS;

View File

@@ -7,7 +7,7 @@
extern UnitsManager* unitsManager;
Scheduler::Scheduler(lua_State* L):
Scheduler::Scheduler(lua_State* L) :
load(0)
{
LogInfo(L, "Scheduler constructor called successfully");
@@ -25,16 +25,15 @@ void Scheduler::appendCommand(Command* command)
void Scheduler::execute(lua_State* L)
{
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
This is needed to avoid server lag. */
if (load > 0) {
load--;
return;
}
unsigned int priority = CommandPriority::IMMEDIATE;
while (priority >= CommandPriority::LOW)
{
int priority = CommandPriority::IMMEDIATE;
while (priority >= CommandPriority::LOW) {
for (auto command : commands)
{
if (command->getPriority() == priority)
@@ -42,13 +41,15 @@ void Scheduler::execute(lua_State* L)
string commandString = "Olympus.protectedCall(" + command->getString(L) + ")";
if (dostring_in(L, "server", (commandString)))
log("Error executing command " + commandString);
else
log("Command '" + commandString + "' executed correctly, current load " + to_string(load));
load = command->getLoad();
commands.remove(command);
return;
}
}
priority--;
}
};
}
void Scheduler::handleRequest(string key, json::value value)
@@ -66,11 +67,11 @@ void Scheduler::handleRequest(string key, json::value value)
string unitName = unit->getUnitName();
json::value path = value[L"path"];
list<Coords> newPath;
for (unsigned int i = 1; i <= path.as_object().size(); i++)
for (unsigned int i = 0; i < path.as_array().size(); i++)
{
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();
double lat = path[i][L"lat"].as_double();
double lng = path[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);
@@ -126,7 +127,7 @@ void Scheduler::handleRequest(string key, json::value value)
string unitName;
string targetName;
if (unit != nullptr)
unitName = unit->getUnitName();
else
@@ -197,11 +198,11 @@ void Scheduler::handleRequest(string key, json::value value)
}
else if (key.compare("setSpeedType") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
}
else if (key.compare("setAltitude") == 0)
{
@@ -233,7 +234,7 @@ void Scheduler::handleRequest(string key, json::value value)
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
unsigned char ROE = value[L"ROE"].as_number().is_uint32();
unsigned char ROE = value[L"ROE"].as_number().to_uint32();
unit->setROE(ROE);
}
else if (key.compare("setReactionToThreat") == 0)
@@ -241,7 +242,7 @@ void Scheduler::handleRequest(string key, json::value value)
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().is_uint32();
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().to_uint32();
unit->setReactionToThreat(reactionToThreat);
}
else if (key.compare("setEmissionsCountermeasures") == 0)
@@ -249,7 +250,7 @@ void Scheduler::handleRequest(string key, json::value value)
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().is_uint32();
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().to_uint32();
unit->setEmissionsCountermeasures(emissionsCountermeasures);
}
else if (key.compare("landAt") == 0)
@@ -317,7 +318,7 @@ void Scheduler::handleRequest(string key, json::value value)
}
}
else if (key.compare("setFollowRoads") == 0)
{
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool followRoads = value[L"followRoads"].as_bool();
@@ -325,7 +326,7 @@ void Scheduler::handleRequest(string key, json::value value)
unit->setFollowRoads(followRoads);
}
else if (key.compare("setOnOff") == 0)
{
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool onOff = value[L"onOff"].as_bool();
@@ -389,10 +390,11 @@ void Scheduler::handleRequest(string key, json::value value)
{
log("Unknown command: " + key);
}
if (command != nullptr)
{
appendCommand(command);
log("New command appended correctly to stack. Current server load: " + to_string(load));
}
}

View File

@@ -69,10 +69,11 @@ void Server::handle_get(http_request request)
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
http_response response(status_codes::OK);
string authorization = to_base64("admin:" + password);
log(authorization);
if (password == "" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
if (password.length() == 0 || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization)) == 0))
{
std::exception_ptr eptr;
try {
@@ -96,28 +97,34 @@ void Server::handle_get(http_request request)
}
}
// TODO would be nice to optimize this
answer[L"units"] = json::value(to_wstring(unitsManager->getUnitData(time == 0)));
}
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 (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)
answer[L"mission"] = mission;
bool refresh = (time == 0);
unsigned long long updateTime = ms.count();
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
answer[L"time"] = json::value::string(to_wstring(ms.count()));
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
stringstream ss;
ss.write((char*)&updateTime, sizeof(updateTime));
unitsManager->getUnitData(ss, time, refresh);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
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 (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)
answer[L"mission"] = mission;
answer[L"time"] = json::value::string(to_wstring(ms.count()));
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
response.set_body(answer);
}
}
response.set_body(answer);
}
catch (...) {
eptr = std::current_exception(); // capture
@@ -140,7 +147,7 @@ void Server::handle_request(http_request request, function<void(json::value cons
{
http_response response(status_codes::OK);
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))))
if (password.length() == 0 || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization)) == 0))
{
auto answer = json::value::object();
request.extract_json().then([&answer, &action](pplx::task<json::value> task)

View File

@@ -45,6 +45,24 @@ 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_object_field(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("Olympus") != string::npos)
setControlled(true);
updateExportData(json);
setDefaults();
}
@@ -92,6 +110,21 @@ void Unit::runAILoop() {
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"))
{
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()
});
}
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)
{
@@ -100,35 +133,7 @@ void Unit::updateExportData(json::value json, double dt)
if (dt > 0)
setSpeed(getSpeed() * 0.95 + (dist / dt) * 0.05);
}
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"))
setCoalitionID(json[L"CoalitionID"].as_number().to_int32());
if (json.has_object_field(L"LatLongAlt"))
{
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"))
setHuman(json[L"Flags"][L"Human"].as_bool());
/* All units which contain the name "Olympus" are automatically under AI control */
if (getUnitName().find("Olympus") != string::npos)
setControlled(true);
oldPosition = position;
}
@@ -175,7 +180,7 @@ void Unit::updateMissionData(json::value json)
setHasTask(json[L"hasTask"].as_bool());
}
unsigned int Unit::getUpdateData(char* &data)
unsigned int Unit::getDataPacket(char* &data)
{
/* Reserve data for:
1) DataPacket;
@@ -217,34 +222,31 @@ unsigned int Unit::getUpdateData(char* &data)
fuel,
desiredSpeed,
desiredAltitude,
leaderID,
targetID,
targetPosition,
state,
ROE,
reactionToThreat,
emissionsCountermeasures,
coalition,
TACAN,
radio,
activePath.size(),
ammo.size(),
contacts.size(),
name.size(),
unitName.size(),
groupName.size(),
getCategory().size(),
coalition.size()
task.size()
};
memcpy(data + offset, &dataPacket, sizeof(dataPacket));
offset += sizeof(dataPacket);
/* Prepare the path vector and copy it to memory */
std::vector<Coords> path;
for (const Coords& c : activePath)
path.push_back(c);
memcpy(data + offset, &path, activePath.size() * sizeof(Coords));
offset += activePath.size() * sizeof(Coords);
for (const Coords& c : activePath) {
memcpy(data + offset, &c, sizeof(Coords));
offset += sizeof(Coords);
}
/* Copy the ammo vector to memory */
memcpy(data + offset, &ammo, ammo.size() * sizeof(DataTypes::Ammo));
offset += ammo.size() * sizeof(DataTypes::Ammo);
@@ -256,10 +258,12 @@ unsigned int Unit::getUpdateData(char* &data)
return offset;
}
void Unit::getData(stringstream &ss, bool refresh)
void Unit::getData(stringstream &ss, unsigned long long time, bool refresh)
{
if (time > lastUpdateTime && !refresh) return;
char* data;
unsigned int size = getUpdateData(data);
unsigned int size = getDataPacket(data);
/* Prepare the data packet and copy it to memory */
/* If the unit is in a group, get the update data from the group leader and only replace the position, speed and heading */
@@ -271,15 +275,25 @@ void Unit::getData(stringstream &ss, bool refresh)
}
ss.write(data, size);
delete data;
ss << task;
if (refresh) {
ss << name;
ss << unitName;
ss << groupName;
ss << getCategory();
ss << coalition;
}
unsigned short nameLength = name.length();
unsigned short unitNameLength = unitName.length();
unsigned short groupNameLength = groupName.length();
unsigned short categoryLength = getCategory().length();
ss.write((char*)&nameLength, sizeof(nameLength));
ss.write((char*)&unitNameLength, sizeof(unitNameLength));
ss.write((char*)&groupNameLength, sizeof(groupNameLength));
ss.write((char*)&categoryLength, sizeof(categoryLength));
ss << name;
ss << unitName;
ss << groupName;
ss << getCategory();
delete data;
}
void Unit::setActivePath(list<Coords> newPath)
@@ -315,26 +329,6 @@ void Unit::popActivePathFront()
setActivePath(path);
}
void Unit::setCoalitionID(unsigned int newCoalitionID)
{
if (newCoalitionID == 0)
coalition = "neutral";
else if (newCoalitionID == 1)
coalition = "red";
else
coalition = "blue";
}
unsigned int Unit::getCoalitionID()
{
if (coalition == "neutral")
return 0;
else if (coalition == "red")
return 1;
else
return 2;
}
string Unit::getTargetName()
{
if (isTargetAlive())
@@ -398,6 +392,8 @@ void Unit::setFormationOffset(Offset newFormationOffset)
{
formationOffset = newFormationOffset;
resetTask();
triggerUpdate();
}
void Unit::setROE(unsigned char newROE, bool force)
@@ -406,6 +402,8 @@ void Unit::setROE(unsigned char newROE, bool force)
ROE = newROE;
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, static_cast<unsigned int>(ROE)));
scheduler->appendCommand(command);
triggerUpdate();
}
}
@@ -416,6 +414,8 @@ void Unit::setReactionToThreat(unsigned char newReactionToThreat, bool force)
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, static_cast<unsigned int>(reactionToThreat)));
scheduler->appendCommand(command);
triggerUpdate();
}
}
@@ -464,6 +464,8 @@ void Unit::setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ECM_USING, ECMEnum));
scheduler->appendCommand(command);
triggerUpdate();
}
}
@@ -476,15 +478,23 @@ void Unit::landAt(Coords loc)
void Unit::setIsTanker(bool newIsTanker)
{
isTanker = newIsTanker;
resetTask();
if (isTanker != newIsTanker) {
isTanker = newIsTanker;
resetTask();
triggerUpdate();
}
}
void Unit::setIsAWACS(bool newIsAWACS)
{
isAWACS = newIsAWACS;
resetTask();
setEPLRS(isAWACS);
if (isAWACS != newIsAWACS) {
isAWACS = newIsAWACS;
resetTask();
setEPLRS(isAWACS);
triggerUpdate();
}
}
void Unit::setTACAN(Options::TACAN newTACAN, bool force)
@@ -517,6 +527,8 @@ void Unit::setTACAN(Options::TACAN newTACAN, bool force)
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
triggerUpdate();
}
}
@@ -551,6 +563,8 @@ void Unit::setRadio(Options::Radio newRadio, bool force)
<< "}";
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
triggerUpdate();
}
}
@@ -590,6 +604,8 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
scheduler->appendCommand(command);
triggerUpdate();
}
}
@@ -600,6 +616,8 @@ void Unit::setDesiredSpeed(double newDesiredSpeed)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
triggerUpdate();
}
void Unit::setDesiredAltitude(double newDesiredAltitude)
@@ -609,6 +627,8 @@ void Unit::setDesiredAltitude(double newDesiredAltitude)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
triggerUpdate();
}
void Unit::setDesiredSpeedType(string newDesiredSpeedType)
@@ -618,6 +638,8 @@ void Unit::setDesiredSpeedType(string newDesiredSpeedType)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
triggerUpdate();
}
void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
@@ -627,6 +649,8 @@ void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
triggerUpdate();
}
void Unit::goToDestination(string enrouteTask)
@@ -669,12 +693,16 @@ bool Unit::setActiveDestination()
{
activeDestination = activePath.front();
log(unitName + " active destination set to queue front");
triggerUpdate();
return true;
}
else
{
activeDestination = Coords(0);
log(unitName + " active destination set to NULL");
triggerUpdate();
return false;
}
}
@@ -695,11 +723,6 @@ bool Unit::updateActivePath(bool looping)
}
}
void Unit::setTargetPosition(Coords newTargetPosition)
{
targetPosition = newTargetPosition;
}
bool Unit::checkTaskFailed()
{
if (getHasTask())
@@ -714,8 +737,3 @@ bool Unit::checkTaskFailed()
void Unit::resetTaskFailedCounter() {
taskCheckCounter = TASK_CHECK_INIT_VALUE;
}
void Unit::setHasTask(bool newHasTask)
{
hasTask = newHasTask;
}

View File

@@ -154,11 +154,10 @@ void UnitsManager::runAILoop() {
unit.second->runAILoop();
}
string UnitsManager::getUnitData(bool refresh)
string UnitsManager::getUnitData(stringstream &ss, unsigned long long time, bool refresh)
{
stringstream ss;
for (auto const& p : units)
p.second->getData(ss, refresh);
p.second->getData(ss, time, refresh);
return to_base64(ss.str());
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "framework.h"
#pragma pack(push, 1)
struct Coords {
double lat = 0;
double lng = 0;
@@ -12,6 +13,7 @@ struct Offset {
double y = 0;
double z = 0;
};
#pragma pack(pop)
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const DllExport std::string CurrentDateTime();