Create a checked, releasable type for laser codes.

The release behavior isn't used yet, but I'm working on pre-allocating
laser codes for front lines and flights to make it easier for players to
pick the laser codes for their weapons.
This commit is contained in:
Dan Albert
2023-07-22 14:01:02 -07:00
committed by Raffson
parent cb6bffe3ec
commit 723e191f10
8 changed files with 180 additions and 7 deletions

View File

@@ -1 +1,3 @@
from .ilasercoderegistry import ILaserCodeRegistry
from .lasercode import LaserCode
from .lasercoderegistry import LaserCodeRegistry

View File

@@ -0,0 +1,17 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .lasercode import LaserCode
class ILaserCodeRegistry(ABC):
@abstractmethod
def alloc_laser_code(self) -> LaserCode:
...
@abstractmethod
def release_code(self, code: LaserCode) -> None:
...

View File

@@ -0,0 +1,56 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .ilasercoderegistry import ILaserCodeRegistry
class LaserCode:
def __init__(self, code: int, registry: ILaserCodeRegistry) -> None:
self.verify_laser_code(code)
self.code = code
self.registry = registry
def release(self) -> None:
self.registry.release_code(self)
@staticmethod
def verify_laser_code(code: int) -> None:
# https://forum.dcs.world/topic/211574-valid-laser-codes/
# Valid laser codes are as follows
# First digit is always 1
# Second digit is 5-7
# Third and fourth digits are 1 - 8
# We iterate backward (reversed()) so that 1687 follows 1688
# Special case used by FC3 aircraft like the A-10A that is not valid for other
# aircraft.
if code == 1113:
return
# Must be 4 digits with no leading 0
if code < 1000 or code >= 2000:
raise ValueError
# The first digit was already verified above. Isolate the remaining three
# digits. The resulting list is ordered by significance, not printed position.
digits = [code // 10**i % 10 for i in range(3)]
if digits[0] < 1 or digits[0] > 8:
raise ValueError
if digits[1] < 1 or digits[1] > 8:
raise ValueError
if digits[2] < 5 or digits[2] > 7:
raise ValueError
def __str__(self) -> str:
return f"{self.code}"
def __eq__(self, other: object) -> bool:
if not isinstance(other, LaserCode):
return False
return self.code == other.code
def __hash__(self) -> int:
return hash(self.code)

View File

@@ -1,19 +1,33 @@
import logging
from collections import deque
from .ilasercoderegistry import ILaserCodeRegistry
from .lasercode import LaserCode
class LaserCodeRegistry:
class LaserCodeRegistry(ILaserCodeRegistry):
def __init__(self) -> None:
self.allocated_codes: set[int] = set()
self.available_codes = LaserCodeRegistry._all_valid_laser_codes()
self.fc3_code = LaserCode(1113, self)
def alloc_laser_code(self) -> int:
def alloc_laser_code(self) -> LaserCode:
try:
code = self.available_codes.popleft()
self.allocated_codes.add(code)
return code
return LaserCode(code, self)
except IndexError:
raise RuntimeError("All laser codes have been allocated")
def release_code(self, code: LaserCode) -> None:
if code.code in self.allocated_codes:
self.allocated_codes.remove(code.code)
self.available_codes.appendleft(code.code)
else:
logging.error(
"attempted to release laser code %d which was not allocated", code.code
)
@staticmethod
def _all_valid_laser_codes() -> deque[int]:
# Valid laser codes are as follows

View File

@@ -148,7 +148,7 @@ class FlightGroupConfigurator:
) -> None:
self.set_skill(unit, member)
if member.loadout.has_weapon_of_type(WeaponTypeEnum.TGP) and member.is_player:
laser_codes.append(self.laser_code_registry.alloc_laser_code())
laser_codes.append(self.laser_code_registry.alloc_laser_code().code)
else:
laser_codes.append(None)
settings = self.flight.coalition.game.settings

View File

@@ -144,13 +144,12 @@ class FlotGenerator:
# Add JTAC
if self.game.blue.faction.has_jtac:
code: int
freq = self.radio_registry.alloc_uhf()
# If the option fc3LaserCode is enabled, force all JTAC
# laser codes to 1113 to allow lasing for Su-25 Frogfoots and A-10A Warthogs.
# Otherwise use 1688 for the first JTAC, 1687 for the second etc.
if self.game.settings.plugins.get("ctld.fc3LaserCode"):
code = 1113
code = self.laser_code_registry.fc3_code
else:
code = self.laser_code_registry.alloc_laser_code()