From 727fcb87a82402a6f1e26ee5d9297381c3ed702b Mon Sep 17 00:00:00 2001 From: JS Date: Sun, 18 Oct 2026 21:45:52 +0800 Subject: [PATCH] fix(dis7): restore EntityID alias and legacy flat field names Fixes #88 --- opendis/dis7.py | 1 + opendis/record/common.py | 34 ++++++++++++++++++++++ tests/test_EntityID_compat.py | 54 +++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 tests/test_EntityID_compat.py diff --git a/opendis/dis7.py b/opendis/dis7.py index 1b0036b..2cf5a15 100644 --- a/opendis/dis7.py +++ b/opendis/dis7.py @@ -15,6 +15,7 @@ DEFireFlags, WorldCoordinates, EntityIdentifier, + EntityID, EventIdentifier, SimulationAddress, BeamAntennaPattern, diff --git a/opendis/record/common.py b/opendis/record/common.py index 3f35f87..091e459 100644 --- a/opendis/record/common.py +++ b/opendis/record/common.py @@ -23,6 +23,7 @@ "Vector3Float", "WorldCoordinates", "EntityIdentifier", + "EntityID", "EulerAngles", "SimulationAddress", "EventIdentifier", @@ -53,6 +54,39 @@ def parse(self, inputStream: DataInputStream) -> None: self.simulationAddress.parse(inputStream) self.entityNumber = inputStream.read_uint16() + # Legacy EntityID field names, kept for backwards compatibility with + # pre-1.1 code and other open-dis implementations. They delegate to the + # fields above and do not change the wire format. + @property + def siteID(self) -> uint16: + return self.simulationAddress.site + + @siteID.setter + def siteID(self, value: uint16) -> None: + self.simulationAddress.site = value + + @property + def applicationID(self) -> uint16: + return self.simulationAddress.application + + @applicationID.setter + def applicationID(self, value: uint16) -> None: + self.simulationAddress.application = value + + @property + def entityID(self) -> uint16: + return self.entityNumber + + @entityID.setter + def entityID(self, value: uint16) -> None: + self.entityNumber = value + + +# Legacy name for EntityIdentifier (the standard's own shorthand for the +# ยง6.2.28 record is "Entity ID"); kept as an alias for backwards +# compatibility. +EntityID = EntityIdentifier + class EulerAngles(base.Record): """6.2.32 Euler Angles record diff --git a/tests/test_EntityID_compat.py b/tests/test_EntityID_compat.py new file mode 100644 index 0000000..ff8cee8 --- /dev/null +++ b/tests/test_EntityID_compat.py @@ -0,0 +1,54 @@ +"""Backwards compatibility of the EntityID name and its flat field names. + +The type of EntityStatePdu.entityID changed from the flat EntityID class to +EntityIdentifier (see issue #88). EntityID is an alias of EntityIdentifier +and the flat field names delegate to it, restoring pre-1.1 code without +changing the wire format. +""" + +import io +import os +import unittest + +from opendis.dis7 import EntityID, EntityIdentifier +from opendis.PduFactory import createPduFromFilePath +from opendis.stream import DataOutputStream + + +class TestEntityIDCompat(unittest.TestCase): + + def setUp(self): + testdir = os.path.dirname(os.path.abspath(__file__)) + os.chdir(testdir) + + def test_alias_identity(self): + self.assertIs(EntityID, EntityIdentifier) + + def test_flat_fields_write_through(self): + entityID = EntityID() + entityID.siteID = 17 + entityID.applicationID = 23 + entityID.entityID = 42 + self.assertEqual(17, entityID.simulationAddress.site) + self.assertEqual(23, entityID.simulationAddress.application) + self.assertEqual(42, entityID.entityNumber) + + def test_wire_format_unchanged(self): + entityID = EntityID() + entityID.siteID = 17 + entityID.applicationID = 23 + entityID.entityID = 42 + buffer = io.BytesIO() + entityID.serialize(DataOutputStream(buffer)) + # site 17, application 23, entity number 42, as three big-endian u16 + self.assertEqual(b"\x00\x11\x00\x17\x00\x2a", buffer.getvalue()) + + def test_flat_reads_on_parsed_pdu(self): + pdu = createPduFromFilePath("EntityStatePdu-26.raw") + self.assertEqual(42, pdu.entityID.siteID) + self.assertEqual(4, pdu.entityID.applicationID) + self.assertEqual(26, pdu.entityID.entityID) + + +if __name__ == "__main__": + unittest.main()