diff --git a/game/event/event.py b/game/event/event.py index d0a20d9e..6a8885be 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -100,18 +100,13 @@ class Event: for object_identifier in debriefing.destroyed_objects: for cp in self.game.theater.controlpoints: - remove_ids = [] if not cp.ground_objects: continue for i, ground_object in enumerate(cp.ground_objects): if ground_object.matches_string_identifier(object_identifier): - logging.info("cp {} removing ground object {}".format(cp, ground_object.string_identifier)) - remove_ids.append(i) - - remove_ids.reverse() - for i in remove_ids: - del cp.ground_objects[i] + logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier)) + ground_object.is_dead = True def skip(self): pass diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py index 93f33c4f..2264b33a 100644 --- a/gen/groundobjectsgen.py +++ b/gen/groundobjectsgen.py @@ -10,17 +10,6 @@ from dcs.statics import * FARP_FRONTLINE_DISTANCE = 10000 -CATEGORY_MAPPING = { - "power": [Fortification.Workshop_A], - "warehouse": [Warehouse.Warehouse], - "fuel": [Warehouse.Tank], - "ammo": [Warehouse.Ammunition_depot], - "farp": [Fortification.FARP_Tent], - "comms": [Fortification.TV_tower], - "oil": [Fortification.Oil_platform], -} - - class GroundObjectsGenerator: FARP_CAPACITY = 4 @@ -53,7 +42,10 @@ class GroundObjectsGenerator: cp = self.conflict.from_cp for ground_object in cp.ground_objects: - if ground_object.category == "defense": + if ground_object.dcs_identifier == "AA": + if ground_object.is_dead: + continue + unit_type = random.choice(self.game.commision_unit_types(cp, AirDefence)) assert unit_type is not None, "Cannot find unit type for GroundObject defense ({})!".format(cp) @@ -62,17 +54,23 @@ class GroundObjectsGenerator: name=ground_object.string_identifier, _type=unit_type, position=ground_object.position, - heading=ground_object.heading + heading=ground_object.heading, ) logging.info("generated defense object identifier {} with mission id {}".format(group.name, group.id)) else: + if ground_object.dcs_identifier in warehouse_map: + static_type = warehouse_map[ground_object.dcs_identifier] + else: + static_type = fortification_map[ground_object.dcs_identifier] + group = self.m.static_group( country=side, name=ground_object.string_identifier, - _type=random.choice(CATEGORY_MAPPING[ground_object.category]), + _type=static_type, position=ground_object.position, - heading=ground_object.heading + heading=ground_object.heading, + dead=ground_object.is_dead, ) logging.info("generated object identifier {} with mission id {}".format(group.name, group.id)) diff --git a/resources/cau_groundobjects.p b/resources/cau_groundobjects.p index d13e22c5..88a38e8f 100644 Binary files a/resources/cau_groundobjects.p and b/resources/cau_groundobjects.p differ diff --git a/resources/tools/cau_groundobjects.miz b/resources/tools/cau_groundobjects.miz index 17fde93d..cc026acc 100644 Binary files a/resources/tools/cau_groundobjects.miz and b/resources/tools/cau_groundobjects.miz differ diff --git a/resources/tools/generate_groundobjectsmap.py b/resources/tools/generate_groundobjectsmap.py index 6dc50b8e..45130ca4 100644 --- a/resources/tools/generate_groundobjectsmap.py +++ b/resources/tools/generate_groundobjectsmap.py @@ -1,86 +1,87 @@ import pickle import typing -from game import db -from gen.groundobjectsgen import TheaterGroundObject from dcs.mission import Mission from dcs.mapping import Point +from dcs.unitgroup import VehicleGroup, StaticGroup +from dcs.unit import * +from dcs.statics import warehouse_map, fortification_map + +from game import db +from gen.groundobjectsgen import TheaterGroundObject m = Mission() m.load_file("./cau_groundobjects.miz") -result = {} -result_by_groups = {} # type: typing.Dict[int, TheaterGroundObject] -cp_counters = {} -ids_counters = {} -group_id_counter = 0 -previous_group_id = None + +def parse_name(name: str) -> int: + first_part = name.split()[0].split("|") + return int(first_part[0]) if len(first_part) == 1 else int(first_part[1]) -def append_group(cp_id, category, group_id, object_id, position, heading): - global result - global result_by_groups +if __name__ == "__main__": + theater_objects = [] - ground_object = TheaterGroundObject(category, cp_id, group_id, object_id, position, heading) + for group in m.country("Russia").static_group + m.country("Russia").vehicle_group: + for unit in group.units: + theater_object = TheaterGroundObject() + theater_object.object_id = len(theater_objects) + 1 - if cp_id not in result: - result[cp_id] = [] - result[cp_id].append(ground_object) + try: + theater_object.cp_id = parse_name(str(unit.name)) + except Exception as e: + theater_object.cp_id = parse_name(str(group.name)) - result_by_groups_key = "{}_{}_{}".format(cp_id, category, group_id) - if result_by_groups_key not in result_by_groups: - result_by_groups[result_by_groups_key] = [] - result_by_groups[result_by_groups_key].append(ground_object) + theater_object.position = unit.position + theater_object.heading = unit.heading + if isinstance(unit, Vehicle): + theater_object.dcs_identifier = "AA" + else: + theater_object.dcs_identifier = unit.type -def parse_name(name: str) -> typing.Tuple: - args = str(name.split()[0]).split("|") + airport_distance = m.terrain.airport_by_id(theater_object.cp_id).position.distance_to_point(theater_object.position) + if airport_distance > 150000: + print("Object {} {} is placed {}m from airport {}!".format(theater_object.dcs_identifier, + group.name, + airport_distance, + m.terrain.airport_by_id(theater_object.cp_id))) - if len(args) == 2: - global group_id_counter - group_id_counter += 1 - args.append(str(group_id_counter)) - else: - global previous_group_id - if previous_group_id != args[2]: - group_id_counter += 1 - previous_group_id = args[2] + assert theater_object.dcs_identifier + assert theater_object.cp_id + assert theater_object.object_id - return args[0], int(args[1]), int(args[2]) + theater_objects.append(theater_object) + group_ids = 1 + for object_a in theater_objects: + for object_b in theater_objects: + if object_a.position.distance_to_point(object_b.position) < 2000: + if object_a.group_id and object_b.group_id: + continue + elif object_a.group_id: + object_b.group_id = object_a.group_id + elif object_b.group_id: + object_a.group_id = object_b.group_id + else: + object_a.group_id = group_ids + object_b.group_id = group_ids + group_ids += 1 -for group in m.country("Russia").static_group + m.country("Russia").vehicle_group: - try: - category, cp_id, group_id = parse_name(str(group.name)) - except: - print("Failed to parse {}".format(group.name)) - continue + assert object_a.cp_id == object_b.cp_id, "Object {} and {} are placed in group with different airports!".format(object_a.string_identifier, object_b.string_identifier) - ids_counters_key = "{}_{}".format(cp_id, group_id) - ids_counters[ids_counters_key] = ids_counters.get(ids_counters_key, 0) + 1 - object_id = ids_counters[ids_counters_key] - cp_counters[cp_id] = cp_counters.get(cp_id, 0) + 1 + for a in theater_objects: + if not a.group_id: + a.group_id = group_ids + group_ids += 1 - append_group(cp_id, category, group_id, object_id, group.position, group.units[0].heading) + print("Total {} objects".format(len(theater_objects))) + with open("../cau_groundobjects.p", "wb") as f: + result = {} + for theater_object in theater_objects: + if theater_object.cp_id not in result: + result[theater_object.cp_id] = [] + result[theater_object.cp_id].append(theater_object) -GROUP_TRESHOLD = 2000 -did_check_pairs = [] -for group_id, objects_in_group in result_by_groups.items(): - for a in objects_in_group: - for b in objects_in_group: - if (a, b) in did_check_pairs: - continue - - did_check_pairs.append((a, b)) - distance = a.position.distance_to_point(b.position) - if distance > GROUP_TRESHOLD: - print("Objects {} and {} in group {} are too far apart ({})!".format(a.string_identifier, b.string_identifier, group_id, distance)) - -print("Total {} objects".format(sum([len(x) for x in result.values()]))) -for cp_id, count in cp_counters.items(): - print("{} - {} objects".format(cp_id, count)) - - -with open("../cau_groundobjects.p", "wb") as f: - pickle.dump(result, f) + pickle.dump(result, f) diff --git a/theater/theatergroundobject.py b/theater/theatergroundobject.py index 3e091fa2..96557887 100644 --- a/theater/theatergroundobject.py +++ b/theater/theatergroundobject.py @@ -6,7 +6,7 @@ NAME_BY_CATEGORY = { "power": "Power plant", "ammo": "Ammo depot", "fuel": "Fuel depot", - "defense": "AA Defense Site", + "aa": "AA Defense Site", "warehouse": "Warehouse", "farp": "FARP", "comms": "Comms. tower", @@ -17,7 +17,7 @@ ABBREV_NAME = { "power": "PLANT", "ammo": "AMMO", "fuel": "FUEL", - "defense": "AA", + "aa": "AA", "warehouse": "WARE", "farp": "FARP", "comms": "COMMST", @@ -25,21 +25,35 @@ ABBREV_NAME = { } +CATEGORY_MAP = { + "aa": ["AA"], + "power": ["Workshop A"], + "warehouse": ["Warehouse"], + "fuel": ["Tank"], + "ammo": [".Ammunition depot"], + "farp": ["FARP Tent"], + "comms": ["TV tower", "Comms tower"], + "oil": ["Oil platform"], +} + + class TheaterGroundObject: - object_id = 0 cp_id = 0 group_id = 0 + object_id = 0 + + dcs_identifier = None # type: str + is_dead = False + heading = 0 position = None # type: Point - category = None # type: str - def __init__(self, category, cp_id, group_id, object_id, position, heading): - self.category = category - self.cp_id = cp_id - self.group_id = group_id - self.object_id = object_id - self.position = position - self.heading = heading + @property + def category(self) -> str: + for k, v in CATEGORY_MAP.items(): + if self.dcs_identifier in v: + return k + assert False, "Identifier not found in mapping: {}".format(self.dcs_identifier) @property def string_identifier(self): diff --git a/userdata/debriefing.py b/userdata/debriefing.py index 68006696..c3f65d55 100644 --- a/userdata/debriefing.py +++ b/userdata/debriefing.py @@ -17,6 +17,7 @@ from dcs.unit import UnitType from game import db from .persistency import base_path +from theater.theatergroundobject import CATEGORY_MAP DEBRIEFING_LOG_EXTENSION = "log" @@ -123,10 +124,9 @@ class Debriefing: for event in events.values(): event_type = event.get("type", None) if event_type in ["crash", "dead"]: - object_initiator = event["initiator"] in ["SKLAD_CRUSH", "SKLADCDESTR", "TEC_A_CRUSH", "BAK_CRUSH"] - defense_initiator = event["initiator"].startswith("defense|") + initiator_components = event["initiator"].split("|") - if object_initiator or defense_initiator: + if initiator_components[0] in CATEGORY_MAP: parse_dead_object(event) else: parse_dead_unit(event) @@ -138,7 +138,6 @@ class Debriefing: result = {} for group in groups: for unit in group.units: - unit_type = None if isinstance(unit, Vehicle): unit_type = vehicle_map[unit.type] elif isinstance(unit, Ship):