diff --git a/Source/PythonConsole/Private/PythonScriptFactory.cpp b/Source/PythonConsole/Private/PythonScriptFactory.cpp index 1b1828a7c..a66e98dee 100644 --- a/Source/PythonConsole/Private/PythonScriptFactory.cpp +++ b/Source/PythonConsole/Private/PythonScriptFactory.cpp @@ -5,8 +5,6 @@ UPythonScriptFactory::UPythonScriptFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - Formats.Add(FString("py;Python Script")); - bCreateNew = false; bEditAfterNew = true; diff --git a/Source/UnrealEnginePython/Private/ConsoleManager/UEPyIConsoleManager.cpp b/Source/UnrealEnginePython/Private/ConsoleManager/UEPyIConsoleManager.cpp index cd39cd599..986152154 100644 --- a/Source/UnrealEnginePython/Private/ConsoleManager/UEPyIConsoleManager.cpp +++ b/Source/UnrealEnginePython/Private/ConsoleManager/UEPyIConsoleManager.cpp @@ -560,7 +560,7 @@ static PyObject *py_ue_iconsole_manager_register_command(PyObject *cls, PyObject return PyErr_Format(PyExc_Exception, "console object \"%s\" already exists", key); } - TSharedRef py_delegate = MakeShareable(new FPythonSmartConsoleDelegate); + TSharedRef py_delegate = MakeShared(); py_delegate->SetPyCallable(py_callable); FConsoleCommandWithArgsDelegate console_delegate; console_delegate.BindSP(py_delegate, &FPythonSmartConsoleDelegate::OnConsoleCommand); diff --git a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp index a4937b7e3..40ca5309c 100644 --- a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp +++ b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp @@ -1,9 +1,6 @@ - -#include "UEPyFbxObject.h" - #if ENGINE_MINOR_VERSION > 12 #if WITH_EDITOR - +#include "UEPyFbxObject.h" #include "UEPyFbx.h" #include "Runtime/Engine/Classes/Curves/RichCurve.h" @@ -238,8 +235,8 @@ static PyObject *py_ue_fbx_object_key_get_tangent_mode(ue_PyFbxObject *self, PyO ERichCurveTangentMode Mode = RCTM_Auto; // Convert the interpolation type from FBX to Unreal. - if (fbx_anim_curve->KeyGetInterpolation(index) == - FbxAnimCurveDef::eInterpolationCubic) + if ( fbx_anim_curve->KeyGetInterpolation(index) == + FbxAnimCurveDef::eInterpolationCubic ) { switch (fbx_anim_curve->KeyGetTangentMode(index)) { diff --git a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp index b6e513550..1ffd98446 100644 --- a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp +++ b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp @@ -18,6 +18,14 @@ static PyObject *py_ue_fbx_property_get_string(ue_PyFbxProperty *self, PyObject return PyUnicode_FromString(self->fbx_property.Get()); } +static PyObject *py_ue_fbx_property_get_bool(ue_PyFbxProperty *self, PyObject *args) { + return self->fbx_property.Get() ? Py_True : Py_False; +} + +static PyObject *py_ue_fbx_property_get_int(ue_PyFbxProperty *self, PyObject *args) { + return PyLong_FromLong(self->fbx_property.Get()); +} + static PyObject *py_ue_fbx_property_is_valid(ue_PyFbxProperty *self, PyObject *args) { if (self->fbx_property.IsValid()) { Py_RETURN_TRUE; @@ -49,6 +57,8 @@ static PyMethodDef ue_PyFbxProperty_methods[] = { { "get_name", (PyCFunction)py_ue_fbx_property_get_name, METH_VARARGS, "" }, { "get_double3", (PyCFunction)py_ue_fbx_property_get_double3, METH_VARARGS, "" }, { "get_string", (PyCFunction)py_ue_fbx_property_get_string, METH_VARARGS, "" }, + { "get_bool", (PyCFunction)py_ue_fbx_property_get_bool, METH_VARARGS, "" }, + { "get_int", (PyCFunction)py_ue_fbx_property_get_int, METH_VARARGS, "" }, { "is_valid", (PyCFunction)py_ue_fbx_property_is_valid, METH_VARARGS, "" }, { "get_curve_node", (PyCFunction)py_ue_fbx_property_get_curve_node, METH_VARARGS, "" }, { NULL } /* Sentinel */ diff --git a/Source/UnrealEnginePython/Private/PythonBlueprintFunctionLibrary.cpp b/Source/UnrealEnginePython/Private/PythonBlueprintFunctionLibrary.cpp index 2bef39d34..440284287 100644 --- a/Source/UnrealEnginePython/Private/PythonBlueprintFunctionLibrary.cpp +++ b/Source/UnrealEnginePython/Private/PythonBlueprintFunctionLibrary.cpp @@ -1,6 +1,7 @@ #include "PythonBlueprintFunctionLibrary.h" +#include "UEPyModule.h" void UPythonBlueprintFunctionLibrary::ExecutePythonScript(FString script) { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index 1aa92d703..11b64ffd3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -23,8 +23,7 @@ static PyObject *py_ue_fmenu_builder_end_section(ue_PyFMenuBuilder *self, PyObje static PyObject *py_ue_fmenu_builder_make_widget(ue_PyFMenuBuilder *self, PyObject * args) { - ue_PySWidget *ret = (ue_PySWidget *)PyObject_New(ue_PySWidget, &ue_PySWidgetType); - new (&ret->Widget) TSharedRef(self->menu_builder.MakeWidget()); + ue_PySWidget *ret = py_ue_new_swidget(self->menu_builder.MakeWidget(), &ue_PySWidgetType); return (PyObject *)ret; } @@ -34,8 +33,8 @@ static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyO char *tooltip; PyObject *py_callable; PyObject *py_obj = nullptr; - PyObject *py_uiaction_obj = nullptr; - if (!PyArg_ParseTuple(args, "ssO|OO:add_menu_entry", &label, &tooltip, &py_callable, &py_obj, &py_uiaction_obj)) + int ui_action_type = EUserInterfaceActionType::Button; + if (!PyArg_ParseTuple(args, "ssO|Oi:add_menu_entry", &label, &tooltip, &py_callable, &py_obj, &ui_action_type)) return nullptr; if (!PyCalllable_Check_Extended(py_callable)) @@ -57,9 +56,8 @@ static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyO handler.BindSP(py_delegate, &FPythonSlateDelegate::SimpleExecuteAction); } - ue_PyESlateEnums *py_uiaction_enum = py_uiaction_obj ? py_ue_is_eslate_enums(py_uiaction_obj) : nullptr; self->menu_builder.AddMenuEntry(FText::FromString(UTF8_TO_TCHAR(label)), FText::FromString(UTF8_TO_TCHAR(tooltip)), FSlateIcon(), FUIAction(handler), NAME_None, - py_uiaction_enum ? (EUserInterfaceActionType::Type)(py_uiaction_enum->val) : EUserInterfaceActionType::Button); + (EUserInterfaceActionType::Type)ui_action_type); Py_RETURN_NONE; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp index a3ff52b7f..74204ad94 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp @@ -1,5 +1,7 @@ #include "UEPyFSlateIcon.h" +#include "Engine/Texture2D.h" +#include "Engine/Engine.h" static PyObject *py_ue_fslate_icon_get_icon(ue_PyFSlateIcon *self, PyObject * args) { @@ -64,6 +66,44 @@ static int ue_py_fslate_icon_init(ue_PyFSlateIcon *self, PyObject *args, PyObjec PyErr_SetString(PyExc_ValueError, "you have not specified as style name"); return -1; } + + ISlateStyle const* const foundStyleSet = FSlateStyleRegistry::FindSlateStyle(FName(style_set)); + + const FSlateBrush * iconBrush = foundStyleSet->GetBrush(style); + FString Path = iconBrush->GetResourceName().ToString(); + + // Hack to load in the texture resource object of the icon brush in case it hasn't been already loaded + if (!Path.IsEmpty() && iconBrush->GetResourceObject() == nullptr) + { + if (Path.StartsWith(FSlateBrush::UTextureIdentifier())) + { + Path = Path.RightChop(FSlateBrush::UTextureIdentifier().Len()); + } + + UObject* TextureObject = LoadObject(NULL, *Path, NULL, LOAD_None, NULL); + FSlateBrush* Brush = const_cast(iconBrush); + + // Set the texture object to a default texture to prevent constant loading of missing textures + if (!TextureObject) + { + UE_LOG(LogSlate, Warning, TEXT("Error loading loading UTexture from path: %s not found"), *Path); + if (GEngine) + { + TextureObject = GEngine->DefaultTexture; + } + } + else + { + // We do this here because this deprecated system of loading textures will not report references and we dont want the Slate RHI resource manager to manage references + TextureObject->AddToRoot(); + } + + if (TextureObject) + { + Brush->SetResourceObject(TextureObject); + } + } + new(&self->icon) FSlateIcon(FName(style_set), FName(style)); } else diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp index ebea3c3d9..0d1fc2d3a 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp @@ -28,6 +28,14 @@ static PyObject *py_ue_fslate_style_set_register(ue_PyFSlateStyleSet *self, PyOb Py_RETURN_NONE; } +namespace { + template + void pySetWidgetStyle(FSlateStyleSet& InStyle, const FName PropertyName, void* InStyleDefintion) + { + InStyle.Set(PropertyName, *static_cast(InStyleDefintion)); + } +} + static PyObject *py_ue_fslate_style_set_set(ue_PyFSlateStyleSet *self, PyObject * args) { char *name; @@ -63,6 +71,52 @@ static PyObject *py_ue_fslate_style_set_set(ue_PyFSlateStyleSet *self, PyObject Py_RETURN_NONE; } + if (ue_py_check_childstruct(py_value)) + { + typedef TFunction WStyleSetter; + typedef TPair WStylePair; +#if ENGINE_MINOR_VERSION > 15 + static const WStylePair validWidgetStyleUStructList[] = { + WStylePair{ FTextBlockStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FButtonStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FCheckBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FComboButtonStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FComboBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FHyperlinkStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FEditableTextStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FScrollBarStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FEditableTextBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FInlineEditableTextBlockStyle::StaticStruct(), WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle(InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FProgressBarStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FExpandableAreaStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FSearchBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FSliderStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FVolumeControlStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FInlineTextImageStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FSpinBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FSplitterStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FTableRowStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FTableColumnHeaderStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FHeaderRowStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FDockTabStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FScrollBoxStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FScrollBorderStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + WStylePair{ FWindowStyle::StaticStruct() , WStyleSetter([](FSlateStyleSet& InStyle, FName InName, void* InWidgetStyleDef) { pySetWidgetStyle (InStyle, InName,InWidgetStyleDef); }) }, + }; + + + for(WStylePair widgetStyleUStruct : validWidgetStyleUStructList) + { + if (void* struct_data = do_ue_py_check_struct(py_value, widgetStyleUStruct.Key)) + { + widgetStyleUStruct.Value(*self->style_set, FName(name), struct_data); + Py_RETURN_NONE; + } + } +#endif + return PyErr_Format(PyExc_ValueError, "Unsupported FSlateWidgetStyle type. Add it manually to python plugin."); + } + ue_PyFLinearColor *py_linear_color = py_ue_is_flinearcolor(py_value); if (py_linear_color) { @@ -90,122 +144,123 @@ static PyObject *py_ue_fslate_style_set_set(ue_PyFSlateStyleSet *self, PyObject namespace { - template - PyObject* pyGetWidgetStyle(FSlateStyleSet& InStyle, FName PropertyName) - { - const WidgetStyleType styleWidgetStyle = InStyle.GetWidgetStyle(PropertyName); - return py_ue_new_uscriptstruct(WidgetStyleType::StaticStruct(), (uint8*)&styleWidgetStyle); - } + template + PyObject* pyGetWidgetStyle(FSlateStyleSet& InStyle, FName PropertyName) + { + const WidgetStyleType styleWidgetStyle = InStyle.GetWidgetStyle(PropertyName); + return py_ue_new_uscriptstruct(WidgetStyleType::StaticStruct(), (uint8*)&styleWidgetStyle); + } } static PyObject *py_ue_fslate_style_set_get(ue_PyFSlateStyleSet *self, PyObject * args) { - if (!(self && self->style_set)) - return PyErr_Format(PyExc_Exception, "fstyleset is in invalid state"); + if (!(self && self->style_set)) + return PyErr_Format(PyExc_Exception, "fstyleset is in invalid state"); - char *name = nullptr; - PyObject *py_type = nullptr; + char *name = nullptr; + PyObject *py_type = nullptr; if (!PyArg_ParseTuple(args, "sO:get", &name, &py_type)) return NULL; - PyObject *ret = nullptr; + PyObject *ret = nullptr; if (ue_py_check_struct(py_type)) { - const FSlateSound& styleSound = self->style_set->GetSound(FName(name)); - ret = py_ue_new_uscriptstruct(FSlateSound::StaticStruct(), (uint8*)&styleSound); + const FSlateSound& styleSound = self->style_set->GetSound(FName(name)); + ret = py_ue_new_uscriptstruct(FSlateSound::StaticStruct(), (uint8*)&styleSound); } else if (ue_py_check_struct(py_type)) { - if (const FSlateBrush* styleBrush = self->style_set->GetBrush(FName(name))) - { - ret = py_ue_new_uscriptstruct(FSlateBrush::StaticStruct(), (uint8*)styleBrush); - } + if (const FSlateBrush* styleBrush = self->style_set->GetBrush(FName(name))) + { + ret = py_ue_new_uscriptstruct(FSlateBrush::StaticStruct(), (uint8*)styleBrush); + } } else if (ue_py_check_struct(py_type)) { - const FSlateColor styleSlateColor = self->style_set->GetSlateColor(FName(name)); - ret = py_ue_new_uscriptstruct(FSlateColor::StaticStruct(), (uint8*)&styleSlateColor); + const FSlateColor styleSlateColor = self->style_set->GetSlateColor(FName(name)); + ret = py_ue_new_uscriptstruct(FSlateColor::StaticStruct(), (uint8*)&styleSlateColor); } - else if (ue_py_check_struct(py_type)) + else if (ue_py_check_struct(py_type)) { - const FSlateFontInfo styleFontInfo = self->style_set->GetFontStyle(FName(name)); - ret = py_ue_new_uscriptstruct(FSlateFontInfo::StaticStruct(), (uint8*)&styleFontInfo); + const FSlateFontInfo styleFontInfo = self->style_set->GetFontStyle(FName(name)); + ret = py_ue_new_uscriptstruct(FSlateFontInfo::StaticStruct(), (uint8*)&styleFontInfo); } - else if (ue_py_check_childstruct(py_type)) - { + else if (ue_py_check_childstruct(py_type)) + { - typedef TFunction WStyleGetter; - typedef TPair WStylePair; + typedef TFunction WStyleGetter; + typedef TPair WStylePair; #if ENGINE_MINOR_VERSION > 15 - static const WStylePair validWidgetStyleUStructList[] = { - WStylePair{ FTextBlockStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FButtonStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FComboButtonStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FComboBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FHyperlinkStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FEditableTextStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FScrollBarStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FEditableTextBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FInlineEditableTextBlockStyle::StaticStruct(), WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FProgressBarStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FExpandableAreaStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FSearchBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FSliderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FVolumeControlStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FInlineTextImageStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FSpinBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FSplitterStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FTableRowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FTableColumnHeaderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FHeaderRowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FDockTabStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FScrollBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FScrollBorderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - WStylePair{ FWindowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, - }; - - - for (WStylePair widgetStyleUStruct : validWidgetStyleUStructList) - { - if (do_ue_py_check_struct(py_type, widgetStyleUStruct.Key)) - { - ret = widgetStyleUStruct.Value(*self->style_set, FName(name)); - break; - } - } + static const WStylePair validWidgetStyleUStructList[] = { + WStylePair{ FTextBlockStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FButtonStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FCheckBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FComboButtonStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FComboBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FHyperlinkStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FEditableTextStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FScrollBarStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FEditableTextBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FInlineEditableTextBlockStyle::StaticStruct(), WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle(InStyle, InName); }) }, + WStylePair{ FProgressBarStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FExpandableAreaStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FSearchBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FSliderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FVolumeControlStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FInlineTextImageStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FSpinBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FSplitterStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FTableRowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FTableColumnHeaderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FHeaderRowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FDockTabStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FScrollBoxStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FScrollBorderStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + WStylePair{ FWindowStyle::StaticStruct() , WStyleGetter([](FSlateStyleSet& InStyle, FName InName) { return pyGetWidgetStyle (InStyle, InName); }) }, + }; + + + for(WStylePair widgetStyleUStruct : validWidgetStyleUStructList) + { + if (do_ue_py_check_struct(py_type, widgetStyleUStruct.Key)) + { + ret = widgetStyleUStruct.Value(*self->style_set, FName(name)); + break; + } + } #endif - - if (!ret) - { - return PyErr_Format(PyExc_ValueError, "Unsupported FSlateWidgetStyle type. Add it manually."); - } - } - else if (py_ue_is_flinearcolor(py_type)) - { - ret = py_ue_new_flinearcolor(self->style_set->GetColor(FName(name))); - } - else if (PyNumber_Check(py_type)) + + if (!ret) + { + return PyErr_Format(PyExc_ValueError, "Unsupported FSlateWidgetStyle type. Add it manually."); + } + } + else if (py_ue_is_flinearcolor(py_type)) { - ret = PyFloat_FromDouble(self->style_set->GetFloat(FName(name))); + ret = py_ue_new_flinearcolor(self->style_set->GetColor(FName(name))); } - else + else if (PyNumber_Check(py_type)) { - return PyErr_Format(PyExc_ValueError, "unsupported value type"); + ret = PyFloat_FromDouble(self->style_set->GetFloat(FName(name))); } + else + { + return PyErr_Format(PyExc_ValueError, "unsupported value type"); + } - if (!ret) - return PyErr_Format(PyExc_Exception, "Retrieved style object is in invalid state"); + if (!ret) + return PyErr_Format(PyExc_Exception, "Retrieved style object is in invalid state"); - return ret; + return ret; } static PyMethodDef ue_PyFSlateStyleSet_methods[] = { { "set_content_root", (PyCFunction)py_ue_fslate_style_set_set_content_root, METH_VARARGS, "" }, { "set", (PyCFunction)py_ue_fslate_style_set_set, METH_VARARGS, "" }, - { "get", (PyCFunction)py_ue_fslate_style_set_get, METH_VARARGS, "" }, + { "get", (PyCFunction)py_ue_fslate_style_set_get, METH_VARARGS, "" }, { "register", (PyCFunction)py_ue_fslate_style_set_register, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -255,16 +310,16 @@ static int ue_py_fslate_style_set_init(ue_PyFSlateStyleSet *self, PyObject *args { return -1; } - //TODO: roberto: ikrimae- I think this leaks? How is FSlateIcon destroyed ever? + //TODO: roberto: ikrimae- I think this leaks? How is FSlateIcon destroyed ever? self->style_set = new FSlateStyleSet(name); return 0; } ue_PyFSlateStyleSet* py_ue_new_fslate_style_set(FSlateStyleSet* styleSet) { - ue_PyFSlateStyleSet *ret = (ue_PyFSlateStyleSet *)PyObject_New(ue_PyFSlateStyleSet, &ue_PyFSlateStyleSetType); - ret->style_set = styleSet; - return ret; + ue_PyFSlateStyleSet *ret = (ue_PyFSlateStyleSet *)PyObject_New(ue_PyFSlateStyleSet, &ue_PyFSlateStyleSetType); + ret->style_set = styleSet; + return ret; } void ue_python_init_fslate_style_set(PyObject *ue_module) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp index 3832be0b8..efce049a5 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp @@ -52,15 +52,19 @@ static PyObject *py_ue_istructure_details_view_set_structure_data(ue_PyIStructur Py_XDECREF(self->ue_py_struct); self->ue_py_struct = ue_py_struct; Py_INCREF(self->ue_py_struct); - TSharedPtr struct_scope = MakeShared(ue_py_struct->u_struct, ue_py_struct->data); + TSharedPtr struct_scope = MakeShared(ue_py_struct->u_struct, py_ue_uscriptstruct_get_data(ue_py_struct)); FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); self->istructure_details_view->SetStructureData(struct_scope); -#if ENGINE_MINOR_VERSION > 17 +#if ENGINE_MINOR_VERSION > 16 if (py_force_refresh && PyObject_IsTrue(py_force_refresh)) { +#if ENGINE_MINOR_VERSION > 17 self->istructure_details_view->GetDetailsView()->ForceRefresh(); -} +#else + self->istructure_details_view->GetDetailsView().ForceRefresh(); +#endif + } #endif Py_RETURN_NONE; @@ -188,7 +192,7 @@ static int ue_py_istructure_details_view_init(ue_PyIStructureDetailsView *self, self->ue_py_struct = ue_py_struct; Py_INCREF(self->ue_py_struct); - TSharedPtr struct_scope = MakeShared(ue_py_struct->u_struct, ue_py_struct->data); + TSharedPtr struct_scope = MakeShared(ue_py_struct->u_struct, py_ue_uscriptstruct_get_data(ue_py_struct)); FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); new(&self->istructure_details_view) TSharedRef(PropertyEditorModule.CreateStructureDetailView(view_args, struct_view_args, struct_scope)); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp index 3aff74d85..cf6dd7496 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp @@ -22,7 +22,7 @@ static PyObject *py_ue_sborder_set_content(ue_PySBorder *self, PyObject * args) TSharedPtr child = py_ue_is_swidget(py_content); if (!child.IsValid()) - return nullptr; + { return nullptr; } py_SBorder->SetContent(child.ToSharedRef()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp index 5b46e2501..0f1fd0ae5 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp @@ -13,15 +13,49 @@ static PyObject *py_ue_sbox_set_content(ue_PySBox *self, PyObject * args) TSharedPtr child = py_ue_is_swidget(py_content); if (!child.IsValid()) - return nullptr; + { return nullptr; } py_SBox->SetContent(child.ToSharedRef()); Py_RETURN_SLATE_SELF; } +static PyObject *py_ue_sbox_set_height_override(ue_PySBox *self, PyObject * args) +{ + ue_py_slate_cast(SBox); + + float height_override = 0; + if (!PyArg_ParseTuple(args, "f:set_height_override", &height_override)) + { + return NULL; + } + + if (height_override != 0) + py_SBox->SetHeightOverride(height_override); + + Py_RETURN_NONE; +} + +static PyObject *py_ue_sbox_set_width_override(ue_PySBox *self, PyObject * args) +{ + ue_py_slate_cast(SBox); + + float width_override = 0; + if (!PyArg_ParseTuple(args, "f:set_width_override", &width_override)) + { + return NULL; + } + + if (width_override != 0) + py_SBox->SetWidthOverride(width_override); + + Py_RETURN_NONE; +} + static PyMethodDef ue_PySBox_methods[] = { { "set_content", (PyCFunction)py_ue_sbox_set_content, METH_VARARGS, "" }, + { "set_height_override", (PyCFunction)py_ue_sbox_set_height_override, METH_VARARGS, "" }, + { "set_width_override", (PyCFunction)py_ue_sbox_set_width_override, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -65,6 +99,7 @@ static int ue_py_sbox_init(ue_PySBox *self, PyObject *args, PyObject *kwargs) ue_py_slate_farguments_optional_enum("v_align", VAlign, EVerticalAlignment); ue_py_slate_farguments_struct("padding", Padding, FMargin); ue_py_slate_farguments_optional_foptional_size("height_override", HeightOverride); + ue_py_slate_farguments_optional_foptional_size("width_override", WidthOverride); #if ENGINE_MINOR_VERSION > 12 ue_py_slate_farguments_optional_foptional_size("max_aspect_ratio", MaxAspectRatio); #endif diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp index e8e241cd8..594778833 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp @@ -40,7 +40,7 @@ static PyObject *py_ue_scanvas_add_slot(ue_PySCanvas *self, PyObject * args, PyO TSharedPtr child = py_ue_is_swidget(py_content); if (!child.IsValid()) - return nullptr; + { return nullptr; } SCanvas::FSlot &fslot = py_SCanvas->AddSlot(); fslot.AttachWidget(child.ToSharedRef()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp index 5f734acd7..967113b4b 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp @@ -1,6 +1,27 @@ #include "UEPySCheckBox.h" +// Needed for PROPERTY_BINDING macro +#include "Widget.h" + +static PyObject *py_ue_scheck_box_set_content(ue_PySCheckBox *self, PyObject * args) +{ + ue_py_slate_cast(SCheckBox); + PyObject *py_content; + if (!PyArg_ParseTuple(args, "O:set_content", &py_content)) + { + return NULL; + } + + TSharedPtr child = py_ue_is_swidget(py_content); + if (!child.IsValid()) + { return nullptr; } + + py_SCheckBox->SetContent(child.ToSharedRef()); + + Py_RETURN_SLATE_SELF; +} + static PyObject *py_ue_scheck_box_is_checked(ue_PySCheckBox *self, PyObject * args) { ue_py_slate_cast(SCheckBox); @@ -8,12 +29,30 @@ static PyObject *py_ue_scheck_box_is_checked(ue_PySCheckBox *self, PyObject * ar { Py_RETURN_TRUE; } - + Py_RETURN_FALSE; } +static PyObject *py_ue_scheck_box_set_is_checked(ue_PySCheckBox *self, PyObject * args) { + ue_py_slate_cast(SCheckBox); + PyObject *py_bool; + if (!PyArg_ParseTuple(args, "O:set_is_checked", &py_bool)) + { + return NULL; + } + + ECheckBoxState CheckedState = PyObject_IsTrue(py_bool) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + + py_SCheckBox->SetIsChecked(TAttribute(CheckedState)); + + Py_RETURN_NONE; +} + + static PyMethodDef ue_PySCheckBox_methods[] = { { "is_checked", (PyCFunction)py_ue_scheck_box_is_checked, METH_VARARGS, "" }, + { "set_content", (PyCFunction)py_ue_scheck_box_set_content, METH_VARARGS, "" }, + { "set_is_checked", (PyCFunction)py_ue_scheck_box_set_is_checked, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -50,12 +89,30 @@ PyTypeObject ue_PySCheckBoxType = { static int ue_py_scheck_box_init(ue_PySCheckBox *self, PyObject *args, PyObject *kwargs) { - + ue_py_slate_setup_farguments(SCheckBox); + ue_py_slate_farguments_optional_struct_ptr("style", Style, FCheckBoxStyle); + ue_py_slate_farguments_optional_enum ("type", Type, ESlateCheckBoxType::Type); + ue_py_slate_farguments_event ("on_check_state_changed", OnCheckStateChanged, FOnCheckStateChanged, CheckBoxChanged); + ue_py_slate_farguments_enum ("is_checked", IsChecked, ECheckBoxState); + ue_py_slate_farguments_optional_enum ("h_align", HAlign, EHorizontalAlignment); + ue_py_slate_farguments_struct ("padding", Padding, FMargin); + ue_py_slate_farguments_enum ("click_method", ClickMethod, EButtonClickMethod::Type); ue_py_slate_farguments_struct("border_background_color", BorderBackgroundColor, FSlateColor); ue_py_slate_farguments_struct("foreground_color", ForegroundColor, FSlateColor); - ue_py_slate_farguments_enum("is_checked", IsChecked, ECheckBoxState); - ue_py_slate_farguments_event("on_check_state_changed", OnCheckStateChanged, FOnCheckStateChanged, CheckBoxChanged); + ue_py_slate_farguments_optional_bool ("is_focusable", IsFocusable); + ue_py_slate_farguments_event ("on_get_menu_content", OnGetMenuContent, FOnGetContent, OnGetMenuContent); + ue_py_slate_farguments_optional_struct_ptr("unchecked_image", UncheckedImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("unchecked_hoveredimage", UncheckedHoveredImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("unchecked_pressedimage", UncheckedPressedImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("checked_image", CheckedImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("checked_hoveredimage", CheckedHoveredImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("checked_pressedimage", CheckedPressedImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("undetermined_image", UndeterminedImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("undetermined_hoveredimage", UndeterminedHoveredImage, FSlateBrush); + ue_py_slate_farguments_optional_struct_ptr("undetermined_pressedimage", UndeterminedPressedImage, FSlateBrush); + + ue_py_snew(SCheckBox); return 0; @@ -65,6 +122,7 @@ void ue_python_init_scheck_box(PyObject *ue_module) { ue_PySCheckBoxType.tp_init = (initproc)ue_py_scheck_box_init; + ue_PySCheckBoxType.tp_call = (ternaryfunc)py_ue_scheck_box_set_content; ue_PySCheckBoxType.tp_base = &ue_PySCompoundWidgetType; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDirectoryPicker.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDirectoryPicker.cpp index bda93bbc3..4912e0858 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDirectoryPicker.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDirectoryPicker.cpp @@ -35,10 +35,10 @@ static int ue_py_sdirectory_picker_init(ue_PySDirectoryPicker *self, PyObject *a { ue_py_slate_setup_farguments(SDirectoryPicker); - ue_py_slate_farguments_optional_text("message", Message); - ue_py_slate_farguments_optional_string("directory", Directory); - ue_py_slate_farguments_optional_string("file", File); - ue_py_slate_farguments_bool("is_enabled", IsEnabled); + ue_py_slate_farguments_argument_text("message", Message); + ue_py_slate_farguments_argument_string("directory", Directory); + ue_py_slate_farguments_argument_string("file", File); + ue_py_slate_farguments_attribute_bool("is_enabled", IsEnabled); ue_py_slate_farguments_event("on_directory_changed", OnDirectoryChanged, FOnDirectoryChanged, OnStringChanged); ue_py_snew(SDirectoryPicker); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index d8beb88ad..6ea7501ab 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -1,5 +1,11 @@ #include "UEPySDockTab.h" +#include "SDockTab.h" +#include "Private/Framework/Docking/SDockingArea.h" +#include "SlateWindowHelper.h" +#include "WidgetPath.h" +#include "IMenu.h" +#include "SlateApplication.h" #include "UEPyFTabManager.h" @@ -17,6 +23,27 @@ static PyObject *py_ue_sdock_tab_set_label(ue_PySDockTab *self, PyObject * args) Py_RETURN_SLATE_SELF; } +static PyObject *py_ue_sdock_tab_set_on_tab_closed(ue_PySDockTab *self, PyObject * args) +{ + ue_py_slate_cast(SDockTab); + + PyObject *py_callable; + if (!PyArg_ParseTuple(args, "O:set_on_tab_closed", &py_callable)) + { + return NULL; + } + + if (!PyCalllable_Check_Extended(py_callable)) + return PyErr_Format(PyExc_Exception, "argument is not callable"); + + SDockTab::FOnTabClosedCallback onTabClosed; + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewSlateDelegate(py_SDockTab, py_callable); + onTabClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnTabClosed); + + py_SDockTab->SetOnTabClosed(onTabClosed); + Py_RETURN_NONE; +} + static PyObject *py_ue_sdock_tab_request_close_tab(ue_PySDockTab *self, PyObject * args) { ue_py_slate_cast(SDockTab); @@ -33,10 +60,53 @@ static PyObject *py_ue_sdock_tab_new_tab_manager(ue_PySDockTab *self, PyObject * return py_ue_new_ftab_manager(tab_manager); } + +static PyObject *py_ue_sdock_tab_bring_to_front(ue_PySDockTab *self, PyObject * args) +{ + ue_py_slate_cast(SDockTab); + TSharedPtr parentWindow = py_SDockTab->GetParentWindow(); + if (parentWindow.Get() != nullptr) + { + parentWindow->HACK_ForceToFront(); + } + Py_RETURN_NONE; +} + +static PyObject *py_ue_sdock_get_parent_window(ue_PySDockTab *self, PyObject * args) +{ + ue_py_slate_cast(SDockTab); + TSharedPtr ParentWindow = py_SDockTab->GetParentWindow(); + if (ParentWindow.IsValid()) + { + // Check to see if the widget exists already + ue_PySWidget *ret = ue_py_get_swidget(StaticCastSharedRef(ParentWindow.ToSharedRef())); + return (PyObject *)ret; + } + Py_RETURN_NONE; +} + +static PyObject *py_ue_sdock_get_docking_area(ue_PySDockTab *self, PyObject * args) +{ + ue_py_slate_cast(SDockTab); + TSharedPtr DockingArea = py_SDockTab->GetDockArea(); + if (DockingArea.IsValid()) + { + ue_PySWidget *ret = nullptr; + // Checks to see if the widget exists already, is added to mapping if not + ret = ue_py_get_swidget(StaticCastSharedRef(DockingArea.ToSharedRef())); + return (PyObject *)ret; + } + Py_RETURN_NONE; +} + static PyMethodDef ue_PySDockTab_methods[] = { { "set_label", (PyCFunction)py_ue_sdock_tab_set_label, METH_VARARGS, "" }, + { "set_on_tab_closed", (PyCFunction)py_ue_sdock_tab_set_on_tab_closed, METH_VARARGS, "" }, { "request_close_tab", (PyCFunction)py_ue_sdock_tab_request_close_tab, METH_VARARGS, "" }, + { "bring_to_front", (PyCFunction)py_ue_sdock_tab_bring_to_front, METH_VARARGS, "" }, { "new_tab_manager", (PyCFunction)py_ue_sdock_tab_new_tab_manager, METH_VARARGS, "" }, + { "get_parent_window", (PyCFunction)py_ue_sdock_get_parent_window, METH_VARARGS, "" }, + { "get_docking_area", (PyCFunction)py_ue_sdock_get_docking_area, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -75,12 +145,20 @@ static int ue_py_sdock_tab_init(ue_PySDockTab *self, PyObject *args, PyObject *k { ue_py_slate_setup_farguments(SDockTab); - ue_py_slate_farguments_struct("content_padding", ContentPadding, FMargin); - ue_py_slate_farguments_optional_struct_ptr("icon", Icon, FSlateBrush); - ue_py_slate_farguments_text("label", Label); - ue_py_slate_farguments_optional_bool("should_autosize", ShouldAutosize); - ue_py_slate_farguments_optional_enum("tab_role", TabRole, ETabRole); - + ue_py_slate_farguments_default_slot ("content", Content); + ue_py_slate_farguments_named_slot ("tab_well_content_left", TabWellContentLeft); + ue_py_slate_farguments_named_slot ("tab_well_content_right", TabWellContentRight); + ue_py_slate_farguments_named_slot ("tab_well_content_background", TabWellContentBackground); + ue_py_slate_farguments_attribute_struct ("content_padding", ContentPadding, FMargin); + ue_py_slate_farguments_argument_enum ("tab_role", TabRole, ETabRole); + ue_py_slate_farguments_attribute_text ("label", Label); + ue_py_slate_farguments_argument_struct_ptr ("icon", Icon, FSlateBrush); + ue_py_slate_farguments_attribute_event ("on_tab_closed", OnTabClosed, SDockTab::FOnTabClosedCallback, OnTabClosed); + ue_py_slate_farguments_attribute_event ("on_tab_activated", OnTabActivated, SDockTab::FOnTabActivatedCallback, OnTabActivated); + ue_py_slate_farguments_argument_bool ("should_autosize", ShouldAutosize); + ue_py_slate_farguments_attribute_event ("on_can_close_tab", OnCanCloseTab, SDockTab::FCanCloseTab, OnCanCloseTab); + ue_py_slate_farguments_attribute_event ("on_persist_visual_state", OnPersistVisualState, SDockTab::FOnPersistVisualState, OnPersistVisualState); + ue_py_slate_farguments_attribute_flinear_color("tab_color_scale", TabColorScale); ue_py_snew(SDockTab); return 0; @@ -98,3 +176,10 @@ void ue_python_init_sdock_tab(PyObject *ue_module) Py_INCREF(&ue_PySDockTabType); PyModule_AddObject(ue_module, "SDockTab", (PyObject *)&ue_PySDockTabType); } + +ue_PySDockTab* py_ue_is_sdock_tab(PyObject *obj) +{ + if (!PyObject_IsInstance(obj, (PyObject *)&ue_PySDockTabType)) + return nullptr; + return (ue_PySDockTab* )obj; +} diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h index f1be66f1b..84bdec4c1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h @@ -13,3 +13,5 @@ typedef struct } ue_PySDockTab; void ue_python_init_sdock_tab(PyObject *); + +ue_PySDockTab* py_ue_is_sdock_tab(PyObject *obj); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp new file mode 100644 index 000000000..2b4537020 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp @@ -0,0 +1,101 @@ + +#include "UEPySExpandableArea.h" +#include "UEPySCheckBox.h" + + +static PyObject *py_ue_sexpandable_area_is_expanded(ue_PySCheckBox *self, PyObject * args) +{ + ue_py_slate_cast(SExpandableArea); + if (py_SExpandableArea->IsExpanded()) { + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + +static PyObject *py_ue_sexpandable_area_set_expanded(ue_PySCheckBox *self, PyObject * args) +{ + ue_py_slate_cast(SExpandableArea); + PyObject *py_bool; + if (!PyArg_ParseTuple(args, "O:set_expanded", &py_bool)) + { + return NULL; + } + + py_SExpandableArea->SetExpanded(PyObject_IsTrue(py_bool) ? true : false); + + Py_RETURN_NONE; +} + +static PyMethodDef ue_PySExpandableArea_methods[] = { + { "is_expanded", (PyCFunction)py_ue_sexpandable_area_is_expanded, METH_VARARGS, "" }, + { "set_expanded", (PyCFunction)py_ue_sexpandable_area_set_expanded, METH_VARARGS, "" }, + { NULL } /* Sentinel */ +}; + +PyTypeObject ue_PySExpandableAreaType = { + PyVarObject_HEAD_INIT(NULL, 0) + "unreal_engine.SExpandableArea", /* tp_name */ + sizeof(ue_PySExpandableArea), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Unreal Engine SExpandableArea", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ue_PySExpandableArea_methods, /* tp_methods */ +}; + +static int ue_py_sexpandable_area_init(ue_PySExpandableArea *self, PyObject *args, PyObject *kwargs) +{ + ue_py_slate_setup_farguments(SExpandableArea); + ue_py_slate_farguments_argument_struct_ptr("style", Style, FExpandableAreaStyle); + ue_py_slate_farguments_attribute_struct ("border_background_color", BorderBackgroundColor, FSlateColor); + ue_py_slate_farguments_argument_struct_ptr("border_image", BorderImage, FSlateBrush); + ue_py_slate_farguments_attribute_struct ("body_border_background_color", BodyBorderBackgroundColor, FSlateColor); + ue_py_slate_farguments_argument_struct_ptr("body_border_image", BodyBorderImage, FSlateBrush); + ue_py_slate_farguments_named_slot ("header_content", HeaderContent); + ue_py_slate_farguments_named_slot ("body_content", BodyContent); + ue_py_slate_farguments_attribute_text ("area_title", AreaTitle); + ue_py_slate_farguments_argument_bool ("initially_collapsed", InitiallyCollapsed); + ue_py_slate_farguments_argument_float ("min_width", MinWidth); + ue_py_slate_farguments_argument_float ("max_height", MaxHeight); + ue_py_slate_farguments_attribute_struct ("area_title_padding", AreaTitlePadding, FMargin); + ue_py_slate_farguments_attribute_struct ("header_padding", HeaderPadding, FMargin); + ue_py_slate_farguments_attribute_struct ("padding", Padding, FMargin); + ue_py_slate_farguments_event ("on_area_expansion_changed", OnAreaExpansionChanged, FOnBooleanValueChanged, OnBoolChanged); + ue_py_slate_farguments_struct ("area_title_font", AreaTitleFont, FSlateFontInfo); + + ue_py_snew(SExpandableArea); + return 0; +} + +void ue_python_init_sexpandable_area(PyObject *ue_module) +{ + ue_PySExpandableAreaType.tp_init = (initproc)ue_py_sexpandable_area_init; + ue_PySExpandableAreaType.tp_base = &ue_PySCompoundWidgetType; + + if (PyType_Ready(&ue_PySExpandableAreaType) < 0) + return; + + Py_INCREF(&ue_PySExpandableAreaType); + PyModule_AddObject(ue_module, "SExpandableArea", (PyObject *)&ue_PySExpandableAreaType); +} diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.h b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.h new file mode 100644 index 000000000..6c0eeba75 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.h @@ -0,0 +1,12 @@ +#pragma once + +#include "UnrealEnginePython.h" + +#include "UEPySCompoundWidget.h" + +typedef struct { + ue_PySCompoundWidget s_compound_widget; + /* Type-specific fields go here. */ +} ue_PySExpandableArea; + +void ue_python_init_sexpandable_area(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp new file mode 100644 index 000000000..9a208e7d6 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp @@ -0,0 +1,85 @@ + +#include "UEPySExpanderArrow.h" + + +static PyMethodDef ue_PySExpanderArrow_methods[] = { + { NULL } /* Sentinel */ +}; + +static void ue_PySExpanderArrow_dealloc(ue_PySExpanderArrow *self) +{ +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySExpanderArrow %p"), self); +#endif + + Py_XDECREF(self->owner_row_py); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +PyTypeObject ue_PySExpanderArrowType = { + PyVarObject_HEAD_INIT(NULL, 0) + "unreal_engine.SExpanderArrow", /* tp_name */ + sizeof(ue_PySExpanderArrow), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)ue_PySExpanderArrow_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Unreal Engine SExpanderArrow", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ue_PySExpanderArrow_methods, /* tp_methods */ +}; + +static int ue_py_sexpander_arrow_init(ue_PySExpanderArrow *self, PyObject *args, PyObject *kwargs) +{ + PyObject *py_object = nullptr; + if (!PyArg_ParseTuple(args, "O", &py_object)) + { + return -1; + } + + ue_PySPythonMultiColumnTableRow* py_owner_table_row = py_ue_is_spython_multicolumn_table_row(py_object); + if (!py_owner_table_row) { + PyErr_SetString(PyExc_Exception, "Argument is not a SPythonMultiColumnTableRow"); + return -1; + } + + ue_py_slate_setup_farguments(SExpanderArrow); + ue_py_slate_farguments_attribute_float("indent_amount", IndentAmount); + ue_py_slate_farguments_attribute_int("base_indent_level", BaseIndentLevel); + ue_py_snew_with_args(SExpanderArrow, py_ue_is_swidget((PyObject*)py_owner_table_row).ToSharedRef()); + + self->owner_row_py = py_owner_table_row; + Py_INCREF(py_owner_table_row); + + return 0; +} + +void ue_python_init_sexpander_arrow(PyObject *ue_module) +{ + ue_PySExpanderArrowType.tp_init = (initproc)ue_py_sexpander_arrow_init; + ue_PySExpanderArrowType.tp_base = &ue_PySCompoundWidgetType; + + if (PyType_Ready(&ue_PySExpanderArrowType) < 0) + return; + + Py_INCREF(&ue_PySExpanderArrowType); + PyModule_AddObject(ue_module, "SExpanderArrow", (PyObject *)&ue_PySExpanderArrowType); +} diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.h b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.h new file mode 100644 index 000000000..53ac20021 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.h @@ -0,0 +1,18 @@ +#pragma once + +#include "UnrealEnginePython.h" + + +#include "UEPySPythonMultiColumnTableRow.h" + +#include "Runtime/Slate/Public/Widgets/Views/SExpanderArrow.h" + +extern PyTypeObject ue_PySExpanderArrowType; + +typedef struct { + ue_PySCompoundWidget s_compound_widget; + /* Type-specific fields go here. */ + ue_PySPythonMultiColumnTableRow* owner_row_py; +} ue_PySExpanderArrow; + +void ue_python_init_sexpander_arrow(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySGraphPanel.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySGraphPanel.cpp index 349cd1c1b..0d42ac763 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySGraphPanel.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySGraphPanel.cpp @@ -4,11 +4,10 @@ #if ENGINE_MINOR_VERSION > 15 -#define sw_graph_panel StaticCastSharedRef(self->s_nodePanel.s_panel.s_widget) - /* static PyObject *py_ue_sgraph_panel_add_slot(ue_PySGraphPanel* self, PyObject *args, PyObject *kwargs) { + ue_py_slate_cast(SGraphPanel); PyObject *py_content; int z_order = -1; int h_align = 0; @@ -41,9 +40,8 @@ static PyObject *py_ue_sgraph_panel_add_slot(ue_PySGraphPanel* self, PyObject *a Py_INCREF(py_swidget); self->s_nodePanel.s_panel.s_widget.py_swidget_slots.Add(py_swidget); - sw_graph_panel; - - SOverlay::FOverlaySlot &fslot = sw_graph_panel->//sw_overlay->AddSlot(z_order); + + SOverlay::FOverlaySlot &fslot = py_SGraphPanel-> fslot.AttachWidget(py_swidget->s_widget->AsShared()); fslot.HAlign((EHorizontalAlignment)h_align); if (padding) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp index 6598a6bd9..ac912c2e8 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp @@ -45,16 +45,9 @@ static PyObject *py_ue_sheader_row_add_column(ue_PySHeaderRow *self, PyObject *a ue_py_slate_farguments_bool("should_generate_widget", ShouldGenerateWidget); - //sw_header_row->AddColumn( - // SHeaderRow::Column(FName(UTF8_TO_TCHAR(column_id))) - // .DefaultLabel(FText::FromString(UTF8_TO_TCHAR(default_label))) - // .DefaultTooltip(FText::FromString(UTF8_TO_TCHAR(default_tooltip))) - // .FixedWidth(fixed_width) - // .HAlignCell((EHorizontalAlignment)cell_h_align) - // .VAlignCell((EVerticalAlignment)cell_v_align) - //); - py_SHeaderRow->AddColumn(arguments); + + ue_py_slate_track_delegates(py_SHeaderRow); return 0; }(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp index 579615ebb..51cab4bdd 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp @@ -14,6 +14,7 @@ static PyObject *py_ue_shorizontal_box_add_slot(ue_PySHorizontalBox *self, PyObj ue_py_slate_farguments_optional_enum("v_align", VAlign, EVerticalAlignment); ue_py_slate_farguments_call("auto_width", AutoWidth); ue_py_slate_farguments_padding("padding", Padding); + ue_py_slate_track_delegates(py_SHorizontalBox); return 0; }(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySLevelViewport.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySLevelViewport.cpp index fd8cce68b..a623bd183 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySLevelViewport.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySLevelViewport.cpp @@ -79,7 +79,7 @@ static PyObject *py_ue_slevel_viewport_set_exposure_settings(ue_PySLevelViewport /* PyObject *py_ue_spython_editor_viewport_simulate(ue_PySLevelViewport *self, PyObject * args) { - sw_python_editor_viewport->GetViewportClient()->SetIsSimulateInEditorViewport(true); + py_SLevelViewport->GetViewportClient()->SetIsSimulateInEditorViewport(true); Py_RETURN_NONE; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp index 3652785b3..abfb6bade 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp @@ -31,7 +31,7 @@ static PyObject *py_ue_soverlay_add_slot(ue_PySOverlay *self, PyObject * args, P TSharedPtr Child = py_ue_is_swidget(py_content); if (!Child.IsValid()) - return nullptr; + { return nullptr; } SOverlay::FOverlaySlot &fslot = py_SOverlay->AddSlot(z_order); fslot.AttachWidget(Child.ToSharedRef()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp index 1babd8d3a..42ad27bf9 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp @@ -31,14 +31,17 @@ static PyObject *py_ue_spython_combo_box_set_selected_item(ue_PySPythonComboBox return nullptr; } - for (TSharedPtr item : *(py_SPythonComboBox->PythonOptionsSource)) + for (TSharedPtr& item : self->options_source_list) { // just for being safe - if (!item.IsValid()) - continue; - if (py_item == item->py_object) - { - py_SPythonComboBox->SetSelectedItem(item); + if (!item.IsValid()) + { + continue; + } + + if (py_item == item.Get()->py_object) + { + py_SPythonComboBox->SetSelectedItem(item); break; } } @@ -46,19 +49,72 @@ static PyObject *py_ue_spython_combo_box_set_selected_item(ue_PySPythonComboBox Py_RETURN_SLATE_SELF; } +static PyObject *py_ue_spython_combo_box_update_options_source_list(ue_PySPythonComboBox *self, PyObject * args) +{ + ue_py_slate_cast(SPythonComboBox); + + PyObject *values; + if (!PyArg_ParseTuple(args, "O:update_options_source_list", &values)) + { + return NULL; + } + + values = PyObject_GetIter(values); + if (!values) { + return PyErr_Format(PyExc_Exception, "argument is not an iterable"); + } + + //NOTE: ikrimae: Increment first so we don't decrement and destroy python objects that + //we're passing in e.g. if you pass the same item source array into update_items(). + //Might not be necessary but I'm not too familiar with python's GC + TArray> tempNewArray; + while (PyObject *item = PyIter_Next(values)) { + Py_INCREF(item); + tempNewArray.Add(TSharedPtr(new FPythonItem(item))); + } + + for (TSharedPtr& item : self->options_source_list) + { + Py_XDECREF(item->py_object); + } + self->options_source_list.Empty(); + + Move>>(self->options_source_list, tempNewArray); + py_SPythonComboBox->RefreshOptions(); + + Py_RETURN_NONE; +} + static PyMethodDef ue_PySPythonComboBox_methods[] = { { "clear_selection", (PyCFunction)py_ue_spython_combo_box_clear_selection, METH_VARARGS, "" }, { "get_selected_item", (PyCFunction)py_ue_spython_combo_box_get_selected_item, METH_VARARGS, "" }, { "set_selected_item", (PyCFunction)py_ue_spython_combo_box_set_selected_item, METH_VARARGS, "" }, + { "update_options_source_list", (PyCFunction)py_ue_spython_combo_box_update_options_source_list, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; +static void ue_PySPythonComboBox_dealloc(ue_PySPythonComboBox *self) +{ +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySPythonComboBox %p"), self); +#endif + + for (TSharedPtr& item : self->options_source_list) + { + Py_XDECREF(item->py_object); + } + self->options_source_list.Empty(); + self->options_source_list.~TArray(); + + Py_TYPE(self)->tp_free((PyObject *)self); +} + PyTypeObject ue_PySPythonComboBoxType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.SPythonComboBox", /* tp_name */ sizeof(ue_PySPythonComboBox), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor)ue_PySPythonComboBox_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -100,33 +156,25 @@ static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *ar if (!values) { PyErr_SetString(PyExc_Exception, "values field is not an iterable"); + Py_DECREF(values); return -1; } - TArray> *items = new TArray>(); + new(&self->options_source_list) TArray>(); while (PyObject *item = PyIter_Next(values)) { Py_INCREF(item); - items->Add(TSharedPtr(new FPythonItem(item))); + self->options_source_list.Add(TSharedPtr(new FPythonItem(item))); } - Py_DECREF(values); - - arguments.OptionsSource(items); + arguments.OptionsSource(&self->options_source_list); + //TODO: ikrimae: #ThirdParty-Python: #BUG: We are on purpose not doing Py_DECREF(values) because we're stealing the reference from _GetIter + // But we never decref values in the dealloc function. We should store a py_ref to the python list + // Ask roberto for the new refactored way for this - TSharedPtr child = nullptr; - - PyObject *content = ue_py_dict_get_item(kwargs, "content"); - if (content) - { - child = py_ue_is_swidget(content); - if (!child.IsValid()) - { - return -1; - } - arguments.Content()[child.ToSharedRef()]; - } + ue_py_slate_farguments_optional_named_slot("content", Content); ue_py_slate_farguments_optional_struct_ptr("button_style", ButtonStyle, FButtonStyle); + ue_py_slate_farguments_optional_struct_ptr("combobox_style", ComboBoxStyle, FComboBoxStyle); ue_py_slate_farguments_struct("content_padding", ContentPadding, FMargin); #if ENGINE_MINOR_VERSION > 13 ue_py_slate_farguments_optional_bool("enable_gamepad_navigation_mode", EnableGamepadNavigationMode); @@ -148,9 +196,6 @@ static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *ar ue_py_slate_cast(SPythonComboBox); - // keep track of the list, so we can delete on destruction - py_SPythonComboBox->PythonOptionsSource = items; - return 0; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.h index d07faa423..56139703f 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.h @@ -8,19 +8,15 @@ extern PyTypeObject ue_PySPythonComboBoxType; -class SPythonComboBox : public SComboBox> { -public: - ~SPythonComboBox() { - if (PythonOptionsSource) - delete(PythonOptionsSource); - } - - const TArray> *PythonOptionsSource; +class SPythonComboBox : public SComboBox> +{ + }; typedef struct { ue_PySPanel s_panel; /* Type-specific fields go here. */ + TArray> options_source_list; } ue_PySPythonComboBox; void ue_python_init_spython_combo_box(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp index 649b842ca..61ae7febb 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp @@ -91,7 +91,7 @@ static PyObject *py_ue_spython_editor_viewport_set_view_location(ue_PySPythonEdi { return PyErr_Format(PyExc_Exception, "argument is not a FVector"); } - vec = ue_py_vec->vec; + vec = py_ue_fvector_get(ue_py_vec); } else { @@ -123,7 +123,7 @@ static PyObject *py_ue_spython_editor_viewport_set_view_rotation(ue_PySPythonEdi { return PyErr_Format(PyExc_Exception, "argument is not a FRotator"); } - rot = ue_py_rot->rot; + rot = py_ue_frotator_get(ue_py_rot); } else { @@ -186,7 +186,7 @@ static PyObject *py_ue_spython_editor_viewport_set_light_direction(ue_PySPythonE { return PyErr_Format(PyExc_Exception, "argument is not a FRotator"); } - rot = ue_py_rot->rot; + rot = py_ue_frotator_get(ue_py_rot); } else { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp index 79f9fed20..82e0a75f0 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp @@ -3,12 +3,6 @@ #include "UEPySHeaderRow.h" - -void SPythonListView::SetHeaderRow(TSharedPtr InHeaderRowWidget) -{ - HeaderRow = InHeaderRowWidget; -} - static PyObject *py_ue_spython_list_view_get_selected_items(ue_PySPythonListView *self, PyObject * args) { ue_py_slate_cast(SPythonListView); @@ -39,25 +33,7 @@ static PyObject *py_ue_spython_list_view_get_num_items_selected(ue_PySPythonList return PyLong_FromLong(py_SPythonListView->GetNumItemsSelected()); } -static PyObject *py_ue_spython_list_view_set_header_row(ue_PySPythonListView *self, PyObject * args) -{ - ue_py_slate_cast(SPythonListView); - PyObject *py_content; - if (!PyArg_ParseTuple(args, "O:set_header_row", &py_content)) - { - return nullptr; - } - - TSharedPtr HeaderRow = py_ue_is_swidget(py_content); - if (!HeaderRow.IsValid()) - { - return nullptr; - } - - py_SPythonListView->SetHeaderRow(HeaderRow); - Py_RETURN_SLATE_SELF; -} static PyObject *py_spython_list_view_update_item_source_list(ue_PySPythonListView *self, PyObject * args) { @@ -97,7 +73,6 @@ static PyMethodDef ue_PySPythonListView_methods[] = { { "get_selected_items", (PyCFunction)py_ue_spython_list_view_get_selected_items, METH_VARARGS, "" }, { "get_num_items_selected", (PyCFunction)py_ue_spython_list_view_get_num_items_selected, METH_VARARGS, "" }, { "clear_selection", (PyCFunction)py_ue_spython_list_view_clear_selection, METH_VARARGS, "" }, - { "set_header_row", (PyCFunction)py_ue_spython_list_view_set_header_row, METH_VARARGS, "" }, { "update_item_source_list", (PyCFunction)py_spython_list_view_update_item_source_list, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -113,6 +88,7 @@ static void ue_PySPythonListView_dealloc(ue_PySPythonListView *self) Py_XDECREF(item->py_object); } self->item_source_list.Empty(); + self->item_source_list.~TArray(); Py_TYPE(self)->tp_free((PyObject *)self); } @@ -164,6 +140,7 @@ static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *ar values = PyObject_GetIter(values); if (!values) { + PyErr_SetString(PyExc_Exception, "list_items_source field is not an iterable"); Py_DECREF(values); return -1; } @@ -175,6 +152,9 @@ static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *ar self->item_source_list.Add(TSharedPtr(new FPythonItem(item))); } arguments.ListItemsSource(&self->item_source_list); + //TODO: ikrimae: #ThirdParty-Python: #BUG: We are on purpose not doing Py_DECREF(values) because we're stealing the reference from _GetIter + // But we never decref values in the dealloc function. We should store a py_ref to the python list + // Ask roberto for the new refactored way for this { PyObject *value = ue_py_dict_get_item(kwargs, "header_row"); @@ -202,6 +182,7 @@ static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *ar ue_py_slate_farguments_event("on_generate_row", OnGenerateRow, TSlateDelegates>::FOnGenerateRow, GenerateRow); ue_py_slate_farguments_event("on_selection_changed", OnSelectionChanged, TSlateDelegates>::FOnSelectionChanged, OnSelectionChanged); ue_py_slate_farguments_enum("selection_mode", SelectionMode, ESelectionMode::Type); + ue_py_slate_farguments_event("on_context_menu_opening", OnContextMenuOpening, FOnContextMenuOpening, OnContextMenuOpening); #if ENGINE_MINOR_VERSION > 12 ue_py_slate_farguments_optional_float("wheel_scroll_multiplier", WheelScrollMultiplier); #endif diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h index 482a4e23e..b5036ce20 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h @@ -4,22 +4,17 @@ extern PyTypeObject ue_PySPythonListViewType; -class SPythonListView : public SListView> +class SPythonListView : public SListView> { public: - ~SPythonListView() - { - delete(ItemsSource); - } - void SetHeaderRow(TSharedPtr InHeaderRowWidget); }; typedef struct { ue_PySListView s_list_view; /* Type-specific fields go here. */ - TArray> item_source_list; + TArray> item_source_list; } ue_PySPythonListView; void ue_python_init_spython_list_view(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp index 4f40f1106..d90c3f741 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp @@ -4,16 +4,44 @@ #include "UEPySTableViewBase.h" +static PyObject *py_ue_spython_multicolumn_table_row_set_first_column_name(ue_PySPythonMultiColumnTableRow *self, PyObject * args) +{ + ue_py_slate_cast(SPythonMultiColumnTableRow); + + char* column_name = nullptr; + if (!PyArg_ParseTuple(args, "s:set_first_column_name", &column_name)) + { + return nullptr; + } + + py_SPythonMultiColumnTableRow->SetFirstColumnName(FName(column_name)); + + Py_RETURN_NONE; +} + static PyMethodDef ue_PySPythonMultiColumnTableRow_methods[] = { + { "set_first_column_name", (PyCFunction)py_ue_spython_multicolumn_table_row_set_first_column_name, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; + +static void ue_PySPythonMultiColumnTableRow_dealloc(ue_PySPythonMultiColumnTableRow *self) +{ +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySPythonMultiColumnTableRow %p"), self); +#endif + + Py_XDECREF(self->owner_table); + Py_TYPE(self)->tp_free((PyObject *)self); +} + + PyTypeObject ue_PySPythonMultiColumnTableRowType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.SPythonMultiColumnTableRow", /* tp_name */ sizeof(ue_PySPythonMultiColumnTableRow), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor)ue_PySPythonMultiColumnTableRow_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -56,9 +84,11 @@ static int ue_py_spython_multicolumn_table_row_init(ue_PySPythonMultiColumnTable } Py_INCREF(py_owner_table_view_base); + self->owner_table = py_owner_table_view_base; + ue_py_snew_simple_with_req_args( SPythonMultiColumnTableRow, - StaticCastSharedRef(py_owner_table_view_base->s_compound_widget.s_widget.Widget), + StaticCastSharedRef(((ue_PySWidget*)py_owner_table_view_base)->Widget), (PyObject *)self); return 0; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h index 4ed260580..aba2c2353 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h @@ -1,103 +1,134 @@ #pragma once #include "UEPySCompoundWidget.h" +#include "UEPySTableViewBase.h" extern PyTypeObject ue_PySCompoundWidgetType; extern PyTypeObject ue_PySTableViewBaseType; class SPythonMultiColumnTableRow : public SMultiColumnTableRow> { public: - SLATE_BEGIN_ARGS(SPythonMultiColumnTableRow) {} - SLATE_END_ARGS(); - - void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTableView, PyObject *in_py_self) - { - SetPyObject(in_py_self); - SMultiColumnTableRow>::Construct(FSuperRowType::FArguments(), InOwnerTableView); - } - - TSharedRef GenerateWidgetForColumn(const FName& ColumnName) - { - FScopePythonGIL gil; - - if (!PyObject_HasAttrString(self, (char *)"generate_widget_for_column")) - return SNullWidget::NullWidget; - - PyObject *py_callable_generate_widget_for_column = PyObject_GetAttrString(self, (char *)"generate_widget_for_column"); - if (!PyCalllable_Check_Extended(py_callable_generate_widget_for_column)) - { - UE_LOG(LogPython, Error, TEXT("generate_widget_for_column is not a callable")); - return SNullWidget::NullWidget; - } - - PyObject *ret = PyObject_CallFunction(py_callable_generate_widget_for_column, (char *)"s", TCHAR_TO_UTF8(*ColumnName.ToString())); - if (!ret) - { - unreal_engine_py_log_error(); - return SNullWidget::NullWidget; - } + SLATE_BEGIN_ARGS(SPythonMultiColumnTableRow) { } + SLATE_END_ARGS(); + + void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTableView, PyObject *in_py_self) + { + SetPyObject(in_py_self); + FSuperRowType::Construct(FSuperRowType::FArguments(), InOwnerTableView); + } + + virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override + { + FScopePythonGIL gil; + + if (!PyObject_HasAttrString(self, (char *)"generate_widget_for_column")) + return SNullWidget::NullWidget; + + PyObject *py_callable_generate_widget_for_column = PyObject_GetAttrString(self, (char *)"generate_widget_for_column"); + if (!PyCalllable_Check_Extended(py_callable_generate_widget_for_column)) + { + UE_LOG(LogPython, Error, TEXT("generate_widget_for_column is not a callable")); + return SNullWidget::NullWidget; + } + + PyObject *ret = PyObject_CallFunction(py_callable_generate_widget_for_column, (char *)"s", TCHAR_TO_UTF8(*ColumnName.ToString())); + if (!ret) + { + unreal_engine_py_log_error(); + return SNullWidget::NullWidget; + } TSharedPtr Widget = py_ue_is_swidget(ret); if (!Widget.IsValid()) - { - Py_DECREF(ret); - UE_LOG(LogPython, Error, TEXT("returned value is not a SWidget")); - return SNullWidget::NullWidget; - } - - Py_DECREF(ret); - return Widget.ToSharedRef(); - } - - - FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) - { - FScopePythonGIL gil; - - if (PyObject_HasAttrString(self, (char *)"on_mouse_button_double_click")) - { - PyObject *py_callable_on_mouse_button_double_click = PyObject_GetAttrString(self, (char *)"on_mouse_button_double_click"); - if (!PyCalllable_Check_Extended(py_callable_on_mouse_button_double_click)) - { - UE_LOG(LogPython, Error, TEXT("on_mouse_button_double_click is not a callable")); - return FReply::Unhandled(); - } - - PyObject *ret = PyObject_CallFunction(py_callable_on_mouse_button_double_click, (char *)"OO", py_ue_new_fgeometry(InMyGeometry), py_ue_new_fpointer_event(InMouseEvent)); - if (!ret) - { - unreal_engine_py_log_error(); - return FReply::Unhandled(); - } - - if (ret == Py_False) - { - Py_DECREF(ret); - return FReply::Unhandled(); - } - Py_DECREF(ret); - return FReply::Handled(); - } - else - { - return SPythonMultiColumnTableRow::OnMouseButtonDoubleClick(InMyGeometry, InMouseEvent); - } - } - - void SetPyObject(PyObject *py_obj) - { - self = py_obj; - } + { + Py_DECREF(ret); + UE_LOG(LogPython, Error, TEXT("returned value is not a SWidget")); + return SNullWidget::NullWidget; + } + + if (ColumnName == firstColumnName && OwnerTablePtr.Pin()->GetTableViewMode() == ETableViewMode::Tree) + { + // Rows in a tree need to show an SExpanderArrow (it also indents!) to give the appearance of being a tree. + TSharedRef value = SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Top) + [ + SNew(SExpanderArrow, SharedThis(this)) + ] + +SHorizontalBox::Slot() + .AutoWidth() + [ + Widget.ToSharedRef() + ]; + Py_DECREF(ret); + return value; + } + else + { + // Lists do not need an expander arrow + Py_DECREF(ret); + return Widget.ToSharedRef(); + } + } + + + FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) + { + FScopePythonGIL gil; + + if (PyObject_HasAttrString(self, (char *)"on_mouse_button_double_click")) + { + PyObject *py_callable_on_mouse_button_double_click = PyObject_GetAttrString(self, (char *)"on_mouse_button_double_click"); + if (!PyCalllable_Check_Extended(py_callable_on_mouse_button_double_click)) + { + UE_LOG(LogPython, Error, TEXT("on_mouse_button_double_click is not a callable")); + return FReply::Unhandled(); + } + + PyObject *ret = PyObject_CallFunction(py_callable_on_mouse_button_double_click, (char *)"OO", py_ue_new_fgeometry(InMyGeometry), py_ue_new_fpointer_event(InMouseEvent)); + if (!ret) + { + unreal_engine_py_log_error(); + return FReply::Unhandled(); + } + + if (ret == Py_False) + { + Py_DECREF(ret); + return FReply::Unhandled(); + } + Py_DECREF(ret); + return FReply::Handled(); + } + else + { + return FSuperRowType::OnMouseButtonDoubleClick(InMyGeometry, InMouseEvent); + } + } + + void SetPyObject(PyObject *py_obj) + { + self = py_obj; + } + + void SetFirstColumnName(FName InFirstColName) + { + firstColumnName = InFirstColName; + } private: - PyObject * self = nullptr; + PyObject *self = nullptr; - TSharedPtr RowPythonObject; + TSharedPtr RowPythonObject; + + FName firstColumnName = FName("friendlyName"); }; typedef struct { - ue_PySCompoundWidget s_compound_widget; + ue_PySCompoundWidget s_compound_widget; /* Type-specific fields go here. */ + ue_PySTableViewBase* owner_table; } ue_PySPythonMultiColumnTableRow; void ue_python_init_spython_multicolumn_table_row(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.h index 9861d4176..de1e61051 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.h @@ -1,7 +1,7 @@ #pragma once #include "UnrealEnginePython.h" - +#if WITH_EDITOR #include "UEPySCompoundWidget.h" extern PyTypeObject ue_PySPythonShelfType; @@ -12,3 +12,4 @@ typedef struct { } ue_PySPythonShelf; void ue_python_init_spython_shelf(PyObject *); +#endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp index 5815ca2c5..4d1965921 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp @@ -2,9 +2,24 @@ #include "UEPySPythonTreeView.h" #include "Runtime/Slate/Public/Widgets/Views/STreeView.h" +#include "UEPySHeaderRow.h" + +TSharedPtr const* SPythonTreeView::Find(PyObject *item) +{ + for (const TSharedPtr& PythonItem : *ItemsSource) + { + if (PythonItem->py_object == item) + { + return &PythonItem; + } + } + return nullptr; +} + + static PyObject *py_ue_spython_tree_view_set_item_expansion(ue_PySPythonTreeView *self, PyObject * args) { ue_py_slate_cast(SPythonTreeView); @@ -14,32 +29,165 @@ static PyObject *py_ue_spython_tree_view_set_item_expansion(ue_PySPythonTreeView { return nullptr; } - py_SPythonTreeView->SetPythonItemExpansion(py_item, PyObject_IsTrue(py_bool) ? true : false); + + if (TSharedPtr const* foundItem = py_SPythonTreeView->Find(py_item)) + { + py_SPythonTreeView->SetItemExpansion(*foundItem, PyObject_IsTrue(py_bool) ? true : false); + } + Py_RETURN_NONE; } -void SPythonTreeView::SetPythonItemExpansion(PyObject *item, bool InShouldExpandItem) +static PyObject *py_ue_spython_tree_view_is_item_expanded(ue_PySPythonTreeView *self, PyObject * args) { - for (TSharedPtr PythonItem : *ItemsSource) + ue_py_slate_cast(SPythonTreeView); + + PyObject *py_item; + if (!PyArg_ParseTuple(args, "O:is_item_expanded", &py_item)) { - if (PythonItem->py_object == item) + return nullptr; + } + + if (TSharedPtr const* foundItem = py_SPythonTreeView->Find(py_item)) + { + bool bItemExpanded = py_SPythonTreeView->IsItemExpanded(*foundItem); + if (bItemExpanded) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + } + + Py_RETURN_NONE; +} + +static PyObject *py_ue_spython_tree_view_get_selected_items(ue_PySPythonTreeView *self, PyObject * args) +{ + ue_py_slate_cast(SPythonTreeView); + + PyObject *py_list = PyList_New(0); + + TArray> items = py_SPythonTreeView->GetSelectedItems(); + + for (TSharedPtr& item : items) { + PyList_Append(py_list, item->py_object); + } + + return py_list; +} + +static PyObject *py_ue_spython_tree_view_get_expanded_items(ue_PySPythonTreeView *self, PyObject * args) +{ + ue_py_slate_cast(SPythonTreeView); + + PyObject *py_list = PyList_New(0); + + TSet > ExpandedItems; + py_SPythonTreeView->GetExpandedItems(ExpandedItems); + + for (TSharedPtr& item : ExpandedItems) { + PyList_Append(py_list, item->py_object); + } + + return py_list; +} + +static PyObject *py_ue_spython_tree_view_clear_selection(ue_PySPythonTreeView *self, PyObject * args) +{ + ue_py_slate_cast(SPythonTreeView); + + py_SPythonTreeView->ClearSelection(); + + Py_RETURN_NONE; +} + +static PyObject *py_ue_spython_tree_view_get_num_items_selected(ue_PySPythonTreeView *self, PyObject * args) +{ + ue_py_slate_cast(SPythonTreeView); + return PyLong_FromLong(py_SPythonTreeView->GetNumItemsSelected()); +} + +static PyObject *py_ue_spython_tree_view_update_item_source_list(ue_PySPythonTreeView *self, PyObject * args) +{ + ue_py_slate_cast(SPythonTreeView); + + PyObject *values; + if (!PyArg_ParseTuple(args, "O:update_item_source_list", &values)) { - SetItemExpansion(PythonItem, InShouldExpandItem); - } + return NULL; + } + + values = PyObject_GetIter(values); + if (!values) + { + return PyErr_Format(PyExc_Exception, "argument is not an iterable"); + } + + TSet> expanded_items; + py_SPythonTreeView->GetExpandedItems(expanded_items); + + //NOTE: ikrimae: Increment first so we don't decrement and destroy python objects that + //we're passing in e.g. if you pass the same item source array into update_items(). + //Might not be necessary but I'm not too familiar with python's GC + TArray> tempNewArray; + while (PyObject *item = PyIter_Next(values)) { + Py_INCREF(item); + tempNewArray.Add(MakeShared(item)); } + + for (TSharedPtr& item : self->item_source_list) +{ + Py_XDECREF(item->py_object); + } + self->item_source_list.Empty(); + + Move>>(self->item_source_list, tempNewArray); + + for (TSharedPtr& old_item : expanded_items) + { + for (TSharedPtr& new_item : self->item_source_list) + { + if (old_item->py_object == new_item->py_object) + { + py_SPythonTreeView->SetItemExpansion(new_item, true); + } + } + } + + Py_RETURN_NONE; } static PyMethodDef ue_PySPythonTreeView_methods[] = { + { "get_selected_items", (PyCFunction) py_ue_spython_tree_view_get_selected_items, METH_VARARGS, "" }, + { "get_expanded_items", (PyCFunction)py_ue_spython_tree_view_get_expanded_items, METH_VARARGS, "" }, + { "get_num_items_selected", (PyCFunction) py_ue_spython_tree_view_get_num_items_selected, METH_VARARGS, "" }, + { "clear_selection", (PyCFunction) py_ue_spython_tree_view_clear_selection, METH_VARARGS, "" }, + { "update_item_source_list", (PyCFunction)py_ue_spython_tree_view_update_item_source_list, METH_VARARGS, "" }, { "set_item_expansion", (PyCFunction)py_ue_spython_tree_view_set_item_expansion, METH_VARARGS, "" }, + { "is_item_expanded", (PyCFunction)py_ue_spython_tree_view_is_item_expanded, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; +static void ue_PySPythonTreeView_dealloc(ue_PySPythonTreeView *self) +{ +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySPythonTreeView %p"), self); +#endif + + for (TSharedPtr& item : self->item_source_list) + { + Py_XDECREF(item->py_object); + } + self->item_source_list.Empty(); + + Py_TYPE(self)->tp_free((PyObject *)self); +} + PyTypeObject ue_PySPythonTreeViewType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.SPythonTreeView", /* tp_name */ sizeof(ue_PySPythonTreeView), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor)ue_PySPythonTreeView_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -81,27 +229,46 @@ static int ue_py_spython_tree_view_init(ue_PySPythonTreeView *self, PyObject *ar values = PyObject_GetIter(values); if (!values) { - PyErr_SetString(PyExc_Exception, "values field is not an iterable"); + PyErr_SetString(PyExc_Exception, "tree_items_source field is not an iterable"); + Py_DECREF(values); return -1; } - TArray> *items = new TArray>(); + new(&self->item_source_list) TArray>(); while (PyObject *item = PyIter_Next(values)) { Py_INCREF(item); - items->Add(TSharedPtr(new FPythonItem(item))); + // keep track of items + self->item_source_list.Add(MakeShared(item)); } - Py_DECREF(values); + arguments.TreeItemsSource(&self->item_source_list); - arguments.TreeItemsSource(items); + { + PyObject *value = ue_py_dict_get_item(kwargs, "header_row"); + if (value) { + if (ue_PySHeaderRow *_py_swidget = py_ue_is_sheader_row(value)) { + + Py_INCREF(_py_swidget); + arguments.HeaderRow(StaticCastSharedRef(((ue_PySWidget *)_py_swidget)->Widget)); + } + else { + PyErr_SetString(PyExc_TypeError, "unsupported type for attribute " "header_row"); + return -1; + } + } + } ue_py_slate_farguments_optional_enum("allow_overscroll", AllowOverscroll, EAllowOverscroll); ue_py_slate_farguments_optional_bool("clear_selection_on_click", ClearSelectionOnClick); ue_py_slate_farguments_optional_enum("consume_mouse_wheel", ConsumeMouseWheel, EConsumeMouseWheel); +#if ENGINE_MINOR_VERSION > 12 + ue_py_slate_farguments_optional_bool("handle_gamepad_events", HandleGamepadEvents); +#endif ue_py_slate_farguments_float("item_height", ItemHeight); ue_py_slate_farguments_event("on_generate_row", OnGenerateRow, TSlateDelegates>::FOnGenerateRow, GenerateRow); ue_py_slate_farguments_event("on_selection_changed", OnSelectionChanged, TSlateDelegates>::FOnSelectionChanged, OnSelectionChanged); ue_py_slate_farguments_enum("selection_mode", SelectionMode, ESelectionMode::Type); + ue_py_slate_farguments_event("on_context_menu_opening", OnContextMenuOpening, FOnContextMenuOpening, OnContextMenuOpening); #if ENGINE_MINOR_VERSION > 12 ue_py_slate_farguments_optional_float("wheel_scroll_multiplier", WheelScrollMultiplier); #endif diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h index 4c20d9e1c..5bab56bf2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h @@ -14,13 +14,14 @@ class SPythonTreeView : public STreeView> delete(ItemsSource); } - void SetPythonItemExpansion(PyObject *item, bool InShouldExpandItem); + TSharedPtr const* Find(PyObject *item); }; typedef struct { ue_PySTreeView s_tree_view; /* Type-specific fields go here. */ + TArray> item_source_list; } ue_PySPythonTreeView; void ue_python_init_spython_tree_view(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp index 3a22a5c92..51ee9cbd4 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp @@ -36,6 +36,25 @@ static PyObject *py_ue_sscroll_box_add_slot(ue_PySScrollBox *self, PyObject * ar Py_RETURN_SLATE_SELF; } +static PyObject * py_ue_sscroll_box_remove_slot(ue_PySScrollBox *self, PyObject * args) +{ + ue_py_slate_cast(SScrollBox); + + PyObject *py_content; + if (!PyArg_ParseTuple(args, "O:remove_slot", &py_content)) + { + return NULL; + } + + TSharedPtr child = py_ue_is_swidget(py_content); + if (!child.IsValid()) + { return nullptr; } + + py_SScrollBox->RemoveSlot(child.ToSharedRef()); + + Py_RETURN_NONE; +} + static PyObject *py_ue_sscroll_box_clear_children(ue_PySScrollBox *self, PyObject * args) { ue_py_slate_cast(SScrollBox); @@ -48,6 +67,7 @@ static PyMethodDef ue_PySScrollBox_methods[] = { { "clear_children", (PyCFunction)py_ue_sscroll_box_clear_children, METH_VARARGS, "" }, #pragma warning(suppress: 4191) { "add_slot", (PyCFunction)py_ue_sscroll_box_add_slot, METH_VARARGS | METH_KEYWORDS, "" }, + { "remove_slot", (PyCFunction)py_ue_sscroll_box_remove_slot, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp index cbce68dfe..11994c617 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp @@ -2,39 +2,21 @@ static PyObject *py_ue_ssplitter_add_slot(ue_PySSplitter *self, PyObject * args, PyObject *kwargs) { - ue_py_slate_cast(SSplitter); - PyObject *py_content; - int index = -1; - float size_value = -1; - int sizing_rule = -1; - - char *kwlist[] = { (char *)"widget", - (char *)"index", - (char *)"size_value", - (char *)"sizing_rule", - nullptr }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|ifi:add_slot", kwlist, &py_content, &index, &size_value, &sizing_rule)) - { - return nullptr; - } - - TSharedPtr Child = py_ue_is_swidget(py_content); - if (!Child.IsValid()) - { - return nullptr; - } - - SSplitter::FSlot &fslot = py_SSplitter->AddSlot(index); - if (size_value > -1) - { - fslot.SizeValue = size_value; - } - if (sizing_rule > -1) + ue_py_slate_cast(SSplitter); + + int32 retCode = [&]() { + ue_py_slate_setup_hack_slot_args(SSplitter, py_SSplitter); + ue_py_slate_farguments_float("value", Value); + ue_py_slate_farguments_enum("size_rule", SizeRule, SSplitter::ESizeRule); + ue_py_slate_farguments_event("on_slot_resized", OnSlotResized, SSplitter::FOnSlotResized, OnFloatChanged); + ue_py_slate_track_delegates(py_SSplitter); + return 0; + }(); + + if (retCode != 0) { - fslot.SizingRule = (SSplitter::ESizeRule)sizing_rule; + return PyErr_Format(PyExc_Exception, "could not add horizontal slot"); } - fslot.AttachWidget(Child.ToSharedRef()); Py_RETURN_SLATE_SELF; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp index a994186a5..ce111a7a2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp @@ -16,6 +16,19 @@ static PyObject *py_ue_stext_block_set_text(ue_PySTextBlock *self, PyObject * ar Py_RETURN_SLATE_SELF; } +static PyObject *py_ue_stext_block_set_highlight_text(ue_PySTextBlock *self, PyObject * args) { + ue_py_slate_cast(STextBlock); + + char *text; + if (!PyArg_ParseTuple(args, "s:set_text", &text)) { + return NULL; + } + + py_STextBlock->SetHighlightText(FText::FromString(FString(UTF8_TO_TCHAR(text)))); + + Py_RETURN_SLATE_SELF; +} + static PyObject *py_ue_stext_block_set_color_and_opacity(ue_PySTextBlock *self, PyObject * args) { @@ -49,6 +62,7 @@ static PyObject *py_ue_stext_block_get_text(ue_PySTextBlock *self, PyObject * ar static PyMethodDef ue_PySTextBlock_methods[] = { { "set_color_and_opacity", (PyCFunction)py_ue_stext_block_set_color_and_opacity, METH_VARARGS, "" }, { "set_text", (PyCFunction)py_ue_stext_block_set_text, METH_VARARGS, "" }, + { "set_highlight_text", (PyCFunction)py_ue_stext_block_set_highlight_text, METH_VARARGS, "" }, { "get_text", (PyCFunction)py_ue_stext_block_get_text, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -57,7 +71,7 @@ DECLARE_UE_PY_SLATE_WIDGET(STextBlock); static int ue_py_stext_block_init(ue_PySTextBlock *self, PyObject *args, PyObject *kwargs) { - + ue_py_slate_setup_farguments(STextBlock); ue_py_slate_farguments_bool("autowrap_text", AutoWrapText); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp index b5063de25..eddec6ca4 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp @@ -14,6 +14,7 @@ static PyObject *py_ue_svertical_box_add_slot(ue_PySVerticalBox *self, PyObject ue_py_slate_farguments_optional_enum("v_align", VAlign, EVerticalAlignment); ue_py_slate_farguments_call("auto_height", AutoHeight); ue_py_slate_farguments_padding("padding", Padding); + ue_py_slate_track_delegates(py_SVerticalBox); return 0; }(); @@ -56,7 +57,7 @@ static PyObject *ue_py_svertical_box_add(ue_PySVerticalBox *self, PyObject *valu if (!Child.IsValid()) { return nullptr; - } +} SVerticalBox::FSlot &fslot = py_SVerticalBox->AddSlot(); fslot.AttachWidget(Child.ToSharedRef()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp index 1af968f8c..9876c5467 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -1,6 +1,7 @@ #include "UEPySWidget.h" +#include static PyObject *ue_PySWidget_str(ue_PySWidget *self) { @@ -222,6 +223,35 @@ static PyObject *py_ue_swidget_get_type(ue_PySWidget *self, PyObject * args) return PyUnicode_FromString(TCHAR_TO_UTF8(*(self->Widget->GetTypeAsString()))); } +static PyObject *py_ue_swidget_get_visibility(ue_PySWidget *self, PyObject * args) +{ + if (self->Widget->GetVisibility().IsVisible()) + { + Py_INCREF(Py_True); + return Py_True; + } + else + { + Py_INCREF(Py_False); + return Py_False; + } +} + +static PyObject *py_ue_swidget_to_string(ue_PySWidget *self, PyObject * args) +{ + return PyUnicode_FromString(TCHAR_TO_UTF8(*(self->Widget->ToString()))); +} + +static PyObject *py_ue_swidget_get_widget_path(ue_PySWidget *self, PyObject * args) +{ + FString ret; + FWidgetPath OutWidgetPath; + FSlateApplication::Get().GeneratePathToWidgetUnchecked(self->Widget, OutWidgetPath); + ret = OutWidgetPath.ToString(); + + return PyUnicode_FromString(TCHAR_TO_UTF8(*ret)); +} + static PyObject *py_ue_swidget_get_cached_geometry(ue_PySWidget *self, PyObject * args) { return py_ue_new_fgeometry(self->Widget->GetCachedGeometry()); @@ -321,11 +351,26 @@ static PyObject *py_ue_swidget_new_ref(ue_PySWidget *self, PyObject * args) return (PyObject *)py_ue_new_swidget(Widget.ToSharedRef(), &ue_PySWidgetType); } +static PyObject *py_ue_swidget_is_valid(ue_PySWidget *self, PyObject * args) +{ + TSharedPtr checkPtr = self->Widget; + if (checkPtr.IsValid()) + { + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + static PyMethodDef ue_PySWidget_methods[] = { { "new_ref", (PyCFunction)py_ue_swidget_new_ref, METH_VARARGS, "" }, { "get_shared_reference_count", (PyCFunction)py_ue_swidget_get_shared_reference_count, METH_VARARGS, "" }, { "get_cached_geometry", (PyCFunction)py_ue_swidget_get_cached_geometry, METH_VARARGS, "" }, { "get_children", (PyCFunction)py_ue_swidget_get_children, METH_VARARGS, "" }, + { "get_visibility", (PyCFunction)py_ue_swidget_get_visibility, METH_VARARGS, "" }, + { "to_string", (PyCFunction)py_ue_swidget_to_string, METH_VARARGS, "" }, + { "get_widget_path", (PyCFunction)py_ue_swidget_get_widget_path, METH_VARARGS, "" }, + { "is_valid", (PyCFunction)py_ue_swidget_is_valid, METH_VARARGS, "" }, { "get_type", (PyCFunction)py_ue_swidget_get_type, METH_VARARGS, "" }, { "set_tooltip_text", (PyCFunction)py_ue_swidget_set_tooltip_text, METH_VARARGS, "" }, { "set_cursor", (PyCFunction)py_ue_swidget_set_cursor, METH_VARARGS, "" }, @@ -336,7 +381,7 @@ static PyMethodDef ue_PySWidget_methods[] = { { "set_visibility", (PyCFunction)py_ue_swidget_set_visibility, METH_VARARGS, "" }, #if ENGINE_MINOR_VERSION > 12 { "bind_on_mouse_button_down", (PyCFunction)py_ue_swidget_bind_on_mouse_button_down, METH_VARARGS, "" }, - { "bind_on_mouse_button_up", (PyCFunction)py_ue_swidget_bind_on_mouse_button_down, METH_VARARGS, "" }, + { "bind_on_mouse_button_up", (PyCFunction)py_ue_swidget_bind_on_mouse_button_up, METH_VARARGS, "" }, { "bind_on_mouse_double_click", (PyCFunction)py_ue_swidget_bind_on_mouse_double_click, METH_VARARGS, "" }, { "bind_on_mouse_move", (PyCFunction)py_ue_swidget_bind_on_mouse_move, METH_VARARGS, "" }, #endif @@ -348,11 +393,12 @@ static PyMethodDef ue_PySWidget_methods[] = { static void ue_PySWidgett_dealloc(ue_PySWidget *self) { #if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySWidget %p mapped to %s %p (slate refcount: %d)"), self, *self->s_widget->GetTypeAsString(), &self->s_widget.Get(), self->s_widget.GetSharedReferenceCount()); + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PySWidget %p mapped to %s %p (slate refcount: %d)"), self, *self->Widget->GetTypeAsString(), &self->Widget.Get(), self->Widget.GetSharedReferenceCount()); #endif + Py_DECREF(self->py_dict); if (self->weakreflist != nullptr) - PyObject_ClearWeakRefs((PyObject *)self); + { PyObject_ClearWeakRefs((PyObject *)self); } // decrement widget reference count // but only if python vm is still fully active (hack to avoid crashes on editor shutdown) @@ -407,8 +453,11 @@ ue_PySWidget_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self = (ue_PySWidget *)type->tp_alloc(type, 0); if (self != NULL) { + //NOTE: This initialization code block needs to match py_ue_new_swidget() because that gets used in other places + // Not sure why PyObject_New() inside of py_ue_new_swidget() does not call this function new(&self->Widget) TSharedRef(SNullWidget::NullWidget); self->weakreflist = nullptr; + self->py_dict = self->py_dict = PyDict_New(); } return (PyObject *)self; @@ -417,7 +466,10 @@ ue_PySWidget_new(PyTypeObject *type, PyObject *args, PyObject *kwds) void ue_python_init_swidget(PyObject *ue_module) { ue_PySWidgetType.tp_new = ue_PySWidget_new; - // support for weak references, useful for tests + ue_PySWidgetType.tp_getattro = PyObject_GenericGetAttr; + ue_PySWidgetType.tp_setattro = PyObject_GenericSetAttr; + ue_PySWidgetType.tp_dictoffset = offsetof(ue_PySWidget, py_dict); + // support for weak references, useful for tests ue_PySWidgetType.tp_weaklistoffset = offsetof(ue_PySWidget, weakreflist); if (PyType_Ready(&ue_PySWidgetType) < 0) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp index 87ea5e430..a6a0380ca 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp @@ -65,6 +65,28 @@ static PyObject *py_ue_swindow_set_content(ue_PySWindow *self, PyObject * args) Py_RETURN_SLATE_SELF; } +static PyObject *py_ue_swindow_set_on_window_closed(ue_PySWindow *self, PyObject * args) +{ + ue_py_slate_cast(SWindow); + + PyObject *py_callable; + if (!PyArg_ParseTuple(args, "O:set_on_window_closed", &py_callable)) + { + return NULL; + } + + if (!PyCalllable_Check_Extended(py_callable)) + return PyErr_Format(PyExc_Exception, "argument is not callable"); + + FOnWindowClosed onWindowClosed; + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewSlateDelegate(py_SWindow, py_callable); + onWindowClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnWindowClosed); + + py_SWindow->SetOnWindowClosed(onWindowClosed); + Py_RETURN_NONE; +} + + static PyObject *py_ue_swindow_set_sizing_rule(ue_PySWindow *self, PyObject * args) { ue_py_slate_cast(SWindow); @@ -141,6 +163,7 @@ static PyMethodDef ue_PySWindow_methods[] = { { "resize", (PyCFunction)py_ue_swindow_resize, METH_VARARGS, "" }, { "set_client_size", (PyCFunction)py_ue_swindow_resize, METH_VARARGS, "" }, { "set_content", (PyCFunction)py_ue_swindow_set_content, METH_VARARGS, "" }, + { "set_on_window_closed", (PyCFunction)py_ue_swindow_set_on_window_closed, METH_VARARGS, "" }, { "get_handle", (PyCFunction)py_ue_swindow_get_handle, METH_VARARGS, "" }, { "request_destroy", (PyCFunction)py_ue_swindow_request_destroy, METH_VARARGS, "" }, #if WITH_EDITOR diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 5b64fa041..61a088114 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -25,6 +25,10 @@ #include "UEPySlate.h" #include "PyNativeWidgetHost.h" +#include +#include +#include "UEPySWidget.h" +#include #include "Wrappers/UEPyFAssetData.h" @@ -71,6 +75,8 @@ #include "UEPySSpacer.h" #include "UEPySPythonWidget.h" #include "UEPySOverlay.h" +#include "UEPySExpanderArrow.h" +#include "UEPySExpandableArea.h" #include "UEPyFTabManager.h" #include "UEPyFTabSpawnerEntry.h" @@ -264,7 +270,7 @@ void FPythonSlateDelegate::OnWindowClosed(const TSharedRef &Window) { FScopePythonGIL gil; - PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_ue_new_swidget(StaticCastSharedRef(Window), &ue_PySWindowType)); + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", (PyObject *)ue_py_get_swidget(Window)); if (!ret) { unreal_engine_py_log_error(); @@ -273,6 +279,66 @@ void FPythonSlateDelegate::OnWindowClosed(const TSharedRef &Window) Py_DECREF(ret); } +void FPythonSlateDelegate::OnTabClosed(TSharedRef Tab) +{ + FScopePythonGIL gil; + ue_PySWidget * py_dock_tab = ue_py_get_swidget(Tab); + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", (PyObject *)py_dock_tab); + if (!ret) + { + unreal_engine_py_log_error(); + return; + } + + Py_DECREF(ret); + Py_DECREF((PyObject*)py_dock_tab); + +} + +void FPythonSlateDelegate::OnTabActivated(TSharedRef Tab, ETabActivationCause TabActivationCause) +{ + FScopePythonGIL gil; + ue_PySWidget * py_dock_tab = ue_py_get_swidget(Tab); + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"Oi", (PyObject *)py_dock_tab, (int)TabActivationCause); + if (!ret) + { + unreal_engine_py_log_error(); + return; + } + Py_DECREF(ret); + Py_DECREF((PyObject*)py_dock_tab); +} + +bool FPythonSlateDelegate::OnCanCloseTab() +{ + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, (char *)""); + if (!ret || !PyBool_Check(ret)) + { + unreal_engine_py_log_error(); + Py_XDECREF(ret); + return true; + } + + const bool bCanClose = ret == Py_True; + Py_DECREF(ret); + return bCanClose; +} + +void FPythonSlateDelegate::OnPersistVisualState() +{ + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, (char *)""); + if (!ret) + { + unreal_engine_py_log_error(); + } + + Py_DECREF(ret); +} + void FPythonSlateDelegate::OnFloatCommitted(float value, ETextCommit::Type commit_type) { FScopePythonGIL gil; @@ -286,6 +352,19 @@ void FPythonSlateDelegate::OnFloatCommitted(float value, ETextCommit::Type commi Py_DECREF(ret); } +void FPythonSlateDelegate::OnBoolChanged(bool value) +{ + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", value ? Py_True : Py_False); + if (!ret) + { + unreal_engine_py_log_error(); + return; + } + Py_DECREF(ret); +} + void FPythonSlateDelegate::OnSort(const EColumnSortPriority::Type SortPriority, const FName& ColumnName, const EColumnSortMode::Type NewSortMode) { FScopePythonGIL gil; @@ -687,21 +766,21 @@ FVector2D FPythonSlateDelegate::GetterFVector2D() const if (!ret) { unreal_engine_py_log_error(); - return FVector2D(); + return FVector2D::ZeroVector; } if (!PyTuple_Check(ret)) { Py_DECREF(ret); PyErr_SetString(PyExc_ValueError, "returned value is not a tuple"); - return FVector2D(); + return FVector2D::ZeroVector; } if (PyTuple_Size(ret) != 2) { Py_DECREF(ret); PyErr_SetString(PyExc_ValueError, "returned value is not a 2 items tuple"); - return FVector2D(); + return FVector2D::ZeroVector; } PyObject *first_item = PyTuple_GetItem(ret, 0); @@ -709,7 +788,7 @@ FVector2D FPythonSlateDelegate::GetterFVector2D() const { Py_DECREF(ret); PyErr_SetString(PyExc_ValueError, "tuple does not contain numbers"); - return FVector2D(); + return FVector2D::ZeroVector; } PyObject *py_x = PyNumber_Float(first_item); @@ -752,19 +831,28 @@ FLinearColor FPythonSlateDelegate::GetterFLinearColor() const return color; } -TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &args) +TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &args, bool bShouldAutosize) { - TSharedRef dock_tab = SNew(SDockTab).TabRole(ETabRole::NomadTab); - PyObject *py_dock = (PyObject *)ue_py_get_swidget(dock_tab); - PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_dock); + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", bShouldAutosize ? Py_True : Py_False); if (!ret) { + PyErr_Format(PyExc_Exception, "Object returned by dock tab spawning in python is in invalid state"); unreal_engine_py_log_error(); + return SNew(SDockTab); } - else + ue_PySDockTab* py_dock = py_ue_is_sdock_tab(ret); + if (!py_dock) { Py_DECREF(ret); + PyErr_Format(PyExc_Exception, "Object returned by dock tab spawning in python is not a dock tab"); + unreal_engine_py_log_error(); + return SNew(SDockTab); } + + TSharedRef dock_tab = StaticCastSharedRef(((ue_PySWidget*)py_dock)->Widget); + + Py_DECREF(py_dock); + return dock_tab; } @@ -781,7 +869,7 @@ TSharedRef FPythonSlateDelegate::GenerateRow(TSharedPtr if (ue_PySPythonMultiColumnTableRow *spython_multicolumn_table_row = py_ue_is_spython_multicolumn_table_row(ret)) { - return StaticCastSharedRef(spython_multicolumn_table_row->s_compound_widget.s_widget.Widget->AsShared()); + return StaticCastSharedRef(((ue_PySWidget*)spython_multicolumn_table_row)->Widget); } TSharedPtr Widget = py_ue_is_swidget(ret); @@ -828,18 +916,18 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget) { ue_PySWidget *ret = nullptr; - if (s_widget->GetType().Compare(FName("SWindow")) == 0) - { - return py_ue_new_swidget(s_widget, &ue_PySWindowType); - } - if (s_widget->GetType().Compare(FName("SDockTab")) == 0) - { - return py_ue_new_swidget(s_widget, &ue_PySDockTabType); - } - else - { - return py_ue_new_swidget(s_widget, &ue_PySWidgetType); - } + if (s_widget->GetType().Compare(FName("SWindow")) == 0) + { + return py_ue_new_swidget(s_widget, &ue_PySWindowType); + } + if (s_widget->GetType().Compare(FName("SDockTab")) == 0) + { + return py_ue_new_swidget(s_widget, &ue_PySDockTabType); + } + else + { + return py_ue_new_swidget(s_widget, &ue_PySWidgetType); + } } @@ -867,6 +955,7 @@ void ue_python_init_slate(PyObject *module) ue_python_init_slist_view(module); ue_python_init_spython_list_view(module); ue_python_init_spython_multicolumn_table_row(module); + ue_python_init_sexpander_arrow(module); ue_python_init_stree_view(module); ue_python_init_spython_tree_view(module); ue_python_init_ssplitter(module); @@ -885,6 +974,7 @@ void ue_python_init_slate(PyObject *module) ue_python_init_sspacer(module); ue_python_init_spython_widget(module); ue_python_init_soverlay(module); + ue_python_init_sexpandable_area(module); #if WITH_EDITOR @@ -1078,6 +1168,7 @@ PyObject *py_unreal_engine_create_detail_view(PyObject *self, PyObject * args, P char *py_name_area_settings = nullptr; PyObject *py_hide_selection_tip = nullptr; PyObject *py_search_initial_key_focus = nullptr; + int defaults_show_visibility = (int)EEditDefaultsOnlyNodeVisibility::Show; char *kwlist[] = { (char *)"uobject", @@ -1088,10 +1179,12 @@ PyObject *py_unreal_engine_create_detail_view(PyObject *self, PyObject * args, P (char *)"name_area_settings", (char *)"hide_selection_tip", (char *)"search_initial_key_focus", + (char *)"defaults_only_visibility", nullptr }; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOsOO:create_detail_view", kwlist, - &py_object, &py_allow_search, &py_update_from_selection, &py_lockable, &py_name_area_settings, &py_hide_selection_tip, &py_search_initial_key_focus)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOsOOi:create_detail_view", kwlist, + &py_object, &py_allow_search, &py_update_from_selection, &py_lockable, &py_name_area_settings, &py_hide_selection_tip, &py_search_initial_key_focus, + &defaults_show_visibility)) { return nullptr; } @@ -1112,6 +1205,7 @@ PyObject *py_unreal_engine_create_detail_view(PyObject *self, PyObject * args, P else if (FCString::Stricmp(*name_area_string, TEXT("ComponentsAndActorsUseNameArea")) == 0) { return FDetailsViewArgs::ENameAreaSettings::ComponentsAndActorsUseNameArea; } else { return FDetailsViewArgs::ENameAreaSettings::ActorsUseNameArea; } }(); + view_args.DefaultsOnlyVisibility = (EEditDefaultsOnlyNodeVisibility)defaults_show_visibility; TSharedPtr view = PropertyEditorModule.CreateDetailView(view_args); @@ -1189,11 +1283,19 @@ PyObject *py_unreal_engine_create_structure_detail_view(PyObject *self, PyObject { Py_INCREF(ue_py_struct); ret->ue_py_struct = ue_py_struct; - struct_scope = MakeShared(ue_py_struct->u_struct, ue_py_struct->data); + struct_scope = MakeShared(ue_py_struct->u_struct, py_ue_uscriptstruct_get_data(ue_py_struct)); } FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); ret->istructure_details_view = PropertyEditorModule.CreateStructureDetailView(view_args, struct_view_args, struct_scope); + //ret->istructure_details_view->GetOnFinishedChangingPropertiesDelegate().AddLambda([ret](const FPropertyChangedEvent& ChangeEvent) { + // //NOTE: Kind of risque but YOLO + // if (ret->istructure_details_view.IsValid() && ret->ue_py_struct != nullptr + // && ret->ue_py_struct->is_ptr && ret->ue_py_struct->original_data && ret->ue_py_struct->data) + // { + // FMemory::Memcpy(ret->ue_py_struct->original_data, ret->ue_py_struct->data, ret->ue_py_struct->u_struct->GetStructureSize()); + // } + //}); return (PyObject *)ret; } @@ -1398,7 +1500,8 @@ PyObject *py_unreal_engine_register_nomad_tab_spawner(PyObject * self, PyObject char *name; PyObject *py_callable; - if (!PyArg_ParseTuple(args, "sO:register_nomad_tab_spawner", &name, &py_callable)) + PyObject *py_bool = nullptr; + if (!PyArg_ParseTuple(args, "sO|O:register_nomad_tab_spawner", &name, &py_callable, &py_bool)) { return NULL; } @@ -1406,13 +1509,18 @@ PyObject *py_unreal_engine_register_nomad_tab_spawner(PyObject * self, PyObject if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); + const FName tabName = FName(UTF8_TO_TCHAR(name)); + if (FGlobalTabmanager::Get()->CanSpawnTab(tabName)) + { return PyErr_Format(PyExc_Exception, "tab spawner already registered!"); } + FOnSpawnTab spawn_tab; - TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); - spawn_tab.BindSP(py_delegate, &FPythonSlateDelegate::SpawnPythonTab); + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable, FPythonSlateDelegate::TabSpawner, tabName); + bool bshould_auto_size = py_bool && PyObject_IsTrue(py_bool) ? true : false; + spawn_tab.BindSP(py_delegate, &FPythonSlateDelegate::SpawnPythonTab, bshould_auto_size); - FTabSpawnerEntry *spawner_entry = &FGlobalTabmanager::Get()->RegisterNomadTabSpawner(UTF8_TO_TCHAR(name), spawn_tab) - // TODO: more generic way to set the group + FTabSpawnerEntry *spawner_entry = &FGlobalTabmanager::Get()->RegisterNomadTabSpawner(tabName, spawn_tab) #if WITH_EDITOR + // TODO: more generic way to set the group .SetGroup(WorkspaceMenu::GetMenuStructure().GetDeveloperToolsMiscCategory()) #endif ; @@ -1431,7 +1539,9 @@ PyObject *py_unreal_engine_unregister_nomad_tab_spawner(PyObject * self, PyObjec return NULL; } - FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(UTF8_TO_TCHAR(name)); + FName tabSpawnerName = FName(UTF8_TO_TCHAR(name)); + FUnrealEnginePythonHouseKeeper::Get()->UntrackStaticSlateDelegate(FPythonSlateDelegate::TabSpawner, tabSpawnerName); + FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(tabSpawnerName); Py_INCREF(Py_None); return Py_None; @@ -1440,18 +1550,79 @@ PyObject *py_unreal_engine_unregister_nomad_tab_spawner(PyObject * self, PyObjec PyObject *py_unreal_engine_invoke_tab(PyObject * self, PyObject * args) { - char *name; - if (!PyArg_ParseTuple(args, "s:invoke_tab", &name)) + char *name = nullptr; + char *tabmanager = (char *)"LevelEditorTabManager"; + if (!PyArg_ParseTuple(args, "s|s:invoke_tab", &name, &tabmanager)) { return NULL; } - +#if WITH_EDITOR + // To persist nomad tabs docking, make sure to specify LevelEditorTabManager + if (_stricmp(tabmanager, (char *)"GlobalTabManager") == 0) + { + //NOTE: This will not persist the tab docking location after being closed + FGlobalTabmanager::Get()->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); + } + else if (FLevelEditorModule* level_editor_module = FModuleManager::GetModulePtr("LevelEditor")) + { + TSharedPtr level_editor_tab_manager = level_editor_module->GetLevelEditorTabManager(); + level_editor_tab_manager->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); + } +#else + //NOTE: This will not persist the tab docking location after being closed FGlobalTabmanager::Get()->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); +#endif + Py_RETURN_NONE; +} - Py_INCREF(Py_None); - return Py_None; +PyObject *py_unreal_engine_insert_new_document_tab(PyObject * self, PyObject * args) +{ + char* name = nullptr; + int searchPreference = 0; + PyObject* py_docktab = nullptr; + char* tabmanager = (char *)"LevelEditorTabManager"; + + if (!PyArg_ParseTuple(args, "siO|s:insert_new_document_tab", &name, &searchPreference, &py_docktab, &tabmanager)) + { + return NULL; + } + + ue_PySDockTab* ue_docktab = py_ue_is_sdock_tab(py_docktab); + if (!ue_docktab) + { + return PyErr_Format(PyExc_Exception, "Widget is not a dock tab!"); + } + + FTabManager* tabManager = nullptr; + { +#if WITH_EDITOR + // To persist nomad tabs docking, make sure to specify LevelEditorTabManager + if (_stricmp(tabmanager, (char *)"GlobalTabManager") == 0) + { + //NOTE: This will not persist the tab docking location after being closed + tabManager = &FGlobalTabmanager::Get().Get(); + } + else if (FLevelEditorModule* level_editor_module = FModuleManager::GetModulePtr("LevelEditor")) + { + tabManager = level_editor_module->GetLevelEditorTabManager().Get(); + } +#else + tabManager = &FGlobalTabmanager::Get().Get(); +#endif + } + + if (!tabManager) + { + return PyErr_Format(PyExc_Exception, "Could not retrieve tab manager!"); } + tabManager->InsertNewDocumentTab( + UTF8_TO_TCHAR(name), + (FTabManager::ESearchPreference::Type)searchPreference, + StaticCastSharedRef(ue_docktab->s_border.s_compound_widget.s_widget.Widget)); + + Py_RETURN_NONE; +} PyObject * py_unreal_engine_get_swidget_from_wrapper(PyObject *self, PyObject *args) { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 161ff686d..9f29ebbf6 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -29,6 +29,7 @@ struct ue_PySWidget PyObject_HEAD /* Type-specific fields go here. */ TSharedRef Widget; + PyObject *py_dict; PyObject *weakreflist; }; @@ -62,6 +63,7 @@ PyObject *py_unreal_engine_add_asset_view_context_menu_extension(PyObject * self #endif PyObject *py_unreal_engine_invoke_tab(PyObject *, PyObject *); +PyObject *py_unreal_engine_insert_new_document_tab(PyObject *, PyObject *); PyObject *py_unreal_engine_get_swidget_from_wrapper(PyObject *, PyObject *); PyObject *py_unreal_engine_create_wrapper_from_pyswidget(PyObject *, PyObject *); @@ -80,16 +82,21 @@ template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widge ue_PySWidget *ret = (ue_PySWidget *)PyObject_New(T, py_type); new(&ret->Widget) TSharedRef(s_widget); + ret->weakreflist = nullptr; + ret->py_dict = PyDict_New(); return ret; } -#define ue_py_snew_base(T, required, arguments) ((ue_PySWidget *)self)->Widget = TSharedRef(MakeTDecl(#T, __FILE__, __LINE__, required) <<= arguments);\ +#define ue_py_slate_track_delegates(_swidget_ref) \ for(TSharedRef Delegate : DeferredSlateDelegates)\ {\ - FUnrealEnginePythonHouseKeeper::Get()->TrackDeferredSlateDelegate(Delegate, ((ue_PySWidget *)self)->Widget);\ + FUnrealEnginePythonHouseKeeper::Get()->TrackDeferredSlateDelegate(Delegate, _swidget_ref);\ } +#define ue_py_snew_base(T, required, arguments) ((ue_PySWidget *)self)->Widget = TSharedRef(MakeTDecl(#T, __FILE__, __LINE__, required) <<= arguments);\ + ue_py_slate_track_delegates(((ue_PySWidget *)self)->Widget) + #define ue_py_snew_simple(T) TArray> DeferredSlateDelegates;\ ue_py_snew_base(T, RequiredArgs::MakeRequiredArgs(), T::FArguments()) @@ -98,11 +105,16 @@ template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widge #define ue_py_snew(T) ue_py_snew_base(T, RequiredArgs::MakeRequiredArgs(), arguments) -#define ue_py_snew_with_args(T, args) ue_py_snew_base(T, RequiredArgs::MakeRequiredArgs(args), arguments) +#define ue_py_snew_with_args(T, ...) ue_py_snew_base(T, RequiredArgs::MakeRequiredArgs(__VA_ARGS__), arguments) ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); + +//---------------------------------------------------------------------------- +// Slate Attribute Parameters macros +//---------------------------------------------------------------------------- + #define ue_py_slate_base_up(_base, _func, _param, _attribute) \ {\ PyObject *value = ue_py_dict_get_item(kwargs, _param);\ @@ -136,6 +148,9 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); #define ue_py_slate_up(_type, _func, _param, _attribute) ue_py_slate_base_up(TAttribute<_type>, _func, _param, _attribute) + +#define ue_py_slate_farguments_attribute_text(param, attribute) ue_py_slate_farguments_text(param, attribute) + #define ue_py_slate_farguments_text(param, attribute) ue_py_slate_up(FText, GetterFText, param, attribute)\ else if (PyUnicode_Check(value)) {\ arguments.attribute(FText::FromString(UTF8_TO_TCHAR(PyUnicode_AsUTF8(value))));\ @@ -143,6 +158,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_string(param, attribute) ue_py_slate_farguments_string(param, attribute) + #define ue_py_slate_farguments_string(param, attribute) ue_py_slate_up(FString, GetterFString, param, attribute)\ else if (PyUnicode_Check(value)) {\ arguments.attribute(UTF8_TO_TCHAR(PyUnicode_AsUTF8(value)));\ @@ -150,6 +167,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_float(param, attribute) ue_py_slate_farguments_float(param, attribute) #define ue_py_slate_farguments_float(param, attribute) ue_py_slate_up(float, GetterFloat, param, attribute)\ else if (PyNumber_Check(value)) {\ @@ -160,6 +178,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_tfloat(param, attribute) ue_py_slate_farguments_tfloat(param, attribute) + #define ue_py_slate_farguments_tfloat(param, attribute) ue_py_slate_up(TOptional, GetterTFloat, param, attribute)\ else if (PyNumber_Check(value)) {\ PyObject *py_float = PyNumber_Float(value);\ @@ -169,6 +189,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_fvector2d(param, attribute) ue_py_slate_farguments_fvector2d(param, attribute) + #define ue_py_slate_farguments_fvector2d(param, attribute) ue_py_slate_up(FVector2D, GetterFVector2D, param, attribute)\ else if (PyTuple_Check(value)) {\ if (PyTuple_Size(value) == 2) {\ @@ -187,7 +209,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); - +#define ue_py_slate_farguments_attribute_int(param, attribute) ue_py_slate_farguments_int(param, attribute) #define ue_py_slate_farguments_int(param, attribute) ue_py_slate_up(int, GetterInt, param, attribute)\ else if (PyNumber_Check(value)) {\ @@ -197,6 +219,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_tint(param, attribute) ue_py_slate_farguments_tint(param, attribute) + #define ue_py_slate_farguments_tint(param, attribute) ue_py_slate_up(TOptional, GetterIntT>, param, attribute)\ else if (PyNumber_Check(value)) {\ PyObject *py_int = PyNumber_Long(value);\ @@ -206,6 +230,9 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) + +#define ue_py_slate_farguments_attribute_enum(param, attribute, _type) ue_py_slate_farguments_enum(param, attribute, _type) + #define ue_py_slate_farguments_enum(param, attribute, _type) ue_py_slate_up(_type, GetterIntT<_type>, param, attribute)\ else if (PyNumber_Check(value)) {\ PyObject *py_int = PyNumber_Long(value);\ @@ -216,6 +243,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); +#define ue_py_slate_farguments_attribute_flinear_color(param, attribute) ue_py_slate_farguments_flinear_color(param, attribute) + #define ue_py_slate_farguments_flinear_color(param, attribute) ue_py_slate_up(FLinearColor, GetterFLinearColor, param, attribute)\ else if (ue_PyFLinearColor *py_color = py_ue_is_flinearcolor(value)) {\ arguments.attribute(py_color->color); \ @@ -223,6 +252,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_struct(param, attribute, _type) ue_py_slate_farguments_struct(param, attribute, _type) #define ue_py_slate_farguments_struct(param, attribute, _type) ue_py_slate_up(_type, GetterStructT<_type>, param, attribute)\ else if (_type *u_struct = ue_py_check_struct<_type>(value)) {\ @@ -231,6 +261,28 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); ue_py_slate_down(param) +#define ue_py_slate_farguments_attribute_bool(param, attribute) ue_py_slate_farguments_bool(param, attribute) + +#define ue_py_slate_farguments_bool(param, attribute) ue_py_slate_up(bool, GetterBool, param, attribute)\ + else if (PyObject_IsTrue(value)) {\ + arguments.attribute(true); \ + }\ + else {\ + arguments.attribute(false); \ + }\ + }\ +} + + +#define ue_py_slate_farguments_attribute_event(param, attribute, type, method) ue_py_slate_farguments_event(param, attribute, type, method) + +#define ue_py_slate_farguments_event(param, attribute, type, method) ue_py_slate_base_event_up(type, method, param, attribute)\ + ue_py_slate_down(param) + +//---------------------------------------------------------------------------- +// Slate Argument Parameters macros +//---------------------------------------------------------------------------- +#define ue_py_slate_farguments_argument_struct(param, attribute, _type) ue_py_slate_farguments_optional_struct(param, attribute, _type) #define ue_py_slate_farguments_optional_struct(param, attribute, _type) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ @@ -245,6 +297,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); } +#define ue_py_slate_farguments_argument_struct_ptr(param, attribute, _type) ue_py_slate_farguments_optional_struct_ptr(param, attribute, _type) + #define ue_py_slate_farguments_optional_struct_ptr(param, attribute, _type) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (_type *u_struct = ue_py_check_struct<_type>(value)) {\ @@ -258,6 +312,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } +#define ue_py_slate_farguments_argument_uobject(param, attribute, _type) ue_py_slate_farguments_optional_uobject(param, attribute, _type) + #define ue_py_slate_farguments_optional_uobject(param, attribute, _type) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (_type *u_object = ue_py_check_type<_type>(value)) {\ @@ -271,6 +327,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); } +#define ue_py_slate_farguments_argument_fvector2d(param, attribute) ue_py_slate_farguments_optional_fvector2d(param, attribute) + #define ue_py_slate_farguments_optional_fvector2d(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (PyTuple_Check(value)) {\ @@ -298,6 +356,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); } +#define ue_py_slate_farguments_argument_enum(param, attribute, _type) ue_py_slate_farguments_optional_enum(param, attribute, _type) + #define ue_py_slate_farguments_optional_enum(param, attribute, _type) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (PyNumber_Check(value)) {\ @@ -314,6 +374,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); +#define ue_py_slate_farguments_argument_float(param, attribute) ue_py_slate_farguments_optional_float(param, attribute) + #define ue_py_slate_farguments_optional_float(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (PyNumber_Check(value)) {\ @@ -328,6 +390,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } +#define ue_py_slate_farguments_argument_foptional_size(param, attribute) ue_py_slate_farguments_optional_foptional_size(param, attribute) + #define ue_py_slate_farguments_optional_foptional_size(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (PyNumber_Check(value)) {\ @@ -342,12 +406,22 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } +#define ue_py_slate_farguments_argument_string(param, attribute) ue_py_slate_farguments_optional_string(param, attribute) + #define ue_py_slate_farguments_optional_string(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ - if (PyUnicode_Check(value)) {\ - arguments.attribute(UTF8_TO_TCHAR(PyUnicode_AsUTF8(value)));\ + if (value) {\ + if (PyUnicode_Check(value)) {\ + arguments.attribute(UTF8_TO_TCHAR(PyUnicode_AsUTF8(value)));\ + }\ + else {\ + PyErr_SetString(PyExc_TypeError, "unsupported type for attribute " param); \ + return -1;\ + }\ }\ } +#define ue_py_slate_farguments_argument_text(param, attribute) ue_py_slate_farguments_optional_text(param, attribute) + #define ue_py_slate_farguments_optional_text(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (PyUnicode_Check(value)) {\ @@ -360,25 +434,12 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } -#define ue_py_slate_farguments_optional_named_slot(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ - if (value) {\ - TSharedPtr Child = py_ue_is_swidget(value);\ - if (Child.IsValid()) {\ - arguments.attribute()\ - [\ - Child.ToSharedRef()\ - ];\ - }\ - else {\ - PyErr_SetString(PyExc_TypeError, "unsupported type for attribute " param); \ - return -1;\ - }\ - }\ -} +#define ue_py_slate_farguments_argument_bool(param, attribute) ue_py_slate_farguments_optional_bool(param, attribute) -#define ue_py_slate_farguments_bool(param, attribute) ue_py_slate_up(bool, GetterBool, param, attribute)\ - else if (PyObject_IsTrue(value)) {\ +#define ue_py_slate_farguments_optional_bool(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ + if (value) {\ + if (PyObject_IsTrue(value)) {\ arguments.attribute(true); \ }\ else {\ @@ -424,25 +485,27 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } +#define ue_py_slate_farguments_named_slot(param, attribute) ue_py_slate_farguments_optional_named_slot(param, attribute) +// SLATE_DEFAULT_SLOT == SLATE_NAMED_SLOT with difference that slate declarative syntax [] defaults to this slot +#define ue_py_slate_farguments_default_slot(param, attribute) ue_py_slate_farguments_named_slot(param, attribute) -#define ue_py_slate_farguments_optional_bool(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ +#define ue_py_slate_farguments_optional_named_slot(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ - if (PyObject_IsTrue(value)) {\ - arguments.attribute(true); \ + TSharedPtr Child = py_ue_is_swidget(value);\ + if (Child.IsValid()) {\ + arguments.attribute()\ + [\ + Child.ToSharedRef()\ + ];\ }\ else {\ - arguments.attribute(false); \ + PyErr_SetString(PyExc_TypeError, "unsupported type for attribute " param); \ + return -1;\ }\ }\ } - -#define ue_py_slate_farguments_event(param, attribute, type, method) ue_py_slate_base_event_up(type, method, param, attribute)\ - ue_py_slate_down(param) - - - #define ue_py_slate_setup_farguments(_type) _type::FArguments arguments;\ TArray> DeferredSlateDelegates;\ ue_py_slate_farguments_bool("is_enabled", IsEnabled); \ @@ -453,7 +516,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); value = value ? value : PyTuple_GetItem(args, 0);\ TSharedPtr Widget = py_ue_is_swidget(value);\ if (Widget.IsValid())\ - arguments.AttachWidget(Widget.ToSharedRef());\ + { arguments.AttachWidget(Widget.ToSharedRef()); } \ else\ {\ PyErr_SetString(PyExc_TypeError, "unsupported type for required slot " param);\ @@ -468,5 +531,3 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); void ue_python_init_slate(PyObject *); - - diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h index 575896ca7..4b50fbcc9 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h @@ -16,8 +16,14 @@ template T *ue_py_check_struct(PyObject *); class FPythonSlateDelegate : public FPythonSmartDelegate { - public: + enum Type { + None, + TabSpawner + }; + Type StaticDelegateType; + FName LifeTimeCtx; + FReply OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event); FReply OnClicked(); @@ -28,13 +34,14 @@ class FPythonSlateDelegate : public FPythonSmartDelegate void OnInt32Committed(int32 value, ETextCommit::Type commit_type); void OnFloatChanged(float value); void OnFloatCommitted(float value, ETextCommit::Type commit_type); + void OnBoolChanged(bool value); void OnSort(const EColumnSortPriority::Type SortPriority, const FName& ColumnName, const EColumnSortMode::Type NewSortMode); void OnLinearColorChanged(FLinearColor color); void OnStringChanged(const FString &text); - TSharedRef SpawnPythonTab(const FSpawnTabArgs& args); + TSharedRef SpawnPythonTab(const FSpawnTabArgs& args, bool bShouldAutosize); TSharedRef GenerateRow(TSharedPtr InItem, const TSharedRef& OwnerTable); void GetChildren(TSharedPtr InItem, TArray>& OutChildren); @@ -50,6 +57,10 @@ class FPythonSlateDelegate : public FPythonSmartDelegate #endif void OnWindowClosed(const TSharedRef &Window); + void OnTabClosed(TSharedRef Tab); + void OnTabActivated(TSharedRef Tab, ETabActivationCause TabActivationCause); + bool OnCanCloseTab(); + void OnPersistVisualState(); TSharedPtr OnContextMenuOpening(); TSharedRef OnGenerateWidget(TSharedPtr py_item); diff --git a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp index 270eaf586..d6e447be6 100644 --- a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp +++ b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp @@ -1,7 +1,11 @@ #include "UEPyFSlateApplication.h" +#include "Framework/Application/MenuStack.h" +#include "Layout/WidgetPath.h" +#include "Slate/UEPySWidget.h" #include "Slate/UEPySWidget.h" +#include "Slate/UEPySWindow.h" static PyObject *py_ue_get_average_delta_time(PyObject *cls, PyObject * args) { @@ -151,6 +155,77 @@ static PyObject *py_ue_process_key_char_event(PyObject *cls, PyObject * args) Py_RETURN_FALSE; } +static PyObject *py_ue_push_menu(PyObject *cls, PyObject * args) +{ + PyObject *py_parent_widget; + PyObject *py_menu_widget; + float x; + float y; + int menuSlideDirection = (int)FPopupTransitionEffect::ESlideDirection::None; + + if (!PyArg_ParseTuple(args, "OOffi:push_menu", &py_parent_widget, &py_menu_widget, &x, &y, &menuSlideDirection)) + { + return nullptr; + } + // Parse cursor position as a blueprint struct + TSharedPtr parentWidget = py_ue_is_swidget(py_parent_widget); + if (!parentWidget.IsValid()) + { return nullptr; } + + TSharedPtr menuWidget = py_ue_is_swidget(py_menu_widget); + if (!menuWidget.IsValid()) + { return nullptr; } + + FVector2D CursorPos = FVector2D(x, y); + + FSlateApplication::Get().PushMenu(parentWidget.ToSharedRef(), FWidgetPath(), menuWidget.ToSharedRef(), CursorPos, FPopupTransitionEffect((FPopupTransitionEffect::ESlideDirection)menuSlideDirection)); + Py_RETURN_NONE; +} + +static PyObject *py_ue_add_window(PyObject *cls, PyObject * args) +{ + PyObject *py_window_obj; + PyObject *py_show_immediately; + + if (!PyArg_ParseTuple(args, "O|O", &py_window_obj, &py_show_immediately)) + { + return nullptr; + } + + ue_PySWindow *py_window = py_ue_is_swindow(py_window_obj); + if (!py_window) + { + return PyErr_Format(PyExc_Exception, "window to add is not an SWindow"); + } + + const bool showImmediately = (py_show_immediately) ? (PyObject_IsTrue(py_show_immediately)) : true; + + FSlateApplication::Get().AddWindow(StaticCastSharedRef(((ue_PySWidget*)py_window)->Widget), showImmediately); + + return py_window_obj; +} + +static PyObject *py_ue_destroy_window_immediately(PyObject *cls, PyObject * args) +{ + PyObject *py_window_obj; + + if (!PyArg_ParseTuple(args, "O:window_to_destroy", &py_window_obj)) + { + return nullptr; + } + + ue_PySWindow *py_window = py_ue_is_swindow(py_window_obj); + + if (!py_window) + { + return PyErr_Format(PyExc_Exception, "window_to_destroy is not an SWindow"); + } + + FSlateApplication::Get().DestroyWindowImmediately(StaticCastSharedRef(py_window->s_compound_widget.s_widget.Widget)); + + Py_RETURN_NONE; +} + static PyMethodDef ue_PyFSlateApplication_methods[] = { { "get_average_delta_time", (PyCFunction)py_ue_get_average_delta_time, METH_VARARGS | METH_CLASS, "" }, { "get_cursor_radius", (PyCFunction)py_ue_get_cursor_radius, METH_VARARGS | METH_CLASS, "" }, @@ -164,6 +239,9 @@ static PyMethodDef ue_PyFSlateApplication_methods[] = { { "set_application_scale", (PyCFunction)py_ue_set_application_scale, METH_VARARGS | METH_CLASS, "" }, { "set_all_user_focus", (PyCFunction)py_ue_set_all_user_focus, METH_VARARGS | METH_CLASS, "" }, { "set_cursor_pos", (PyCFunction)py_ue_set_cursor_pos, METH_VARARGS | METH_CLASS, "" }, + { "push_menu", (PyCFunction)py_ue_push_menu, METH_VARARGS | METH_CLASS, "" }, + { "add_window", (PyCFunction)py_ue_add_window, METH_VARARGS | METH_CLASS, "" }, + { "destroy_window_immediately", (PyCFunction)py_ue_destroy_window_immediately, METH_VARARGS | METH_CLASS, "" }, { NULL } /* Sentinel */ }; diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index b20f60dc1..edd6933b4 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -28,6 +28,11 @@ #include "Developer/Settings/Public/ISettingsModule.h" #include "Engine/Blueprint.h" +#include "Components/PrimitiveComponent.h" +#include "GameFramework/Actor.h" +#include "Editor/EditorEngine.h" +#include "Components/ActorComponent.h" +#include "UnrealClient.h" #include "Wrappers/UEPyFARFilter.h" #include "Wrappers/UEPyFVector.h" @@ -55,7 +60,7 @@ PyObject *py_unreal_engine_editor_play_in_viewport(PyObject * self, PyObject * a ue_PyFVector *vector = py_ue_is_fvector(py_vector); if (!vector) return PyErr_Format(PyExc_Exception, "argument is not a FVector"); - v = vector->vec; + v = py_ue_fvector_get(vector); } if (py_rotator) @@ -63,7 +68,7 @@ PyObject *py_unreal_engine_editor_play_in_viewport(PyObject * self, PyObject * a ue_PyFRotator *rotator = py_ue_is_frotator(py_rotator); if (!rotator) return PyErr_Format(PyExc_Exception, "argument is not a FRotator"); - r = rotator->rot; + r = py_ue_frotator_get(rotator); } FLevelEditorModule &EditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); @@ -108,24 +113,6 @@ PyObject *py_unreal_engine_get_editor_world(PyObject * self, PyObject * args) Py_RETURN_UOBJECT(world); } -PyObject *py_unreal_engine_console_exec(PyObject * self, PyObject * args) -{ - - char *command; - - if (!GEditor) - return PyErr_Format(PyExc_Exception, "no GEditor found"); - - if (!PyArg_ParseTuple(args, "s:console_exec", &command)) - { - return NULL; - } - - GEditor->Exec(GEditor->GetEditorWorldContext().World(), UTF8_TO_TCHAR(command), *GLog); - - Py_RETURN_NONE; -} - PyObject *py_unreal_engine_allow_actor_script_execution_in_editor(PyObject * self, PyObject * args) { @@ -174,6 +161,39 @@ PyObject *py_unreal_engine_editor_get_selected_actors(PyObject * self, PyObject return actors; } +PyObject *py_unreal_engine_editor_get_actors_in_folder(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + char *folder_path = nullptr; + if (!PyArg_ParseTuple(args, "s:get_actors_in_folder", &folder_path)) + { + return NULL; + } + + PyObject *actors = PyList_New(0); + + FName FolderPath(folder_path); + UWorld *world = GEditor->GetEditorWorldContext().World(); + + for (AActor* actor : TActorRange(world)) + { + //NOTE: WORKAROUND: UE4 Editor does not update folder path for children after attachment. So some childnodes in a folder + // may erroneously have an outdated folder path + if (actor->GetFolderPath() == FolderPath) + { + if (!actor->IsA()) + continue; + ue_PyUObject *item = ue_get_python_uobject(actor); + if (item) + PyList_Append(actors, (PyObject *)item); + } + } + + return actors; +} + PyObject *py_unreal_engine_editor_command_build(PyObject * self, PyObject * args) { @@ -186,6 +206,13 @@ PyObject *py_unreal_engine_editor_command_build(PyObject * self, PyObject * args return Py_None; } +PyObject *py_unreal_engine_editor_refresh_all_browsers(PyObject * self, PyObject * args) +{ + FEditorDelegates::RefreshAllBrowsers.Broadcast(); + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_editor_command_save_current_level(PyObject * self, PyObject * args) { FLevelEditorActionCallbacks::Save(); @@ -226,6 +253,98 @@ PyObject *py_unreal_engine_editor_deselect_actors(PyObject * self, PyObject * ar Py_RETURN_NONE; } +PyObject *py_unreal_engine_editor_is_ctrl_down(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + if (IsCtrlDown(activeViewport)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyObject *py_unreal_engine_editor_is_shift_down(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + if (IsShiftDown(activeViewport)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyObject *py_unreal_engine_editor_is_alt_down(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + if (IsAltDown(activeViewport)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyObject *py_unreal_engine_editor_is_space_bar_down(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + if (activeViewport->KeyState(EKeys::SpaceBar)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyObject *py_unreal_engine_editor_get_widget_mode(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + FEditorViewportClient * activeViewportClient = static_cast(activeViewport->GetClient()); + + if (activeViewportClient) + { + FWidget::EWidgetMode currentWidgetMode = activeViewportClient->GetWidgetMode(); + return PyLong_FromUnsignedLong(uint64(currentWidgetMode)); + } + + Py_RETURN_NONE; +} + +PyObject *py_unreal_engine_editor_get_widget_coord_system_space(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FViewport * activeViewport = GEditor->GetActiveViewport(); + + FEditorViewportClient * activeViewportClient = static_cast(activeViewport->GetClient()); + + if (activeViewportClient) + { + ECoordSystem currentWidgetCoordSystemSpace = activeViewportClient->GetWidgetCoordSystemSpace(); + return PyLong_FromUnsignedLong(uint64(currentWidgetCoordSystemSpace)); + } + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_editor_play(PyObject * self, PyObject * args) { @@ -245,7 +364,7 @@ PyObject *py_unreal_engine_editor_play(PyObject * self, PyObject * args) ue_PyFVector *vector = py_ue_is_fvector(py_vector); if (!vector) return PyErr_Format(PyExc_Exception, "argument is not a FVector"); - v = vector->vec; + v = py_ue_fvector_get(vector); } if (py_rotator) @@ -253,7 +372,7 @@ PyObject *py_unreal_engine_editor_play(PyObject * self, PyObject * args) ue_PyFRotator *rotator = py_ue_is_frotator(py_rotator); if (!rotator) return PyErr_Format(PyExc_Exception, "argument is not a FRotator"); - r = rotator->rot; + r = py_ue_frotator_get(rotator); } #if ENGINE_MINOR_VERSION >= 17 @@ -294,6 +413,28 @@ PyObject *py_unreal_engine_editor_select_actor(PyObject * self, PyObject * args) return Py_None; } +PyObject *py_unreal_engine_editor_select_component(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + PyObject *py_obj; + if (!PyArg_ParseTuple(args, "O:editor_select_component", &py_obj)) + { + return NULL; + } + + UActorComponent *actor_component = ue_py_check_type(py_obj); + if (!actor_component) + { + return PyErr_Format(PyExc_Exception, "object is not an Actor Component"); + } + + GEditor->SelectComponent(actor_component, true, true); + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_import_asset(PyObject * self, PyObject * args) { @@ -527,6 +668,43 @@ PyObject *py_unreal_engine_get_asset(PyObject * self, PyObject * args) Py_RETURN_UOBJECT(asset.GetAsset()); } +PyObject *py_unreal_engine_get_all_assets(PyObject * self, PyObject * args) +{ + IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked("AssetRegistry").Get(); + + TArray OutAssetData; + + AssetRegistry.GetAllAssets(OutAssetData); + + PyObject *ret = PyList_New(0); + + for (FAssetData & assetData : OutAssetData) + { + PyObject *py_obj = py_ue_new_fassetdata(assetData); + if (!py_obj) + continue; + PyList_Append(ret, (PyObject *)py_obj); + } + + return ret; +} + +PyObject * py_unreal_engine_get_asset_by_object_path(PyObject * self, PyObject * args) +{ + char * object_path = nullptr; + if (!PyArg_ParseTuple(args, "s:get_asset_by_object_path", &object_path)) + { + return NULL; + } + + if (!object_path) + return PyErr_Format(PyExc_Exception, "Argument is not a valid string"); + + IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked("AssetRegistry").Get(); + + return py_ue_new_fassetdata(AssetRegistry.GetAssetByObjectPath(FName(object_path))); +} + PyObject *py_unreal_engine_find_asset(PyObject * self, PyObject * args) { char *path; @@ -1686,7 +1864,7 @@ PyObject *py_unreal_engine_editor_on_asset_post_import(PyObject * self, PyObject if (!PyCallable_Check(py_callable)) return PyErr_Format(PyExc_Exception, "object is not a callable"); - TSharedRef py_delegate = MakeShareable(new FPythonSmartDelegate); + TSharedRef py_delegate = MakeShared(); py_delegate->SetPyCallable(py_callable); FEditorDelegates::OnAssetPostImport.AddSP(py_delegate, &FPythonSmartDelegate::PyFOnAssetPostImport); Py_RETURN_NONE; @@ -1921,6 +2099,56 @@ PyObject *py_unreal_engine_move_actor_to_level(PyObject *self, PyObject * args) Py_RETURN_NONE; } +// Accepts actors and components, will prefer to focus on components first and actors next if component list is empty +PyObject *py_unreal_engine_move_viewport_cameras_to_actor(PyObject * self, PyObject * args) +{ + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + PyObject *py_actor; + PyObject *py_component; + PyObject *py_bool; + if (!PyArg_ParseTuple(args, "OOO:move_viewport_cameras_to_actor", &py_actor, &py_component, &py_bool)) + { + return NULL; + } + + // Pack the provided actors and components into a array and call the more robust version of this function. + TArray Actors; + TArray Components; + + AActor* const in_actor = ue_py_check_type(py_actor); + if (py_actor != Py_None && in_actor == nullptr) + return PyErr_Format(PyExc_Exception, "actor argument is not an actor"); + + if (in_actor) + { + Actors.Add(in_actor); + } + + UPrimitiveComponent* const in_component = ue_py_check_type(py_component); + if (py_component != Py_None && in_component == nullptr) + { + return PyErr_Format(PyExc_Exception, "component argument is not a primitive component"); + } + + if (in_component) + { + Components.Add(in_component); + } + + if (!in_actor && !in_component) + { + return PyErr_Format(PyExc_Exception, "must pass in an actor or component."); + } + + bool bActiveViewportOnly = PyObject_IsTrue(py_bool) ? true : false; + + GEditor->MoveViewportCamerasToActor(Actors, Components, bActiveViewportOnly); + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_editor_take_high_res_screen_shots(PyObject * self, PyObject * args) { @@ -2231,7 +2459,7 @@ PyObject * py_unreal_engine_show_viewer(PyObject * self, PyObject * args) char *category_name; char *section_name; - if (!PyArg_ParseTuple(args, "sss:register_settings", &container_name, &category_name, §ion_name)) + if (!PyArg_ParseTuple(args, "sss:show_viewer", &container_name, &category_name, §ion_name)) return nullptr; if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) @@ -2269,6 +2497,23 @@ PyObject *py_unreal_engine_unregister_settings(PyObject * self, PyObject * args) Py_RETURN_NONE; } +PyObject *py_unreal_engine_gconfig_set_string(PyObject * self, PyObject * args) +{ + char *section_name; + char *key_name; + char *key_value; + char *file_name; + + if (!PyArg_ParseTuple(args, "ssss:gconfig_set_string", §ion_name, &key_name, &key_value, &file_name)) + { + return NULL; + } + + GConfig->SetString(UTF8_TO_TCHAR(section_name), UTF8_TO_TCHAR(key_name), UTF8_TO_TCHAR(key_value), FString(UTF8_TO_TCHAR(file_name))); + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_all_viewport_clients(PyObject * self, PyObject * args) { TArray clients = GEditor->AllViewportClients; diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 56c42a18b..282110402 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -7,10 +7,20 @@ #if WITH_EDITOR PyObject *py_unreal_engine_get_editor_world(PyObject *, PyObject * args); +PyObject *py_unreal_engine_get_all_assets(PyObject * self, PyObject * args); +PyObject *py_unreal_engine_get_asset_by_object_path(PyObject * self, PyObject * args); PyObject *py_unreal_engine_editor_play_in_viewport(PyObject *, PyObject * args); PyObject *py_unreal_engine_editor_get_selected_actors(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_get_actors_in_folder(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_deselect_actors(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_is_ctrl_down(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_is_shift_down(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_is_alt_down(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_is_space_bar_down(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_get_widget_mode(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_get_widget_coord_system_space(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_select_actor(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_select_component(PyObject * self, PyObject * args); PyObject *py_unreal_engine_import_asset(PyObject *, PyObject *); PyObject *py_unreal_engine_get_asset(PyObject *, PyObject *); PyObject *py_unreal_engine_find_asset(PyObject *, PyObject *); @@ -23,8 +33,6 @@ PyObject *py_unreal_engine_set_fbx_import_option(PyObject *, PyObject *); PyObject *py_unreal_engine_create_modal_save_asset_dialog(PyObject *, PyObject *); -PyObject *py_unreal_engine_console_exec(PyObject *, PyObject * args); - PyObject *py_unreal_engine_editor_tick(PyObject *, PyObject *); PyObject *py_unreal_engine_get_discovered_plugins(PyObject *, PyObject *); @@ -58,6 +66,8 @@ PyObject *py_unreal_engine_editor_on_asset_post_import(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_command_build(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_command_build_lighting(PyObject *, PyObject *); +PyObject *py_unreal_engine_editor_refresh_all_browsers(PyObject *, PyObject *); + PyObject *py_unreal_engine_editor_command_save_current_level(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_command_save_all_levels(PyObject *, PyObject *); @@ -66,6 +76,8 @@ PyObject *py_unreal_engine_editor_save_all(PyObject *, PyObject *); PyObject *py_unreal_engine_add_level_to_world(PyObject *, PyObject *); PyObject *py_unreal_engine_move_selected_actors_to_level(PyObject *, PyObject *); PyObject *py_unreal_engine_move_actor_to_level(PyObject *, PyObject *); +PyObject *py_unreal_engine_move_viewport_cameras_to_actor(PyObject *, PyObject *); + PyObject *py_ue_factory_create_new(ue_PyUObject *, PyObject *); PyObject *py_ue_factory_import_object(ue_PyUObject *, PyObject *); @@ -118,6 +130,7 @@ PyObject *py_unreal_engine_play_preview_sound(PyObject *, PyObject *); PyObject *py_unreal_engine_register_settings(PyObject *, PyObject *); PyObject *py_unreal_engine_show_viewer(PyObject *, PyObject *); PyObject *py_unreal_engine_unregister_settings(PyObject *, PyObject *); +PyObject *py_unreal_engine_gconfig_set_string(PyObject *, PyObject *); PyObject *py_unreal_engine_request_play_session(PyObject *, PyObject *); PyObject *py_unreal_engine_export_assets(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index 6fdcbc302..260cd8cbe 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -9,8 +9,10 @@ #include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h" #if WITH_EDITOR #include "PackageTools.h" +#include "PackageHelperFunctions.h" #include "Editor.h" #endif +#include "HAL/PlatformApplicationMisc.h" #include "UnrealEngine.h" #include "Runtime/Engine/Classes/Engine/GameViewportClient.h" @@ -18,6 +20,7 @@ #if ENGINE_MINOR_VERSION >= 18 #include "HAL/PlatformApplicationMisc.h" #endif +#include "EngineUtils.h" PyObject *py_unreal_engine_log(PyObject * self, PyObject * args) @@ -77,6 +80,54 @@ PyObject *py_unreal_engine_log_error(PyObject * self, PyObject * args) return Py_None; } +PyObject *py_unreal_engine_is_editor(PyObject * self, PyObject * args) +{ + if (GIsEditor) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } +} + +PyObject *py_unreal_engine_is_running_game(PyObject * self, PyObject * args) +{ + if (IsRunningGame()) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } +} + +PyObject *py_unreal_engine_is_running_commandlet(PyObject * self, PyObject * args) +{ + if (IsRunningCommandlet()) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } +} + +PyObject *py_unreal_engine_is_running_dedicated_server(PyObject * self, PyObject * args) +{ + if (IsRunningDedicatedServer()) + { + Py_RETURN_TRUE; + } + else + { + Py_RETURN_FALSE; + } +} + PyObject *py_unreal_engine_add_on_screen_debug_message(PyObject * self, PyObject * args) { int key; @@ -171,6 +222,30 @@ PyObject *py_unreal_engine_get_up_vector(PyObject * self, PyObject * args) return py_ue_new_fvector(vec); } +PyObject *py_unreal_engine_get_section(PyObject *self, PyObject * args) +{ + char * section_name = nullptr; + char *file_name = nullptr; + + if (!PyArg_ParseTuple(args, "ss:get_section", §ion_name, &file_name)) + { + return NULL; + } + + TArray outSection; + GConfig->GetSection(*FString(section_name), outSection, FString(file_name)); + + PyObject *ret = PyList_New(0); + for (FString & outString : outSection) + { + PyObject *py_string = PyUnicode_FromString(TCHAR_TO_UTF8(*outString)); + PyList_Append(ret, py_string); + Py_DECREF(py_string); + } + + return ret; +} + PyObject *py_unreal_engine_get_content_dir(PyObject * self, PyObject * args) { #if ENGINE_MINOR_VERSION >= 18 @@ -296,6 +371,41 @@ PyObject *py_unreal_engine_load_package(PyObject * self, PyObject * args) } #if WITH_EDITOR +PyObject *py_unreal_engine_find_actor_by_label_in_world(PyObject * self, PyObject * args) +{ + PyObject* py_world; + char* actor_label; + if (!PyArg_ParseTuple(args, "Os:find_actor_by_label_in_world", &py_world, &actor_label)) + { + return NULL; + } + + UWorld *u_world = ue_py_check_type(py_world); + if (!u_world) + { + return PyErr_Format(PyExc_Exception, "Argument is not a UWorld"); + } + + UObject *u_object = nullptr; + + for (TActorIterator Itr(u_world); Itr; ++Itr) + { + AActor *u_obj = *Itr; + if (u_obj->GetActorLabel().Equals(UTF8_TO_TCHAR(actor_label))) + { + u_object = u_obj; + break; + } + } + + if (u_object) + { + Py_RETURN_UOBJECT(u_object); + } + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_unload_package(PyObject * self, PyObject * args) { PyObject *obj; @@ -448,7 +558,7 @@ PyObject *py_unreal_engine_string_to_guid(PyObject * self, PyObject * args) if (FGuid::Parse(FString(str), guid)) { - return py_ue_new_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&guid); + return py_ue_new_uscriptstruct(TBaseStructure::Get(), (uint8 *)&guid); } return PyErr_Format(PyExc_Exception, "unable to build FGuid"); @@ -459,7 +569,7 @@ PyObject *py_unreal_engine_new_guid(PyObject * self, PyObject * args) FGuid guid = FGuid::NewGuid(); - return py_ue_new_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&guid); + return py_ue_new_uscriptstruct(TBaseStructure::Get(), (uint8 *)&guid); } PyObject *py_unreal_engine_guid_to_string(PyObject * self, PyObject * args) @@ -503,7 +613,6 @@ PyObject *py_unreal_engine_get_delta_time(PyObject * self, PyObject * args) return PyFloat_FromDouble(FApp::GetDeltaTime()); } - PyObject *py_unreal_engine_find_object(PyObject * self, PyObject * args) { char *name; @@ -1022,6 +1131,34 @@ PyObject *py_unreal_engine_get_transient_package(PyObject *self, PyObject * args Py_RETURN_UOBJECT(GetTransientPackage()); } +#if WITH_EDITOR +PyObject *py_unreal_engine_save_package_helper(PyObject *self, PyObject *args) +{ + char *name = nullptr; + UPackage *package = nullptr; + PyObject *py_obj = nullptr; + uint64 flags = (uint64)(RF_Standalone); + if (!PyArg_ParseTuple(args, "Os|K:save_package_helper",&py_obj, &name, &flags)) + { + return nullptr; + } + + UPackage* pkg = ue_py_check_type(py_obj); + if (!pkg) + { + return PyErr_Format(PyExc_Exception, "argument is not a UPackage"); + } + + if (!SavePackageHelper(pkg, UTF8_TO_TCHAR(name), (EObjectFlags)flags)) + { + PyErr_SetString(PyExc_Exception, "unable to save package"); + Py_RETURN_FALSE; + } + + Py_RETURN_TRUE; +} +#endif + PyObject *py_unreal_engine_open_file_dialog(PyObject *self, PyObject * args) { char *title; @@ -1259,7 +1396,7 @@ PyObject *py_unreal_engine_clipboard_copy(PyObject * self, PyObject * args) FGenericPlatformMisc::ClipboardCopy(UTF8_TO_TCHAR(text)); #endif Py_RETURN_NONE; -} + } PyObject *py_unreal_engine_clipboard_paste(PyObject * self, PyObject * args) { @@ -1270,4 +1407,50 @@ PyObject *py_unreal_engine_clipboard_paste(PyObject * self, PyObject * args) FGenericPlatformMisc::ClipboardPaste(clipboard); #endif return PyUnicode_FromString(TCHAR_TO_UTF8(*clipboard)); +} +PyObject *py_unreal_engine_console_exec(PyObject * self, PyObject * args) +{ + + char *command; + + + if (!PyArg_ParseTuple(args, "s:console_exec", &command)) + { + return NULL; + } + + FWorldContext* worldContext = nullptr; +#if WITH_EDITOR + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + worldContext = GEditor->GetPIEWorldContext(); + worldContext = worldContext ? worldContext : &GEditor->GetEditorWorldContext(); + if (!worldContext) + { + // error! + return NULL; + } + GEditor->Exec(worldContext->World(), UTF8_TO_TCHAR(command), *GLog); +#else +#include "Engine/Engine.h" + extern ENGINE_API class UEngine* GEngine; + for (auto Context : GEngine->GetWorldContexts()) + { + if (Context.World()->IsGameWorld()) + { + worldContext = &Context; + break; + } + } + + if (!worldContext) + { + // error! + return NULL; + } + GEngine->Exec(worldContext->World(), UTF8_TO_TCHAR(command), *GLog); +#endif + + Py_RETURN_NONE; } \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index bbe3d8fa8..02843c7f3 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -7,6 +7,12 @@ PyObject *py_unreal_engine_log(PyObject *, PyObject *); PyObject *py_unreal_engine_log_warning(PyObject *, PyObject *); PyObject *py_unreal_engine_log_error(PyObject *, PyObject *); + +PyObject *py_unreal_engine_is_editor(PyObject *, PyObject *); +PyObject *py_unreal_engine_is_running_game(PyObject *, PyObject *); +PyObject *py_unreal_engine_is_running_commandlet(PyObject *, PyObject *); +PyObject *py_unreal_engine_is_running_dedicated_server(PyObject *, PyObject *); + PyObject *py_unreal_engine_add_on_screen_debug_message(PyObject *, PyObject *); PyObject *py_unreal_engine_print_string(PyObject *, PyObject *); PyObject *py_unreal_engine_get_forward_vector(PyObject *, PyObject *); @@ -21,6 +27,7 @@ PyObject *py_unreal_engine_set_random_seed(PyObject *, PyObject *); PyObject *py_unreal_engine_get_game_viewport_size(PyObject *, PyObject *); PyObject *py_unreal_engine_get_resolution(PyObject *, PyObject *); +PyObject *py_unreal_engine_get_section(PyObject *self, PyObject * args); PyObject *py_unreal_engine_get_content_dir(PyObject *, PyObject *); PyObject *py_unreal_engine_get_game_saved_dir(PyObject *, PyObject *); PyObject *py_unreal_engine_get_game_user_developer_dir(PyObject *, PyObject *); @@ -36,6 +43,7 @@ PyObject *py_unreal_engine_load_struct(PyObject *, PyObject *); PyObject *py_unreal_engine_load_enum(PyObject *, PyObject *); PyObject *py_unreal_engine_load_package(PyObject *, PyObject *); #if WITH_EDITOR +PyObject *py_unreal_engine_find_actor_by_label_in_world(PyObject *, PyObject *); PyObject *py_unreal_engine_unload_package(PyObject *, PyObject *); #endif @@ -72,6 +80,7 @@ PyObject *py_unreal_engine_create_world(PyObject *, PyObject *); PyObject *py_unreal_engine_create_package(PyObject *, PyObject *); PyObject *py_unreal_engine_get_or_create_package(PyObject *, PyObject *); PyObject *py_unreal_engine_get_transient_package(PyObject *, PyObject *); +PyObject *py_unreal_engine_save_package_helper(PyObject *, PyObject *); PyObject *py_unreal_engine_object_path_to_package_name(PyObject *, PyObject *); PyObject *py_unreal_engine_get_path(PyObject *, PyObject *); @@ -83,6 +92,7 @@ PyObject *py_unreal_engine_open_directory_dialog(PyObject *, PyObject *); PyObject *py_unreal_engine_save_file_dialog(PyObject *, PyObject *); PyObject *py_unreal_engine_copy_properties_for_unrelated_objects(PyObject *, PyObject *, PyObject *); +PyObject *py_unreal_engine_console_exec(PyObject * self, PyObject * args); #if WITH_EDITOR PyObject *py_unreal_engine_editor_get_active_viewport_screenshot(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 6e73dda95..3123e788e 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -5,6 +5,8 @@ #include "UEPyTicker.h" #include "UEPyVisualLogger.h" +#include + #include "UObject/UEPyObject.h" #include "UObject/UEPyActor.h" #include "UObject/UEPyTransform.h" @@ -141,6 +143,23 @@ void init_unreal_engine_builtin() } #endif +std::map ue_python_gc; + +//Missing structs in Class.cpp for some noexport types +static UScriptStruct* StaticGetBaseStructureInternal(const TCHAR* Name) +{ + static auto* CoreUObjectPkg = FindObjectChecked(nullptr, TEXT("/Script/CoreUObject")); + return FindObjectChecked(CoreUObjectPkg, Name); +} + +#if ENGINE_MINOR_VERSION <= 17 +UScriptStruct* TBaseStructure::Get() +{ + static auto ScriptStruct = StaticGetBaseStructureInternal(TEXT("Quat")); + return ScriptStruct; +} +#endif + static PyObject *py_unreal_engine_py_gc(PyObject * self, PyObject * args) { @@ -193,6 +212,11 @@ static PyMethodDef unreal_engine_methods[] = { { "log_warning", py_unreal_engine_log_warning, METH_VARARGS, "" }, { "log_error", py_unreal_engine_log_error, METH_VARARGS, "" }, + { "is_editor", py_unreal_engine_is_editor, METH_VARARGS, "" }, + { "is_running_game", py_unreal_engine_is_running_game, METH_VARARGS, "" }, + { "is_running_commandlet", py_unreal_engine_is_running_commandlet, METH_VARARGS, "" }, + { "is_running_dedicated_server", py_unreal_engine_is_running_dedicated_server, METH_VARARGS, "" }, + { "add_on_screen_debug_message", py_unreal_engine_add_on_screen_debug_message, METH_VARARGS, "" }, { "print_string", py_unreal_engine_print_string, METH_VARARGS, "" }, @@ -217,6 +241,9 @@ static PyMethodDef unreal_engine_methods[] = { { "get_up_vector", py_unreal_engine_get_up_vector, METH_VARARGS, "" }, { "get_right_vector", py_unreal_engine_get_right_vector, METH_VARARGS, "" }, + // Config + { "get_section", py_unreal_engine_get_section, METH_VARARGS, "" }, + { "get_content_dir", py_unreal_engine_get_content_dir, METH_VARARGS, "" }, { "get_game_saved_dir", py_unreal_engine_get_game_saved_dir, METH_VARARGS, "" }, { "get_game_user_developer_dir", py_unreal_engine_get_game_user_developer_dir, METH_VARARGS, "" }, @@ -240,7 +267,9 @@ static PyMethodDef unreal_engine_methods[] = { { "create_package", (PyCFunction)py_unreal_engine_create_package, METH_VARARGS, "" }, { "get_or_create_package", (PyCFunction)py_unreal_engine_get_or_create_package, METH_VARARGS, "" }, { "get_transient_package", (PyCFunction)py_unreal_engine_get_transient_package, METH_VARARGS, "" }, - +#if WITH_EDITOR + { "save_package_helper", (PyCFunction)py_unreal_engine_save_package_helper, METH_VARARGS, "" }, +#endif { "open_file_dialog", py_unreal_engine_open_file_dialog, METH_VARARGS, "" }, { "save_file_dialog", py_unreal_engine_save_file_dialog, METH_VARARGS, "" }, @@ -255,6 +284,7 @@ static PyMethodDef unreal_engine_methods[] = { { "register_nomad_tab_spawner", py_unreal_engine_register_nomad_tab_spawner, METH_VARARGS, "" }, { "unregister_nomad_tab_spawner", py_unreal_engine_unregister_nomad_tab_spawner, METH_VARARGS, "" }, { "invoke_tab", py_unreal_engine_invoke_tab, METH_VARARGS, "" }, + { "insert_new_document_tab", py_unreal_engine_insert_new_document_tab, METH_VARARGS, "" }, { "get_swidget_from_wrapper", py_unreal_engine_get_swidget_from_wrapper, METH_VARARGS, "" }, { "create_wrapper_from_pyswidget", py_unreal_engine_create_wrapper_from_pyswidget, METH_VARARGS, "" }, #if WITH_EDITOR @@ -277,19 +307,28 @@ static PyMethodDef unreal_engine_methods[] = { { "close_all_asset_editors", py_unreal_engine_close_all_asset_editors, METH_VARARGS, "" }, { "allow_actor_script_execution_in_editor", py_unreal_engine_allow_actor_script_execution_in_editor , METH_VARARGS, "" }, { "get_editor_world", py_unreal_engine_get_editor_world, METH_VARARGS, "" }, - { "console_exec", py_unreal_engine_console_exec, METH_VARARGS, "" }, { "editor_get_selected_actors", py_unreal_engine_editor_get_selected_actors, METH_VARARGS, "" }, + { "editor_get_actors_in_folder", py_unreal_engine_editor_get_actors_in_folder, METH_VARARGS, "" }, { "editor_select_actor", py_unreal_engine_editor_select_actor, METH_VARARGS, "" }, + { "editor_select_component", py_unreal_engine_editor_select_component, METH_VARARGS, "" }, { "editor_deselect_actors", py_unreal_engine_editor_deselect_actors, METH_VARARGS, "" }, + { "editor_is_ctrl_down", py_unreal_engine_editor_is_ctrl_down, METH_VARARGS, "" }, + { "editor_is_shift_down", py_unreal_engine_editor_is_shift_down, METH_VARARGS, "" }, + { "editor_is_alt_down", py_unreal_engine_editor_is_alt_down, METH_VARARGS, "" }, + { "editor_is_space_bar_down", py_unreal_engine_editor_is_space_bar_down, METH_VARARGS, "" }, + { "editor_get_widget_mode", py_unreal_engine_editor_get_widget_mode, METH_VARARGS, "" }, + { "editor_get_widget_coord_system_space", py_unreal_engine_editor_get_widget_coord_system_space, METH_VARARGS, "" }, { "import_asset", py_unreal_engine_import_asset, METH_VARARGS, "" }, { "export_assets", py_unreal_engine_export_assets, METH_VARARGS, "" }, { "get_asset", py_unreal_engine_get_asset, METH_VARARGS, "" }, { "find_asset", py_unreal_engine_find_asset, METH_VARARGS, "" }, { "delete_object", py_unreal_engine_delete_object, METH_VARARGS, "" }, { "get_assets", py_unreal_engine_get_assets, METH_VARARGS, "" }, + { "get_all_assets", py_unreal_engine_get_all_assets, METH_VARARGS, "" }, + { "get_asset_by_object_path", py_unreal_engine_get_asset_by_object_path, METH_VARARGS, "" }, + { "get_selected_assets", py_unreal_engine_get_selected_assets, METH_VARARGS, "" }, { "get_assets_by_class", py_unreal_engine_get_assets_by_class, METH_VARARGS, "" }, - { "sync_browser_to_assets", py_unreal_engine_editor_sync_browser_to_assets, METH_VARARGS, "" }, { "get_asset_referencers", py_unreal_engine_get_asset_referencers, METH_VARARGS, "" }, @@ -303,6 +342,7 @@ static PyMethodDef unreal_engine_methods[] = { { "editor_command_build", py_unreal_engine_editor_command_build, METH_VARARGS, "" }, { "editor_command_build_lighting", py_unreal_engine_editor_command_build_lighting, METH_VARARGS, "" }, + { "editor_refresh_all_browsers", py_unreal_engine_editor_refresh_all_browsers, METH_VARARGS, "" }, { "editor_command_save_current_level", py_unreal_engine_editor_command_save_current_level, METH_VARARGS, "" }, { "editor_command_save_all_levels", py_unreal_engine_editor_command_save_all_levels, METH_VARARGS, "" }, @@ -348,9 +388,11 @@ static PyMethodDef unreal_engine_methods[] = { { "editor_play", py_unreal_engine_editor_play, METH_VARARGS, "" }, + { "find_actor_by_label_in_world", py_unreal_engine_find_actor_by_label_in_world, METH_VARARGS, "" }, { "add_level_to_world", py_unreal_engine_add_level_to_world, METH_VARARGS, "" }, { "move_selected_actors_to_level", py_unreal_engine_move_selected_actors_to_level, METH_VARARGS, "" }, { "move_actor_to_level", py_unreal_engine_move_actor_to_level, METH_VARARGS, "" }, + { "move_viewport_cameras_to_actor", py_unreal_engine_move_viewport_cameras_to_actor, METH_VARARGS, "" }, { "editor_on_asset_post_import", py_unreal_engine_editor_on_asset_post_import, METH_VARARGS, "" }, @@ -436,12 +478,14 @@ static PyMethodDef unreal_engine_methods[] = { { "register_settings", py_unreal_engine_register_settings, METH_VARARGS, "" }, { "show_viewer", py_unreal_engine_show_viewer, METH_VARARGS, "" }, { "unregister_settings", py_unreal_engine_unregister_settings, METH_VARARGS, "" }, + { "gconfig_set_string", py_unreal_engine_gconfig_set_string, METH_VARARGS, "" }, { "in_editor_capture", py_unreal_engine_in_editor_capture, METH_VARARGS, "" }, #endif { "clipboard_copy", py_unreal_engine_clipboard_copy, METH_VARARGS, "" }, { "clipboard_paste", py_unreal_engine_clipboard_paste, METH_VARARGS, "" }, + { "console_exec", py_unreal_engine_console_exec, METH_VARARGS, "" }, #pragma warning(suppress: 4191) @@ -499,6 +543,11 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_up_vector", (PyCFunction)py_ue_get_up_vector, METH_VARARGS, "" }, { "get_right_vector", (PyCFunction)py_ue_get_right_vector, METH_VARARGS, "" }, + // Primitive +#if WITH_EDITOR + { "get_num_uncached_static_lighting_interactions", (PyCFunction)py_ue_get_num_uncached_static_lighting_interactions, METH_VARARGS, "" }, +#endif + // UObject { "get_property", (PyCFunction)py_ue_get_property, METH_VARARGS, "" }, @@ -511,6 +560,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "has_property", (PyCFunction)py_ue_has_property, METH_VARARGS, "" }, { "get_uproperty", (PyCFunction)py_ue_get_uproperty, METH_VARARGS, "" }, { "get_property_struct", (PyCFunction)py_ue_get_property_struct, METH_VARARGS, "" }, + { "output_referencers", (PyCFunction)py_ue_output_referencers, METH_VARARGS, "" }, { "get_property_array_dim", (PyCFunction)py_ue_get_property_array_dim, METH_VARARGS, "" }, { "functions", (PyCFunction)py_ue_functions, METH_VARARGS, "" }, @@ -528,6 +578,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_super_class", (PyCFunction)py_ue_get_super_class, METH_VARARGS, "" }, + { "get_archetype", (PyCFunction)py_ue_get_archetype, METH_VARARGS, "" }, + { "get_archetype_instances", (PyCFunction)py_ue_get_archetype_instances, METH_VARARGS, "" }, + { "get_name", (PyCFunction)py_ue_get_name, METH_VARARGS, "" }, { "get_display_name", (PyCFunction)py_ue_get_display_name, METH_VARARGS, "" }, { "get_path_name", (PyCFunction)py_ue_get_path_name, METH_VARARGS, "" }, @@ -544,6 +597,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "set_name", (PyCFunction)py_ue_set_name, METH_VARARGS, "" }, + { "clear_event", (PyCFunction)py_ue_clear_event, METH_VARARGS, "" }, { "bind_event", (PyCFunction)py_ue_bind_event, METH_VARARGS, "" }, { "delegate_bind_ufunction", (PyCFunction)py_ue_delegate_bind_ufunction, METH_VARARGS, "" }, @@ -559,8 +613,18 @@ static PyMethodDef ue_PyUObject_methods[] = { { "render_thumbnail", (PyCFunction)py_ue_render_thumbnail, METH_VARARGS, "" }, #endif +// Config #if WITH_EDITOR - { "save_config", (PyCFunction)py_ue_save_config, METH_VARARGS, "" }, +#pragma warning(suppress: 4191) + { "save_config", (PyCFunction)py_ue_save_config, METH_VARARGS | METH_KEYWORDS, "" }, +#pragma warning(suppress: 4191) + { "save_config_to_section", (PyCFunction)py_ue_save_config_to_section, METH_VARARGS | METH_KEYWORDS, "" }, +#pragma warning(suppress: 4191) + { "load_config", (PyCFunction)py_ue_load_config, METH_VARARGS | METH_KEYWORDS, "" }, +#pragma warning(suppress: 4191) + { "load_config_from_section", (PyCFunction)py_ue_load_config_from_section, METH_VARARGS | METH_KEYWORDS, "" }, + + { "set_folder_path", (PyCFunction)py_ue_actor_set_folder_path, METH_VARARGS, "" }, { "get_actor_label", (PyCFunction)py_ue_get_actor_label, METH_VARARGS, "" }, { "set_actor_label", (PyCFunction)py_ue_set_actor_label, METH_VARARGS, "" }, @@ -617,6 +681,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "export_to_file", (PyCFunction)py_ue_export_to_file, METH_VARARGS, "" }, { "is_rooted", (PyCFunction)py_ue_is_rooted, METH_VARARGS, "" }, + { "is_selected", (PyCFunction)py_ue_is_selected, METH_VARARGS, "" }, { "add_to_root", (PyCFunction)py_ue_add_to_root, METH_VARARGS, "" }, { "auto_root", (PyCFunction)py_ue_auto_root, METH_VARARGS, "" }, { "remove_from_root", (PyCFunction)py_ue_remove_from_root, METH_VARARGS, "" }, @@ -665,6 +730,7 @@ static PyMethodDef ue_PyUObject_methods[] = { #if WITH_EDITOR { "static_mesh_build", (PyCFunction)py_ue_static_mesh_build, METH_VARARGS, "" }, { "static_mesh_create_body_setup", (PyCFunction)py_ue_static_mesh_create_body_setup, METH_VARARGS, "" }, + { "static_mesh_can_lods_share_static_lighting", (PyCFunction)py_ue_static_mesh_can_lods_share_static_lighting, METH_VARARGS, "" }, #endif // Input @@ -722,10 +788,14 @@ static PyMethodDef ue_PyUObject_methods[] = { { "class_generated_by", (PyCFunction)py_ue_class_generated_by, METH_VARARGS, "" }, { "class_get_flags", (PyCFunction)py_ue_class_get_flags, METH_VARARGS, "" }, { "class_set_flags", (PyCFunction)py_ue_class_set_flags, METH_VARARGS, "" }, + { "class_has_any_flags", (PyCFunction)py_ue_class_has_any_flags, METH_VARARGS, "" }, { "get_obj_flags", (PyCFunction)py_ue_get_obj_flags, METH_VARARGS, "" }, { "set_obj_flags", (PyCFunction)py_ue_set_obj_flags, METH_VARARGS, "" }, #if WITH_EDITOR +#if ENGINE_MINOR_VERSION >= 19 + { "is_data_valid", (PyCFunction)py_ue_is_data_valid, METH_VARARGS, "" }, +#endif { "class_get_config_name", (PyCFunction)py_ue_class_get_config_name, METH_VARARGS, "" }, { "class_set_config_name", (PyCFunction)py_ue_class_set_config_name, METH_VARARGS, "" }, #endif @@ -737,6 +807,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "register_component", (PyCFunction)py_ue_register_component, METH_VARARGS, "" }, { "unregister_component", (PyCFunction)py_ue_unregister_component, METH_VARARGS, "" }, { "destroy_component", (PyCFunction)py_ue_destroy_component, METH_VARARGS, "" }, + { "actor_component_set_can_ever_affect_navigation", (PyCFunction)py_ue_actor_component_set_can_ever_affect_navigation, METH_VARARGS, "" }, { "actor_destroy_component", (PyCFunction)py_ue_actor_destroy_component, METH_VARARGS, "" }, { "destroy_actor_component", (PyCFunction)py_ue_actor_destroy_component, METH_VARARGS, "" }, @@ -751,6 +822,7 @@ static PyMethodDef ue_PyUObject_methods[] = { #if WITH_EDITOR { "get_metadata", (PyCFunction)py_ue_get_metadata, METH_VARARGS, "" }, { "set_metadata", (PyCFunction)py_ue_set_metadata, METH_VARARGS, "" }, + { "set_metadata_on_property", (PyCFunction)py_ue_set_metadata_on_property, METH_VARARGS, "" }, { "has_metadata", (PyCFunction)py_ue_has_metadata, METH_VARARGS, "" }, #endif @@ -783,6 +855,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_world_delta_seconds", (PyCFunction)py_ue_get_world_delta_seconds, METH_VARARGS, "" }, { "get_levels", (PyCFunction)py_ue_get_levels, METH_VARARGS, "" }, + { "get_actors", (PyCFunction)py_ue_get_actors, METH_VARARGS, "" }, + { "get_current_level", (PyCFunction)py_ue_get_current_level, METH_VARARGS, "" }, { "set_current_level", (PyCFunction)py_ue_set_current_level, METH_VARARGS, "" }, @@ -870,6 +944,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_overlapping_actors", (PyCFunction)py_ue_get_overlapping_actors, METH_VARARGS, "" }, { "actor_set_level_sequence", (PyCFunction)py_ue_actor_set_level_sequence, METH_VARARGS, "" }, + { "actor_get_level_sequence", (PyCFunction)py_ue_actor_get_level_sequence, METH_VARARGS, "" }, // MovieSceneCapture { "capture_initialize", (PyCFunction)py_ue_capture_initialize, METH_VARARGS, "" }, @@ -926,10 +1001,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "skeletal_mesh_get_lod", (PyCFunction)py_ue_skeletal_mesh_get_lod, METH_VARARGS, "" }, { "skeletal_mesh_get_raw_indices", (PyCFunction)py_ue_skeletal_mesh_get_raw_indices, METH_VARARGS, "" }, -#endif + { "skeletal_mesh_set_skeleton", (PyCFunction)py_ue_skeletal_mesh_set_skeleton, METH_VARARGS, "" }, -#if WITH_EDITOR #if ENGINE_MINOR_VERSION > 12 { "skeletal_mesh_get_bone_map", (PyCFunction)py_ue_skeletal_mesh_get_bone_map, METH_VARARGS, "" }, { "skeletal_mesh_set_bone_map", (PyCFunction)py_ue_skeletal_mesh_set_bone_map, METH_VARARGS, "" }, @@ -938,16 +1012,15 @@ static PyMethodDef ue_PyUObject_methods[] = { { "skeletal_mesh_set_required_bones", (PyCFunction)py_ue_skeletal_mesh_set_required_bones, METH_VARARGS, "" }, { "skeletal_mesh_get_active_bone_indices", (PyCFunction)py_ue_skeletal_mesh_get_active_bone_indices, METH_VARARGS, "" }, { "skeletal_mesh_get_required_bones", (PyCFunction)py_ue_skeletal_mesh_get_required_bones, METH_VARARGS, "" }, + { "skeletal_mesh_get_num_triangles", (PyCFunction)py_ue_skeletal_mesh_get_num_triangles, METH_VARARGS, "" }, + { "skeletal_mesh_lods_num", (PyCFunction)py_ue_skeletal_mesh_lods_num, METH_VARARGS, "" }, { "skeletal_mesh_sections_num", (PyCFunction)py_ue_skeletal_mesh_sections_num, METH_VARARGS, "" }, #pragma warning(suppress: 4191) { "skeletal_mesh_build_lod", (PyCFunction)py_ue_skeletal_mesh_build_lod, METH_VARARGS | METH_KEYWORDS, "" }, -#endif -#if WITH_EDITOR { "skeletal_mesh_register_morph_target", (PyCFunction)py_ue_skeletal_mesh_register_morph_target, METH_VARARGS, "" }, - { "skeletal_mesh_to_import_vertex_map", (PyCFunction)py_ue_skeletal_mesh_to_import_vertex_map, METH_VARARGS, "" }, { "morph_target_populate_deltas", (PyCFunction)py_ue_morph_target_populate_deltas, METH_VARARGS, "" }, @@ -978,6 +1051,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_create_folder", (PyCFunction)py_ue_sequencer_create_folder, METH_VARARGS, "" }, { "sequencer_set_display_name", (PyCFunction)py_ue_sequencer_set_display_name, METH_VARARGS, "" }, { "sequencer_get_display_name", (PyCFunction)py_ue_sequencer_get_display_name, METH_VARARGS, "" }, + { "sequencer_get_track_display_name", (PyCFunction)py_ue_sequencer_get_track_display_name, METH_VARARGS, "" }, + { "sequencer_get_track_unique_name", (PyCFunction)py_ue_sequencer_get_track_unique_name, METH_VARARGS, "" }, { "sequencer_changed", (PyCFunction)py_ue_sequencer_changed, METH_VARARGS, "" }, { "sequencer_add_camera_cut_track", (PyCFunction)py_ue_sequencer_add_camera_cut_track, METH_VARARGS, "" }, { "sequencer_add_actor", (PyCFunction)py_ue_sequencer_add_actor, METH_VARARGS, "" }, @@ -993,6 +1068,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_remove_camera_cut_track", (PyCFunction)py_ue_sequencer_remove_camera_cut_track, METH_VARARGS, "" }, { "sequencer_remove_master_track", (PyCFunction)py_ue_sequencer_remove_master_track, METH_VARARGS, "" }, { "sequencer_remove_track", (PyCFunction)py_ue_sequencer_remove_track, METH_VARARGS, "" }, +#if ENGINE_MINOR_VERSION >= 18 + { "sequencer_get_selected_sections", (PyCFunction)py_ue_sequencer_get_selected_sections, METH_VARARGS, "" }, +#endif { "sequencer_import_fbx_transform", (PyCFunction)py_ue_sequencer_import_fbx_transform, METH_VARARGS, "" }, #endif @@ -1002,6 +1080,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_possessables_guid", (PyCFunction)py_ue_sequencer_possessables_guid, METH_VARARGS, "" }, { "sequencer_find_possessable", (PyCFunction)py_ue_sequencer_find_possessable, METH_VARARGS, "" }, { "sequencer_find_spawnable", (PyCFunction)py_ue_sequencer_find_spawnable, METH_VARARGS, "" }, + { "sequencer_get_all_spawnables", (PyCFunction)py_ue_sequencer_get_all_spawnables, METH_VARARGS, "" }, { "sequencer_add_master_track", (PyCFunction)py_ue_sequencer_add_master_track, METH_VARARGS, "" }, @@ -1014,6 +1093,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "set_material_scalar_parameter", (PyCFunction)py_ue_set_material_scalar_parameter, METH_VARARGS, "" }, { "set_material_vector_parameter", (PyCFunction)py_ue_set_material_vector_parameter, METH_VARARGS, "" }, { "set_material_texture_parameter", (PyCFunction)py_ue_set_material_texture_parameter, METH_VARARGS, "" }, + { "get_material_instruction_count", (PyCFunction)py_ue_get_material_instruction_count, METH_VARARGS, "" }, + { "get_material_sampler_count", (PyCFunction)py_ue_get_material_sampler_count, METH_VARARGS, "" }, { "get_material_scalar_parameter", (PyCFunction)py_ue_get_material_scalar_parameter, METH_VARARGS, "" }, { "get_material_vector_parameter", (PyCFunction)py_ue_get_material_vector_parameter, METH_VARARGS, "" }, { "get_material_texture_parameter", (PyCFunction)py_ue_get_material_texture_parameter, METH_VARARGS, "" }, @@ -1024,6 +1105,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "static_mesh_set_collision_for_lod", (PyCFunction)py_ue_static_mesh_set_collision_for_lod, METH_VARARGS, "" }, { "static_mesh_set_shadow_for_lod", (PyCFunction)py_ue_static_mesh_set_shadow_for_lod, METH_VARARGS, "" }, { "get_raw_mesh", (PyCFunction)py_ue_static_mesh_get_raw_mesh, METH_VARARGS, "" }, + { "get_num_triangles", (PyCFunction)py_ue_static_mesh_get_num_triangles, METH_VARARGS, "" }, #endif // Viewport @@ -1238,11 +1320,12 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject } PyObject *py_name = nullptr; PyObject *py_outer = Py_None; - if (!PyArg_ParseTuple(args, "|OO:new_object", &py_name, &py_outer)) + uint64 flags = (uint64)(RF_Public); + if (!PyArg_ParseTuple(args, "|OOK:new_object", &py_name, &py_outer, &flags)) { return NULL; } - int num_args = py_name ? 3 : 1; + int num_args = py_name ? 4 : 1; PyObject *py_args = PyTuple_New(num_args); Py_INCREF((PyObject *)self); PyTuple_SetItem(py_args, 0, (PyObject *)self); @@ -1252,6 +1335,7 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject PyTuple_SetItem(py_args, 1, py_outer); Py_INCREF(py_name); PyTuple_SetItem(py_args, 2, py_name); + PyTuple_SetItem(py_args, 3, PyLong_FromLongLong(flags)); } PyObject *ret = py_unreal_engine_new_object(nullptr, py_args); Py_DECREF(py_args); @@ -1494,11 +1578,9 @@ void unreal_engine_init_py_module() ue_python_init_frandomstream(new_unreal_engine_module); ue_python_init_fraw_anim_sequence_track(new_unreal_engine_module); - #if WITH_EDITOR ue_python_init_fsoft_skin_vertex(new_unreal_engine_module); #endif - ue_python_init_fmorph_target_delta(new_unreal_engine_module); ue_python_init_fobject_thumbnail(new_unreal_engine_module); @@ -1594,8 +1676,10 @@ void unreal_engine_init_py_module() // Classes PyDict_SetItemString(unreal_engine_dict, "CLASS_CONFIG", PyLong_FromUnsignedLongLong((uint64)CLASS_Config)); PyDict_SetItemString(unreal_engine_dict, "CLASS_DEFAULT_CONFIG", PyLong_FromUnsignedLongLong((uint64)CLASS_DefaultConfig)); + PyDict_SetItemString(unreal_engine_dict, "CLASS_PER_OBJECT_CONFIG", PyLong_FromUnsignedLongLong((uint64)CLASS_PerObjectConfig)); PyDict_SetItemString(unreal_engine_dict, "CLASS_ABSTRACT", PyLong_FromUnsignedLongLong((uint64)CLASS_Abstract)); PyDict_SetItemString(unreal_engine_dict, "CLASS_INTERFACE", PyLong_FromUnsignedLongLong((uint64)CLASS_Interface)); + PyDict_SetItemString(unreal_engine_dict, "CLASS_NEWER_VERSION_EXISTS", PyLong_FromUnsignedLongLong((uint64)CLASS_NewerVersionExists)); // Objects PyDict_SetItemString(unreal_engine_dict, "RF_NOFLAGS", PyLong_FromUnsignedLongLong((uint64)RF_NoFlags)); @@ -1635,6 +1719,8 @@ void unreal_engine_init_py_module() PyDict_SetItemString(unreal_engine_dict, "CPF_CONFIG", PyLong_FromUnsignedLongLong((uint64)CPF_Config)); PyDict_SetItemString(unreal_engine_dict, "CPF_GLOBAL_CONFIG", PyLong_FromUnsignedLongLong((uint64)CPF_GlobalConfig)); PyDict_SetItemString(unreal_engine_dict, "CPF_EXPOSE_ON_SPAWN", PyLong_FromUnsignedLongLong((uint64)CPF_ExposeOnSpawn)); + PyDict_SetItemString(unreal_engine_dict, "CPF_ADVANCED_DISPLAY", PyLong_FromUnsignedLongLong((uint64)CPF_AdvancedDisplay)); + PyDict_SetItemString(unreal_engine_dict, "CPF_EDIT_CONST", PyLong_FromUnsignedLongLong((uint64)CPF_EditConst)); PyDict_SetItemString(unreal_engine_dict, "CPF_NET", PyLong_FromUnsignedLongLong((uint64)CPF_Net)); PyDict_SetItemString(unreal_engine_dict, "CPF_REP_NOTIFY", PyLong_FromUnsignedLongLong((uint64)CPF_RepNotify)); @@ -1928,18 +2014,19 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) // check for FVector if (casted_struct == TBaseStructure::Get()) { - FVector vec = *casted_prop->ContainerPtrToValuePtr(buffer, index); - return py_ue_new_fvector(vec); + return py_ue_new_fvector_ptr(casted_prop->ContainerPtrToValuePtr(buffer, index)); } if (casted_struct == TBaseStructure::Get()) { - FRotator rot = *casted_prop->ContainerPtrToValuePtr(buffer, index); - return py_ue_new_frotator(rot); + return py_ue_new_frotator_ptr(casted_prop->ContainerPtrToValuePtr(buffer, index)); + } + if (casted_struct == TBaseStructure::Get()) + { + return py_ue_new_fquat_ptr(casted_prop->ContainerPtrToValuePtr(buffer, index)); } if (casted_struct == TBaseStructure::Get()) { - FTransform transform = *casted_prop->ContainerPtrToValuePtr(buffer, index); - return py_ue_new_ftransform(transform); + return py_ue_new_ftransform_ptr(casted_prop->ContainerPtrToValuePtr(buffer, index)); } if (casted_struct == FHitResult::StaticStruct()) { @@ -2324,7 +2411,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_vec->vec; + *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_ue_fvector_get(py_vec); return true; } } @@ -2337,7 +2424,20 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_rot->rot; + *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_ue_frotator_get(py_rot); + return true; + } + } + return false; + } + + if (ue_PyFQuat *py_quat = py_ue_is_fquat(py_obj)) + { + if (auto casted_prop = Cast(prop)) + { + if (casted_prop->Struct == TBaseStructure::Get()) + { + *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_ue_fquat_get(py_quat); return true; } } @@ -2350,7 +2450,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_transform->transform; + *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_ue_ftransform_get(py_transform); return true; } } @@ -2405,7 +2505,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in if (casted_prop->Struct == py_u_struct->u_struct) { uint8 *dest = casted_prop->ContainerPtrToValuePtr(buffer, index); - FMemory::Memcpy(dest, py_u_struct->data, py_u_struct->u_struct->GetStructureSize()); + FMemory::Memcpy(dest, py_ue_uscriptstruct_get_data(py_u_struct), py_u_struct->u_struct->GetStructureSize()); return true; } } @@ -2479,6 +2579,48 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } + if (PyCallable_Check(py_obj)) + { + if (auto casted_multicastdelegate_prop = Cast(prop)) + { + FMulticastScriptDelegate* multiscript_delegate = casted_multicastdelegate_prop->GetPropertyValuePtr_InContainer(buffer); + new(multiscript_delegate) FMulticastScriptDelegate(); + + FScriptDelegate script_delegate; + //TODO: ikrimae: #ThirdParty-Python: Not sure if this will auto cleanup when the function parameters are destroyed or if the GWorld owner will force it to keep alive + UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(GWorld, py_obj, casted_multicastdelegate_prop->SignatureFunction); + // fake UFUNCTION for bypassing checks + script_delegate.BindUFunction(py_delegate, FName("PyFakeCallable")); + + // add the new delegate + multiscript_delegate->Add(script_delegate); + + // Should not be needed anymore + //// re-assign multicast delegate + //casted_multicastdelegate_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + return true; + } + else if (auto casted_delegate_prop = Cast(prop)) + { + FScriptDelegate* script_delegate = casted_delegate_prop->GetPropertyValuePtr_InContainer(buffer); + new(script_delegate) FScriptDelegate(); + + //TODO: ikrimae: #ThirdParty-Python: Not sure if this will auto cleanup when the function parameters are destroyed or if the GWorld owner will force it to keep alive + UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(GWorld, py_obj, casted_delegate_prop->SignatureFunction); + // fake UFUNCTION for bypassing checks + script_delegate->BindUFunction(py_delegate, FName("PyFakeCallable")); + + // add the new delegate + //multiscript_delegate->Add(script_delegate); + + // Should not be needed anymore + //// re-assign multicast delegate + //casted_delegate_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + return true; + } + + } + if (py_obj == Py_None) { auto casted_prop_class = Cast(prop); @@ -2811,6 +2953,7 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * return Py_None; } + PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) { @@ -2824,7 +2967,7 @@ PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_ if (auto casted_prop = Cast(u_property)) { - FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object); + FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(u_obj->ue_object); FScriptDelegate script_delegate; UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(u_obj->ue_object, py_callable, casted_prop->SignatureFunction); @@ -2832,10 +2975,11 @@ PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_ script_delegate.BindUFunction(py_delegate, FName("PyFakeCallable")); // add the new delegate - multiscript_delegate.Add(script_delegate); + multiscript_delegate->Add(script_delegate); - // re-assign multicast delegate - casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); + // Should not be needed anymore + //// re-assign multicast delegate + //casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); } else if (auto casted_prop_delegate = Cast(u_property)) { @@ -3197,9 +3341,9 @@ FGuid *ue_py_check_fguid(PyObject *py_obj) return nullptr; } - if (ue_py_struct->u_struct == FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid"))) + if (ue_py_struct->u_struct == TBaseStructure::Get()) { - return (FGuid*)ue_py_struct->data; + return (FGuid*)(py_ue_uscriptstruct_get_data(ue_py_struct)); } return nullptr; @@ -3214,7 +3358,7 @@ uint8 * do_ue_py_check_struct(PyObject *py_obj, UScriptStruct* chk_u_struct) if (ue_py_struct->u_struct == chk_u_struct) { - return ue_py_struct->data; + return py_ue_uscriptstruct_get_data(ue_py_struct); } return nullptr; diff --git a/Source/UnrealEnginePython/Private/UEPyModule.h b/Source/UnrealEnginePython/Private/UEPyModule.h index b193e0a10..c39345e9b 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.h +++ b/Source/UnrealEnginePython/Private/UEPyModule.h @@ -32,6 +32,12 @@ PyObject *py_ue_ufunction_call(UFunction *, UObject *, PyObject *, int, PyObject UClass *unreal_engine_new_uclass(char *, UClass *); UFunction *unreal_engine_add_function(UClass *, char *, PyObject *, uint32); +#if ENGINE_MINOR_VERSION <= 17 +template<> struct TBaseStructure +{ + static UScriptStruct* Get(); +}; +#endif template T *ue_py_check_type(PyObject *py_obj) { diff --git a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp index b0afc78a5..e7a2b7864 100644 --- a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp +++ b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp @@ -111,6 +111,15 @@ int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) } prop_added = true; } + else if (py_obj->ue_object->IsA()) + { + if (!py_ue_add_property(self, Py_BuildValue("(OsO)", value, class_key, py_obj))) + { + unreal_engine_py_log_error(); + return -1; + } + prop_added = true; + } } // add array property @@ -346,7 +355,7 @@ int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) { if (auto casted_prop = Cast(u_property)) { - FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(ObjectInitializer.GetObj()); + FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(ObjectInitializer.GetObj()); FScriptDelegate script_delegate; UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(ObjectInitializer.GetObj(), mc_value, casted_prop->SignatureFunction); @@ -354,10 +363,11 @@ int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) script_delegate.BindUFunction(py_delegate, FName("PyFakeCallable")); // add the new delegate - multiscript_delegate.Add(script_delegate); + multiscript_delegate->Add(script_delegate); - // re-assign multicast delegate - casted_prop->SetPropertyValue_InContainer(ObjectInitializer.GetObj(), multiscript_delegate); + // Should not be needed anymore + //// re-assign multicast delegate + //casted_prop->SetPropertyValue_InContainer(ObjectInitializer.GetObj(), multiscript_delegate); } else { diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp index cac103f1e..24df9268e 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp @@ -1,6 +1,7 @@ // Copyright 20Tab S.r.l. #include "UEPyUScriptStruct.h" +#include "UEPyModule.h" static PyObject *py_ue_uscriptstruct_get_field(ue_PyUScriptStruct *self, PyObject * args) @@ -16,7 +17,7 @@ static PyObject *py_ue_uscriptstruct_get_field(ue_PyUScriptStruct *self, PyObjec if (!u_property) return PyErr_Format(PyExc_Exception, "unable to find property %s", name); - return ue_py_convert_property(u_property, self->data, index); + return ue_py_convert_property(u_property, py_ue_uscriptstruct_get_data(self), index); } static PyObject *py_ue_uscriptstruct_get_field_array_dim(ue_PyUScriptStruct *self, PyObject * args) @@ -49,7 +50,7 @@ static PyObject *py_ue_uscriptstruct_set_field(ue_PyUScriptStruct *self, PyObjec return PyErr_Format(PyExc_Exception, "unable to find property %s", name); - if (!ue_py_convert_pyobject(value, u_property, self->data, index)) + if (!ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self), index)) { return PyErr_Format(PyExc_Exception, "unable to set property %s", name); } @@ -80,7 +81,7 @@ static PyObject *py_ue_uscriptstruct_get_struct(ue_PyUScriptStruct *self, PyObje static PyObject *py_ue_uscriptstruct_clone(ue_PyUScriptStruct *self, PyObject * args) { - return py_ue_new_uscriptstruct(self->u_struct, self->data); + return py_ue_new_uscriptstruct(self->u_struct, py_ue_uscriptstruct_get_data(self)); } PyObject *py_ue_uscriptstruct_as_dict(ue_PyUScriptStruct * self, PyObject * args) @@ -98,7 +99,7 @@ PyObject *py_ue_uscriptstruct_as_dict(ue_PyUScriptStruct * self, PyObject * args TFieldIterator SArgs(self->u_struct); for (; SArgs; ++SArgs) { - PyObject *struct_value = ue_py_convert_property(*SArgs, self->data, 0); + PyObject *struct_value = ue_py_convert_property(*SArgs, py_ue_uscriptstruct_get_data(self), 0); if (!struct_value) { Py_DECREF(py_struct_dict); @@ -143,7 +144,7 @@ static PyMethodDef ue_PyUScriptStruct_methods[] = { static PyObject *ue_PyUScriptStruct_str(ue_PyUScriptStruct *self) { return PyUnicode_FromFormat("", - TCHAR_TO_UTF8(*self->u_struct->GetName()), self->u_struct->GetStructureSize(), self->data); + TCHAR_TO_UTF8(*self->u_struct->GetName()), self->u_struct->GetStructureSize(), py_ue_uscriptstruct_get_data(self)); } static UProperty *get_field_from_name(UScriptStruct *u_struct, char *name) @@ -193,7 +194,7 @@ static PyObject *ue_PyUScriptStruct_getattro(ue_PyUScriptStruct *self, PyObject { // swallow previous exception PyErr_Clear(); - return ue_py_convert_property(u_property, self->data, 0); + return ue_py_convert_property(u_property, py_ue_uscriptstruct_get_data(self), 0); } } } @@ -210,8 +211,14 @@ static int ue_PyUScriptStruct_setattro(ue_PyUScriptStruct *self, PyObject *attr_ UProperty *u_property = get_field_from_name(self->u_struct, attr); if (u_property) { - if (ue_py_convert_pyobject(value, u_property, self->data, 0)) + if (ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self), 0)) { + if (self->is_ptr) + { + // NOTE: We just wrote out to original pointer block; now we need to update our local shadow copy + // This might be unnecessary + FMemory::Memcpy(self->data, self->original_data, self->u_struct->GetStructureSize()); + } return 0; } PyErr_SetString(PyExc_ValueError, "invalid value for UProperty"); @@ -236,7 +243,7 @@ static void ue_PyUScriptStruct_dealloc(ue_PyUScriptStruct *self) Py_TYPE(self)->tp_free((PyObject *)self); } -static PyTypeObject ue_PyUScriptStructType = { +PyTypeObject ue_PyUScriptStructType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.UScriptStruct", /* tp_name */ sizeof(ue_PyUScriptStruct), /* tp_basicsize */ @@ -269,6 +276,28 @@ static PyTypeObject ue_PyUScriptStructType = { 0, }; + +void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *self, UScriptStruct* in_u_struct, uint8 const* in_src_data, bool keep_src_ptr) +{ + self->u_struct = in_u_struct; + self->data = (uint8*)FMemory::Malloc(self->u_struct->GetStructureSize()); + self->u_struct->InitializeStruct(self->data); + + if (in_src_data) + { + self->u_struct->CopyScriptStruct(self->data, in_src_data); + } + else + { +#if WITH_EDITOR + self->u_struct->InitializeDefaultValue(self->data); +#endif + } + + self->original_data = keep_src_ptr && in_src_data ? const_cast(in_src_data) : self->data; + self->is_ptr = 0; +} + static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, PyObject *kwargs) { PyObject *py_struct; @@ -287,15 +316,7 @@ static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, Py PyErr_SetString(PyExc_Exception, "argument is not a UScriptStruct"); return -1; } - - self->u_struct = (UScriptStruct *)py_u_obj->ue_object; - self->data = (uint8*)FMemory::Malloc(self->u_struct->GetStructureSize()); - self->u_struct->InitializeStruct(self->data); -#if WITH_EDITOR - self->u_struct->InitializeDefaultValue(self->data); -#endif - self->original_data = self->data; - self->is_ptr = 0; + ue_py_uscriptstruct_alloc(self, (UScriptStruct *)py_u_obj->ue_object, nullptr, false); return 0; } @@ -305,7 +326,7 @@ static PyObject *py_ue_uscriptstruct_ref(ue_PyUScriptStruct *self, PyObject * ar ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); ret->u_struct = self->u_struct; ret->data = self->original_data; - ret->original_data = ret->data; + ret->original_data = self->original_data; ret->is_ptr = 1; return (PyObject *)ret; } @@ -318,7 +339,7 @@ static PyObject *ue_py_uscriptstruct_richcompare(ue_PyUScriptStruct *u_struct1, return PyErr_Format(PyExc_NotImplementedError, "can only compare with another UScriptStruct"); } - bool equals = (u_struct1->u_struct == u_struct2->u_struct && !memcmp(u_struct1->data, u_struct2->data, u_struct1->u_struct->GetStructureSize())); + bool equals = (u_struct1->u_struct == u_struct2->u_struct && !memcmp(py_ue_uscriptstruct_get_data(u_struct1), py_ue_uscriptstruct_get_data(u_struct2), u_struct1->u_struct->GetStructureSize())); if (op == Py_EQ) { @@ -354,16 +375,10 @@ void ue_python_init_uscriptstruct(PyObject *ue_module) PyModule_AddObject(ue_module, "UScriptStruct", (PyObject *)&ue_PyUScriptStructType); } -PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *data) +PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *in_data) { ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); - ret->u_struct = u_struct; - uint8 *struct_data = (uint8*)FMemory::Malloc(u_struct->GetStructureSize()); - ret->u_struct->InitializeStruct(struct_data); - ret->u_struct->CopyScriptStruct(struct_data, data); - ret->data = struct_data; - ret->original_data = data; - ret->is_ptr = 0; + ue_py_uscriptstruct_alloc(ret, u_struct, in_data, true); return (PyObject *)ret; } diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h index 8630ab43c..4b617ca4c 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h @@ -1,12 +1,14 @@ #pragma once -#include "UEPyModule.h" +#include "UnrealEnginePython.h" + +class UScriptStruct; typedef struct { PyObject_HEAD - /* Type-specific fields go here. */ - UScriptStruct *u_struct; + /* Type-specific fields go here. */ + UScriptStruct *u_struct; uint8 *data; // if 1, data points to un-owned memory int is_ptr; @@ -16,8 +18,14 @@ typedef struct PyObject *py_ue_new_uscriptstruct(UScriptStruct *, uint8 *); PyObject *py_ue_wrap_uscriptstruct(UScriptStruct *, uint8 *); +void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *, UScriptStruct *, uint8 const*, bool); ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *); +inline static uint8* py_ue_uscriptstruct_get_data(ue_PyUScriptStruct *py_u_struct) +{ + return (uint8*)(py_u_struct->is_ptr ? py_u_struct->original_data : py_u_struct->data); +} + UProperty *ue_struct_get_field_from_name(UScriptStruct *, char *); void ue_python_init_uscriptstruct(PyObject *); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp b/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp index b84d3357c..6ee283e82 100644 --- a/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp +++ b/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp @@ -65,7 +65,7 @@ PyObject *py_ue_vlog_cylinder(ue_PyUObject *self, PyObject * args) FVisualLogger::GeometryShapeLogf(self->ue_object, FLogCategoryBase(UTF8_TO_TCHAR(category), (ELogVerbosity::Type)verbosity, (ELogVerbosity::Type)verbosity), (ELogVerbosity::Type)verbosity, - py_vec_start->vec, py_vec_end->vec, radius, color, + py_ue_fvector_get(py_vec_start), py_ue_fvector_get(py_vec_end), radius, color, TEXT("%s"), UTF8_TO_TCHAR(text)); } #endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp index 3e992e2e5..31961cf26 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp @@ -126,6 +126,24 @@ PyObject *py_ue_actor_destroy_component(ue_PyUObject * self, PyObject * args) return Py_None; } +PyObject *py_ue_actor_component_set_can_ever_affect_navigation(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + UActorComponent *actor_component = ue_py_check_type(self); + if (!actor_component) + return PyErr_Format(PyExc_Exception, "Self is not a UActorComponent"); + + PyObject *py_bool; + if (!PyArg_ParseTuple(args, "O:actor_component_set_can_ever_affect_navigation", &py_bool)) + { + return NULL; + } + actor_component->SetCanEverAffectNavigation(PyObject_IsTrue(py_bool) ? true : false); + + Py_RETURN_NONE; +} + PyObject *py_ue_actor_destroy(ue_PyUObject * self, PyObject * args) { @@ -182,6 +200,36 @@ PyObject *py_ue_get_actor_velocity(ue_PyUObject *self, PyObject * args) #if WITH_EDITOR +PyObject * py_ue_actor_set_folder_path(ue_PyUObject* self, PyObject * args) +{ + ue_py_check(self); + + char *folder_path = nullptr; + PyObject *py_bool = nullptr; + if (!PyArg_ParseTuple(args, "s|O:set_folder_path", &folder_path, &py_bool)) + { + return NULL; + } + + AActor *actor = ue_py_check_type(self); + if (!actor) + { + return PyErr_Format(PyExc_Exception, "uobject is not an Actor!"); + } + + bool bSetRecursively = py_bool && PyObject_IsTrue(py_bool) ? true : false; + if (bSetRecursively) + { + actor->SetFolderPath(FName(folder_path)); + } + else + { + actor->SetFolderPath_Recursively(FName(folder_path)); + } + + Py_RETURN_NONE; +} + PyObject *py_ue_get_actor_label(ue_PyUObject *self, PyObject * args) { @@ -771,7 +819,7 @@ PyObject *py_ue_actor_spawn(ue_PyUObject * self, PyObject * args, PyObject *kwar ue_PyFVector *py_location = py_ue_is_fvector(py_obj_location); if (!py_location) return PyErr_Format(PyExc_Exception, "location must be an FVector"); - location = py_location->vec; + location = py_ue_fvector_get(py_location); } if (py_obj_rotation) @@ -779,7 +827,7 @@ PyObject *py_ue_actor_spawn(ue_PyUObject * self, PyObject * args, PyObject *kwar ue_PyFRotator *py_rotation = py_ue_is_frotator(py_obj_rotation); if (!py_rotation) return PyErr_Format(PyExc_Exception, "location must be an FRotator"); - rotation = py_rotation->rot; + rotation = py_ue_frotator_get(py_rotation); } if (kwargs && PyDict_Size(kwargs) > 0) @@ -892,6 +940,32 @@ PyObject *py_ue_actor_set_level_sequence(ue_PyUObject * self, PyObject * args) Py_RETURN_NONE; } +PyObject *py_ue_actor_get_level_sequence(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + if (!PyArg_ParseTuple(args, ":actor_get_level_sequence")) + { + return NULL; + } + + ALevelSequenceActor *actor = ue_py_check_type(self); + if (!actor) + { + return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequenceActor"); + } + + ULevelSequence * retSequence = nullptr; + retSequence = actor->GetSequence(true, false); + + if (retSequence == nullptr) + Py_RETURN_NONE; + + Py_RETURN_UOBJECT(retSequence); + +} + #if WITH_EDITOR PyObject *py_ue_get_editor_world_counterpart_actor(ue_PyUObject * self, PyObject * args) @@ -909,4 +983,15 @@ PyObject *py_ue_get_editor_world_counterpart_actor(ue_PyUObject * self, PyObject Py_RETURN_UOBJECT(editor_actor); } + +PyObject *py_ue_get_num_uncached_static_lighting_interactions(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + + UPrimitiveComponent *component = ue_py_check_type(self); + if (!component) + return PyErr_Format(PyExc_Exception, "uobject is not a primitive component"); + + return PyLong_FromLong(component->GetNumUncachedStaticLightingInteractions()); +} #endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.h b/Source/UnrealEnginePython/Private/UObject/UEPyActor.h index 2d8fb3690..c400e03ce 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.h @@ -23,11 +23,14 @@ PyObject *py_ue_actor_destroy(ue_PyUObject *, PyObject *); PyObject *py_ue_actor_components(ue_PyUObject *, PyObject *); PyObject *py_ue_get_actor_velocity(ue_PyUObject *, PyObject *); PyObject *py_ue_actor_set_level_sequence(ue_PyUObject *, PyObject *); +PyObject *py_ue_actor_get_level_sequence(ue_PyUObject * self, PyObject * args); #if WITH_EDITOR +PyObject *py_ue_actor_set_folder_path(ue_PyUObject *, PyObject *); PyObject *py_ue_get_actor_label(ue_PyUObject *, PyObject *); PyObject *py_ue_set_actor_label(ue_PyUObject *, PyObject *); PyObject *py_ue_find_actor_by_label(ue_PyUObject *, PyObject *); PyObject *py_ue_get_editor_world_counterpart_actor(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_num_uncached_static_lighting_interactions(ue_PyUObject *self, PyObject * args); #endif PyObject *py_ue_get_owner(ue_PyUObject *, PyObject *); PyObject *py_ue_add_actor_component(ue_PyUObject *, PyObject *); @@ -42,6 +45,7 @@ PyObject *py_ue_get_overlapping_actors(ue_PyUObject *, PyObject *); PyObject *py_ue_actor_destroy_component(ue_PyUObject *, PyObject *); +PyObject *py_ue_actor_component_set_can_ever_affect_navigation(ue_PyUObject * self, PyObject * args); PyObject *py_ue_register_component(ue_PyUObject * self, PyObject *); PyObject *py_ue_unregister_component(ue_PyUObject * self, PyObject *); PyObject *py_ue_destroy_component(ue_PyUObject * self, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp index 93f6e14b0..0d379c263 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp @@ -146,7 +146,7 @@ PyObject *py_ue_play_sound_at_location(ue_PyUObject *self, PyObject * args) if (!location) return PyErr_Format(PyExc_TypeError, "sound location must be a FVector"); - UGameplayStatics::PlaySoundAtLocation(self->ue_object, sound_object, location->vec, volume, pitch, start); + UGameplayStatics::PlaySoundAtLocation(self->ue_object, sound_object, py_ue_fvector_get(location), volume, pitch, start); Py_RETURN_NONE; } \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp index 15519285a..4b01d4381 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp @@ -99,7 +99,7 @@ PyObject *py_ue_controller_project_world_location_to_screen(ue_PyUObject * self, // TODO: Check return value: FVector2D screenLocation; - if (!controller->ProjectWorldLocationToScreen(point->vec, screenLocation, (py_relative && PyObject_IsTrue(py_relative)))) + if (!controller->ProjectWorldLocationToScreen(py_ue_fvector_get(point), screenLocation, (py_relative && PyObject_IsTrue(py_relative)))) { return PyErr_Format(PyExc_Exception, "unable to project coordinates"); } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyDataTable.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyDataTable.cpp index 11450d5b6..408a6249a 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyDataTable.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyDataTable.cpp @@ -38,7 +38,7 @@ PyObject *py_ue_data_table_add_row(ue_PyUObject * self, PyObject * args) if (!row) return PyErr_Format(PyExc_Exception, "unable to add row"); data_table->RowStruct->InitializeStruct(row); - data_table->RowStruct->CopyScriptStruct(row, u_struct->data); + data_table->RowStruct->CopyScriptStruct(row, py_ue_uscriptstruct_get_data(u_struct)); Py_RETURN_NONE; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp index ee0d5b4a6..cec76325f 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp @@ -6,6 +6,80 @@ #include "Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h" #include "Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphSchema.h" #endif +#include +#include +#include +#include "Materials/Material.h" + +PyObject *py_ue_get_material_instruction_count(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + uint64 feature_level = ERHIFeatureLevel::SM5, material_quality = EMaterialQualityLevel::High, shader_platform = EShaderPlatform::SP_PCD3D_SM5; + if (!PyArg_ParseTuple(args, "KKK:get_material_instruction_count", &feature_level, &material_quality, &shader_platform)) + { + return nullptr; + } + + if (!self->ue_object->GetClass()->IsChildOf()) + { + return PyErr_Format(PyExc_Exception, "uobject is not a UMaterialInterface"); + } + + UMaterialInterface *material = (UMaterialInterface *)self->ue_object; + UMaterialInterface *old_material = nullptr; + FMaterialResource * material_resource = material->GetMaterialResource((ERHIFeatureLevel::Type)feature_level, (EMaterialQualityLevel::Type)material_quality); + int instruction_count = 0; + if (material_resource == nullptr) + { + // If this is an instance, will get the resource from parent material + material = material->GetMaterial(); + } + + material_resource = material->GetMaterialResource((ERHIFeatureLevel::Type)feature_level, (EMaterialQualityLevel::Type)material_quality); + FMaterialShaderMapId OutId; + TArray Descriptions; + TArray InstructionCounts; + + material_resource->GetRepresentativeInstructionCounts(Descriptions, InstructionCounts); + + // [0] = Base pass shader count, [Last] = Vertex shader, discarding the other two as they are permutations of 0 for surface/volumetric lightmap cases + instruction_count = InstructionCounts.Last() + InstructionCounts[0]; + + return PyLong_FromLong(instruction_count); +} + +PyObject *py_ue_get_material_sampler_count(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + uint64 feature_level = ERHIFeatureLevel::SM5, material_quality = EMaterialQualityLevel::High, shader_platform = EShaderPlatform::SP_PCD3D_SM5; + if (!PyArg_ParseTuple(args, "KKK:get_material_sampler_count", &feature_level, &material_quality, &shader_platform)) + { + return nullptr; + } + + if (!self->ue_object->GetClass()->IsChildOf()) + { + return PyErr_Format(PyExc_Exception, "uobject is not a UMaterialInterface"); + } + + UMaterialInterface *material = (UMaterialInterface *)self->ue_object; + UMaterialInterface *old_material = nullptr; + FMaterialResource * material_resource = material->GetMaterialResource((ERHIFeatureLevel::Type)feature_level, (EMaterialQualityLevel::Type)material_quality); + if (material_resource == nullptr) + { + // If this is an instance, will get the resource from parent material + material = material->GetMaterial(); + } + + material_resource = material->GetMaterialResource((ERHIFeatureLevel::Type)feature_level, (EMaterialQualityLevel::Type)material_quality); + FMaterialShaderMapId OutId; + material_resource->GetShaderMapId((EShaderPlatform)shader_platform, OutId); + + int sampler_count = 0; + sampler_count += material_resource->GetSamplerUsage(); + + return PyLong_FromLong(sampler_count); +} #include "Materials/MaterialInstanceConstant.h" #include "Materials/MaterialInstanceDynamic.h" @@ -190,9 +264,9 @@ PyObject *py_ue_set_material_vector_parameter(ue_PyUObject *self, PyObject * arg } else { - vectorParameter.R = py_true_vector->vec.X; - vectorParameter.G = py_true_vector->vec.Y; - vectorParameter.B = py_true_vector->vec.Z; + vectorParameter.R = py_ue_fvector_get(py_true_vector).X; + vectorParameter.G = py_ue_fvector_get(py_true_vector).Y; + vectorParameter.B = py_ue_fvector_get(py_true_vector).Z; vectorParameter.A = 1; } } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h index f2b0516c0..1425b2639 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h @@ -4,6 +4,8 @@ +PyObject *py_ue_get_material_instruction_count(ue_PyUObject *self, PyObject * args); +PyObject *py_ue_get_material_sampler_count(ue_PyUObject *self, PyObject * args); PyObject *py_ue_set_material_scalar_parameter(ue_PyUObject *, PyObject *); PyObject *py_ue_set_material_vector_parameter(ue_PyUObject *, PyObject *); PyObject *py_ue_set_material_texture_parameter(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp index d325ddefe..519cc0e54 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp @@ -181,7 +181,7 @@ PyObject *py_ue_add_movement_input(ue_PyUObject *self, PyObject * args) if (!movement) return PyErr_Format(PyExc_Exception, "movement input must be a FVector"); - pawn->AddMovementInput(movement->vec, scale, force); + pawn->AddMovementInput(py_ue_fvector_get(movement), scale, force); Py_INCREF(Py_None); return Py_None; @@ -403,7 +403,7 @@ PyObject *py_ue_launch(ue_PyUObject *self, PyObject * args) if (!force) return PyErr_Format(PyExc_Exception, "launch force must be a FVector"); - character->LaunchCharacter(force->vec, xy_override, z_override); + character->LaunchCharacter(py_ue_fvector_get(force), xy_override, z_override); Py_INCREF(Py_None); return Py_None; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index a6b207989..44d974bb8 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -13,6 +13,7 @@ #include "Wrappers/UEPyFObjectThumbnail.h" #endif +#include PyObject *py_ue_get_class(ue_PyUObject * self, PyObject * args) { @@ -70,6 +71,27 @@ PyObject *py_ue_class_set_flags(ue_PyUObject * self, PyObject * args) Py_RETURN_NONE; } +PyObject *py_ue_class_has_any_flags(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + uint64 flags; + if (!PyArg_ParseTuple(args, "K:class_has_any_flags", &flags)) + { + return nullptr; + } + + UClass *u_class = ue_py_check_type(self); + if (!u_class) + return PyErr_Format(PyExc_Exception, "uobject is a not a UClass"); + + if (u_class->HasAnyClassFlags((EClassFlags)flags)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + PyObject *py_ue_get_obj_flags(ue_PyUObject * self, PyObject * args) { ue_py_check(self); @@ -95,6 +117,38 @@ PyObject *py_ue_set_obj_flags(ue_PyUObject * self, PyObject * args) #if WITH_EDITOR + +#if ENGINE_MINOR_VERSION >= 19 +PyObject *py_ue_is_data_valid(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + PyObject* py_validErrors = nullptr; + if (!PyArg_ParseTuple(args, "O:is_data_valid", &py_validErrors)) + { + return NULL; + } + + UObject* uobj = ue_py_check_type(self); + if (!uobj) + { return PyErr_Format(PyExc_Exception, "object is not a valid UObject"); } + + if (!PyList_Check(py_validErrors)) + { + return PyErr_Format(PyExc_Exception, "validation errors must be an array "); + } + + TArray newValidErrors; + EDataValidationResult validationResult = uobj->IsDataValid(newValidErrors); + for (const FText& validError : newValidErrors) + { + PyList_Append(py_validErrors, PyUnicode_FromString(TCHAR_TO_UTF8(*validError.ToString()))); + } + + return PyLong_FromLong((uint8)validationResult); +} +#endif + PyObject *py_ue_class_set_config_name(ue_PyUObject * self, PyObject * args) { @@ -155,10 +209,52 @@ PyObject *py_ue_get_property_struct(ue_PyUObject * self, PyObject * args) if (!u_property) return PyErr_Format(PyExc_Exception, "unable to find property %s", property_name); - UStructProperty *prop = Cast(u_property); - if (!prop) - return PyErr_Format(PyExc_Exception, "object is not a StructProperty"); - return py_ue_new_uscriptstruct(prop->Struct, prop->ContainerPtrToValuePtr(self->ue_object)); + UStruct* ret_prop_ustruct = nullptr; + if (UObjectPropertyBase* uobj_prop = Cast(u_property)) + { + ret_prop_ustruct = uobj_prop->PropertyClass; + } + else if (UStructProperty* ustruct_prop = Cast(u_property)) + { + ret_prop_ustruct = ustruct_prop->Struct; + } + else + { + ret_prop_ustruct = u_property->GetClass(); + } + + Py_RETURN_UOBJECT(ret_prop_ustruct); +} + +PyObject *py_ue_output_referencers(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + FStringOutputDevice outputDevice; + + // Get referencer information + FReferencerInformationList outputList; + self->ue_object->OutputReferencers((FOutputDevice &)outputDevice); + + // Get actual list of objects referencing this actor + TArray outInternalRefs, outExternalRefs; + self->ue_object->RetrieveReferencers(&outInternalRefs, &outExternalRefs); + + PyObject *retList = PyList_New(0); + + // Pack objects into list + for (FReferencerInformation & info : outExternalRefs) + { + ue_PyUObject *py_obj = ue_get_python_uobject(info.Referencer); + if (!py_obj) + continue; + Py_INCREF(py_obj); + PyList_Append(retList, (PyObject *)py_obj); + } + // Pack into tuple of type(String, List[UObject]) and return + PyObject * retTuple = PyTuple_New(2); + PyTuple_SetItem(retTuple, 0, PyUnicode_FromString(TCHAR_TO_UTF8(*outputDevice))); + PyTuple_SetItem(retTuple, 1, retList); + return retTuple; } PyObject *py_ue_get_super_class(ue_PyUObject * self, PyObject * args) @@ -261,22 +357,22 @@ PyObject *py_ue_is_child_of(ue_PyUObject * self, PyObject * args) { return NULL; } + + if (!self->ue_object->IsA()) + return PyErr_Format(PyExc_Exception, "object is not a UStruct"); - if (!self->ue_object->IsA()) - return PyErr_Format(PyExc_Exception, "object is not a UClass"); - - if (!ue_is_pyuobject(obj)) + ue_PyUObject *py_obj = ue_is_pyuobject(obj); + if (!py_obj) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } - ue_PyUObject *py_obj = (ue_PyUObject *)obj; - if (!py_obj->ue_object->IsA()) - return PyErr_Format(PyExc_Exception, "argument is not a UClass"); + if (!py_obj->ue_object->IsA()) + return PyErr_Format(PyExc_Exception, "argument is not a UStruct"); - UClass *parent = (UClass *)py_obj->ue_object; - UClass *child = (UClass *)self->ue_object; + UStruct *parent = (UStruct *)py_obj->ue_object; + UStruct *child = (UStruct *)self->ue_object; if (child->IsChildOf(parent)) { @@ -409,6 +505,33 @@ PyObject *py_ue_set_metadata(ue_PyUObject * self, PyObject * args) Py_RETURN_NONE; } +PyObject *py_ue_set_metadata_on_property(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + char *metadata_key; + char *metadata_value; + char *property_name; + + if (!PyArg_ParseTuple(args, "sss:set_metadata_on_property", &property_name, &metadata_key, &metadata_value)) + { + return NULL; + } + + if (self->ue_object->IsA()) + { + UClass *u_class = (UClass *)self->ue_object; + UProperty * u_property = u_class->FindPropertyByName(FName(UTF8_TO_TCHAR(property_name))); + u_property->SetMetaData(FName(UTF8_TO_TCHAR(metadata_key)), UTF8_TO_TCHAR(metadata_value)); + } + else + { + return PyErr_Format(PyExc_TypeError, "the object does not support MetaData"); + } + + Py_RETURN_NONE; +} + PyObject *py_ue_get_metadata(ue_PyUObject * self, PyObject * args) { @@ -645,12 +768,693 @@ PyObject *py_ue_get_path_name(ue_PyUObject *self, PyObject * args) return PyUnicode_FromString(TCHAR_TO_UTF8(*(self->ue_object->GetPathName()))); } -PyObject *py_ue_save_config(ue_PyUObject *self, PyObject * args) +PyObject *py_ue_save_config(ue_PyUObject *self, PyObject * args, PyObject *kwargs) +{ + ue_py_check(self); + + uint64 flags = CPF_Config; + char *file_name = nullptr; + + char *kwlist[] = { + (char *)"flags", + (char *)"filename", + nullptr + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Ks:save_config", (char**)kwlist, &flags, &file_name)) + { + PyErr_Format(PyExc_Exception, "\nPossible causes of error:\n1. Arguments provided in wrong order\n2. Arguments provided with wrong keywords"); + Py_RETURN_NONE; + } + + self->ue_object->SaveConfig(flags, UTF8_TO_TCHAR(file_name)); + + Py_RETURN_NONE; +} + +//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition; this looks bad- lots of copy/paste code from engine and overcomplicated reimplementation +PyObject *py_ue_save_config_to_section(ue_PyUObject *self, PyObject * args, PyObject *kwargs) { + ue_py_check(self); + + uint64 flags = CPF_Config; + char *file_name = nullptr; + char *section_name = nullptr; + + char *kwlist[] = { + (char *)"section_name", + (char *)"flags", + (char *)"filename", + nullptr + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Ks:save_config_to_section", (char**)kwlist, §ion_name, &flags, &file_name)) + { + PyErr_Format(PyExc_Exception, "\nPossible causes of error:\n1. Arguments provided in wrong order\n2. Arguments provided with wrong keywords"); + Py_RETURN_NONE; + } + + + if (!self->ue_object->GetClass()->HasAnyClassFlags(CLASS_Config)) + { + Py_RETURN_NONE; + } + + TCHAR * InFileName = UTF8_TO_TCHAR(file_name); + uint32 PropagationFlags = UE4::LCPF_None; + + const FString Filename + // if a filename was specified, always load from that file + = InFileName + ? InFileName + : GetConfigFilename(self->ue_object); + + // Determine whether the file we are writing is a default file config. + const bool bIsADefaultIniWrite = Filename == self->ue_object->GetDefaultConfigFilename() || Filename == self->ue_object->GetGlobalUserConfigFilename(); + + const bool bPerObject = UsesPerObjectConfig(self->ue_object); + FString Section = UTF8_TO_TCHAR(section_name); + + UObject* CDO = self->ue_object->GetClass()->GetDefaultObject(); + + // only copy the values to the CDO if this is GConfig and we're not saving the CDO + const bool bCopyValues = (self->ue_object != CDO); + + for (UProperty* Property = self->ue_object->GetClass()->PropertyLink; Property; Property = Property->PropertyLinkNext) + { + if (!Property->HasAnyPropertyFlags(CPF_Config)) + { + continue; + } + + if ((Property->PropertyFlags & flags) == flags) + { + UClass* BaseClass = self->ue_object->GetClass(); + + if (Property->PropertyFlags & CPF_GlobalConfig) + { + // call LoadConfig() on child classes if any of the properties were global config + PropagationFlags |= UE4::LCPF_PropagateToChildDefaultObjects; + BaseClass = Property->GetOwnerClass(); + if (BaseClass != self->ue_object->GetClass()) + { + // call LoadConfig() on parent classes only if the global config property was declared in a parent class + PropagationFlags |= UE4::LCPF_ReadParentSections; + } + } + + FString Key = Property->GetName(); + int32 PortFlags = 0; + +#if WITH_EDITOR + static FName ConsoleVariableFName(TEXT("ConsoleVariable")); + const FString& CVarName = Property->GetMetaData(ConsoleVariableFName); + if (!CVarName.IsEmpty()) + { + Key = CVarName; + PortFlags |= PPF_ConsoleVariable; + } +#endif // #if WITH_EDITOR + + // globalconfig properties should always use the owning class's config file + // specifying a value for InFilename will override this behavior (as it does with normal properties) + const FString& PropFileName = ((Property->PropertyFlags & CPF_GlobalConfig) && InFileName == NULL) ? Property->GetOwnerClass()->GetConfigName() : Filename; + + // Properties that are the same as the parent class' defaults should not be saved to ini + // Before modifying any key in the section, first check to see if it is different from the parent. + const bool bIsPropertyInherited = Property->GetOwnerClass() != self->ue_object->GetClass(); + const bool bShouldCheckIfIdenticalBeforeAdding = !self->ue_object->GetClass()->HasAnyClassFlags(CLASS_ConfigDoNotCheckDefaults) && !bPerObject && bIsPropertyInherited; + UObject* SuperClassDefaultObject = self->ue_object->GetClass()->GetSuperClass()->GetDefaultObject(); + + UArrayProperty* Array = dynamic_cast(Property); + if (Array) + { + if (!bShouldCheckIfIdenticalBeforeAdding || !Property->Identical_InContainer(self->ue_object, SuperClassDefaultObject)) + { + FConfigSection* Sec = GConfig->GetSectionPrivate(*Section, 1, 0, *PropFileName); + check(Sec); + Sec->Remove(*Key); + + // Default ini's require the array syntax to be applied to the property name + FString CompleteKey = FString::Printf(TEXT("%s%s"), bIsADefaultIniWrite ? TEXT("+") : TEXT(""), *Key); + + FScriptArrayHelper_InContainer ArrayHelper(Array, self->ue_object); + for (int32 i = 0; i < ArrayHelper.Num(); i++) + { + FString Buffer; + Array->Inner->ExportTextItem(Buffer, ArrayHelper.GetRawPtr(i), ArrayHelper.GetRawPtr(i), self->ue_object, PortFlags); + Sec->Add(*CompleteKey, *Buffer); + } + } + else if (Property->Identical_InContainer(self->ue_object, SuperClassDefaultObject)) + { + // If we are not writing it to config above, we should make sure that this property isn't stagnant in the cache. + FConfigSection* Sec = GConfig->GetSectionPrivate(*Section, 1, 0, *PropFileName); + if (Sec) + { + Sec->Remove(*Key); + } + + } + } + else + { + TCHAR TempKey[MAX_SPRINTF] = TEXT(""); + for (int32 Index = 0; Index < Property->ArrayDim; Index++) + { + if (Property->ArrayDim != 1) + { + FCString::Sprintf(TempKey, TEXT("%s[%i]"), *Property->GetName(), Index); + Key = TempKey; + } + + if (!bShouldCheckIfIdenticalBeforeAdding || !Property->Identical_InContainer(self->ue_object, SuperClassDefaultObject, Index)) + { + FString Value; + Property->ExportText_InContainer(Index, Value, self->ue_object, self->ue_object, self->ue_object, PortFlags); + GConfig->SetString(*Section, *Key, *Value, *PropFileName); + } + else if (Property->Identical_InContainer(self->ue_object, SuperClassDefaultObject, Index)) + { + // If we are not writing it to config above, we should make sure that this property isn't stagnant in the cache. + FConfigSection* Sec = GConfig->GetSectionPrivate(*Section, 1, 0, *PropFileName); + if (Sec) + { + Sec->Remove(*Key); + } + } + } + } + + if (bCopyValues) + { + void* ThisPropertyAddress = Property->ContainerPtrToValuePtr(self->ue_object); + void* CDOPropertyAddr = Property->ContainerPtrToValuePtr(CDO); + + Property->CopyCompleteValue(CDOPropertyAddr, ThisPropertyAddress); + } + } + } + + GConfig->Flush(0); + Py_RETURN_NONE; +} + +//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition; this looks bad- lots of copy/paste code from engine and overcomplicated reimplementation +PyObject *py_ue_load_config(ue_PyUObject *self, PyObject * args, PyObject *kwargs) +{ ue_py_check(self); - self->ue_object->SaveConfig(); + PyObject * py_uclass = nullptr; + PyObject * py_uproperty = nullptr; + char *file_name = nullptr; + int propagation_flags = UE4::ELoadConfigPropagationFlags::LCPF_None; + + char *kwlist[] = { + (char *)"config_class", + (char *)"filename", + (char *)"propagation_flags", + (char *)"property_to_load", + nullptr + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OsiO:load_config", (char**)kwlist, &py_uclass, &file_name, &propagation_flags, &py_uproperty)) + { + PyErr_Format(PyExc_Exception, "\nPossible causes of error:\n1. Arguments provided in wrong order\n2. Arguments provided with wrong keywords"); + Py_RETURN_NONE; + } + + // Validate UClass argument + ue_PyUObject *py_uclass_obj = nullptr; + UClass * config_uclass = nullptr; + if (py_uclass != nullptr) + { + if (!ue_is_pyuobject(py_uclass)) + { + return PyErr_Format(PyExc_Exception, "ConfigClass argument is not a UObject"); + } + py_uclass_obj = (ue_PyUObject *)py_uclass; + + if (py_uclass_obj->ue_object->IsA()) + { + config_uclass = (UClass *)py_uclass_obj->ue_object; + } + else + { + PyErr_Format(PyExc_Exception, "ConfigClass Argument is not a UClass"); + Py_RETURN_NONE; + } + } + + // Validate UProperty argument + ue_PyUObject *py_uproperty_obj = nullptr; + UProperty * uproperty_to_load = nullptr; + if (py_uproperty != nullptr) + { + if (!ue_is_pyuobject(py_uproperty)) + { + return PyErr_Format(PyExc_Exception, "PropertyToLoad argument is not a UObject"); + } + py_uproperty_obj = (ue_PyUObject *)py_uproperty; + + if (py_uproperty_obj->ue_object->IsA()) + { + uproperty_to_load = (UProperty *)py_uproperty_obj->ue_object; + } + else + { + PyErr_Format(PyExc_Exception, "PropertyToLoad argument is not a UProperty"); + Py_RETURN_NONE; + } + } + + self->ue_object->LoadConfig(config_uclass, UTF8_TO_TCHAR(file_name), propagation_flags, uproperty_to_load); + + Py_RETURN_NONE; +} + +/** Checks if a section specified as a long package name can be found as short name in ini. - Used below */ +#if !UE_BUILD_SHIPPING +namespace { + void CheckMissingSection(const FString& SectionName, const FString& IniFilename) + { + static TSet MissingSections; + FConfigSection* Sec = GConfig->GetSectionPrivate(*SectionName, false, true, *IniFilename); + if (!Sec && MissingSections.Contains(SectionName) == false) + { + FString ShortSectionName = FPackageName::GetShortName(SectionName); + if (ShortSectionName != SectionName) + { + Sec = GConfig->GetSectionPrivate(*ShortSectionName, false, true, *IniFilename); + if (Sec != NULL) + { + UE_LOG(LogConfig, Fatal, TEXT("Short class section names (%s) are not supported, please use long name: %s"), *ShortSectionName, *SectionName); + } + } + MissingSections.Add(SectionName); + } + } +} +#endif + +//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition; this looks bad- lots of copy/paste code from engine and overcomplicated reimplementation +PyObject *py_ue_load_config_from_section(ue_PyUObject *self, PyObject * args, PyObject *kwargs) +{ + ue_py_check(self); + + char *section_name = nullptr; + PyObject * py_uclass = nullptr; + PyObject * py_uproperty = nullptr; + char *file_name = nullptr; + int propagation_flags = UE4::ELoadConfigPropagationFlags::LCPF_None; + + char *kwlist[] = { + (char *)"section_name", + (char *)"config_class", + (char *)"filename", + (char *)"propagation_flags", + (char *)"property_to_load", + nullptr + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OsiO:load_config_from_section", (char**)kwlist, §ion_name, &py_uclass, &file_name, &propagation_flags, &py_uproperty)) + { + PyErr_Format(PyExc_Exception, "\nPossible causes of error:\n1. Arguments provided in wrong order\n2. Arguments provided with wrong keywords"); + Py_RETURN_NONE; + } + + // Validate UClass argument + ue_PyUObject *py_uclass_obj = nullptr; + UClass * config_uclass = nullptr; + if (py_uclass != nullptr) + { + if (!ue_is_pyuobject(py_uclass)) + { + return PyErr_Format(PyExc_Exception, "ConfigClass argument is not a UObject"); + } + py_uclass_obj = (ue_PyUObject *)py_uclass; + + if (py_uclass_obj->ue_object->IsA()) + { + config_uclass = (UClass *)py_uclass_obj->ue_object; + } + else + { + PyErr_Format(PyExc_Exception, "ConfigClass Argument is not a UClass"); + Py_RETURN_NONE; + } + } + + // Validate UProperty argument + ue_PyUObject *py_uproperty_obj = nullptr; + UProperty * uproperty_to_load = nullptr; + if (py_uproperty != nullptr) + { + if (!ue_is_pyuobject(py_uproperty)) + { + return PyErr_Format(PyExc_Exception, "PropertyToLoad argument is not a UObject"); + } + py_uproperty_obj = (ue_PyUObject *)py_uproperty; + + if (py_uproperty_obj->ue_object->IsA()) + { + uproperty_to_load = (UProperty *)py_uproperty_obj->ue_object; + } + else + { + PyErr_Format(PyExc_Exception, "PropertyToLoad argument is not a UProperty"); + Py_RETURN_NONE; + } + } + + // OriginalClass is the class that LoadConfig() was originally called on + static UClass* OriginalClass = NULL; + + if (!config_uclass) + { + // if no class was specified in the call, this is the OriginalClass + config_uclass = self->ue_object->GetClass(); + OriginalClass = config_uclass; + } + + if (!config_uclass->HasAnyClassFlags(CLASS_Config)) + { + Py_RETURN_NONE; + } + + UClass* ParentClass = config_uclass->GetSuperClass(); + if (ParentClass != NULL) + { + if (ParentClass->HasAnyClassFlags(CLASS_Config)) + { + if ((propagation_flags&UE4::LCPF_ReadParentSections) != 0) + { + // call LoadConfig on the parent class + self->ue_object->LoadConfig(ParentClass, NULL, propagation_flags, uproperty_to_load); + + // if we are also notifying child classes or instances, stop here as this object's properties will be imported as a result of notifying the others + if ((propagation_flags & (UE4::LCPF_PropagateToChildDefaultObjects | UE4::LCPF_PropagateToInstances)) != 0) + { + Py_RETURN_NONE; + } + } + else if ((propagation_flags&UE4::LCPF_PropagateToChildDefaultObjects) != 0) + { + // not propagating the call upwards, but we are propagating the call to all child classes + for (TObjectIterator It; It; ++It) + { + if (It->IsChildOf(config_uclass)) + { + // mask out the PropgateToParent and PropagateToChildren values + It->GetDefaultObject()->LoadConfig(*It, NULL, (propagation_flags&(UE4::LCPF_PersistentFlags | UE4::LCPF_PropagateToInstances)), uproperty_to_load); + } + } + + // LoadConfig() was called on this object during iteration, so stop here + Py_RETURN_NONE; + } + else if ((propagation_flags&UE4::LCPF_PropagateToInstances) != 0) + { + // call LoadConfig() on all instances of this class (except the CDO) + // Do not propagate this call to parents, and do not propagate to children or instances (would be redundant) + for (TObjectIterator It; It; ++It) + { + if (It->IsA(config_uclass)) + { + if (!GIsEditor) + { + // make sure to pass in the class so that OriginalClass isn't reset + It->LoadConfig(It->GetClass(), NULL, (propagation_flags&UE4::LCPF_PersistentFlags), uproperty_to_load); + } +#if WITH_EDITOR + else + { + It->PreEditChange(NULL); + + // make sure to pass in the class so that OriginalClass isn't reset + It->LoadConfig(It->GetClass(), NULL, (propagation_flags&UE4::LCPF_PersistentFlags), uproperty_to_load); + + It->PostEditChange(); + } +#endif // WITH_EDITOR + } + } + } + } + else if ((propagation_flags&UE4::LCPF_PropagateToChildDefaultObjects) != 0) + { + // we're at the base-most config class + for (TObjectIterator It; It; ++It) + { + if (It->IsChildOf(config_uclass)) + { + if (!GIsEditor) + { + // make sure to pass in the class so that OriginalClass isn't reset + It->GetDefaultObject()->LoadConfig(*It, NULL, (propagation_flags&(UE4::LCPF_PersistentFlags | UE4::LCPF_PropagateToInstances)), uproperty_to_load); + } +#if WITH_EDITOR + else + { + It->PreEditChange(NULL); + + // make sure to pass in the class so that OriginalClass isn't reset + It->GetDefaultObject()->LoadConfig(*It, NULL, (propagation_flags&(UE4::LCPF_PersistentFlags | UE4::LCPF_PropagateToInstances)), uproperty_to_load); + + It->PostEditChange(); + } +#endif // WITH_EDITOR + } + } + + Py_RETURN_NONE; + } + else if ((propagation_flags&UE4::LCPF_PropagateToInstances) != 0) + { + for (TObjectIterator It; It; ++It) + { + if (It->GetClass() == config_uclass) + { + if (!GIsEditor) + { + // make sure to pass in the class so that OriginalClass isn't reset + It->LoadConfig(It->GetClass(), NULL, (propagation_flags&UE4::LCPF_PersistentFlags), uproperty_to_load); + } +#if WITH_EDITOR + else + { + It->PreEditChange(NULL); + + // make sure to pass in the class so that OriginalClass isn't reset + It->LoadConfig(It->GetClass(), NULL, (propagation_flags&UE4::LCPF_PersistentFlags), uproperty_to_load); + It->PostEditChange(); + } +#endif // WITH_EDITOR + } + } + } + } + + TCHAR * InFilename = UTF8_TO_TCHAR(file_name); + const FString Filename + // if a filename was specified, always load from that file + = InFilename + ? InFilename + : GetConfigFilename(self->ue_object); + + const bool bPerObject = UsesPerObjectConfig(self->ue_object); + + // does the class want to override the platform hierarchy (ignored if we passd in a specific ini file), + // and if the name isn't the current running platform (no need to load extra files if already in GConfig) + bool bUseConfigOverride = InFilename == nullptr && self->ue_object->GetConfigOverridePlatform() != nullptr && + FCString::Stricmp(self->ue_object->GetConfigOverridePlatform(), ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName())) != 0; + FConfigFile OverrideConfig; + if (bUseConfigOverride) + { + // load into a local ini file + FConfigCacheIni::LoadLocalIniFile(OverrideConfig, *self->ue_object->GetClass()->ClassConfigName.ToString(), true, self->ue_object->GetConfigOverridePlatform()); + } + + + FString ClassSection; + ClassSection = UTF8_TO_TCHAR(section_name); + + // If any of my properties are class variables, then LoadConfig() would also be called for each one of those classes. + // Since OrigClass is a static variable, if the value of a class variable is a class different from the current class, + // we'll lose our nice reference to the original class - and cause any variables which were declared after this class variable to fail + // the 'if (OriginalClass != Class)' check....better store it in a temporary place while we do the actual loading of our properties + UClass* MyOrigClass = OriginalClass; + + if (uproperty_to_load == NULL) + { + UE_LOG(LogConfig, Verbose, TEXT("(%s) '%s' loading configuration from %s"), *config_uclass->GetName(), *self->ue_object->GetName(), *Filename); + } + else + { + UE_LOG(LogConfig, Verbose, TEXT("(%s) '%s' loading configuration for property %s from %s"), *config_uclass->GetName(), *self->ue_object->GetName(), *uproperty_to_load->GetName(), *Filename); + } + + for (UProperty* Property = config_uclass->PropertyLink; Property; Property = Property->PropertyLinkNext) + { + if (!Property->HasAnyPropertyFlags(CPF_Config)) + { + continue; + } + + // if we're only supposed to load the value for a specific property, skip all others + if (uproperty_to_load != NULL && uproperty_to_load != Property) + { + continue; + } + + // Don't load config properties that are marked editoronly if not in the editor + if ((Property->PropertyFlags & CPF_EditorOnly) && !GIsEditor) + { + continue; + } + + const bool bGlobalConfig = (Property->PropertyFlags&CPF_GlobalConfig) != 0; + UClass* OwnerClass = Property->GetOwnerClass(); + + UClass* BaseClass = bGlobalConfig ? OwnerClass : config_uclass; + + // globalconfig properties should always use the owning class's config file + // specifying a value for InFilename will override this behavior (as it does with normal properties) + const FString& PropFileName = (bGlobalConfig && InFilename == NULL) ? OwnerClass->GetConfigName() : Filename; + + FString Key = Property->GetName(); + int32 PortFlags = 0; + +#if WITH_EDITOR + static FName ConsoleVariableFName(TEXT("ConsoleVariable")); + const FString& CVarName = Property->GetMetaData(ConsoleVariableFName); + if (!CVarName.IsEmpty()) + { + Key = CVarName; + PortFlags |= PPF_ConsoleVariable; + } +#endif // #if WITH_EDITOR + + UE_LOG(LogConfig, Verbose, TEXT(" Loading value for %s from [%s]"), *Key, *ClassSection); + UArrayProperty* Array = dynamic_cast(Property); + if (Array == NULL) + { + for (int32 i = 0; i < Property->ArrayDim; i++) + { + if (Property->ArrayDim != 1) + { + Key = FString::Printf(TEXT("%s[%i]"), *Property->GetName(), i); + } + + FString Value; + bool bFoundValue; + if (bUseConfigOverride) + { + bFoundValue = OverrideConfig.GetString(*ClassSection, *Key, Value); + } + else + { + bFoundValue = GConfig->GetString(*ClassSection, *Key, Value, *PropFileName); + } + + if (bFoundValue) + { + if (Property->ImportText(*Value, Property->ContainerPtrToValuePtr(self->ue_object, i), PortFlags, self->ue_object) == NULL) + { + // this should be an error as the properties from the .ini / .int file are not correctly being read in and probably are affecting things in subtle ways + UE_LOG(LogConfig, Error, TEXT("LoadConfig (%s): import failed for %s in: %s"), *self->ue_object->GetPathName(), *Property->GetName(), *Value); + } + } + +#if !UE_BUILD_SHIPPING + if (!bFoundValue && !FPlatformProperties::RequiresCookedData()) + { + CheckMissingSection(ClassSection, PropFileName); + } +#endif + } + } + else + { + FConfigSection* Sec; + if (bUseConfigOverride) + { + Sec = OverrideConfig.Find(*ClassSection); + } + else + { + Sec = GConfig->GetSectionPrivate(*ClassSection, false, true, *PropFileName); + } + + FConfigSection* AltSec = NULL; + //@Package name transition + if (Sec) + { + TArray List; + const FName KeyName(*Key, FNAME_Find); + Sec->MultiFind(KeyName, List); + + // If we didn't find anything in the first section, try the alternate + if ((List.Num() == 0) && AltSec) + { + AltSec->MultiFind(KeyName, List); + } + + FScriptArrayHelper_InContainer ArrayHelper(Array, self->ue_object); + const int32 Size = Array->Inner->ElementSize; + // Only override default properties if there is something to override them with. + if (List.Num() > 0) + { + ArrayHelper.EmptyAndAddValues(List.Num()); + for (int32 i = List.Num() - 1, c = 0; i >= 0; i--, c++) + { + Array->Inner->ImportText(*List[i].GetValue(), ArrayHelper.GetRawPtr(c), PortFlags, self->ue_object); + } + } + else + { + int32 Index = 0; + const FConfigValue* ElementValue = nullptr; + do + { + // Add array index number to end of key + FString IndexedKey = FString::Printf(TEXT("%s[%i]"), *Key, Index); + + // Try to find value of key + const FName IndexedName(*IndexedKey, FNAME_Find); + if (IndexedName == NAME_None) + { + break; + } + ElementValue = Sec->Find(IndexedName); + + // If found, import the element + if (ElementValue != nullptr) + { + // expand the array if necessary so that Index is a valid element + ArrayHelper.ExpandForIndex(Index); + Array->Inner->ImportText(*ElementValue->GetValue(), ArrayHelper.GetRawPtr(Index), PortFlags, self->ue_object); + } + + Index++; + } while (ElementValue || Index < ArrayHelper.Num()); + } + } +#if !UE_BUILD_SHIPPING + else if (!FPlatformProperties::RequiresCookedData()) + { + CheckMissingSection(ClassSection, PropFileName); + } +#endif + } + } + + // if we are reloading config data after the initial class load, fire the callback now + if ((propagation_flags&UE4::LCPF_ReloadingConfigData) != 0) + { + self->ue_object->PostReloadConfig(uproperty_to_load); + } Py_RETURN_NONE; } @@ -852,6 +1656,14 @@ PyObject *py_ue_properties(ue_PyUObject *self, PyObject * args) ue_py_check(self); + EFieldIteratorFlags::SuperClassFlags inSuperClassFlags = EFieldIteratorFlags::IncludeSuper; + EFieldIteratorFlags::DeprecatedPropertyFlags inDeprecatedFieldFlags = EFieldIteratorFlags::IncludeDeprecated; + EFieldIteratorFlags::InterfaceClassFlags inInterfaceFieldFlags = EFieldIteratorFlags::ExcludeInterfaces; + if (!PyArg_ParseTuple(args, "|KKK:properties", &inSuperClassFlags, &inDeprecatedFieldFlags, &inInterfaceFieldFlags)) + { + return NULL; + } + UStruct *u_struct = nullptr; if (self->ue_object->IsA()) @@ -864,8 +1676,7 @@ PyObject *py_ue_properties(ue_PyUObject *self, PyObject * args) } PyObject *ret = PyList_New(0); - - for (TFieldIterator PropIt(u_struct); PropIt; ++PropIt) + for (TFieldIterator PropIt(u_struct, inSuperClassFlags, inDeprecatedFieldFlags, inInterfaceFieldFlags); PropIt; ++PropIt) { UProperty* property = *PropIt; PyObject *property_name = PyUnicode_FromString(TCHAR_TO_UTF8(*property->GetName())); @@ -943,10 +1754,10 @@ PyObject *py_ue_broadcast(ue_PyUObject *self, PyObject *args) if (auto casted_prop = Cast(u_property)) { - FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(self->ue_object); + FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(self->ue_object); uint8 *parms = (uint8 *)FMemory_Alloca(casted_prop->SignatureFunction->PropertiesSize); FMemory::Memzero(parms, casted_prop->SignatureFunction->PropertiesSize); - multiscript_delegate.ProcessMulticastDelegate(parms); + multiscript_delegate->ProcessMulticastDelegate(parms); } else { @@ -1178,6 +1989,19 @@ PyObject *py_ue_is_rooted(ue_PyUObject *self, PyObject * args) return Py_False; } +PyObject *py_ue_is_selected(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + + if (self->ue_object->IsSelected()) + { + Py_INCREF(Py_True); + return Py_True; + } + + Py_INCREF(Py_False); + return Py_False; +} PyObject *py_ue_add_to_root(ue_PyUObject *self, PyObject * args) { @@ -1212,6 +2036,32 @@ PyObject *py_ue_remove_from_root(ue_PyUObject *self, PyObject * args) return Py_None; } +PyObject *py_ue_clear_event(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + char *event_name; + if (!PyArg_ParseTuple(args, "s:clear_events", &event_name)) + { + return NULL; + } + + UProperty *u_property = self->ue_object->GetClass()->FindPropertyByName(FName(*FString(event_name))); + if (!u_property) + { + return PyErr_Format(PyExc_Exception, "unable to find event property %s", TCHAR_TO_UTF8(*FString(event_name))); + } + + if (UMulticastDelegateProperty* casted_prop = Cast(u_property)) + { + FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(self->ue_object); + multiscript_delegate->Clear(); + Py_RETURN_NONE; + } + + return PyErr_Format(PyExc_Exception, "property %s is not an event", TCHAR_TO_UTF8(*FString(event_name))); +} + PyObject *py_ue_bind_event(ue_PyUObject * self, PyObject * args) { @@ -1325,6 +2175,8 @@ PyObject *py_ue_add_property(ue_PyUObject * self, PyObject * args) UClass *u_prop_class = nullptr; UScriptStruct *u_script_struct = nullptr; + UEnum * u_enum_class = nullptr; + UClass *u_prop_class2 = nullptr; UScriptStruct *u_script_struct2 = nullptr; bool is_array = false; @@ -1345,9 +2197,13 @@ PyObject *py_ue_add_property(ue_PyUObject * self, PyObject * args) { u_script_struct = (UScriptStruct *)py_prop_class->ue_object; } + else if (py_prop_class->ue_object->IsA()) + { + u_enum_class = (UEnum *)py_prop_class->ue_object; + } else { - return PyErr_Format(PyExc_Exception, "property class arg is not a UClass or a UScriptStruct"); + return PyErr_Format(PyExc_Exception, "property class arg is not a UClass or a UScriptStruct or a UEnum"); } } @@ -1377,16 +2233,25 @@ PyObject *py_ue_add_property(ue_PyUObject * self, PyObject * args) if (ue_is_pyuobject(obj)) { ue_PyUObject *py_obj = (ue_PyUObject *)obj; - if (!py_obj->ue_object->IsA()) + + if (py_obj->ue_object->IsA()) + { + scope = self->ue_object; + u_class = UEnumProperty::StaticClass(); + } + else { - return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); + if (!py_obj->ue_object->IsA()) + { + return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); + } + u_class = (UClass *)py_obj->ue_object; + if (!u_class->IsChildOf()) + return PyErr_Format(PyExc_Exception, "uobject is not a UProperty"); + if (u_class == UArrayProperty::StaticClass()) + return PyErr_Format(PyExc_Exception, "please use a single-item list of property for arrays"); + scope = self->ue_object; } - u_class = (UClass *)py_obj->ue_object; - if (!u_class->IsChildOf()) - return PyErr_Format(PyExc_Exception, "uobject is not a UProperty"); - if (u_class == UArrayProperty::StaticClass()) - return PyErr_Format(PyExc_Exception, "please use a single-item list of property for arrays"); - scope = self->ue_object; } else if (PyList_Check(obj)) { @@ -1612,6 +2477,22 @@ PyObject *py_ue_add_property(ue_PyUObject * self, PyObject * args) } } + else if (u_class == UEnumProperty::StaticClass()) + { + // ensure it is not an arry as we have already managed it ! + if (!is_array && !is_map) + { + UEnumProperty *enum_prop = (UEnumProperty *)u_property; + if(enum_prop) + { + //UEnum* EnumType = CastChecked(u_enum_class); + enum_prop->SetEnum(u_enum_class); + enum_prop->AddCppProperty(NewObject(enum_prop, TEXT("UnderlyingType"))); + + } + } + } + u_property->SetPropertyFlags(flags); u_property->ArrayDim = 1; @@ -1686,6 +2567,33 @@ PyObject *py_ue_get_cdo(ue_PyUObject * self, PyObject * args) Py_RETURN_UOBJECT(u_class->GetDefaultObject()); } +PyObject *py_ue_get_archetype(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + Py_RETURN_UOBJECT(self->ue_object->GetArchetype()); +} + +PyObject *py_ue_get_archetype_instances(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + TArray ObjectArchetypeInstances; + self->ue_object->GetArchetypeInstances(ObjectArchetypeInstances); + + PyObject *retArchInstances = PyList_New(0); + for (UObject* ObjectArchetype : ObjectArchetypeInstances) + { + ue_PyUObject *archInstance = ue_get_python_uobject(ObjectArchetype); + if (archInstance) + { + PyList_Append(retArchInstances, (PyObject *)archInstance); + } + } + + return retArchInstances; +} + #if WITH_EDITOR PyObject *py_ue_save_package(ue_PyUObject * self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 7f3c95fb7..3931b2d10 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -28,13 +28,20 @@ PyObject *py_ue_get_uproperty(ue_PyUObject *, PyObject *); PyObject *py_ue_get_property_class(ue_PyUObject *, PyObject *); PyObject *py_ue_has_property(ue_PyUObject *, PyObject *); PyObject *py_ue_is_rooted(ue_PyUObject *, PyObject *); +PyObject *py_ue_is_selected(ue_PyUObject *, PyObject *); PyObject *py_ue_add_to_root(ue_PyUObject *, PyObject *); PyObject *py_ue_remove_from_root(ue_PyUObject *, PyObject *); PyObject *py_ue_auto_root(ue_PyUObject *, PyObject *); +PyObject *py_ue_output_referencers(ue_PyUObject *, PyObject *); -PyObject *py_ue_save_config(ue_PyUObject *, PyObject *); +PyObject *py_ue_save_config(ue_PyUObject *, PyObject *, PyObject *); +PyObject *py_ue_save_config_to_section(ue_PyUObject *, PyObject *, PyObject *); +PyObject *py_ue_load_config(ue_PyUObject *, PyObject *, PyObject *); +PyObject *py_ue_load_config_from_section(ue_PyUObject *, PyObject *, PyObject *); PyObject *py_ue_get_cdo(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_archetype(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_archetype_instances(ue_PyUObject *, PyObject *); PyObject *py_ue_enum_values(ue_PyUObject *, PyObject *); PyObject *py_ue_enum_names(ue_PyUObject *, PyObject *); #if ENGINE_MINOR_VERSION >= 15 @@ -42,6 +49,7 @@ PyObject *py_ue_enum_user_defined_names(ue_PyUObject *, PyObject *); #endif +PyObject *py_ue_clear_event(ue_PyUObject *, PyObject *); PyObject *py_ue_bind_event(ue_PyUObject *, PyObject *); PyObject *py_ue_add_function(ue_PyUObject *, PyObject *); PyObject *py_ue_add_property(ue_PyUObject *, PyObject *); @@ -70,12 +78,16 @@ PyObject *py_ue_class_generated_by(ue_PyUObject *, PyObject *); PyObject *py_ue_class_get_flags(ue_PyUObject *, PyObject *); PyObject *py_ue_class_set_flags(ue_PyUObject *, PyObject *); +PyObject *py_ue_class_has_any_flags(ue_PyUObject * self, PyObject * args); PyObject *py_ue_get_obj_flags(ue_PyUObject *, PyObject *); PyObject *py_ue_set_obj_flags(ue_PyUObject *, PyObject *); PyObject *py_ue_delegate_bind_ufunction(ue_PyUObject *, PyObject *); #if WITH_EDITOR +#if ENGINE_MINOR_VERSION >= 19 +PyObject *py_ue_is_data_valid(ue_PyUObject *, PyObject *); +#endif PyObject *py_ue_class_get_config_name(ue_PyUObject *, PyObject *); PyObject *py_ue_class_set_config_name(ue_PyUObject *, PyObject *); PyObject *py_ue_save_package(ue_PyUObject *, PyObject *); @@ -85,6 +97,7 @@ PyObject *py_ue_asset_reimport(ue_PyUObject *, PyObject *); PyObject *py_ue_get_metadata(ue_PyUObject *, PyObject *); PyObject *py_ue_set_metadata(ue_PyUObject *, PyObject *); +PyObject *py_ue_set_metadata_on_property(ue_PyUObject *, PyObject *); PyObject *py_ue_has_metadata(ue_PyUObject *, PyObject *); PyObject *py_ue_import_custom_properties(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp index bd8036577..124507fe6 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp @@ -78,7 +78,7 @@ PyObject *py_ue_add_impulse(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_impulse = py_ue_is_fvector(py_obj_impulse); if (!py_impulse) return PyErr_Format(PyExc_Exception, "impulse must be a FVector"); - impulse = py_impulse->vec; + impulse = py_ue_fvector_get(py_impulse); } FName f_bone_name = NAME_None; @@ -128,7 +128,7 @@ PyObject *py_ue_add_angular_impulse(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_impulse = py_ue_is_fvector(py_obj_impulse); if (!py_impulse) return PyErr_Format(PyExc_Exception, "impulse must be a FVector"); - impulse = py_impulse->vec; + impulse = py_ue_fvector_get(py_impulse); } FName f_bone_name = NAME_None; @@ -181,7 +181,7 @@ PyObject *py_ue_add_force(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_force = py_ue_is_fvector(py_obj_force); if (!py_force) return PyErr_Format(PyExc_Exception, "force must be a FVector"); - force = py_force->vec; + force = py_ue_fvector_get(py_force); } FName f_bone_name = NAME_None; @@ -231,7 +231,7 @@ PyObject *py_ue_add_torque(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_torque = py_ue_is_fvector(py_obj_torque); if (!py_torque) return PyErr_Format(PyExc_Exception, "torque must be a FVector"); - torque = py_torque->vec; + torque = py_ue_fvector_get(py_torque); } FName f_bone_name = NAME_None; @@ -284,7 +284,7 @@ PyObject *py_ue_set_physics_linear_velocity(ue_PyUObject * self, PyObject * args ue_PyFVector *py_new_vel = py_ue_is_fvector(py_obj_new_vel); if (!py_new_vel) return PyErr_Format(PyExc_Exception, "torque must be a FVector"); - new_vel = py_new_vel->vec; + new_vel = py_ue_fvector_get(py_new_vel); } bool add_to_current = false; @@ -366,7 +366,7 @@ PyObject *py_ue_set_physics_angular_velocity(ue_PyUObject * self, PyObject * arg ue_PyFVector *py_new_ang_vel = py_ue_is_fvector(py_obj_new_ang_vel); if (!py_new_ang_vel) return PyErr_Format(PyExc_Exception, "torque must be a FVector"); - new_ang_vel = py_new_ang_vel->vec; + new_ang_vel = py_ue_fvector_get(py_new_ang_vel); } bool add_to_current = false; @@ -492,7 +492,7 @@ PyObject *py_ue_destructible_apply_damage(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_location = py_ue_is_fvector(py_obj_location); if (!py_location) return PyErr_Format(PyExc_Exception, "location must be a FVector"); - location = py_location->vec; + location = py_ue_fvector_get(py_location); } if (py_obj_impulse) @@ -500,7 +500,7 @@ PyObject *py_ue_destructible_apply_damage(ue_PyUObject * self, PyObject * args) ue_PyFVector *py_impulse = py_ue_is_fvector(py_obj_impulse); if (!py_impulse) return PyErr_Format(PyExc_Exception, "impulse must be a FVector"); - impulse = py_impulse->vec; + impulse = py_ue_fvector_get(py_impulse); } if (destructible) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 1fbdc70fb..1b6db9d8d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -20,6 +20,7 @@ #include "Sections/MovieSceneVectorSection.h" #include "Runtime/MovieScene/Public/MovieSceneFolder.h" #include "Runtime/MovieScene/Public/MovieSceneSpawnable.h" +#include "Private/SequencerSelection.h" #if ENGINE_MINOR_VERSION < 18 #include "Editor/UnrealEd/Private/FbxImporter.h" #else @@ -27,6 +28,12 @@ #endif #include "Editor/MovieSceneTools/Public/MatineeImportTools.h" #endif +#include "MovieSceneSection.h" +#include "Set.h" + +namespace { + const FName LevelSequenceEditorName("LevelSequenceEditor"); +} #include "GameFramework/Actor.h" #include "Runtime/LevelSequence/Public/LevelSequence.h" @@ -39,7 +46,12 @@ PyObject *py_ue_sequencer_changed(ue_PyUObject *self, PyObject * args) ue_py_check(self); PyObject *py_bool = nullptr; - if (!PyArg_ParseTuple(args, "|O:sequencer_changed", &py_bool)) +#if ENGINE_MINOR_VERSION < 13 + int changeNotificationType = (int)EMovieSceneDataChangeType::Unknown; +#else + int changeNotificationType = 0; +#endif + if (!PyArg_ParseTuple(args, "|Oi:sequencer_changed", &py_bool, &changeNotificationType)) { return NULL; } @@ -65,7 +77,7 @@ PyObject *py_ue_sequencer_changed(ue_PyUObject *self, PyObject * args) #if ENGINE_MINOR_VERSION < 13 sequencer->NotifyMovieSceneDataChanged(); #else - sequencer->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::Unknown); + sequencer->NotifyMovieSceneDataChanged((EMovieSceneDataChangeType)changeNotificationType); #endif } @@ -173,7 +185,7 @@ PyObject *py_ue_sequencer_find_possessable(ue_PyUObject *self, PyObject * args) return PyErr_Format(PyExc_Exception, "unable to find uobject with GUID \"%s\"", guid); Py_RETURN_UOBJECT(u_obj); -} + } PyObject *py_ue_sequencer_find_spawnable(ue_PyUObject *self, PyObject * args) { @@ -203,6 +215,40 @@ PyObject *py_ue_sequencer_find_spawnable(ue_PyUObject *self, PyObject * args) return ret; } +PyObject *py_ue_sequencer_get_all_spawnables(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + if (!PyArg_ParseTuple(args, ":get_all_spawnables")) + { + return NULL; + } + + if (!self->ue_object->IsA()) + return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence"); + + ULevelSequence *seq = (ULevelSequence *)self->ue_object; + + UMovieScene *scene = seq->GetMovieScene(); + + PyObject *py_spawnables = PyList_New(0); + + for (int i = 0; i < scene->GetSpawnableCount(); ++i) + { + FMovieSceneSpawnable & spawnable = scene->GetSpawnable(i); + PyObject *ret = py_ue_new_uscriptstruct(spawnable.StaticStruct(), (uint8 *)&spawnable); + if (!ret) + { + Py_DECREF(py_spawnables); + return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state"); + } + PyList_Append(py_spawnables, (PyObject *)ret); + } + + return py_spawnables; +} + #if WITH_EDITOR PyObject *py_ue_sequencer_add_possessable(ue_PyUObject *self, PyObject * args) { @@ -294,7 +340,7 @@ PyObject *py_ue_sequencer_add_actor(ue_PyUObject *self, PyObject * args) } return PyUnicode_FromString(TCHAR_TO_UTF8(*new_guid.ToString())); -} + } PyObject *py_ue_sequencer_add_actor_component(ue_PyUObject *self, PyObject * args) { @@ -752,7 +798,7 @@ PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args) if (ue_PyFTransform *py_transform = py_ue_is_ftransform(py_value)) { bool unwind = (py_unwind && PyObject_IsTrue(py_unwind)); - FTransform transform = py_transform->transform; + FTransform transform = py_ue_ftransform_get(py_transform); FTransformKey tx = FTransformKey(EKey3DTransformChannel::Translation, EAxis::X, transform.GetLocation().X, unwind); @@ -785,7 +831,7 @@ PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args) { if (ue_PyFVector *py_vector = py_ue_is_fvector(py_value)) { - FVector vec = py_vector->vec; + FVector vec = py_ue_fvector_get(py_vector); FVectorKey vx = FVectorKey(EKeyVectorChannel::X, vec.X); FVectorKey vy = FVectorKey(EKeyVectorChannel::Y, vec.Y); FVectorKey vz = FVectorKey(EKeyVectorChannel::Z, vec.Z); @@ -943,6 +989,44 @@ PyObject *py_ue_sequencer_remove_track(ue_PyUObject *self, PyObject * args) Py_RETURN_FALSE; } +#if ENGINE_MINOR_VERSION >= 18 +// Returns the selected sections +PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + + ULevelSequence *seq = ue_py_check_type(self); + if (!seq) + return PyErr_Format(PyExc_Exception, "uobject is not a LevelSequence"); + + IAssetEditorInstance *editor = FAssetEditorManager::Get().FindEditorForAsset(seq, true); + if (!editor || editor->GetEditorName() != LevelSequenceEditorName) + { + return PyErr_Format(PyExc_Exception, "unable to access level sequence editor"); + } + + FLevelSequenceEditorToolkit *toolkit = static_cast(editor); + ISequencer *sequencer = toolkit->GetSequencer().Get(); + FSequencerSelection seqSelection = sequencer->GetSelection(); + TArray sectionList; + sequencer->GetSelectedSections(sectionList); + + PyObject *py_sections = PyList_New(0); + for (UMovieSceneSection* section : sectionList) + { + ue_PyUObject *ret = ue_get_python_uobject(section); + if (!ret) + { + Py_DECREF(py_sections); + return PyErr_Format(PyExc_Exception, "PyUObject is in invalid state"); + } + PyList_Append(py_sections, (PyObject *)ret); + } + + return py_sections; +} +#endif + #endif PyObject *py_ue_sequencer_add_track(ue_PyUObject *self, PyObject * args) @@ -1028,6 +1112,36 @@ PyObject *py_ue_sequencer_get_display_name(ue_PyUObject *self, PyObject * args) return PyErr_Format(PyExc_Exception, "the uobject does not expose the GetDefaultDisplayName() method"); } +PyObject *py_ue_sequencer_get_track_display_name(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + if (self->ue_object->IsA()) + { + UMovieSceneNameableTrack *track = (UMovieSceneNameableTrack *)self->ue_object; + FText name = track->GetDisplayName(); + return PyUnicode_FromString(TCHAR_TO_UTF8(*name.ToString())); + } + + return PyErr_Format(PyExc_Exception, "the uobject does not expose the GetDisplayName() method"); +} + +PyObject *py_ue_sequencer_get_track_unique_name(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + if (self->ue_object->IsA()) + { + UMovieSceneNameableTrack *track = (UMovieSceneNameableTrack *)self->ue_object; + FName name = track->GetTrackName(); + return PyUnicode_FromString(TCHAR_TO_UTF8(*name.ToString())); + } + + return PyErr_Format(PyExc_Exception, "the uobject does not expose the GetDisplayName() method"); +} + PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * args) { ue_py_check(self); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index 54c748b94..f1e409b4d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -13,6 +13,8 @@ PyObject *py_ue_sequencer_folders(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_create_folder(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_set_display_name(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_get_display_name(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_get_track_display_name(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_get_track_unique_name(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_changed(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *, PyObject *); @@ -30,18 +32,25 @@ PyObject *py_ue_sequencer_remove_spawnable(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_remove_camera_cut_track(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_remove_master_track(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_remove_track(ue_PyUObject *, PyObject *); +#if ENGINE_MINOR_VERSION >= 18 +PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args); +#endif PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *, PyObject *); #endif PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *); + PyObject *py_ue_sequencer_possessables(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_possessables_guid(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_find_possessable(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_find_spawnable(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_get_all_spawnables(ue_PyUObject *self, PyObject * args); PyObject *py_ue_sequencer_add_master_track(ue_PyUObject *, PyObject *); + + PyObject *py_ue_sequencer_add_track(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp index c456e1c96..bc94b0870 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp @@ -188,7 +188,7 @@ PyObject *py_ue_skeleton_add_bone(ue_PyUObject *self, PyObject * args) TCHAR *bone_name = UTF8_TO_TCHAR(name); - modifier.Add(FMeshBoneInfo(FName(bone_name), FString(bone_name), parent_index), transform->transform); + modifier.Add(FMeshBoneInfo(FName(bone_name), FString(bone_name), parent_index), py_ue_ftransform_get(transform)); } @@ -711,6 +711,30 @@ PyObject *py_ue_skeletal_mesh_set_active_bone_indices(ue_PyUObject *self, PyObje } +PyObject *py_ue_skeletal_mesh_get_num_triangles(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + + int lod_index = 0; + if (!PyArg_ParseTuple(args, "|i:skeletal_mesh_get_num_triangles", &lod_index)) + return nullptr; + + USkeletalMesh *mesh = ue_py_check_type(self); + if (!mesh) + return PyErr_Format(PyExc_Exception, "uobject is not a USkeletalMesh"); + + #if ENGINE_MINOR_VERSION < 19 + FSkeletalMeshResource *resource = mesh->GetImportedResource(); + #else + FSkeletalMeshModel *resource = mesh->GetImportedModel(); + #endif + + if (lod_index < 0 || lod_index >= resource->LODModels.Num()) + return PyErr_Format(PyExc_Exception, "invalid LOD index, must be between 0 and %d", resource->LODModels.Num() - 1); + + return PyLong_FromLong(resource->LODModels[lod_index].NumVertices / 3); +} + PyObject *py_ue_skeletal_mesh_get_required_bones(ue_PyUObject *self, PyObject * args) { ue_py_check(self); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h index 3b32e9e03..5b139adca 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h @@ -14,8 +14,10 @@ PyObject *py_ue_skeleton_find_bone_index(ue_PyUObject *, PyObject *); PyObject *py_ue_skeleton_get_ref_bone_pose(ue_PyUObject *, PyObject *); PyObject *py_ue_skeleton_add_bone(ue_PyUObject *, PyObject *); +#if WITH_EDITOR PyObject *py_ue_skeletal_mesh_set_soft_vertices(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_soft_vertices(ue_PyUObject *, PyObject *); + PyObject *py_ue_skeletal_mesh_set_skeleton(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_lod(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_raw_indices(ue_PyUObject *, PyObject *); @@ -23,6 +25,7 @@ PyObject *py_ue_skeletal_mesh_get_raw_indices(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_bone_map(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_set_bone_map(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_set_active_bone_indices(ue_PyUObject *, PyObject *); +PyObject *py_ue_skeletal_mesh_get_num_triangles(ue_PyUObject *self, PyObject * args); PyObject *py_ue_skeletal_mesh_set_required_bones(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_active_bone_indices(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_get_required_bones(ue_PyUObject *, PyObject *); @@ -36,3 +39,4 @@ PyObject *py_ue_skeletal_mesh_register_morph_target(ue_PyUObject *, PyObject *); PyObject *py_ue_morph_target_populate_deltas(ue_PyUObject *, PyObject *); PyObject *py_ue_morph_target_get_deltas(ue_PyUObject *, PyObject *); PyObject *py_ue_skeletal_mesh_to_import_vertex_map(ue_PyUObject *, PyObject *); +#endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp index 405c9152e..14848e274 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp @@ -14,7 +14,7 @@ PyObject *py_ue_static_mesh_build(ue_PyUObject *self, PyObject * args) UStaticMesh *mesh = ue_py_check_type(self); if (!mesh) return PyErr_Format(PyExc_Exception, "uobject is not a UStaticMesh"); - + #if ENGINE_MINOR_VERSION > 13 mesh->ImportVersion = EImportStaticMeshVersion::LastVersion; #endif @@ -23,7 +23,26 @@ PyObject *py_ue_static_mesh_build(ue_PyUObject *self, PyObject * args) Py_RETURN_NONE; } -PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *self, PyObject * args) +PyObject * py_ue_static_mesh_get_num_triangles(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + int lod_index = 0; + if (!PyArg_ParseTuple(args, "|i:get_num_tris", &lod_index)) + return nullptr; + + UStaticMesh *mesh = ue_py_check_type(self); + if (!mesh) + return PyErr_Format(PyExc_Exception, "uobject is not a UStaticMesh"); + + if (lod_index < 0 || lod_index >= mesh->GetNumLODs()) + return PyErr_Format(PyExc_Exception, "invalid LOD index, must be between 0 and %d", mesh->GetNumLODs() - 1); + + return PyLong_FromLong(mesh->RenderData ? mesh->RenderData->LODResources[lod_index].GetNumTriangles() : 0); +} + +PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *self, PyObject * args) { ue_py_check(self); @@ -37,7 +56,22 @@ PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *self, PyObject * arg Py_RETURN_NONE; } -PyObject *py_ue_static_mesh_get_raw_mesh(ue_PyUObject *self, PyObject * args) +PyObject *py_ue_static_mesh_can_lods_share_static_lighting(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + UStaticMesh *mesh = ue_py_check_type(self); + if (!mesh) + return PyErr_Format(PyExc_Exception, "uobject is not a UStaticMesh"); + + //if (mesh->CanLODsShareStaticLighting()) + // Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +PyObject *py_ue_static_mesh_get_raw_mesh(ue_PyUObject *self, PyObject * args) { ue_py_check(self); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h index cb85c9b08..96d8b92fd 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h @@ -6,6 +6,9 @@ #if WITH_EDITOR PyObject *py_ue_static_mesh_build(ue_PyUObject *, PyObject *); +PyObject *py_ue_static_mesh_get_num_triangles(ue_PyUObject *self, PyObject * args); PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *, PyObject *); +PyObject *py_ue_static_mesh_can_lods_share_static_lighting(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_get_raw_mesh(ue_PyUObject *, PyObject *); + #endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp index 053a31fc7..d39d2e728 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp @@ -32,7 +32,7 @@ PyObject *py_ue_line_trace_single_by_channel(ue_PyUObject * self, PyObject * arg FHitResult hit; - bool got_hit = world->LineTraceSingleByChannel(hit, start->vec, end->vec, (ECollisionChannel)channel); + bool got_hit = world->LineTraceSingleByChannel(hit, py_ue_fvector_get(start), py_ue_fvector_get(end), (ECollisionChannel)channel); if (got_hit) { @@ -73,7 +73,7 @@ PyObject *py_ue_line_trace_multi_by_channel(ue_PyUObject * self, PyObject * args PyObject *hits_list = PyList_New(0); - bool got_hits = world->LineTraceMultiByChannel(hits, start->vec, end->vec, (ECollisionChannel)channel); + bool got_hits = world->LineTraceMultiByChannel(hits, py_ue_fvector_get(start), py_ue_fvector_get(end), (ECollisionChannel)channel); if (got_hits) { @@ -161,7 +161,7 @@ PyObject *py_ue_draw_debug_line(ue_PyUObject * self, PyObject * args) if (!py_linear_color) return PyErr_Format(PyExc_Exception, "argument is not a FLinearColor"); - UKismetSystemLibrary::DrawDebugLine(world, start->vec, end->vec, py_linear_color->color, duration, thickness); + UKismetSystemLibrary::DrawDebugLine(world, py_ue_fvector_get(start), py_ue_fvector_get(end), py_linear_color->color, duration, thickness); Py_RETURN_NONE; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp index 952d61423..58fb5b79f 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp @@ -28,7 +28,7 @@ static bool check_vector_args(PyObject *args, FVector &vec, bool &sweep, bool &t } else { - vec = ue_py_vec->vec; + vec = py_ue_fvector_get(ue_py_vec); } sweep = (py_sweep && PyObject_IsTrue(py_sweep)); @@ -58,7 +58,7 @@ static bool check_rotation_args(PyObject *args, FQuat &quat, bool &sweep, bool & ue_PyFQuat *ue_py_quat = py_ue_is_fquat(py_rotation); if (ue_py_quat) { - quat = ue_py_quat->quat; + quat = py_ue_fquat_get(ue_py_quat); } else { @@ -68,7 +68,7 @@ static bool check_rotation_args(PyObject *args, FQuat &quat, bool &sweep, bool & PyErr_SetString(PyExc_Exception, "argument is not a FQuat or FRotator"); return false; } - quat = ue_py_rot->rot.Quaternion(); + quat = py_ue_frotator_get(ue_py_rot).Quaternion(); } } else @@ -102,7 +102,7 @@ static bool check_rotation_args_no_sweep(PyObject *args, FQuat &quat, bool &tele ue_PyFQuat *ue_py_quat = py_ue_is_fquat(py_rotation); if (ue_py_quat) { - quat = ue_py_quat->quat; + quat = py_ue_fquat_get(ue_py_quat); } else { @@ -112,7 +112,7 @@ static bool check_rotation_args_no_sweep(PyObject *args, FQuat &quat, bool &tele PyErr_SetString(PyExc_Exception, "argument is not a FQuat or FRotator"); return false; } - quat = ue_py_rot->rot.Quaternion(); + quat = py_ue_frotator_get(ue_py_rot).Quaternion(); } } else diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp index 75cedf6e6..b0421f94a 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp @@ -33,7 +33,7 @@ PyObject *py_ue_struct_add_variable(ue_PyUObject * self, PyObject * args) FStructureEditorUtils::OnStructureChanged(u_struct, FStructureEditorUtils::EStructureEditorChangeInfo::AddedVariable); - return py_ue_new_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&var->VarGuid); + return py_ue_new_uscriptstruct(TBaseStructure::Get(), (uint8 *)&var->VarGuid); } PyObject *py_ue_struct_get_variables(ue_PyUObject * self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp index 41cbea974..eb0baf929 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp @@ -98,7 +98,7 @@ PyObject *py_unreal_engine_editor_set_view_location(PyObject * self, PyObject * FLevelEditorViewportClient &viewport_client = EditorModule.GetFirstActiveViewport()->GetLevelViewportClient(); - viewport_client.SetViewLocation(vector->vec); + viewport_client.SetViewLocation(py_ue_fvector_get(vector)); Py_RETURN_NONE; } @@ -124,7 +124,7 @@ PyObject *py_unreal_engine_editor_set_view_rotation(PyObject * self, PyObject * FLevelEditorViewportClient &viewport_client = EditorModule.GetFirstActiveViewport()->GetLevelViewportClient(); - viewport_client.SetViewRotation(rotator->rot); + viewport_client.SetViewRotation(py_ue_frotator_get(rotator)); Py_RETURN_NONE; } @@ -161,7 +161,7 @@ PyObject *py_ue_add_viewport_widget_content(ue_PyUObject *self, PyObject * args) return nullptr; } - viewport->AddViewportWidgetContent(content.ToSharedRef()); + viewport->AddViewportWidgetContent(content.ToSharedRef(), z_order); Py_RETURN_NONE; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp index 284223c61..f1ec1b706 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp @@ -25,10 +25,10 @@ PyObject *py_ue_set_slate_widget(ue_PyUObject * self, PyObject * args) TSharedPtr Widget = py_ue_is_swidget(py_widget); if (!Widget.IsValid()) - return nullptr; + { return nullptr; } - if (widget_component) { widget_component->SetSlateWidget(Widget); } - else { py_user_widget->SetSlateWidget(Widget.ToSharedRef()); } + if (widget_component) { widget_component->SetSlateWidget(Widget); } + else { py_user_widget->SetSlateWidget(Widget.ToSharedRef()); } Py_RETURN_NONE; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp index a649ce2aa..2eff4a06e 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp @@ -1,4 +1,6 @@ #include "UEPyWorld.h" +#include "EngineUtils.h" +#include "Kismet/GameplayStatics.h" #include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h" #include "EngineUtils.h" @@ -274,6 +276,28 @@ PyObject *py_ue_get_levels(ue_PyUObject * self, PyObject * args) return ret; } +PyObject *py_ue_get_actors(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + ULevel *level = ue_py_check_type(self); + if (!level) + return PyErr_Format(PyExc_Exception, "This uobject is not a ULevel"); + + PyObject *ret = PyList_New(0); + + for (AActor * actor : level->Actors) + { + ue_PyUObject *py_obj = ue_get_python_uobject(actor); + if (!py_obj) + continue; + PyList_Append(ret, (PyObject *)py_obj); + } + + return ret; +} + PyObject *py_ue_get_current_level(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h index fddb850a2..bb60977a6 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h @@ -22,6 +22,7 @@ PyObject *py_ue_set_view_target(ue_PyUObject *, PyObject *); PyObject *py_ue_get_world_delta_seconds(ue_PyUObject *, PyObject *); PyObject *py_ue_get_levels(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_actors(ue_PyUObject *, PyObject *); PyObject *py_ue_get_game_viewport(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index a10a4870b..3a16efc18 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -511,8 +511,8 @@ void FUnrealEnginePythonModule::RunFile(char *filename) { FScopePythonGIL gil; FString full_path = UTF8_TO_TCHAR(filename); - bool foundFile = false; - if (!FPaths::FileExists(filename)) + bool foundFile = FPaths::FileExists(filename); + if (!foundFile) { for (FString ScriptsPath : ScriptsPaths) { @@ -527,7 +527,7 @@ void FUnrealEnginePythonModule::RunFile(char *filename) if (!foundFile) { - UE_LOG(LogPython, Error, TEXT("Unable to find file %s"), UTF8_TO_TCHAR(filename)); + UE_LOG(LogPython, Error, TEXT("Unable to find file %s"), *full_path); return; } @@ -575,8 +575,8 @@ void FUnrealEnginePythonModule::RunFileSandboxed(char *filename, void(*callback) { FScopePythonGIL gil; FString full_path = filename; - bool foundFile = false; - if (!FPaths::FileExists(filename)) + bool foundFile = FPaths::FileExists(filename); + if (!foundFile) { for (FString ScriptsPath : ScriptsPaths) { @@ -591,7 +591,7 @@ void FUnrealEnginePythonModule::RunFileSandboxed(char *filename, void(*callback) if (!foundFile) { - UE_LOG(LogPython, Error, TEXT("Unable to find file %s"), UTF8_TO_TCHAR(filename)); + UE_LOG(LogPython, Error, TEXT("Unable to find file %s"), *full_path); return; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 4352312ba..3eb9b635d 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -2,19 +2,29 @@ #include "Runtime/Slate/Public/Framework/Commands/UICommandInfo.h" -static PyObject *py_ue_eslate_enums_get(ue_PyESlateEnums *self, void *closure) -{ - return PyLong_FromLong(self->val); -} +#if WITH_EDITOR +#include "ISequencer.h" +#include "IDetailsView.h" +#endif +#include +#include "SSplitter.h" +#include "MenuStack.h" +#include "SlateFwd.h" +#include "SDockTab.h" +#include "RHIDefinitions.h" +#include "SceneTypes.h" static PyGetSetDef ue_PyESlateEnums_getseters[] = { - { (char*)"val", (getter)py_ue_eslate_enums_get, 0, (char *)"", NULL }, { NULL } /* Sentinel */ }; -static PyObject *ue_PyESlateEnums_str(ue_PyESlateEnums *self) +static void ue_PyESlateEnums_dealloc(ue_PyESlateEnums *self) { - return PyUnicode_FromFormat("", PyLong_FromLong(self->val)); +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Destroying ue_PyESlateEnums %p"), self); +#endif + Py_DECREF(self->py_dict); + Py_TYPE(self)->tp_free((PyObject *)self); } static PyTypeObject ue_PyESlateEnumsType = { @@ -22,7 +32,7 @@ static PyTypeObject ue_PyESlateEnumsType = { "unreal_engine.ESlateEnums", /* tp_name */ sizeof(ue_PyESlateEnums), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + (destructor)ue_PyESlateEnums_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -33,7 +43,7 @@ static PyTypeObject ue_PyESlateEnumsType = { 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - (reprfunc)ue_PyESlateEnums_str, /* tp_str */ + 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -50,21 +60,27 @@ static PyTypeObject ue_PyESlateEnumsType = { ue_PyESlateEnums_getseters, }; -static int ue_py_eslate_enums_init(ue_PyESlateEnums *self, PyObject *args, PyObject *kwargs) +static PyObject* ue_PyESlateEnums_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - int val = 0; - if (!PyArg_ParseTuple(args, "i", &val)) - return -1; + ue_PyESlateEnums *self = (ue_PyESlateEnums *)type->tp_alloc(type, 0); + if (self != NULL) + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Allocating new %s..."), UTF8_TO_TCHAR(self->ob_base.ob_type->tp_name)); +#endif + self->py_dict = PyDict_New(); + } - self->val = val; - return 0; + return (PyObject *)self; } void ue_python_init_eslate_enums(PyObject *ue_module) { - ue_PyESlateEnumsType.tp_new = PyType_GenericNew; + ue_PyESlateEnumsType.tp_new = ue_PyESlateEnums_new; - ue_PyESlateEnumsType.tp_init = (initproc)ue_py_eslate_enums_init; + ue_PyESlateEnumsType.tp_getattro = PyObject_GenericGetAttr; + ue_PyESlateEnumsType.tp_setattro = PyObject_GenericSetAttr; + ue_PyESlateEnumsType.tp_dictoffset = offsetof(ue_PyESlateEnums, py_dict); if (PyType_Ready(&ue_PyESlateEnumsType) < 0) return; @@ -72,24 +88,552 @@ void ue_python_init_eslate_enums(PyObject *ue_module) Py_INCREF(&ue_PyESlateEnumsType); PyModule_AddObject(ue_module, "ESlateEnums", (PyObject *)&ue_PyESlateEnumsType); - auto add_native_enum = [](const char *enum_name, uint8 val) - { - ue_PyESlateEnums* native_enum = (ue_PyESlateEnums *)PyObject_New(ue_PyESlateEnums, &ue_PyESlateEnumsType); - native_enum->val = val; - PyDict_SetItemString(ue_PyESlateEnumsType.tp_dict, enum_name, (PyObject *)native_enum); - }; - -#if ENGINE_MINOR_VERSION > 15 -#define ADD_NATIVE_ENUM(EnumType, EnumVal) add_native_enum(#EnumType "." #EnumVal, (uint8)EnumType::Type::EnumVal) - ADD_NATIVE_ENUM(EUserInterfaceActionType, None); - ADD_NATIVE_ENUM(EUserInterfaceActionType, Button); - ADD_NATIVE_ENUM(EUserInterfaceActionType, ToggleButton); - ADD_NATIVE_ENUM(EUserInterfaceActionType, RadioButton); - ADD_NATIVE_ENUM(EUserInterfaceActionType, Check); - ADD_NATIVE_ENUM(EUserInterfaceActionType, CollapsedButton); -#undef ADD_NATIVE_ENUM -#endif + + PyObject *unreal_engine_dict = PyModule_GetDict(ue_module); + + /*[[[cog + import collections + EnumDef = collections.namedtuple('EnumDef', 'name cppNameScope values') + + native_enums_list = [ + EnumDef(name='ESizeRule', + cppNameScope='SSplitter::ESizeRule', + values=[ + 'SizeToContent', + 'FractionOfParent', + ]), + + EnumDef(name='EUserInterfaceActionType', + cppNameScope='EUserInterfaceActionType::Type', + values=[ + 'None', + 'Button', + 'ToggleButton', + 'RadioButton', + 'Check', + 'CollapsedButton', + ]), + + EnumDef(name='ESplitterResizeMode', + cppNameScope='ESplitterResizeMode::Type', + values=[ + 'FixedPosition', + 'FixedSize', + 'Fill', + ]), + + EnumDef(name='ESizingRule', + cppNameScope='ESizingRule', + values=[ + 'FixedSize', + 'Autosized', + 'UserSized', + ]), + + EnumDef(name='ESlideDirection', + cppNameScope='FPopupTransitionEffect::ESlideDirection', + values=[ + 'None', + 'ComboButton', + 'TopMenu', + 'SubMenu', + 'TypeInPopup', + 'ContextMenu', + ]), + + EnumDef(name='ETabRole', + cppNameScope='ETabRole', + values=[ + 'MajorTab', + 'PanelTab', + 'NomadTab', + 'DocumentTab', + 'NumRoles' + ]), + + EnumDef(name='ELoadConfigPropagationFlags', + cppNameScope='UE4::ELoadConfigPropagationFlags', + values=[ + 'LCPF_None', + 'LCPF_ReadParentSections', + 'LCPF_PropagateToChildDefaultObjects', + 'LCPF_PropagateToInstances', + 'LCPF_ReloadingConfigData', + 'LCPF_PersistentFlags', + ]), + + EnumDef(name='ESearchPreference', + cppNameScope='FTabManager::ESearchPreference::ESearchPreference', + values=[ + 'PreferLiveTab', + 'RequireClosedTab', + ]), + + EnumDef(name='ETabActivationCause', + cppNameScope='ETabActivationCause', + values=[ + 'UserClickedOnTab', + 'SetDirectly', + ]), + + EnumDef(name='EMaterialQualityLevel', + cppNameScope='EMaterialQualityLevel', + values=[ + 'High', + 'Medium', + 'Low', + 'Num', + ]), + + EnumDef(name='ERHIFeatureLevel', + cppNameScope='ERHIFeatureLevel', + values=[ + 'ES2', + 'ES3_1', + 'SM4', + 'SM5', + 'Num', + ]), + + EnumDef(name='EShaderPlatform', + cppNameScope='EShaderPlatform', + values=[ + 'SP_PCD3D_SM5', + 'SP_OPENGL_SM4', + 'SP_PS4', + 'SP_OPENGL_PCES2', + 'SP_XBOXONE_D3D12', + 'SP_PCD3D_SM4', + 'SP_OPENGL_SM5', + 'SP_PCD3D_ES2', + 'SP_OPENGL_ES2_ANDROID', + 'SP_OPENGL_ES2_WEBGL', + 'SP_OPENGL_ES2_IOS', + 'SP_METAL', + 'SP_METAL_MRT', + 'SP_OPENGL_ES31_EXT', + 'SP_PCD3D_ES3_1', + 'SP_OPENGL_PCES3_1', + 'SP_METAL_SM5', + 'SP_VULKAN_PCES3_1', + 'SP_METAL_SM5_NOTESS', + 'SP_VULKAN_SM4', + 'SP_VULKAN_SM5', + 'SP_VULKAN_ES3_1_ANDROID', + 'SP_METAL_MACES3_1', + 'SP_METAL_MACES2', + 'SP_OPENGL_ES3_1_ANDROID', + 'SP_SWITCH', + 'SP_SWITCH_FORWARD', + 'SP_METAL_MRT_MAC', + 'SP_NumPlatforms', + 'SP_NumBits', + ]), + + EnumDef(name='EDataValidationResult', + cppNameScope='EDataValidationResult', + values=[ + 'Invalid', + 'Valid', + 'NotValidated' + ]), + + EnumDef(name='EFieldIteratorFlags', + cppNameScope='EFieldIteratorFlags', + values=[ + 'ExcludeSuper', + 'IncludeSuper', + 'ExcludeDeprecated', + 'IncludeDeprecated', + 'ExcludeInterfaces', + 'IncludeInterfaces', + ]), + ] + + ############################################################################################# + # Editor Only Native Enums # + ############################################################################################# + + editor_native_enums_list = [ + EnumDef(name='EEditDefaultsOnlyNodeVisibility', + cppNameScope='EEditDefaultsOnlyNodeVisibility', + values=[ + 'Show', + 'Hide', + 'Automatic', + ]), + + EnumDef(name='EMovieSceneDataChangeType', + cppNameScope='EMovieSceneDataChangeType', + values=[ + 'TrackValueChanged', + 'TrackValueChangedRefreshImmediately', + 'MovieSceneStructureItemAdded', + 'MovieSceneStructureItemRemoved', + 'MovieSceneStructureItemsChanged', + 'ActiveMovieSceneChanged', + 'RefreshAllImmediately', + 'Unknown', + ]), + + EnumDef(name='EWidgetMode', + cppNameScope='FWidget::EWidgetMode', + values=[ + 'WM_None', + 'WM_Translate', + 'WM_TranslateRotateZ', + 'WM_2D', + 'WM_Rotate', + 'WM_Scale', + 'WM_Max', + ]), + + EnumDef(name='ECoordSystem', + cppNameScope='ECoordSystem', + values=[ + 'COORD_None', + 'COORD_World', + 'COORD_Local', + 'COORD_Max', + ]), + ] + + def output_cpp_enums(in_enum_list): + for enum_def in in_enum_list: + enumVar_str = f'native_{enum_def.name}' + cog.out(f""" + // Enum Wrapper: {enum_def.name} + {{ + PyObject* {enumVar_str} = PyDict_GetItemString(unreal_engine_dict, "{enum_def.name}"); + if ({enumVar_str} == nullptr) + {{ + {enumVar_str} = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "{enum_def.name}", (PyObject*){enumVar_str}); + }} + + """, dedent=True, trimblanklines=True) + + for enum_val in enum_def.values: + enum_val_str = '"' + enum_val + '"' + cog.outl(f' PyObject_SetAttrString((PyObject*){enumVar_str}, {enum_val_str:17}, PyLong_FromLong((int){enum_def.cppNameScope}::{enum_val}));'); + + cog.outl("}") + cog.outl("") + + output_cpp_enums(native_enums_list) + + cog.outl("#if WITH_EDITOR") + output_cpp_enums(editor_native_enums_list) + cog.outl("#endif") + + ]]]*/ + // Enum Wrapper: ESizeRule + { + PyObject* native_ESizeRule = PyDict_GetItemString(unreal_engine_dict, "ESizeRule"); + if (native_ESizeRule == nullptr) + { + native_ESizeRule = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ESizeRule", (PyObject*)native_ESizeRule); + } + + PyObject_SetAttrString((PyObject*)native_ESizeRule, "SizeToContent" , PyLong_FromLong((int)SSplitter::ESizeRule::SizeToContent)); + PyObject_SetAttrString((PyObject*)native_ESizeRule, "FractionOfParent", PyLong_FromLong((int)SSplitter::ESizeRule::FractionOfParent)); + } + + // Enum Wrapper: EUserInterfaceActionType + { + PyObject* native_EUserInterfaceActionType = PyDict_GetItemString(unreal_engine_dict, "EUserInterfaceActionType"); + if (native_EUserInterfaceActionType == nullptr) + { + native_EUserInterfaceActionType = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EUserInterfaceActionType", (PyObject*)native_EUserInterfaceActionType); + } + + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "None" , PyLong_FromLong((int)EUserInterfaceActionType::Type::None)); + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "Button" , PyLong_FromLong((int)EUserInterfaceActionType::Type::Button)); + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "ToggleButton" , PyLong_FromLong((int)EUserInterfaceActionType::Type::ToggleButton)); + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "RadioButton" , PyLong_FromLong((int)EUserInterfaceActionType::Type::RadioButton)); + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "Check" , PyLong_FromLong((int)EUserInterfaceActionType::Type::Check)); + PyObject_SetAttrString((PyObject*)native_EUserInterfaceActionType, "CollapsedButton", PyLong_FromLong((int)EUserInterfaceActionType::Type::CollapsedButton)); + } + + // Enum Wrapper: ESplitterResizeMode + { + PyObject* native_ESplitterResizeMode = PyDict_GetItemString(unreal_engine_dict, "ESplitterResizeMode"); + if (native_ESplitterResizeMode == nullptr) + { + native_ESplitterResizeMode = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ESplitterResizeMode", (PyObject*)native_ESplitterResizeMode); + } + + PyObject_SetAttrString((PyObject*)native_ESplitterResizeMode, "FixedPosition" , PyLong_FromLong((int)ESplitterResizeMode::Type::FixedPosition)); + PyObject_SetAttrString((PyObject*)native_ESplitterResizeMode, "FixedSize" , PyLong_FromLong((int)ESplitterResizeMode::Type::FixedSize)); + PyObject_SetAttrString((PyObject*)native_ESplitterResizeMode, "Fill" , PyLong_FromLong((int)ESplitterResizeMode::Type::Fill)); + } + + // Enum Wrapper: ESizingRule + { + PyObject* native_ESizingRule = PyDict_GetItemString(unreal_engine_dict, "ESizingRule"); + if (native_ESizingRule == nullptr) + { + native_ESizingRule = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ESizingRule", (PyObject*)native_ESizingRule); + } + + PyObject_SetAttrString((PyObject*)native_ESizingRule, "FixedSize" , PyLong_FromLong((int)ESizingRule::FixedSize)); + PyObject_SetAttrString((PyObject*)native_ESizingRule, "Autosized" , PyLong_FromLong((int)ESizingRule::Autosized)); + PyObject_SetAttrString((PyObject*)native_ESizingRule, "UserSized" , PyLong_FromLong((int)ESizingRule::UserSized)); + } + + // Enum Wrapper: ESlideDirection + { + PyObject* native_ESlideDirection = PyDict_GetItemString(unreal_engine_dict, "ESlideDirection"); + if (native_ESlideDirection == nullptr) + { + native_ESlideDirection = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ESlideDirection", (PyObject*)native_ESlideDirection); + } + + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "None" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::None)); + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "ComboButton" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::ComboButton)); + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "TopMenu" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::TopMenu)); + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "SubMenu" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::SubMenu)); + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "TypeInPopup" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::TypeInPopup)); + PyObject_SetAttrString((PyObject*)native_ESlideDirection, "ContextMenu" , PyLong_FromLong((int)FPopupTransitionEffect::ESlideDirection::ContextMenu)); + } + + // Enum Wrapper: ETabRole + { + PyObject* native_ETabRole = PyDict_GetItemString(unreal_engine_dict, "ETabRole"); + if (native_ETabRole == nullptr) + { + native_ETabRole = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ETabRole", (PyObject*)native_ETabRole); + } + + PyObject_SetAttrString((PyObject*)native_ETabRole, "MajorTab" , PyLong_FromLong((int)ETabRole::MajorTab)); + PyObject_SetAttrString((PyObject*)native_ETabRole, "PanelTab" , PyLong_FromLong((int)ETabRole::PanelTab)); + PyObject_SetAttrString((PyObject*)native_ETabRole, "NomadTab" , PyLong_FromLong((int)ETabRole::NomadTab)); + PyObject_SetAttrString((PyObject*)native_ETabRole, "DocumentTab" , PyLong_FromLong((int)ETabRole::DocumentTab)); + PyObject_SetAttrString((PyObject*)native_ETabRole, "NumRoles" , PyLong_FromLong((int)ETabRole::NumRoles)); + } + + // Enum Wrapper: ELoadConfigPropagationFlags + { + PyObject* native_ELoadConfigPropagationFlags = PyDict_GetItemString(unreal_engine_dict, "ELoadConfigPropagationFlags"); + if (native_ELoadConfigPropagationFlags == nullptr) + { + native_ELoadConfigPropagationFlags = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ELoadConfigPropagationFlags", (PyObject*)native_ELoadConfigPropagationFlags); + } + + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_None" , PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_None)); + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_ReadParentSections", PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_ReadParentSections)); + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_PropagateToChildDefaultObjects", PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_PropagateToChildDefaultObjects)); + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_PropagateToInstances", PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_PropagateToInstances)); + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_ReloadingConfigData", PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_ReloadingConfigData)); + PyObject_SetAttrString((PyObject*)native_ELoadConfigPropagationFlags, "LCPF_PersistentFlags", PyLong_FromLong((int)UE4::ELoadConfigPropagationFlags::LCPF_PersistentFlags)); + } + + // Enum Wrapper: ESearchPreference + { + PyObject* native_ESearchPreference = PyDict_GetItemString(unreal_engine_dict, "ESearchPreference"); + if (native_ESearchPreference == nullptr) + { + native_ESearchPreference = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ESearchPreference", (PyObject*)native_ESearchPreference); + } + + PyObject_SetAttrString((PyObject*)native_ESearchPreference, "PreferLiveTab" , PyLong_FromLong((int)FTabManager::ESearchPreference::ESearchPreference::PreferLiveTab)); + PyObject_SetAttrString((PyObject*)native_ESearchPreference, "RequireClosedTab", PyLong_FromLong((int)FTabManager::ESearchPreference::ESearchPreference::RequireClosedTab)); + } + + // Enum Wrapper: ETabActivationCause + { + PyObject* native_ETabActivationCause = PyDict_GetItemString(unreal_engine_dict, "ETabActivationCause"); + if (native_ETabActivationCause == nullptr) + { + native_ETabActivationCause = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ETabActivationCause", (PyObject*)native_ETabActivationCause); + } + + PyObject_SetAttrString((PyObject*)native_ETabActivationCause, "UserClickedOnTab", PyLong_FromLong((int)ETabActivationCause::UserClickedOnTab)); + PyObject_SetAttrString((PyObject*)native_ETabActivationCause, "SetDirectly" , PyLong_FromLong((int)ETabActivationCause::SetDirectly)); + } + + // Enum Wrapper: EMaterialQualityLevel + { + PyObject* native_EMaterialQualityLevel = PyDict_GetItemString(unreal_engine_dict, "EMaterialQualityLevel"); + if (native_EMaterialQualityLevel == nullptr) + { + native_EMaterialQualityLevel = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EMaterialQualityLevel", (PyObject*)native_EMaterialQualityLevel); + } + + PyObject_SetAttrString((PyObject*)native_EMaterialQualityLevel, "High" , PyLong_FromLong((int)EMaterialQualityLevel::High)); + PyObject_SetAttrString((PyObject*)native_EMaterialQualityLevel, "Medium" , PyLong_FromLong((int)EMaterialQualityLevel::Medium)); + PyObject_SetAttrString((PyObject*)native_EMaterialQualityLevel, "Low" , PyLong_FromLong((int)EMaterialQualityLevel::Low)); + PyObject_SetAttrString((PyObject*)native_EMaterialQualityLevel, "Num" , PyLong_FromLong((int)EMaterialQualityLevel::Num)); + } + + // Enum Wrapper: ERHIFeatureLevel + { + PyObject* native_ERHIFeatureLevel = PyDict_GetItemString(unreal_engine_dict, "ERHIFeatureLevel"); + if (native_ERHIFeatureLevel == nullptr) + { + native_ERHIFeatureLevel = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ERHIFeatureLevel", (PyObject*)native_ERHIFeatureLevel); + } + + PyObject_SetAttrString((PyObject*)native_ERHIFeatureLevel, "ES2" , PyLong_FromLong((int)ERHIFeatureLevel::ES2)); + PyObject_SetAttrString((PyObject*)native_ERHIFeatureLevel, "ES3_1" , PyLong_FromLong((int)ERHIFeatureLevel::ES3_1)); + PyObject_SetAttrString((PyObject*)native_ERHIFeatureLevel, "SM4" , PyLong_FromLong((int)ERHIFeatureLevel::SM4)); + PyObject_SetAttrString((PyObject*)native_ERHIFeatureLevel, "SM5" , PyLong_FromLong((int)ERHIFeatureLevel::SM5)); + PyObject_SetAttrString((PyObject*)native_ERHIFeatureLevel, "Num" , PyLong_FromLong((int)ERHIFeatureLevel::Num)); + } + + // Enum Wrapper: EShaderPlatform + { + PyObject* native_EShaderPlatform = PyDict_GetItemString(unreal_engine_dict, "EShaderPlatform"); + if (native_EShaderPlatform == nullptr) + { + native_EShaderPlatform = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EShaderPlatform", (PyObject*)native_EShaderPlatform); + } + + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_PCD3D_SM5" , PyLong_FromLong((int)EShaderPlatform::SP_PCD3D_SM5)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_SM4" , PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_SM4)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_PS4" , PyLong_FromLong((int)EShaderPlatform::SP_PS4)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_PCES2", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_PCES2)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_XBOXONE_D3D12", PyLong_FromLong((int)EShaderPlatform::SP_XBOXONE_D3D12)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_PCD3D_SM4" , PyLong_FromLong((int)EShaderPlatform::SP_PCD3D_SM4)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_SM5" , PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_SM5)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_PCD3D_ES2" , PyLong_FromLong((int)EShaderPlatform::SP_PCD3D_ES2)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_ES2_ANDROID", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_ES2_ANDROID)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_ES2_WEBGL", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_ES2_WEBGL)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_ES2_IOS", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_ES2_IOS)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL" , PyLong_FromLong((int)EShaderPlatform::SP_METAL)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_MRT" , PyLong_FromLong((int)EShaderPlatform::SP_METAL_MRT)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_ES31_EXT", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_ES31_EXT)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_PCD3D_ES3_1" , PyLong_FromLong((int)EShaderPlatform::SP_PCD3D_ES3_1)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_PCES3_1", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_PCES3_1)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_SM5" , PyLong_FromLong((int)EShaderPlatform::SP_METAL_SM5)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_VULKAN_PCES3_1", PyLong_FromLong((int)EShaderPlatform::SP_VULKAN_PCES3_1)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_SM5_NOTESS", PyLong_FromLong((int)EShaderPlatform::SP_METAL_SM5_NOTESS)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_VULKAN_SM4" , PyLong_FromLong((int)EShaderPlatform::SP_VULKAN_SM4)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_VULKAN_SM5" , PyLong_FromLong((int)EShaderPlatform::SP_VULKAN_SM5)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_VULKAN_ES3_1_ANDROID", PyLong_FromLong((int)EShaderPlatform::SP_VULKAN_ES3_1_ANDROID)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_MACES3_1", PyLong_FromLong((int)EShaderPlatform::SP_METAL_MACES3_1)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_MACES2", PyLong_FromLong((int)EShaderPlatform::SP_METAL_MACES2)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_OPENGL_ES3_1_ANDROID", PyLong_FromLong((int)EShaderPlatform::SP_OPENGL_ES3_1_ANDROID)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_SWITCH" , PyLong_FromLong((int)EShaderPlatform::SP_SWITCH)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_SWITCH_FORWARD", PyLong_FromLong((int)EShaderPlatform::SP_SWITCH_FORWARD)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_METAL_MRT_MAC", PyLong_FromLong((int)EShaderPlatform::SP_METAL_MRT_MAC)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_NumPlatforms", PyLong_FromLong((int)EShaderPlatform::SP_NumPlatforms)); + PyObject_SetAttrString((PyObject*)native_EShaderPlatform, "SP_NumBits" , PyLong_FromLong((int)EShaderPlatform::SP_NumBits)); + } + + // Enum Wrapper: EDataValidationResult + { + PyObject* native_EDataValidationResult = PyDict_GetItemString(unreal_engine_dict, "EDataValidationResult"); + if (native_EDataValidationResult == nullptr) + { + native_EDataValidationResult = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EDataValidationResult", (PyObject*)native_EDataValidationResult); + } + + PyObject_SetAttrString((PyObject*)native_EDataValidationResult, "Invalid" , PyLong_FromLong((int)EDataValidationResult::Invalid)); + PyObject_SetAttrString((PyObject*)native_EDataValidationResult, "Valid" , PyLong_FromLong((int)EDataValidationResult::Valid)); + PyObject_SetAttrString((PyObject*)native_EDataValidationResult, "NotValidated" , PyLong_FromLong((int)EDataValidationResult::NotValidated)); + } + + // Enum Wrapper: EFieldIteratorFlags + { + PyObject* native_EFieldIteratorFlags = PyDict_GetItemString(unreal_engine_dict, "EFieldIteratorFlags"); + if (native_EFieldIteratorFlags == nullptr) + { + native_EFieldIteratorFlags = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EFieldIteratorFlags", (PyObject*)native_EFieldIteratorFlags); + } + + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "ExcludeSuper" , PyLong_FromLong((int)EFieldIteratorFlags::ExcludeSuper)); + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "IncludeSuper" , PyLong_FromLong((int)EFieldIteratorFlags::IncludeSuper)); + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "ExcludeDeprecated", PyLong_FromLong((int)EFieldIteratorFlags::ExcludeDeprecated)); + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "IncludeDeprecated", PyLong_FromLong((int)EFieldIteratorFlags::IncludeDeprecated)); + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "ExcludeInterfaces", PyLong_FromLong((int)EFieldIteratorFlags::ExcludeInterfaces)); + PyObject_SetAttrString((PyObject*)native_EFieldIteratorFlags, "IncludeInterfaces", PyLong_FromLong((int)EFieldIteratorFlags::IncludeInterfaces)); + } + + #if WITH_EDITOR + // Enum Wrapper: EEditDefaultsOnlyNodeVisibility + { + PyObject* native_EEditDefaultsOnlyNodeVisibility = PyDict_GetItemString(unreal_engine_dict, "EEditDefaultsOnlyNodeVisibility"); + if (native_EEditDefaultsOnlyNodeVisibility == nullptr) + { + native_EEditDefaultsOnlyNodeVisibility = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EEditDefaultsOnlyNodeVisibility", (PyObject*)native_EEditDefaultsOnlyNodeVisibility); + } + + PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Show" , PyLong_FromLong((int)EEditDefaultsOnlyNodeVisibility::Show)); + PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Hide" , PyLong_FromLong((int)EEditDefaultsOnlyNodeVisibility::Hide)); + PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Automatic" , PyLong_FromLong((int)EEditDefaultsOnlyNodeVisibility::Automatic)); + } + + // Enum Wrapper: EMovieSceneDataChangeType + { + PyObject* native_EMovieSceneDataChangeType = PyDict_GetItemString(unreal_engine_dict, "EMovieSceneDataChangeType"); + if (native_EMovieSceneDataChangeType == nullptr) + { + native_EMovieSceneDataChangeType = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EMovieSceneDataChangeType", (PyObject*)native_EMovieSceneDataChangeType); + } + + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "TrackValueChanged", PyLong_FromLong((int)EMovieSceneDataChangeType::TrackValueChanged)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "TrackValueChangedRefreshImmediately", PyLong_FromLong((int)EMovieSceneDataChangeType::TrackValueChangedRefreshImmediately)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "MovieSceneStructureItemAdded", PyLong_FromLong((int)EMovieSceneDataChangeType::MovieSceneStructureItemAdded)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "MovieSceneStructureItemRemoved", PyLong_FromLong((int)EMovieSceneDataChangeType::MovieSceneStructureItemRemoved)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "MovieSceneStructureItemsChanged", PyLong_FromLong((int)EMovieSceneDataChangeType::MovieSceneStructureItemsChanged)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "ActiveMovieSceneChanged", PyLong_FromLong((int)EMovieSceneDataChangeType::ActiveMovieSceneChanged)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "RefreshAllImmediately", PyLong_FromLong((int)EMovieSceneDataChangeType::RefreshAllImmediately)); + PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "Unknown" , PyLong_FromLong((int)EMovieSceneDataChangeType::Unknown)); + } + + // Enum Wrapper: EWidgetMode + { + PyObject* native_EWidgetMode = PyDict_GetItemString(unreal_engine_dict, "EWidgetMode"); + if (native_EWidgetMode == nullptr) + { + native_EWidgetMode = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "EWidgetMode", (PyObject*)native_EWidgetMode); + } + + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_None" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_None)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_Translate" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_Translate)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_TranslateRotateZ", PyLong_FromLong((int)FWidget::EWidgetMode::WM_TranslateRotateZ)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_2D" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_2D)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_Rotate" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_Rotate)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_Scale" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_Scale)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "WM_Max" , PyLong_FromLong((int)FWidget::EWidgetMode::WM_Max)); + } + + // Enum Wrapper: ECoordSystem + { + PyObject* native_ECoordSystem = PyDict_GetItemString(unreal_engine_dict, "ECoordSystem"); + if (native_ECoordSystem == nullptr) + { + native_ECoordSystem = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); + PyDict_SetItemString(unreal_engine_dict, "ECoordSystem", (PyObject*)native_ECoordSystem); + } + + PyObject_SetAttrString((PyObject*)native_ECoordSystem, "COORD_None" , PyLong_FromLong((int)ECoordSystem::COORD_None)); + PyObject_SetAttrString((PyObject*)native_ECoordSystem, "COORD_World" , PyLong_FromLong((int)ECoordSystem::COORD_World)); + PyObject_SetAttrString((PyObject*)native_ECoordSystem, "COORD_Local" , PyLong_FromLong((int)ECoordSystem::COORD_Local)); + PyObject_SetAttrString((PyObject*)native_ECoordSystem, "COORD_Max" , PyLong_FromLong((int)ECoordSystem::COORD_Max)); + } + + #endif + //[[[end]]] } ue_PyESlateEnums *py_ue_is_eslate_enums(PyObject *obj) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.h index dae16da2c..09ec430bd 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.h @@ -7,7 +7,7 @@ typedef struct { PyObject_HEAD /* Type-specific fields go here. */ - uint8 val; + PyObject *py_dict; } ue_PyESlateEnums; void ue_python_init_eslate_enums(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFAssetData.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFAssetData.cpp index 6cb186f8b..8072eabf6 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFAssetData.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFAssetData.cpp @@ -13,7 +13,16 @@ static PyObject *py_ue_fassetdata_get_asset(ue_PyFAssetData *self, PyObject * ar static PyObject *py_ue_fassetdata_is_asset_loaded(ue_PyFAssetData *self, PyObject * args) { if (self->asset_data.IsAssetLoaded()) - Py_RETURN_TRUE; + { Py_RETURN_TRUE; } + + Py_RETURN_FALSE; +} + +static PyObject *py_ue_fassetdata_is_valid(ue_PyFAssetData *self, PyObject * args) +{ + if (self->asset_data.IsValid()) + { Py_RETURN_TRUE; } + Py_RETURN_FALSE; } @@ -70,6 +79,7 @@ static PyObject *py_ue_fassetdata_has_cached_thumbnail(ue_PyFAssetData *self, Py static PyMethodDef ue_PyFAssetData_methods[] = { { "get_asset", (PyCFunction)py_ue_fassetdata_get_asset, METH_VARARGS, "" }, { "is_asset_loaded", (PyCFunction)py_ue_fassetdata_is_asset_loaded, METH_VARARGS, "" }, + { "is_valid", (PyCFunction)py_ue_fassetdata_is_valid, METH_VARARGS, "" }, { "get_thumbnail", (PyCFunction)py_ue_fassetdata_get_thumbnail, METH_VARARGS, "" }, #if ENGINE_MINOR_VERSION >= 18 diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp index d71188d97..e116a146a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp @@ -1,4 +1,5 @@ #include "UEPyFColor.h" +#include "UEPyFLinearColor.h" static PyObject *py_ue_fcolor_to_hex(ue_PyFColor *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp index 9e36b459f..6ac22f29e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp @@ -1,4 +1,5 @@ #include "UEPyFEditorViewportClient.h" +#include "UEPyFVector.h" #if WITH_EDITOR @@ -57,6 +58,13 @@ static PyObject *py_ue_feditor_viewport_client_is_visible(ue_PyFEditorViewportCl Py_RETURN_FALSE; } +static PyObject *py_ue_feditor_viewport_client_is_camera_locked(ue_PyFEditorViewportClient *self, PyObject * args) +{ + if (self->editor_viewport_client->IsCameraLocked()) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + static PyObject *py_ue_feditor_viewport_client_get_scene_depth_at_location(ue_PyFEditorViewportClient *self, PyObject * args) { int x; @@ -86,16 +94,27 @@ static PyObject *py_ue_feditor_viewport_client_set_view_location(ue_PyFEditorVie static PyObject *py_ue_feditor_viewport_client_set_realtime(ue_PyFEditorViewportClient *self, PyObject * args) { - PyObject* bInRealtime; - PyObject* bStoreCurrentValue; - if (!PyArg_ParseTuple(args, "OO", &bInRealtime, &bStoreCurrentValue)) + PyObject* bInRealtime; + PyObject* bStoreCurrentValue; + if (!PyArg_ParseTuple(args, "OO", &bInRealtime, &bStoreCurrentValue)) + return nullptr; + + self->editor_viewport_client->SetRealtime(PyObject_IsTrue(bInRealtime) ? true : false, + PyObject_IsTrue(bStoreCurrentValue) ? true : false); + Py_RETURN_NONE; +} + +static PyObject *py_ue_feditor_viewport_client_set_game_mode(ue_PyFEditorViewportClient *self, PyObject * args) +{ + PyObject* bIsEnabled; + if (!PyArg_ParseTuple(args, "O", &bIsEnabled)) return nullptr; - self->editor_viewport_client->SetRealtime(PyObject_IsTrue(bInRealtime) ? true : false, - PyObject_IsTrue(bStoreCurrentValue) ? true : false); + self->editor_viewport_client->SetGameView(PyObject_IsTrue(bIsEnabled) ? true : false); Py_RETURN_NONE; } + static PyMethodDef ue_PyFEditorViewportClient_methods[] = { { "take_high_res_screen_shot", (PyCFunction)py_ue_feditor_viewport_client_take_high_res_screen_shot, METH_VARARGS, "" }, { "tick", (PyCFunction)py_ue_feditor_viewport_client_tick, METH_VARARGS, "" }, @@ -103,11 +122,13 @@ static PyMethodDef ue_PyFEditorViewportClient_methods[] = { { "get_view_location", (PyCFunction)py_ue_feditor_viewport_client_get_view_location, METH_VARARGS, "" }, { "get_camera_speed", (PyCFunction)py_ue_feditor_viewport_client_get_camera_speed, METH_VARARGS, "" }, { "get_viewport_dimensions", (PyCFunction)py_ue_feditor_viewport_client_get_viewport_dimensions, METH_VARARGS, "" }, + { "is_camera_locked", (PyCFunction)py_ue_feditor_viewport_client_is_camera_locked, METH_VARARGS, "" }, { "is_visible", (PyCFunction)py_ue_feditor_viewport_client_is_visible, METH_VARARGS, "" }, { "get_scene_depth_at_location", (PyCFunction)py_ue_feditor_viewport_client_get_scene_depth_at_location, METH_VARARGS, "" }, { "set_look_at_location", (PyCFunction)py_ue_feditor_viewport_client_set_look_at_location, METH_VARARGS, "" }, { "set_view_location", (PyCFunction)py_ue_feditor_viewport_client_set_view_location, METH_VARARGS, "" }, - { "set_realtime", (PyCFunction)py_ue_feditor_viewport_client_set_realtime, METH_VARARGS, "" }, + { "set_realtime", (PyCFunction)py_ue_feditor_viewport_client_set_realtime, METH_VARARGS, "" }, + { "set_game_mode", (PyCFunction)py_ue_feditor_viewport_client_set_game_mode, METH_VARARGS, "" }, { nullptr } /* Sentinel */ }; diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFHitResult.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFHitResult.cpp index 0ca0277e5..3e8ec6cf2 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFHitResult.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFHitResult.cpp @@ -1,4 +1,5 @@ #include "UEPyFHitResult.h" +#include "UEPyFVector.h" #include "GameFramework/Actor.h" diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp index 1c697717a..96dfc7aa8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp @@ -10,7 +10,7 @@ static int py_ue_fmorph_target_delta_set_position_delta(ue_PyFMorphTargetDelta * ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->morph_target_delta.PositionDelta = py_vec->vec; + self->morph_target_delta.PositionDelta = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); @@ -27,7 +27,7 @@ static int py_ue_fmorph_target_delta_set_tangent_z_delta(ue_PyFMorphTargetDelta ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->morph_target_delta.TangentZDelta = py_vec->vec; + self->morph_target_delta.TangentZDelta = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFObjectThumbnail.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFObjectThumbnail.h index 23819d33f..ab7f4b02e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFObjectThumbnail.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFObjectThumbnail.h @@ -14,3 +14,5 @@ void ue_python_init_fobject_thumbnail(PyObject *); PyObject *py_ue_new_fobject_thumbnail(FObjectThumbnail); ue_PyFObjectThumbnail *py_ue_is_fobject_thumbnail(PyObject *); + +PyObject *py_ue_new_fobject_thumbnail(FObjectThumbnail object_thumnail); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index 74d914848..ddfbda9cf 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -1,51 +1,47 @@ #include "UEPyFQuat.h" +#include "UEPyFRotator.h" #if ENGINE_MINOR_VERSION > 12 -static PyObject *py_ue_fquat_angular_distance(ue_PyFQuat *self, PyObject * args) -{ +static PyObject *py_ue_fquat_angular_distance(ue_PyFQuat *self, PyObject * args) { FQuat q; - if (!py_ue_quat_arg(args, q)) - { + if (!py_ue_quat_arg(args, q)) { return nullptr; } - return PyFloat_FromDouble(self->quat.AngularDistance(q)); + return PyFloat_FromDouble(py_ue_fquat_get(self).AngularDistance(q)); } #endif -static PyObject *py_ue_fquat_euler(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fvector(self->quat.Euler()); +static PyObject *py_ue_fquat_euler(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fvector(py_ue_fquat_get(self).Euler()); } -static PyObject *py_ue_fquat_get_axis_x(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fvector(self->quat.GetAxisX()); +static PyObject *py_ue_fquat_rotator(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_frotator(py_ue_fquat_get(self).Rotator()); } -static PyObject *py_ue_fquat_get_axis_y(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fvector(self->quat.GetAxisY()); +static PyObject *py_ue_fquat_get_axis_x(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisX()); } -static PyObject *py_ue_fquat_get_axis_z(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fvector(self->quat.GetAxisZ()); +static PyObject *py_ue_fquat_get_axis_y(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisY()); } -static PyObject *py_ue_fquat_inverse(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fquat(self->quat.Inverse()); +static PyObject *py_ue_fquat_get_axis_z(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisZ()); } -static PyObject *py_ue_fquat_get_normalized(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fquat(self->quat.GetNormalized()); +static PyObject *py_ue_fquat_inverse(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fquat(py_ue_fquat_get(self).Inverse()); } -static PyObject *py_ue_fquat_vector(ue_PyFQuat *self, PyObject * args) -{ - return py_ue_new_fvector(self->quat.Vector()); +static PyObject *py_ue_fquat_get_normalized(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fquat(py_ue_fquat_get(self).GetNormalized()); +} + +static PyObject *py_ue_fquat_vector(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_fvector(py_ue_fquat_get(self).Vector()); } static PyMethodDef ue_PyFQuat_methods[] = { @@ -53,7 +49,7 @@ static PyMethodDef ue_PyFQuat_methods[] = { { "angular_distance", (PyCFunction)py_ue_fquat_angular_distance, METH_VARARGS, "" }, #endif { "euler", (PyCFunction)py_ue_fquat_euler, METH_VARARGS, "" }, - { "rotator", (PyCFunction)py_ue_fquat_euler, METH_VARARGS, "" }, + { "rotator", (PyCFunction)py_ue_fquat_rotator, METH_VARARGS, "" }, { "get_axis_x", (PyCFunction)py_ue_fquat_get_axis_x, METH_VARARGS, "" }, { "get_axis_y", (PyCFunction)py_ue_fquat_get_axis_y, METH_VARARGS, "" }, { "get_axis_z", (PyCFunction)py_ue_fquat_get_axis_z, METH_VARARGS, "" }, @@ -66,17 +62,14 @@ static PyMethodDef ue_PyFQuat_methods[] = { { NULL } /* Sentinel */ }; -static PyObject *py_ue_fquat_get_x(ue_PyFQuat *self, void *closure) -{ - return PyFloat_FromDouble(self->quat.X); +static PyObject *py_ue_fquat_get_x(ue_PyFQuat *self, void *closure) { + return PyFloat_FromDouble(py_ue_fquat_get(self).X); } -static int py_ue_fquat_set_x(ue_PyFQuat *self, PyObject *value, void *closure) -{ - if (value && PyNumber_Check(value)) - { +static int py_ue_fquat_set_x(ue_PyFQuat *self, PyObject *value, void *closure) { + if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->quat.X = PyFloat_AsDouble(f_value); + py_ue_fquat_get(self).X = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -84,17 +77,14 @@ static int py_ue_fquat_set_x(ue_PyFQuat *self, PyObject *value, void *closure) return -1; } -static PyObject *py_ue_fquat_get_y(ue_PyFQuat *self, void *closure) -{ - return PyFloat_FromDouble(self->quat.Y); +static PyObject *py_ue_fquat_get_y(ue_PyFQuat *self, void *closure) { + return PyFloat_FromDouble(py_ue_fquat_get(self).Y); } -static int py_ue_fquat_set_y(ue_PyFQuat *self, PyObject *value, void *closure) -{ - if (value && PyNumber_Check(value)) - { +static int py_ue_fquat_set_y(ue_PyFQuat *self, PyObject *value, void *closure) { + if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->quat.Y = PyFloat_AsDouble(f_value); + py_ue_fquat_get(self).Y = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -102,17 +92,14 @@ static int py_ue_fquat_set_y(ue_PyFQuat *self, PyObject *value, void *closure) return -1; } -static PyObject *py_ue_fquat_get_z(ue_PyFQuat *self, void *closure) -{ - return PyFloat_FromDouble(self->quat.Z); +static PyObject *py_ue_fquat_get_z(ue_PyFQuat *self, void *closure) { + return PyFloat_FromDouble(py_ue_fquat_get(self).Z); } -static int py_ue_fquat_set_z(ue_PyFQuat *self, PyObject *value, void *closure) -{ - if (value && PyNumber_Check(value)) - { +static int py_ue_fquat_set_z(ue_PyFQuat *self, PyObject *value, void *closure) { + if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->quat.Z = PyFloat_AsDouble(f_value); + py_ue_fquat_get(self).Z = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -120,17 +107,14 @@ static int py_ue_fquat_set_z(ue_PyFQuat *self, PyObject *value, void *closure) return -1; } -static PyObject *py_ue_fquat_get_w(ue_PyFQuat *self, void *closure) -{ - return PyFloat_FromDouble(self->quat.W); +static PyObject *py_ue_fquat_get_w(ue_PyFQuat *self, void *closure) { + return PyFloat_FromDouble(py_ue_fquat_get(self).W); } -static int py_ue_fquat_set_w(ue_PyFQuat *self, PyObject *value, void *closure) -{ - if (value && PyNumber_Check(value)) - { +static int py_ue_fquat_set_w(ue_PyFQuat *self, PyObject *value, void *closure) { + if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->quat.W = PyFloat_AsDouble(f_value); + py_ue_fquat_get(self).W = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -149,7 +133,7 @@ static PyGetSetDef ue_PyFQuat_getseters[] = { static PyObject *ue_PyFQuat_str(ue_PyFQuat *self) { return PyUnicode_FromFormat("", - PyFloat_FromDouble(self->quat.X), PyFloat_FromDouble(self->quat.Y), PyFloat_FromDouble(self->quat.Z), PyFloat_FromDouble(self->quat.W)); + PyFloat_FromDouble(py_ue_fquat_get(self).X), PyFloat_FromDouble(py_ue_fquat_get(self).Y), PyFloat_FromDouble(py_ue_fquat_get(self).Z), PyFloat_FromDouble(py_ue_fquat_get(self).W)); } static PyTypeObject ue_PyFQuatType = { @@ -190,43 +174,35 @@ static PyTypeObject ue_PyFQuatType = { }; -static PyObject *ue_py_fquat_add(ue_PyFQuat *self, PyObject *value) -{ - FQuat quat = self->quat; +static PyObject *ue_py_fquat_add(ue_PyFQuat *self, PyObject *value) { + FQuat quat = py_ue_fquat_get(self); ue_PyFQuat *py_quat = py_ue_is_fquat(value); - if (py_quat) - { - quat += py_quat->quat; + if (py_quat) { + quat += py_ue_fquat_get(py_quat); } return py_ue_new_fquat(quat); } -static PyObject *ue_py_fquat_sub(ue_PyFQuat *self, PyObject *value) -{ - FQuat quat = self->quat; +static PyObject *ue_py_fquat_sub(ue_PyFQuat *self, PyObject *value) { + FQuat quat = py_ue_fquat_get(self); ue_PyFQuat *py_quat = py_ue_is_fquat(value); - if (py_quat) - { - quat -= py_quat->quat; + if (py_quat) { + quat -= py_ue_fquat_get(py_quat); } return py_ue_new_fquat(quat); } -static PyObject *ue_py_fquat_mul(ue_PyFQuat *self, PyObject *value) -{ - if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) - { - FVector vec = self->quat * py_vec->vec; +static PyObject *ue_py_fquat_mul(ue_PyFQuat *self, PyObject *value) { + if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) { + FVector vec = py_ue_fquat_get(self) * py_ue_fvector_get(py_vec); return py_ue_new_fvector(vec); } - if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) - { - FQuat quat = self->quat * py_quat->quat; + if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { + FQuat quat = py_ue_fquat_get(self) * py_ue_fquat_get(py_quat); return py_ue_new_fquat(quat); } - else if (PyNumber_Check(value)) - { - FQuat quat = self->quat; + else if (PyNumber_Check(value)) { + FQuat quat = py_ue_fquat_get(self); PyObject *f_value = PyNumber_Float(value); float f = PyFloat_AsDouble(f_value); quat *= f; @@ -236,12 +212,10 @@ static PyObject *ue_py_fquat_mul(ue_PyFQuat *self, PyObject *value) return PyErr_Format(PyExc_TypeError, "unsupported argument type"); } -static PyObject *ue_py_fquat_div(ue_PyFQuat *self, PyObject *value) -{ - FQuat quat = self->quat; +static PyObject *ue_py_fquat_div(ue_PyFQuat *self, PyObject *value) { + FQuat quat = py_ue_fquat_get(self); - if (PyNumber_Check(value)) - { + if (PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); float f = PyFloat_AsDouble(f_value); if (f == 0) @@ -256,45 +230,42 @@ static PyObject *ue_py_fquat_div(ue_PyFQuat *self, PyObject *value) PyNumberMethods ue_PyFQuat_number_methods; -static Py_ssize_t ue_py_fquat_seq_length(ue_PyFQuat *self) -{ +static Py_ssize_t ue_py_fquat_seq_length(ue_PyFQuat *self) { return 4; } -static PyObject *ue_py_fquat_seq_item(ue_PyFQuat *self, Py_ssize_t i) -{ - switch (i) - { +static PyObject *ue_py_fquat_seq_item(ue_PyFQuat *self, Py_ssize_t i) { + switch (i) { case 0: - return PyFloat_FromDouble(self->quat.X); + return PyFloat_FromDouble(py_ue_fquat_get(self).X); case 1: - return PyFloat_FromDouble(self->quat.Y); + return PyFloat_FromDouble(py_ue_fquat_get(self).Y); case 2: - return PyFloat_FromDouble(self->quat.Z); + return PyFloat_FromDouble(py_ue_fquat_get(self).Z); case 3: - return PyFloat_FromDouble(self->quat.W); + return PyFloat_FromDouble(py_ue_fquat_get(self).W); } return PyErr_Format(PyExc_IndexError, "FQuat has only 4 items"); } PySequenceMethods ue_PyFQuat_sequence_methods; -static int ue_py_fquat_init(ue_PyFQuat *self, PyObject *args, PyObject *kwargs) -{ +static int ue_py_fquat_init(ue_PyFQuat *self, PyObject *args, PyObject *kwargs) { float x = 0, y = 0, z = 0, w = 1; if (!PyArg_ParseTuple(args, "|ffff", &x, &y, &z, &w)) return -1; - self->quat.X = x; - self->quat.Y = y; - self->quat.Z = z; - self->quat.W = w; + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); + + py_ue_fquat_get(self).X = x; + py_ue_fquat_get(self).Y = y; + py_ue_fquat_get(self).Z = z; + py_ue_fquat_get(self).W = w; return 0; } -void ue_python_init_fquat(PyObject *ue_module) -{ +void ue_python_init_fquat(PyObject *ue_module) { ue_PyFQuatType.tp_new = PyType_GenericNew; ue_PyFQuatType.tp_init = (initproc)ue_py_fquat_init; @@ -311,6 +282,8 @@ void ue_python_init_fquat(PyObject *ue_module) ue_PyFQuat_sequence_methods.sq_length = (lenfunc)ue_py_fquat_seq_length; ue_PyFQuat_sequence_methods.sq_item = (ssizeargfunc)ue_py_fquat_seq_item; + ue_PyFQuatType.tp_base = &ue_PyUScriptStructType; + if (PyType_Ready(&ue_PyFQuatType) < 0) return; @@ -318,33 +291,37 @@ void ue_python_init_fquat(PyObject *ue_module) PyModule_AddObject(ue_module, "FQuat", (PyObject *)&ue_PyFQuatType); } -PyObject *py_ue_new_fquat(FQuat quat) + +PyObject *py_ue_new_fquat(const FQuat& quat) { ue_PyFQuat *ret = (ue_PyFQuat *)PyObject_New(ue_PyFQuat, &ue_PyFQuatType); - ret->quat = quat; + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8 const*)&quat, false); return (PyObject *)ret; } -ue_PyFQuat *py_ue_is_fquat(PyObject *obj) +PyObject * py_ue_new_fquat_ptr(FQuat* quat_ptr) { + ue_PyFQuat *ret = (ue_PyFQuat *)PyObject_New(ue_PyFQuat, &ue_PyFQuatType); + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8*)quat_ptr, true); + return (PyObject *)ret; +} + +ue_PyFQuat *py_ue_is_fquat(PyObject *obj) { if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFQuatType)) return nullptr; return (ue_PyFQuat *)obj; } -bool py_ue_quat_arg(PyObject *args, FQuat &quat) -{ +bool py_ue_quat_arg(PyObject *args, FQuat &quat) { - if (PyTuple_Size(args) == 1) - { + if (PyTuple_Size(args) == 1) { PyObject *arg = PyTuple_GetItem(args, 0); ue_PyFQuat *py_quat = py_ue_is_fquat(arg); - if (!py_quat) - { + if (!py_quat) { PyErr_Format(PyExc_TypeError, "argument is not a FQuat"); return false; } - quat = py_quat->quat; + quat = py_ue_fquat_get(py_quat); return true; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h index 1a39ce0a8..479f572aa 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h @@ -1,19 +1,23 @@ #pragma once -#include "UEPyModule.h" - +#include "UEPyUScriptStruct.h" #include "Runtime/Core/Public/Math/Quat.h" -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - FQuat quat; +extern PyTypeObject ue_PyUScriptStructType; + +typedef struct { + ue_PyUScriptStruct py_base; } ue_PyFQuat; -PyObject *py_ue_new_fquat(FQuat); +PyObject *py_ue_new_fquat(const FQuat&); +PyObject *py_ue_new_fquat_ptr(FQuat*); ue_PyFQuat *py_ue_is_fquat(PyObject *); +inline static FQuat& py_ue_fquat_get(ue_PyFQuat *self) +{ + return *((FQuat*)py_ue_uscriptstruct_get_data((ue_PyUScriptStruct *)self)); +} + void ue_python_init_fquat(PyObject *); bool py_ue_quat_arg(PyObject *, FQuat &); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp index d315dd2f0..0514c5c52 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp @@ -83,7 +83,7 @@ static PyObject *py_ue_frandomstream_vrand_cone(ue_PyFRandomStream *self, PyObje return PyErr_Format(PyExc_TypeError, "argument is not a FVector"); if (vertical < 0) vertical = horizontal; - return py_ue_new_fvector(self->rstream.VRandCone(py_vec->vec, horizontal, vertical)); + return py_ue_new_fvector(self->rstream.VRandCone(py_ue_fvector_get(py_vec), horizontal, vertical)); } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp index af69b254c..daf21dfc4 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp @@ -53,7 +53,7 @@ static int py_ue_fraw_anim_sequence_track_set_pos_keys(ue_PyFRawAnimSequenceTrac failed = true; break; } - pos.Add(py_vec->vec); + pos.Add(py_ue_fvector_get(py_vec)); } Py_DECREF(py_iter); if (!failed) @@ -84,7 +84,7 @@ static int py_ue_fraw_anim_sequence_track_set_scale_keys(ue_PyFRawAnimSequenceTr failed = true; break; } - scale.Add(py_vec->vec); + scale.Add(py_ue_fvector_get(py_vec)); } Py_DECREF(py_iter); if (!failed) @@ -115,7 +115,7 @@ static int py_ue_fraw_anim_sequence_track_set_rot_keys(ue_PyFRawAnimSequenceTrac failed = true; break; } - rot.Add(py_quat->quat); + rot.Add(py_ue_fquat_get(py_quat)); } Py_DECREF(py_iter); if (!failed) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp index d6f8f24d2..2fe99c105 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp @@ -28,7 +28,7 @@ static PyObject *py_ue_fraw_mesh_set_vertex_positions(ue_PyFRawMesh *self, PyObj if (ue_PyFVector *py_fvector = py_ue_is_fvector(item_x)) { - vertex.Add(py_fvector->vec); + vertex.Add(py_ue_fvector_get(py_fvector)); } else { @@ -263,7 +263,7 @@ static PyObject *py_ue_fraw_mesh_set_wedge_tangent_x(ue_PyFRawMesh *self, PyObje break; if (ue_PyFVector *py_fvector = py_ue_is_fvector(item_x)) { - vertex.Add(py_fvector->vec); + vertex.Add(py_ue_fvector_get(py_fvector)); } else { @@ -324,7 +324,7 @@ static PyObject *py_ue_fraw_mesh_set_wedge_tangent_y(ue_PyFRawMesh *self, PyObje break; if (ue_PyFVector *py_fvector = py_ue_is_fvector(item_x)) { - vertex.Add(py_fvector->vec); + vertex.Add(py_ue_fvector_get(py_fvector)); } else { @@ -386,7 +386,7 @@ static PyObject *py_ue_fraw_mesh_set_wedge_tangent_z(ue_PyFRawMesh *self, PyObje if (ue_PyFVector *py_fvector = py_ue_is_fvector(item_x)) { - vertex.Add(py_fvector->vec); + vertex.Add(py_ue_fvector_get(py_fvector)); } else { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index 45d4c2369..1a5de2e26 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -1,27 +1,29 @@ #include "UEPyFRotator.h" +#include "Quat.h" +#include "UEPyFQuat.h" static PyObject *py_ue_frotator_get_vector(ue_PyFRotator *self, PyObject * args) { - FVector vec = self->rot.Vector(); + FVector vec = py_ue_frotator_get(self).Vector(); return py_ue_new_fvector(vec); } static PyObject *py_ue_frotator_get_euler(ue_PyFRotator *self, PyObject * args) { - FVector vec = self->rot.Euler(); + FVector vec = py_ue_frotator_get(self).Euler(); return py_ue_new_fvector(vec); } static PyObject *py_ue_frotator_inversed(ue_PyFRotator *self, PyObject * args) { - FRotator rot = self->rot.GetInverse(); + FRotator rot = py_ue_frotator_get(self).GetInverse(); return py_ue_new_frotator(rot); } static PyObject *py_ue_frotator_normalized(ue_PyFRotator *self, PyObject * args) { - FRotator rot = self->rot.GetNormalized(); + FRotator rot = py_ue_frotator_get(self).GetNormalized(); return py_ue_new_frotator(rot); } static PyObject *py_ue_frotator_quaternion(ue_PyFRotator *self, PyObject * args) { - FQuat quat = self->rot.Quaternion(); + FQuat quat = py_ue_frotator_get(self).Quaternion(); return py_ue_new_fquat(quat); } @@ -35,13 +37,13 @@ static PyMethodDef ue_PyFRotator_methods[] = { }; static PyObject *py_ue_frotator_get_pitch(ue_PyFRotator *self, void *closure) { - return PyFloat_FromDouble(self->rot.Pitch); + return PyFloat_FromDouble(py_ue_frotator_get(self).Pitch); } static int py_ue_frotator_set_pitch(ue_PyFRotator *self, PyObject *value, void *closure) { if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->rot.Pitch = PyFloat_AsDouble(f_value); + py_ue_frotator_get(self).Pitch = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -50,13 +52,13 @@ static int py_ue_frotator_set_pitch(ue_PyFRotator *self, PyObject *value, void * } static PyObject *py_ue_frotator_get_yaw(ue_PyFRotator *self, void *closure) { - return PyFloat_FromDouble(self->rot.Yaw); + return PyFloat_FromDouble(py_ue_frotator_get(self).Yaw); } static int py_ue_frotator_set_yaw(ue_PyFRotator *self, PyObject *value, void *closure) { if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->rot.Yaw = PyFloat_AsDouble(f_value); + py_ue_frotator_get(self).Yaw = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -65,13 +67,13 @@ static int py_ue_frotator_set_yaw(ue_PyFRotator *self, PyObject *value, void *cl } static PyObject *py_ue_frotator_get_roll(ue_PyFRotator *self, void *closure) { - return PyFloat_FromDouble(self->rot.Roll); + return PyFloat_FromDouble(py_ue_frotator_get(self).Roll); } static int py_ue_frotator_set_roll(ue_PyFRotator *self, PyObject *value, void *closure) { if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->rot.Roll = PyFloat_AsDouble(f_value); + py_ue_frotator_get(self).Roll = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -90,7 +92,7 @@ static PyGetSetDef ue_PyFRotator_getseters[] = { static PyObject *ue_PyFRotator_str(ue_PyFRotator *self) { return PyUnicode_FromFormat("", - PyFloat_FromDouble(self->rot.Roll), PyFloat_FromDouble(self->rot.Pitch), PyFloat_FromDouble(self->rot.Yaw)); + PyFloat_FromDouble(py_ue_frotator_get(self).Roll), PyFloat_FromDouble(py_ue_frotator_get(self).Pitch), PyFloat_FromDouble(py_ue_frotator_get(self).Yaw)); } static PyTypeObject ue_PyFRotatorType = { @@ -132,10 +134,10 @@ static PyTypeObject ue_PyFRotatorType = { static PyObject *ue_py_frotator_add(ue_PyFRotator *self, PyObject *value) { - FRotator rot = self->rot; + FRotator rot = py_ue_frotator_get(self); ue_PyFRotator *py_rot = py_ue_is_frotator(value); if (py_rot) { - rot += py_rot->rot; + rot += py_ue_frotator_get(py_rot); } else if (PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); @@ -149,10 +151,10 @@ static PyObject *ue_py_frotator_add(ue_PyFRotator *self, PyObject *value) { } static PyObject *ue_py_frotator_sub(ue_PyFRotator *self, PyObject *value) { - FRotator rot = self->rot; + FRotator rot = py_ue_frotator_get(self); ue_PyFRotator *py_rot = py_ue_is_frotator(value); if (py_rot) { - rot -= py_rot->rot; + rot -= py_ue_frotator_get(py_rot); } else if (PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); @@ -168,11 +170,11 @@ static PyObject *ue_py_frotator_sub(ue_PyFRotator *self, PyObject *value) { static PyObject *ue_py_frotator_mul(ue_PyFRotator *self, PyObject *value) { ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - FVector vec = self->rot.RotateVector(py_vec->vec); + FVector vec = py_ue_frotator_get(self).RotateVector(py_ue_fvector_get(py_vec)); return py_ue_new_fvector(vec); } else if (PyNumber_Check(value)) { - FRotator rot = self->rot; + FRotator rot = py_ue_frotator_get(self); PyObject *f_value = PyNumber_Float(value); float f = PyFloat_AsDouble(f_value); rot.Pitch *= f; @@ -185,7 +187,7 @@ static PyObject *ue_py_frotator_mul(ue_PyFRotator *self, PyObject *value) { } static PyObject *ue_py_frotator_div(ue_PyFRotator *self, PyObject *value) { - FRotator rot = self->rot; + FRotator rot = py_ue_frotator_get(self); if (PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); @@ -211,11 +213,11 @@ static Py_ssize_t ue_py_frotator_seq_length(ue_PyFRotator *self) { static PyObject *ue_py_frotator_seq_item(ue_PyFRotator *self, Py_ssize_t i) { switch (i) { case 0: - return PyFloat_FromDouble(self->rot.Roll); + return PyFloat_FromDouble(py_ue_frotator_get(self).Roll); case 1: - return PyFloat_FromDouble(self->rot.Pitch); + return PyFloat_FromDouble(py_ue_frotator_get(self).Pitch); case 2: - return PyFloat_FromDouble(self->rot.Yaw); + return PyFloat_FromDouble(py_ue_frotator_get(self).Yaw); } return PyErr_Format(PyExc_IndexError, "FRotator has only 3 items"); } @@ -223,28 +225,37 @@ static PyObject *ue_py_frotator_seq_item(ue_PyFRotator *self, Py_ssize_t i) { PySequenceMethods ue_PyFRotator_sequence_methods; static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kwargs) { - float pitch = 0, yaw = 0, roll = 0; - - if (PyTuple_Size(args) == 1) { - if (ue_PyFQuat *py_quat = py_ue_is_fquat(PyTuple_GetItem(args, 0))) { - self->rot = FRotator(py_quat->quat); - return 0; - } - } - - if (!PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) - return -1; + float pitch = 0, yaw = 0, roll = 0; - if (PyTuple_Size(args) == 1) { - yaw = pitch; - roll = pitch; - } + if (PyTuple_Size(args) == 3 && PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) + { + } + else if (PyTuple_Size(args) == 1 && PyArg_ParseTuple(args, "|f", &roll)) + { + pitch = roll; + yaw = roll; + } + else if (ue_PyFQuat *py_quat = PyTuple_Size(args) == 1 ? py_ue_is_fquat(PyTuple_GetItem(args, 0)) : nullptr) + { + FRotator rot_from_quat = FRotator(py_ue_fquat_get(py_quat)); + roll = rot_from_quat.Roll; + pitch = rot_from_quat.Pitch; + yaw = rot_from_quat.Yaw; + } + else if (PyTuple_Size(args) == 0) + { + } + else + { + return -1; + } - self->rot.Pitch = pitch; - self->rot.Yaw = yaw; - self->rot.Roll = roll; + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); + py_ue_frotator_get(self).Pitch = pitch; + py_ue_frotator_get(self).Yaw = yaw; + py_ue_frotator_get(self).Roll = roll; - return 0; + return 0; } void ue_python_init_frotator(PyObject *ue_module) { @@ -263,6 +274,8 @@ void ue_python_init_frotator(PyObject *ue_module) { ue_PyFRotatorType.tp_as_sequence = &ue_PyFRotator_sequence_methods; ue_PyFRotator_sequence_methods.sq_length = (lenfunc)ue_py_frotator_seq_length; ue_PyFRotator_sequence_methods.sq_item = (ssizeargfunc)ue_py_frotator_seq_item; + + ue_PyFRotatorType.tp_base = &ue_PyUScriptStructType; if (PyType_Ready(&ue_PyFRotatorType) < 0) return; @@ -271,12 +284,21 @@ void ue_python_init_frotator(PyObject *ue_module) { PyModule_AddObject(ue_module, "FRotator", (PyObject *)&ue_PyFRotatorType); } -PyObject *py_ue_new_frotator(FRotator rot) { +PyObject *py_ue_new_frotator(const FRotator& rot) +{ ue_PyFRotator *ret = (ue_PyFRotator *)PyObject_New(ue_PyFRotator, &ue_PyFRotatorType); - ret->rot = rot; + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8 const*)&rot, false); return (PyObject *)ret; } + +PyObject *py_ue_new_frotator_ptr(FRotator* rot_ptr) +{ + ue_PyFRotator *ret = (ue_PyFRotator *)PyObject_New(ue_PyFRotator, &ue_PyFRotatorType); + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8*)rot_ptr, true); + return (PyObject *)ret; +} + ue_PyFRotator *py_ue_is_frotator(PyObject *obj) { if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFRotatorType)) return nullptr; @@ -292,7 +314,7 @@ bool py_ue_rotator_arg(PyObject *args, FRotator &rot) { PyErr_Format(PyExc_TypeError, "argument is not a FRotator"); return false; } - rot = py_rot->rot; + rot = py_ue_frotator_get(py_rot); return true; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h index a4ea71a84..c0f513e65 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h @@ -1,18 +1,23 @@ #pragma once -#include "UnrealEnginePython.h" +#include "UEPyUScriptStruct.h" #include "UEPyFVector.h" -#include "UEPyFQuat.h" + +extern PyTypeObject ue_PyUScriptStructType; typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - FRotator rot; + ue_PyUScriptStruct py_base; } ue_PyFRotator; -PyObject *py_ue_new_frotator(FRotator); +PyObject *py_ue_new_frotator(const FRotator&); +PyObject *py_ue_new_frotator_ptr(FRotator*); ue_PyFRotator *py_ue_is_frotator(PyObject *); +inline static FRotator& py_ue_frotator_get(ue_PyFRotator *self) +{ + return *((FRotator*)py_ue_uscriptstruct_get_data((ue_PyUScriptStruct *)self)); +} + void ue_python_init_frotator(PyObject *); bool py_ue_rotator_arg(PyObject *, FRotator &); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp index 64e168222..79db74bc7 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp @@ -29,7 +29,7 @@ static int py_ue_fsoft_skin_vertex_set_position(ue_PyFSoftSkinVertex *self, PyOb ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->ss_vertex.Position = py_vec->vec; + self->ss_vertex.Position = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); @@ -46,7 +46,7 @@ static int py_ue_fsoft_skin_vertex_set_tangent_x(ue_PyFSoftSkinVertex *self, PyO ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->ss_vertex.TangentX = py_vec->vec; + self->ss_vertex.TangentX = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); @@ -63,7 +63,7 @@ static int py_ue_fsoft_skin_vertex_set_tangent_y(ue_PyFSoftSkinVertex *self, PyO ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->ss_vertex.TangentY = py_vec->vec; + self->ss_vertex.TangentY = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); @@ -80,7 +80,7 @@ static int py_ue_fsoft_skin_vertex_set_tangent_z(ue_PyFSoftSkinVertex *self, PyO ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - self->ss_vertex.TangentZ = py_vec->vec; + self->ss_vertex.TangentZ = py_ue_fvector_get(py_vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a FVector"); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 3e8f0251c..40002f007 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -1,13 +1,19 @@ #include "UEPyFTransform.h" +#include "UEPyFVector.h" +#include "UEPyFRotator.h" +#include "UEPyFQuat.h" +#include "Class.h" +#include "UObjectGlobals.h" +#include "Package.h" static PyObject *py_ue_ftransform_inverse(ue_PyFTransform *self, PyObject * args) { - return py_ue_new_ftransform(self->transform.Inverse()); + return py_ue_new_ftransform(py_ue_ftransform_get(self).Inverse()); } static PyObject *py_ue_ftransform_normalize_rotation(ue_PyFTransform *self, PyObject * args) { - FTransform transform = self->transform; + FTransform transform = py_ue_ftransform_get(self); transform.NormalizeRotation(); return py_ue_new_ftransform(transform); } @@ -23,12 +29,13 @@ static PyObject *py_ue_ftransform_get_relative_transform(ue_PyFTransform *self, ue_PyFTransform *py_transform = py_ue_is_ftransform(py_obj); if (!py_transform) return PyErr_Format(PyExc_Exception, "argument is not a FTransform"); - return py_ue_new_ftransform(self->transform.GetRelativeTransform(py_transform->transform)); + + return py_ue_new_ftransform(py_ue_ftransform_get(self).GetRelativeTransform(py_ue_ftransform_get(py_transform))); } static PyObject *py_ue_ftransform_get_matrix(ue_PyFTransform *self, PyObject * args) { - FTransform transform = self->transform; + FTransform transform = py_ue_ftransform_get(self); transform.NormalizeRotation(); FMatrix matrix = transform.ToMatrixWithScale(); UScriptStruct *u_struct = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR("Matrix")); @@ -49,29 +56,29 @@ static PyMethodDef ue_PyFTransform_methods[] = { static PyObject *py_ue_ftransform_get_translation(ue_PyFTransform *self, void *closure) { - return py_ue_new_fvector(self->transform.GetTranslation()); + return py_ue_new_fvector(py_ue_ftransform_get(self).GetTranslation()); } static PyObject *py_ue_ftransform_get_scale(ue_PyFTransform *self, void *closure) { - return py_ue_new_fvector(self->transform.GetScale3D()); + return py_ue_new_fvector(py_ue_ftransform_get(self).GetScale3D()); } static PyObject *py_ue_ftransform_get_rotation(ue_PyFTransform *self, void *closure) { - return py_ue_new_frotator(self->transform.GetRotation().Rotator()); + return py_ue_new_frotator(py_ue_ftransform_get(self).GetRotation().Rotator()); } static PyObject *py_ue_ftransform_get_quaternion(ue_PyFTransform *self, void *closure) { - return py_ue_new_fquat(self->transform.GetRotation()); + return py_ue_new_fquat(py_ue_ftransform_get(self).GetRotation()); } static int py_ue_ftransform_set_translation(ue_PyFTransform *self, PyObject *value, void *closure) { if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) { - self->transform.SetLocation(py_vec->vec); + py_ue_ftransform_get(self).SetLocation(py_ue_fvector_get(py_vec)); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a vector"); @@ -82,7 +89,7 @@ static int py_ue_ftransform_set_rotation(ue_PyFTransform *self, PyObject *value, { if (ue_PyFRotator *py_rot = py_ue_is_frotator(value)) { - self->transform.SetRotation(py_rot->rot.Quaternion()); + py_ue_ftransform_get(self).SetRotation(py_ue_frotator_get(py_rot).Quaternion()); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a rotator"); @@ -93,7 +100,7 @@ static int py_ue_ftransform_set_quaternion(ue_PyFTransform *self, PyObject *valu { if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { - self->transform.SetRotation(py_quat->quat); + py_ue_ftransform_get(self).SetRotation(py_ue_fquat_get(py_quat)); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a quaternion"); @@ -104,7 +111,7 @@ static int py_ue_ftransform_set_scale(ue_PyFTransform *self, PyObject *value, vo { if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) { - self->transform.SetScale3D(py_vec->vec); + py_ue_ftransform_get(self).SetScale3D(py_ue_fvector_get(py_vec)); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a vector"); @@ -123,9 +130,9 @@ static PyGetSetDef ue_PyFTransform_getseters[] = { static PyObject *ue_PyFTransform_str(ue_PyFTransform *self) { - FVector vec = self->transform.GetTranslation(); - FRotator rot = self->transform.Rotator(); - FVector scale = self->transform.GetScale3D(); + FVector vec = py_ue_ftransform_get(self).GetTranslation(); + FRotator rot = py_ue_ftransform_get(self).Rotator(); + FVector scale = py_ue_ftransform_get(self).GetScale3D(); return PyUnicode_FromFormat("", PyFloat_FromDouble(vec.X), @@ -184,11 +191,13 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject return -1; } + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); + if (py_translation) { if (ue_PyFVector *py_vec = py_ue_is_fvector(py_translation)) { - self->transform.SetTranslation(py_vec->vec); + py_ue_ftransform_get(self).SetTranslation(py_ue_fvector_get(py_vec)); } else { @@ -226,7 +235,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject Py_DECREF(py_num); } } - self->transform.SetFromMatrix(matrix); + py_ue_ftransform_get(self).SetFromMatrix(matrix); Py_DECREF(py_iter); return 0; } @@ -239,11 +248,11 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject { if (ue_PyFRotator *py_rot = py_ue_is_frotator(py_rotation)) { - self->transform.SetRotation(py_rot->rot.Quaternion()); + py_ue_ftransform_get(self).SetRotation(py_ue_frotator_get(py_rot).Quaternion()); } else if (ue_PyFQuat *py_quat = py_ue_is_fquat(py_rotation)) { - self->transform.SetRotation(py_quat->quat); + py_ue_ftransform_get(self).SetRotation(py_ue_fquat_get(py_quat)); } else { @@ -253,7 +262,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject } else { - self->transform.SetRotation(FQuat::Identity); + py_ue_ftransform_get(self).SetRotation(FQuat::Identity); } // ensure scaling is set to 1,1,1 @@ -263,7 +272,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject { if (ue_PyFVector *py_vec = py_ue_is_fvector(py_scale)) { - scale = py_vec->vec; + scale = py_ue_fvector_get(py_vec); } else { @@ -271,24 +280,24 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject return -1; } } - self->transform.SetScale3D(scale); + py_ue_ftransform_get(self).SetScale3D(scale); return 0; } static PyObject *ue_py_ftransform_mul(ue_PyFTransform *self, PyObject *value) { - FTransform t = self->transform; + FTransform t = py_ue_ftransform_get(self); if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { - t *= py_quat->quat; + t *= py_ue_fquat_get(py_quat); } else if (ue_PyFRotator *py_rot = py_ue_is_frotator(value)) { - t *= py_rot->rot.Quaternion(); + t *= py_ue_frotator_get(py_rot).Quaternion(); } else if (ue_PyFTransform *py_transform = py_ue_is_ftransform(value)) { - t *= py_transform->transform; + t *= py_ue_ftransform_get(py_transform); } else { @@ -309,6 +318,8 @@ void ue_python_init_ftransform(PyObject *ue_module) ue_PyFTransformType.tp_as_number = &ue_PyFTransform_number_methods; ue_PyFTransform_number_methods.nb_multiply = (binaryfunc)ue_py_ftransform_mul; + ue_PyFTransformType.tp_base = &ue_PyUScriptStructType; + if (PyType_Ready(&ue_PyFTransformType) < 0) return; @@ -316,10 +327,21 @@ void ue_python_init_ftransform(PyObject *ue_module) PyModule_AddObject(ue_module, "FTransform", (PyObject *)&ue_PyFTransformType); } -PyObject *py_ue_new_ftransform(FTransform transform) +PyObject *py_ue_new_ftransform(const FTransform& transform) +{ + ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); + + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8 const*)&transform, false); + + return (PyObject *)ret; +} + +PyObject* py_ue_new_ftransform_ptr(FTransform* transform_ptr) { ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); - ret->transform = transform; + + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8*)transform_ptr, true); + return (PyObject *)ret; } @@ -342,7 +364,7 @@ bool py_ue_transform_arg(PyObject *args, FTransform &t) PyErr_Format(PyExc_TypeError, "argument is not a FTransform"); return false; } - t = py_t->transform; + t = py_ue_ftransform_get(py_t); return true; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h index 3cb64312f..9313eeb22 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h @@ -2,16 +2,22 @@ -#include "UEPyModule.h" +#include "UEPyUScriptStruct.h" + +extern PyTypeObject ue_PyUScriptStructType; typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - FTransform transform; + ue_PyUScriptStruct py_base; } ue_PyFTransform; -PyObject *py_ue_new_ftransform(FTransform); +PyObject *py_ue_new_ftransform(const FTransform&); +PyObject *py_ue_new_ftransform_ptr(FTransform*); ue_PyFTransform *py_ue_is_ftransform(PyObject *); +inline static FTransform& py_ue_ftransform_get(ue_PyFTransform *self) +{ + return *((FTransform*)py_ue_uscriptstruct_get_data((ue_PyUScriptStruct *)self)); +} + void ue_python_init_ftransform(PyObject *); bool py_ue_transform_arg(PyObject *, FTransform &); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index 3380d82df..57d3a9454 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -1,25 +1,27 @@ #include "UEPyFVector.h" +#include "UEPyFRotator.h" +#include "UEPyFQuat.h" static PyObject *py_ue_fvector_length(ue_PyFVector *self, PyObject * args) { - return PyFloat_FromDouble(self->vec.Size()); + return PyFloat_FromDouble(py_ue_fvector_get(self).Size()); } static PyObject *py_ue_fvector_length_squared(ue_PyFVector *self, PyObject * args) { - return PyFloat_FromDouble(self->vec.SizeSquared()); + return PyFloat_FromDouble(py_ue_fvector_get(self).SizeSquared()); } static PyObject *py_ue_fvector_normalized(ue_PyFVector *self, PyObject * args) { - FVector vec = self->vec; + FVector vec = py_ue_fvector_get(self); vec.Normalize(); return py_ue_new_fvector(vec); } static PyObject *py_ue_fvector_rotation(ue_PyFVector *self, PyObject * args) { - FRotator rot = self->vec.Rotation(); + FRotator rot = py_ue_fvector_get(self).Rotation(); return py_ue_new_frotator(rot); } @@ -31,7 +33,7 @@ static PyObject *py_ue_fvector_dot(ue_PyFVector *self, PyObject * args) ue_PyFVector *py_vec = py_ue_is_fvector(py_obj); if (!py_vec) return PyErr_Format(PyExc_TypeError, "argument is not a FVector"); - return PyFloat_FromDouble(FVector::DotProduct(self->vec, py_vec->vec)); + return PyFloat_FromDouble(FVector::DotProduct(py_ue_fvector_get(self), py_ue_fvector_get(py_vec))); } static PyObject *py_ue_fvector_cross(ue_PyFVector *self, PyObject * args) @@ -42,7 +44,7 @@ static PyObject *py_ue_fvector_cross(ue_PyFVector *self, PyObject * args) ue_PyFVector *py_vec = py_ue_is_fvector(py_obj); if (!py_vec) return PyErr_Format(PyExc_TypeError, "argument is not a FVector"); - return py_ue_new_fvector(FVector::CrossProduct(self->vec, py_vec->vec)); + return py_ue_new_fvector(FVector::CrossProduct(py_ue_fvector_get(self), py_ue_fvector_get(py_vec))); } static PyObject *py_ue_fvector_project_on_to(ue_PyFVector *self, PyObject * args) @@ -53,7 +55,7 @@ static PyObject *py_ue_fvector_project_on_to(ue_PyFVector *self, PyObject * args ue_PyFVector *py_vec = py_ue_is_fvector(py_obj); if (!py_vec) return PyErr_Format(PyExc_TypeError, "argument is not a FVector"); - return py_ue_new_fvector(self->vec.ProjectOnTo(py_vec->vec)); + return py_ue_new_fvector(py_ue_fvector_get(self).ProjectOnTo(py_ue_fvector_get(py_vec))); } static PyObject *py_ue_fvector_project_on_to_normal(ue_PyFVector *self, PyObject * args) @@ -64,7 +66,7 @@ static PyObject *py_ue_fvector_project_on_to_normal(ue_PyFVector *self, PyObject ue_PyFVector *py_vec = py_ue_is_fvector(py_obj); if (!py_vec) return PyErr_Format(PyExc_TypeError, "argument is not a FVector"); - return py_ue_new_fvector(self->vec.ProjectOnToNormal(py_vec->vec)); + return py_ue_new_fvector(py_ue_fvector_get(self).ProjectOnToNormal(py_ue_fvector_get(py_vec))); } @@ -85,7 +87,7 @@ static PyMethodDef ue_PyFVector_methods[] = { static PyObject *py_ue_fvector_get_x(ue_PyFVector *self, void *closure) { - return PyFloat_FromDouble(self->vec.X); + return PyFloat_FromDouble(py_ue_fvector_get(self).X); } static int py_ue_fvector_set_x(ue_PyFVector *self, PyObject *value, void *closure) @@ -93,7 +95,7 @@ static int py_ue_fvector_set_x(ue_PyFVector *self, PyObject *value, void *closur if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->vec.X = PyFloat_AsDouble(f_value); + py_ue_fvector_get(self).X = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -103,7 +105,7 @@ static int py_ue_fvector_set_x(ue_PyFVector *self, PyObject *value, void *closur static PyObject *py_ue_fvector_get_y(ue_PyFVector *self, void *closure) { - return PyFloat_FromDouble(self->vec.Y); + return PyFloat_FromDouble(py_ue_fvector_get(self).Y); } static int py_ue_fvector_set_y(ue_PyFVector *self, PyObject *value, void *closure) @@ -111,7 +113,7 @@ static int py_ue_fvector_set_y(ue_PyFVector *self, PyObject *value, void *closur if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->vec.Y = PyFloat_AsDouble(f_value); + py_ue_fvector_get(self).Y = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -121,7 +123,7 @@ static int py_ue_fvector_set_y(ue_PyFVector *self, PyObject *value, void *closur static PyObject *py_ue_fvector_get_z(ue_PyFVector *self, void *closure) { - return PyFloat_FromDouble(self->vec.Z); + return PyFloat_FromDouble(py_ue_fvector_get(self).Z); } static int py_ue_fvector_set_z(ue_PyFVector *self, PyObject *value, void *closure) @@ -129,7 +131,7 @@ static int py_ue_fvector_set_z(ue_PyFVector *self, PyObject *value, void *closur if (value && PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); - self->vec.Z = PyFloat_AsDouble(f_value); + py_ue_fvector_get(self).Z = PyFloat_AsDouble(f_value); Py_DECREF(f_value); return 0; } @@ -148,7 +150,7 @@ static PyGetSetDef ue_PyFVector_getseters[] = { static PyObject *ue_PyFVector_str(ue_PyFVector *self) { return PyUnicode_FromFormat("", - PyFloat_FromDouble(self->vec.X), PyFloat_FromDouble(self->vec.Y), PyFloat_FromDouble(self->vec.Z)); + PyFloat_FromDouble(py_ue_fvector_get(self).X), PyFloat_FromDouble(py_ue_fvector_get(self).Y), PyFloat_FromDouble(py_ue_fvector_get(self).Z)); } static PyTypeObject ue_PyFVectorType = { @@ -191,11 +193,11 @@ static PyTypeObject ue_PyFVectorType = { static PyObject *ue_py_fvector_add(ue_PyFVector *self, PyObject *value) { - FVector vec = self->vec; + FVector vec = py_ue_fvector_get(self); ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - vec += py_vec->vec; + vec += py_ue_fvector_get(py_vec); } else if (PyNumber_Check(value)) { @@ -211,11 +213,11 @@ static PyObject *ue_py_fvector_add(ue_PyFVector *self, PyObject *value) static PyObject *ue_py_fvector_sub(ue_PyFVector *self, PyObject *value) { - FVector vec = self->vec; + FVector vec = py_ue_fvector_get(self); ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - vec -= py_vec->vec; + vec -= py_ue_fvector_get(py_vec); } else if (PyNumber_Check(value)) { @@ -231,19 +233,19 @@ static PyObject *ue_py_fvector_sub(ue_PyFVector *self, PyObject *value) static PyObject *ue_py_fvector_mul(ue_PyFVector *self, PyObject *value) { - FVector vec = self->vec; + FVector vec = py_ue_fvector_get(self); ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - vec *= py_vec->vec; + vec *= py_ue_fvector_get(py_vec); } else if (ue_PyFRotator *py_rot = py_ue_is_frotator(value)) { - return py_ue_new_fvector(py_rot->rot.RotateVector(vec)); + return py_ue_new_fvector(py_ue_frotator_get(py_rot).RotateVector(vec)); } else if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { - return py_ue_new_fvector(py_quat->quat.RotateVector(vec)); + return py_ue_new_fvector(py_ue_fquat_get(py_quat).RotateVector(vec)); } else if (PyNumber_Check(value)) { @@ -257,13 +259,13 @@ static PyObject *ue_py_fvector_mul(ue_PyFVector *self, PyObject *value) static PyObject *ue_py_fvector_div(ue_PyFVector *self, PyObject *value) { - FVector vec = self->vec; + FVector vec = py_ue_fvector_get(self); ue_PyFVector *py_vec = py_ue_is_fvector(value); if (py_vec) { - if (py_vec->vec.X == 0 || py_vec->vec.Y == 0 || py_vec->vec.Z == 0) + if (py_ue_fvector_get(py_vec).X == 0 || py_ue_fvector_get(py_vec).Y == 0 || py_ue_fvector_get(py_vec).Z == 0) return PyErr_Format(PyExc_ZeroDivisionError, "division by zero"); - vec /= py_vec->vec; + vec /= py_ue_fvector_get(py_vec); } else if (PyNumber_Check(value)) { @@ -289,11 +291,11 @@ static PyObject *ue_py_fvector_seq_item(ue_PyFVector *self, Py_ssize_t i) switch (i) { case 0: - return PyFloat_FromDouble(self->vec.X); + return PyFloat_FromDouble(py_ue_fvector_get(self).X); case 1: - return PyFloat_FromDouble(self->vec.Y); + return PyFloat_FromDouble(py_ue_fvector_get(self).Y); case 2: - return PyFloat_FromDouble(self->vec.Z); + return PyFloat_FromDouble(py_ue_fvector_get(self).Z); } return PyErr_Format(PyExc_IndexError, "FVector has only 3 items"); } @@ -306,15 +308,17 @@ static int ue_py_fvector_init(ue_PyFVector *self, PyObject *args, PyObject *kwar if (!PyArg_ParseTuple(args, "|fff", &x, &y, &z)) return -1; + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); + if (PyTuple_Size(args) == 1) { y = x; z = x; } - self->vec.X = x; - self->vec.Y = y; - self->vec.Z = z; + py_ue_fvector_get(self).X = x; + py_ue_fvector_get(self).Y = y; + py_ue_fvector_get(self).Z = z; return 0; } @@ -329,9 +333,9 @@ static PyObject *ue_py_fvector_richcompare(ue_PyFVector *vec1, PyObject *b, int if (op == Py_EQ) { - if (vec1->vec.X == vec2->vec.X && - vec1->vec.Y == vec2->vec.Y && - vec1->vec.Z == vec2->vec.Z) + if (py_ue_fvector_get(vec1).X == py_ue_fvector_get(vec2).X && + py_ue_fvector_get(vec1).Y == py_ue_fvector_get(vec2).Y && + py_ue_fvector_get(vec1).Z == py_ue_fvector_get(vec2).Z) { Py_INCREF(Py_True); return Py_True; @@ -340,9 +344,9 @@ static PyObject *ue_py_fvector_richcompare(ue_PyFVector *vec1, PyObject *b, int return Py_False; } - if (vec1->vec.X == vec2->vec.X && - vec1->vec.Y == vec2->vec.Y && - vec1->vec.Z == vec2->vec.Z) + if (py_ue_fvector_get(vec1).X == py_ue_fvector_get(vec2).X && + py_ue_fvector_get(vec1).Y == py_ue_fvector_get(vec2).Y && + py_ue_fvector_get(vec1).Z == py_ue_fvector_get(vec2).Z) { Py_INCREF(Py_False); return Py_False; @@ -370,6 +374,8 @@ void ue_python_init_fvector(PyObject *ue_module) ue_PyFVector_sequence_methods.sq_length = (lenfunc)ue_py_fvector_seq_length; ue_PyFVector_sequence_methods.sq_item = (ssizeargfunc)ue_py_fvector_seq_item; + ue_PyFVectorType.tp_base = &ue_PyUScriptStructType; + if (PyType_Ready(&ue_PyFVectorType) < 0) return; @@ -381,13 +387,20 @@ void ue_python_init_fvector(PyObject *ue_module) PyModule_AddObject(ue_module, "FVector", (PyObject *)&ue_PyFVectorType); } -PyObject *py_ue_new_fvector(FVector vec) +PyObject *py_ue_new_fvector(const FVector& vec) { ue_PyFVector *ret = (ue_PyFVector *)PyObject_New(ue_PyFVector, &ue_PyFVectorType); - ret->vec = vec; + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8 const*)&vec, false); return (PyObject *)ret; } +PyObject *py_ue_new_fvector_ptr(FVector* vec_ptr) +{ + ue_PyFVector *ret = (ue_PyFVector *)PyObject_New(ue_PyFVector, &ue_PyFVectorType); + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8*)vec_ptr, true); + return (PyObject *)ret; +} + ue_PyFVector *py_ue_is_fvector(PyObject *obj) { if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFVectorType)) @@ -407,7 +420,7 @@ bool py_ue_vector_arg(PyObject *args, FVector &vec) PyErr_Format(PyExc_TypeError, "argument is not a FVector"); return false; } - vec = py_vec->vec; + vec = py_ue_fvector_get(py_vec); return true; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h index e23935943..3d2a1238a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h @@ -2,18 +2,23 @@ -#include "UEPyModule.h" +#include "UEPyUScriptStruct.h" -typedef struct -{ - PyObject_HEAD - /* Type-specific fields go here. */ - FVector vec; +extern PyTypeObject ue_PyUScriptStructType; + +typedef struct { + ue_PyUScriptStruct py_base; } ue_PyFVector; -PyObject *py_ue_new_fvector(FVector); +PyObject *py_ue_new_fvector(const FVector&); +PyObject *py_ue_new_fvector_ptr(FVector*); ue_PyFVector *py_ue_is_fvector(PyObject *); +inline static FVector& py_ue_fvector_get(ue_PyFVector *self) +{ + return *((FVector*)py_ue_uscriptstruct_get_data((ue_PyUScriptStruct *)self)); +} + void ue_python_init_fvector(PyObject *); bool py_ue_vector_arg(PyObject *, FVector &); \ No newline at end of file diff --git a/Source/UnrealEnginePython/Public/PythonBlueprintFunctionLibrary.h b/Source/UnrealEnginePython/Public/PythonBlueprintFunctionLibrary.h index 51acdc180..3e640c84e 100644 --- a/Source/UnrealEnginePython/Public/PythonBlueprintFunctionLibrary.h +++ b/Source/UnrealEnginePython/Public/PythonBlueprintFunctionLibrary.h @@ -2,7 +2,6 @@ #include "Kismet/BlueprintFunctionLibrary.h" -#include "UnrealEnginePython.h" #include "PythonBlueprintFunctionLibrary.generated.h" diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index b50796b24..7d610299e 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -245,20 +245,33 @@ class FUnrealEnginePythonHouseKeeper PySlateDelegatesTracker.Add(Tracker); } - TSharedRef NewStaticSlateDelegate(PyObject *PyCallable) + TSharedRef NewStaticSlateDelegate(PyObject *PyCallable, FPythonSlateDelegate::Type InStatDelType = FPythonSlateDelegate::None, FName InContext = NAME_None) { TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); Delegate->SetPyCallable(PyCallable); - + Delegate->StaticDelegateType = InStatDelType; + Delegate->LifeTimeCtx = InContext; PyStaticSlateDelegatesTracker.Add(Delegate); return Delegate; } + void UntrackStaticSlateDelegate(FPythonSlateDelegate::Type InStaticDelType, FName InContext) + { + if (InStaticDelType == FPythonSlateDelegate::None) + { return; } + + PyStaticSlateDelegatesTracker.RemoveAll([InContext, InStaticDelType](const TSharedRef& trackedStaticDel) { + return trackedStaticDel->StaticDelegateType == InStaticDelType && trackedStaticDel->LifeTimeCtx == InContext; + }); + } + private: TMap UObjectPyMapping; TArray PyDelegatesTracker; TArray PySlateDelegatesTracker; + + //TODO: ikrimae: #ThirdParty-Python: #BUG: This implementation memory leaks. These delegates never get cleaned up TArray> PyStaticSlateDelegatesTracker; }; diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 9831618d3..6c636910c 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -11,13 +11,14 @@ public class UnrealEnginePython : ModuleRules private string pythonHome = ""; // otherwise specify the path of your python installation //private string pythonHome = "C:/Program Files/Python36"; - // this is an example for Homebrew on Mac + // this is an example for Homebrew on Mac //private string pythonHome = "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/"; // on Linux an include;libs syntax is expected: //private string pythonHome = "/usr/local/include/python3.6;/usr/local/lib/libpython3.6.so" private string[] windowsKnownPaths = { + "../../../../../ThirdParty/Python3", "C:/Program Files/Python36", "C:/Program Files/Python35", "C:/Python27", @@ -79,6 +80,7 @@ public UnrealEnginePython(TargetInfo Target) #endif { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; string enableUnityBuild = System.Environment.GetEnvironmentVariable("UEP_ENABLE_UNITY_BUILD"); bFasterWithoutUnity = string.IsNullOrEmpty(enableUnityBuild); @@ -217,7 +219,7 @@ public UnrealEnginePython(TargetInfo Target) string libPath = GetMacPythonLibFile(pythonHome); PublicLibraryPaths.Add(Path.GetDirectoryName(libPath)); PublicDelayLoadDLLs.Add(libPath); - Definitions.Add(string.Format("UNREAL_ENGINE_PYTHON_ON_MAC")); + PublicDefinitions.Add(string.Format("UNREAL_ENGINE_PYTHON_ON_MAC")); } else if (Target.Platform == UnrealTargetPlatform.Linux) { @@ -242,13 +244,13 @@ public UnrealEnginePython(TargetInfo Target) PublicIncludePaths.Add(items[0]); PublicAdditionalLibraries.Add(items[1]); } - Definitions.Add(string.Format("UNREAL_ENGINE_PYTHON_ON_LINUX")); + PublicDefinitions.Add(string.Format("UNREAL_ENGINE_PYTHON_ON_LINUX")); } string enableThreads = System.Environment.GetEnvironmentVariable("UEP_ENABLE_THREADS"); if (!string.IsNullOrEmpty(enableThreads)) { - Definitions.Add("UEPY_THREADING"); + PublicDefinitions.Add("UEPY_THREADING"); System.Console.WriteLine("*** Enabled Python Threads support ***"); } @@ -257,8 +259,8 @@ public UnrealEnginePython(TargetInfo Target) private bool IsPathRelative(string Path) { bool IsRooted = Path.StartsWith("\\", System.StringComparison.Ordinal) || // Root of the current directory on Windows. Also covers "\\" for UNC or "network" paths. - Path.StartsWith("/", System.StringComparison.Ordinal) || // Root of the current directory on Windows, root on UNIX-likes. - // Also covers "\\", considering normalization replaces "\\" with "//". + Path.StartsWith("/", System.StringComparison.Ordinal) || // Root of the current directory on Windows, root on UNIX-likes. + // Also covers "\\", considering normalization replaces "\\" with "//". (Path.Length >= 2 && char.IsLetter(Path[0]) && Path[1] == ':'); // Starts with ":" return !IsRooted; } diff --git a/UnrealEnginePython.uplugin b/UnrealEnginePython.uplugin index f07e0ffb9..91b30df39 100644 --- a/UnrealEnginePython.uplugin +++ b/UnrealEnginePython.uplugin @@ -14,27 +14,27 @@ "CanContainContent": true, "IsBetaVersion": true, "Installed": false, - "Modules": [ + "Modules": [ { "Name": "UnrealEnginePython", - "Type": "Runtime", + "Type": "RuntimeNoCommandlet", "LoadingPhase": "Default" }, - { + { "Name": "PythonAutomation", - "Type": "Editor", - "LoadingPhase": "PostDefault" - }, - { - "Name": "PythonConsole", - "Type": "Editor", + "Type": "EditorNoCommandlet", "LoadingPhase": "PostDefault" }, { - "Name": "PythonEditor", - "Type": "Editor", - "LoadingPhase": "PostDefault" - } + "Name": "PythonConsole", + "Type": "EditorNoCommandlet", + "LoadingPhase": "PostDefault" + }, + { + "Name" : "PythonEditor", + "Type": "EditorNoCommandlet", + "LoadingPhase": "PostDefault" + } ], "Plugins": [ { diff --git a/tools/codegen_nativeshim.py b/tools/codegen_nativeshim.py new file mode 100644 index 000000000..e5c799983 --- /dev/null +++ b/tools/codegen_nativeshim.py @@ -0,0 +1,27 @@ +import os, sys +from pprint import pprint +import cogapp +from pathlib import Path + + + +plugin_source_path = os.path.join(os.path.dirname(__file__), "../Source") + +cog_files = [ + r'UnrealEnginePython\Private\Wrappers\UEPyESlateEnums.cpp', +] + +cog_files = [str(Path(plugin_source_path, inCogFile)) for inCogFile in cog_files] + + + +##============## +## Run Script ## +##============## + + +if __name__ == '__main__': + for cog_file in cog_files: + if not os.access(cog_file, os.W_OK): + print(f'ERROR: File is read only: {cog_file}') + cogapp.Cog().main(['codegen_nativeshim.py','-r', f'-w', '-I ' + os.path.dirname(__file__), cog_file])