mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Fixed update error and added update trigger
This commit is contained in:
4
client/src/@types/unit.d.ts
vendored
4
client/src/@types/unit.d.ts
vendored
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user