Merge branch 'v0.1.0' of https://github.com/Pax1601/DCSOlympus into v0.1.0

This commit is contained in:
PeekabooSteam
2023-03-12 16:38:51 +00:00
28 changed files with 12879 additions and 12790 deletions

View File

@@ -4,6 +4,17 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Chrome",
"port": 9222,
"urlFilter": "http://localhost:3000/*",
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/public/",
"sourceMapPathOverrides": {
"src/*": "${workspaceFolder}/src/*"
}
},
{
"type": "chrome",
"request": "launch",

View File

@@ -155,6 +155,14 @@ dl.data-grid dd.br-info[data-bearing][data-distance][data-distance-units]::after
color: var( --accent-light-blue );
}
#unit-info-panel {
bottom: 20px;
font-size:12px;
position: absolute;
left: 10px;
width: fit-content;
z-index: 1000;
}
#connection-status-panel {
bottom: 20px;

View File

@@ -533,34 +533,34 @@ nav.ol-panel> :last-child {
#unit-info-panel {
#unit-selection {
display: flex;
flex-direction: column;
}
#unit-info-panel #unit-identification {
#unit-selection #unit-identification {
align-items: center;
display: flex;
margin-bottom: 11px;
}
#unit-info-panel #unit-identification [data-object|="unit"] {
#unit-selection #unit-identification [data-object|="unit"] {
height: 28px;
margin-right: 6px;
width: 28px;
}
#unit-info-panel #unit-identification [data-object|="unit"] .unit-marker {
#unit-selection #unit-identification [data-object|="unit"] .unit-marker {
background-size: 28px 28px;
height: 28px;
width: 28px;
}
#unit-info-panel #unit-identification [data-object|="unit"] .unit-short-label {
#unit-selection #unit-identification [data-object|="unit"] .unit-short-label {
font-size: 12px;
}
#unit-info-panel #unit-identification #unit-name {
#unit-selection #unit-identification #unit-name {
background-color: transparent;
border: none;
color: white;

View File

@@ -167,9 +167,7 @@
/*** Context menu ***/
--spawn-aircraft-url: url( "/themes/olympus/images/spawn_aircraft.svg" );
--spawn-ground-url: url( "/themes/olympus/images/spawn_ground.svg" );
--spawn-smoke-url: url( "/themes/olympus/images/spawn_smoke.svg" );
}

View File

@@ -1,3 +1,16 @@
interface UpdateData {
[key: string]: any
}
interface BaseData {
AI: boolean;
name: string;
unitName: string;
groupName: string;
alive: boolean;
category: string;
}
interface FlightData {
latitude: number;
longitude: number;
@@ -36,13 +49,7 @@ interface OptionsData {
}
interface UnitData {
AI: boolean;
name: string;
unitName: string;
groupName: string;
alive: boolean;
category: string;
baseData: BaseData;
flightData: FlightData;
missionData: MissionData;
formationData: FormationData;

View File

@@ -51,7 +51,7 @@ function setup() {
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
//logPanel = new LogPanel("log-panel");
missionHandler = new MissionHandler();
missionHandler = new MissionHandler();
/* AIC */
let aicFeatureSwitch = featureSwitches.getSwitch( "aic" );

View File

@@ -1,6 +1,6 @@
import { getUnitsManager } from "..";
import { Slider } from "../controls/slider";
import { Aircraft, AirUnit, GroundUnit, Helicopter, NavyUnit, Unit } from "../units/unit";
import { Unit } from "../units/unit";
import { Panel } from "./panel";
const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"];
@@ -62,13 +62,13 @@ export class UnitControlPanel extends Panel {
}
update(units: Unit[]) {
if (this.getElement() != null)
if (this.getElement() != null && units.length > 0)
{
this.#showFlightControlSliders(units);
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit) =>
{
var button = document.createElement("button");
button.innerText = unit.getData().unitName;
button.innerText = unit.getBaseData().unitName;
button.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID, true));
return (button);
}));

View File

@@ -40,9 +40,9 @@ export class UnitInfoPanel extends Panel {
#onUnitUpdate(unit: Unit) {
if (this.getElement() != null && this.getVisible()) {
/* Set the unit info */
this.#unitName.innerText = unit.getData().unitName;
this.#groupName.innerText = unit.getData().groupName;
this.#name.innerText = unit.getData().name;
this.#unitName.innerText = unit.getBaseData().unitName;
this.#groupName.innerText = unit.getBaseData().groupName;
this.#name.innerText = unit.getBaseData().name;
this.#heading.innerText = String(Math.floor(rad2deg(unit.getFlightData().heading)) + " °");
this.#altitude.innerText = String(Math.floor(unit.getFlightData().altitude / 0.3048) + " ft");
this.#groundSpeed.innerText = String(Math.floor(unit.getFlightData().speed * 1.94384) + " kts");

View File

@@ -3,20 +3,21 @@ import { setConnected } from '..';
import { SpawnOptions } from '../controls/contextmenu';
/* Edit here to change server address */
const REST_ADDRESS = "http://localhost:3000/demo";
const REST_ADDRESS = "http://localhost:30000/olympus";
const UNITS_URI = "units";
const REFRESH_URI = "refresh";
const UPDATE_URI = "update";
const LOGS_URI = "logs";
const AIRBASES_URI = "airbases";
const BULLSEYE_URI = "bullseyes";
var lastUpdateTime = 0;
export function GET(callback: CallableFunction, uri: string){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", `${REST_ADDRESS}/${uri}`, true);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
lastUpdateTime = parseInt(data.time);
setConnected(true);
};
xmlHttp.onerror = function () {
@@ -49,7 +50,7 @@ export function getLogs(callback: CallableFunction) {
}
export function getUnits(callback: CallableFunction, refresh: boolean = false) {
GET(callback, `${UNITS_URI}/${refresh? REFRESH_URI: UPDATE_URI}`);
GET(callback, `${UNITS_URI}?time=${refresh? 0: lastUpdateTime}`);
}
export function addDestination(ID: number, path: any) {

View File

@@ -14,7 +14,48 @@ var pathIcon = new Icon({
export class Unit extends Marker {
ID: number;
#data: UnitData;
#data: UnitData = {
baseData: {
AI: false,
name: "",
unitName: "",
groupName: "",
alive: true,
category: "",
},
flightData: {
latitude: 0,
longitude: 0,
altitude: 0,
heading: 0,
speed: 0,
},
missionData: {
fuel: 0,
flags: {},
ammo: {},
targets: {},
hasTask: false,
coalition: "",
},
formationData: {
formation: "",
isLeader: false,
isWingman: false,
leaderID: 0,
wingmenIDs: [],
},
taskData: {
currentTask: "",
activePath: {},
targetSpeed: 0,
targetAltitude: 0,
},
optionsData: {
ROE: "",
reactionToThreat: "",
}
};
#selectable: boolean;
#selected: boolean = false;
@@ -37,14 +78,13 @@ export class Unit extends Marker {
if (type === "NavyUnit") return NavyUnit;
}
constructor(ID: number, data: UnitData, html: string) {
constructor(ID: number, data: UpdateData, html: string) {
super(new LatLng(0, 0), { riseOnHover: true });
this.ID = ID;
this.#selectable = true;
this.#data = data;
this.on('click', (e) => this.#onClick(e));
this.on('dblclick', (e) => this.#onDoubleClick(e));
this.on('contextmenu', (e) => this.#onContextMenu(e));
@@ -59,37 +99,69 @@ export class Unit extends Marker {
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
this.#pathPolyline.addTo(getMap());
this.#targetsPolylines = [];
this.setData(data);
}
setData(data: UnitData) {
setData(data: UpdateData) {
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
var updateMarker = false;
if (this.getFlightData().latitude != data.flightData.latitude ||
this.getFlightData().longitude != data.flightData.longitude ||
this.getData().alive != data.alive || this.#forceUpdate || !getMap().hasLayer(this))
this.getBaseData().alive != data.baseData.alive || this.#forceUpdate || !getMap().hasLayer(this))
updateMarker = true;
if (data.baseData != undefined)
{
for (let key in this.#data.baseData)
if (key in data.baseData)
//@ts-ignore
this.#data.baseData[key] = data.baseData[key];
}
this.#data.AI = data.AI;
this.#data.name = data.name;
this.#data.unitName = data.unitName;
this.#data.groupName = data.groupName;
this.#data.alive = data.alive;
this.#data.category = data.category;
if (data.flightData != undefined)
this.#data.flightData = data.flightData;
if (data.missionData != undefined)
this.#data.missionData = data.missionData;
if (data.formationData != undefined)
this.#data.formationData = data.formationData;
if (data.taskData != undefined)
this.#data.taskData = data.taskData;
if (data.optionsData != undefined)
this.#data.optionsData = data.optionsData;
{
for (let key in this.#data.flightData)
if (key in data.flightData)
//@ts-ignore
this.#data.flightData[key] = data.flightData[key];
}
if (data.missionData != undefined)
{
for (let key in this.#data.missionData)
if (key in data.missionData)
//@ts-ignore
this.#data.missionData[key] = data.missionData[key];
}
if (data.formationData != undefined)
{
for (let key in this.#data.formationData)
if (key in data.formationData)
//@ts-ignore
this.#data.formationData[key] = data.formationData[key];
}
if (data.taskData != undefined)
{
for (let key in this.#data.taskData)
if (key in data.taskData)
//@ts-ignore
this.#data.taskData[key] = data.taskData[key];
}
if (data.optionsData != undefined)
{
for (let key in this.#data.optionsData)
if (key in data.optionsData)
//@ts-ignore
this.#data.optionsData[key] = data.optionsData[key];
}
/* Dead units can't be selected */
this.setSelected(this.getSelected() && this.getData().alive)
this.setSelected(this.getSelected() && this.getBaseData().alive)
if (updateMarker)
this.#updateMarker();
@@ -107,6 +179,10 @@ export class Unit extends Marker {
return this.#data;
}
getBaseData() {
return this.getData().baseData;
}
getFlightData() {
return this.getData().flightData;
}
@@ -129,7 +205,7 @@ export class Unit extends Marker {
setSelected(selected: boolean) {
/* Only alive units can be selected. Some units are not selectable (weapons) */
if ((this.getData().alive || !selected) && this.#selectable && this.#selected != selected) {
if ((this.getBaseData().alive || !selected) && this.#selectable && this.#selected != selected) {
this.#selected = selected;
this.getElement()?.querySelector( `[data-object|="unit"]` )?.toggleAttribute( "data-is-selected" );
if (selected)
@@ -288,9 +364,7 @@ export class Unit extends Marker {
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
var element = this.getElement();
if (element != null) {
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${this.getFlightData().speed / 5}px; transform:rotate(${rad2deg(this.getFlightData().heading)}deg);`);
element.querySelector(".unit")?.setAttribute("data-fuel-level", "20");
element.querySelector(".unit")?.toggleAttribute("data-has-fox-1", true );
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.getFlightData().speed / 5}px; transform:rotate(${rad2deg(this.getFlightData().heading)}deg);`);
var unitHeadingDiv = element.querySelector(".unit-heading");
if (unitHeadingDiv != null)
@@ -390,10 +464,10 @@ export class Aircraft extends AirUnit {
<div class="unit-status"></div>
<div class="unit-vvi"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
<div class="unit-hotgroup-id"></div>
</div>
<div class="unit-marker"></div>
<div class="unit-short-label">${aircraftDatabase.getShortLabelByName(data.name)}</div>
<div class="unit-short-label">${aircraftDatabase.getShortLabelByName(data.baseData.name)}</div>
<div class="unit-fuel">
<div class="unit-fuel-level" style="width:100%;"></div>
</div>
@@ -404,7 +478,7 @@ export class Aircraft extends AirUnit {
<div class="unit-ammo-other"></div>
</div>
<div class="unit-summary">
<div class="unit-callsign">${data.unitName}</div>
<div class="unit-callsign">${data.baseData.unitName}</div>
<div class="unit-heading"></div>
<div class="unit-altitude"></div>
</div>
@@ -421,7 +495,7 @@ export class Helicopter extends AirUnit {
export class GroundUnit extends Unit {
constructor(ID: number, data: UnitData) {
var role = groundUnitsDatabase.getByName(data.name)?.loadouts[0].roles[0];
var role = groundUnitsDatabase.getByName(data.baseData.name)?.loadouts[0].roles[0];
var roleType = (role === "SAM") ? "sam" : "mi";
super(ID, data, `

View File

@@ -33,7 +33,7 @@ export class UnitsManager {
addUnit(ID: number, data: UnitData) {
/* The name of the unit category is exactly the same as the constructor name */
var constructor = Unit.getConstructor(data.category);
var constructor = Unit.getConstructor(data.baseData.category);
if (constructor != undefined) {
this.#units[ID] = new constructor(ID, data);
}

View File

@@ -27,6 +27,7 @@
<%- include('contextmenu.ejs') %>
<%- include('unitcontrolpanel.ejs') %>
<%- include('unitinfopanel.ejs') %>
<%- include('mouseinfopanel.ejs') %>
<%- include('navbar.ejs') %>
<%- include('connectionstatuspanel.ejs') %>

View File

@@ -1,6 +1,6 @@
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg">
<div id="unit-info-panel">
<div id="unit-selection">
<div id="unit-identification">
<div data-object="unit-air-aircraft">
@@ -13,36 +13,18 @@
<!-- <button id="edit-unit-name" data-on-click="editUnitName"></button> -->
</div>
<div class="ol-group">
<div id="name" class="pill highlight-primary">Name</div>
<div id="group-name" class="pill highlight-primary">Group</div>
<div id="task" class="pill highlight-primary">Task</div>
</div>
<div id="selected-units-container" class="ol-scroll">
<!-- This is where all the unit selection buttons will be shown-->
</div>
<div id="flight-data">
<h4 id="loadout-label">Flight data</h4>
<dl class="data-grid">
<dt>Heading</dt>
<dd id="heading">123&deg;</dd>
<dt>Speed</dt>
<dd id="ground-speed">323kts</dd>
<dt>Altitude</dt>
<dd id="altitude">27,414ft</dd>
</dl>
<h4>Flight controls</h4>
<div class="slider-container flight-control-slider" id="airspeed-slider">
<dl class="data-grid">
<dt>Speed</dt>
<dd class="flight-control-value" id="value">451kts</dd>
</dl>
<input type="range" min="1" max="600" value="451" class="slider">
<input type="range" min="1" max="100" value="0" class="slider">
</div>
<div class="slider-container flight-control-slider" id="altitude-slider">
@@ -50,19 +32,10 @@
<dt>Altitude</dt>
<dd class="flight-control-value" id="value">21,594ft</dd>
</dl>
<input type="range" min="1" max="50000" value="21594" class="slider">
<input type="range" min="1" max="100" value="0" class="slider">
</div>
</div>
<div id="loadout-data" class="panel-section">
<h4 id="loadout-label">Loadout<span id="loadout-fuel-level" data-fuel-level="69"></span></h4>
<div id="loadout-container" class="ol-group">
<div class="pill loadout-item" data-qty="2" data-item="AIM-120B"></div>
<div class="pill loadout-item" data-qty="2" data-item="AIM-9P"></div>
<div class="pill loadout-item" data-qty="100" data-item="AIM-120B"></div>
</div>
</div>
</div>
<!-- <h3>Formation</h3> -->

View File

@@ -0,0 +1,28 @@
<div id="unit-info-panel" class="ol-panel" >
<div class="ol-panel-board">
<div id="general" class="panel-section">
<h1 id="unit-name">Olympus 1-1</h1>
<div id="name" class="pill highlight-primary">Name</div>
<div id="group-name" class="pill highlight-primary">Group</div>
<div id="task" class="pill highlight-primary">Task</div>
</div>
<div id="flight-data" class="panel-section">
<dl class="data-grid">
<dt>Heading</dt>
<dd id="heading">123&deg;</dd>
<dt>Speed</dt>
<dd id="ground-speed">323kts</dd>
<dt>Altitude</dt>
<dd id="altitude">27,414ft</dd>
</dl>
</div>
<div id="loadout-data" class="panel-section">
<h4 id="loadout-label">Loadout<span id="loadout-fuel-level" data-fuel-level="69"></span></h4>
<div id="loadout-container" class="ol-group">
<div class="pill loadout-item" data-qty="2" data-item="AIM-120B"></div>
<div class="pill loadout-item" data-qty="2" data-item="AIM-9P"></div>
<div class="pill loadout-item" data-qty="100" data-item="AIM-120B"></div>
</div>
</div>
</div>
</div>