Skip to content

Commit

Permalink
clean up optional_list_casts
Browse files Browse the repository at this point in the history
There's now a helper function that enforces correct error handling when
casting lists of optionals.
  • Loading branch information
mrwonko committed Apr 3, 2024
1 parent 4a9525c commit 3128e93
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 20 deletions.
10 changes: 7 additions & 3 deletions JAG2GLA.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from . import JAG2Constants
from . import JAG2Math
from . import MrwProfiler
from .casts import optional_cast, downcast, bpy_generic_cast, matrix_getter_cast, matrix_overload_cast, optional_list_cast, vector_getter_cast
from .error_types import ErrorMessage, NoError
from .casts import optional_cast, downcast, bpy_generic_cast, matrix_getter_cast, matrix_overload_cast, vector_getter_cast
from .error_types import ErrorMessage, NoError, ensureListIsGapless

from typing import BinaryIO, Dict, List, Optional, Tuple
from enum import Enum
Expand Down Expand Up @@ -677,6 +677,7 @@ def loadFromBlender(self, gla_filepath_rel: str, gla_reference_abs: str) -> Tupl
absoluteBoneOffsets: List[Optional[mathutils.Matrix]] = [None] * self.header.numBones

unprocessed = list(range(self.header.numBones))
# FIXME: instead of doing this once per frame, cache the correct processing order
while len(unprocessed) > 0:
# make sure we're not looping infinitely (shouldn't be possible)
progressed = False
Expand Down Expand Up @@ -715,8 +716,11 @@ def loadFromBlender(self, gla_filepath_rel: str, gla_reference_abs: str) -> Tupl

assert (progressed)

gaplessRelativeBoneOffsets, err = ensureListIsGapless(relativeBoneOffsets)
if gaplessRelativeBoneOffsets is None:
return False, ErrorMessage(f"internal error: did not calculate all bone transformations: {err}")
# then write precalculated offsets:
for offset in optional_list_cast(List[mathutils.Matrix], relativeBoneOffsets):
for offset in gaplessRelativeBoneOffsets:

# compress that offset
compOffset = JAG2Math.CompBone.compress(offset)
Expand Down
29 changes: 14 additions & 15 deletions JAG2GLM.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
from . import JAMaterialmanager
from . import MrwProfiler
from . import JAG2Panels
from .casts import optional_cast, downcast, bpy_generic_cast, optional_list_cast, unpack_cast, matrix_getter_cast, vector_getter_cast, vector_overload_cast
from .error_types import ErrorMessage, NoError
from .casts import optional_cast, downcast, bpy_generic_cast, unpack_cast, matrix_getter_cast, vector_getter_cast, vector_overload_cast
from .error_types import ErrorMessage, NoError, ensureListIsGapless

import bpy
import mathutils
Expand Down Expand Up @@ -331,10 +331,10 @@ def addChildren(object: bpy.types.Object) -> Tuple[bool, ErrorMessage]:
success, message = addChildren(rootObject)
if not success:
return False, message
emptyIndices = [i for i, x in enumerate(surfaces) if x is None]
if len(emptyIndices) > 0: # a surface that was referenced did not get created
return False, ErrorMessage(f"Internal error during hierarchy creation! (Surfaces {emptyIndices} referenced but not created)")
self.surfaces = optional_list_cast(List[MdxmSurfaceData], surfaces)
gaplessSurfaces, err = ensureListIsGapless(surfaces)
if gaplessSurfaces is None:
return False, ErrorMessage(f"Internal error during hierarchy creation! (Missing Surfaces: {err})")
self.surfaces = gaplessSurfaces
return True, NoError

def saveToFile(self, file: BinaryIO) -> None:
Expand Down Expand Up @@ -629,11 +629,10 @@ def loadFromBlender(self, object: bpy.types.Object, surfaceData: MdxmSurfaceData
boneReferences: List[Optional[int]] = [None] * len(boneIndices)
for boneName, index in boneIndices.items():
boneReferences[index] = boneIndexMap[boneName]
missingIndices = [i for i, x in enumerate(boneReferences) if x is None]
if len(missingIndices) > 0:
return False, ErrorMessage(f"bug: boneIndexMap did not fill indices {missingIndices}")

self.boneReferences = optional_list_cast(List[int], boneReferences)
gaplessBoneReferences, err = ensureListIsGapless(boneReferences)
if gaplessBoneReferences is None:
return False, ErrorMessage(f"bug: boneIndexMap left gaps: {err}")
self.boneReferences = gaplessBoneReferences

self._calculateOffsets()
return True, NoError
Expand Down Expand Up @@ -855,13 +854,13 @@ def addChildren(dict, object):
surf.makeEmpty()
# add surface to list
surfaces[index] = surf
missingIndices = [i for i, x in enumerate(surfaces) if x is None]
if len(missingIndices) > 0:
return None, ErrorMessage(f"internal error: surface index map has missing indices {missingIndices}")
gaplessSurfaces, err = ensureListIsGapless(surfaces)
if gaplessSurfaces is None:
return None, ErrorMessage(f"internal error: surface index map incomplete: {err}")
return MdxmLOD(
surfaceOffsets=[], # FIXME: avoid this invalid state
level=level,
surfaces=optional_list_cast(List[MdxmSurface], surfaces),
surfaces=gaplessSurfaces,
ofsEnd=-1, # FIXME: avoid this invalid state
), NoError

Expand Down
5 changes: 4 additions & 1 deletion casts.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ def optional_cast(t: Type[T], v: Optional[T]) -> T:
return cast(t, v)


def optional_list_cast(t: Type[List[T]], v: List[Optional[T]]) -> List[T]: # TODO replace with error-returning helper
def optional_list_cast(t: Type[List[T]], v: List[Optional[T]]) -> List[T]:
"""
Avoid using this directly, use error_types.ensureListIsGapless instead.
"""
return cast(t, v)


Expand Down
15 changes: 14 additions & 1 deletion error_types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
from typing import NewType
from .mod_reload import reload_modules
reload_modules(locals(), __package__, [], [".casts"]) # nopep8

from typing import List, NewType, Optional, Tuple, TypeVar
from .casts import optional_list_cast

ErrorMessage = NewType("ErrorMessage", str)
NoError = ErrorMessage("")

T = TypeVar("T")


def ensureListIsGapless(l: List[Optional[T]]) -> Tuple[Optional[List[T]], ErrorMessage]:
emptyIndices = [i for i, x in enumerate(l) if x is None]
if len(emptyIndices) > 0: # a surface that was referenced did not get created
return None, ErrorMessage(f"unexpected None at indices {emptyIndices}")
return optional_list_cast(List[T], l), NoError

0 comments on commit 3128e93

Please sign in to comment.