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:
parent
ad6ff6df27
commit
e0b8f3087d
4 changed files with 112 additions and 7 deletions
|
@ -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
|
||||
)
|
||||
|
|
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,
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue