diff --git a/game/operation/operation.py b/game/operation/operation.py index 59822312..271a99aa 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -446,6 +446,8 @@ class Operation: "AWACs": {}, "JTACs": {}, "TargetPoints": {}, + "RedAA": {}, + "BlueAA": {}, } # type: ignore for tanker in airsupportgen.air_support.tankers: @@ -503,6 +505,26 @@ class Operation: }, } + for cp in cls.game.theater.controlpoints: + for ground_object in cp.ground_objects: + if ground_object.might_have_aa and not ground_object.is_dead: + for g in ground_object.groups: + threat_range = ground_object.threat_range(g) + + if not threat_range: + continue + + faction = "BlueAA" if cp.captured else "RedAA" + + luaData[faction][g.name] = { + "name": ground_object.name, + "range": threat_range.meters, + "position": { + "x": ground_object.position.x, + "y": ground_object.position.y, + }, + } + # set a LUA table with data from Liberation that we want to set # at the moment it contains Liberation's install path, and an overridable definition for the JTACAutoLase function # later, we'll add data about the units and points having been generated, in order to facilitate the configuration of the plugin lua scripts @@ -595,7 +617,33 @@ class Operation: -- list the aircraft carriers generated by Liberation -- dcsLiberation.Carriers = {} - -- later, we'll add more data to the table + -- list the Red AA generated by Liberation + dcsLiberation.RedAA = { + """ + for key in luaData["RedAA"]: + data = luaData["RedAA"][key] + name = data["name"] + radius = data["range"] + positionX = data["position"]["x"] + positionY = data["position"]["y"] + lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n" + lua += "}" + + lua += """ + + -- list the Blue AA generated by Liberation + dcsLiberation.BlueAA = { + """ + for key in luaData["BlueAA"]: + data = luaData["BlueAA"][key] + name = data["name"] + radius = data["range"] + positionX = data["position"]["x"] + positionY = data["position"]["y"] + lua += f" {{dcsGroupName='{key}', name='{name}', range='{radius}', positionX='{positionX}', positionY='{positionY}' }}, \n" + lua += "}" + + lua += """ """ diff --git a/resources/plugins/lotatc/LotAtcExport-config.lua b/resources/plugins/lotatc/LotAtcExport-config.lua new file mode 100644 index 00000000..494be5f1 --- /dev/null +++ b/resources/plugins/lotatc/LotAtcExport-config.lua @@ -0,0 +1,58 @@ +------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- configuration file for the LotATC Export script +-- +-- This configuration is tailored for a mission generated by DCS Liberation +-- see https://github.com/Khopa/dcs_liberation +------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- LotATC Export plugin - configuration +logger:info("DCSLiberation|LotATC Export plugin - configuration") + +local function discoverLotAtcDrawingsPath() + -- establish a search pattern into the following modes + -- 1. Environment variable LOTATC_DRAWINGS_DIR, to support server exporting with auto load from LotATC + -- 2. DCS saved games folder as configured in DCS Liberation + + local drawingEnvDir = os.getenv("LOTATC_DRAWINGS_DIR") + if drawingEnvDir then + return drawingEnvDir + else + return lfs.writedir()..[[\Mods\services\LotAtc\userdb\drawings\]] + end +end + +if dcsLiberation then + logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation") + + local exportRedAA = true + local exportBlueAA = false + local exportSymbols = true + + -- retrieve specific options values + if dcsLiberation.plugins then + logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation.plugins") + + if dcsLiberation.plugins.lotatc then + logger:info("DCSLiberation|LotATC Export plugin - dcsLiberation.plugins.lotatcExport") + + exportRedAA = dcsLiberation.plugins.lotatc.exportRedAA + logger:info(string.format("DCSLiberation|LotATC Export plugin - exportRedAA = %s",tostring(exportRedAA))) + + exportBlueAA = dcsLiberation.plugins.lotatc.exportBlueAA + logger:info(string.format("DCSLiberation|LotATC Export plugin - exportBlueAA = %s",tostring(exportBlueAA))) + + exportBlueAA = dcsLiberation.plugins.lotatc.exportSymbols + logger:info(string.format("DCSLiberation|LotATC Export plugin - exportSymbols = %s",tostring(exportSymbols))) + end + end + + -- actual configuration code + if LotAtcExportConfig then + LotAtcExportConfig.exportRedAA = exportRedAA + LotAtcExportConfig.exportBlueAA = exportBlueAA + LotAtcExportConfig.exportSymbols = exportSymbols + LotAtcExportConfig.drawingBasePath = discoverLotAtcDrawingsPath() + + LotatcExport() + end +end diff --git a/resources/plugins/lotatc/LotAtcExport.lua b/resources/plugins/lotatc/LotAtcExport.lua new file mode 100644 index 00000000..c4785243 --- /dev/null +++ b/resources/plugins/lotatc/LotAtcExport.lua @@ -0,0 +1,253 @@ +--[[ +Export script for LotATC drawings + +Allows to export certain DCS Liberation objects as predefined drawing in LotATC. + +This script runs at mission startup and generates a drawing JSON file to be imported +in LotATC. +]] + +LotAtcExportConfig = { + ["exportRedAA"] = false, + ["exportBlueAA"] = false, + ["exportSymbols"] = false, + ["exportVersion"] = "2.2.0", + ["drawingBasePath"] = nil, + ["redColor"] = "#7FE32000", + ["blueColor"] = "#7F0084FF" +} + +local function factionName(isFriend) + if isFriend then + return "BLUE" + else + return "RED" + end +end + +local function uuid() + local random = math.random + local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + return string.gsub(template, '[xy]', function (c) + local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) + return string.format('%x', v) + end) +end + +local function ends_with(str, ending) + return ending == "" or str:sub(-#ending) == ending + end + +local function combine(path1, path2) + if not ends_with(path1, "\\") then + path1 = path1 .. "\\" + end + + return path1 .. path2 +end + +local function lotatcExport_get_aa_nato_name(unit, isFriend) + if not redIADS or not blueIADS then + return nil + end + + -- logger:info(string.format("DCSLiberation|LotATC Export plugin - try get NATO name for unit %s", unit.dcsGroupName)) + + local iads = redIADS + if isFriend then + iads = blueIADS + end + + local samSite = iads:getSAMSiteByGroupName(unit.dcsGroupName) + if samSite and samSite.natoName then + -- logger:info(string.format("DCSLiberation|LotATC Export plugin - NATO name is %s", samSite.natoName)) + return samSite.natoName + else + return nil + end +end + +local function lotatcExport_get_name(unit, isFriend) + local classification = "SAM" + + if string.find(unit.dcsGroupName, "|EWR|", 1, true) then + classification = "EWR" + elseif string.find(unit.dcsGroupName, "|AA", 1, true) then + classification = "AAA" + end + + local natoName = lotatcExport_get_aa_nato_name(unit, isFriend) + + local name = nil + if not natoName then + name = string.format("%s|%s", unit.name, classification) + else + name = string.format("%s|%s|%s", unit.name, classification, natoName) + end + + return name, classification +end + +local function lotatc_write_json(filename, json) + logger:info(string.format("DCSLiberation|LotATC Export plugin - writing %s", filename)) + + local function Write() + local fp = io.open(filename, 'w') + if fp then + fp:write(json) + fp:close() + end + end + + if pcall(Write) then + else + logger:error("Unable to write LotATC export file to %s", filename) + end +end + +local function lotatcExport_threat_circles_for_faction(faction, color, isFriend) + local drawings = {} + + for _,aa in pairs(faction) do + logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting threat circle for %s", aa.dcsGroupName)) + + local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY}) + + local name = lotatcExport_get_name(aa, isFriend) + + table.insert(drawings, + { + ["author"] = "DCSLiberation", + ["brushStyle"] = 1, + ["color"] = color, + ["colorBg"] = "#00000000", + ["id"] = string.format("{%s}", uuid()), + ["longitude"] = convLon, + ["latitude"] = convLat, + ["radius"] = tonumber(aa.range), + ["lineWidth"] = 2, + ["name"] = name, + ["shared"] = true, + ["timestamp"] = "", + ["type"] = "circle", + ["text"] = name, + ["font"] = { + ["color"] = color, + ["font"] = "Lato" + } + }) + end + + local lotatcData = { + ["name"] = "Threat Circles " .. factionName(isFriend), + ["enable"] = "true", + ["version"] = LotAtcExportConfig.exportVersion, + ["drawings"] = drawings + } + + local drawings_json = json:encode(lotatcData) + return drawings_json +end + +local function lotatcExport_symbols_for_faction(faction, color, isFriend) + local drawings = {} + + for _,aa in pairs(faction) do + logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting AA symbol for %s", aa.dcsGroupName)) + + local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY}) + + local name = lotatcExport_get_name(aa, isFriend) + + local classification = "hostile" + if isFriend then + classification = "friend" + end + + local sub_dimension = "none" + + if string.find(aa.dcsGroupName, "|EWR|", 1, true) then + sub_dimension = "ew" + end + + table.insert(drawings, + { + ["author"] = "DCSLiberation", + ["brushStyle"] = 1, + ["classification"] = { + ["classification"] = classification, + ["dimension"] = "land_unit", + ["sub_dimension"] = sub_dimension + }, + ["color"] = color, + ["colorBg"] = "#33FF0000", + ["font"] = { + ["color"] = color, + ["font"] = "Lato" + }, + ["id"] = string.format("{%s}", uuid()), + ["longitude"] = convLon, + ["latitude"] = convLat, + ["lineWidth"] = 2, + ["name"] = name, + ["shared"] = true, + ["timestamp"] = "", + ["type"] = "symbol", + ["text"] = name + }) + end + + local lotatcData = { + ["name"] = "Threat Symbols " .. factionName(isFriend), + ["enable"] = "true", + ["version"] = LotAtcExportConfig.exportVersion, + ["drawings"] = drawings, + } + + local drawings_json = json:encode(lotatcData) + return drawings_json +end + +local function lotatc_export_faction(faction, color, factionPath, isFriend) + local exportBasePathFaction = combine(LotAtcExportConfig.drawingBasePath, factionPath) + lfs.mkdir(exportBasePathFaction) + + local exportFileName = combine(exportBasePathFaction, "threatZones.json") + local json = lotatcExport_threat_circles_for_faction(faction, color, isFriend) + lotatc_write_json(exportFileName, json) + + if LotAtcExportConfig.exportSymbols then + exportFileName = combine(exportBasePathFaction, "threatSymbols.json") + json = lotatcExport_symbols_for_faction(faction, color, isFriend); + lotatc_write_json(exportFileName, json) + end +end + +function LotatcExport() + + if not json then + local message = "Unable to export LotATC drawings, JSON library is not loaded!" + logger:error(message) + return + end + + if not LotAtcExportConfig.drawingBasePath then + local message = "No writable export path for LotATC drawings. Set environment variable LOTATC_DRAWINGS_DIR pointing to your export path." + logger:error(message) + return + end + + local message = "Export LotATC drawings to "..LotAtcExportConfig.drawingBasePath + logger:info(message) + + -- The RED AA is exported to the blue folder and vice versa. If a BLUE GCI connects he/she + -- wants to see the RED AA. + + if LotAtcExportConfig.exportRedAA then + lotatc_export_faction(dcsLiberation.RedAA, LotAtcExportConfig.redColor, [[blue\]], false) + end + + if LotAtcExportConfig.exportBlueAA then + lotatc_export_faction(dcsLiberation.BlueAA, LotAtcExportConfig.blueColor, [[red\]], true) + end +end diff --git a/resources/plugins/lotatc/plugin.json b/resources/plugins/lotatc/plugin.json new file mode 100644 index 00000000..13af401d --- /dev/null +++ b/resources/plugins/lotatc/plugin.json @@ -0,0 +1,33 @@ +{ + "nameInUI": "LotATC Export", + "defaultValue": false, + "specificOptions": [ + { + "nameInUI": "Export RED AA", + "mnemonic": "exportRedAA", + "defaultValue": true + }, + { + "nameInUI": "Export BLUE AA", + "mnemonic": "exportBlueAA", + "defaultValue": false + }, + { + "nameInUI": "Export AA Symbols", + "mnemonic": "exportSymbols", + "defaultValue": true + } + ], + "scriptsWorkOrders": [ + { + "file": "LotAtcExport.lua", + "mnemonic": "LotAtcExport-script" + } + ], + "configurationWorkOrders": [ + { + "file": "LotAtcExport-config.lua", + "mnemonic": "LotAtcExport-config" + } + ] +} \ No newline at end of file diff --git a/resources/plugins/plugins.json b/resources/plugins/plugins.json index f93888d5..ba5c338e 100644 --- a/resources/plugins/plugins.json +++ b/resources/plugins/plugins.json @@ -1,8 +1,9 @@ -[ - "base", - "jtacautolase", - "skynetiads", - "ewrs", - "herculescargo", - "splashdamage" -] +[ + "base", + "jtacautolase", + "skynetiads", + "ewrs", + "herculescargo", + "splashdamage", + "lotatc" +]