diff --git a/game/db.py b/game/db.py index 28369cab..51ccb197 100644 --- a/game/db.py +++ b/game/db.py @@ -2,6 +2,7 @@ import typing import enum from datetime import datetime +from dcs.countries import get_by_id, country_dict from dcs.vehicles import * from dcs.ships import * from dcs.planes import * @@ -836,6 +837,13 @@ def unitdict_from(fd: AssignedUnitsDict) -> Dict: return {k: v1 for k, (v1, v2) in fd.items()} +def country_id_from_name(name): + for k,v in country_dict.items(): + if v.name == name: + return k + return -1 + + def _validate_db(): # check unit by task uniquity total_set = set() diff --git a/game/event/event.py b/game/event/event.py index 2dfbcee7..13dc259c 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -130,44 +130,65 @@ class Event: def commit(self, debriefing: Debriefing): - for destroyed_unit_name in debriefing.dead_units_name: + logging.info("Commiting mission results") - for cp in self.game.theater.controlpoints: + # ------------------------------ + # Destroyed aircrafts + cp_map = {cp.id: cp for cp in self.game.theater.controlpoints} + for destroyed_aircraft in debriefing.killed_aircrafts: + try: + cpid = int(destroyed_aircraft.split("|")[3]) + type = db.unit_type_from_name(destroyed_aircraft.split("|")[4]) + if cpid in cp_map.keys(): + cp = cp_map[cpid] + if type in cp.base.aircraft.keys(): + logging.info("Aircraft destroyed : " + str(type)) + cp.base.aircraft[type] = max(0, cp.base.aircraft[type]-1) + except Exception as e: + print(e) - for i, ground_object in enumerate(cp.ground_objects): - if ground_object.dcs_identifier == "AA": - for g in ground_object.groups: - for u in g.units: - if u.name == destroyed_unit_name: - g.units.remove(u) - ucount = sum([len(g.units) for g in ground_object.groups]) - print(ucount) - if ucount == 0: - print("SET DEAD") - ground_object.is_dead = True + # ------------------------------ + # Destroyed ground units + cp_map = {cp.id: cp for cp in self.game.theater.controlpoints} + for killed_ground_unit in debriefing.killed_ground_units: + try: + cpid = int(killed_ground_unit.split("|")[3]) + type = db.unit_type_from_name(killed_ground_unit.split("|")[4]) + if cpid in cp_map.keys(): + cp = cp_map[cpid] + if type in cp.base.armor.keys(): + logging.info("Ground unit destroyed : " + str(type)) + cp.base.armor[type] = max(0, cp.base.armor[type] - 1) + except Exception as e: + print(e) - for country, losses in debriefing.destroyed_units.items(): - if country == self.attacker_name: - cp = self.departure_cp - else: - cp = self.to_cp - - logging.info("base {} commit losses {}".format(cp.base, losses)) - cp.base.commit_losses(losses) - - for object_identifier in debriefing.destroyed_objects: + # ------------------------------ + # Static ground objects + for destroyed_ground_unit_name in debriefing.killed_ground_units: for cp in self.game.theater.controlpoints: if not cp.ground_objects: continue + # -- Static ground objects for i, ground_object in enumerate(cp.ground_objects): if ground_object.is_dead: continue - if ground_object.matches_string_identifier(object_identifier): + if ground_object.matches_string_identifier(destroyed_ground_unit_name): logging.info("cp {} killing ground object {}".format(cp, ground_object.string_identifier)) cp.ground_objects[i].is_dead = True + # -- AA Site groups + for i, ground_object in enumerate(cp.ground_objects): + if ground_object.dcs_identifier == "AA": + for g in ground_object.groups: + for u in g.units: + if u.name == destroyed_ground_unit_name: + g.units.remove(u) + ucount = sum([len(g.units) for g in ground_object.groups]) + if ucount == 0: + ground_object.is_dead = True + def skip(self): pass diff --git a/game/event/frontlineattack.py b/game/event/frontlineattack.py index d834098a..4d4ed434 100644 --- a/game/event/frontlineattack.py +++ b/game/event/frontlineattack.py @@ -46,10 +46,12 @@ class FrontlineAttackEvent(Event): attacker_country = self.game.enemy_country defender_country = self.game.player_country - alive_attackers = sum([v for k, v in debriefing.alive_units.get(attacker_country, {}).items() if db.unit_task(k) == PinpointStrike]) - alive_defenders = sum([v for k, v in debriefing.alive_units.get(defender_country, {}).items() if db.unit_task(k) == PinpointStrike]) + # TODO : Rework + #alive_attackers = sum([v for k, v in debriefing.alive_units.get(attacker_country, {}).items() if db.unit_task(k) == PinpointStrike]) + #alive_defenders = sum([v for k, v in debriefing.alive_units.get(defender_country, {}).items() if db.unit_task(k) == PinpointStrike]) + #attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR + attackers_success = True - attackers_success = (float(alive_attackers) / (alive_defenders + 0.01)) > self.SUCCESS_FACTOR if self.from_cp.captured: return attackers_success else: diff --git a/game/operation/baseattack.py b/game/operation/baseattack.py index 739b007b..d57cb519 100644 --- a/game/operation/baseattack.py +++ b/game/operation/baseattack.py @@ -50,7 +50,6 @@ class BaseAttackOperation(Operation): def generate(self): self.armorgen.generate(self.attack, self.defense) - self.aagen.generate(self.aa) self.airgen.generate_defense(*assigned_units_split(self.intercept), at=self.defenders_starting_position) diff --git a/game/operation/infantrytransport.py b/game/operation/infantrytransport.py index b06fd009..756722b3 100644 --- a/game/operation/infantrytransport.py +++ b/game/operation/infantrytransport.py @@ -31,7 +31,6 @@ class InfantryTransportOperation(Operation): self.airgen.generate_passenger_transport(*assigned_units_split(self.transport), at=self.attackers_starting_position) self.armorgen.generate_passengers(count=6) - self.aagen.generate_at_defenders_location(self.aa) self.visualgen.generate_transportation_marker(self.conflict.ground_attackers_location) self.visualgen.generate_transportation_destination(self.conflict.position) diff --git a/game/operation/operation.py b/game/operation/operation.py index 66f736a7..717eeaff 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -1,8 +1,7 @@ from dcs.lua.parse import loads -from userdata.debriefing import * - from gen import * +from userdata.debriefing import * TANKER_CALLSIGNS = ["Texaco", "Arco", "Shell"] @@ -17,7 +16,6 @@ class Operation: conflict = None # type: Conflict armorgen = None # type: ArmorConflictGenerator airgen = None # type: AircraftConflictGenerator - aagen = None # type: AAConflictGenerator extra_aagen = None # type: ExtraAAConflictGenerator shipgen = None # type: ShipGenerator triggersgen = None # type: TriggersGenerator @@ -67,7 +65,6 @@ class Operation: self.conflict = conflict self.armorgen = ArmorConflictGenerator(mission, conflict) self.airgen = AircraftConflictGenerator(mission, conflict, self.game.settings) - self.aagen = AAConflictGenerator(mission, conflict) self.shipgen = ShipGenerator(mission, conflict) self.airsupportgen = AirSupportConflictGenerator(mission, conflict, self.game) self.triggersgen = TriggersGenerator(mission, conflict, self.game) @@ -85,8 +82,6 @@ class Operation: with open("resources/default_options.lua", "r") as f: options_dict = loads(f.read())["options"] - dcs.Mission.aaa_vehicle_group = aaa.aaa_vehicle_group - self.current_mission = dcs.Mission(terrain) if is_quick: @@ -200,7 +195,10 @@ class Operation: load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script") with open(os.path.abspath("./resources/scripts/dcs_liberation.lua")) as f: script = f.read() - script = script.replace("{{json_file_abs_location}}", "'"+os.path.abspath("./resources/scripts/json.lua"+"'")) + json_location = "[["+os.path.abspath("resources\\scripts\\json.lua")+"]]" + state_location = "[[" + os.path.abspath("state.json") + "]]" + script = script.replace("{{json_file_abs_location}}", json_location) + script = script.replace("{{debriefing_file_location}}", state_location) load_dcs_libe.add_action(DoScript(String(script))) self.current_mission.triggerrules.triggers.append(load_dcs_libe) diff --git a/gen/aaa.py b/gen/aaa.py index f3fdbdc1..d9822202 100644 --- a/gen/aaa.py +++ b/gen/aaa.py @@ -1,441 +1,17 @@ -import random -import math from .conflictgen import * from .naming import * from dcs.mission import * +from dcs.mission import * + +from .conflictgen import * +from .naming import * DISTANCE_FACTOR = 0.5, 1 EXTRA_AA_MIN_DISTANCE = 50000 EXTRA_AA_MAX_DISTANCE = 150000 EXTRA_AA_POSITION_FROM_CP = 550 - -def num_sam_dead(sam_type, destroyed_count): - """ - Given a type and count of SAM units, determine if enough units were destroyed to warrant the - loss of a site - :param sam_type: - inidivudal unit name in SAM site which was destroyed - :param destroyed_count: - count of that unit type which was destroyed *in the sortie* - :return: - INT: number of sites lost - """ - sam_threshold = { - AirDefence.SAM_SR_P_19: 1, - AirDefence.SAM_SA_3_S_125_TR_SNR: 1, - AirDefence.SAM_SA_6_Kub_STR_9S91: 1, - AirDefence.SAM_SA_10_S_300PS_SR_5N66M: 1, - AirDefence.SAM_SA_10_S_300PS_TR_30N6: 1, - AirDefence.SAM_SA_10_S_300PS_CP_54K6: 1, - AirDefence.SAM_SA_10_S_300PS_SR_64H6E: 1, - AirDefence.SAM_SA_3_S_125_LN_5P73: 4, - AirDefence.SAM_SA_6_Kub_LN_2P25: 6, - AirDefence.SAM_SA_10_S_300PS_LN_5P85C: 8, - AirDefence.SAM_SA_2_LN_SM_90:4, - AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song: 1, - AirDefence.SAM_Hawk_PCP: 1, - AirDefence.SAM_Hawk_LN_M192: 4, - AirDefence.SAM_Hawk_SR_AN_MPQ_50: 1, - AirDefence.SAM_Hawk_TR_AN_MPQ_46: 1 - } - - return int(destroyed_count / sam_threshold[sam_type]) - - -def determine_positions(position, heading, num_units, launcher_distance, coverage=90): - """ - Given a position on the map, array a group of units in a circle a uniform distance from the unit - :param position: - position of the center unit - :param heading: - the direction the units should be arranged toward if coverage is not 360 - :param num_units: - number of units to play on the circle - :param launcher_distance: - distance the units should be from the center unit - :param coverage: - 0-360 - :return: - list of tuples representing each unit location - [(pos_x, pos_y, heading), ...] - """ - if coverage == 360: - # one of the positions is shared :'( - outer_offset = coverage / num_units - else: - outer_offset = coverage / (num_units - 1) - - positions = [] - - if num_units % 2 == 0: - current_offset = heading - ((coverage / (num_units - 1)) / 2) - else: - current_offset = heading - current_offset -= outer_offset * (math.ceil(num_units / 2) - 1) - for x in range(1, num_units + 1): - positions.append(( - position.x + launcher_distance * math.cos(math.radians(current_offset)), - position.y + launcher_distance * math.sin(math.radians(current_offset)), - current_offset, - )) - current_offset += outer_offset - return positions - - -def aaa_vehicle_group(self, country, name, _type: unittype.VehicleType, position: mapping.Point, - heading=0, group_size=1, - formation=unitgroup.VehicleGroup.Formation.Line, - move_formation: PointAction=PointAction.OffRoad): - """ - Override the default vehicle group so that our group can contain a mix of units (which is required for advanced - SAM sites) - For further docstrings, see the built-in function - """ - vg = unitgroup.VehicleGroup(self.next_group_id(), self.string(name)) - - for i in range(1, group_size + 1): - heading = randint(0, 359) - if _type == AirDefence.SAM_SA_3_S_125_LN_5P73: - # 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR - num_launchers = 4 - # search radar - v = self.vehicle( - name + " Unit #{nr}-sr".format(nr=i), - AirDefence.SAM_SR_P_19, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - # track radar - v = self.vehicle( - name + " Unit #{nr}-tr".format(nr=i), - AirDefence.SAM_SA_3_S_125_TR_SNR, - ) - - center_x = position.x + randint(20, 40) - center_y = position.y + (i - 1) * 20 - - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - plop_positions = determine_positions( - position, - heading, - num_launchers, - launcher_distance=100, - coverage=180, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_SA_3_S_125_LN_5P73, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - - elif _type == AirDefence.SAM_SA_6_Kub_LN_2P25: - # 6 launchers (360 degree coverage) - # 1 S/TR - # search/track radar - num_launchers = 6 - v = self.vehicle( - name + " Unit #{nr}-str".format(nr=i), - AirDefence.SAM_SA_6_Kub_STR_9S91, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - - plop_positions = determine_positions( - position, - heading, - num_launchers, - launcher_distance=100, - coverage=360, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_SA_6_Kub_LN_2P25, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - elif _type == AirDefence.SAM_SA_10_S_300PS_LN_5P85C: - # 8 launchers - 4 directions, two in each direction - # 1 SR (offset) - # 1 TR (center) - # search radar - num_launchers = 8 - v = self.vehicle( - name + " Unit #{nr}-sr".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_SR_5N66M, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - # track radar - v = self.vehicle( - name + " Unit #{nr}-tr".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_TR_30N6, - ) - - center_x = position.x + randint(20, 40) - center_y = position.y + (i - 1) * 20 - - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - # command center - v = self.vehicle( - name + " Unit #{nr}-c".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_CP_54K6, - ) - - center_x = position.x + randint(40, 60) - center_y = position.y + (i - 1) * 20 - - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - plop_positions = determine_positions( - position, - heading, - num_launchers, - launcher_distance=150, - coverage=360, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_SA_10_S_300PS_LN_5P85C, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - - elif _type == AirDefence.SAM_SA_10_S_300PS_CP_54K6: - # 8 launchers - 4 directions, two in each direction - # 1 SR (offset) - # 1 TR (center) - # search radar - num_launchers = 8 - v = self.vehicle( - name + " Unit #{nr}-sr".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_SR_64H6E, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - # track radar - v = self.vehicle( - name + " Unit #{nr}-tr".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_TR_30N6, - ) - - center_x = position.x + randint(20, 40) - center_y = position.y + (i - 1) * 20 - - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - # command center - v = self.vehicle( - name + " Unit #{nr}-c".format(nr=i), - AirDefence.SAM_SA_10_S_300PS_CP_54K6, - ) - - center_x = position.x + randint(40, 60) - center_y = position.y + (i - 1) * 20 - - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - plop_positions = determine_positions( - position, - heading, - num_units=num_launchers, - launcher_distance=150, - coverage=360, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_SA_10_S_300PS_LN_5P85D, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - elif _type == AirDefence.SAM_Hawk_PCP: - # 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR, 1 PCP - num_launchers = 4 - - # search radar - v = self.vehicle( - name + " Unit #{nr}-sr".format(nr=i), - AirDefence.SAM_Hawk_SR_AN_MPQ_50, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - - - # track radar - v = self.vehicle( - name + " Unit #{nr}-tr".format(nr=i), - AirDefence.SAM_Hawk_TR_AN_MPQ_46, - ) - center_x = position.x + randint(20, 40) - center_y = position.y + (i - 1) * 20 - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - # PCP - v = self.vehicle( - name + " Unit #{nr}-pcp".format(nr=i), - AirDefence.SAM_Hawk_PCP, - ) - - center_x = position.x + randint(60, 80) - center_y = position.y + 20 - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - plop_positions = determine_positions( - position, - heading, - num_launchers, - launcher_distance=100, - coverage=180, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_Hawk_LN_M192, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - elif _type == AirDefence.SAM_SA_2_LN_SM_90: - # 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR - num_launchers = 4 - - # search radar - v = self.vehicle( - name + " Unit #{nr}-sr".format(nr=i), - AirDefence.SAM_SR_P_19, - ) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - - - # track radar - v = self.vehicle( - name + " Unit #{nr}-tr".format(nr=i), - AirDefence.SAM_SA_2_TR_SNR_75_Fan_Song, - ) - center_x = position.x + randint(20, 40) - center_y = position.y + (i - 1) * 20 - v.position.x = center_x - v.position.y = center_y - v.heading = heading - vg.add_unit(v) - - plop_positions = determine_positions( - position, - heading, - num_launchers, - launcher_distance=100, - coverage=180, - ) - for x in range(0, num_launchers): - v = self.vehicle( - name + " Unit #{nr}-{x}".format(nr=i, x=x), - AirDefence.SAM_SA_2_LN_SM_90, - ) - - v.position.x = plop_positions[x][0] - v.position.y = plop_positions[x][1] - v.heading = plop_positions[x][2] - vg.add_unit(v) - else: - v = self.vehicle(name + " Unit #{nr}-sam".format(nr=i), _type) - v.position.x = position.x - v.position.y = position.y + (i - 1) * 20 - v.heading = heading - vg.add_unit(v) - - wp = vg.add_waypoint(vg.units[0].position, move_formation, 0) - wp.ETA_locked = True - if _type.eplrs: - wp.tasks.append(task.EPLRS(self.next_eplrs("vehicle"))) - - country.add_vehicle_group(vg) - return vg - - -class AAConflictGenerator: - def __init__(self, mission: Mission, conflict: Conflict): - self.m = mission - self.conflict = conflict - - def generate_at_defenders_location(self, units: db.AirDefenseDict): - for unit_type, count in units.items(): - for _ in range(count): - self.m.vehicle_group( - country=self.conflict.defenders_country, - name=namegen.next_unit_name(self.conflict.defenders_country, unit_type), - _type=unit_type, - position=self.conflict.ground_defenders_location.random_point_within(100, 100), - group_size=1) - - def generate(self, units: db.AirDefenseDict): - for type, count in units.items(): - for _, radial in zip(range(count), self.conflict.radials): - distance = randint(self.conflict.size * DISTANCE_FACTOR[0] + 9000, self.conflict.size * DISTANCE_FACTOR[1] + 14000) - p = self.conflict.position.point_from_heading(random.choice(self.conflict.radials), distance) - - self.m.aaa_vehicle_group( - country=self.conflict.defenders_country, - name=namegen.next_unit_name(self.conflict.defenders_country, type), - _type=type, - position=p, - group_size=1) - - class ExtraAAConflictGenerator: def __init__(self, mission: Mission, conflict: Conflict, game, player_country: Country, enemy_country: Country): self.mission = mission @@ -445,7 +21,6 @@ class ExtraAAConflictGenerator: self.enemy_country = enemy_country def generate(self): - from theater.conflicttheater import ControlPoint for cp in self.game.theater.controlpoints: if cp.is_global: diff --git a/gen/aircraft.py b/gen/aircraft.py index af7cb074..8e2e1687 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -242,11 +242,11 @@ class AircraftConflictGenerator: else: assert False - def _generate_escort(self, side: Country, units: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition, is_quick=False, should_orbit=False): + def _generate_escort(self, side: Country, units: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition, cp, is_quick=False, should_orbit=False): groups = [] for flying_type, count, client_count in self._split_to_groups(units, clients): group = self._generate_group( - name=namegen.next_unit_name(side, flying_type), + name=namegen.next_unit_name(side, cp.id, flying_type), side=side, unit_type=flying_type, count=count, @@ -279,7 +279,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(attackers, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -313,7 +313,7 @@ class AircraftConflictGenerator: try: group = self._generate_at_airport( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -322,7 +322,7 @@ class AircraftConflictGenerator: start_type=StartType.Runway) except Exception: group = self._generate_group( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -360,7 +360,7 @@ class AircraftConflictGenerator: try: group = self._generate_at_airport( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -369,7 +369,7 @@ class AircraftConflictGenerator: start_type=StartType.Runway) except Exception: group = self._generate_group( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -413,7 +413,7 @@ class AircraftConflictGenerator: try: group = self._generate_at_airport( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -422,7 +422,7 @@ class AircraftConflictGenerator: start_type=StartType.Runway) except Exception: group = self._generate_group( - name=namegen.next_unit_name(country, type), + name=namegen.next_unit_name(country, cp.id, type), side=country, unit_type=type, count=number, @@ -450,7 +450,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -476,7 +476,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -502,7 +502,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(defenders, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.defenders_country, self.conflict.to_cp.id, flying_type), side=self.conflict.defenders_country, unit_type=flying_type, count=count, @@ -528,7 +528,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(attackers, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -552,6 +552,7 @@ class AircraftConflictGenerator: clients=clients, at=at and at or self._group_point(self.conflict.air_attackers_location), is_quick=at is None, + cp=self.conflict.from_cp, should_orbit=True): self._rtb_for(g, self.conflict.from_cp, at) @@ -562,13 +563,14 @@ class AircraftConflictGenerator: clients=clients, at=at and at or self._group_point(self.conflict.air_defenders_location), is_quick=at is None, + cp=self.conflict.to_cp, should_orbit=False): self._rtb_for(g, self.conflict.to_cp, at) def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): for flying_type, count, client_count in self._split_to_groups(defenders, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.to_cp.id, flying_type), side=self.conflict.defenders_country, unit_type=flying_type, count=count, @@ -585,7 +587,7 @@ class AircraftConflictGenerator: def generate_migcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): for flying_type, count, client_count in self._split_to_groups(patrol, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -603,7 +605,7 @@ class AircraftConflictGenerator: def generate_barcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): for flying_type, count, client_count in self._split_to_groups(patrol, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.defenders_country, unit_type=flying_type, count=count, @@ -629,7 +631,7 @@ class AircraftConflictGenerator: for flying_type, count, client_count in self._split_to_groups(transport): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.defenders_country, unit_type=flying_type, count=count, @@ -647,7 +649,7 @@ class AircraftConflictGenerator: def generate_interception(self, interceptors: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): for flying_type, count, client_count in self._split_to_groups(interceptors, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, flying_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), side=self.conflict.attackers_country, unit_type=flying_type, count=count, @@ -669,7 +671,7 @@ class AircraftConflictGenerator: def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition): for heli_type, count, client_count in self._split_to_groups(helis, clients): group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, heli_type), + name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, heli_type), side=self.conflict.attackers_country, unit_type=heli_type, count=count, diff --git a/gen/armor.py b/gen/armor.py index 2c5f89a2..18dfd90f 100644 --- a/gen/armor.py +++ b/gen/armor.py @@ -37,11 +37,17 @@ class ArmorConflictGenerator: return point.random_point_within(distance, self.conflict.size * SPREAD_DISTANCE_SIZE_FACTOR) def _generate_group(self, side: Country, unit: VehicleType, count: int, at: Point, to: Point = None, move_formation: PointAction = PointAction.OffRoad): + + if side == self.conflict.attackers_country: + cp = self.conflict.from_cp + else: + cp = self.conflict.to_cp + for c in range(count): logging.info("armorgen: {} for {}".format(unit, side.id)) group = self.m.vehicle_group( side, - namegen.next_unit_name(side, unit), + namegen.next_unit_name(side, cp.id, unit), unit, position=self._group_point(at), group_size=1, diff --git a/gen/naming.py b/gen/naming.py index f769dfb3..0a0cffcb 100644 --- a/gen/naming.py +++ b/gen/naming.py @@ -4,9 +4,9 @@ from game import db class NameGenerator: number = 0 - def next_unit_name(self, country, unit_type): + def next_unit_name(self, country, parent_base_id, unit_type): self.number += 1 - return "unit|{}|{}|{}|".format(country.id, self.number, db.unit_type_name(unit_type)) + return "unit|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type)) def next_basedefense_name(self): return "basedefense_aa|0|0|" diff --git a/qt_ui/main.py b/qt_ui/main.py index aea16c66..36e53797 100644 --- a/qt_ui/main.py +++ b/qt_ui/main.py @@ -47,12 +47,6 @@ if __name__ == "__main__": copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua") app.processEvents() - # Create DCS Liberation script folder - script_dir = installation.get_dcs_saved_games_directory() + os.sep + "Scripts" + os.sep + "DCSLiberation" - if not os.path.exists(script_dir): - os.makedirs(script_dir) - copyfile("./resources/scripts/json.lua", script_dir + os.path.sep + "json.lua") - # Apply CSS (need works) app.setStyleSheet(css) GameUpdateSignal() diff --git a/qt_ui/widgets/QDebriefingInformation.py b/qt_ui/widgets/QDebriefingInformation.py new file mode 100644 index 00000000..abf6caea --- /dev/null +++ b/qt_ui/widgets/QDebriefingInformation.py @@ -0,0 +1,11 @@ +from PySide2.QtWidgets import QFrame + + +class QDebriefingInformation(QFrame): + """ + UI component to display debreifing informations + """ + + def __init__(self): + super(QDebriefingInformation, self).__init__() + self.init_ui() \ No newline at end of file diff --git a/qt_ui/windows/QDebriefingWindow.py b/qt_ui/windows/QDebriefingWindow.py index 1f2161f5..5896d71c 100644 --- a/qt_ui/windows/QDebriefingWindow.py +++ b/qt_ui/windows/QDebriefingWindow.py @@ -19,9 +19,6 @@ class QDebriefingWindow(QDialog): self.gameEvent = gameEvent self.debriefing = debriefing - self.player_losses = debriefing.destroyed_units.get(self.game.player_country, {}) - self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy_country, {}) - self.initUI() def initUI(self): @@ -44,7 +41,12 @@ class QDebriefingWindow(QDialog): lostUnits.setLayout(lostUnitsLayout) row = 0 - for unit_type, count in self.player_losses.items(): + for unit_type, count in self.debriefing.player_dead_aircraft_dict.items(): + lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0) + lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1) + row += 1 + + for unit_type, count in self.debriefing.player_dead_units_dict.items(): lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0) lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1) row += 1 @@ -56,13 +58,20 @@ class QDebriefingWindow(QDialog): enemylostUnitsLayout = QGridLayout() enemylostUnits.setLayout(enemylostUnitsLayout) - row = 0 - if self.debriefing.destroyed_objects: - enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0) - enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1) + #row = 0 + #if self.debriefing.destroyed_objects: + # enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0) + # enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1) + # row += 1 + + for unit_type, count in self.debriefing.enemy_dead_aircraft_dict.items(): + if count == 0: + continue + enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0) + enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1) row += 1 - for unit_type, count in self.enemy_losses.items(): + for unit_type, count in self.debriefing.enemy_dead_units_dict.items(): if count == 0: continue enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0) diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py index c9ebb14b..4af0c9c3 100644 --- a/qt_ui/windows/QWaitingForMissionResultWindow.py +++ b/qt_ui/windows/QWaitingForMissionResultWindow.py @@ -1,14 +1,32 @@ import os from PySide2 import QtCore +from PySide2.QtCore import QObject, Signal from PySide2.QtGui import QMovie, QIcon -from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout +from PySide2.QtWidgets import QLabel, QDialog, QVBoxLayout, QGroupBox, QGridLayout, QPushButton from game.game import Event, Game from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from userdata.debriefing import wait_for_debriefing, Debriefing from userdata.persistency import base_path +class DebriefingFileWrittenSignal(QObject): + + instance = None + debriefingReceived = Signal(Debriefing) + + def __init__(self): + super(DebriefingFileWrittenSignal, self).__init__() + DebriefingFileWrittenSignal.instance = self + + def sendDebriefing(self, debriefing: Debriefing): + self.debriefingReceived.emit(debriefing) + + @staticmethod + def get_instance(): + return DebriefingFileWrittenSignal.instance + +DebriefingFileWrittenSignal() class QWaitingForMissionResultWindow(QDialog): @@ -22,34 +40,67 @@ class QWaitingForMissionResultWindow(QDialog): self.setWindowIcon(QIcon("./resources/icon.png")) self.initUi() - wait_for_debriefing(lambda debriefing: self.process_debriefing(debriefing)) + DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(self.updateLayout) + wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game) def initUi(self): - self.layout = QVBoxLayout() - self.layout.addWidget(QLabel("You are clear for takeoff !")) - self.layout.addWidget(QLabel("In DCS open and play the mission : ")) - self.layout.addWidget(QLabel("liberation_nextturn")) - self.layout.addWidget(QLabel("or")) - self.layout.addWidget(QLabel("liberation_nextturn_quick")) - self.layout.addWidget(QLabel("Then save the debriefing to the folder :")) - self.layout.addWidget(QLabel(self.debriefing_directory_location())) + self.layout = QGridLayout() + self.gridLayout = QGridLayout() + self.gridLayout.addWidget(QLabel("You are clear for takeoff !"),0,0) + self.gridLayout.addWidget(QLabel("In DCS open and start playing the mission : "),1,0) + self.gridLayout.addWidget(QLabel("liberation_nextturn"),2,0) + self.gridLayout.addWidget(QLabel("or"),3,0) + self.gridLayout.addWidget(QLabel("liberation_nextturn_quick"),4,0) progress = QLabel("") progress.setAlignment(QtCore.Qt.AlignCenter) progressBar = QMovie("./resources/ui/loader.gif") progress.setMovie(progressBar) - self.layout.addWidget(progress) + self.gridLayout.addWidget(progress,5,0) progressBar.start() - + self.layout.addLayout(self.gridLayout,0,0) self.setLayout(self.layout) + def updateLayout(self, debriefing): + updateBox = QGroupBox("Mission status") + updateLayout = QGridLayout() + updateBox.setLayout(updateLayout) + + updateLayout.addWidget(QLabel("Aircrafts destroyed"), 0, 0) + updateLayout.addWidget(QLabel(str(len(debriefing.killed_aircrafts))), 0, 1) + + updateLayout.addWidget(QLabel("Ground units destroyed"), 1, 0) + updateLayout.addWidget(QLabel(str(len(debriefing.killed_ground_units))), 1, 1) + + updateLayout.addWidget(QLabel("Weapons fired"), 2, 0) + updateLayout.addWidget(QLabel(str(len(debriefing.weapons_fired))), 2, 1) + + updateLayout.addWidget(QLabel("Base Capture Events"), 3, 0) + updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 3, 1) + + # Clear previous content of the window + for i in reversed(range(self.gridLayout.count())): + self.gridLayout.itemAt(i).widget().setParent(None) + + # Set new window content + self.gridLayout.addWidget(updateBox, 0, 0) + + if not debriefing.mission_ended: + self.gridLayout.addWidget(QLabel("Mission is being played"), 1, 0) + else: + #self.gridLayout.addWidget(QLabel("Mission is over !"), 1, 0) + proceed = QPushButton("Accept results") + proceed.setProperty("style", "btn-primary") + proceed.clicked.connect(lambda: self.process_debriefing(debriefing)) + self.gridLayout.addWidget(proceed, 1, 0) + + def on_debriefing_udpate(self, debriefing): + print("On Debriefing update") + print(debriefing) + DebriefingFileWrittenSignal.get_instance().sendDebriefing(debriefing) + wait_for_debriefing(lambda debriefing: self.on_debriefing_udpate(debriefing), self.game) + def process_debriefing(self, debriefing: Debriefing): - - debriefing.calculate_units(regular_mission=self.gameEvent.operation.regular_mission, - quick_mission=self.gameEvent.operation.quick_mission, - player_country=self.game.player_country, - enemy_country=self.game.enemy_country) - self.game.finish_event(event=self.gameEvent, debriefing=debriefing) self.game.pass_turn(ignored_cps=[self.gameEvent.to_cp, ]) diff --git a/resources/scripts/dcs_liberation.lua b/resources/scripts/dcs_liberation.lua index 921c7da5..a45bba90 100644 --- a/resources/scripts/dcs_liberation.lua +++ b/resources/scripts/dcs_liberation.lua @@ -1,9 +1,15 @@ -local jsonlib = lfs.writedir() .. "Scripts\\DCSLiberation\\json.lua" +local jsonlib = {{json_file_abs_location}} json = loadfile(jsonlib)() -killed_aircrafts = {}; -killed_ground_units = {}; +logger = mist.Logger:new("DCSLiberation", "info") + +debriefing_file_location = {{debriefing_file_location}} + +killed_aircrafts = {} +killed_ground_units = {} weapons_fired = {} +base_capture_events = {} +mission_ended = false local function messageAll(message) local msg = {} @@ -14,23 +20,24 @@ local function messageAll(message) end write_state = function() - log("Writing DCS Liberation State...") - local stateFile = lfs.writedir()..[[Scripts\DCSLiberation\state.json]] - local fp = io.open(stateFile, 'w') + messageAll("Writing DCS Liberation State...") + local fp = io.open(debriefing_file_location, 'w') local game_state = { ["killed_aircrafts"] = killed_aircrafts, ["killed_ground_units"] = killed_ground_units, ["weapons_fired"] = weapons_fired, + ["base_capture_events"] = base_capture_events, + ["mission_ended"] = mission_ended, } fp:write(json:encode(game_state)) fp:close() - log("Done writing DCS Liberation state.") + messageAll("Done writing DCS Liberation state.") end mist.scheduleFunction(write_state, {}, timer.getTime() + 10, 60, timer.getTime() + 3600) activeWeapons = {} -local function onCrash(event) +local function onEvent(event) if event.id == world.event.S_EVENT_CRASH and event.initiator then messageAll("Crash :" .. event.initiator.getName(event.initiator)) killed_aircrafts[#killed_aircrafts + 1] = event.initiator.getName(event.initiator) @@ -43,8 +50,16 @@ local function onCrash(event) if event.id == world.event.S_EVENT_SHOT and event.weapon then weapons_fired[#weapons_fired + 1] = event.weapon.getTypeName(event.weapon) end + + if event.id == world.event.S_EVENT_BASE_CAPTURED and event.place then + base_capture_events[#base_capture_events + 1] = event.place.getName(event.place) .. "||" .. event.place.getCoalition(event.place) + end + + if event.id == world.event.S_EVENT_MISSION_END then + mission_ended = true + write_state() + end + end - - -mist.addEventHandler(onCrash) \ No newline at end of file +mist.addEventHandler(onEvent) \ No newline at end of file diff --git a/userdata/debriefing.py b/userdata/debriefing.py index 6df7cde4..e40a52cc 100644 --- a/userdata/debriefing.py +++ b/userdata/debriefing.py @@ -1,3 +1,4 @@ +import json import logging import os import re @@ -14,188 +15,97 @@ from .persistency import base_path DEBRIEFING_LOG_EXTENSION = "log" +class DebriefingDeadUnitInfo: + country_id = -1 + player_unit = False + type = None -def parse_mutliplayer_debriefing(contents: str): - result = {} - element = None - - in_events = False - - for line in [x.strip() for x in contents.splitlines()]: - if line.startswith("events ="): - in_events = True - elif line.startswith("} -- end of events"): - in_events = False - - if not in_events: - continue - - key = None - if line.startswith("initiator\t"): - key = "initiator" - if element is None: - element = {} - elif line.startswith("initiatorMissionID\t"): - key = "initiatorMissionID" - if element is None: - element = {} - elif line.startswith("type\t"): - key = "type" - if element is None: - element = {} - elif line.startswith("}, -- end of ["): - result[len(result)] = element - element = None - continue - else: - continue - - value = re.findall(r"=\s*\"(.*?)\",", line)[0] - element[key] = value - - return {"debriefing": {"events": result}} - + def __init__(self, country_id, player_unit , type): + self.country_id = country_id + self.player_unit = player_unit + self.type = type class Debriefing: - def __init__(self, dead_units, dead_units_name, trigger_state): - self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]] - self.alive_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]] - self.destroyed_objects = [] # type: typing.List[str] + def __init__(self, state_data, game): + self.base_capture_events = state_data["base_capture_events"] + self.killed_aircrafts = state_data["killed_aircrafts"] + self.killed_ground_units = state_data["killed_ground_units"] + self.weapons_fired = state_data["weapons_fired"] + self.mission_ended = state_data["mission_ended"] - self._trigger_state = trigger_state - self._dead_units = dead_units - self.dead_units_name = dead_units_name + self.player_country_id = db.country_id_from_name(game.player_country) + self.enemy_country_id = db.country_id_from_name(game.enemy_country) - @classmethod - def parse(cls, path: str): - dead_units = [] - dead_units_name = [] + self.dead_aircraft = [] + self.dead_units = [] - def append_dead_object(object_mission_id_str, object_name): - nonlocal dead_units - object_mission_id = int(object_mission_id_str) - if object_mission_id in dead_units: - logging.error("debriefing: failed to append_dead_object {}: already exists!".format(object_mission_id)) - return - - dead_units.append(object_mission_id) - dead_units_name.append(object_name) - - def parse_dead_object(event): - print(event) + for aircraft in self.killed_aircrafts: try: - append_dead_object(event["initiatorMissionID"], event["initiator"]) + country = int(aircraft.split("|")[1]) + type = db.unit_type_from_name(aircraft.split("|")[4]) + player_unit = (country == self.player_country_id) + aircraft = DebriefingDeadUnitInfo(country, player_unit, type) + self.dead_aircraft.append(aircraft) except Exception as e: - logging.error(e) + print(e) - with open(path, "r") as f: - table_string = f.read() + for unit in self.killed_ground_units: try: - table = parse.loads(table_string) + country = int(unit.split("|")[1]) + type = db.unit_type_from_name(unit.split("|")[4]) + player_unit = (country == self.player_country_id) + unit = DebriefingDeadUnitInfo(country, player_unit, type) + self.dead_units.append(unit) except Exception as e: - table = parse_mutliplayer_debriefing(table_string) + print(e) - events = table.get("debriefing", {}).get("events", {}) - for event in events.values(): - event_type = event.get("type", None) - if event_type in ["crash", "dead"]: - parse_dead_object(event) + self.player_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.player_country_id] + self.enemy_dead_aircraft = [a for a in self.dead_aircraft if a.country_id == self.enemy_country_id] + self.player_dead_units = [a for a in self.dead_units if a.country_id == self.player_country_id] + self.enemy_dead_units = [a for a in self.dead_units if a.country_id == self.enemy_country_id] - trigger_state = table.get("debriefing", {}).get("triggers_state", {}) + self.player_dead_aircraft_dict = {} + for a in self.player_dead_aircraft: + if a.type in self.player_dead_aircraft_dict.keys(): + self.player_dead_aircraft_dict[a.type] = self.player_dead_aircraft_dict[a.type] + 1 + else: + self.player_dead_aircraft_dict[a.type] = 1 - return Debriefing(dead_units, dead_units_name, trigger_state) + self.enemy_dead_aircraft_dict = {} + for a in self.enemy_dead_aircraft: + if a.type in self.enemy_dead_aircraft_dict.keys(): + self.enemy_dead_aircraft_dict[a.type] = self.enemy_dead_aircraft_dict[a.type] + 1 + else: + self.enemy_dead_aircraft_dict[a.type] = 1 - def calculate_units(self, regular_mission: Mission, quick_mission: Mission, player_country: str, enemy_country: str): - def count_groups(groups: typing.List[UnitType]) -> typing.Dict[UnitType, int]: - result = {} - for group in groups: - for unit in group.units: - unit_type = db.unit_type_of(unit) - if unit_type in db.EXTRA_AA.values(): - continue + self.player_dead_units_dict = {} + for a in self.player_dead_units: + if a.type in self.player_dead_units_dict.keys(): + self.player_dead_units_dict[a.type] = self.player_dead_units_dict[a.type] + 1 + else: + self.player_dead_units_dict[a.type] = 1 - result[unit_type] = result.get(unit_type, 0) + 1 + self.enemy_dead_units_dict = {} + for a in self.enemy_dead_units: + if a.type in self.enemy_dead_units_dict.keys(): + self.enemy_dead_units_dict[a.type] = self.enemy_dead_units_dict[a.type] + 1 + else: + self.enemy_dead_units_dict[a.type] = 1 - return result - - mission = regular_mission if len(self._trigger_state) else quick_mission - - player = mission.country(player_country) - enemy = mission.country(enemy_country) - - player_units = count_groups(player.plane_group + player.vehicle_group + player.ship_group) - enemy_units = count_groups(enemy.plane_group + enemy.vehicle_group + enemy.ship_group) - - self.destroyed_units = { - player.name: {}, - enemy.name: {}, - } - - all_groups = { - player.name: player.plane_group + player.helicopter_group + player.vehicle_group + player.ship_group, - enemy.name: enemy.plane_group + enemy.helicopter_group + enemy.vehicle_group + enemy.ship_group, - } - - static_groups = enemy.static_group - - for country_name, country_groups in all_groups.items(): - for group in country_groups: - for unit in group.units: - if unit.id in self._dead_units: - unit_type = db.unit_type_of(unit) - logging.info("debriefing: found dead unit {} ({}, {}) for country {}".format(str(unit.name), unit.id, unit_type, country_name)) - - assert country_name - assert unit_type - self.destroyed_units[country_name][unit_type] = self.destroyed_units[country_name].get(unit_type, 0) + 1 - self._dead_units.remove(unit.id) - - for group in static_groups: - identifier = group.units[0].id - if identifier in self._dead_units: - logging.info("debriefing: found dead static {} ({})".format(str(group.name), identifier)) - - assert str(group.name) - self.destroyed_objects.append(str(group.name)) - self._dead_units.remove(identifier) - - logging.info("debriefing: unsatistied ids: {}".format(self._dead_units)) - - self.alive_units = { - player.name: {k: v - self.destroyed_units[player.name].get(k, 0) for k, v in player_units.items()}, - enemy.name: {k: v - self.destroyed_units[enemy.name].get(k, 0) for k, v in enemy_units.items()}, - } - - -def debriefing_directory_location() -> str: - return os.path.join(base_path(), "liberation_debriefings") - - -def _logfiles_snapshot() -> typing.Dict[str, float]: - result = {} - for file in os.listdir(debriefing_directory_location()): - fullpath = os.path.join(debriefing_directory_location(), file) - result[file] = os.path.getmtime(fullpath) - - return result - - -def _poll_new_debriefing_log(snapshot: typing.Dict[str, float], callback: typing.Callable): - should_run = True - while should_run: - for file, timestamp in _logfiles_snapshot().items(): - if file not in snapshot or timestamp != snapshot[file]: - debriefing = Debriefing.parse(os.path.join(debriefing_directory_location(), file)) +def _poll_new_debriefing_log(callback: typing.Callable, game): + if os.path.isfile("state.json"): + last_modified = os.path.getmtime("state.json") + else: + last_modified = 0 + while True: + if os.path.isfile("state.json") and os.path.getmtime("state.json") > last_modified: + with open("state.json", "r") as json_file: + json_data = json.load(json_file) #Debriefing.parse(os.path.join(debriefing_directory_location(), file)) + debriefing = Debriefing(json_data, game) callback(debriefing) - should_run = False - break + break + time.sleep(5) - time.sleep(3) - - -def wait_for_debriefing(callback: typing.Callable): - if not os.path.exists(debriefing_directory_location()): - os.mkdir(debriefing_directory_location()) - - threading.Thread(target=_poll_new_debriefing_log, args=(_logfiles_snapshot(), callback)).start() +def wait_for_debriefing(callback: typing.Callable, game): + threading.Thread(target=_poll_new_debriefing_log, args=[callback, game]).start() diff --git a/userdata/persistency.py b/userdata/persistency.py index dbb42705..e416d8d9 100644 --- a/userdata/persistency.py +++ b/userdata/persistency.py @@ -5,6 +5,8 @@ import os import sys import shutil +from dcs import installation + _user_folder = None # type: str @@ -17,6 +19,7 @@ def base_path() -> str: global _user_folder assert _user_folder + return installation.get_dcs_saved_games_directory() openbeta_path = os.path.join(_user_folder, "DCS.openbeta") if "--force-stable-DCS" not in sys.argv and os.path.exists(openbeta_path): return openbeta_path diff --git a/userdata/state.py b/userdata/state.py new file mode 100644 index 00000000..846f5893 --- /dev/null +++ b/userdata/state.py @@ -0,0 +1,10 @@ + + +class RunningMissionState: + + killed_aircrafts = [] + killed_ground_units = [] + weapons_fired = [] + + def __init__(self): + pass \ No newline at end of file