diff --git a/frontend/server/demo.js b/frontend/server/demo.js index 486eb484b..f5b437f3a 100644 --- a/frontend/server/demo.js +++ b/frontend/server/demo.js @@ -458,7 +458,7 @@ module.exports = function (configLocation) { }; mission(req, res){ - var ret = {mission: {theatre: "Nevada"}}; + var ret = {mission: {theatre: "Afghanistan"}}; ret.time = Date.now(); ret.mission.dateAndTime = { diff --git a/frontend/server/public/databases/airbases/afghanistan.json b/frontend/server/public/databases/airbases/afghanistan.json new file mode 100644 index 000000000..bfd256f8a --- /dev/null +++ b/frontend/server/public/databases/airbases/afghanistan.json @@ -0,0 +1,395 @@ +{ + "airfields": { + "Farah": { + "runways": [ + { + "headings": [ + { + "33": { + "magHeading": "328", + "Heading": "330", + "ILS": "" + } + }, + { + "15": { + "magHeading": "148", + "Heading": "150", + "ILS": "" + } + } + ], + "length": "6990" + } + ], + "TACAN": "", + "ICAO": "OAFR", + "elevation": "2240" + }, + "Kandahar": { + "runways": [ + { + "headings": [ + { + "23": { + "magHeading": "232", + "Heading": "234", + "ILS": "" + } + }, + { + "05": { + "magHeading": "052", + "Heading": "054", + "ILS": "" + } + } + ], + "length": "9779" + } + ], + "TACAN": "75X", + "ICAO": "OAKN", + "elevation": "3336" + }, + "Bost": { + "runways": [ + { + "headings": [ + { + "01": { + "magHeading": "005", + "Heading": "007", + "ILS": "" + } + }, + { + "19": { + "magHeading": "186", + "Heading": "187", + "ILS": "" + } + } + ], + "length": "5758" + } + ], + "TACAN": "", + "ICAO": "OABT", + "elevation": "2546" + }, + "Kandahar Heliport": { + "runways": [ + { + "headings": [ + { + "23": { + "magHeading": "232", + "Heading": "234", + "ILS": "" + } + }, + { + "05": { + "magHeading": "052", + "Heading": "054", + "ILS": "" + } + } + ], + "length": "718" + } + ], + "TACAN": "", + "ICAO": "", + "elevation": "3336" + }, + "Shindand Heliport": { + "runways": [ + { + "headings": [ + { + "36": { + "magHeading": "360", + "Heading": "002", + "ILS": "" + } + }, + { + "18": { + "magHeading": "181", + "Heading": "182", + "ILS": "" + } + } + ], + "length": "687" + } + ], + "TACAN": "", + "ICAO": "", + "elevation": "3798" + }, + "Camp Bastion Heliport": { + "runways": [ + { + "headings": [ + { + "01": { + "magHeading": "008", + "Heading": "010", + "ILS": "" + } + }, + { + "19": { + "magHeading": "189", + "Heading": "190", + "ILS": "" + } + } + ], + "length": "1271" + } + ], + "TACAN": "", + "ICAO": "", + "elevation": "2901" + }, + "Tarinkot": { + "runways": [ + { + "headings": [ + { + "30": { + "magHeading": "300", + "Heading": "303", + "ILS": "" + } + }, + { + "12": { + "magHeading": "121", + "Heading": "123", + "ILS": "" + + } + } + ], + "length": "5903" + } + ], + "TACAN": "", + "ICAO": "OATN", + "elevation": "4373" + }, + "Nimroz": { + "runways": [ + { + "headings": [ + { + "14": { + "magHeading": "138", + "Heading": "140", + "ILS": "" + } + }, + { + "32": { + "magHeading": "318", + "Heading": "320", + "ILS": "" + } + } + ], + "length": "6944" + } + ], + "TACAN": "", + "ICAO": "OANZ", + "elevation": "1584" + }, + "Dwyer": { + "runways": [ + { + "headings": [ + { + "05": { + "magHeading": "048", + "Heading": "050", + "ILS": "" + } + }, + { + "23": { + "magHeading": "228", + "Heading": "230", + "ILS": "" + } + } + ], + "length": "7458" + } + ], + "TACAN": "46X", + "ICAO": "OADY", + "elevation": "2398" + }, + "Herat": { + "runways": [ + { + "headings": [ + { + "18": { + "magHeading": "186", + "Heading": "188", + "ILS": "" + } + }, + { + "36": { + "magHeading": "006", + "Heading": "008", + "ILS": "" + } + } + ], + "length": "8920" + } + ], + "TACAN": "54X", + "ICAO": "OAHR", + "elevation": "3182" + }, + "Shindand": { + "runways": [ + { + "headings": [ + { + "36": { + "magHeading": "360", + "Heading": "002", + "ILS": "" + } + }, + { + "18": { + "magHeading": "180", + "Heading": "182", + "ILS": "" + } + } + ], + "length": "7032" + } + ], + "TACAN": "48X", + "ICAO": "OASD", + "elevation": "3715" + }, + "Maymana Zahiraddin Faryabi": { + "runways": [ + { + "headings": [ + { + "32": { + "magHeading": "320", + "Heading": "322", + "ILS": "" + } + }, + { + "14": { + "magHeading": "140", + "Heading": "142", + "ILS": "" + } + } + ], + "length": "5542" + } + ], + "TACAN": "", + "ICAO": "OAMN", + "elevation": "2758" + }, + "Qala i Naw": { + "runways": [ + { + "headings": [ + { + "22": { + "magHeading": "218", + "Heading": "220", + "ILS": "" + } + }, + { + "04": { + "magHeading": "038", + "Heading": "040", + "ILS": "" + } + } + ], + "length": "6114" + } + ], + "TACAN": "", + "ICAO": "OAQN", + "elevation": "2916" + }, + "Chaghcharan": { + "runways": [ + { + "headings": [ + { + "25": { + "magHeading": "243", + "Heading": "245", + "ILS": "" + } + }, + { + "07": { + "magHeading": "063", + "Heading": "65", + "ILS": "" + } + } + ], + "length": "5709" + } + ], + "TACAN": "", + "ICAO": "OACC", + "elevation": "7451" + }, + "Camp Bastion": { + "runways": [ + { + "headings": [ + { + "01": { + "magHeading": "008", + "Heading": "010", + "ILS": "" + } + }, + { + "19": { + "magHeading": "188", + "Heading": "190", + "ILS": "" + } + } + ], + "length": "10647" + } + ], + "TACAN": "98X", + "ICAO": "OAZI", + "elevation": "2886" + } + } +} \ No newline at end of file diff --git a/frontend/server/routes/api/airbases.js b/frontend/server/routes/api/airbases.js index f5144f67a..54f1c862a 100644 --- a/frontend/server/routes/api/airbases.js +++ b/frontend/server/routes/api/airbases.js @@ -17,7 +17,8 @@ const allowedTheatres = [ "sinaimap", "syria", "thechannel", - "kola" + "kola", + "afghanistan" ]; function getAirbasesData( theatreName ) { diff --git a/frontend/server/routes/api/airbases.js.bak b/frontend/server/routes/api/airbases.js.bak new file mode 100644 index 000000000..f5144f67a --- /dev/null +++ b/frontend/server/routes/api/airbases.js.bak @@ -0,0 +1,74 @@ +var express = require('express'); +var app = express(); + +var fs = require('fs'); + +const bodyParser = require('body-parser'); +app.use(bodyParser.urlencoded({ extended: false})); +app.use(bodyParser.json()); + +const allowedTheatres = [ + "caucasus", + "falklands", + "marianas", + "nevada", + "normandy", + "persiangulf", + "sinaimap", + "syria", + "thechannel", + "kola" +]; + +function getAirbasesData( theatreName ) { + if ( !isValidTheatre( theatreName ) ) { + return false; + } + + return JSON.parse( fs.readFileSync( `public/databases/airbases/${theatreName}.json` ) ).airfields +} + +function isValidTheatre( theatre ) { + return ( allowedTheatres.indexOf( theatre ) > -1 ) +} + +function sendInvalidTheatre( res ) { + res.status( 400 ).send( "Missing/invalid theatre name; must be one of:\n\t" + allowedTheatres.join( "\n\t" ) ); +} + +/**************************************************************************************************************/ +// Endpoints +/**************************************************************************************************************/ +app.get( "/", ( req, res ) => { + sendInvalidTheatre( res ); +}); + +app.get( "/:theatreName/:airbaseName", ( req, res ) => { + const airbases = getAirbasesData( req.params.theatreName ); + if ( !airbases ) { + sendInvalidTheatre( res ); + return; + } + + const airbaseName = req.params.airbaseName; + if ( !airbases.hasOwnProperty( airbaseName ) ) { + res.status( 404 ).send( `Unknown airbase name "${airbaseName}". Available options are:\n\t` + Object.keys( airbases ).join( "\n\t" ) ); + } else { + res.status( 200 ).json( airbases[ airbaseName ] ); + } +}); + + +app.get( "/:theatreName", ( req, res ) => { + const theatreName = req.params.theatreName.toLowerCase().replace( /\s*/g, "" ); + const airbases = getAirbasesData( theatreName ); + + if ( !airbases ) { + sendInvalidTheatre( res ); + return; + } + + res.status( 200 ).json( airbases ); +}); + +module.exports = app; \ No newline at end of file diff --git a/frontend/website/src/constants/constants.ts b/frontend/website/src/constants/constants.ts index d845cbe95..7d4117616 100644 --- a/frontend/website/src/constants/constants.ts +++ b/frontend/website/src/constants/constants.ts @@ -147,6 +147,13 @@ export const minimapBoundaries = { new LatLng(63.570300, 39.364000), new LatLng(71.48000, 48.091100), new LatLng(72.055300, 4.01400003) + ], + "Afghanistan": [ // Afghanistan + new LatLng(39.27472222, 59.81138889), + new LatLng(29.41166667, 60.04305556), + new LatLng(28.97722222, 73.87666667), + new LatLng(38.40055556, 75.07638889), + new LatLng(39.27472222, 59.81138889) ] }; @@ -159,7 +166,8 @@ export const mapBounds = { "Falklands": { bounds: new LatLngBounds([-49.097217, -79.418267], [-56.874517, -43.316433]), zoom: 3 }, "Normandy": { bounds: new LatLngBounds([50.44, -3.29], [48.12, 3.70]), zoom: 5 }, "SinaiMap": { bounds: new LatLngBounds([34.312222, 28.523333], [25.946944, 36.897778]), zoom: 4 }, - "Kola": { bounds: new LatLngBounds([61.59999, 4.29982], [75.05179, 44.29982]), zoom: 3} + "Kola": { bounds: new LatLngBounds([61.59999, 4.29982], [75.05179, 44.29982]), zoom: 3}, + "Afghanistan": { bounds: new LatLngBounds([29.41166667, 60.04305556], [38.40055556, 75.07638889]), zoom: 3} } export const defaultMapMirrors = {} diff --git a/frontend/website/src/constants/constants.ts.bak b/frontend/website/src/constants/constants.ts.bak new file mode 100644 index 000000000..d845cbe95 --- /dev/null +++ b/frontend/website/src/constants/constants.ts.bak @@ -0,0 +1,310 @@ +import { LatLng, LatLngBounds } from "leaflet"; +import { MapMarkerVisibilityControl } from "../map/map"; + +export const UNITS_URI = "units"; +export const WEAPONS_URI = "weapons"; +export const LOGS_URI = "logs"; +export const AIRBASES_URI = "airbases"; +export const BULLSEYE_URI = "bullseyes"; +export const MISSION_URI = "mission"; +export const COMMANDS_URI = "commands"; + +export const NONE = "None"; +export const GAME_MASTER = "Game master"; +export const BLUE_COMMANDER = "Blue commander"; +export const RED_COMMANDER = "Red commander"; + +export const VISUAL = 1; +export const OPTIC = 2; +export const RADAR = 4; +export const IRST = 8; +export const RWR = 16; +export const DLINK = 32; + +export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area", "simulate-fire-fight", "scenic-aaa", "miss-on-purpose", "land-at-point"]; +export const ROEs: string[] = ["free", "designated", "", "return", "hold"]; +export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"]; +export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"]; + +export const ERAS = [{ + "name": "Early Cold War", + "chronologicalOrder": 2 +}, { + "name": "Late Cold War", + "chronologicalOrder": 4 +}, { + "name": "Mid Cold War", + "chronologicalOrder": 3 +}, { + "name": "Modern", + "chronologicalOrder": 5 +}, { + "name": "WW2", + "chronologicalOrder": 1 +}]; + +export const ROEDescriptions: string[] = [ + "Free (Attack anyone)", + "Designated (Attack the designated target only) \nWARNING: Ground and Navy units don't respect this ROE, it will be equivalent to weapons FREE.", + "", + "Return (Only fire if fired upon) \nWARNING: Ground and Navy units don't respect this ROE, it will be equivalent to weapons FREE.", + "Hold (Never fire)" +]; + +export const reactionsToThreatDescriptions: string[] = [ + "None (No reaction)", + "Manoeuvre (no countermeasures)", + "Passive (Countermeasures only, no manoeuvre)", + "Evade (Countermeasures and manoeuvers)" +]; + +export const emissionsCountermeasuresDescriptions: string[] = [ + "Silent (Radar OFF, no ECM)", + "Attack (Radar only for targeting, ECM only if locked)", + "Defend (Radar for searching, ECM if locked)", + "Always on (Radar and ECM always on)" +]; + +export const shotsScatterDescriptions: string[] = [ + "When performing scenic shooting tasks like simulated firefights, will shoot with a large scatter", + "When performing scenic shooting tasks like simulated firefights, will shoot with a medium scatter", + "When performing scenic shooting tasks like simulated firefights, will shoot with a small scatter (Radar guided units will track shots when the enemy unit is close)" +]; + +export const shotsIntensityDescriptions: string[] = [ + "When performing scenic shooting tasks like simulated firefights, will shoot with a low rate of fire", + "When performing scenic shooting tasks like simulated firefights, will shoot with a medium rate of fire", + "When performing scenic shooting tasks like simulated firefights, will shoot with a high rate of fire" +]; + +export const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 }; +export const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 }; +export const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 }; +export const minAltitudeValues: { [key: string]: number } = { Aircraft: 0, Helicopter: 0 }; +export const maxAltitudeValues: { [key: string]: number } = { Aircraft: 50000, Helicopter: 10000 }; +export const altitudeIncrements: { [key: string]: number } = { Aircraft: 500, Helicopter: 100 }; + +export const minimapBoundaries = { + "Nevada": [ // NTTR + new LatLng(39.7982463, -119.985425), + new LatLng(34.4037128, -119.7806729), + new LatLng(34.3483316, -112.4529351), + new LatLng(39.7372411, -112.1130805), + new LatLng(39.7982463, -119.985425) + ], + "Syria": [ // Syria + new LatLng(37.3630556, 29.2686111), + new LatLng(31.8472222, 29.8975), + new LatLng(32.1358333, 42.1502778), + new LatLng(37.7177778, 42.3716667), + new LatLng(37.3630556, 29.2686111) + ], + "Caucasus": [ // Caucasus + new LatLng(39.6170191, 27.634935), + new LatLng(38.8735863, 47.1423108), + new LatLng(47.3907982, 49.3101946), + new LatLng(48.3955879, 26.7753625), + new LatLng(39.6170191, 27.634935) + ], + "PersianGulf": [ // Persian Gulf + new LatLng(32.9355285, 46.5623682), + new LatLng(21.729393, 47.572675), + new LatLng(21.8501348, 63.9734737), + new LatLng(33.131584, 64.7313594), + new LatLng(32.9355285, 46.5623682) + ], + "MarianaIslands": [ // Marianas + new LatLng(22.09, 135.0572222), + new LatLng(10.5777778, 135.7477778), + new LatLng(10.7725, 149.3918333), + new LatLng(22.5127778, 149.5427778), + new LatLng(22.09, 135.0572222) + ], + "Falklands": [ // South Atlantic + new LatLng(-49.097217, -79.418267), + new LatLng(-56.874517, -79.418267), + new LatLng(-56.874517, -43.316433), + new LatLng(-49.097217, -43.316433), + new LatLng(-49.097217, -79.418267) + ], + "Normandy": [ // Normandy + new LatLng(50.44, -3.29), + new LatLng(48.12, -3.29), + new LatLng(48.12, 3.70), + new LatLng(50.44, 3.70), + new LatLng(50.44, -3.29) + ], + "SinaiMap": [ // Sinai + new LatLng(34.312222, 28.523333), + new LatLng(25.946944, 28.523333), + new LatLng(25.946944, 36.897778), + new LatLng(34.312222, 36.897778), + new LatLng(34.312222, 28.523333) + ], + "Kola": [ // Kola + new LatLng(72.055300, 4.0140000), + new LatLng(64.421145, 10.353076), + new LatLng(63.570300, 39.364000), + new LatLng(71.48000, 48.091100), + new LatLng(72.055300, 4.01400003) + ] +}; + +export const mapBounds = { + "Syria": { bounds: new LatLngBounds([31.8472222, 29.8975], [37.7177778, 42.3716667]), zoom: 5 }, + "MarianaIslands": { bounds: new LatLngBounds([10.5777778, 135.7477778], [22.5127778, 149.5427778]), zoom: 5 }, + "Nevada": { bounds: new LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805]), zoom: 5 }, + "PersianGulf": { bounds: new LatLngBounds([21.729393, 47.572675], [33.131584, 64.7313594]), zoom: 4 }, + "Caucasus": { bounds: new LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946]), zoom: 4 }, + "Falklands": { bounds: new LatLngBounds([-49.097217, -79.418267], [-56.874517, -43.316433]), zoom: 3 }, + "Normandy": { bounds: new LatLngBounds([50.44, -3.29], [48.12, 3.70]), zoom: 5 }, + "SinaiMap": { bounds: new LatLngBounds([34.312222, 28.523333], [25.946944, 36.897778]), zoom: 4 }, + "Kola": { bounds: new LatLngBounds([61.59999, 4.29982], [75.05179, 44.29982]), zoom: 3} +} + +export const defaultMapMirrors = {} + +export const defaultMapLayers = {} + +/* Map constants */ +export const IDLE = "Idle"; +export const MOVE_UNIT = "Move unit"; +export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area"; +export const visibilityControls: string[] = ["human", "dcs", "aircraft", "helicopter", "groundunit-sam", "groundunit", "navyunit", "airbase"]; +export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["helicopter"], ["groundunit-sam"], ["groundunit"], ["navyunit"], ["airbase"]]; +export const visibilityControlsTooltips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle helicopter visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"]; + +export const MAP_MARKER_CONTROLS: MapMarkerVisibilityControl[] = [{ + "name": "Human", + "image": "visibility/human.svg", + "toggles": ["human"], + "tooltip": "Toggle human players' visibility" +}, { + "image": "visibility/olympus.svg", + "isProtected": false, + "name": "Olympus", + "protectable": false, + "toggles": ["olympus"], + "tooltip": "Toggle Olympus-controlled units' visibility" +}, { + "image": "visibility/dcs.svg", + "isProtected": true, + "name": "DCS", + "protectable": true, + "toggles": ["dcs"], + "tooltip": "Toggle DCS-controlled units' visibility" +}, { + "category": "Aircraft", + "image": "visibility/aircraft.svg", + "name": "Aircraft", + "toggles": ["aircraft"], + "tooltip": "Toggle aircraft's visibility" +}, { + "category": "Helicopter", + "image": "visibility/helicopter.svg", + "name": "Helicopter", + "toggles": ["helicopter"], + "tooltip": "Toggle helicopters' visibility" +}, { + "category": "AirDefence", + "image": "visibility/groundunit-sam.svg", + "name": "Air defence", + "toggles": ["groundunit-sam"], + "tooltip": "Toggle air defence units' visibility" +}, { + "image": "visibility/groundunit.svg", + "name": "Ground units", + "toggles": ["groundunit"], + "tooltip": "Toggle ground units' visibility" +}, { + "category": "GroundUnit", + "image": "visibility/navyunit.svg", + "name": "Naval", + "toggles": ["navyunit"], + "tooltip": "Toggle naval units' visibility" +}, { + "image": "visibility/airbase.svg", + "name": "Airbase", + "toggles": ["airbase"], + "tooltip": "Toggle airbase' visibility" +}]; + +export const IADSTypes = ["AAA", "SAM Site", "Radar (EWR)"]; +export const IADSDensities: { [key: string]: number } = { "AAA": 0.8, "SAM Site": 0.1, "Radar (EWR)": 0.05 }; +export const GROUND_UNIT_AIR_DEFENCE_REGEX: RegExp = /(\b(AAA|SAM|MANPADS?|[mM]anpads?)|[sS]tinger\b)/; +export const HIDE_GROUP_MEMBERS = "Hide group members when zoomed out"; +export const SHOW_UNIT_LABELS = "Show unit labels (L)"; +export const SHOW_UNITS_ENGAGEMENT_RINGS = "Show units threat range rings (Q)"; +export const HIDE_UNITS_SHORT_RANGE_RINGS = "Hide short range units threat range rings (R)"; +export const SHOW_UNITS_ACQUISITION_RINGS = "Show units detection range rings (E)"; +export const FILL_SELECTED_RING = "Fill the threat range rings of selected units (F)"; +export const SHOW_UNIT_CONTACTS = "Show selected units contact lines"; +export const SHOW_UNIT_PATHS = "Show selected unit paths"; +export const SHOW_UNIT_TARGETS = "Show selected unit targets"; +export const DCS_LINK_PORT = "DCS Camera link port"; +export const DCS_LINK_RATIO = "DCS Camera zoom"; + +export enum DataIndexes { + startOfData = 0, + category, + alive, + human, + controlled, + coalition, + country, + name, + unitName, + groupName, + state, + task, + hasTask, + position, + speed, + horizontalVelocity, + verticalVelocity, + heading, + track, + isActiveTanker, + isActiveAWACS, + onOff, + followRoads, + fuel, + desiredSpeed, + desiredSpeedType, + desiredAltitude, + desiredAltitudeType, + leaderID, + formationOffset, + targetID, + targetPosition, + ROE, + reactionToThreat, + emissionsCountermeasures, + TACAN, + radio, + generalSettings, + ammo, + contacts, + activePath, + isLeader, + operateAs, + shotsScatter, + shotsIntensity, + health, + endOfData = 255 +}; + +export const MGRS_PRECISION_10KM = 2; +export const MGRS_PRECISION_1KM = 3; +export const MGRS_PRECISION_100M = 4; +export const MGRS_PRECISION_10M = 5; +export const MGRS_PRECISION_1M = 6; + +export const DELETE_CYCLE_TIME = 0.05; +export const DELETE_SLOW_THRESHOLD = 50; + +export const GROUPING_ZOOM_TRANSITION = 13; + +export const MAX_SHOTS_SCATTER = 3; +export const MAX_SHOTS_INTENSITY = 3; +export const SHOTS_SCATTER_DEGREES = 10; \ No newline at end of file