mirror of
https://github.com/zeldaret/oot.git
synced 2025-05-12 20:13:47 +00:00
check attributes of xml resources elements
This commit is contained in:
parent
ad6ff6df27
commit
e0b8f3087d
4 changed files with 112 additions and 7 deletions
|
@ -11,6 +11,10 @@ from .base import (
|
||||||
ResourceHandlerNeedsPass2Exception,
|
ResourceHandlerNeedsPass2Exception,
|
||||||
BaseromFileBackingMemory,
|
BaseromFileBackingMemory,
|
||||||
)
|
)
|
||||||
|
from . import xml_errors
|
||||||
|
|
||||||
|
# TODO remove
|
||||||
|
STATIC_ATTRIB = {"Static"}
|
||||||
|
|
||||||
|
|
||||||
class GfxMicroCode(enum.Enum):
|
class GfxMicroCode(enum.Enum):
|
||||||
|
@ -26,6 +30,9 @@ class DListResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_DList(symbol_name, offset, collection, reselem: Element):
|
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:
|
if "Ucode" in reselem.attrib:
|
||||||
ucode = GfxMicroCode[reselem.attrib["Ucode"].upper()]
|
ucode = GfxMicroCode[reselem.attrib["Ucode"].upper()]
|
||||||
else:
|
else:
|
||||||
|
@ -44,6 +51,7 @@ class BlobResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_Blob(symbol_name, offset, collection, reselem: Element):
|
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)
|
size = int(reselem.attrib["Size"], 16)
|
||||||
return BlobResourceDesc(symbol_name, offset, collection, reselem, size)
|
return BlobResourceDesc(symbol_name, offset, collection, reselem, size)
|
||||||
|
|
||||||
|
@ -54,6 +62,7 @@ class MtxResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_Mtx(symbol_name, offset, collection, reselem: Element):
|
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)
|
return MtxResourceDesc(symbol_name, offset, collection, reselem)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +82,7 @@ class VtxArrayResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_Array(symbol_name, offset, collection, reselem: Element):
|
def handler_Array(symbol_name, offset, collection, reselem: Element):
|
||||||
|
xml_errors.check_attrib(reselem, {"Name", "Offset", "Count"}, STATIC_ATTRIB)
|
||||||
count = int(reselem.attrib["Count"])
|
count = int(reselem.attrib["Count"])
|
||||||
assert len(reselem) == 1, "Expected exactly one child of Array node"
|
assert len(reselem) == 1, "Expected exactly one child of Array node"
|
||||||
array_elem = reselem[0]
|
array_elem = reselem[0]
|
||||||
|
@ -122,6 +132,20 @@ class CITextureResourceDesc(TextureResourceDesc):
|
||||||
def handler_Texture(
|
def handler_Texture(
|
||||||
symbol_name, offset, collection: ResourcesDescCollection, reselem: Element
|
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()]
|
format = TextureFormat[reselem.attrib["Format"].upper()]
|
||||||
width = int(reselem.attrib["Width"])
|
width = int(reselem.attrib["Width"])
|
||||||
height = int(reselem.attrib["Height"])
|
height = int(reselem.attrib["Height"])
|
||||||
|
@ -138,6 +162,12 @@ def handler_Texture(
|
||||||
), f"CI texture {symbol_name} is missing a tlut offset"
|
), f"CI texture {symbol_name} is missing a tlut offset"
|
||||||
|
|
||||||
if "TlutOffset" in reselem.attrib:
|
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)
|
tlut_offset = int(reselem.attrib["TlutOffset"], 16)
|
||||||
|
|
||||||
def pass2_callback(pool: ResourcesDescCollectionsPool):
|
def pass2_callback(pool: ResourcesDescCollectionsPool):
|
||||||
|
@ -154,6 +184,20 @@ def handler_Texture(
|
||||||
res.tlut = matching_tlut_resources[0]
|
res.tlut = matching_tlut_resources[0]
|
||||||
|
|
||||||
else:
|
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_file = reselem.attrib["ExternalTlut"]
|
||||||
external_tlut_offset = int(reselem.attrib["ExternalTlutOffset"], 16)
|
external_tlut_offset = int(reselem.attrib["ExternalTlutOffset"], 16)
|
||||||
|
|
||||||
|
@ -178,6 +222,12 @@ def handler_Texture(
|
||||||
|
|
||||||
raise ResourceHandlerNeedsPass2Exception(res, pass2_callback)
|
raise ResourceHandlerNeedsPass2Exception(res, pass2_callback)
|
||||||
else:
|
else:
|
||||||
|
xml_errors.check_attrib(
|
||||||
|
reselem,
|
||||||
|
{"Name", "Offset", "Format", "Width", "Height"},
|
||||||
|
# TODO remove OutName
|
||||||
|
{"OutName", "HackMode"} | STATIC_ATTRIB,
|
||||||
|
)
|
||||||
res = TextureResourceDesc(
|
res = TextureResourceDesc(
|
||||||
symbol_name, offset, collection, reselem, format, width, height
|
symbol_name, offset, collection, reselem, format, width, height
|
||||||
)
|
)
|
||||||
|
|
28
tools/assets/descriptor/xml_errors.py
Normal file
28
tools/assets/descriptor/xml_errors.py
Normal 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)
|
||||||
|
)
|
|
@ -8,6 +8,7 @@ from .base import (
|
||||||
ResourcesDescCollection,
|
ResourcesDescCollection,
|
||||||
ResourceHandlerNeedsPass2Exception,
|
ResourceHandlerNeedsPass2Exception,
|
||||||
)
|
)
|
||||||
|
from . import xml_errors
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(eq=False)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -15,7 +16,9 @@ class CollisionResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -23,7 +26,9 @@ class AnimationResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -31,7 +36,9 @@ class PlayerAnimationResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -39,7 +46,9 @@ class LegacyAnimationResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -47,7 +56,9 @@ class CutsceneResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -55,7 +66,9 @@ class SceneResourceDesc(ResourceDesc):
|
||||||
pass
|
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)
|
@dataclasses.dataclass(eq=False)
|
||||||
|
@ -64,6 +77,7 @@ class RoomResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_Room(symbol_name, offset, collection, reselem: Element):
|
def handler_Room(symbol_name, offset, collection, reselem: Element):
|
||||||
|
xml_errors.check_attrib(reselem, {"Name", "Offset"}, {"HackMode"})
|
||||||
res = RoomResourceDesc(symbol_name, offset, collection, reselem)
|
res = RoomResourceDesc(symbol_name, offset, collection, reselem)
|
||||||
if reselem.attrib.get("HackMode") == "syotes_room":
|
if reselem.attrib.get("HackMode") == "syotes_room":
|
||||||
res.hack_modes.add("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):
|
def handler_PlayerAnimationData(symbol_name, offset, collection, reselem: Element):
|
||||||
|
xml_errors.check_attrib(reselem, {"Name", "Offset", "FrameCount"})
|
||||||
frame_count = int(reselem.attrib["FrameCount"])
|
frame_count = int(reselem.attrib["FrameCount"])
|
||||||
return PlayerAnimationDataResourceDesc(
|
return PlayerAnimationDataResourceDesc(
|
||||||
symbol_name, offset, collection, reselem, frame_count
|
symbol_name, offset, collection, reselem, frame_count
|
||||||
|
@ -88,6 +103,7 @@ class PathListResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_PathList(symbol_name, offset, collection, reselem: Element):
|
def handler_PathList(symbol_name, offset, collection, reselem: Element):
|
||||||
|
xml_errors.check_attrib(reselem, {"Name", "Offset", "NumPaths"})
|
||||||
num_paths = int(reselem.attrib["NumPaths"])
|
num_paths = int(reselem.attrib["NumPaths"])
|
||||||
return PathListResourceDesc(symbol_name, offset, collection, reselem, num_paths)
|
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):
|
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()]
|
skel_type = SkeletonType[reselem.attrib["Type"].upper()]
|
||||||
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
|
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
|
||||||
return SkeletonResourceDesc(
|
return SkeletonResourceDesc(
|
||||||
|
@ -138,6 +159,7 @@ class LimbResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_Limb(symbol_name, offset, collection, reselem: Element):
|
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()]
|
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
|
||||||
return LimbResourceDesc(
|
return LimbResourceDesc(
|
||||||
symbol_name,
|
symbol_name,
|
||||||
|
@ -156,6 +178,7 @@ class LimbTableResourceDesc(ResourceDesc):
|
||||||
|
|
||||||
|
|
||||||
def handler_LimbTable(symbol_name, offset, collection, reselem: Element):
|
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()]
|
limb_type = LimbType[reselem.attrib["LimbType"].upper()]
|
||||||
count = int(reselem.attrib["Count"])
|
count = int(reselem.attrib["Count"])
|
||||||
return LimbTableResourceDesc(
|
return LimbTableResourceDesc(
|
||||||
|
@ -171,6 +194,7 @@ class CurveAnimationResourceDesc(ResourceDesc):
|
||||||
def handler_CurveAnimation(
|
def handler_CurveAnimation(
|
||||||
symbol_name, offset, collection: ResourcesDescCollection, reselem: Element
|
symbol_name, offset, collection: ResourcesDescCollection, reselem: Element
|
||||||
):
|
):
|
||||||
|
xml_errors.check_attrib(reselem, {"Name", "Offset", "SkelOffset"})
|
||||||
res = CurveAnimationResourceDesc(symbol_name, offset, collection, reselem, None)
|
res = CurveAnimationResourceDesc(symbol_name, offset, collection, reselem, None)
|
||||||
|
|
||||||
skel_offset = int(reselem.attrib["SkelOffset"], 16)
|
skel_offset = int(reselem.attrib["SkelOffset"], 16)
|
||||||
|
|
|
@ -129,7 +129,10 @@ def process_pool(
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f"alignment for {rescoll.start_address.vram=:#08X}"
|
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
|
alignment = 8
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(rescoll.start_address)
|
raise NotImplementedError(rescoll.start_address)
|
||||||
|
|
Loading…
Add table
Reference in a new issue