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
This commit is contained in:
RndName 2022-04-06 12:41:52 +02:00
parent 4664a7bbd4
commit 004bcce58e
6 changed files with 109 additions and 24 deletions

View File

@ -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", {})
),
)

View File

@ -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)

View File

@ -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"

View File

@ -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:

View File

@ -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))

View File

@ -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