1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-05-11 11:33:48 +00:00

check attributes of xml resources elements

This commit is contained in:
Dragorn421 2025-02-09 21:42:48 +01:00
parent ad6ff6df27
commit e0b8f3087d
No known key found for this signature in database
GPG key ID: 381AEBAF3D429335
4 changed files with 112 additions and 7 deletions

View file

@ -11,6 +11,10 @@ from .base import (
ResourceHandlerNeedsPass2Exception,
BaseromFileBackingMemory,
)
from . import xml_errors
# TODO remove
STATIC_ATTRIB = {"Static"}
class GfxMicroCode(enum.Enum):
@ -26,6 +30,9 @@ class DListResourceDesc(ResourceDesc):
def handler_DList(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(
reselem, {"Name", "Offset"}, {"Ucode", "RawPointers"} | STATIC_ATTRIB
)
if "Ucode" in reselem.attrib:
ucode = GfxMicroCode[reselem.attrib["Ucode"].upper()]
else:
@ -44,6 +51,7 @@ class BlobResourceDesc(ResourceDesc):
def handler_Blob(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "Size"}, STATIC_ATTRIB)
size = int(reselem.attrib["Size"], 16)
return BlobResourceDesc(symbol_name, offset, collection, reselem, size)
@ -54,6 +62,7 @@ class MtxResourceDesc(ResourceDesc):
def handler_Mtx(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"}, STATIC_ATTRIB)
return MtxResourceDesc(symbol_name, offset, collection, reselem)
@ -73,6 +82,7 @@ class VtxArrayResourceDesc(ResourceDesc):
def handler_Array(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "Count"}, STATIC_ATTRIB)
count = int(reselem.attrib["Count"])
assert len(reselem) == 1, "Expected exactly one child of Array node"
array_elem = reselem[0]
@ -122,6 +132,20 @@ class CITextureResourceDesc(TextureResourceDesc):
def handler_Texture(
symbol_name, offset, collection: ResourcesDescCollection, reselem: Element
):
xml_errors.check_attrib(
reselem,
{"Name", "Offset", "Format", "Width", "Height"},
# TODO remove OutName, SplitTlut
{
"OutName",
"SplitTlut",
"TlutOffset",
"ExternalTlut",
"ExternalTlutOffset",
"HackMode",
}
| STATIC_ATTRIB,
)
format = TextureFormat[reselem.attrib["Format"].upper()]
width = int(reselem.attrib["Width"])
height = int(reselem.attrib["Height"])
@ -138,6 +162,12 @@ def handler_Texture(
), f"CI texture {symbol_name} is missing a tlut offset"
if "TlutOffset" in reselem.attrib:
xml_errors.check_attrib(
reselem,
{"Name", "Offset", "Format", "Width", "Height", "TlutOffset"},
# TODO remove OutName, SplitTlut
{"OutName", "SplitTlut", "HackMode"} | STATIC_ATTRIB,
)
tlut_offset = int(reselem.attrib["TlutOffset"], 16)
def pass2_callback(pool: ResourcesDescCollectionsPool):
@ -154,6 +184,20 @@ def handler_Texture(
res.tlut = matching_tlut_resources[0]
else:
xml_errors.check_attrib(
reselem,
{
"Name",
"Offset",
"Format",
"Width",
"Height",
"ExternalTlut",
"ExternalTlutOffset",
},
# TODO remove OutName, SplitTlut
{"OutName", "SplitTlut", "HackMode"} | STATIC_ATTRIB,
)
external_tlut_file = reselem.attrib["ExternalTlut"]
external_tlut_offset = int(reselem.attrib["ExternalTlutOffset"], 16)
@ -178,6 +222,12 @@ def handler_Texture(
raise ResourceHandlerNeedsPass2Exception(res, pass2_callback)
else:
xml_errors.check_attrib(
reselem,
{"Name", "Offset", "Format", "Width", "Height"},
# TODO remove OutName
{"OutName", "HackMode"} | STATIC_ATTRIB,
)
res = TextureResourceDesc(
symbol_name, offset, collection, reselem, format, width, height
)

View file

@ -0,0 +1,28 @@
from xml.etree import ElementTree
class XMLDescError(Exception):
pass
def check_attrib(
elem: ElementTree.Element,
required: set[str],
optional: set[str] = set(),
):
required_and_missing = required - elem.attrib.keys()
if required_and_missing:
raise XMLDescError(
"Missing attributes on "
+ ElementTree.tostring(elem, encoding="unicode")
+ ": "
+ ", ".join(required_and_missing)
)
unknown = elem.attrib.keys() - required - optional
if unknown:
raise XMLDescError(
"Unknown attributes on "
+ ElementTree.tostring(elem, encoding="unicode")
+ ": "
+ ", ".join(unknown)
)

View file

@ -8,6 +8,7 @@ from .base import (
ResourcesDescCollection,
ResourceHandlerNeedsPass2Exception,
)
from . import xml_errors
@dataclasses.dataclass(eq=False)
@ -15,7 +16,9 @@ class CollisionResourceDesc(ResourceDesc):
pass
handler_Collision = CollisionResourceDesc
def handler_Collision(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return CollisionResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -23,7 +26,9 @@ class AnimationResourceDesc(ResourceDesc):
pass
handler_Animation = AnimationResourceDesc
def handler_Animation(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return AnimationResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -31,7 +36,9 @@ class PlayerAnimationResourceDesc(ResourceDesc):
pass
handler_PlayerAnimation = PlayerAnimationResourceDesc
def handler_PlayerAnimation(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return PlayerAnimationResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -39,7 +46,9 @@ class LegacyAnimationResourceDesc(ResourceDesc):
pass
handler_LegacyAnimation = LegacyAnimationResourceDesc
def handler_LegacyAnimation(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return LegacyAnimationResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -47,7 +56,9 @@ class CutsceneResourceDesc(ResourceDesc):
pass
handler_Cutscene = CutsceneResourceDesc
def handler_Cutscene(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return CutsceneResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -55,7 +66,9 @@ class SceneResourceDesc(ResourceDesc):
pass
handler_Scene = SceneResourceDesc
def handler_Scene(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"})
return SceneResourceDesc(symbol_name, offset, collection, reselem)
@dataclasses.dataclass(eq=False)
@ -64,6 +77,7 @@ class RoomResourceDesc(ResourceDesc):
def handler_Room(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset"}, {"HackMode"})
res = RoomResourceDesc(symbol_name, offset, collection, reselem)
if reselem.attrib.get("HackMode") == "syotes_room":
res.hack_modes.add("hackmode_syotes_room")
@ -76,6 +90,7 @@ class PlayerAnimationDataResourceDesc(ResourceDesc):
def handler_PlayerAnimationData(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "FrameCount"})
frame_count = int(reselem.attrib["FrameCount"])
return PlayerAnimationDataResourceDesc(
symbol_name, offset, collection, reselem, frame_count
@ -88,6 +103,7 @@ class PathListResourceDesc(ResourceDesc):
def handler_PathList(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "NumPaths"})
num_paths = int(reselem.attrib["NumPaths"])
return PathListResourceDesc(symbol_name, offset, collection, reselem, num_paths)
@ -116,6 +132,11 @@ class SkeletonResourceDesc(ResourceDesc):
def handler_Skeleton(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(
reselem,
{"Name", "Offset", "Type", "LimbType"},
{"EnumName", "LimbNone", "LimbMax"},
)
skel_type = SkeletonType[reselem.attrib["Type"].upper()]
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
return SkeletonResourceDesc(
@ -138,6 +159,7 @@ class LimbResourceDesc(ResourceDesc):
def handler_Limb(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "LimbType"}, {"EnumName"})
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
return LimbResourceDesc(
symbol_name,
@ -156,6 +178,7 @@ class LimbTableResourceDesc(ResourceDesc):
def handler_LimbTable(symbol_name, offset, collection, reselem: Element):
xml_errors.check_attrib(reselem, {"Name", "Offset", "LimbType", "Count"})
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
count = int(reselem.attrib["Count"])
return LimbTableResourceDesc(
@ -171,6 +194,7 @@ class CurveAnimationResourceDesc(ResourceDesc):
def handler_CurveAnimation(
symbol_name, offset, collection: ResourcesDescCollection, reselem: Element
):
xml_errors.check_attrib(reselem, {"Name", "Offset", "SkelOffset"})
res = CurveAnimationResourceDesc(symbol_name, offset, collection, reselem, None)
skel_offset = int(reselem.attrib["SkelOffset"], 16)

View file

@ -129,7 +129,10 @@ def process_pool(
raise NotImplementedError(
f"alignment for {rescoll.start_address.vram=:#08X}"
)
elif isinstance(rescoll.start_address, SegmentStartAddress):
elif (
isinstance(rescoll.start_address, SegmentStartAddress)
or rescoll.start_address is None
):
alignment = 8
else:
raise NotImplementedError(rescoll.start_address)