diff --git a/hippolyzer/lib/base/templates.py b/hippolyzer/lib/base/templates.py index 6b62eea..a7ff18a 100644 --- a/hippolyzer/lib/base/templates.py +++ b/hippolyzer/lib/base/templates.py @@ -1065,12 +1065,38 @@ class TextureEntry: default_factory=lambda: MediaFlags(WebPage=False, TexGen=TexGen.DEFAULT, _Unused=0), ) Glow: Dict[_TE_FIELD_KEY, int] = _te_field(se.U8, default=0) - Materials: Dict[_TE_FIELD_KEY, UUID] = _te_field(se.UUID, optional=True, default=UUID()) + Materials: Dict[_TE_FIELD_KEY, UUID] = _te_field(se.UUID, optional=True, default=UUID.ZERO) def unwrap(self): """Return `self` regardless of whether this is lazy wrapped object or not""" return self + def realize(self, num_faces: int): + """ + Turn the "default" vs "exception cases" wire format TE representation to per-face lookups + + Makes it easier to just index into a list of offsets with a face number. + Returns something like: + { + "OffsetsS": [0.5, 0.2, ...], + ... + } + """ + as_dict = {} + for key, vals in dataclasses.asdict(self).items(): + # Fill all of the faces in this key with the default value stored in the TE + key_arr = as_dict[key] = [vals[None]] * num_faces + # Walk over the exception cases and replace the default value + for face_nums, val in vals.items(): + # Default case already handled + if face_nums is None: + continue + for face_num in face_nums: + if face_num >= num_faces: + raise ValueError(f"Bad value for num_faces? {face_num} >= {num_faces}") + key_arr[face_num] = val + return as_dict + TE_SERIALIZER = se.Dataclass(TextureEntry) diff --git a/tests/proxy/test_templates.py b/tests/proxy/test_templates.py index bb59680..97785bc 100644 --- a/tests/proxy/test_templates.py +++ b/tests/proxy/test_templates.py @@ -12,12 +12,18 @@ EXAMPLE_TE = b'\x89UgG$\xcbC\xed\x92\x0bG\xca\xed\x15F_\x08\xca*\x98:\x18\x02,\r class TemplateTests(unittest.TestCase): - def test_te_round_trips(self): deserialized = TextureEntrySubfieldSerializer.deserialize(None, EXAMPLE_TE) serialized = TextureEntrySubfieldSerializer.serialize(None, deserialized) self.assertEqual(EXAMPLE_TE, serialized) + def test_realize_te(self): + deserialized: TextureEntry = TextureEntrySubfieldSerializer.deserialize(None, EXAMPLE_TE) + realized = deserialized.realize(num_faces=4) + self.assertEqual(UUID('ca2a983a-1802-2c0d-f41e-c6f591015d83'), realized["Textures"][3]) + with self.assertRaises(ValueError): + deserialized.realize(3) + def test_face_bitfield_round_trips(self): test_val = b"\x81\x03" reader = se.BufferReader("!", test_val)