Tweaks and optimizations of front end

This commit is contained in:
Pax1601 2023-07-05 20:14:48 +02:00
parent ec91376da2
commit 1af98cc54f
13 changed files with 215 additions and 165 deletions

View File

@ -12,8 +12,8 @@ export class UnitDataTable extends Panel {
var units = getUnitsManager().getUnits();
const unitsArray = Object.values(units).sort((a: Unit, b: Unit) => {
const aVal = a.getData().unitName?.toLowerCase();
const bVal = b.getData().unitName?.toLowerCase();
const aVal = a.getUnitName()?.toLowerCase();
const bVal = b.getUnitName()?.toLowerCase();
if (aVal > bVal) {
return 1;
@ -48,7 +48,7 @@ export class UnitDataTable extends Panel {
for (const unit of unitsArray) {
const dataset = [unit.getData().unitName, unit.getData().name, unit.getCategory(), (unit.getData().controlled) ? "AI" : "Human"];
const dataset = [unit.getUnitName(), unit.getName(), unit.getCategory(), (unit.getControlled()) ? "AI" : "Human"];
addRow(el, dataset);
}

View File

@ -16,7 +16,7 @@ import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_
import { TargetMarker } from "./targetmarker";
import { CoalitionArea } from "./coalitionarea";
import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu";
import { DrawingCursor } from "./drawingmarker";
import { DrawingCursor } from "./drawingcursor";
L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect);
@ -37,6 +37,8 @@ export class Map extends L.Map {
#panUp: boolean = false;
#panDown: boolean = false;
#lastMousePosition: L.Point = new L.Point(0, 0);
#shiftKey: boolean = false;
#ctrlKey: boolean = false;
#centerUnit: Unit | null = null;
#miniMap: ClickableMiniMap | null = null;
#miniMapLayerGroup: L.LayerGroup;
@ -454,7 +456,7 @@ export class Map extends L.Map {
if (!e.originalEvent.ctrlKey) {
getUnitsManager().selectedUnitsClearDestinations();
}
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, e.originalEvent.shiftKey, this.#destinationGroupRotation)
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, this.#shiftKey, this.#destinationGroupRotation)
this.#destinationGroupRotation = 0;
this.#destinationRotationCenter = null;
this.#computeDestinationRotation = false;
@ -513,13 +515,13 @@ export class Map extends L.Map {
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
this.#updateCursor(e);
this.#updateCursor();
if (this.#state === MOVE_UNIT) {
/* Update the position of the destination cursors depeding on mouse rotation */
if (this.#computeDestinationRotation && this.#destinationRotationCenter != null)
this.#destinationGroupRotation = -bearing(this.#destinationRotationCenter.lat, this.#destinationRotationCenter.lng, this.getMouseCoordinates().lat, this.getMouseCoordinates().lng);
this.#updateDestinationCursors(e);
this.#updateDestinationCursors();
}
else if ([BOMBING, CARPET_BOMBING, FIRE_AT_AREA].includes(this.#state)) {
this.#targetCursor.setLatLng(this.getMouseCoordinates());
@ -532,13 +534,17 @@ export class Map extends L.Map {
}
#onKeyDown(e: any) {
this.#updateDestinationCursors(e);
this.#updateCursor(e);
this.#shiftKey = e.originalEvent.shiftKey;
this.#ctrlKey = e.originalEvent.ctrlKey;
this.#updateCursor();
this.#updateDestinationCursors();
}
#onKeyUp(e: any) {
this.#updateDestinationCursors(e);
this.#updateCursor(e);
this.#shiftKey = e.originalEvent.shiftKey;
this.#ctrlKey = e.originalEvent.ctrlKey;
this.#updateCursor();
this.#updateDestinationCursors();
}
#onZoom(e: any) {
@ -547,7 +553,7 @@ export class Map extends L.Map {
}
#panToUnit(unit: Unit) {
var unitPosition = new L.LatLng(unit.getData().position.lat, unit.getData().position.lng);
var unitPosition = new L.LatLng(unit.getPosition().lat, unit.getPosition().lng);
this.setView(unitPosition, this.getZoom(), { animate: false });
}
@ -582,38 +588,41 @@ export class Map extends L.Map {
document.getElementById(this.#ID)?.classList.add("hidden-cursor");
}
#showDestinationCursors(singleCursor: boolean) {
/* Don't create the cursors if there already are the correct number of them available */
if (singleCursor || getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length != this.#destinationPreviewCursors.length) {
/* Reset the cursors to start from a clean condition */
this.#hideDestinationCursors();
#showDestinationCursors() {
const singleCursor = !this.#shiftKey;
const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length;
if (selectedUnitsCount > 0) {
if (singleCursor && this.#destinationPreviewCursors.length != 1) {
this.#hideDestinationCursors();
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
marker.addTo(this);
this.#destinationPreviewCursors = [marker];
}
else if (!singleCursor) {
while (this.#destinationPreviewCursors.length > selectedUnitsCount) {
this.removeLayer(this.#destinationPreviewCursors[0]);
this.#destinationPreviewCursors.splice(0, 1);
}
if (getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length > 0) {
if (singleCursor) {
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
marker.addTo(this);
this.#destinationPreviewCursors = [marker];
}
else {
/* Create the cursors. If a group is selected only one cursor is shown for it, because you can't control single units in a group */
this.#destinationPreviewCursors = getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).map((unit: Unit) => {
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
marker.addTo(this);
return marker;
});
while (this.#destinationPreviewCursors.length < selectedUnitsCount) {
var cursor = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
cursor.addTo(this);
this.#destinationPreviewCursors.push(cursor);
}
this.#updateDestinationCursors();
}
}
}
#updateDestinationCursors(e: any) {
#updateDestinationCursors() {
const groupLatLng = this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : this.getMouseCoordinates();
if (this.#destinationPreviewCursors.length == 1)
this.#destinationPreviewCursors[0].setLatLng(this.getMouseCoordinates());
else {
Object.values(getUnitsManager().selectedUnitsComputeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
if (idx < this.#destinationPreviewCursors.length)
this.#destinationPreviewCursors[idx].setLatLng(e.originalEvent.shiftKey ? latlng : this.getMouseCoordinates());
this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey? latlng : this.getMouseCoordinates());
})
};
}
@ -653,9 +662,9 @@ export class Map extends L.Map {
this.#drawingCursor.removeFrom(this);
}
#updateCursor(e?: any) {
#updateCursor() {
/* If the ctrl key is being pressed or we are performing an area selection, show the default cursor */
if (e?.originalEvent.ctrlKey || this.#selecting) {
if (this.#ctrlKey || this.#selecting) {
/* Hide all non default cursors */
this.#hideDestinationCursors();
this.#hideTargetCursor();
@ -671,7 +680,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 && e.originaleEvent && !e.originalEvent.shiftKey);
else if (this.#state === MOVE_UNIT) this.#showDestinationCursors();
else if ([BOMBING, CARPET_BOMBING, FIRE_AT_AREA].includes(this.#state)) this.#showTargetCursor();
else if (this.#state === COALITIONAREA_DRAW_POLYGON) this.#showDrawingCursor();
}

View File

@ -36,7 +36,7 @@ export class MouseInfoPanel extends Panel {
var selectedUnitPosition = null;
var selectedUnits = getUnitsManager().getSelectedUnits();
if (selectedUnits && selectedUnits.length == 1)
selectedUnitPosition = new LatLng(selectedUnits[0].getData().position.lat, selectedUnits[0].getData().position.lng);
selectedUnitPosition = new LatLng(selectedUnits[0].getPosition().lat, selectedUnits[0].getPosition().lng);
/* Draw measures from selected unit, from pin location, and from bullseyes */
this.#drawMeasure("ref-measure-position", "measure-position", this.#measurePoint, mousePosition);

View File

@ -99,13 +99,13 @@ export class UnitControlPanel extends Panel {
if (units.length < 20) {
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit, index: number) => {
var button = document.createElement("button");
var callsign = unit.getData().unitName || "";
var label = unit.getDatabase()?.getByName(unit.getData().name)?.label || unit.getData().name;
var callsign = unit.getUnitName() || "";
var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName();
button.setAttribute("data-label", label);
button.setAttribute("data-callsign", callsign);
button.setAttribute("data-coalition", unit.getData().coalition);
button.setAttribute("data-coalition", unit.getCoalition());
button.classList.add("pill", "highlight-coalition")
button.addEventListener("click", () => {
@ -140,12 +140,12 @@ export class UnitControlPanel extends Panel {
element.toggleAttribute("data-show-advanced-settings-button", units.length == 1);
/* Flight controls */
var desiredAltitude: number | undefined = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().desiredAltitude});
var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().desiredAltitudeType});
var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().desiredSpeed});
var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().desiredSpeedType});
var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().onOff});
var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getData().followRoads});
var desiredAltitude: number | undefined = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()});
var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()});
var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()});
var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()});
var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()});
var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()});
if (selectedUnitsTypes.length == 1) {
this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false);
@ -171,15 +171,15 @@ export class UnitControlPanel extends Panel {
/* Option buttons */
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getData().ROE === button.value))
button.classList.toggle("selected", units.every((unit: Unit) => unit.getROE() === button.value))
});
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getData().reactionToThreat === button.value))
button.classList.toggle("selected", units.every((unit: Unit) => unit.getReactionToThreat() === button.value))
});
this.#optionButtons["emissionsCountermeasures"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getData().emissionsCountermeasures === button.value))
button.classList.toggle("selected", units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value))
});
this.#onOffSwitch.setValue(onOff, false);
@ -208,11 +208,11 @@ export class UnitControlPanel extends Panel {
const radioCallsignNumberInput = this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input") as HTMLInputElement;
const unit = units[0];
const roles = aircraftDatabase.getByName(unit.getData().name)?.loadouts.map((loadout) => {return loadout.roles})
const roles = aircraftDatabase.getByName(unit.getName())?.loadouts.map((loadout) => {return loadout.roles})
const tanker = roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker");
const AWACS = roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS");
const radioMHz = Math.floor(unit.getData().radio.frequency / 1000000);
const radioDecimals = (unit.getData().radio.frequency / 1000000 - radioMHz) * 1000;
const radioMHz = Math.floor(unit.getRadio().frequency / 1000000);
const radioDecimals = (unit.getRadio().frequency / 1000000 - radioMHz) * 1000;
/* Activate the correct options depending on unit type */
this.#advancedSettingsDialog.toggleAttribute("data-show-settings", !tanker && !AWACS);
@ -224,28 +224,28 @@ export class UnitControlPanel extends Panel {
/* Set common properties */
// Name
unitNameEl.innerText = unit.getData().unitName;
unitNameEl.innerText = unit.getUnitName();
// General settings
prohibitJettisonCheckbox.checked = unit.getData().generalSettings.prohibitJettison;
prohibitAfterburnerCheckbox.checked = unit.getData().generalSettings.prohibitAfterburner;
prohibitAACheckbox.checked = unit.getData().generalSettings.prohibitAA;
prohibitAGCheckbox.checked = unit.getData().generalSettings.prohibitAG;
prohibitAirWpnCheckbox.checked = unit.getData().generalSettings.prohibitAirWpn;
prohibitJettisonCheckbox.checked = unit.getGeneralSettings().prohibitJettison;
prohibitAfterburnerCheckbox.checked = unit.getGeneralSettings().prohibitAfterburner;
prohibitAACheckbox.checked = unit.getGeneralSettings().prohibitAA;
prohibitAGCheckbox.checked = unit.getGeneralSettings().prohibitAG;
prohibitAirWpnCheckbox.checked = unit.getGeneralSettings().prohibitAirWpn;
// Tasking
tankerCheckbox.checked = unit.getData().isTanker;
AWACSCheckbox.checked = unit.getData().isAWACS;
tankerCheckbox.checked = unit.getIsTanker();
AWACSCheckbox.checked = unit.getIsAWACS();
// TACAN
TACANCheckbox.checked = unit.getData().TACAN.isOn;
TACANChannelInput.value = String(unit.getData().TACAN.channel);
TACANCallsignInput.value = String(unit.getData().TACAN.callsign);
this.#TACANXYDropdown.setValue(unit.getData().TACAN.XY);
TACANCheckbox.checked = unit.getTACAN().isOn;
TACANChannelInput.value = String(unit.getTACAN().channel);
TACANCallsignInput.value = String(unit.getTACAN().callsign);
this.#TACANXYDropdown.setValue(unit.getTACAN().XY);
// Radio
radioMhzInput.value = String(radioMHz);
radioCallsignNumberInput.value = String(unit.getData().radio.callsignNumber);
radioCallsignNumberInput.value = String(unit.getRadio().callsignNumber);
this.#radioDecimalsDropdown.setValue("." + radioDecimals);
if (tanker) /* Set tanker specific options */
@ -256,7 +256,7 @@ export class UnitControlPanel extends Panel {
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
// This must be done after setting the options
if (!this.#radioCallsignDropdown.selectValue(unit.getData().radio.callsign - 1)) // Ensure the selected value is in the acceptable range
if (!this.#radioCallsignDropdown.selectValue(unit.getRadio().callsign - 1)) // Ensure the selected value is in the acceptable range
this.#radioCallsignDropdown.selectValue(0);
}
}

View File

@ -57,16 +57,16 @@ export class UnitInfoPanel extends Panel {
/* Set the unit info */
this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || baseData.name;
this.#unitName.innerText = baseData.unitName;
if (unit.getData().human)
if (unit.getHuman())
this.#unitControl.innerText = "Human";
else if (baseData.controlled)
this.#unitControl.innerText = "Olympus controlled";
else
this.#unitControl.innerText = "DCS Controlled";
this.#fuelBar.style.width = String(unit.getData().fuel + "%");
this.#fuelPercentage.dataset.percentage = "" + unit.getData().fuel;
this.#currentTask.dataset.currentTask = unit.getData().task !== "" ? unit.getData().task : "No task";
this.#currentTask.dataset.coalition = unit.getData().coalition;
this.#fuelBar.style.width = String(unit.getFuel() + "%");
this.#fuelPercentage.dataset.percentage = "" + unit.getFuel();
this.#currentTask.dataset.currentTask = unit.getTask() !== "" ? unit.getTask() : "No task";
this.#currentTask.dataset.coalition = unit.getCoalition();
this.#silhouette.src = `/images/units/${unit.getDatabase()?.getByName(baseData.name)?.filename}`;
this.#silhouette.classList.toggle("hide", unit.getDatabase()?.getByName(baseData.name)?.filename == undefined || unit.getDatabase()?.getByName(baseData.name)?.filename == '');
@ -75,9 +75,9 @@ export class UnitInfoPanel extends Panel {
const items = <HTMLElement>this.#loadoutContainer.querySelector("#loadout-items");
if (items) {
const ammo = Object.values(unit.getData().ammo);
const ammo = Object.values(unit.getAmmo());
if (ammo.length > 0) {
items.replaceChildren(...Object.values(unit.getData().ammo).map(
items.replaceChildren(...Object.values(unit.getAmmo()).map(
(ammo: Ammo) => {
var el = document.createElement("div");
el.dataset.qty = `${ammo.quantity}`;

View File

@ -73,7 +73,7 @@ export class Unit extends CustomMarker {
};
#ammo: Ammo[] = [];
#contacts: Contact[] = [];
#activePath: LatLng[] = [];
#activePath: LatLng[] = [];
#selectable: boolean;
#selected: boolean = false;
@ -89,6 +89,43 @@ export class Unit extends CustomMarker {
#timer: number = 0;
#hotgroup: number | null = null;
getAlive() {return this.#alive};
getHuman() {return this.#human};
getControlled() {return this.#controlled};
getCoalition() {return this.#coalition};
getCountry() {return this.#country};
getName() {return this.#name};
getUnitName() {return this.#unitName};
getGroupName() {return this.#groupName};
getState() {return this.#state};
getTask() {return this.#task};
getHasTask() {return this.#hasTask};
getPosition() {return this.#position};
getSpeed() {return this.#speed};
getHeading() {return this.#heading};
getIsTanker() {return this.#isTanker};
getIsAWACS() {return this.#isAWACS};
getOnOff() {return this.#onOff};
getFollowRoads() {return this.#followRoads};
getFuel() {return this.#fuel};
getDesiredSpeed() {return this.#desiredSpeed};
getDesiredSpeedType() {return this.#desiredSpeedType};
getDesiredAltitude() {return this.#desiredAltitude};
getDesiredAltitudeType() {return this.#desiredAltitudeType};
getLeaderID() {return this.#leaderID};
getFormationOffset() {return this.#formationOffset};
getTargetID() {return this.#targetID};
getTargetPosition() {return this.#targetPosition};
getROE() {return this.#ROE};
getReactionToThreat() {return this.#reactionToThreat};
getEmissionsCountermeasures() {return this.#emissionsCountermeasures};
getTACAN() {return this.#TACAN};
getRadio() {return this.#radio};
getGeneralSettings() {return this.#generalSettings};
getAmmo() {return this.#ammo};
getContacts() {return this.#contacts};
getActivePath() {return this.#activePath};
static getConstructor(type: string) {
if (type === "GroundUnit") return GroundUnit;
if (type === "Aircraft") return Aircraft;
@ -242,10 +279,8 @@ export class Unit extends CustomMarker {
}
}
getMarkerCategory() {
// Overloaded by child classes
// TODO convert to use getMarkerCategoryByName
return "";
getMarkerCategory(): string {
return getMarkerCategoryByName(this.getName());
}
getDatabase(): UnitDatabase | null {
@ -737,8 +772,10 @@ export class Unit extends CustomMarker {
this.#miniMapMarker.bringToBack();
}
else {
this.#miniMapMarker.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
this.#miniMapMarker.bringToBack();
if (this.#miniMapMarker.getLatLng().lat !== this.getPosition().lat && this.#miniMapMarker.getLatLng().lng !== this.getPosition().lng) {
this.#miniMapMarker.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
this.#miniMapMarker.bringToBack();
}
}
}
else {
@ -750,7 +787,9 @@ export class Unit extends CustomMarker {
/* Draw the marker */
if (!this.getHidden()) {
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
if (this.getLatLng().lat !== this.getPosition().lat && this.getLatLng().lng !== this.getPosition().lng) {
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
}
var element = this.getElement();
if (element != null) {
@ -904,7 +943,7 @@ export class Unit extends CustomMarker {
this.#drawtargetPosition(this.#targetPosition);
}
else if (this.#targetID != 0 && getUnitsManager().getUnitByID(this.#targetID)) {
const position = getUnitsManager().getUnitByID(this.#targetID)?.getData().position;
const position = getUnitsManager().getUnitByID(this.#targetID)?.getPosition();
if (position)
this.#drawtargetPosition(position);
}
@ -954,10 +993,6 @@ export class Aircraft extends AirUnit {
getCategory() {
return "Aircraft";
}
getMarkerCategory() {
return "aircraft";
}
}
export class Helicopter extends AirUnit {
@ -968,10 +1003,6 @@ export class Helicopter extends AirUnit {
getCategory() {
return "Helicopter";
}
getMarkerCategory() {
return "helicopter";
}
}
export class GroundUnit extends Unit {
@ -996,10 +1027,6 @@ export class GroundUnit extends Unit {
getCategory() {
return "GroundUnit";
}
getMarkerCategory() {
return getMarkerCategoryByName(this.getData().name);
}
}
export class NavyUnit extends Unit {
@ -1024,10 +1051,6 @@ export class NavyUnit extends Unit {
getCategory() {
return "NavyUnit";
}
getMarkerCategory() {
return "navyunit";
}
}
export class Weapon extends Unit {

View File

@ -32,7 +32,7 @@ export class UnitsManager {
getSelectableAircraft() {
const units = this.getUnits();
return Object.keys(units).reduce((acc: { [key: number]: Unit }, unitId: any) => {
if (units[unitId].getCategory() === "Aircraft" && units[unitId].getData().alive === true) {
if (units[unitId].getCategory() === "Aircraft" && units[unitId].getAlive() === true) {
acc[unitId] = units[unitId];
}
return acc;
@ -51,7 +51,7 @@ export class UnitsManager {
}
getUnitsByHotgroup(hotgroup: number) {
return Object.values(this.#units).filter((unit: Unit) => { return unit.getData().alive && unit.getHotgroup() == hotgroup });
return Object.values(this.#units).filter((unit: Unit) => { return unit.getAlive() && unit.getHotgroup() == hotgroup });
}
addUnit(ID: number, category: string) {
@ -114,7 +114,7 @@ export class UnitsManager {
this.deselectAllUnits();
for (let ID in this.#units) {
if (this.#units[ID].getHidden() == false) {
var latlng = new LatLng(this.#units[ID].getData().position.lat, this.#units[ID].getData().position.lng);
var latlng = new LatLng(this.#units[ID].getPosition().lat, this.#units[ID].getPosition().lng);
if (bounds.contains(latlng)) {
this.#units[ID].setSelected(true);
}
@ -131,11 +131,11 @@ export class UnitsManager {
}
if (options) {
if (options.excludeHumans)
selectedUnits = selectedUnits.filter((unit: Unit) => { return !unit.getData().human });
selectedUnits = selectedUnits.filter((unit: Unit) => { return !unit.getHuman() });
if (options.onlyOnePerGroup) {
var temp: Unit[] = [];
for (let unit of selectedUnits) {
if (!temp.some((otherUnit: Unit) => unit.getData().groupName == otherUnit.getData().groupName))
if (!temp.some((otherUnit: Unit) => unit.getGroupName() == otherUnit.getGroupName()))
temp.push(unit);
}
selectedUnits = temp;
@ -180,7 +180,7 @@ export class UnitsManager {
if (this.getSelectedUnits().length == 0)
return undefined;
return this.getSelectedUnits().map((unit: Unit) => {
return unit.getData().coalition
return unit.getCoalition()
})?.reduce((a: any, b: any) => {
return a == b ? a : undefined
});
@ -200,8 +200,8 @@ export class UnitsManager {
for (let idx in selectedUnits) {
const unit = selectedUnits[idx];
/* If a unit is following another unit, and that unit is also selected, send the command to the followed unit */
if (unit.getData().state === "Follow") {
const leader = this.getUnitByID(unit.getData().leaderID)
if (unit.getState() === "Follow") {
const leader = this.getUnitByID(unit.getLeaderID())
if (leader && leader.getSelected())
leader.addDestination(latlng);
else
@ -220,8 +220,8 @@ export class UnitsManager {
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
for (let idx in selectedUnits) {
const unit = selectedUnits[idx];
if (unit.getData().state === "Follow") {
const leader = this.getUnitByID(unit.getData().leaderID)
if (unit.getState() === "Follow") {
const leader = this.getUnitByID(unit.getLeaderID())
if (leader && leader.getSelected())
leader.clearDestinations();
else
@ -332,13 +332,13 @@ export class UnitsManager {
for (let idx in selectedUnits) {
selectedUnits[idx].attackUnit(ID);
}
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getData().unitName}`);
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getUnitName()}`);
}
selectedUnitsDelete(explosion: boolean = false) {
var selectedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
const selectionContainsAHuman = selectedUnits.some( ( unit:Unit ) => {
return unit.getData().human === true;
return unit.getHuman() === true;
});
if (selectionContainsAHuman && !confirm( "Your selection includes a human player. Deleting humans causes their vehicle to crash.\n\nAre you sure you want to do this?" ) ) {
@ -399,7 +399,7 @@ export class UnitsManager {
}
count++;
}
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getData().unitName}`);
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getUnitName()}`);
}
selectedUnitsSetHotgroup(hotgroup: number) {
@ -421,7 +421,7 @@ export class UnitsManager {
/* Compute the center of the group */
var center = { x: 0, y: 0 };
selectedUnits.forEach((unit: Unit) => {
var mercator = latLngToMercator(unit.getData().position.lat, unit.getData().position.lng);
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
center.x += mercator.x / selectedUnits.length;
center.y += mercator.y / selectedUnits.length;
});
@ -429,7 +429,7 @@ export class UnitsManager {
/* Compute the distances from the center of the group */
var unitDestinations: { [key: number]: LatLng } = {};
selectedUnits.forEach((unit: Unit) => {
var mercator = latLngToMercator(unit.getData().position.lat, unit.getData().position.lat);
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
var distancesFromCenter = { dx: mercator.x - center.x, dy: mercator.y - center.y };
/* Rotate the distance according to the group rotation */
@ -559,8 +559,8 @@ export class UnitsManager {
#showActionMessage(units: Unit[], message: string) {
if (units.length == 1)
getInfoPopup().setText(`${units[0].getData().unitName} ${message}`);
getInfoPopup().setText(`${units[0].getUnitName()} ${message}`);
else if (units.length > 1)
getInfoPopup().setText(`${units[0].getData().unitName} and ${units.length - 1} other units ${message}`);
getInfoPopup().setText(`${units[0].getUnitName()} and ${units.length - 1} other units ${message}`);
}
}

View File

@ -53,6 +53,7 @@ namespace DataIndex {
ammo,
contacts,
activePath,
lastIndex,
endOfData = 255
};
}
@ -94,7 +95,7 @@ public:
unsigned int getDataPacket(char*& data);
unsigned int getID() { return ID; }
void getData(stringstream& ss, unsigned long long time, bool refresh);
void getData(stringstream& ss, unsigned long long time);
Coords getActiveDestination() { return activeDestination; }
virtual void changeSpeed(string change) {};
@ -122,6 +123,9 @@ public:
void triggerUpdate(unsigned char datumIndex);
bool hasFreshData(unsigned long long time);
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
/********** Setters **********/
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }

View File

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

View File

@ -96,13 +96,11 @@ void Server::handle_get(http_request request)
time = 0;
}
}
bool refresh = (time == 0);
unsigned long long updateTime = ms.count();
stringstream ss;
ss.write((char*)&updateTime, sizeof(updateTime));
unitsManager->getUnitData(ss, time, refresh);
unitsManager->getUnitData(ss, time);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
else {

View File

@ -170,56 +170,72 @@ void Unit::updateMissionData(json::value json)
setHasTask(json[L"hasTask"].as_bool());
}
bool Unit::checkFreshness(unsigned char datumIndex, unsigned long long time) {
auto it = updateTimeMap.find(datumIndex);
if (it == updateTimeMap.end())
return false;
else
return it->second > time;
}
void Unit::getData(stringstream& ss, unsigned long long time, bool refresh)
bool Unit::hasFreshData(unsigned long long time) {
for (auto it : updateTimeMap)
if (it.second > time)
return true;
return false;
}
void Unit::getData(stringstream& ss, unsigned long long time)
{
Unit* sourceUnit = this;
Unit* leader = this;
if (unitsManager->isUnitInGroup(this) && !unitsManager->isUnitGroupLeader(this))
sourceUnit = unitsManager->getGroupLeader(this);
leader = unitsManager->getGroupLeader(this);
if (!leader->hasFreshData(time)) return;
const unsigned char endOfData = DataIndex::endOfData;
ss.write((const char*)&ID, sizeof(ID));
for (auto d : updateTimeMap) {
if (d.second > time) {
switch (d.first) {
case DataIndex::category: appendString(ss, d.first, category); break;
case DataIndex::alive: appendNumeric(ss, d.first, alive); break;
case DataIndex::human: appendNumeric(ss, d.first, sourceUnit->human); break;
case DataIndex::controlled: appendNumeric(ss, d.first, sourceUnit->controlled); break;
case DataIndex::coalition: appendNumeric(ss, d.first, sourceUnit->coalition); break;
case DataIndex::country: appendNumeric(ss, d.first, sourceUnit->country); break;
case DataIndex::name: appendString(ss, d.first, name); break;
case DataIndex::unitName: appendString(ss, d.first, unitName); break;
case DataIndex::groupName: appendString(ss, d.first, sourceUnit->groupName); break;
case DataIndex::state: appendNumeric(ss, d.first, sourceUnit->state); break;
case DataIndex::task: appendString(ss, d.first, sourceUnit->task); break;
case DataIndex::hasTask: appendNumeric(ss, d.first, sourceUnit->hasTask); break;
case DataIndex::position: appendNumeric(ss, d.first, position); break;
case DataIndex::speed: appendNumeric(ss, d.first, speed); break;
case DataIndex::heading: appendNumeric(ss, d.first, heading); break;
case DataIndex::isTanker: appendNumeric(ss, d.first, sourceUnit->isTanker); break;
case DataIndex::isAWACS: appendNumeric(ss, d.first, sourceUnit->isAWACS); break;
case DataIndex::onOff: appendNumeric(ss, d.first, sourceUnit->onOff); break;
case DataIndex::followRoads: appendNumeric(ss, d.first, sourceUnit->followRoads); break;
case DataIndex::fuel: appendNumeric(ss, d.first, fuel); break;
case DataIndex::desiredSpeed: appendNumeric(ss, d.first, sourceUnit->desiredSpeed); break;
case DataIndex::desiredSpeedType: appendNumeric(ss, d.first, sourceUnit->desiredSpeedType); break;
case DataIndex::desiredAltitude: appendNumeric(ss, d.first, sourceUnit->desiredAltitude); break;
case DataIndex::desiredAltitudeType: appendNumeric(ss, d.first, sourceUnit->desiredAltitudeType); break;
case DataIndex::leaderID: appendNumeric(ss, d.first, sourceUnit->leaderID); break;
case DataIndex::formationOffset: appendNumeric(ss, d.first, sourceUnit->formationOffset); break;
case DataIndex::targetID: appendNumeric(ss, d.first, sourceUnit->targetID); break;
case DataIndex::targetPosition: appendNumeric(ss, d.first, sourceUnit->targetPosition); break;
case DataIndex::ROE: appendNumeric(ss, d.first, sourceUnit->ROE); break;
case DataIndex::reactionToThreat: appendNumeric(ss, d.first, sourceUnit->reactionToThreat); break;
case DataIndex::emissionsCountermeasures: appendNumeric(ss, d.first, sourceUnit->emissionsCountermeasures); break;
case DataIndex::TACAN: appendNumeric(ss, d.first, sourceUnit->TACAN); break;
case DataIndex::radio: appendNumeric(ss, d.first, sourceUnit->radio); break;
case DataIndex::generalSettings: appendNumeric(ss, d.first, sourceUnit->generalSettings); break;
case DataIndex::ammo: appendVector(ss, d.first, ammo); break;
case DataIndex::contacts: appendVector(ss, d.first, contacts); break;
case DataIndex::activePath: appendList(ss, d.first, sourceUnit->activePath); break;
}
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;
}
}
ss.write((const char*)&endOfData, sizeof(endOfData));

View File

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