Add classmethod for rebuilding TEs into a TECollection

This commit is contained in:
Salad Dais
2022-07-18 06:37:20 +00:00
parent 309dbeeb52
commit 8c0635bb2a
2 changed files with 31 additions and 3 deletions

View File

@@ -3,6 +3,7 @@ Serialization templates for structures used in LLUDP and HTTP bodies.
"""
import abc
import collections
import dataclasses
import enum
import importlib
@@ -863,7 +864,7 @@ class ShineLevel(IntEnum):
HIGH = 3
@dataclasses.dataclass
@dataclasses.dataclass(unsafe_hash=True)
class BasicMaterials:
# Meaning is technically implementation-dependent, these are in LL data files
Bump: int = se.bitfield_field(bits=5)
@@ -882,7 +883,7 @@ class TexGen(IntEnum):
CYLINDRICAL = 0x6
@dataclasses.dataclass
@dataclasses.dataclass(unsafe_hash=True)
class MediaFlags:
WebPage: bool = se.bitfield_field(bits=1, adapter=se.BoolAdapter())
TexGen: "TexGen" = se.bitfield_field(bits=2, adapter=se.IntEnum(TexGen))
@@ -1129,7 +1130,9 @@ class TextureEntryCollection:
Makes it easier to get all TE details associated with a specific face
"""
as_dicts = [dict() for _ in range(num_faces)]
for key, vals in dataclasses.asdict(self).items():
for field in dataclasses.fields(self):
key = field.name
vals = getattr(self, key)
# Fill give all faces the default value for this key
for te in as_dicts:
te[key] = vals[None]
@@ -1144,6 +1147,26 @@ class TextureEntryCollection:
as_dicts[face_num][key] = val
return [TextureEntry(**x) for x in as_dicts]
@classmethod
def from_tes(cls, tes: List[TextureEntry]) -> "TextureEntryCollection":
instance = cls()
if not tes:
return instance
for field in dataclasses.fields(cls):
te_vals: Dict[Any, List[int]] = collections.defaultdict(list)
for i, te in enumerate(tes):
# Group values by what face they occur on
te_vals[getattr(te, field.name)].append(i)
# Make most common value the "default", everything else is an exception
sorted_vals = sorted(te_vals.items(), key=lambda x: len(x[1]), reverse=True)
default_val = sorted_vals.pop(0)[0]
te_vals = {None: default_val}
for val, face_nums in sorted_vals:
te_vals[tuple(face_nums)] = val
setattr(instance, field.name, te_vals)
return instance
TE_SERIALIZER = se.Dataclass(TextureEntryCollection)

View File

@@ -27,6 +27,11 @@ class TemplateTests(unittest.TestCase):
with self.assertRaises(ValueError):
deserialized.realize(3)
def test_tecollection_from_tes(self):
deserialized: TextureEntryCollection = TextureEntrySubfieldSerializer.deserialize(None, EXAMPLE_TE)
# The TE collection should re-serialize to the same collection when split up and regrouped
self.assertEqual(deserialized, TextureEntryCollection.from_tes(deserialized.realize(4)))
def test_face_bitfield_round_trips(self):
test_val = b"\x81\x03"
reader = se.BufferReader("!", test_val)