diff --git a/.cruft.json b/.cruft.json index 87fbe93..3c61eb5 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "git@github.com:bl-sdk/common_dotfiles.git", - "commit": "5404cb2bf2c71c7572667468d58f7518d6e340ef", + "commit": "6b31480199099e9957b18918373a75d979951919", "checkout": null, "context": { "cookiecutter": { diff --git a/.typos.toml b/.typos.toml index 50a3ebc..279be2f 100644 --- a/.typos.toml +++ b/.typos.toml @@ -7,6 +7,12 @@ extend-exclude = [ ".typos.toml" ] +[default] +extend-ignore-re = [ + # Ignore markdown links to github commits/trees + "\\[[0-9a-fA-F]+?\\]\\(https://github.com/.+?/.+?/(commit|tree)/.+?\\)", +] + [default.extend-identifiers] llibgcc_s_seh = "llibgcc_s_seh" diff --git a/CMakeLists.txt b/CMakeLists.txt index 3951f05..813733a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) -project(pyunrealsdk VERSION 1.2.0) +project(pyunrealsdk VERSION 1.3.0) function(_pyunrealsdk_add_base_target_args target_name) target_compile_features(${target_name} PUBLIC cxx_std_20) @@ -10,7 +10,13 @@ function(_pyunrealsdk_add_base_target_args target_name) EXPORT_COMPILE_COMMANDS True PREFIX "" ) - if(MINGW) + if(MSVC) + # Under MSVC, enable edit and continue in debug - which conflicts with LTO + set_target_properties(${target_name} PROPERTIES + MSVC_DEBUG_INFORMATION_FORMAT "$<$:EditAndContinue>" + INTERPROCEDURAL_OPTIMIZATION $ + ) + elseif(MINGW) # Under MinGW, only enable LTO in release mode - it causes linking errors in debug set_target_properties(${target_name} PROPERTIES INTERPROCEDURAL_OPTIMIZATION $ diff --git a/changelog.md b/changelog.md index 833878b..1273bd9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,20 @@ # Changelog +## v1.3.0 + +Also see the unrealsdk v1.3.0 changelog [here](https://github.com/bl-sdk/unrealsdk/blob/master/changelog.md#v130). + +- Added bindings for the new classes introduced in unrealsdk v1.3.0 - `WeakPointer`, + `ULazyObjectProperty`, `USoftObjectProperty`, and `USoftClassProperty` + + [18294df4](https://github.com/bl-sdk/pyunrealsdk/commit/18294df4), + [7e724f1e](https://github.com/bl-sdk/pyunrealsdk/commit/7e724f1e), + [6558e1cc](https://github.com/bl-sdk/pyunrealsdk/commit/6558e1cc) + +- Fixed that hooks could not always be removed after adding, or that they might not always fire. + + [unrealsdk@227a93d2](https://github.com/bl-sdk/unrealsdk/commit/227a93d2) + ## v1.2.0 Also see the unrealsdk v1.2.0 changelog [here](https://github.com/bl-sdk/unrealsdk/blob/master/changelog.md#v120). diff --git a/common_cmake b/common_cmake index b9d8e17..c27d687 160000 --- a/common_cmake +++ b/common_cmake @@ -1 +1 @@ -Subproject commit b9d8e17caa2165f68adf605cda42d5f3db5ed499 +Subproject commit c27d68718f01ca2e40fc2627fa7461b552a0d6ce diff --git a/libs/unrealsdk b/libs/unrealsdk index 3a5a40f..63bd2fb 160000 --- a/libs/unrealsdk +++ b/libs/unrealsdk @@ -1 +1 @@ -Subproject commit 3a5a40f7b25554f1814dbcd37d23f6cbef736a45 +Subproject commit 63bd2fb491c5e4071b871a0bbf7e1503e298eacd diff --git a/src/pyunrealsdk/unreal_bindings/bindings.cpp b/src/pyunrealsdk/unreal_bindings/bindings.cpp index f27b2ff..a8deeeb 100644 --- a/src/pyunrealsdk/unreal_bindings/bindings.cpp +++ b/src/pyunrealsdk/unreal_bindings/bindings.cpp @@ -1,10 +1,12 @@ #include "pyunrealsdk/pch.h" #include "pyunrealsdk/unreal_bindings/bindings.h" #include "pyunrealsdk/unreal_bindings/bound_function.h" +#include "pyunrealsdk/unreal_bindings/persistent_object_ptr_property.h" #include "pyunrealsdk/unreal_bindings/property_access.h" #include "pyunrealsdk/unreal_bindings/uenum.h" #include "pyunrealsdk/unreal_bindings/uobject.h" #include "pyunrealsdk/unreal_bindings/uobject_children.h" +#include "pyunrealsdk/unreal_bindings/weak_pointer.h" #include "pyunrealsdk/unreal_bindings/wrapped_array.h" #include "pyunrealsdk/unreal_bindings/wrapped_struct.h" #include "unrealsdk/unreal/classes/ufield.h" @@ -28,6 +30,8 @@ void register_module(py::module_& mod) { register_wrapped_array(unreal); register_wrapped_struct(unreal); register_bound_function(unreal); + register_weak_pointer(unreal); + register_persistent_object_properties(unreal); } } // namespace pyunrealsdk::unreal diff --git a/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.cpp b/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.cpp new file mode 100644 index 0000000..0ee69ef --- /dev/null +++ b/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.cpp @@ -0,0 +1,186 @@ +#include "pyunrealsdk/pch.h" +#include "unrealsdk/unreal/classes/properties/persistent_object_ptr_property.h" +#include "pyunrealsdk/unreal_bindings/bindings.h" +#include "pyunrealsdk/unreal_bindings/persistent_object_ptr_property.h" +#include "unrealsdk/unreal/classes/properties/uobjectproperty.h" +#include "unrealsdk/unreal/structs/tpersistentobjectptr.h" +#include "unrealsdk/unreal/wrappers/wrapped_array.h" +#include "unrealsdk/unreal/wrappers/wrapped_struct.h" + +#ifdef PYUNREALSDK_INTERNAL + +using namespace unrealsdk::unreal; + +namespace pyunrealsdk::unreal { + +namespace { + +/** + * @brief Call the relevant `get_from` overload given the args passed to the python function. + * @note Also ensures no null pointers. + * + * @tparam PathType The type of the path to get. + * @tparam PropertyType The type of the property associated with this path. + * @param source The source location. + * @param prop The property to get. + * @param idx The fixed array index. + * @return A pointer to the property's identifier. + */ +template +const PathType* resolve_get_from_overload( + const std::variant& source, + const std::variant& prop, + size_t idx) { + if (std::holds_alternative(source)) { + auto source_ptr = std::get(source); + if (source_ptr == nullptr) { + throw std::invalid_argument("Cannot get identifier from a null source!"); + } + + if (std::holds_alternative(prop)) { + return PathType::get_from(source_ptr, std::get(prop), idx); + } + + auto prop_ptr = std::get(prop); + if (prop_ptr == nullptr) { + throw std::invalid_argument("Cannot get identifier using a null property!"); + } + return PathType::get_from(source_ptr, prop_ptr, idx); + } + + auto source_ptr = std::get(source); + if (source_ptr == nullptr) { + throw std::invalid_argument("Cannot get identifier from a null source!"); + } + + if (std::holds_alternative(prop)) { + return PathType::get_from(*source_ptr, std::get(prop), idx); + } + + auto prop_ptr = std::get(prop); + if (prop_ptr == nullptr) { + throw std::invalid_argument("Cannot get identifier using a null property!"); + } + return PathType::get_from(*source_ptr, prop_ptr, idx); +} + +/** + * @brief Converts a lazy object path to it's python equivalent. + * + * @param path The path to convert. + * @return The python representation of the lazy object path. + */ +py::bytes lazy_obj_path_to_py(const FLazyObjectPath* path) { + // Just return the raw guid bytes for now, since it's probably the most neutral way + // of doing it, and this isn't likely to be used much anyway + + // Can't easily return a `Guid` struct since there are plenty of structs using that + // name, and the package of the core engine one we want changes between versions, so + // we can't really easily fully qualify it either + + return {reinterpret_cast(path), sizeof(*path)}; +} + +/** + * @brief Converts a soft object path to it's python equivalent. + * + * @param path The path to convert. + * @return The python representation of the soft object path. + */ +std::wstring soft_obj_path_to_py(const FSoftObjectPath* path) { + std::wstring name{path->asset_path_name}; + if (path->subpath.size() > 0) { + name.reserve(name.size() + path->subpath.size() + 1); + name += L':'; + name += (std::wstring_view)path->subpath; + } + return name; +} + +} // namespace + +void register_persistent_object_properties(py::module_& mod) { + PyUEClass(mod, "ULazyObjectProperty") + .def_static( + "_get_identifier_from", + [](const std::variant& source, + const std::variant& prop, size_t idx) { + auto path = resolve_get_from_overload( + source, prop, idx); + return lazy_obj_path_to_py(path); + }, + "Gets the Guid identifier associated with a given lazy object property.\n" + "\n" + "When using standard attribute access, lazy object properties resolve directly to\n" + "their contained object. This function can be used to get the identifier instead.\n" + "\n" + "Args:\n" + " source: The object or struct holding the property to get.\n" + " prop: The lazy object property, or name thereof, to get.\n" + " idx: If this property is a fixed sized array, which index to get.\n" + "Returns:\n" + " The raw 16 bytes composing the property's Guid.", + "source"_a, "prop"_a, "idx"_a = 0) + .def_static( + "_get_identifier_from_array", + [](const WrappedArray& source, size_t idx) { + auto path = FLazyObjectPath::get_from_array(source, idx); + return lazy_obj_path_to_py(path); + }, + "Gets the Guid identifier associated with a given lazy object property.\n" + "\n" + "When using standard attribute access, lazy object properties resolve directly to\n" + "their contained object. This function can be used to get the identifier instead.\n" + "\n" + "Args:\n" + " source: The array holding the property to get.\n" + " idx: The index into the array to get from.\n" + "Returns:\n" + " The raw 16 bytes composing the property's Guid.", + "source"_a, "idx"_a); + + PyUEClass(mod, "USoftObjectProperty") + .def_static( + "_get_identifier_from", + [](const std::variant& source, + const std::variant& prop, size_t idx) { + auto path = resolve_get_from_overload( + source, prop, idx); + return soft_obj_path_to_py(path); + }, + "Gets the path name identifier associated with a given soft object property.\n" + "\n" + "When using standard attribute access, soft object properties resolve directly to\n" + "their contained object. This function can be used to get the identifier instead.\n" + "\n" + "Args:\n" + " source: The object or struct holding the property to get.\n" + " prop: The soft object property, or name thereof, to get.\n" + " idx: If this property is a fixed sized array, which index to get.\n" + "Returns:\n" + " The path name of the object the given property is looking for.", + "source"_a, "prop"_a, "idx"_a = 0) + .def_static( + "_get_identifier_from_array", + [](const WrappedArray& source, size_t idx) { + auto path = FSoftObjectPath::get_from_array(source, idx); + return soft_obj_path_to_py(path); + }, + "Gets the path name identifier associated with a given soft object property.\n" + "\n" + "When using standard attribute access, soft object properties resolve directly to\n" + "their contained object. This function can be used to get the identifier instead.\n" + "\n" + "Args:\n" + " source: The array holding the property to get.\n" + " idx: The index into the array to get from.\n" + "Returns:\n" + " The path name of the object the given property is looking for.", + "source"_a, "idx"_a); + + PyUEClass(mod, "USoftClassProperty") + .def_property_readonly("MetaClass", &USoftClassProperty::get_meta_class); +} + +} // namespace pyunrealsdk::unreal +#endif diff --git a/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.h b/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.h new file mode 100644 index 0000000..7ca8f7e --- /dev/null +++ b/src/pyunrealsdk/unreal_bindings/persistent_object_ptr_property.h @@ -0,0 +1,21 @@ +#ifndef PYUNREALSDK_UNREAL_BINDINGS_PERSISTENT_OBJECT_PTR_PROPERTY_H +#define PYUNREALSDK_UNREAL_BINDINGS_PERSISTENT_OBJECT_PTR_PROPERTY_H + +#include "pyunrealsdk/pch.h" + +#ifdef PYUNREALSDK_INTERNAL + +namespace pyunrealsdk::unreal { + +/** + * @brief Registers the persistent object properties. + * + * @param module The module to register within. + */ +void register_persistent_object_properties(py::module_& mod); + +} // namespace pyunrealsdk::unreal + +#endif + +#endif /* PYUNREALSDK_UNREAL_BINDINGS_PERSISTENT_OBJECT_PTR_PROPERTY_H */ diff --git a/src/pyunrealsdk/unreal_bindings/uobject.cpp b/src/pyunrealsdk/unreal_bindings/uobject.cpp index e7c8958..6c7eb11 100644 --- a/src/pyunrealsdk/unreal_bindings/uobject.cpp +++ b/src/pyunrealsdk/unreal_bindings/uobject.cpp @@ -46,15 +46,14 @@ void register_uobject(py::module_& mod) { .def( "__repr__", [](UObject* self) { - return unrealsdk::fmt::format( - "{}'{}'", self->Class->Name, - unrealsdk::utils::narrow(unrealsdk::uobject_path_name(self))); + return unrealsdk::fmt::format("{}'{}'", self->Class->Name, + unrealsdk::utils::narrow(self->get_path_name())); }, "Gets this object's full name.\n" "\n" "Returns:\n" " This object's name.") - .def("_path_name", unrealsdk::uobject_path_name, + .def("_path_name", &UObject::get_path_name, "Gets this object's path name, excluding the class.\n" "\n" "Returns:\n" diff --git a/src/pyunrealsdk/unreal_bindings/uobject_children.cpp b/src/pyunrealsdk/unreal_bindings/uobject_children.cpp index 3de66ab..e06d414 100644 --- a/src/pyunrealsdk/unreal_bindings/uobject_children.cpp +++ b/src/pyunrealsdk/unreal_bindings/uobject_children.cpp @@ -1,9 +1,8 @@ #include "pyunrealsdk/pch.h" -#include "pyunrealsdk/unreal_bindings/uobject_children.h" #include "pyunrealsdk/unreal_bindings/bindings.h" -#include "pyunrealsdk/unreal_bindings/wrapped_struct.h" #include "unrealsdk/unreal/classes/properties/attribute_property.h" #include "unrealsdk/unreal/classes/properties/copyable_property.h" +#include "unrealsdk/unreal/classes/properties/persistent_object_ptr_property.h" #include "unrealsdk/unreal/classes/properties/uarrayproperty.h" #include "unrealsdk/unreal/classes/properties/uboolproperty.h" #include "unrealsdk/unreal/classes/properties/ubyteproperty.h" @@ -25,7 +24,6 @@ #include "unrealsdk/unreal/classes/uproperty.h" #include "unrealsdk/unreal/classes/uscriptstruct.h" #include "unrealsdk/unreal/classes/ustruct.h" -#include "unrealsdk/unreal/wrappers/wrapped_struct.h" #ifdef PYUNREALSDK_INTERNAL @@ -239,7 +237,14 @@ void register_uobject_children(py::module_& mod) { .def_property_readonly("OtherAttributeProperty", &UIntAttributeProperty::get_other_attribute_property); + // ULazyObjectProperty - registered elsewhere + // USoftObjectProperty - registered elsewhere + PyUEClass(mod, "UWeakObjectProperty"); + + // ======== Fifth Layer Subclasses ======== + + // USoftClassProperty - registered elsewhere } } // namespace pyunrealsdk::unreal diff --git a/src/pyunrealsdk/unreal_bindings/weak_pointer.cpp b/src/pyunrealsdk/unreal_bindings/weak_pointer.cpp new file mode 100644 index 0000000..0069b7f --- /dev/null +++ b/src/pyunrealsdk/unreal_bindings/weak_pointer.cpp @@ -0,0 +1,54 @@ +#include "pyunrealsdk/pch.h" +#include "unrealsdk/unreal/wrappers/weak_pointer.h" +#include "unrealsdk/unreal/classes/uobject.h" + +#ifdef PYUNREALSDK_INTERNAL + +using namespace unrealsdk::unreal; + +namespace pyunrealsdk::unreal { + +void register_weak_pointer(py::module_& mod) { + auto cls = py::class_(mod, "WeakPointer"); + cls.def(py::init(), + "Creates a weak reference to an unreal object.\n" + "\n" + "Under Unreal 3 this is emulated, as there's no built in support for weak\n" + "references. This means there's a very rare chance that this returns a different\n" + "object than what was it was set to, however it will be near identical, and it\n" + "will always be a valid object.\n" + "\n" + "Args:\n" + " obj: The object to create a weak reference to.", + "obj"_a) + .def( + "__call__", + // Take a mutable reference, since the mutable dereference can do some optimizations + [](WeakPointer& self) { return *self; }, + "Gets the object this is pointing at.\n" + "\n" + "Note that there's no way to get a strong reference to an unreal object. This\n" + "means if you're using this on a thread, it's always possible for the engine to\n" + "pull the object out from under you after you retrieve it. However, it *should*\n" + "be safe under a hook, since the GC shouldn't be running.\n" + "\n" + "Returns:\n" + " The object this is pointing at, or None if it's become invalid."); + + // Create as a class method, see pybind11#1693 + cls.attr("__class_getitem__") = py::reinterpret_borrow(PyClassMethod_New( + py::cpp_function([](const py::type& cls, const py::args& /*args*/, + const py::kwargs& /*kwargs*/) { return cls; }, + "No-op, implemented to allow type stubs to treat this as a generic type.\n" + "\n" + "Args:\n" + " *args: Ignored.\n" + " **kwargs: Ignored.\n" + "Returns:\n" + " The WeakPointer class.", + "cls"_a) + .ptr())); +} + +} // namespace pyunrealsdk::unreal +#endif diff --git a/src/pyunrealsdk/unreal_bindings/weak_pointer.h b/src/pyunrealsdk/unreal_bindings/weak_pointer.h new file mode 100644 index 0000000..51c4fed --- /dev/null +++ b/src/pyunrealsdk/unreal_bindings/weak_pointer.h @@ -0,0 +1,21 @@ +#ifndef PYUNREALSDK_UNREAL_BINDINGS_WEAK_POINTER_H +#define PYUNREALSDK_UNREAL_BINDINGS_WEAK_POINTER_H + +#include "pyunrealsdk/pch.h" + +#ifdef PYUNREALSDK_INTERNAL + +namespace pyunrealsdk::unreal { + +/** + * @brief Registers WeakPointer. + * + * @param module The module to register within. + */ +void register_weak_pointer(py::module_& mod); + +} // namespace pyunrealsdk::unreal + +#endif + +#endif /* PYUNREALSDK_UNREAL_BINDINGS_WEAK_POINTER_H */ diff --git a/stubs/Readme.md b/stubs/Readme.md index 3493e07..14f7386 100644 --- a/stubs/Readme.md +++ b/stubs/Readme.md @@ -47,4 +47,5 @@ module.parse() module.write() ``` -The output of both generators was manually combined to create these stubs. +The output of both generators was manually combined to create the initial version of these stubs. +Since then, they've been manually maintained as new features have been added. diff --git a/stubs/unrealsdk/unreal/__init__.pyi b/stubs/unrealsdk/unreal/__init__.pyi index e4bc8d4..21d40a6 100644 --- a/stubs/unrealsdk/unreal/__init__.pyi +++ b/stubs/unrealsdk/unreal/__init__.pyi @@ -23,10 +23,13 @@ from ._uobject_children import ( UInt64Property, UInterfaceProperty, UIntProperty, + ULazyObjectProperty, UNameProperty, UObjectProperty, UProperty, UScriptStruct, + USoftClassProperty, + USoftObjectProperty, UStrProperty, UStruct, UStructProperty, @@ -35,6 +38,7 @@ from ._uobject_children import ( UUInt32Property, UUInt64Property, ) +from ._weak_pointer import WeakPointer from ._wrapped_array import WrappedArray from ._wrapped_struct import WrappedStruct @@ -58,11 +62,14 @@ __all__: tuple[str, ...] = ( "UInt64Property", "UInterfaceProperty", "UIntProperty", + "ULazyObjectProperty", "UNameProperty", "UObject", "UObjectProperty", "UProperty", "UScriptStruct", + "USoftClassProperty", + "USoftObjectProperty", "UStrProperty", "UStruct", "UStructProperty", @@ -70,6 +77,7 @@ __all__: tuple[str, ...] = ( "UUInt16Property", "UUInt32Property", "UUInt64Property", + "WeakPointer", "WrappedArray", "WrappedStruct", "dir_includes_unreal", diff --git a/stubs/unrealsdk/unreal/_uobject_children.pyi b/stubs/unrealsdk/unreal/_uobject_children.pyi index b9b85a9..94e66c8 100644 --- a/stubs/unrealsdk/unreal/_uobject_children.pyi +++ b/stubs/unrealsdk/unreal/_uobject_children.pyi @@ -4,12 +4,18 @@ from collections.abc import Iterator from ._uenum import UEnum from ._uobject import UObject +from ._wrapped_array import WrappedArray +from ._wrapped_struct import WrappedStruct # ruff: noqa: N802, N803 +# ======== First Layer Subclasses ======== + class UField(UObject): Next: UField | None +# ======== Second Layer Subclasses ======== + class UConst(UField): Value: str @@ -91,6 +97,8 @@ class UStruct(UField): An iterator over all superfields in the struct. """ +# ======== Third Layer Subclasses ======== + class UArrayProperty(UProperty): @property def Inner(self) -> UProperty: ... @@ -170,6 +178,9 @@ class UTextProperty(UProperty): ... class UUInt16Property(UProperty): ... class UUInt32Property(UProperty): ... class UUInt64Property(UProperty): ... + +# ======== Fourth Layer Subclasses ======== + class UBlueprintGeneratedClass(UClass): ... class UByteAttributeProperty(UByteProperty): @@ -196,4 +207,84 @@ class UIntAttributeProperty(UByteProperty): @property def OtherAttributeProperty(self) -> UByteAttributeProperty | None: ... +class ULazyObjectProperty(UObjectProperty): + @staticmethod + def _get_identifier_from( + source: UObject | WrappedStruct, + prop: str | ULazyObjectProperty, + idx: int = 0, + ) -> bytes: + """ + Gets the Guid identifier associated with a given lazy object property. + + When using standard attribute access, lazy object properties resolve directly to + their contained object. This function can be used to get the identifier instead. + + Args: + source: The object or struct holding the property to get. + prop: The lazy object property, or name thereof, to get. + idx: If this property is a fixed sized array, which index to get. + Returns: + The raw 16 bytes composing the property's Guid. + """ + @staticmethod + def _get_identifier_from_array( + source: WrappedArray[UObject], + idx: int = 0, + ) -> bytes: + """ + Gets the Guid identifier associated with a given lazy object property. + + When using standard attribute access, lazy object properties resolve directly to + their contained object. This function can be used to get the identifier instead. + + Args: + source: The array holding the property to get. + idx: The index into the array to get from. + Returns: + The raw 16 bytes composing the property's Guid. + """ + +class USoftObjectProperty(UObjectProperty): + @staticmethod + def _get_identifier_from( + source: UObject | WrappedStruct, + prop: str | USoftObjectProperty, + idx: int = 0, + ) -> str: + """ + Gets the path name identifier associated with a given soft object property. + + When using standard attribute access, soft object properties resolve directly to + their contained object. This function can be used to get the identifier instead. + + Args: + source: The object or struct holding the property to get. + prop: The soft object property, or name thereof, to get. + idx: If this property is a fixed sized array, which index to get. + Returns: + The path name of the object the given property is looking for. + """ + @staticmethod + def _get_identifier_from_array( + source: WrappedArray[UObject], + idx: int = 0, + ) -> str: + """ + Gets the path name identifier associated with a given soft object property. + + When using standard attribute access, soft object properties resolve directly to + their contained object. This function can be used to get the identifier instead. + + Args: + source: The array holding the property to get. + idx: The index into the array to get from. + Returns: + The path name of the object the given property is looking for. + """ + class UWeakObjectProperty(UObjectProperty): ... + +# ======== Fifth Layer Subclasses ======== + +class USoftClassProperty(USoftObjectProperty): ... diff --git a/stubs/unrealsdk/unreal/_weak_pointer.pyi b/stubs/unrealsdk/unreal/_weak_pointer.pyi new file mode 100644 index 0000000..c40d154 --- /dev/null +++ b/stubs/unrealsdk/unreal/_weak_pointer.pyi @@ -0,0 +1,43 @@ +from types import GenericAlias +from typing import Any + +from ._uobject import UObject + +class WeakPointer[T: UObject = UObject]: + def __init__(self, obj: T) -> None: + """ + Creates a weak reference to an unreal object. + + Under Unreal 3 this is emulated, as there's no built in support for weak + references. This means there's a very rare chance that this returns a different + object than what was it was set to, however it will be near identical, and it + will always be a valid object. + + Args: + obj: The object to create a weak reference to. + """ + + def __call__(self) -> T | None: + """ + Gets the object this is pointing at. + + Note that there's no way to get a strong reference to an unreal object. This + means if you're using this on a thread, it's always possible for the engine to + pull the object out from under you after you retrieve it. However, it *should* + be safe under a hook, since the GC shouldn't be running. + + Returns: + The object this is pointing at, or None if it's become invalid. + """ + + @classmethod + def __class_getitem__(cls, *args: Any, **kwargs: Any) -> GenericAlias: + """ + No-op, implemented to allow type stubs to treat this as a generic type. + + Args: + *args: Ignored. + **kwargs: Ignored. + Returns: + The WeakPointer class. + """