4141 UObject ,
4242 UObjectProperty ,
4343 UProperty ,
44- UScriptStruct ,
4544 UStrProperty ,
4645 UStruct ,
4746 UStructProperty ,
@@ -138,8 +137,11 @@ def ConstructObject(
138137 Error : None = None , # noqa: ARG001
139138 InstanceGraph : None = None , # noqa: ARG001
140139 bAssumeTemplateIsArchetype : int = 0 , # noqa: ARG001
141- ) -> UObject :
142- return construct_object (Class , Outer , Name , SetFlags , Template )
140+ ) -> UObject | None :
141+ try :
142+ return construct_object (Class , Outer , Name , SetFlags , Template )
143+ except RuntimeError :
144+ return None
143145
144146
145147type _SDKHook = Callable [[UObject , UFunction , FStruct ], bool | None ]
@@ -295,28 +297,11 @@ def KeepAlive(obj: UObject, /) -> None:
295297_default_func_call = BoundFunction .__call__
296298
297299
298- def _create_struct_from_tuples (struct : UScriptStruct , value : tuple [Any , ...]) -> WrappedStruct :
299- """
300- Recursively creates a wrapped struct from it's tuple equivalent.
301-
302- Args:
303- struct: The struct type to create:
304- value: The tuple to create it with.
305- Returns:
306- The new struct.
307- """
308- return WrappedStruct (
309- struct ,
310- * (
311- _create_struct_from_tuples (prop .Struct , inner_val ) # pyright: ignore[reportUnknownArgumentType]
312- if isinstance (prop , UStructProperty ) and isinstance (inner_val , tuple )
313- else inner_val
314- for prop , inner_val in zip (struct ._properties (), value , strict = False )
315- ),
316- )
317-
318-
319- def _convert_struct_tuple_if_required (prop : UProperty , value : Any ) -> Any :
300+ def _convert_struct_tuple_if_required (
301+ prop : UProperty ,
302+ value : Any ,
303+ _ignore_array_dim : bool = False ,
304+ ) -> Any :
320305 """
321306 Convert any tuple-based structs in the given value into Wrapped Structs.
322307
@@ -327,16 +312,29 @@ def _convert_struct_tuple_if_required(prop: UProperty, value: Any) -> Any:
327312 The possibly converted value.
328313 """
329314
315+ # If it's a fixed array of structs, need to convert each inner value
316+ if not _ignore_array_dim and prop .ArrayDim > 1 and isinstance (prop , UStructProperty ):
317+ return tuple (
318+ _convert_struct_tuple_if_required (prop , inner_val , _ignore_array_dim = True )
319+ for inner_val in value # type: ignore
320+ )
321+
330322 # If it's a struct being set as a tuple directly
331323 if isinstance (prop , UStructProperty ) and isinstance (value , tuple ):
332- return _create_struct_from_tuples (prop .Struct , value ) # pyright: ignore[reportUnknownArgumentType]
324+ return WrappedStruct (
325+ prop .Struct ,
326+ * (
327+ _convert_struct_tuple_if_required (inner_prop , inner_val )
328+ for inner_prop , inner_val in zip (prop .Struct ._properties (), value , strict = False ) # type: ignore
329+ ),
330+ )
333331
334332 # If it's an array of structs, need to convert each value
335333 if isinstance (prop , UArrayProperty ) and isinstance (prop .Inner , UStructProperty ):
336334 seq_value : Sequence [Any ] = value
337335
338336 return tuple (
339- _create_struct_from_tuples (prop .Inner . Struct , inner_val ) # pyright: ignore[reportUnknownArgumentType]
337+ _convert_struct_tuple_if_required (prop .Inner , inner_val )
340338 if isinstance (inner_val , tuple )
341339 else inner_val
342340 for inner_val in seq_value
@@ -432,6 +430,9 @@ def _uobject_setattr(self: UObject, name: str, value: Any) -> None:
432430
433431@wraps (UObject .__repr__ )
434432def _uobject_repr (self : UObject ) -> str :
433+ if self is None or self .Class is None : # type: ignore
434+ return "(null)"
435+
435436 current = self
436437 output = f"{ self .Name } "
437438 while current := current .Outer :
@@ -614,10 +615,24 @@ def _ustructproperty_get_struct(self: UStructProperty) -> UStruct:
614615
615616
616617@staticmethod
617- def uobject_path_name (obj : UObject , / ) -> str :
618+ def _uobject_path_name (obj : UObject , / ) -> str :
618619 return obj ._path_name ()
619620
620621
622+ def _wrapped_struct_structType_getter (self : WrappedStruct ) -> UStruct :
623+ return self ._type
624+
625+
626+ def _wrapped_struct_structType_setter (self : WrappedStruct , val : UStruct ) -> None :
627+ self ._type = val
628+
629+
630+ _wrapped_struct_structType = property ( # noqa: N816
631+ _wrapped_struct_structType_getter ,
632+ _wrapped_struct_structType_setter ,
633+ )
634+
635+
621636@contextmanager
622637def _unreal_method_compat_handler () -> Iterator [None ]:
623638 UObject .__getattr__ = _uobject_getattr
@@ -634,8 +649,9 @@ def _unreal_method_compat_handler() -> Iterator[None]:
634649
635650 UObject .FindObjectsContaining = _uobject_find_objects_containing # type: ignore
636651 UStructProperty .GetStruct = _ustructproperty_get_struct # type: ignore
637- UObject .PathName = uobject_path_name # type: ignore
652+ UObject .PathName = _uobject_path_name # type: ignore
638653 UObject .GetFullName = _uobject_repr # type: ignore
654+ WrappedStruct .structType = _wrapped_struct_structType # type: ignore
639655
640656 try :
641657 yield
@@ -656,6 +672,7 @@ def _unreal_method_compat_handler() -> Iterator[None]:
656672 del UStructProperty .GetStruct # type: ignore
657673 del UObject .PathName # type: ignore
658674 del UObject .GetFullName # type: ignore
675+ del WrappedStruct .structType # type: ignore
659676
660677
661678compat_handlers .append (_unreal_method_compat_handler )
0 commit comments