Skip to content

Commit

Permalink
Support for Ground Control passwords
Browse files Browse the repository at this point in the history
  • Loading branch information
332fg-raven committed Apr 22, 2024
1 parent b0bba2f commit 8cefdb4
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
80 changes: 80 additions & 0 deletions dcs/groundcontrol.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,69 @@
from __future__ import annotations

from enum import Enum
from typing import Dict, Any, List, Tuple, Optional
from dcs.action import Coalition
from dcs.password import password_hash


class GroundControlRole(Enum):
GAME_MASTER = "instructor"
TACTICAL_COMMANDER = "artillery_commander"
JTAC = "forward_observer"
OBSERVER = "observer"


GroundControlPasswordsEntries = Dict[Coalition, Any]


class GroundControlPasswords:
def __init__(self, d: Optional[Dict[str, Any]] = None) -> None:
self.game_masters: GroundControlPasswordsEntries = {}
self.tactical_commander: GroundControlPasswordsEntries = {}
self.jtac: GroundControlPasswordsEntries = {}
self.observer: GroundControlPasswordsEntries = {}

if d is not None:
for coalition in [Coalition.Red, Coalition.Blue, Coalition.Neutral]:
for miz_role, role_password in self.get_role_to_attr_mapping():
if miz_role.value in d and coalition.value in d[miz_role.value]:
role_password[coalition] = d[miz_role.value][coalition.value]

@classmethod
def create_from_dict(cls, d: Dict[str, Any]) -> GroundControlPasswords:
return GroundControlPasswords(d)

def get_role_to_attr_mapping(self) -> List[Tuple[GroundControlRole, GroundControlPasswordsEntries]]:
return [(GroundControlRole.GAME_MASTER, self.game_masters),
(GroundControlRole.TACTICAL_COMMANDER, self.tactical_commander),
(GroundControlRole.JTAC, self.jtac),
(GroundControlRole.OBSERVER, self.observer)]

def _find_role_password(self, role: GroundControlRole) -> GroundControlPasswordsEntries:
for miz_role, role_password in self.get_role_to_attr_mapping():
if role == miz_role:
return role_password
raise RuntimeError(f"Unable to find passwords for {role.value} role")

def lock(self, coalition: Coalition, role: GroundControlRole, password: str) -> None:
role_password = self._find_role_password(role)
role_password[coalition] = password_hash(password)

def unlock(self, coalition: Coalition, role: GroundControlRole) -> None:
role_password = self._find_role_password(role)
role_password[coalition] = None

def dict(self) -> Dict[str, Dict[str, str]]:
d: Dict[str, Any] = {}
for coalition in [Coalition.Red, Coalition.Blue, Coalition.Neutral]:
for miz_role, role_password in self.get_role_to_attr_mapping():
if coalition in role_password and role_password[coalition] is not None:
if miz_role.value not in d:
d[miz_role.value] = {}
d[miz_role.value][coalition.value] = role_password[coalition]
return d


class GroundControl:
def __init__(self):
self.pilot_can_control_vehicles = False
Expand All @@ -16,6 +82,8 @@ def __init__(self):
self.neutrals_jtac = 0
self.neutrals_observer = 0

self.passwords = GroundControlPasswords()

def load_from_dict(self, d):
if d is None:
return
Expand All @@ -36,9 +104,21 @@ def load_from_dict(self, d):
self.neutrals_jtac = int(d["roles"]["forward_observer"].get("neutrals", 0))
self.neutrals_observer = int(d["roles"]["observer"].get("neutrals", 0))

if "passwords" in d:
self.passwords = GroundControlPasswords.create_from_dict(d["passwords"])
else:
self.passwords = GroundControlPasswords()

def lock(self, coalition: Coalition, role: GroundControlRole, password: str) -> None:
self.passwords.lock(coalition, role, password)

def unlock(self, coalition: Coalition, role: GroundControlRole) -> None:
self.passwords.unlock(coalition, role)

def dict(self):
return {
"isPilotControlVehicles": self.pilot_can_control_vehicles,
"passwords": self.passwords.dict(),
"roles": {
"instructor": {
"red": self.red_game_masters,
Expand Down
54 changes: 54 additions & 0 deletions tests/test_mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from dcs.mission import Mission
from enum import IntEnum
from dcs.forcedoptions import ForcedOptions
from dcs.groundcontrol import GroundControlRole


class BasicTests(unittest.TestCase):
Expand Down Expand Up @@ -1344,3 +1345,56 @@ def test_find_unit(self) -> None:

no_unit = m.find_unit(non_existing_unit_name, red_coalition)
self.assertIsNone(no_unit)

def test_ground_control_password(self) -> None:
m = dcs.mission.Mission()
m_saved_name = "missions/saved.ground-control-passwords.miz"

kobuleti = m.terrain.airports["Kobuleti"]
kobuleti.set_blue()
batumi = m.terrain.airports["Batumi"]
batumi.set_blue()

country_name = "USA"
coal_name = str(Coalition.Blue.value)
country = m.coalition[coal_name].country(country_name)

flying_group = m.flight_group_from_airport(country, "Airgroup", dcs.planes.A_10C, kobuleti,
start_type=dcs.mission.StartType.Warm)
flying_group.units[0].set_client()

self.assertDictEqual(m.groundControl.dict()["passwords"], {})

m.groundControl.lock(Coalition.Blue, GroundControlRole.GAME_MASTER, "p-master-blue")
m.groundControl.lock(Coalition.Blue, GroundControlRole.JTAC, "p-jtac-blue")
m.groundControl.lock(Coalition.Blue, GroundControlRole.OBSERVER, "p-observer-blue")
m.groundControl.lock(Coalition.Blue, GroundControlRole.TACTICAL_COMMANDER, "p-tc-blue")

self.assertIn(Coalition.Blue.value,
m.groundControl.dict()["passwords"][GroundControlRole.TACTICAL_COMMANDER.value])
self.assertIn(Coalition.Blue.value,
m.groundControl.dict()["passwords"][GroundControlRole.JTAC.value])
self.assertIn(Coalition.Blue.value,
m.groundControl.dict()["passwords"][GroundControlRole.GAME_MASTER.value])
self.assertIn(Coalition.Blue.value,
m.groundControl.dict()["passwords"][GroundControlRole.OBSERVER.value])

m.groundControl.unlock(Coalition.Blue, GroundControlRole.TACTICAL_COMMANDER)
self.assertNotIn(GroundControlRole.TACTICAL_COMMANDER.value, m.groundControl.dict()["passwords"])

m.groundControl.lock(Coalition.Red, GroundControlRole.JTAC, "p-jtac-red")

self.assertIn(Coalition.Red.value, m.groundControl.dict()["passwords"][GroundControlRole.JTAC.value])

m.save(m_saved_name)

m2 = Mission()
m2.load_file(m_saved_name)

self.assertIn(Coalition.Blue.value,
m2.groundControl.dict()["passwords"][GroundControlRole.JTAC.value])
self.assertIn(Coalition.Blue.value,
m2.groundControl.dict()["passwords"][GroundControlRole.GAME_MASTER.value])
self.assertIn(Coalition.Blue.value,
m2.groundControl.dict()["passwords"][GroundControlRole.OBSERVER.value])
self.assertIn(Coalition.Red.value, m2.groundControl.dict()["passwords"][GroundControlRole.JTAC.value])

0 comments on commit 8cefdb4

Please sign in to comment.