mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Splitted weapons and units managers
This commit is contained in:
2
client/src/@types/unit.d.ts
vendored
2
client/src/@types/unit.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
import { LatLng } from "leaflet"
|
||||
|
||||
interface UnitIconOptions {
|
||||
interface ObjectIconOptions {
|
||||
showState: boolean,
|
||||
showVvi: boolean,
|
||||
showHotgroup: boolean,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
import { ATC } from "./atc";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { getMissionHandler, getUnitsManager } from "..";
|
||||
import Sortable from "sortablejs";
|
||||
import { FlightInterface } from "./atc";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { Panel } from "../panels/panel";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Unit } from "../unit/unit";
|
||||
|
||||
export class UnitDataTable extends Panel {
|
||||
constructor(id: string) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ContextMenu } from "./contextmenu";
|
||||
import { Dropdown } from "./dropdown";
|
||||
import { Slider } from "./slider";
|
||||
import { Switch } from "./switch";
|
||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
||||
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
||||
|
||||
export class CoalitionAreaContextMenu extends ContextMenu {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from "..";
|
||||
import { spawnExplosion, spawnSmoke } from "../server/server";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
||||
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||
import { ContextMenu } from "./contextmenu";
|
||||
import { Dropdown } from "./dropdown";
|
||||
import { Switch } from "./switch";
|
||||
import { Slider } from "./slider";
|
||||
import { ftToM } from "../other/utils";
|
||||
import { GAME_MASTER } from "../constants/constants";
|
||||
import { navyUnitDatabase } from "../units/navyunitdatabase";
|
||||
import { navyUnitDatabase } from "../unit/navyunitdatabase";
|
||||
import { CoalitionArea } from "../map/coalitionarea";
|
||||
|
||||
export class MapContextMenu extends ContextMenu {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Map } from "./map/map"
|
||||
import { UnitsManager } from "./units/unitsmanager";
|
||||
import { UnitsManager } from "./unit/unitsmanager";
|
||||
import { UnitInfoPanel } from "./panels/unitinfopanel";
|
||||
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
|
||||
import { MissionHandler } from "./mission/missionhandler";
|
||||
@@ -18,10 +18,12 @@ import { HotgroupPanel } from "./panels/hotgrouppanel";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
|
||||
import { ServerStatusPanel } from "./panels/serverstatuspanel";
|
||||
import { WeaponsManager } from "./weapon/weaponsmanager";
|
||||
|
||||
var map: Map;
|
||||
|
||||
var unitsManager: UnitsManager;
|
||||
var weaponsManager: WeaponsManager;
|
||||
var missionHandler: MissionHandler;
|
||||
|
||||
var aic: AIC;
|
||||
@@ -48,6 +50,7 @@ function setup() {
|
||||
|
||||
/* Initialize base functionalitites */
|
||||
unitsManager = new UnitsManager();
|
||||
weaponsManager = new WeaponsManager();
|
||||
map = new Map('map-container');
|
||||
missionHandler = new MissionHandler();
|
||||
|
||||
@@ -222,6 +225,11 @@ export function getUnitsManager() {
|
||||
return unitsManager;
|
||||
}
|
||||
|
||||
export function getWeaponsManager() {
|
||||
return weaponsManager;
|
||||
}
|
||||
|
||||
|
||||
export function getMissionHandler() {
|
||||
return missionHandler;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { UnitContextMenu } from "../controls/unitcontextmenu";
|
||||
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { Airbase } from "../mission/airbase";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { bearing, createCheckboxOption } from "../other/utils";
|
||||
import { DestinationPreviewMarker } from "./destinationpreviewmarker";
|
||||
import { TemporaryUnitMarker } from "./temporaryunitmarker";
|
||||
|
||||
@@ -5,11 +5,11 @@ import { Bullseye } from "./bullseye";
|
||||
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants";
|
||||
import { setCommandModeOptions } from "../server/server";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
||||
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
||||
import { navyUnitDatabase } from "../units/navyunitdatabase";
|
||||
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||
import { navyUnitDatabase } from "../unit/navyunitdatabase";
|
||||
|
||||
export class MissionHandler {
|
||||
#bullseyes: { [name: string]: Bullseye } = {};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { LatLng, Point, Polygon } from "leaflet";
|
||||
import * as turf from "@turf/turf";
|
||||
import { UnitDatabase } from "../units/unitdatabase";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
||||
import { UnitDatabase } from "../unit/unitdatabase";
|
||||
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||
import { Buffer } from "buffer";
|
||||
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
export class HotgroupPanel extends Panel {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Icon, LatLng, Marker, Polyline } from "leaflet";
|
||||
import { getMap, getMissionHandler, getUnitsManager } from "..";
|
||||
import { distance, bearing, zeroAppend, mToNm, nmToFt } from "../other/utils";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
import formatcoords from "formatcoords";
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { SVGInjector } from "@tanem/svg-injector";
|
||||
import { getUnitsManager } from "..";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { Slider } from "../controls/slider";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { Unit } from "../units/unit";
|
||||
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
import { Switch } from "../controls/switch";
|
||||
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { Ammo } from "../@types/unit";
|
||||
import { ConvertDDToDMS, rad2deg } from "../other/utils";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { Unit } from "../units/unit";
|
||||
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
export class UnitInfoPanel extends Panel {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LatLng } from 'leaflet';
|
||||
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitDataTable, getUnitsManager, setLoginStatus } from '..';
|
||||
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..';
|
||||
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
|
||||
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
|
||||
|
||||
@@ -9,6 +9,7 @@ var paused: boolean = false;
|
||||
var REST_ADDRESS = "http://localhost:30000/olympus";
|
||||
var DEMO_ADDRESS = window.location.href + "demo";
|
||||
const UNITS_URI = "units";
|
||||
const WEAPONS_URI = "weapons";
|
||||
const LOGS_URI = "logs";
|
||||
const AIRBASES_URI = "airbases";
|
||||
const BULLSEYE_URI = "bullseyes";
|
||||
@@ -128,6 +129,10 @@ export function getUnits(callback: CallableFunction, refresh: boolean = false) {
|
||||
GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer');
|
||||
}
|
||||
|
||||
export function getWeapons(callback: CallableFunction, refresh: boolean = false) {
|
||||
GET(callback, WEAPONS_URI, { time: refresh ? 0 : lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer');
|
||||
}
|
||||
|
||||
export function addDestination(ID: number, path: any) {
|
||||
var command = { "ID": ID, "path": path }
|
||||
var data = { "setPath": command }
|
||||
@@ -383,6 +388,15 @@ export function startUpdate() {
|
||||
}
|
||||
}, 250);
|
||||
|
||||
window.setInterval(() => {
|
||||
if (!getPaused()) {
|
||||
getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
}, false);
|
||||
}
|
||||
}, 250);
|
||||
|
||||
window.setInterval(() => {
|
||||
if (!getPaused()) {
|
||||
getUnits((buffer: ArrayBuffer) => {
|
||||
@@ -394,14 +408,6 @@ export function startUpdate() {
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
export function requestUpdate() {
|
||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
||||
if (!getPaused()) {
|
||||
getUnits((buffer: ArrayBuffer) => { return getUnitsManager()?.update(buffer); }, false);
|
||||
}
|
||||
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
||||
}
|
||||
|
||||
export function checkSessionHash(newSessionHash: string) {
|
||||
if (sessionHash != null) {
|
||||
if (newSessionHash != sessionHash)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ import { SVGInjector } from '@tanem/svg-injector';
|
||||
import { UnitDatabase } from './unitdatabase';
|
||||
import { TargetMarker } from '../map/targetmarker';
|
||||
import { BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_CONTACT_LINES, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
|
||||
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, UnitIconOptions } from '../@types/unit';
|
||||
import { DataExtractor } from './dataextractor';
|
||||
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, ObjectIconOptions } from '../@types/unit';
|
||||
import { DataExtractor } from '../server/dataextractor';
|
||||
import { groundUnitDatabase } from './groundunitdatabase';
|
||||
import { navyUnitDatabase } from './navyunitdatabase';
|
||||
|
||||
@@ -135,8 +135,6 @@ export class Unit extends CustomMarker {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
if (type === "Aircraft") return Aircraft;
|
||||
if (type === "Helicopter") return Helicopter;
|
||||
if (type === "Missile") return Missile;
|
||||
if (type === "Bomb") return Bomb;
|
||||
if (type === "NavyUnit") return NavyUnit;
|
||||
}
|
||||
|
||||
@@ -297,7 +295,7 @@ export class Unit extends CustomMarker {
|
||||
return getUnitDatabaseByCategory(this.getMarkerCategory());
|
||||
}
|
||||
|
||||
getIconOptions(): UnitIconOptions {
|
||||
getIconOptions(): ObjectIconOptions {
|
||||
// Default values, overloaded by child classes if needed
|
||||
return {
|
||||
showState: false,
|
||||
@@ -976,7 +974,7 @@ export class Unit extends CustomMarker {
|
||||
if (getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) {
|
||||
for (let index in this.#contacts) {
|
||||
var contactData = this.#contacts[index];
|
||||
var contact = getUnitsManager().getUnitByID(contactData.ID)
|
||||
var contact = getUnitsManager().getUnitByID(contactData.ID);
|
||||
if (contact != null && contact.getAlive()) {
|
||||
var startLatLng = new LatLng(this.#position.lat, this.#position.lng);
|
||||
var endLatLng: LatLng;
|
||||
@@ -1149,74 +1147,3 @@ export class NavyUnit extends Unit {
|
||||
return blueprint?.type? blueprint.type: "";
|
||||
}
|
||||
}
|
||||
|
||||
export class Weapon extends Unit {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
this.setSelectable(false);
|
||||
}
|
||||
}
|
||||
|
||||
export class Missile extends Weapon {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Missile";
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||
return "missile";
|
||||
else
|
||||
return "aircraft";
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return {
|
||||
showState: false,
|
||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showHotgroup: false,
|
||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showCallsign: false,
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Bomb extends Weapon {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Bomb";
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||
return "bomb";
|
||||
else
|
||||
return "aircraft";
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return {
|
||||
showState: false,
|
||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showHotgroup: false,
|
||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showCallsign: false,
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercat
|
||||
import { CoalitionArea } from "../map/coalitionarea";
|
||||
import { groundUnitDatabase } from "./groundunitdatabase";
|
||||
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
|
||||
import { DataExtractor } from "./dataextractor";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Contact } from "../@types/unit";
|
||||
import { citiesDatabase } from "./citiesdatabase";
|
||||
import { citiesDatabase } from "./citiesDatabase";
|
||||
import { aircraftDatabase } from "./aircraftdatabase";
|
||||
import { helicopterDatabase } from "./helicopterdatabase";
|
||||
import { navyUnitDatabase } from "./navyunitdatabase";
|
||||
@@ -73,10 +73,6 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
|
||||
removeUnit(ID: number) {
|
||||
|
||||
}
|
||||
|
||||
update(buffer: ArrayBuffer) {
|
||||
var dataExtractor = new DataExtractor(buffer);
|
||||
var updateTime = Number(dataExtractor.extractUInt64());
|
||||
323
client/src/weapon/weapon.ts
Normal file
323
client/src/weapon/weapon.ts
Normal file
@@ -0,0 +1,323 @@
|
||||
import { LatLng, DivIcon, Map } from 'leaflet';
|
||||
import { getMap, getMissionHandler, getUnitsManager } from '..';
|
||||
import { enumToCoalition, mToFt, msToKnots, rad2deg } from '../other/utils';
|
||||
import { CustomMarker } from '../map/custommarker';
|
||||
import { SVGInjector } from '@tanem/svg-injector';
|
||||
import { DLINK, DataIndexes, GAME_MASTER, IRST, OPTIC, RADAR, VISUAL } from '../constants/constants';
|
||||
import { ObjectIconOptions } from '../@types/unit';
|
||||
import { DataExtractor } from '../server/dataextractor';
|
||||
|
||||
export class Weapon extends CustomMarker {
|
||||
ID: number;
|
||||
|
||||
#alive: boolean = false;
|
||||
#coalition: string = "neutral";
|
||||
#name: string = "";
|
||||
#position: LatLng = new LatLng(0, 0, 0);
|
||||
#speed: number = 0;
|
||||
#heading: number = 0;
|
||||
|
||||
#hidden: boolean = false;
|
||||
#detectionMethods: number[] = [];
|
||||
|
||||
getAlive() {return this.#alive};
|
||||
getCoalition() {return this.#coalition};
|
||||
getName() {return this.#name};
|
||||
getPosition() {return this.#position};
|
||||
getSpeed() {return this.#speed};
|
||||
getHeading() {return this.#heading};
|
||||
|
||||
static getConstructor(type: string) {
|
||||
if (type === "Missile") return Missile;
|
||||
if (type === "Bomb") return Bomb;
|
||||
}
|
||||
|
||||
constructor(ID: number) {
|
||||
super(new LatLng(0, 0), { riseOnHover: true, keyboard: false });
|
||||
|
||||
this.ID = ID;
|
||||
|
||||
/* Deselect units if they are hidden */
|
||||
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||
window.setTimeout(() => { !this.getHidden() }, 300);
|
||||
});
|
||||
|
||||
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
||||
window.setTimeout(() => { !this.getHidden() }, 300);
|
||||
});
|
||||
|
||||
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => {
|
||||
this.#updateMarker();
|
||||
});
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
// Overloaded by child classes
|
||||
return "";
|
||||
}
|
||||
|
||||
/********************** Unit data *************************/
|
||||
setData(dataExtractor: DataExtractor) {
|
||||
var updateMarker = !getMap().hasLayer(this);
|
||||
|
||||
var datumIndex = 0;
|
||||
while (datumIndex != DataIndexes.endOfData) {
|
||||
datumIndex = dataExtractor.extractUInt8();
|
||||
switch (datumIndex) {
|
||||
case DataIndexes.category: dataExtractor.extractString(); break;
|
||||
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
|
||||
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
|
||||
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
|
||||
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
|
||||
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
|
||||
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateMarker)
|
||||
this.#updateMarker();
|
||||
}
|
||||
|
||||
getData() {
|
||||
return {
|
||||
category: this.getCategory(),
|
||||
ID: this.ID,
|
||||
alive: this.#alive,
|
||||
coalition: this.#coalition,
|
||||
name: this.#name,
|
||||
position: this.#position,
|
||||
speed: this.#speed,
|
||||
heading: this.#heading
|
||||
}
|
||||
}
|
||||
|
||||
getMarkerCategory(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
getIconOptions(): ObjectIconOptions {
|
||||
// Default values, overloaded by child classes if needed
|
||||
return {
|
||||
showState: false,
|
||||
showVvi: false,
|
||||
showHotgroup: false,
|
||||
showUnitIcon: true,
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary: true,
|
||||
showCallsign: true,
|
||||
rotateToHeading: false
|
||||
}
|
||||
}
|
||||
|
||||
setAlive(newAlive: boolean) {
|
||||
this.#alive = newAlive;
|
||||
}
|
||||
|
||||
belongsToCommandedCoalition() {
|
||||
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
getType() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/********************** Icon *************************/
|
||||
createIcon(): void {
|
||||
/* Set the icon */
|
||||
var icon = new DivIcon({
|
||||
className: 'leaflet-unit-icon',
|
||||
iconAnchor: [25, 25],
|
||||
iconSize: [50, 50],
|
||||
});
|
||||
this.setIcon(icon);
|
||||
|
||||
var el = document.createElement("div");
|
||||
el.classList.add("unit");
|
||||
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
|
||||
el.setAttribute("data-coalition", this.#coalition);
|
||||
|
||||
// Generate and append elements depending on active options
|
||||
// Velocity vector
|
||||
if (this.getIconOptions().showVvi) {
|
||||
var vvi = document.createElement("div");
|
||||
vvi.classList.add("unit-vvi");
|
||||
vvi.toggleAttribute("data-rotate-to-heading");
|
||||
el.append(vvi);
|
||||
}
|
||||
|
||||
// Main icon
|
||||
if (this.getIconOptions().showUnitIcon) {
|
||||
var unitIcon = document.createElement("div");
|
||||
unitIcon.classList.add("unit-icon");
|
||||
var img = document.createElement("img");
|
||||
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
|
||||
img.onload = () => SVGInjector(img);
|
||||
unitIcon.appendChild(img);
|
||||
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
|
||||
el.append(unitIcon);
|
||||
}
|
||||
|
||||
this.getElement()?.appendChild(el);
|
||||
}
|
||||
|
||||
/********************** Visibility *************************/
|
||||
updateVisibility() {
|
||||
const hiddenUnits = getUnitsManager().getHiddenTypes();
|
||||
var hidden = (hiddenUnits.includes(this.getMarkerCategory())) ||
|
||||
(hiddenUnits.includes(this.#coalition)) ||
|
||||
(!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0);
|
||||
|
||||
this.setHidden(hidden || !this.#alive);
|
||||
}
|
||||
|
||||
setHidden(hidden: boolean) {
|
||||
this.#hidden = hidden;
|
||||
|
||||
/* Add the marker if not present */
|
||||
if (!getMap().hasLayer(this) && !this.getHidden()) {
|
||||
if (getMap().isZooming())
|
||||
this.once("zoomend", () => {this.addTo(getMap())})
|
||||
else
|
||||
this.addTo(getMap());
|
||||
}
|
||||
|
||||
/* Hide the marker if necessary*/
|
||||
if (getMap().hasLayer(this) && this.getHidden()) {
|
||||
getMap().removeLayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
return this.#hidden;
|
||||
}
|
||||
|
||||
setDetectionMethods(newDetectionMethods: number[]) {
|
||||
if (!this.belongsToCommandedCoalition()) {
|
||||
/* Check if the detection methods of this unit have changed */
|
||||
if (this.#detectionMethods.length !== newDetectionMethods.length || this.getDetectionMethods().some(value => !newDetectionMethods.includes(value))) {
|
||||
/* Force a redraw of the unit to reflect the new status of the detection methods */
|
||||
this.setHidden(true);
|
||||
this.#detectionMethods = newDetectionMethods;
|
||||
this.updateVisibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getDetectionMethods() {
|
||||
return this.#detectionMethods;
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
onAdd(map: Map): this {
|
||||
super.onAdd(map);
|
||||
/* If this is the first time adding this unit to the map, remove the temporary marker */
|
||||
getMap().removeTemporaryMarker(new LatLng(this.#position.lat, this.#position.lng));
|
||||
return this;
|
||||
}
|
||||
|
||||
#updateMarker() {
|
||||
this.updateVisibility();
|
||||
|
||||
/* Draw the marker */
|
||||
if (!this.getHidden()) {
|
||||
if (this.getLatLng().lat !== this.#position.lat || this.getLatLng().lng !== this.#position.lng) {
|
||||
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
|
||||
}
|
||||
|
||||
var element = this.getElement();
|
||||
if (element != null) {
|
||||
/* Draw the velocity vector */
|
||||
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.#speed / 5}px;`);
|
||||
|
||||
/* Set dead/alive flag */
|
||||
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
|
||||
|
||||
|
||||
/* Set altitude and speed */
|
||||
if (element.querySelector(".unit-altitude"))
|
||||
(<HTMLElement>element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(mToFt(this.#position.alt as number) / 100));
|
||||
if (element.querySelector(".unit-speed"))
|
||||
(<HTMLElement>element.querySelector(".unit-speed")).innerText = String(Math.floor(msToKnots(this.#speed))) + "GS";
|
||||
|
||||
/* Rotate elements according to heading */
|
||||
element.querySelectorAll("[data-rotate-to-heading]").forEach(el => {
|
||||
const headingDeg = rad2deg(this.#heading);
|
||||
let currentStyle = el.getAttribute("style") || "";
|
||||
el.setAttribute("style", currentStyle + `transform:rotate(${headingDeg}deg);`);
|
||||
});
|
||||
}
|
||||
|
||||
/* Set vertical offset for altitude stacking */
|
||||
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
|
||||
this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Missile extends Weapon {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Missile";
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||
return "missile";
|
||||
else
|
||||
return "aircraft";
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return {
|
||||
showState: false,
|
||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showHotgroup: false,
|
||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showCallsign: false,
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Bomb extends Weapon {
|
||||
constructor(ID: number) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Bomb";
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||
return "bomb";
|
||||
else
|
||||
return "aircraft";
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return {
|
||||
showState: false,
|
||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showHotgroup: false,
|
||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||
showCallsign: false,
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||
};
|
||||
}
|
||||
}
|
||||
84
client/src/weapon/weaponsmanager.ts
Normal file
84
client/src/weapon/weaponsmanager.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { getMissionHandler, getUnitsManager } from "..";
|
||||
import { Weapon } from "./weapon";
|
||||
import { DataIndexes, GAME_MASTER } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Contact } from "../@types/unit";
|
||||
|
||||
export class WeaponsManager {
|
||||
#weapons: { [ID: number]: Weapon };
|
||||
#requestDetectionUpdate: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.#weapons = {};
|
||||
|
||||
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#weapons).forEach((weapon: Weapon) => weapon.updateVisibility())});
|
||||
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
|
||||
}
|
||||
|
||||
getWeapons() {
|
||||
return this.#weapons;
|
||||
}
|
||||
|
||||
getWeaponByID(ID: number) {
|
||||
if (ID in this.#weapons)
|
||||
return this.#weapons[ID];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
addWeapon(ID: number, category: string) {
|
||||
if (category){
|
||||
/* The name of the weapon category is exactly the same as the constructor name */
|
||||
var constructor = Weapon.getConstructor(category);
|
||||
if (constructor != undefined) {
|
||||
this.#weapons[ID] = new constructor(ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(buffer: ArrayBuffer) {
|
||||
var dataExtractor = new DataExtractor(buffer);
|
||||
var updateTime = Number(dataExtractor.extractUInt64());
|
||||
var requestRefresh = false;
|
||||
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
|
||||
const ID = dataExtractor.extractUInt32();
|
||||
if (!(ID in this.#weapons)) {
|
||||
const datumIndex = dataExtractor.extractUInt8();
|
||||
if (datumIndex == DataIndexes.category) {
|
||||
const category = dataExtractor.extractString();
|
||||
this.addWeapon(ID, category);
|
||||
}
|
||||
else {
|
||||
requestRefresh = true;
|
||||
}
|
||||
}
|
||||
this.#weapons[ID]?.setData(dataExtractor);
|
||||
}
|
||||
|
||||
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||
for (let ID in this.#weapons) {
|
||||
var weapon = this.#weapons[ID];
|
||||
if (!weapon.belongsToCommandedCoalition())
|
||||
weapon.setDetectionMethods(this.getWeaponDetectedMethods(weapon));
|
||||
}
|
||||
this.#requestDetectionUpdate = false;
|
||||
}
|
||||
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
getWeaponDetectedMethods(weapon: Weapon) {
|
||||
var detectionMethods: number[] = [];
|
||||
var units = getUnitsManager().getUnits();
|
||||
for (let idx in units) {
|
||||
if (units[idx].getAlive() && units[idx].getIsLeader() && units[idx].getCoalition() !== "neutral" && units[idx].getCoalition() != weapon.getCoalition())
|
||||
{
|
||||
units[idx].getContacts().forEach((contact: Contact) => {
|
||||
if (contact.ID == weapon.ID && !detectionMethods.includes(contact.detectionMethod))
|
||||
detectionMethods.push(contact.detectionMethod);
|
||||
});
|
||||
}
|
||||
}
|
||||
return detectionMethods;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user