From 004bcce58e04bc195d3f7b8ea50d9fbb97d5aeaa Mon Sep 17 00:00:00 2001 From: RndName Date: Wed, 6 Apr 2022 12:41:52 +0200 Subject: [PATCH] Allow skynet properties override and improve dead unit handling Now the user can override special skynet properties from the unit.yaml of the main Radar of the sam site. Which unit needs these overrides can be looked up over here: https://github.com/walder/Skynet-IADS/blob/develop/skynet-iads-source/skynet-iads-supported-types.lua - fixed wrong exclusion of groups with the first unit dead but still able to participate - added some exception handling in the lua script for groups which skynet is not able to control. preventing scripting errors --- game/dcs/groundunittype.py | 43 +++++++++++++++- game/missiongenerator/luagenerator.py | 6 ++- game/server/iadsnetwork/models.py | 4 +- game/theater/iadsnetwork/iadsnetwork.py | 51 +++++++++++-------- .../plugins/skynetiads/skynetiads-config.lua | 22 ++++++++ resources/units/ground_units/Patriot str.yaml | 7 +++ 6 files changed, 109 insertions(+), 24 deletions(-) diff --git a/game/dcs/groundunittype.py b/game/dcs/groundunittype.py index 2cf94b5b..35eea894 100644 --- a/game/dcs/groundunittype.py +++ b/game/dcs/groundunittype.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging from dataclasses import dataclass from pathlib import Path -from typing import Type, Iterator +from typing import Any, Optional, Type, Iterator import yaml from dcs.unittype import VehicleType @@ -13,9 +13,47 @@ from game.data.units import UnitClass from game.dcs.unittype import UnitType +@dataclass +class SkynetProperties: + can_engage_harm: Optional[str] = None + can_engage_air_weapon: Optional[str] = None + go_live_range_in_percent: Optional[str] = None + engagement_zone: Optional[str] = None + autonomous_behaviour: Optional[str] = None + harm_detection_chance: Optional[str] = None + + @classmethod + def from_data(cls, data: dict[str, Any]) -> SkynetProperties: + props = SkynetProperties() + if "can_engage_harm" in data: + props.can_engage_harm = str(data["can_engage_harm"]).lower() + if "can_engage_air_weapon" in data: + props.can_engage_air_weapon = str(data["can_engage_air_weapon"]).lower() + if "go_live_range_in_percent" in data: + props.go_live_range_in_percent = str(data["go_live_range_in_percent"]) + if "engagement_zone" in data: + props.engagement_zone = str(data["engagement_zone"]) + if "autonomous_behaviour" in data: + props.autonomous_behaviour = str(data["autonomous_behaviour"]) + if "harm_detection_chance" in data: + props.harm_detection_chance = str(data["harm_detection_chance"]) + return props + + def to_dict(self) -> dict[str, str]: + properties: dict[str, str] = {} + for key, value in self.__dict__.items(): + if value is not None: + properties[key] = value + return properties + + def __hash__(self) -> int: + return hash(id(self)) + + @dataclass(frozen=True) class GroundUnitType(UnitType[Type[VehicleType]]): spawn_weight: int + skynet_properties: SkynetProperties @classmethod def named(cls, name: str) -> GroundUnitType: @@ -76,4 +114,7 @@ class GroundUnitType(UnitType[Type[VehicleType]]): manufacturer=data.get("manufacturer", "No data."), role=data.get("role", "No data."), price=data.get("price", 1), + skynet_properties=SkynetProperties.from_data( + data.get("skynet_properties", {}) + ), ) diff --git a/game/missiongenerator/luagenerator.py b/game/missiongenerator/luagenerator.py index cb9547b0..2eb7f324 100644 --- a/game/missiongenerator/luagenerator.py +++ b/game/missiongenerator/luagenerator.py @@ -1,5 +1,4 @@ from __future__ import annotations -from collections import defaultdict import logging import os @@ -15,6 +14,7 @@ from dcs.triggers import TriggerStart from game.ato import FlightType from game.plugins import LuaPluginManager from game.theater import TheaterGroundObject +from game.theater.iadsnetwork.iadsrole import IadsRole from game.utils import escape_string_for_lua from .aircraft.flightdata import FlightData @@ -142,6 +142,10 @@ class LuaGenerator: iads_type = coalition.get_or_create_item(node.iads_role.value) iads_element = iads_type.add_item() iads_element.add_key_value("dcsGroupName", node.dcs_name) + if node.iads_role in [IadsRole.SAM, IadsRole.SAM_AS_EWR]: + # add additional SkynetProperties to SAM Sites + for property, value in node.properties.items(): + iads_element.add_key_value(property, value) for role, connections in node.connections.items(): iads_element.add_data_array(role, connections) diff --git a/game/server/iadsnetwork/models.py b/game/server/iadsnetwork/models.py index ada32c1b..a00321ff 100644 --- a/game/server/iadsnetwork/models.py +++ b/game/server/iadsnetwork/models.py @@ -46,8 +46,8 @@ class IadsConnectionJs(BaseModel): node=tgo.id, connected=connection.ground_object.id, active=( - tgo.alive_unit_count > 0 - and connection.ground_object.alive_unit_count > 0 + network_node.group.alive_units > 0 + and connection.alive_units > 0 ), blue=tgo.is_friendly(True), is_power="power" diff --git a/game/theater/iadsnetwork/iadsnetwork.py b/game/theater/iadsnetwork/iadsnetwork.py index 4a6bcc76..8de9dc54 100644 --- a/game/theater/iadsnetwork/iadsnetwork.py +++ b/game/theater/iadsnetwork/iadsnetwork.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Iterator, Optional from uuid import UUID import uuid from game.theater.iadsnetwork.iadsrole import IadsRole - +from game.dcs.groundunittype import GroundUnitType from game.theater.theatergroundobject import ( IadsBuildingGroundObject, IadsGroundObject, @@ -31,6 +31,7 @@ class SkynetNode: dcs_name: str player: bool iads_role: IadsRole + properties: dict[str, str] = field(default_factory=dict) connections: dict[str, list[str]] = field(default_factory=lambda: defaultdict(list)) @staticmethod @@ -42,18 +43,30 @@ class SkynetNode: IadsRole.POWER_SOURCE, ]: # Use UnitName for EWR, CommandCenter, Comms, Power - return group.units[0].unit_name + for unit in group.units: + # Check for alive units in the group + if unit.alive: + return unit.unit_name + if group.units[0].is_static: + # Statics will be placed as dead unit + return group.units[0].unit_name + # If no alive unit is available and not static raise error + raise IadsNetworkException("Group has no skynet usable units") else: # Use the GroupName for SAMs, SAMAsEWR and PDs return group.group_name @classmethod def from_group(cls, group: IadsGroundGroup) -> SkynetNode: - return cls( + node = cls( cls.dcs_name_for_group(group), group.ground_object.is_friendly(True), group.iads_role, ) + unit_type = group.units[0].unit_type + if unit_type is not None and isinstance(unit_type, GroundUnitType): + node.properties = unit_type.skynet_properties.to_dict() + return node class IadsNetworkNode: @@ -102,24 +115,22 @@ class IadsNetwork: """Get all skynet nodes from the IADS Network""" skynet_nodes: list[SkynetNode] = [] for node in self.nodes: - if game.iads_considerate_culling(node.group.ground_object) or ( - node.group.units[0].is_vehicle and not node.group.units[0].alive - ): - # Skip + if game.iads_considerate_culling(node.group.ground_object): + # Skip culled ground objects + continue + try: + skynet_node = SkynetNode.from_group(node.group) + for connection in node.connections.values(): + if connection.ground_object.is_friendly( + skynet_node.player + ) and not game.iads_considerate_culling(connection.ground_object): + skynet_node.connections[connection.iads_role.value].append( + SkynetNode.dcs_name_for_group(connection) + ) + skynet_nodes.append(skynet_node) + except IadsNetworkException: + # Node not skynet compatible continue - skynet_node = SkynetNode.from_group(node.group) - for connection in node.connections.values(): - if ( - connection.ground_object.is_friendly(skynet_node.player) - and not game.iads_considerate_culling(connection.ground_object) - and not ( - connection.units[0].is_vehicle and not connection.units[0].alive - ) - ): - skynet_node.connections[connection.iads_role.value].append( - SkynetNode.dcs_name_for_group(connection) - ) - skynet_nodes.append(skynet_node) return skynet_nodes def update_tgo(self, tgo: TheaterGroundObject) -> None: diff --git a/resources/plugins/skynetiads/skynetiads-config.lua b/resources/plugins/skynetiads/skynetiads-config.lua index 38365c80..e8375f12 100644 --- a/resources/plugins/skynetiads/skynetiads-config.lua +++ b/resources/plugins/skynetiads/skynetiads-config.lua @@ -40,6 +40,28 @@ if dcsLiberation and SkynetIADS then -- actual configuration code local function initializeIADSElement(iads, iads_unit, element) + if iads_unit == nil then + -- skip processing of units which can not be handled by skynet + return + end + if element.engagement_zone then + iads_unit:setEngagementZone(element.engagement_zone) + end + if element.can_engage_harm then + iads_unit:setCanEngageHARM(element.can_engage_harm) + end + if element.harm_detection_chance then + iads_unit:setHARMDetectionChance(tonumber(element.harm_detection_chance)) + end + if element.can_engage_air_weapon then + iads_unit:setCanEngageAirWeapons(element.can_engage_air_weapon) + end + if element.go_live_range_in_percent then + iads_unit:setGoLiveRangeInPercent(tonumber(element.go_live_range_in_percent)) + end + if element.autonomous_behaviour then + iads_unit:setAutonomousBehaviour(element.autonomous_behaviour) + end if element.ConnectionNode then for i,cn in pairs(element.ConnectionNode) do env.info(string.format("DCSLiberation|Skynet-IADS plugin - adding IADS ConnectionNode %s", cn)) diff --git a/resources/units/ground_units/Patriot str.yaml b/resources/units/ground_units/Patriot str.yaml index 802ecf59..a32e05a8 100644 --- a/resources/units/ground_units/Patriot str.yaml +++ b/resources/units/ground_units/Patriot str.yaml @@ -2,3 +2,10 @@ class: SearchRadar price: 22 variants: SAM Patriot STR: null +skynet_properties: # Override skynet default properties + can_engage_harm: true + # can_engage_air_weapon: true # https://github.com/walder/Skynet-IADS/tree/develop#engage-air-weapons + go_live_range_in_percent: 100 + harm_detection_chance: 90 + engagement_zone: SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE # https://github.com/walder/Skynet-IADS/tree/develop#engagement-zone + autonomous_behaviour: SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI # https://github.com/walder/Skynet-IADS/tree/develop#autonomous-mode-behaviour