Add debug command to dump aircraft priorities.

https://github.com/dcs-liberation/dcs_liberation/issues/2809
This commit is contained in:
Dan Albert 2023-04-26 20:03:07 -07:00 committed by Raffson
parent 016a9b5762
commit 9ebbe11d83
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
8 changed files with 69 additions and 16 deletions

View File

@ -183,7 +183,7 @@ class Campaign:
@classmethod @classmethod
def iter_campaign_defs(cls) -> Iterator[Path]: def iter_campaign_defs(cls) -> Iterator[Path]:
yield from cls.iter_campaigns_in_dir( yield from cls.iter_campaigns_in_dir(
Path(persistency.base_path()) / "Retribution/Campaigns" persistency.base_path() / "Retribution/Campaigns"
) )
yield from cls.iter_campaigns_in_dir(Path("resources/campaigns")) yield from cls.iter_campaigns_in_dir(Path("resources/campaigns"))

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import logging import logging
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from functools import cached_property from functools import cache, cached_property
from pathlib import Path from pathlib import Path
from typing import Any, ClassVar, Dict, Iterator, Optional, TYPE_CHECKING, Type from typing import Any, ClassVar, Dict, Iterator, Optional, TYPE_CHECKING, Type
@ -355,6 +355,15 @@ class AircraftType(UnitType[Type[FlyingType]]):
cls._load_all() cls._load_all()
yield from cls._by_name.values() yield from cls._by_name.values()
@classmethod
@cache
def priority_list_for_task(cls, task: FlightType) -> list[AircraftType]:
capable = []
for aircraft in cls.iter_all():
if aircraft.capable_of(task):
capable.append(aircraft)
return list(reversed(sorted(capable, key=lambda a: a.task_priority(task))))
@staticmethod @staticmethod
def each_dcs_type() -> Iterator[Type[FlyingType]]: def each_dcs_type() -> Iterator[Type[FlyingType]]:
yield from helicopter_map.values() yield from helicopter_map.values()

View File

@ -31,7 +31,7 @@ class FactionLoader:
@classmethod @classmethod
def load_factions(cls: Type[FactionLoader]) -> Dict[str, Faction]: def load_factions(cls: Type[FactionLoader]) -> Dict[str, Faction]:
user_faction_path = Path(persistency.base_path()) / "Retribution/Factions" user_faction_path = persistency.base_path() / "Retribution/Factions"
files = cls.find_faction_files_in( files = cls.find_faction_files_in(
FACTION_DIRECTORY FACTION_DIRECTORY
) + cls.find_faction_files_in(user_faction_path) ) + cls.find_faction_files_in(user_faction_path)

View File

@ -63,7 +63,7 @@ class LayoutLoader:
"""This will load all pre-loaded layouts from a pickle file. """This will load all pre-loaded layouts from a pickle file.
If pickle can not be loaded it will import and dump the layouts""" If pickle can not be loaded it will import and dump the layouts"""
# We use a pickle for performance reasons. Importing takes many seconds # We use a pickle for performance reasons. Importing takes many seconds
file = Path(persistency.base_path()) / LAYOUT_DUMP file = persistency.base_path() / LAYOUT_DUMP
if file.is_file(): if file.is_file():
# Load from pickle if existing # Load from pickle if existing
with file.open("rb") as f: with file.open("rb") as f:
@ -106,7 +106,7 @@ class LayoutLoader:
self._dump_templates() self._dump_templates()
def _dump_templates(self) -> None: def _dump_templates(self) -> None:
file = Path(persistency.base_path()) / LAYOUT_DUMP file = persistency.base_path() / LAYOUT_DUMP
dump = (VERSION, self._layouts) dump = (VERSION, self._layouts)
with file.open("wb") as fdata: with file.open("wb") as fdata:
pickle.dump(dump, fdata) pickle.dump(dump, fdata)

View File

@ -21,18 +21,18 @@ def setup(user_folder: str) -> None:
save_dir().mkdir(parents=True) save_dir().mkdir(parents=True)
def base_path() -> str: def base_path() -> Path:
global _dcs_saved_game_folder global _dcs_saved_game_folder
assert _dcs_saved_game_folder assert _dcs_saved_game_folder
return _dcs_saved_game_folder return Path(_dcs_saved_game_folder)
def settings_dir() -> Path: def settings_dir() -> Path:
return Path(base_path()) / "Retribution" / "Settings" return base_path() / "Retribution" / "Settings"
def save_dir() -> Path: def save_dir() -> Path:
return Path(base_path()) / "Retribution" / "Saves" return base_path() / "Retribution" / "Saves"
def _temporary_save_file() -> str: def _temporary_save_file() -> str:
@ -44,7 +44,7 @@ def _autosave_path() -> str:
def mission_path_for(name: str) -> Path: def mission_path_for(name: str) -> Path:
return Path(base_path()) / "Missions" / name return base_path() / "Missions" / name
def load_game(path: str) -> Optional[Game]: def load_game(path: str) -> Optional[Game]:

View File

@ -22,7 +22,7 @@ class SquadronDefLoader:
def squadron_directories() -> Iterator[Path]: def squadron_directories() -> Iterator[Path]:
from game import persistency from game import persistency
yield Path(persistency.base_path()) / "Retribution/Squadrons" yield persistency.base_path() / "Retribution/Squadrons"
yield Path("resources/squadrons") yield Path("resources/squadrons")
def load(self) -> dict[AircraftType, list[SquadronDef]]: def load(self) -> dict[AircraftType, list[SquadronDef]]:

View File

@ -1,11 +1,13 @@
import argparse import argparse
import logging import logging
import ntpath
import os import os
import sys import sys
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
import yaml
from PySide2 import QtWidgets from PySide2 import QtWidgets
from PySide2.QtCore import Qt from PySide2.QtCore import Qt
from PySide2.QtGui import QPixmap from PySide2.QtGui import QPixmap
@ -13,10 +15,12 @@ from PySide2.QtWidgets import QApplication, QCheckBox, QSplashScreen
from dcs.payloads import PayloadDirectories from dcs.payloads import PayloadDirectories
from game import Game, VERSION, logging_config, persistency from game import Game, VERSION, logging_config, persistency
from game.ato import FlightType
from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET
from game.data.weapons import Pylon, Weapon, WeaponGroup from game.data.weapons import Pylon, Weapon, WeaponGroup
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.factions import FACTIONS from game.factions import FACTIONS
from game.persistency import base_path
from game.profiling import logged_duration from game.profiling import logged_duration
from game.server import EventStream, Server from game.server import EventStream, Server
from game.settings import Settings from game.settings import Settings
@ -69,12 +73,12 @@ def inject_mod_payloads(mod_path: Path) -> None:
PayloadDirectories.set_preferred(payloads) PayloadDirectories.set_preferred(payloads)
def on_game_load(game: Game | None) -> None: def on_game_load(game: Optional[Game]) -> None:
EventStream.drain() EventStream.drain()
EventStream.put_nowait(GameUpdateEvents().game_loaded(game)) EventStream.put_nowait(GameUpdateEvents().game_loaded(game))
def run_ui(game: Game | None, ui_flags: UiFlags) -> None: def run_ui(game: Optional[Game], ui_flags: UiFlags) -> None:
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" # Potential fix for 4K screens os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" # Potential fix for 4K screens
QApplication.setHighDpiScaleFactorRoundingPolicy( QApplication.setHighDpiScaleFactorRoundingPolicy(
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
@ -107,7 +111,7 @@ def run_ui(game: Game | None, ui_flags: UiFlags) -> None:
) )
) )
inject_custom_payloads(Path(persistency.base_path())) inject_custom_payloads(persistency.base_path())
# Splash screen setup # Splash screen setup
pixmap = QPixmap("./resources/ui/splash_screen.png") pixmap = QPixmap("./resources/ui/splash_screen.png")
@ -260,6 +264,8 @@ def parse_args() -> argparse.Namespace:
lint_weapons = subparsers.add_parser("lint-weapons") lint_weapons = subparsers.add_parser("lint-weapons")
lint_weapons.add_argument("aircraft", help="Name of the aircraft variant to lint.") lint_weapons.add_argument("aircraft", help="Name of the aircraft variant to lint.")
subparsers.add_parser("dump-task-priorities")
return parser.parse_args() return parser.parse_args()
@ -289,7 +295,7 @@ def create_game(
# Without this, it is not possible to use next turn (or anything that needs to check # Without this, it is not possible to use next turn (or anything that needs to check
# for loadouts) without saving the generated campaign and reloading it the normal # for loadouts) without saving the generated campaign and reloading it the normal
# way. # way.
inject_custom_payloads(Path(persistency.base_path())) inject_custom_payloads(persistency.base_path())
campaign = Campaign.from_file(campaign_path) campaign = Campaign.from_file(campaign_path)
theater = campaign.load_theater(advanced_iads) theater = campaign.load_theater(advanced_iads)
generator = GameGenerator( generator = GameGenerator(
@ -364,6 +370,41 @@ def lint_weapon_data_for_aircraft(aircraft: AircraftType) -> None:
logging.warning(f'{weapon.clsid} "{weapon.name}" has no weapon data') logging.warning(f'{weapon.clsid} "{weapon.name}" has no weapon data')
def fix_pycharm_debugger_if_needed() -> None:
"""Applies workaround for a pycharm debugger bug.
https://youtrack.jetbrains.com/issue/PY-53232/Debugger-doesnt-work-when-pyproj-is-imported
"""
# sys.gettrace() will return something whenever *some* debugger is being used. The
# pdb module will be loaded if that debugger is the built-in python debugger.
if sys.gettrace() is not None and "pdb" not in sys.modules:
logging.debug(
"Applying workaround for https://youtrack.jetbrains.com/issue/PY-53232/Debugger-doesnt-work-when-pyproj-is-imported"
)
ntpath.sep = "\\"
def dump_task_priorities() -> None:
first_start = liberation_install.init()
if first_start:
sys.exit(
"Cannot dump task priorities without configuring DCS Liberation. Start the"
"UI for the first run configuration."
)
data: dict[str, dict[str, int]] = {}
for task in FlightType:
data[task.value] = {
a.name: a.task_priority(task)
for a in AircraftType.priority_list_for_task(task)
}
debug_path = base_path() / "Debug" / "priorities.yaml"
debug_path.parent.mkdir(parents=True, exist_ok=True)
with debug_path.open("w", encoding="utf-8") as output:
yaml.dump(data, output, sort_keys=False, allow_unicode=True)
def main(): def main():
logging_config.init_logging(VERSION) logging_config.init_logging(VERSION)
@ -401,6 +442,9 @@ def main():
if args.subcommand == "lint-weapons": if args.subcommand == "lint-weapons":
lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft)) lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft))
return return
if args.subcommand == "dump-task-priorities":
dump_task_priorities()
return
with Server().run_in_thread(): with Server().run_in_thread():
run_ui(game, UiFlags(args.dev, args.show_sim_speed_controls)) run_ui(game, UiFlags(args.dev, args.show_sim_speed_controls))

View File

@ -122,7 +122,7 @@ def main() -> None:
"the first run configuration." "the first run configuration."
) )
inject_custom_payloads(Path(persistency.base_path())) inject_custom_payloads(persistency.base_path())
if args.aircraft_id is None: if args.aircraft_id is None:
show_all_aircraft(args.task) show_all_aircraft(args.task)