From 87f17f92c7eb456f68593a8fa3b9158313358256 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 9 Feb 2018 14:02:34 -0800 Subject: [PATCH 01/64] Put back K&L specific changes --- .../Private/PythonScriptFactory.cpp | 2 + .../Slate/UEPyIStructureDetailsView.cpp | 6 +- .../UnrealEnginePython.Build.cs | 2 + UnrealEnginePython.uplugin | 57 ++++++++++--------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/Source/PythonConsole/Private/PythonScriptFactory.cpp b/Source/PythonConsole/Private/PythonScriptFactory.cpp index 1b1828a7c..b5dba512f 100644 --- a/Source/PythonConsole/Private/PythonScriptFactory.cpp +++ b/Source/PythonConsole/Private/PythonScriptFactory.cpp @@ -5,7 +5,9 @@ UPythonScriptFactory::UPythonScriptFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { +#if !WITH_KNL_PYEXT Formats.Add(FString("py;Python Script")); +#endif bCreateNew = false; bEditAfterNew = true; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp index aec81f315..63eccb2f1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp @@ -56,10 +56,14 @@ static PyObject *py_ue_istructure_details_view_set_structure_data(ue_PyIStructur 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 diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 6498068c9..7c03a068c 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -19,6 +19,7 @@ public class UnrealEnginePython : ModuleRules private string[] windowsKnownPaths = { + "../../../../../ThirdParty/Python3", "C:/Program Files/Python36", "C:/Program Files/Python35", "C:/Python27", @@ -79,6 +80,7 @@ public UnrealEnginePython(ReadOnlyTargetRules Target) : base(Target) public UnrealEnginePython(TargetInfo Target) #endif { + Definitions.Add("WITH_KNL_PYEXT=1"); PublicIncludePaths.AddRange( new string[] { diff --git a/UnrealEnginePython.uplugin b/UnrealEnginePython.uplugin index a7ed3dabb..f2bb82e40 100644 --- a/UnrealEnginePython.uplugin +++ b/UnrealEnginePython.uplugin @@ -1,40 +1,41 @@ { - "FileVersion": 3, - "Version": 1, - "VersionName": "1.0", - "FriendlyName": "UnrealEnginePython", - "Description": "Embed a Python VM in your project", - "Category": "Scripting Languages", - "CreatedBy": "Roberto De Ioris", - "CreatedByURL": "", - "DocsURL": "", - "MarketplaceURL": "", - "SupportURL": "", - "EnabledByDefault": true, - "CanContainContent": true, - "IsBetaVersion": true, - "Installed": false, - "Modules": [ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "UnrealEnginePython", + "Description": "Embed a Python VM in your project", + "Category": "Scripting Languages", + "CreatedBy": "Roberto De Ioris", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "EnabledByDefault": true, + "CanContainContent": true, + "IsBetaVersion": true, + "Installed": false, + "Modules": [ { "Name": "UnrealEnginePython", - "Type": "Runtime", + "Type": "Developer", "LoadingPhase": "Default" }, - { - "Name": "PythonConsole", - "Type": "Editor", - "LoadingPhase": "PostDefault" - }, - { - "Name" : "PythonEditor", - "Type" : "Editor", - "LoadingPhase": "PostDefault" - } + { + "Name": "PythonConsole", + "Type": "Editor", + "LoadingPhase": "PostDefault" + }, + { + "Name": "PythonEditor", + "Type": "Editor", + "LoadingPhase": "PostDefault" + } ], "Plugins": [ { "Name": "LevelSequenceEditor", "Enabled": true } - ] + ], + "BlacklistTargets": [ "Server" ] } From 152540dd358d708f7645309d46463492191b4668 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 9 Feb 2018 22:14:36 -0800 Subject: [PATCH 02/64] Add PyCalllable_Check_Extended macro to guard against "callable" uscriptstructs which are mutable/reference structs -Without it, slate argument binding has errors bc it tries to bind delegates to the uscriptstructs --- .../Private/Slate/UEPyFMenuBuilder.cpp | 2 +- .../Private/Slate/UEPyFToolBarBuilder.cpp | 2 +- .../Private/Slate/UEPySButton.cpp | 2 +- .../Slate/UEPySPythonMultiColumnTableRow.h | 9 +++++---- .../Private/Slate/UEPySPythonShelf.cpp | 6 +++--- .../Private/Slate/UEPySPythonWidget.h | 16 ++++++++-------- .../Private/Slate/UEPySWidget.cpp | 8 ++++---- .../Private/Slate/UEPySWindow.cpp | 2 +- .../Private/Slate/UEPySlate.cpp | 12 ++++++------ .../UnrealEnginePython/Private/Slate/UEPySlate.h | 2 +- .../Private/UObject/UEPyInput.cpp | 6 +++--- .../Public/UnrealEnginePython.h | 3 +++ 12 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index f495a2db3..ea71c0d3a 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -46,7 +46,7 @@ static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyO if (!PyArg_ParseTuple(args, "ssO|OO:add_menu_entry", &label, &tooltip, &py_callable, &py_obj, &py_uiaction_obj)) return nullptr; - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "argument is not callable"); } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp index 6c3cf5fdc..4465e87e1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp @@ -37,7 +37,7 @@ static PyObject *py_ue_ftool_bar_builder_add_tool_bar_button(ue_PyFToolBarBuilde return PyErr_Format(PyExc_Exception, "argument is not a FSlateIcon"); } - if (!PyCallable_Check(py_callable)) { + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "argument is not callable"); } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySButton.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySButton.cpp index 90e35fced..4ebddb07e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySButton.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySButton.cpp @@ -27,7 +27,7 @@ static PyObject *py_ue_sbutton_bind_on_clicked(ue_PySButton *self, PyObject * ar return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "argument is not callable"); } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h index 268ee97b2..8a8933578 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h @@ -22,7 +22,7 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow >::Construct(FSuperRowType::FArguments(), InOwnerTableView); } - virtual TSharedRef GenerateWidgetForColumn( const FName& ColumnName ) override + TSharedRef SPythonMultiColumnTableRow::GenerateWidgetForColumn(const FName& ColumnName) { FScopePythonGIL gil; @@ -30,7 +30,7 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 63788d7a0..664f4d305 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1228,7 +1228,7 @@ PyObject *py_unreal_engine_add_menu_extension(PyObject * self, PyObject * args) if (!menu_extension_interface) return PyErr_Format(PyExc_Exception, "module %s is not supported", module); - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); TSharedRef *commands = new TSharedRef(new FPythonSlateCommands()); @@ -1261,7 +1261,7 @@ PyObject *py_unreal_engine_add_menu_bar_extension(PyObject * self, PyObject * ar FLevelEditorModule &ExtensibleModule = FModuleManager::LoadModuleChecked("LevelEditor"); - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); TSharedRef *commands = new TSharedRef(new FPythonSlateCommands()); @@ -1294,7 +1294,7 @@ PyObject *py_unreal_engine_add_tool_bar_extension(PyObject * self, PyObject * ar FLevelEditorModule &ExtensibleModule = FModuleManager::LoadModuleChecked("LevelEditor"); - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); TSharedRef *commands = new TSharedRef(new FPythonSlateCommands()); @@ -1322,7 +1322,7 @@ PyObject *py_unreal_engine_add_asset_view_context_menu_extension(PyObject * self return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); FContentBrowserModule &ContentBrowser = FModuleManager::LoadModuleChecked("ContentBrowser"); @@ -1350,7 +1350,7 @@ PyObject *py_unreal_engine_register_nomad_tab_spawner(PyObject * self, PyObject return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); FOnSpawnTab spawn_tab; @@ -1455,7 +1455,7 @@ PyObject *py_unreal_engine_open_color_picker(PyObject *self, PyObject *args, PyO return nullptr; } - if (!PyCallable_Check(py_callable_on_color_committed)) + if (!PyCalllable_Check_Extended(py_callable_on_color_committed)) { return PyErr_Format(PyExc_Exception, "on_color_committed must be a callable"); } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 0d95e74b8..131a372ad 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -163,7 +163,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); {\ PyObject *value = ue_py_dict_get_item(kwargs, _param);\ if (value) {\ - if (PyCallable_Check(value)) {\ + if (PyCalllable_Check_Extended(value)) {\ _base handler;\ UPythonSlateDelegate *py_delegate = NewObject();\ py_delegate->SetPyCallable(value);\ diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyInput.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyInput.cpp index 458a1d5fd..f5cc2d975 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyInput.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyInput.cpp @@ -380,7 +380,7 @@ PyObject *py_ue_bind_action(ue_PyUObject *self, PyObject * args) return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "object is not a callable"); } @@ -433,7 +433,7 @@ PyObject *py_ue_bind_axis(ue_PyUObject *self, PyObject * args) return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "object is not a callable"); } @@ -487,7 +487,7 @@ PyObject *py_ue_bind_key(ue_PyUObject *self, PyObject * args) return NULL; } - if (!PyCallable_Check(py_callable)) + if (!PyCalllable_Check_Extended(py_callable)) { return PyErr_Format(PyExc_Exception, "object is not a callable"); } diff --git a/Source/UnrealEnginePython/Public/UnrealEnginePython.h b/Source/UnrealEnginePython/Public/UnrealEnginePython.h index 32d353a22..28421cae4 100644 --- a/Source/UnrealEnginePython/Public/UnrealEnginePython.h +++ b/Source/UnrealEnginePython/Public/UnrealEnginePython.h @@ -12,6 +12,9 @@ #include "Runtime/SlateCore/Public/Styling/ISlateStyle.h" #include "Runtime/SlateCore/Public/Styling/SlateStyle.h" +// We need to make sure reference structs do not mistaken for callable +#define PyCalllable_Check_Extended(value) PyCallable_Check(value) && py_ue_is_uscriptstruct(value) == nullptr + DECLARE_LOG_CATEGORY_EXTERN(LogPython, Log, All); From 39906bf16293386f36aac08dbc93f021469b1021 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 12 Feb 2018 14:25:14 -0800 Subject: [PATCH 03/64] Addd iseditor/isrunninggame/isrunningcommandlet/isrunningdedicatedserver --- .../Private/Slate/UEPySPythonShelf.cpp | 3 +- .../Private/Slate/UEPySPythonShelf.h | 3 +- .../UnrealEnginePython/Private/UEPyEngine.cpp | 48 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEngine.h | 6 +++ .../UnrealEnginePython/Private/UEPyModule.cpp | 5 ++ UnrealEnginePython.uplugin | 6 +-- 6 files changed, 66 insertions(+), 5 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.cpp index e6b580c09..1ee5851f3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonShelf.cpp @@ -1,6 +1,7 @@ -#if WITH_EDITOR #include "UnrealEnginePythonPrivatePCH.h" +#if WITH_EDITOR + #if ENGINE_MINOR_VERSION > 14 #include "UEPySPythonShelf.h" 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/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index 72c68696f..cac4e2f7c 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -69,6 +69,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; diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index 40e78f182..12a44dcfe 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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 481917330..2b59fa341 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -157,6 +157,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, "" }, diff --git a/UnrealEnginePython.uplugin b/UnrealEnginePython.uplugin index f2bb82e40..b7637fac6 100644 --- a/UnrealEnginePython.uplugin +++ b/UnrealEnginePython.uplugin @@ -17,17 +17,17 @@ "Modules": [ { "Name": "UnrealEnginePython", - "Type": "Developer", + "Type": "RuntimeNoCommandlet", "LoadingPhase": "Default" }, { "Name": "PythonConsole", - "Type": "Editor", + "Type": "EditorNoCommandlet", "LoadingPhase": "PostDefault" }, { "Name": "PythonEditor", - "Type": "Editor", + "Type": "EditorNoCommandlet", "LoadingPhase": "PostDefault" } ], From 5fc799f10af2f1ee82e5f2ccc10c863a942dfc97 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 12 Feb 2018 17:19:28 -0800 Subject: [PATCH 04/64] Add back K&L specific build process workaround --- .../UnrealEnginePython.Build.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 3dfaa4a0a..80b7877d1 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -187,6 +187,35 @@ public UnrealEnginePython(TargetInfo Target) string libPath = GetWindowsPythonLibFile(pythonHome); PublicLibraryPaths.Add(Path.GetDirectoryName(libPath)); PublicAdditionalLibraries.Add(libPath); + + // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process + // copy the dlls into the plugins dlls folder, so they don't have to be on the path + string dllsDir = Path.Combine(ModuleDirectory, "../../Binaries", Target.Platform == UnrealTargetPlatform.Win32 ? "Win32" : "Win64"); + try + { + string[] dllsToCopy = + { + "python3.dll", + "python36.dll" + }; + foreach (string dllToCopy in dllsToCopy) + { + // If the dll exist, make sure to set attributes so they are actually accessible + if (File.Exists(Path.Combine(dllsDir, dllToCopy))) + { + File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal); + } + + File.Copy(Path.Combine(pythonHome, dllToCopy), Path.Combine(dllsDir, dllToCopy), true); + File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal); + } + } + catch (System.IO.IOException) { } + catch (System.UnauthorizedAccessException) + { + System.Console.WriteLine("WARNING: Unable to copy python dlls, they are probably in use..."); + } + // @third party code - END Bebylon } else if (Target.Platform == UnrealTargetPlatform.Mac) { From 4ebc878224f5837cf087e0784b86b53fcf251d2b Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 13 Feb 2018 20:53:31 -0800 Subject: [PATCH 05/64] SPythonTreeView extensions --- .../Private/Slate/UEPySPythonListView.cpp | 45 ++--- .../Private/Slate/UEPySPythonListView.h | 2 - .../Private/Slate/UEPySPythonTreeView.cpp | 154 ++++++++++++++++-- .../Private/Slate/UEPySPythonTreeView.h | 3 + 4 files changed, 152 insertions(+), 52 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp index f8c3b08ea..b1de6b753 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp @@ -5,11 +5,6 @@ #include "UEPySPythonListView.h" -void SPythonListView::SetHeaderRow(TSharedPtr InHeaderRowWidget) -{ - HeaderRow = InHeaderRowWidget; -} - #define sw_python_list_view StaticCastSharedRef(self->s_list_view.s_table_view_base.s_compound_widget.s_widget.s_widget) static PyObject *py_ue_spython_list_view_get_selected_items(ue_PySPythonListView *self, PyObject * args) { @@ -37,28 +32,7 @@ static PyObject *py_ue_spython_list_view_get_num_items_selected(ue_PySPythonList return PyLong_FromLong(sw_python_list_view->GetNumItemsSelected()); } -static PyObject *py_ue_spython_list_view_set_header_row(ue_PySPythonListView *self, PyObject * args) -{ - PyObject *py_content; - if (!PyArg_ParseTuple(args, "O:set_header_row", &py_content)) - { - return NULL; - } - - ue_PySHeaderRow *py_sheader_row = py_ue_is_sheader_row(py_content); - if (!py_sheader_row) - { - return PyErr_Format(PyExc_Exception, "argument is not a SHeaderRow"); - } - - Py_INCREF(py_sheader_row); - sw_python_list_view->SetHeaderRow(StaticCastSharedRef(py_sheader_row->s_border.s_compound_widget.s_widget.s_widget->AsShared())); - - Py_INCREF(self); - return (PyObject *)self; -} - -static PyObject *py_spython_list_view_update_item_source_list(ue_PySPythonListView *self, PyObject * args) +static PyObject *py_ue_spython_list_view_update_item_source_list(ue_PySPythonListView *self, PyObject * args) { PyObject *values; if (!PyArg_ParseTuple(args, "O:update_item_source_list", &values)) @@ -94,8 +68,7 @@ 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, "" }, + { "update_item_source_list", (PyCFunction)py_ue_spython_list_view_update_item_source_list, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; @@ -145,25 +118,30 @@ PyTypeObject ue_PySPythonListViewType = { ue_PySPythonListView_methods, /* tp_methods */ }; -static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *args, PyObject *kwargs) { +static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *args, PyObject *kwargs) +{ ue_py_slate_setup_farguments(SPythonListView); // first of all check for values PyObject *values = ue_py_dict_get_item(kwargs, "list_items_source"); - if (!values) { + if (!values) + { PyErr_SetString(PyExc_Exception, "you must specify list items"); return -1; } values = PyObject_GetIter(values); - if (!values) { + if (!values) + { + PyErr_SetString(PyExc_Exception, "list_items_source field is not an iterable"); Py_DECREF(values); return -1; } new(&self->item_source_list) TArray>(); - while (PyObject *item = PyIter_Next(values)) { + while (PyObject *item = PyIter_Next(values)) + { Py_INCREF(item); self->item_source_list.Add(TSharedPtr(new FPythonItem(item))); } @@ -195,6 +173,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 8e981336a..6c3937671 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h @@ -11,8 +11,6 @@ class SPythonListView : public SListView> { ~SPythonListView() { delete(ItemsSource); } - - void SetHeaderRow(TSharedPtr InHeaderRowWidget); }; typedef struct { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp index c1e4deaac..9d86b19ef 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp @@ -8,6 +8,20 @@ #define sw_python_tree_view StaticCastSharedRef(self->s_tree_view.s_list_view.s_table_view_base.s_compound_widget.s_widget.s_widget) + +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) { PyObject *py_item; @@ -16,32 +30,120 @@ static PyObject *py_ue_spython_tree_view_set_item_expansion(ue_PySPythonTreeView { return nullptr; } - sw_python_tree_view->SetPythonItemExpansion(py_item, PyObject_IsTrue(py_bool) ? true : false); + + if (TSharedPtr const* foundItem = sw_python_tree_view->Find(py_item)) + { + sw_python_tree_view->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) + PyObject *py_item; + if (!PyArg_ParseTuple(args, "OO:is_item_expanded", &py_item)) { - if (PythonItem->py_object == item) - { - SetItemExpansion(PythonItem, InShouldExpandItem); - } + return nullptr; } + + if (TSharedPtr const* foundItem = sw_python_tree_view->Find(py_item)) + { + sw_python_tree_view->IsItemExpanded(*foundItem); + } + + Py_RETURN_NONE; +} + +static PyObject *py_ue_spython_tree_view_get_selected_items(ue_PySPythonTreeView *self, PyObject * args) { + + PyObject *py_list = PyList_New(0); + + TArray> items = sw_python_tree_view->GetSelectedItems(); + + for (auto item : items) { + PyList_Append(py_list, item->py_object); + } + + return py_list; +} + +static PyObject *py_ue_spython_tree_view_clear_selection(ue_PySPythonTreeView *self, PyObject * args) +{ + sw_python_tree_view->ClearSelection(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *py_ue_spython_tree_view_get_num_items_selected(ue_PySPythonTreeView *self, PyObject * args) { + return PyLong_FromLong(sw_python_tree_view->GetNumItemsSelected()); +} + +static PyObject *py_ue_spython_tree_view_update_item_source_list(ue_PySPythonTreeView *self, PyObject * args) +{ + PyObject *values; + if (!PyArg_ParseTuple(args, "O:update_item_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->item_source_list) + { + Py_XDECREF(item->py_object); + } + self->item_source_list.Empty(); + + Move>>(self->item_source_list, tempNewArray); + Py_RETURN_NONE; } static PyMethodDef ue_PySPythonTreeView_methods[] = { + { "get_selected_items", (PyCFunction) py_ue_spython_tree_view_get_selected_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 */ @@ -83,29 +185,47 @@ 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"); - return -1; + 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); // keep track of items - self->s_tree_view.s_list_view.s_table_view_base.s_compound_widget.s_widget.py_refs.Add(item); - items->Add(TSharedPtr(new FPythonItem(item))); + self->item_source_list.Add(TSharedPtr(new FPythonItem(item))); } - Py_DECREF(values); - - arguments.TreeItemsSource(items); + arguments.TreeItemsSource(&self->item_source_list); + + { + 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); + ((ue_PySWidget *)self)->py_refs.Add(value); + arguments.HeaderRow(StaticCastSharedRef(((ue_PySWidget *)_py_swidget)->s_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 @@ -127,4 +247,4 @@ void ue_python_init_spython_tree_view(PyObject *ue_module) Py_INCREF(&ue_PySPythonTreeViewType); PyModule_AddObject(ue_module, "SPythonTreeView", (PyObject *)&ue_PySPythonTreeViewType); -} +} \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h index 4c20d9e1c..bfbfacfd0 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h @@ -15,12 +15,15 @@ class SPythonTreeView : public STreeView> } void SetPythonItemExpansion(PyObject *item, bool InShouldExpandItem); + + TSharedPtr const* SPythonTreeView::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 *); From 9751d91c311402f48cac567c98804b6f99025d52 Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 14 Feb 2018 01:45:28 -0800 Subject: [PATCH 06/64] Python Plugin: Add ability to set styleset with slatestyle widgets FIX: Rename variable used in PY_RETURN_UOBJECT to __ret to avoid name collision --- .../Private/Slate/UEPyFSlateStyleSet.cpp | 53 +++++++++++++++++++ .../Private/UnrealEnginePythonPrivatePCH.h | 12 ++--- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp index 7f5e7e45e..e78713e87 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp @@ -29,6 +29,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; @@ -64,6 +72,51 @@ 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{ 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) { diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h b/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h index 342c4e96d..d23778b37 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h +++ b/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h @@ -90,15 +90,15 @@ int PyGILState_Check(); #endif bool PyUnicodeOrString_Check(PyObject *py_obj); -#define Py_RETURN_UOBJECT(py_uobj) ue_PyUObject *ret = ue_get_python_uobject_inc(py_uobj);\ - if (!ret)\ +#define Py_RETURN_UOBJECT(py_uobj) ue_PyUObject *__ret = ue_get_python_uobject_inc(py_uobj);\ + if (!__ret)\ return PyErr_Format(PyExc_Exception, "uobject is in invalid state");\ - return (PyObject *)ret; + return (PyObject *)__ret; -#define Py_RETURN_UOBJECT_NOINC(py_uobj) ue_PyUObject *ret = ue_get_python_uobject(py_uobj);\ - if (!ret)\ +#define Py_RETURN_UOBJECT_NOINC(py_uobj) ue_PyUObject *__ret = ue_get_python_uobject(py_uobj);\ + if (!__ret)\ return PyErr_Format(PyExc_Exception, "uobject is in invalid state");\ - return (PyObject *)ret; + return (PyObject *)__ret; #if ENGINE_MINOR_VERSION < 16 template From 87b70560d381b775d473060f671c7c38a7ed4a34 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 15 Feb 2018 19:53:40 -0800 Subject: [PATCH 07/64] UEPyEngine, UEPyEditor, UEPyModule: Added console exec function to UEPyEngine and removed it from UEPyEditor so that it's usable in standalone scripts. Fix various build ordering/ifdef issues for shipping Add clear_event function for multicasting --- .../Slate/UEPySPythonMultiColumnTableRow.cpp | 71 ++++++++++++++++++- .../Slate/UEPySPythonMultiColumnTableRow.h | 70 +----------------- .../Private/Slate/UEPySPythonTreeView.h | 2 +- .../UnrealEnginePython/Private/UEPyEditor.cpp | 18 ----- .../UnrealEnginePython/Private/UEPyEditor.h | 2 - .../UnrealEnginePython/Private/UEPyEngine.cpp | 46 ++++++++++++ .../UnrealEnginePython/Private/UEPyEngine.h | 1 + .../Private/UObject/UEPyObject.cpp | 26 +++++++ .../Private/UObject/UEPyObject.h | 1 + 9 files changed, 147 insertions(+), 90 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp index a4d8b3d2a..49be46cd8 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp @@ -6,6 +6,75 @@ #define sw_python_multicolumn_table_row StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) +TSharedRef SPythonMultiColumnTableRow::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; + } + + ue_PySWidget *s_widget = py_ue_is_swidget(ret); + if (!s_widget) + { + Py_DECREF(ret); + UE_LOG(LogPython, Error, TEXT("returned value is not a SWidget")); + return SNullWidget::NullWidget; + } + + TSharedRef value = s_widget->s_widget; + Py_DECREF(ret); + return value; +} + +FReply SPythonMultiColumnTableRow::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); + } +} + + static PyMethodDef ue_PySPythonMultiColumnTableRow_methods[] = { { NULL } /* Sentinel */ }; @@ -80,4 +149,4 @@ ue_PySPythonMultiColumnTableRow *py_ue_is_spython_multicolumn_table_row(PyObject if (!PyObject_IsInstance(obj, (PyObject *)&ue_PySPythonMultiColumnTableRowType)) return nullptr; return (ue_PySPythonMultiColumnTableRow *)obj; -} +} \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h index 8a8933578..edf329567 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h @@ -22,74 +22,8 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow >::Construct(FSuperRowType::FArguments(), InOwnerTableView); } - TSharedRef SPythonMultiColumnTableRow::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; - } - - ue_PySWidget *s_widget = py_ue_is_swidget(ret); - if (!s_widget) - { - Py_DECREF(ret); - UE_LOG(LogPython, Error, TEXT("returned value is not a SWidget")); - return SNullWidget::NullWidget; - } - - TSharedRef value = s_widget->s_widget; - Py_DECREF(ret); - return value; - } - - - FReply SPythonMultiColumnTableRow::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); - } - } + TSharedRef GenerateWidgetForColumn(const FName& ColumnName); + FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent); void SetPyObject(PyObject *py_obj) { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h index bfbfacfd0..25771fc3d 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.h @@ -16,7 +16,7 @@ class SPythonTreeView : public STreeView> void SetPythonItemExpansion(PyObject *item, bool InShouldExpandItem); - TSharedPtr const* SPythonTreeView::Find(PyObject *item); + TSharedPtr const* Find(PyObject *item); }; typedef struct diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index b437f35a0..f674807e4 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -81,24 +81,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) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 700fe68d5..ca8d95d51 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -23,8 +23,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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index 0ca68b7ac..17109009a 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -1294,4 +1294,50 @@ PyObject *py_unreal_engine_clipboard_paste(PyObject * self, PyObject * args) FString clipboard; FGenericPlatformMisc::ClipboardPaste(clipboard); 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 12a44dcfe..9f6b2da00 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -89,6 +89,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/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 249d2dd4c..086153b0d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -1177,6 +1177,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 347470bd2..abf23d8c4 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -41,6 +41,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 *); From e6de04b071a9ba189a5fb12d35a49ee7a123ce69 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 15 Feb 2018 19:57:04 -0800 Subject: [PATCH 08/64] FIX: Multicast delegate property should reference pointer in container, not value. Accidentally making copies and not updating the actual delegate --- .../UnrealEnginePython/Private/UEPyModule.cpp | 21 +++++++++++-------- .../Private/UObject/UEPyObject.cpp | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 08b3e5143..0cecd4947 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -245,7 +245,6 @@ 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_select_actor", py_unreal_engine_editor_select_actor, METH_VARARGS, "" }, { "editor_deselect_actors", py_unreal_engine_editor_deselect_actors, METH_VARARGS, "" }, @@ -406,6 +405,7 @@ static PyMethodDef unreal_engine_methods[] = { { "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) { "copy_properties_for_unrelated_objects", (PyCFunction)py_unreal_engine_copy_properties_for_unrelated_objects, METH_VARARGS | METH_KEYWORDS, "" }, @@ -506,6 +506,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, "" }, { "get_py_proxy", (PyCFunction)py_ue_get_py_proxy, METH_VARARGS, "" }, @@ -1729,7 +1730,7 @@ static int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *k { 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 = NewObject(); @@ -1742,10 +1743,11 @@ static int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *k 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 { @@ -3237,7 +3239,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 = NewObject(); @@ -3251,10 +3253,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 { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 086153b0d..8e3d1973b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -938,10 +938,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 { From e14d9366b613db740024eeb0cc93e5091544b3cc Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 15 Feb 2018 23:44:51 -0800 Subject: [PATCH 09/64] Make explicit python FTransform a subchild of of UE4's FTransform so that it's enumerable as a USTRUCT -Adding py_ue_ftransform_get() helper to retrieve FTransform from ue_PyUScriptStruct as we're not storing it anymore directly -Adding new_ftransform_ptr variant that's meant to point to original struct to allow ref struct syntax -Adding global support for returning original data ptr for ref struct or not. Can disable it globally now by just changing py_ue_uscriptstruct_get_data() to return the new data NOTE: Had to explicitly specify ue_PyFTransformType.tp_call; was not picking it up from the base ue_PyUScriptStructType. Not sure if this means the subclassing wasn't set up properly and that other important things like basae.tp_dealloc won't get called --- .../Slate/UEPyIStructureDetailsView.cpp | 4 +- .../Private/Slate/UEPySlate.cpp | 2 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 13 +-- .../Private/UEPyUScriptStruct.cpp | 56 +++++------ .../Private/UEPyUScriptStruct.h | 7 ++ .../Private/UObject/UEPyDataTable.cpp | 2 +- .../Private/UObject/UEPySequencer.cpp | 2 +- .../Private/UObject/UEPySkeletal.cpp | 2 +- .../Private/Wrappers/UEPyFTransform.cpp | 98 ++++++++++++++----- .../Private/Wrappers/UEPyFTransform.h | 18 +++- 10 files changed, 133 insertions(+), 71 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp index d8b4a9e3a..e19a7fed4 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyIStructureDetailsView.cpp @@ -52,7 +52,7 @@ 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); @@ -196,7 +196,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"); self->istructure_details_view = PropertyEditorModule.CreateStructureDetailView(view_args, struct_view_args, struct_scope); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 100de470d..5013a8705 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1135,7 +1135,7 @@ 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"); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 0cecd4947..e3b131800 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -2376,8 +2376,8 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) } if (casted_struct == TBaseStructure::Get()) { - FTransform transform = *casted_prop->ContainerPtrToValuePtr(buffer); - return py_ue_new_ftransform(transform); + FTransform* transform_ptr = casted_prop->ContainerPtrToValuePtr(buffer); + return py_ue_new_ftransform_ptr(transform_ptr); } if (casted_struct == FHitResult::StaticStruct()) { @@ -2784,7 +2784,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer) = py_transform->transform; + *casted_prop->ContainerPtrToValuePtr(buffer) = py_ue_ftransform_get(py_transform); return true; } } @@ -2839,7 +2839,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) if (casted_prop->Struct == py_u_struct->u_struct) { uint8 *dest = casted_prop->ContainerPtrToValuePtr(buffer); - 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; } } @@ -3226,6 +3226,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) { @@ -3610,7 +3611,7 @@ FGuid *ue_py_check_fguid(PyObject *py_obj) if (ue_py_struct->u_struct == FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid"))) { - return (FGuid*)ue_py_struct->data; + return (FGuid*)(py_ue_uscriptstruct_get_data(ue_py_struct)); } return nullptr; @@ -3625,7 +3626,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/UEPyUScriptStruct.cpp b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp index f481dd784..0a536c63c 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp @@ -15,7 +15,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); + return ue_py_convert_property(u_property, py_ue_uscriptstruct_get_data(self)); } static PyObject *py_ue_uscriptstruct_set_field(ue_PyUScriptStruct *self, PyObject * args) @@ -32,7 +32,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)) + if (!ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self))) { return PyErr_Format(PyExc_Exception, "unable to set property %s", name); } @@ -63,7 +63,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) @@ -81,7 +81,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); + PyObject *struct_value = ue_py_convert_property(*SArgs, py_ue_uscriptstruct_get_data(self)); if (!struct_value) { Py_DECREF(py_struct_dict); @@ -120,7 +120,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) @@ -170,7 +170,7 @@ static PyObject *ue_PyUScriptStruct_getattro(ue_PyUScriptStruct *self, PyObject { // swallow previous exception PyErr_Clear(); - return ue_py_convert_property(u_property, self->data); + return ue_py_convert_property(u_property, py_ue_uscriptstruct_get_data(self)); } } } @@ -187,7 +187,7 @@ 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)) + if (ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self))) { return 0; } @@ -211,7 +211,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 */ @@ -262,16 +262,20 @@ static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, Py PyErr_SetString(PyExc_Exception, "argument is not a UScriptStruct"); return -1; } + ue_py_uscriptstruct_alloc(self, (UScriptStruct *)py_u_obj->ue_object); + return 0; +} - self->u_struct = (UScriptStruct *)py_u_obj->ue_object; - self->data = (uint8*)FMemory::Malloc(self->u_struct->GetStructureSize()); +void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *self, UScriptStruct* in_u_struct) +{ + self->u_struct = in_u_struct; + 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; - return 0; + self->is_ptr = 0; } static PyObject *ue_py_uscriptstruct_richcompare(ue_PyUScriptStruct *u_struct1, PyObject *py_obj, int op) @@ -282,7 +286,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) { @@ -301,7 +305,7 @@ static PyObject *ue_py_uscriptstruct_richcompare(ue_PyUScriptStruct *u_struct1, } // get the original pointer of a struct -static PyObject *ue_py_uscriptstruct_get_ptr(ue_PyUScriptStruct *self, PyObject * args) +PyObject *ue_py_uscriptstruct_get_ptr(ue_PyUScriptStruct *self, PyObject * args) { ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); ret->u_struct = self->u_struct; @@ -329,16 +333,12 @@ 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_PyUScriptStruct* ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); + ue_py_uscriptstruct_alloc(ret, u_struct); + ret->u_struct->CopyScriptStruct(ret->data, in_data); + ret->original_data = in_data; return (PyObject *)ret; } @@ -346,10 +346,10 @@ PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *data) PyObject *py_ue_wrap_uscriptstruct(UScriptStruct *u_struct, uint8 *data) { ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); - ret->u_struct = u_struct; - ret->data = data; - ret->original_data = data; - ret->is_ptr = 0; + ret->u_struct = u_struct; + ret->data = data; + ret->original_data = data; + ret->is_ptr = 0; return (PyObject *)ret; } @@ -358,4 +358,4 @@ ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *obj) if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyUScriptStructType)) return nullptr; return (ue_PyUScriptStruct *)obj; -} \ No newline at end of file +} diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h index d7fcba2e2..b2bb79c24 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h @@ -16,8 +16,15 @@ typedef struct PyObject *py_ue_new_uscriptstruct(UScriptStruct *, uint8 *); PyObject *py_ue_wrap_uscriptstruct(UScriptStruct *, uint8 *); +void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *, UScriptStruct *); +PyObject *ue_py_uscriptstruct_get_ptr(ue_PyUScriptStruct *, PyObject *); ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *); +inline 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/UObject/UEPyDataTable.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyDataTable.cpp index a41e4df26..9944e1587 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/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 96ae7a414..4751bbd58 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -709,7 +709,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 = false; - FTransform transform = py_transform->transform; + FTransform transform = py_ue_ftransform_get(py_transform); FTransformKey tx = FTransformKey(EKey3DTransformChannel::Translation, EAxis::X, transform.GetLocation().X, unwind); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp index 3d11753e7..5fcc60bdd 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp @@ -184,7 +184,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)); } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index b76be90a8..47db65727 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -2,12 +2,12 @@ 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,7 +23,7 @@ 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 PyMethodDef ue_PyFTransform_methods[] = { @@ -35,29 +35,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_vec->vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a vector"); @@ -68,7 +68,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_rot->rot.Quaternion()); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a rotator"); @@ -79,7 +79,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_quat->quat); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a quaternion"); @@ -90,7 +90,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_vec->vec); return 0; } PyErr_SetString(PyExc_TypeError, "value is not a vector"); @@ -109,9 +109,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), @@ -170,11 +170,13 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject return -1; } + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get()); + 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_vec->vec); } else { @@ -212,7 +214,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; } @@ -225,11 +227,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_rot->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_quat->quat); } else { @@ -239,7 +241,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 @@ -257,13 +259,13 @@ 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; @@ -274,7 +276,7 @@ static PyObject *ue_py_ftransform_mul(ue_PyFTransform *self, PyObject *value) } else if (ue_PyFTransform *py_transform = py_ue_is_ftransform(value)) { - t *= py_transform->transform; + t *= py_ue_ftransform_get(py_transform); } else { @@ -290,11 +292,14 @@ void ue_python_init_ftransform(PyObject *ue_module) ue_PyFTransformType.tp_new = PyType_GenericNew; ue_PyFTransformType.tp_init = (initproc)ue_py_ftransform_init; + ue_PyFTransformType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; memset(&ue_PyFTransform_number_methods, 0, sizeof(PyNumberMethods)); 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; @@ -302,11 +307,50 @@ 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); + //ret->transform = transform; + //return (PyObject *)ret; + + ue_PyFTransform *xfm_ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); + + { + ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)xfm_ret; + UScriptStruct *u_struct = TBaseStructure::Get(); + uint8 const * const data = (uint8 const*)&transform; + + 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 = struct_data; + ret->is_ptr = 0; + } + + return (PyObject *)xfm_ret; +} + +PyObject* py_ue_new_ftransform_ptr(FTransform* transform_ptr) { - ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); - ret->transform = transform; - return (PyObject *)ret; + ue_PyFTransform *xfm_ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); + + { + ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)xfm_ret; + UScriptStruct *u_struct = TBaseStructure::Get(); + uint8 *data = (uint8*)transform_ptr; + + 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; + } + + return (PyObject *)xfm_ret; } ue_PyFTransform *py_ue_is_ftransform(PyObject *obj) @@ -328,7 +372,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 74c23f214..a4c4d5073 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h @@ -4,14 +4,24 @@ #include "UnrealEnginePython.h" +extern PyTypeObject ue_PyUScriptStructType; + typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - FTransform transform; + //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 From 003d2ae58a166052cb4af23658f75caffdd6a5b9 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 15 Feb 2018 23:53:45 -0800 Subject: [PATCH 10/64] Rationalize struct allocation into ue_py_uscriptstruct_alloc() -Handles intiailization of ustruct, copying from existing data, and whether to hold on to ref or not -Needed to allow other explicit types such as FVector/FRotator/etc to use same code path --- .../Private/UEPyUScriptStruct.cpp | 40 +++++++------ .../Private/UEPyUScriptStruct.h | 4 +- .../Private/Wrappers/UEPyFTransform.cpp | 56 +++++-------------- .../Private/Wrappers/UEPyFTransform.h | 4 -- 4 files changed, 41 insertions(+), 63 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp index 0a536c63c..098976178 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp @@ -244,6 +244,28 @@ 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; @@ -262,22 +284,10 @@ static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, Py PyErr_SetString(PyExc_Exception, "argument is not a UScriptStruct"); return -1; } - ue_py_uscriptstruct_alloc(self, (UScriptStruct *)py_u_obj->ue_object); + ue_py_uscriptstruct_alloc(self, (UScriptStruct *)py_u_obj->ue_object, nullptr, false); return 0; } -void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *self, UScriptStruct* in_u_struct) -{ - self->u_struct = in_u_struct; - 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; -} - static PyObject *ue_py_uscriptstruct_richcompare(ue_PyUScriptStruct *u_struct1, PyObject *py_obj, int op) { ue_PyUScriptStruct *u_struct2 = py_ue_is_uscriptstruct(py_obj); @@ -336,9 +346,7 @@ void ue_python_init_uscriptstruct(PyObject *ue_module) PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *in_data) { ue_PyUScriptStruct* ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); - ue_py_uscriptstruct_alloc(ret, u_struct); - ret->u_struct->CopyScriptStruct(ret->data, in_data); - ret->original_data = in_data; + 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 b2bb79c24..54dfa6262 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.h @@ -16,11 +16,11 @@ typedef struct PyObject *py_ue_new_uscriptstruct(UScriptStruct *, uint8 *); PyObject *py_ue_wrap_uscriptstruct(UScriptStruct *, uint8 *); -void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *, UScriptStruct *); +void ue_py_uscriptstruct_alloc(ue_PyUScriptStruct *, UScriptStruct *, uint8 const*, bool); PyObject *ue_py_uscriptstruct_get_ptr(ue_PyUScriptStruct *, PyObject *); ue_PyUScriptStruct *py_ue_is_uscriptstruct(PyObject *); -inline uint8* py_ue_uscriptstruct_get_data(ue_PyUScriptStruct *py_u_struct) +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); } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 47db65727..2b94de4fc 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -23,6 +23,7 @@ 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(py_ue_ftransform_get(self).GetRelativeTransform(py_ue_ftransform_get(py_transform))); } @@ -109,9 +110,9 @@ static PyGetSetDef ue_PyFTransform_getseters[] = { static PyObject *ue_PyFTransform_str(ue_PyFTransform *self) { - FVector vec = py_ue_ftransform_get(self).GetTranslation(); - FRotator rot = py_ue_ftransform_get(self).Rotator(); - FVector scale = py_ue_ftransform_get(self).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), @@ -170,7 +171,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject return -1; } - ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get()); + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); if (py_translation) { @@ -292,6 +293,7 @@ void ue_python_init_ftransform(PyObject *ue_module) ue_PyFTransformType.tp_new = PyType_GenericNew; ue_PyFTransformType.tp_init = (initproc)ue_py_ftransform_init; + //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? ue_PyFTransformType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; memset(&ue_PyFTransform_number_methods, 0, sizeof(PyNumberMethods)); @@ -309,48 +311,20 @@ void ue_python_init_ftransform(PyObject *ue_module) PyObject *py_ue_new_ftransform(const FTransform& transform) { - //ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); - //ret->transform = transform; - //return (PyObject *)ret; - - ue_PyFTransform *xfm_ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); + ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); - { - ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)xfm_ret; - UScriptStruct *u_struct = TBaseStructure::Get(); - uint8 const * const data = (uint8 const*)&transform; - - 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 = struct_data; - ret->is_ptr = 0; - } - - return (PyObject *)xfm_ret; + 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 *xfm_ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); - - { - ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)xfm_ret; - UScriptStruct *u_struct = TBaseStructure::Get(); - uint8 *data = (uint8*)transform_ptr; - - 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; - } - - return (PyObject *)xfm_ret; + ue_PyFTransform *ret = (ue_PyFTransform *)PyObject_New(ue_PyFTransform, &ue_PyFTransformType); + + ue_py_uscriptstruct_alloc(&ret->py_base, TBaseStructure::Get(), (uint8*)transform_ptr, true); + + return (PyObject *)ret; } ue_PyFTransform *py_ue_is_ftransform(PyObject *obj) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h index a4c4d5073..6e5dedfb8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h @@ -7,10 +7,6 @@ extern PyTypeObject ue_PyUScriptStructType; typedef struct { - //PyObject_HEAD - ///* Type-specific fields go here. */ - //FTransform transform; - ue_PyUScriptStruct py_base; } ue_PyFTransform; From f0d4022bb71a2b401351163f1b3acd342d1b1f01 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 16 Feb 2018 22:08:51 -0800 Subject: [PATCH 11/64] Modify PyFVector & PyFTransform to be children of ue4's native FVector & FTransform NOTE: We just wrote out to original pointer block; now we need to update our local shadow copy This might be unnecessary --- .../Slate/UEPySPythonEditorViewport.cpp | 2 +- .../UnrealEnginePython/Private/UEPyEditor.cpp | 4 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 5 +- .../Private/UEPyUScriptStruct.cpp | 6 ++ .../Private/UEPyVisualLogger.cpp | 2 +- .../Private/UObject/UEPyActor.cpp | 2 +- .../Private/UObject/UEPyAudio.cpp | 2 +- .../Private/UObject/UEPyController.cpp | 2 +- .../Private/UObject/UEPyMaterial.cpp | 6 +- .../Private/UObject/UEPyMovements.cpp | 4 +- .../Private/UObject/UEPyPhysics.cpp | 16 ++-- .../Private/UObject/UEPySequencer.cpp | 2 +- .../Private/UObject/UEPyTraceAndSweep.cpp | 6 +- .../Private/UObject/UEPyTransform.cpp | 2 +- .../Private/UObject/UEPyViewport.cpp | 2 +- .../Wrappers/UEPyFMorphTargetDelta.cpp | 4 +- .../Private/Wrappers/UEPyFQuat.cpp | 2 +- .../Private/Wrappers/UEPyFRandomStream.cpp | 2 +- .../Wrappers/UEPyFRawAnimSequenceTrack.cpp | 4 +- .../Private/Wrappers/UEPyFRawMesh.cpp | 8 +- .../Private/Wrappers/UEPyFRotator.cpp | 2 +- .../Private/Wrappers/UEPyFSoftSkinVertex.cpp | 8 +- .../Private/Wrappers/UEPyFTransform.cpp | 12 +-- .../Private/Wrappers/UEPyFVector.cpp | 94 +++++++++++-------- .../Private/Wrappers/UEPyFVector.h | 14 ++- 25 files changed, 120 insertions(+), 93 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp index 7874cf9d5..b2708d050 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 { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index f674807e4..c5a13c3f6 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -48,7 +48,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) @@ -220,7 +220,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) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index e3b131800..678b96a6e 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -2366,8 +2366,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) // check for FVector if (casted_struct == TBaseStructure::Get()) { - FVector vec = *casted_prop->ContainerPtrToValuePtr(buffer); - return py_ue_new_fvector(vec); + return py_ue_new_fvector_ptr(casted_prop->ContainerPtrToValuePtr(buffer)); } if (casted_struct == TBaseStructure::Get()) { @@ -2758,7 +2757,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer) = py_vec->vec; + *casted_prop->ContainerPtrToValuePtr(buffer) = py_ue_fvector_get(py_vec); return true; } } diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp index 098976178..7334ab2ef 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp @@ -189,6 +189,12 @@ static int ue_PyUScriptStruct_setattro(ue_PyUScriptStruct *self, PyObject *attr_ { if (ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self))) { + 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"); diff --git a/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp b/Source/UnrealEnginePython/Private/UEPyVisualLogger.cpp index 8ec49d0ae..8941c9a40 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 e54c7ec00..b739924a4 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp @@ -780,7 +780,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) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp index 8f319db59..4aecb46db 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyAudio.cpp @@ -129,7 +129,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_INCREF(Py_None); return Py_None; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp index 3dcd6e2a2..6c35410a5 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyController.cpp @@ -95,7 +95,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/UEPyMaterial.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp index 3b23d0189..5efaf83bc 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp @@ -132,9 +132,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/UEPyMovements.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp index 3ea892907..dbe5f91bf 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMovements.cpp @@ -146,7 +146,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; @@ -335,7 +335,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/UEPyPhysics.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp index 01dca4b04..371f2087d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp @@ -74,7 +74,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; @@ -124,7 +124,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; @@ -174,7 +174,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; @@ -224,7 +224,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; @@ -274,7 +274,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; @@ -356,7 +356,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; @@ -479,7 +479,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) @@ -487,7 +487,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 4751bbd58..e0b819067 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -741,7 +741,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); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp index 3b399cd3c..5407d5134 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTraceAndSweep.cpp @@ -29,7 +29,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) { @@ -70,7 +70,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) { @@ -158,7 +158,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 d6f2041da..6c86608e7 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp @@ -25,7 +25,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)); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp index 364947cc3..cbd8d78ee 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp @@ -94,7 +94,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; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp index 0b39d4073..eeaf91a2c 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/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index 843e9cb78..10253b312 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -189,7 +189,7 @@ static PyObject *ue_py_fquat_sub(ue_PyFQuat *self, PyObject *value) { 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; + FVector vec = self->quat * py_ue_fvector_get(py_vec); return py_ue_new_fvector(vec); } if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRandomStream.cpp index a61509f18..f36de51d1 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 300608cc9..e6a10a23c 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp @@ -42,7 +42,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) { @@ -67,7 +67,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) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp index 04164b490..49456238a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawMesh.cpp @@ -26,7 +26,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 { @@ -261,7 +261,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 { @@ -322,7 +322,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 { @@ -384,7 +384,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 896a49f66..8c2bcb733 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -168,7 +168,7 @@ 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 = self->rot.RotateVector(py_ue_fvector_get(py_vec)); return py_ue_new_fvector(vec); } else if (PyNumber_Check(value)) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp index 1cce29b12..a94191330 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp @@ -27,7 +27,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"); @@ -44,7 +44,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"); @@ -61,7 +61,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"); @@ -78,7 +78,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 2b94de4fc..3d734e4bf 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -58,7 +58,7 @@ static int py_ue_ftransform_set_translation(ue_PyFTransform *self, PyObject *val { if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) { - py_ue_ftransform_get(self).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"); @@ -91,7 +91,7 @@ static int py_ue_ftransform_set_scale(ue_PyFTransform *self, PyObject *value, vo { if (ue_PyFVector *py_vec = py_ue_is_fvector(value)) { - py_ue_ftransform_get(self).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"); @@ -177,7 +177,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject { if (ue_PyFVector *py_vec = py_ue_is_fvector(py_translation)) { - py_ue_ftransform_get(self).SetTranslation(py_vec->vec); + py_ue_ftransform_get(self).SetTranslation(py_ue_fvector_get(py_vec)); } else { @@ -252,7 +252,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 { @@ -293,13 +293,13 @@ void ue_python_init_ftransform(PyObject *ue_module) ue_PyFTransformType.tp_new = PyType_GenericNew; ue_PyFTransformType.tp_init = (initproc)ue_py_ftransform_init; - //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? - ue_PyFTransformType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; memset(&ue_PyFTransform_number_methods, 0, sizeof(PyNumberMethods)); ue_PyFTransformType.tp_as_number = &ue_PyFTransform_number_methods; ue_PyFTransform_number_methods.nb_multiply = (binaryfunc)ue_py_ftransform_mul; + //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? + ue_PyFTransformType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; ue_PyFTransformType.tp_base = &ue_PyUScriptStructType; if (PyType_Ready(&ue_PyFTransformType) < 0) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index ba9ffa9ef..8ec109aa0 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -2,24 +2,24 @@ 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 +31,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 +42,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 +53,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 +64,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 +85,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 +93,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 +103,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 +111,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 +121,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 +129,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 +148,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 +191,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 +211,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,11 +231,11 @@ 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)) { @@ -257,13 +257,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 +289,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 +306,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 +331,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 +342,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 +372,10 @@ 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; + //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? + ue_PyFVectorType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; + ue_PyFVectorType.tp_base = &ue_PyUScriptStructType; + if (PyType_Ready(&ue_PyFVectorType) < 0) return; @@ -381,13 +387,23 @@ 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 +423,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 bdc9df770..6aba7658f 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h @@ -4,15 +4,21 @@ #include "UnrealEnginePython.h" +extern PyTypeObject ue_PyUScriptStructType; + typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - FVector vec; + 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 From dcf7ed13b299f8df391dc1aeb81502dd4b0891c8 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 16 Feb 2018 23:43:21 -0800 Subject: [PATCH 12/64] Making PyFRotator derive from UE4's FRotator --- .../Slate/UEPySPythonEditorViewport.cpp | 4 +- .../UnrealEnginePython/Private/UEPyEditor.cpp | 4 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 5 +- .../Private/UObject/UEPyActor.cpp | 2 +- .../Private/UObject/UEPyTransform.cpp | 4 +- .../Private/UObject/UEPyViewport.cpp | 2 +- .../Private/Wrappers/UEPyFRotator.cpp | 71 +++++++++++-------- .../Private/Wrappers/UEPyFRotator.h | 14 ++-- .../Private/Wrappers/UEPyFTransform.cpp | 6 +- .../Private/Wrappers/UEPyFVector.cpp | 2 +- 10 files changed, 66 insertions(+), 48 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp index b2708d050..4dc729e9e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonEditorViewport.cpp @@ -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 { @@ -185,7 +185,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/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index c5a13c3f6..2af25d800 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -56,7 +56,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"); @@ -228,7 +228,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 diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 678b96a6e..d2f8133e5 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -2370,8 +2370,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) } if (casted_struct == TBaseStructure::Get()) { - FRotator rot = *casted_prop->ContainerPtrToValuePtr(buffer); - return py_ue_new_frotator(rot); + return py_ue_new_frotator_ptr(casted_prop->ContainerPtrToValuePtr(buffer)); } if (casted_struct == TBaseStructure::Get()) { @@ -2770,7 +2769,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) { if (casted_prop->Struct == TBaseStructure::Get()) { - *casted_prop->ContainerPtrToValuePtr(buffer) = py_rot->rot; + *casted_prop->ContainerPtrToValuePtr(buffer) = py_ue_frotator_get(py_rot); return true; } } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp index b739924a4..442a85ea8 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp @@ -788,7 +788,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); } AActor *actor = nullptr; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp index 6c86608e7..c10a17dbd 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp @@ -65,7 +65,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 @@ -109,7 +109,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/UEPyViewport.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp index cbd8d78ee..4a8db338d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp @@ -120,7 +120,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; } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index 8c2bcb733..b65507cf4 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -1,27 +1,27 @@ #include "UnrealEnginePythonPrivatePCH.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 +35,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 +50,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 +65,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 +90,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 +132,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 +149,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 +168,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_ue_fvector_get(py_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 +185,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 +211,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"); } @@ -227,7 +227,7 @@ static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kw if (PyTuple_Size(args) == 1) { if (ue_PyFQuat *py_quat = py_ue_is_fquat(PyTuple_GetItem(args, 0))) { - self->rot = FRotator(py_quat->quat); + py_ue_frotator_get(self) = FRotator(py_quat->quat); return 0; } } @@ -240,9 +240,9 @@ static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kw roll = pitch; } - self->rot.Pitch = pitch; - self->rot.Yaw = yaw; - self->rot.Roll = roll; + py_ue_frotator_get(self).Pitch = pitch; + py_ue_frotator_get(self).Yaw = yaw; + py_ue_frotator_get(self).Roll = roll; return 0; } @@ -263,6 +263,10 @@ 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; + + //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? + ue_PyFRotatorType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; + ue_PyFRotatorType.tp_base = &ue_PyUScriptStructType; if (PyType_Ready(&ue_PyFRotatorType) < 0) return; @@ -271,12 +275,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 +305,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 02db8f74f..868055391 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h @@ -4,15 +4,21 @@ #include "UnrealEnginePython.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/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 3d734e4bf..89b283fde 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -69,7 +69,7 @@ static int py_ue_ftransform_set_rotation(ue_PyFTransform *self, PyObject *value, { if (ue_PyFRotator *py_rot = py_ue_is_frotator(value)) { - py_ue_ftransform_get(self).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"); @@ -228,7 +228,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject { if (ue_PyFRotator *py_rot = py_ue_is_frotator(py_rotation)) { - py_ue_ftransform_get(self).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)) { @@ -273,7 +273,7 @@ static PyObject *ue_py_ftransform_mul(ue_PyFTransform *self, PyObject *value) } 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)) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index 8ec109aa0..b4fe22132 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -239,7 +239,7 @@ static PyObject *ue_py_fvector_mul(ue_PyFVector *self, PyObject *value) } 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)) { From 2b044d7712b180d7a29791cc7bfc1a61c29cd61c Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 17 Feb 2018 00:20:24 -0800 Subject: [PATCH 13/64] Convert PyFQuat to UE4 FQuat base -Also adding TBaseStructure --- .../UnrealEnginePython/Private/UEPyModule.cpp | 29 ++++++- .../UnrealEnginePython/Private/UEPyModule.h | 4 + .../Private/UObject/UEPyTransform.cpp | 4 +- .../Private/Wrappers/UEPyFQuat.cpp | 85 +++++++++++-------- .../Private/Wrappers/UEPyFQuat.h | 14 ++- .../Wrappers/UEPyFRawAnimSequenceTrack.cpp | 2 +- .../Private/Wrappers/UEPyFRotator.cpp | 2 +- .../Private/Wrappers/UEPyFTransform.cpp | 6 +- .../Private/Wrappers/UEPyFVector.cpp | 5 +- 9 files changed, 98 insertions(+), 53 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index d2f8133e5..933354bed 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -83,6 +83,15 @@ static PyObject *init_unreal_engine(void) std::map ue_python_gc; +//Missing map in Class.cpp +UScriptStruct* TBaseStructure::Get() +{ + //static auto ScriptStruct = StaticGetBaseStructureInternal(TEXT("Quat")); + static auto* CoreUObjectPkg = FindObjectChecked(nullptr, TEXT("/Script/CoreUObject")); + static auto ScriptStruct = FindObjectChecked(CoreUObjectPkg, TEXT("Quat")); + return ScriptStruct; +} + static PyObject *py_unreal_engine_py_gc(PyObject * self, PyObject * args) { @@ -2372,10 +2381,13 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer) { return py_ue_new_frotator_ptr(casted_prop->ContainerPtrToValuePtr(buffer)); } + if (casted_struct == TBaseStructure::Get()) + { + return py_ue_new_fquat_ptr(casted_prop->ContainerPtrToValuePtr(buffer)); + } if (casted_struct == TBaseStructure::Get()) { - FTransform* transform_ptr = casted_prop->ContainerPtrToValuePtr(buffer); - return py_ue_new_ftransform_ptr(transform_ptr); + return py_ue_new_ftransform_ptr(casted_prop->ContainerPtrToValuePtr(buffer)); } if (casted_struct == FHitResult::StaticStruct()) { @@ -2776,6 +2788,19 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) 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) = py_ue_fquat_get(py_quat); + return true; + } + } + return false; + } + if (ue_PyFTransform *py_transform = py_ue_is_ftransform(py_obj)) { if (auto casted_prop = Cast(prop)) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.h b/Source/UnrealEnginePython/Private/UEPyModule.h index 3b8a3558b..c0ec64be9 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.h +++ b/Source/UnrealEnginePython/Private/UEPyModule.h @@ -45,6 +45,10 @@ void ue_pydelegates_cleanup(ue_PyUObject *); UClass *unreal_engine_new_uclass(char *, UClass *); UFunction *unreal_engine_add_function(UClass *, char *, PyObject *, uint32); +template<> struct TBaseStructure +{ + static UScriptStruct* Get(); +}; template T *ue_py_check_type(PyObject *py_obj) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp index c10a17dbd..0e60e7ba7 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyTransform.cpp @@ -55,7 +55,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 { @@ -99,7 +99,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 { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index 10253b312..e50ac3ed5 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -7,36 +7,36 @@ static PyObject *py_ue_fquat_angular_distance(ue_PyFQuat *self, PyObject * args) 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()); + 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()); + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisX()); } static PyObject *py_ue_fquat_get_axis_y(ue_PyFQuat *self, PyObject * args) { - return py_ue_new_fvector(self->quat.GetAxisY()); + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisY()); } static PyObject *py_ue_fquat_get_axis_z(ue_PyFQuat *self, PyObject * args) { - return py_ue_new_fvector(self->quat.GetAxisZ()); + return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisZ()); } static PyObject *py_ue_fquat_inverse(ue_PyFQuat *self, PyObject * args) { - return py_ue_new_fquat(self->quat.Inverse()); + return py_ue_new_fquat(py_ue_fquat_get(self).Inverse()); } static PyObject *py_ue_fquat_get_normalized(ue_PyFQuat *self, PyObject * args) { - return py_ue_new_fquat(self->quat.GetNormalized()); + 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(self->quat.Vector()); + return py_ue_new_fvector(py_ue_fquat_get(self).Vector()); } static PyMethodDef ue_PyFQuat_methods[] = { @@ -58,13 +58,13 @@ static PyMethodDef ue_PyFQuat_methods[] = { }; static PyObject *py_ue_fquat_get_x(ue_PyFQuat *self, void *closure) { - return PyFloat_FromDouble(self->quat.X); + 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)) { 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; } @@ -73,13 +73,13 @@ static int py_ue_fquat_set_x(ue_PyFQuat *self, PyObject *value, void *closure) { } static PyObject *py_ue_fquat_get_y(ue_PyFQuat *self, void *closure) { - return PyFloat_FromDouble(self->quat.Y); + 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)) { 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; } @@ -88,13 +88,13 @@ static int py_ue_fquat_set_y(ue_PyFQuat *self, PyObject *value, void *closure) { } static PyObject *py_ue_fquat_get_z(ue_PyFQuat *self, void *closure) { - return PyFloat_FromDouble(self->quat.Z); + 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)) { 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; } @@ -103,13 +103,13 @@ static int py_ue_fquat_set_z(ue_PyFQuat *self, PyObject *value, void *closure) { } static PyObject *py_ue_fquat_get_w(ue_PyFQuat *self, void *closure) { - return PyFloat_FromDouble(self->quat.W); + 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)) { 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; } @@ -128,7 +128,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 = { @@ -170,34 +170,34 @@ static PyTypeObject ue_PyFQuatType = { static PyObject *ue_py_fquat_add(ue_PyFQuat *self, PyObject *value) { - FQuat quat = self->quat; + FQuat quat = py_ue_fquat_get(self); ue_PyFQuat *py_quat = py_ue_is_fquat(value); if (py_quat) { - quat += py_quat->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; + FQuat quat = py_ue_fquat_get(self); ue_PyFQuat *py_quat = py_ue_is_fquat(value); if (py_quat) { - quat -= py_quat->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_ue_fvector_get(py_vec); + 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; + 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; + FQuat quat = py_ue_fquat_get(self); PyObject *f_value = PyNumber_Float(value); float f = PyFloat_AsDouble(f_value); quat *= f; @@ -208,7 +208,7 @@ static PyObject *ue_py_fquat_mul(ue_PyFQuat *self, PyObject *value) { } static PyObject *ue_py_fquat_div(ue_PyFQuat *self, PyObject *value) { - FQuat quat = self->quat; + FQuat quat = py_ue_fquat_get(self); if (PyNumber_Check(value)) { PyObject *f_value = PyNumber_Float(value); @@ -232,13 +232,13 @@ static Py_ssize_t ue_py_fquat_seq_length(ue_PyFQuat *self) { 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"); } @@ -250,10 +250,10 @@ static int ue_py_fquat_init(ue_PyFQuat *self, PyObject *args, PyObject *kwargs) 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; + 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; } @@ -275,6 +275,10 @@ 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; + //NOTE: Should this be required? Shouldn't it automatically get inherited from the base type? + ue_PyFQuatType.tp_call = (ternaryfunc)ue_py_uscriptstruct_get_ptr; + ue_PyFQuatType.tp_base = &ue_PyUScriptStructType; + if (PyType_Ready(&ue_PyFQuatType) < 0) return; @@ -282,12 +286,21 @@ 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; } +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; @@ -303,7 +316,7 @@ bool py_ue_quat_arg(PyObject *args, FQuat &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 531417e65..e3d37c09d 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h @@ -4,15 +4,21 @@ #include "Runtime/Core/Public/Math/Quat.h" +extern PyTypeObject ue_PyUScriptStructType; + typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ - FQuat quat; + 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/UEPyFRawAnimSequenceTrack.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp index e6a10a23c..11f3e69e0 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRawAnimSequenceTrack.cpp @@ -92,7 +92,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/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index b65507cf4..578fe8fd3 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -227,7 +227,7 @@ static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kw if (PyTuple_Size(args) == 1) { if (ue_PyFQuat *py_quat = py_ue_is_fquat(PyTuple_GetItem(args, 0))) { - py_ue_frotator_get(self) = FRotator(py_quat->quat); + py_ue_frotator_get(self) = FRotator(py_ue_fquat_get(py_quat)); return 0; } } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 89b283fde..9882fcb53 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -80,7 +80,7 @@ static int py_ue_ftransform_set_quaternion(ue_PyFTransform *self, PyObject *valu { if (ue_PyFQuat *py_quat = py_ue_is_fquat(value)) { - py_ue_ftransform_get(self).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"); @@ -232,7 +232,7 @@ static int ue_py_ftransform_init(ue_PyFTransform *self, PyObject *args, PyObject } else if (ue_PyFQuat *py_quat = py_ue_is_fquat(py_rotation)) { - py_ue_ftransform_get(self).SetRotation(py_quat->quat); + py_ue_ftransform_get(self).SetRotation(py_ue_fquat_get(py_quat)); } else { @@ -269,7 +269,7 @@ static PyObject *ue_py_ftransform_mul(ue_PyFTransform *self, PyObject *value) 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)) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index b4fe22132..835b62ea3 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -243,7 +243,7 @@ static PyObject *ue_py_fvector_mul(ue_PyFVector *self, PyObject *value) } 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)) { @@ -391,16 +391,13 @@ PyObject *py_ue_new_fvector(const FVector& vec) { ue_PyFVector *ret = (ue_PyFVector *)PyObject_New(ue_PyFVector, &ue_PyFVectorType); 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; } From 477a5f5b2cc8c9665efc0324be93058aea42c94c Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 17 Feb 2018 00:41:07 -0800 Subject: [PATCH 14/64] FIX: Manually allocating ue_py_uscriptstruct in fquat_init & frotator_init() like with ftransform/fvector FIX: PyFRotator not properly initializing it's member variables when passed in a single parameter --- .../Private/Wrappers/UEPyFQuat.cpp | 2 ++ .../Private/Wrappers/UEPyFRotator.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index e50ac3ed5..ec3b5e960 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -250,6 +250,8 @@ static int ue_py_fquat_init(ue_PyFQuat *self, PyObject *args, PyObject *kwargs) if (!PyArg_ParseTuple(args, "|ffff", &x, &y, &z, &w)) return -1; + 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; diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index 578fe8fd3..f9366b2da 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -225,19 +225,20 @@ 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))) { - py_ue_frotator_get(self) = FRotator(py_ue_fquat_get(py_quat)); - return 0; - } - } - if (!PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) return -1; + + ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); + + if (ue_PyFQuat *py_quat = PyTuple_Size(args) == 1 ? py_ue_is_fquat(PyTuple_GetItem(args, 0)) : nullptr) { + py_ue_frotator_get(self) = FRotator(py_ue_fquat_get(py_quat)); + return 0; + } + if (PyTuple_Size(args) == 1) { - yaw = pitch; - roll = pitch; + pitch = roll; + yaw = roll; } py_ue_frotator_get(self).Pitch = pitch; From d9fc320faf4e0fe218652afbb9d2f46eb88289e6 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 19 Feb 2018 23:52:12 -0800 Subject: [PATCH 15/64] FIX: GetPostGarbageCollect() does not exist in UE4.17; changing to PostGarbageCollect --- Source/UnrealEnginePython/Public/PythonHouseKeeper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index 84096f74b..386e5fcbd 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -40,7 +40,7 @@ class FUnrealEnginePythonHouseKeeper { Singleton = new FUnrealEnginePythonHouseKeeper(); // register a new delegate for the GC - FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); + FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); } return Singleton; } From db120974b318c2fc6c223427e6caa0309219aaef Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 19 Feb 2018 23:52:18 -0800 Subject: [PATCH 16/64] FIX: Bug with order of FRotator initialization --- .../Private/Wrappers/UEPyFRotator.cpp | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index f9366b2da..6c1e3c34f 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -225,25 +225,30 @@ 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 (!PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) - return -1; - - - ue_py_uscriptstruct_alloc(&self->py_base, TBaseStructure::Get(), nullptr, false); - - if (ue_PyFQuat *py_quat = PyTuple_Size(args) == 1 ? py_ue_is_fquat(PyTuple_GetItem(args, 0)) : nullptr) { - py_ue_frotator_get(self) = FRotator(py_ue_fquat_get(py_quat)); - return 0; + if (PyTuple_Size(args) == 3 && PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) + { } - - if (PyTuple_Size(args) == 1) { + 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 + { + return -1; + } + 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; + py_ue_frotator_get(self).Yaw = yaw; + py_ue_frotator_get(self).Roll = roll; return 0; } From eb212bccf42a2003848a73115e7db950dd381788 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 20 Feb 2018 02:45:18 -0800 Subject: [PATCH 17/64] Add save_package_helper: More robust than save_package --- .../UnrealEnginePython/Private/UEPyEngine.cpp | 28 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEngine.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 4 ++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index 74753f4c5..df4ddbb01 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -9,6 +9,7 @@ #include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h" #if WITH_EDITOR #include "PackageTools.h" +#include "PackageHelperFunctions.h" #endif @@ -1054,6 +1055,33 @@ 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)) + { + return PyErr_Format(PyExc_Exception, "unable to save package"); + } + + Py_RETURN_NONE; +} +#endif + PyObject *py_unreal_engine_open_file_dialog(PyObject *self, PyObject * args) { char *title; diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index 9f6b2da00..84d0d7475 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -78,6 +78,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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index e65d6db8b..ef4ceebe2 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -199,7 +199,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, "" }, From 1299cbd82e5da07aae793416da5baa5d5702a31d Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 20 Feb 2018 09:08:13 -0800 Subject: [PATCH 18/64] Add checks using TBaseStructure() instead of searching for FGuid struct by name Add ability to pass flags when creating new uobject using class name e.g. AnimMetaData('name', packge, outer, RF_PUBLIC|RF_STANDALONE) --- .../UnrealEnginePython/Private/UEPyEngine.cpp | 9 +++++---- .../UnrealEnginePython/Private/UEPyModule.cpp | 19 ++++++++++++------- .../Private/UObject/UEPyUserDefinedStruct.cpp | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index df4ddbb01..b236a9e58 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -481,7 +481,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"); @@ -492,7 +492,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) @@ -1075,10 +1075,11 @@ PyObject *py_unreal_engine_save_package_helper(PyObject *self, PyObject *args) if (!SavePackageHelper(pkg, UTF8_TO_TCHAR(name), (EObjectFlags)flags)) { - return PyErr_Format(PyExc_Exception, "unable to save package"); + PyErr_SetString(PyExc_Exception, "unable to save package"); + Py_RETURN_FALSE; } - Py_RETURN_NONE; + Py_RETURN_TRUE; } #endif diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index ef4ceebe2..214a7638b 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -85,12 +85,15 @@ void init_unreal_engine_builtin() std::map ue_python_gc; -//Missing map in Class.cpp +//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); +} UScriptStruct* TBaseStructure::Get() { - //static auto ScriptStruct = StaticGetBaseStructureInternal(TEXT("Quat")); - static auto* CoreUObjectPkg = FindObjectChecked(nullptr, TEXT("/Script/CoreUObject")); - static auto ScriptStruct = FindObjectChecked(CoreUObjectPkg, TEXT("Quat")); + static auto ScriptStruct = StaticGetBaseStructureInternal(TEXT("Quat")); return ScriptStruct; } @@ -1162,11 +1165,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); @@ -1176,6 +1180,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); @@ -3587,7 +3592,7 @@ 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*)(py_ue_uscriptstruct_get_data(ue_py_struct)); } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyUserDefinedStruct.cpp index ddfda0edd..e12b622bd 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) From 7546858eaf83b5cbd2d9343ed56118ed7c61bda7 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 20 Feb 2018 09:25:03 -0800 Subject: [PATCH 19/64] Demarcate K&L specific stuff --- Source/PythonConsole/Private/PythonScriptFactory.cpp | 2 ++ Source/UnrealEnginePython/UnrealEnginePython.Build.cs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/Source/PythonConsole/Private/PythonScriptFactory.cpp b/Source/PythonConsole/Private/PythonScriptFactory.cpp index b5dba512f..01e30cb05 100644 --- a/Source/PythonConsole/Private/PythonScriptFactory.cpp +++ b/Source/PythonConsole/Private/PythonScriptFactory.cpp @@ -5,9 +5,11 @@ UPythonScriptFactory::UPythonScriptFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { + // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process #if !WITH_KNL_PYEXT Formats.Add(FString("py;Python Script")); #endif + // @third party code - END Bebylon bCreateNew = false; bEditAfterNew = true; diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 80b7877d1..fa7a1802e 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -79,7 +79,10 @@ public UnrealEnginePython(ReadOnlyTargetRules Target) : base(Target) public UnrealEnginePython(TargetInfo Target) #endif { + // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process Definitions.Add("WITH_KNL_PYEXT=1"); + // @third party code - END Bebylon + PublicIncludePaths.AddRange( From 24b354f372b38b6739db4c332a19bc3899f8da9d Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 20 Feb 2018 09:28:34 -0800 Subject: [PATCH 20/64] Prep for pull-request: Remove K&L specific additions --- .../Private/PythonScriptFactory.cpp | 6 ---- .../UnrealEnginePython.Build.cs | 32 ------------------- UnrealEnginePython.uplugin | 1 - 3 files changed, 39 deletions(-) diff --git a/Source/PythonConsole/Private/PythonScriptFactory.cpp b/Source/PythonConsole/Private/PythonScriptFactory.cpp index 01e30cb05..a66e98dee 100644 --- a/Source/PythonConsole/Private/PythonScriptFactory.cpp +++ b/Source/PythonConsole/Private/PythonScriptFactory.cpp @@ -5,12 +5,6 @@ UPythonScriptFactory::UPythonScriptFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process -#if !WITH_KNL_PYEXT - Formats.Add(FString("py;Python Script")); -#endif - // @third party code - END Bebylon - bCreateNew = false; bEditAfterNew = true; diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index fa7a1802e..8f3d23f7f 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -79,9 +79,6 @@ public UnrealEnginePython(ReadOnlyTargetRules Target) : base(Target) public UnrealEnginePython(TargetInfo Target) #endif { - // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process - Definitions.Add("WITH_KNL_PYEXT=1"); - // @third party code - END Bebylon @@ -190,35 +187,6 @@ public UnrealEnginePython(TargetInfo Target) string libPath = GetWindowsPythonLibFile(pythonHome); PublicLibraryPaths.Add(Path.GetDirectoryName(libPath)); PublicAdditionalLibraries.Add(libPath); - - // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process - // copy the dlls into the plugins dlls folder, so they don't have to be on the path - string dllsDir = Path.Combine(ModuleDirectory, "../../Binaries", Target.Platform == UnrealTargetPlatform.Win32 ? "Win32" : "Win64"); - try - { - string[] dllsToCopy = - { - "python3.dll", - "python36.dll" - }; - foreach (string dllToCopy in dllsToCopy) - { - // If the dll exist, make sure to set attributes so they are actually accessible - if (File.Exists(Path.Combine(dllsDir, dllToCopy))) - { - File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal); - } - - File.Copy(Path.Combine(pythonHome, dllToCopy), Path.Combine(dllsDir, dllToCopy), true); - File.SetAttributes(Path.Combine(dllsDir, dllToCopy), FileAttributes.Normal); - } - } - catch (System.IO.IOException) { } - catch (System.UnauthorizedAccessException) - { - System.Console.WriteLine("WARNING: Unable to copy python dlls, they are probably in use..."); - } - // @third party code - END Bebylon } else if (Target.Platform == UnrealTargetPlatform.Mac) { diff --git a/UnrealEnginePython.uplugin b/UnrealEnginePython.uplugin index b7637fac6..caa47800f 100644 --- a/UnrealEnginePython.uplugin +++ b/UnrealEnginePython.uplugin @@ -37,5 +37,4 @@ "Enabled": true } ], - "BlacklistTargets": [ "Server" ] } From acc38e81279d2f75ee5041b018c1c6fa90a65c6f Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 21 Feb 2018 13:03:46 -0800 Subject: [PATCH 21/64] Allow FRotator to be initialized with zero parameters --- .../Private/Wrappers/UEPyFRotator.cpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index 6c1e3c34f..e5c9a863a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -223,8 +223,8 @@ 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; - + float pitch = 0, yaw = 0, roll = 0; + if (PyTuple_Size(args) == 3 && PyArg_ParseTuple(args, "|fff", &roll, &pitch, &yaw)) { } @@ -233,12 +233,15 @@ static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kw pitch = roll; yaw = roll; } - else if (ue_PyFQuat *py_quat = PyTuple_Size(args) == 1 ? py_ue_is_fquat(PyTuple_GetItem(args, 0)) : nullptr) + 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; + roll = rot_from_quat.Roll; + pitch = rot_from_quat.Pitch; + yaw = rot_from_quat.Yaw; + } + else if (PyTuple_Size(args) == 0) + { } else { @@ -246,11 +249,11 @@ static int ue_py_frotator_init(ue_PyFRotator *self, PyObject *args, PyObject *kw } 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; + 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) { From fa549ec9a5da953a236bf8dfd3c0b3812c1422c3 Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 21 Feb 2018 14:44:28 -0800 Subject: [PATCH 22/64] Remove memory debug --- .../Private/UEPyUScriptStruct.cpp | 18 +++++++++--------- .../Private/UnrealEnginePythonPrivatePCH.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp index ac1def0d4..247a055d7 100644 --- a/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp +++ b/Source/UnrealEnginePython/Private/UEPyUScriptStruct.cpp @@ -195,7 +195,7 @@ static int ue_PyUScriptStruct_setattro(ue_PyUScriptStruct *self, PyObject *attr_ if (ue_py_convert_pyobject(value, u_property, py_ue_uscriptstruct_get_data(self))) { 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()); @@ -305,10 +305,10 @@ static int ue_py_uscriptstruct_init(ue_PyUScriptStruct *self, PyObject *args, Py static PyObject *py_ue_uscriptstruct_ref(ue_PyUScriptStruct *self, PyObject * args) { 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->is_ptr = 1; + ret->u_struct = self->u_struct; + ret->data = self->original_data; + ret->original_data = self->original_data; + ret->is_ptr = 1; return (PyObject *)ret; } @@ -367,10 +367,10 @@ PyObject *py_ue_new_uscriptstruct(UScriptStruct *u_struct, uint8 *in_data) PyObject *py_ue_wrap_uscriptstruct(UScriptStruct *u_struct, uint8 *data) { ue_PyUScriptStruct *ret = (ue_PyUScriptStruct *)PyObject_New(ue_PyUScriptStruct, &ue_PyUScriptStructType); - ret->u_struct = u_struct; - ret->data = data; - ret->original_data = data; - ret->is_ptr = 0; + ret->u_struct = u_struct; + ret->data = data; + ret->original_data = data; + ret->is_ptr = 0; return (PyObject *)ret; } diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h b/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h index f2723d620..96387c1f0 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h +++ b/Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h @@ -2,7 +2,7 @@ #pragma once -#define UEPY_MEMORY_DEBUG 1 +//#define UEPY_MEMORY_DEBUG 1 //#define UEPY_THREADING 1 #include "UnrealEnginePython.h" From 6d590d3ecb5a2836b97c4ef85e7e1f9081fb9298 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 23 Feb 2018 09:50:26 -0800 Subject: [PATCH 23/64] Extend SCheckBox & add support for CheckboxStyle --- .../Private/Slate/UEPyFSlateStyleSet.cpp | 2 + .../Private/Slate/UEPySCheckBox.cpp | 52 +++++++++++++++++-- .../Private/Slate/UEPySlate.cpp | 9 ++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp index e78713e87..b933c0857 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateStyleSet.cpp @@ -80,6 +80,7 @@ static PyObject *py_ue_fslate_style_set_set(ue_PyFSlateStyleSet *self, PyObject 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); }) }, @@ -195,6 +196,7 @@ static PyObject *py_ue_fslate_style_set_get(ue_PyFSlateStyleSet *self, PyObject 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); }) }, diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp index 4aa458a8e..17621dc7f 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp @@ -6,6 +6,30 @@ #define sw_check_box StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) +static PyObject *py_ue_scheck_box_set_content(ue_PySCheckBox *self, PyObject * args) +{ + PyObject *py_content; + if (!PyArg_ParseTuple(args, "O:set_content", &py_content)) + { + return NULL; + } + + ue_PySWidget *py_swidget = py_ue_is_swidget(py_content); + if (!py_swidget) + { + return PyErr_Format(PyExc_Exception, "argument is not a SWidget"); + } + + + Py_INCREF(py_swidget); + + + sw_check_box->SetContent(py_swidget->s_widget->AsShared()); + + Py_INCREF(self); + return (PyObject *)self; +} + static PyObject *py_ue_scheck_box_is_checked(ue_PySCheckBox *self, PyObject * args) { if (sw_check_box->IsChecked()) { @@ -17,6 +41,7 @@ static PyObject *py_ue_scheck_box_is_checked(ue_PySCheckBox *self, PyObject * ar 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, "" }, { NULL } /* Sentinel */ }; @@ -54,10 +79,28 @@ 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_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_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_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, s_compound_widget.s_widget); return 0; @@ -66,6 +109,7 @@ static int ue_py_scheck_box_init(ue_PySCheckBox *self, PyObject *args, PyObject 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/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 107c3b19b..26be39029 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -25,6 +25,7 @@ #include "UEPySlate.h" #include "PyNativeWidgetHost.h" +#include "IStructureDetailsView.h" FReply FPythonSlateDelegate::OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event) { @@ -1136,6 +1137,14 @@ PyObject *py_unreal_engine_create_structure_detail_view(PyObject *self, PyObject 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; } From cc44b06733d2b41d19f04fde30bfdf3493f77a65 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 26 Feb 2018 19:42:14 -0800 Subject: [PATCH 24/64] Python Plugin feature aadditions around Combobox/SSplitter -Add enum type for native enums mostly used in slate widgets -Added codegen to enable quickly adding new ones -FIX: Memory corruption with incorrect delete in ListView -SPythonCombobox: Allow updating to options source list -Move Combobox to use same structure as SPythonListView (ue_PySPythonComboBox owns ref to the combobox TArray list) -Add ComboBoxStyle -Fixing SSplitter's slot's parameters & on_slot_resized -Making EUserInterfaceActionType a native enum in python Python Plugin: Add Set Folder Path function --- .../Private/Slate/UEPyFMenuBuilder.cpp | 7 +- .../Private/Slate/UEPySPythonComboBox.cpp | 114 ++++++++--- .../Private/Slate/UEPySPythonComboBox.h | 12 +- .../Private/Slate/UEPySPythonListView.cpp | 5 +- .../Private/Slate/UEPySPythonListView.h | 4 +- .../Private/Slate/UEPySSplitter.cpp | 48 ++--- .../Private/Slate/UEPySlate.cpp | 1 - .../Private/Slate/UEPySlate.h | 1 + .../UnrealEnginePython/Private/UEPyEditor.cpp | 2 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 + .../Private/UObject/UEPyActor.cpp | 30 +++ .../Private/UObject/UEPyActor.h | 1 + .../Private/Wrappers/UEPyESlateEnums.cpp | 182 ++++++++++++++---- .../Private/Wrappers/UEPyESlateEnums.h | 2 +- tools/codegen_nativeshim.py | 27 +++ 15 files changed, 317 insertions(+), 121 deletions(-) create mode 100644 tools/codegen_nativeshim.py diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index 1b128f24f..5bd5020d1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -42,8 +42,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)) @@ -65,9 +65,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/UEPySPythonComboBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp index 83dedef20..86e88e4b9 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp @@ -24,15 +24,21 @@ static PyObject *py_ue_spython_combo_box_get_selected_item(ue_PySPythonComboBox static PyObject *py_ue_spython_combo_box_set_selected_item(ue_PySPythonComboBox *self, PyObject * args) { PyObject *py_item; - if (!PyArg_ParseTuple(args, "O", &py_item)) { + if (!PyArg_ParseTuple(args, "O", &py_item)) + { return nullptr; } - for (TSharedPtr item : *(sw_python_combo_box->PythonOptionsSource)) { + for (TSharedPtr& item : self->options_source_list) + { // just for being safe - if (!item.IsValid()) - continue; - if (py_item == item.Get()->py_object) { + if (!item.IsValid()) + { + continue; + } + + if (py_item == item.Get()->py_object) + { sw_python_combo_box->SetSelectedItem(item); break; } @@ -42,19 +48,70 @@ static PyObject *py_ue_spython_combo_box_set_selected_item(ue_PySPythonComboBox return (PyObject *)self; } +static PyObject *py_ue_spython_combo_box_update_options_source_list(ue_PySPythonComboBox *self, PyObject * args) +{ + 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); + sw_python_combo_box->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 */ @@ -80,45 +137,41 @@ PyTypeObject ue_PySPythonComboBoxType = { ue_PySPythonComboBox_methods, /* tp_methods */ }; -static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *args, PyObject *kwargs) { +static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *args, PyObject *kwargs) +{ ue_py_slate_setup_farguments(SPythonComboBox); // first of all check for values PyObject *values = ue_py_dict_get_item(kwargs, "options_source"); - if (!values) { + if (!values) + { PyErr_SetString(PyExc_Exception, "you must specify the combo box items"); return -1; } values = PyObject_GetIter(values); - if (!values) { + if (!values) + { PyErr_SetString(PyExc_Exception, "values field is not an iterable"); + Py_DECREF(values); return -1; } - TArray> *items = new TArray>(); - while (PyObject *item = PyIter_Next(values)) { - Py_INCREF(item); - items->Add(TSharedPtr(new FPythonItem(item))); - } - Py_DECREF(values); - - arguments.OptionsSource(items); + new(&self->options_source_list) TArray>(); + while (PyObject *item = PyIter_Next(values)) + { + Py_INCREF(item); + self->options_source_list.Add(TSharedPtr(new FPythonItem(item))); + } + arguments.OptionsSource(&self->options_source_list); + //TODO: ikrimae: #PyUE: #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 - ue_PySWidget *s_widget_content = nullptr; - - PyObject *content = ue_py_dict_get_item(kwargs, "content"); - if (content) { - s_widget_content = py_ue_is_swidget(content); - if (!s_widget_content) { - PyErr_SetString(PyExc_Exception, "content is not a SWidget"); - return -1; - } - Py_INCREF(s_widget_content); - arguments.Content()[s_widget_content->s_widget]; - } + 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); @@ -138,9 +191,6 @@ static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *ar ue_py_snew(SPythonComboBox, s_panel.s_widget); - // keep track of the list, so we can delete on destruction - sw_python_combo_box->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/UEPySPythonListView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp index 118ac0a5b..7ffb2c28e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp @@ -83,6 +83,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); } @@ -120,7 +121,6 @@ PyTypeObject ue_PySPythonListViewType = { static int ue_py_spython_list_view_init(ue_PySPythonListView *self, PyObject *args, PyObject *kwargs) { - ue_py_slate_setup_farguments(SPythonListView); // first of all check for values @@ -146,6 +146,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: #PyUE: #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"); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h index 6c3937671..d24608932 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.h @@ -8,9 +8,7 @@ extern PyTypeObject ue_PySPythonListViewType; class SPythonListView : public SListView> { public: - ~SPythonListView() { - delete(ItemsSource); - } + }; typedef struct { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp index d4f5e783a..476a22012 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp @@ -7,41 +7,19 @@ static PyObject *py_ue_ssplitter_add_slot(ue_PySSplitter *self, PyObject * args, PyObject *kwargs) { - 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; - } - - ue_PySWidget *py_swidget = py_ue_is_swidget(py_content); - if (!py_swidget) - { - return PyErr_Format(PyExc_Exception, "argument is not a SWidget"); - } - - Py_INCREF(py_swidget); - - SSplitter::FSlot &fslot = sw_splitter->AddSlot(index); - if (size_value > -1) - { - fslot.SizeValue = size_value; - } - if (sizing_rule > -1) - { - fslot.SizingRule = (SSplitter::ESizeRule)sizing_rule; - } - fslot.AttachWidget(py_swidget->s_widget->AsShared()); - + int32 retCode = [&]() { + ue_py_slate_setup_hack_slot_args(SSplitter, sw_splitter); + 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); + + return 0; + }(); + + if (retCode != 0) + { + return PyErr_Format(PyExc_Exception, "could not add horizontal slot"); + } Py_INCREF(self); return (PyObject *)self; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 26be39029..379cb44f6 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -25,7 +25,6 @@ #include "UEPySlate.h" #include "PyNativeWidgetHost.h" -#include "IStructureDetailsView.h" FReply FPythonSlateDelegate::OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event) { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 99a8ffc7b..96812de44 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -415,6 +415,7 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } +// SLATE_DEFAULT_SLOT == SLATE_NAMED_SLOT with difference that slate declarative syntax [] defaults to this slot #define ue_py_slate_farguments_optional_named_slot(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ if (value) {\ if (ue_PySWidget *py_swidget = py_ue_is_swidget(value)) {\ diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 26c374af6..0dcc8b228 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -2196,7 +2196,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")) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 214a7638b..df0a1d49b 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -519,9 +519,11 @@ static PyMethodDef ue_PyUObject_methods[] = { #if WITH_EDITOR { "save_config", (PyCFunction)py_ue_save_config, METH_VARARGS, "" }, + { "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, "" }, + { "get_editor_world_counterpart_actor", (PyCFunction)py_ue_get_editor_world_counterpart_actor, METH_VARARGS, "" }, { "find_actor_by_label", (PyCFunction)py_ue_find_actor_by_label, METH_VARARGS, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp index 0067c4271..b49f55a55 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp @@ -183,6 +183,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.h b/Source/UnrealEnginePython/Private/UObject/UEPyActor.h index 5e46abbb1..bdcd71bb9 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.h @@ -13,6 +13,7 @@ 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 *); #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 *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 71113bd09..afe18d4f8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -1,18 +1,16 @@ #include "UnrealEnginePythonPrivatePCH.h" -static PyObject *py_ue_eslate_enums_get(ue_PyESlateEnums *self, void *closure) -{ - return PyLong_FromLong(self->val); -} - 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 = { @@ -20,7 +18,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 */ @@ -31,7 +29,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 */ @@ -48,20 +46,27 @@ static PyTypeObject ue_PyESlateEnumsType = { ue_PyESlateEnums_getseters, }; -static int ue_py_eslate_enums_init(ue_PyESlateEnums *self, PyObject *args, PyObject *kwargs) { - int val = 0; - if (!PyArg_ParseTuple(args, "i", &val)) - return -1; +static PyObject* ue_PyESlateEnums_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + 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; @@ -69,24 +74,131 @@ 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', + ]), + ] + + for enum_def in native_enums_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("") + ]]]*/ + // 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)); + } + + //[[[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/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]) From 32a4afdc5426acae0e601b2128f4aac0e0b0675e Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 27 Feb 2018 02:48:56 -0800 Subject: [PATCH 25/64] Add autosize option to register_nomad_spawner --- Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp | 10 ++++++---- Source/UnrealEnginePython/Private/Slate/UEPySlate.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 379cb44f6..65b28681e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -666,9 +666,9 @@ 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); + TSharedRef dock_tab = SNew(SDockTab).TabRole(ETabRole::NomadTab).ShouldAutosize(bShouldAutosize); PyObject *py_dock = (PyObject *)ue_py_get_swidget(dock_tab); PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_dock); if (!ret) @@ -1348,7 +1348,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; } @@ -1358,7 +1359,8 @@ PyObject *py_unreal_engine_register_nomad_tab_spawner(PyObject * self, PyObject FOnSpawnTab spawn_tab; TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); - spawn_tab.BindSP(py_delegate, &FPythonSlateDelegate::SpawnPythonTab); + 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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 96812de44..52aebf779 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -516,7 +516,7 @@ class FPythonSlateDelegate : public FPythonSmartDelegate 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); From f7c00eb15331e74de9944dccdb1008bca0bd1f32 Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 28 Feb 2018 01:37:01 -0800 Subject: [PATCH 26/64] Python: Extend create detail view to support EEditDefaultsOnlyNodeVisibility param --- .../Private/Slate/UEPySlate.cpp | 8 +++++-- .../Private/Wrappers/UEPyESlateEnums.cpp | 22 +++++++++++++++++++ .../Private/Wrappers/UEPyFQuat.cpp | 6 ++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 65b28681e..9f423af95 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1020,6 +1020,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)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show; char *kwlist[] = { (char *)"uobject", @@ -1030,10 +1031,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; } @@ -1054,6 +1057,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 = (FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility)defaults_show_visibility; TSharedPtr view = PropertyEditorModule.CreateDetailView(view_args); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index afe18d4f8..49de5867f 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -116,6 +116,14 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'Autosized', 'UserSized', ]), + + EnumDef(name='EEditDefaultsOnlyNodeVisibility', + cppNameScope='FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility', + values=[ + 'Show', + 'Hide', + 'Automatic', + ]), ] @@ -198,6 +206,20 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_ESizingRule, "UserSized" , PyLong_FromLong((int)ESizingRule::UserSized)); } + // 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)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show)); + PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Hide" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Hide)); + PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Automatic" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic)); + } + //[[[end]]] } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index eee7e16ee..d8d084b0e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -15,6 +15,10 @@ 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_rotator(ue_PyFQuat *self, PyObject * args) { + return py_ue_new_frotator(py_ue_fquat_get(self).Rotator()); +} + static PyObject *py_ue_fquat_get_axis_x(ue_PyFQuat *self, PyObject * args) { return py_ue_new_fvector(py_ue_fquat_get(self).GetAxisX()); } @@ -44,7 +48,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, "" }, From 6bed3f98bb3616285fac6b5dd586f3717616896f Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 28 Feb 2018 21:39:21 -0800 Subject: [PATCH 27/64] Extend SScrollBox with remove_slot --- .../Private/Slate/UEPySScrollBox.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp index 0684c89c0..44a3f6744 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp @@ -42,6 +42,25 @@ static PyObject *py_ue_sscroll_box_add_slot(ue_PySScrollBox *self, PyObject * ar return (PyObject *)self; } +static PyObject * py_ue_sscroll_box_remove_slot(ue_PySScrollBox *self, PyObject * args) +{ + PyObject *py_content; + if (!PyArg_ParseTuple(args, "O:remove_slot", &py_content)) + { + return NULL; + } + + ue_PySWidget *py_swidget = py_ue_is_swidget(py_content); + if (!py_swidget) + { + return PyErr_Format(PyExc_Exception, "argument is not a SWidget"); + } + + sw_scroll_box->RemoveSlot(py_swidget->s_widget); + + Py_RETURN_NONE; +} + static PyObject *py_ue_sscroll_box_clear_children(ue_PySScrollBox *self, PyObject * args) { sw_scroll_box->ClearChildren(); @@ -53,6 +72,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 */ }; From 7901d4d15e7174b7b0888c59ed0cc03515c4d213 Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 7 Mar 2018 18:14:30 -0800 Subject: [PATCH 28/64] Adding SExpandableArea widget FIX: Changing slate fargument macros to match slate and make them less confusing. Keeping old ones around to minimize code change FIX: Bug py_ue_swidget_bind_on_mouse_button_up not being properly called Add EMovieSceneDataChangeType & ESlideDirection enums Support for those enums in py_ue_sequencer_changed Add support for py_ue_push_menu --- .../Private/Fbx/UEPyFbxManager.cpp | 3 +- .../Private/Fbx/UEPyFbxObject.cpp | 3 +- .../Private/Slate/UEPySCheckBox.cpp | 19 ++- .../Private/Slate/UEPySDockTab.cpp | 10 ++ .../Private/Slate/UEPySExpandableArea.cpp | 102 ++++++++++++++++ .../Private/Slate/UEPySExpandableArea.h | 12 ++ .../Private/Slate/UEPySWidget.cpp | 2 +- .../Private/Slate/UEPySlate.cpp | 14 +++ .../Private/Slate/UEPySlate.h | 109 +++++++++++++----- .../UEPyFSlateApplication.cpp | 35 ++++++ .../Private/UObject/UEPySequencer.cpp | 9 +- .../Private/Wrappers/UEPyESlateEnums.cpp | 61 ++++++++++ .../Private/Wrappers/UEPyFTransform.cpp | 2 +- 13 files changed, 345 insertions(+), 36 deletions(-) create mode 100644 Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp create mode 100644 Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.h diff --git a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxManager.cpp b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxManager.cpp index b62a20ba8..f0b4103e9 100644 --- a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxManager.cpp +++ b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxManager.cpp @@ -1,6 +1,7 @@ -#if ENGINE_MINOR_VERSION > 12 #include "UnrealEnginePythonPrivatePCH.h" +#if ENGINE_MINOR_VERSION > 12 + #if WITH_EDITOR #include "UEPyFbx.h" diff --git a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp index b9d902a32..c6fd20e08 100644 --- a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp +++ b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxObject.cpp @@ -1,6 +1,7 @@ -#if ENGINE_MINOR_VERSION > 12 #include "UnrealEnginePythonPrivatePCH.h" +#if ENGINE_MINOR_VERSION > 12 + #if WITH_EDITOR #include "UEPyFbx.h" diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp index 17621dc7f..062f62059 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp @@ -2,7 +2,8 @@ #include "UnrealEnginePythonPrivatePCH.h" #include "UEPySCheckBox.h" - +// Needed for PROPERTY_BINDING macro +#include "Widget.h" #define sw_check_box StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) @@ -39,9 +40,25 @@ static PyObject *py_ue_scheck_box_is_checked(ue_PySCheckBox *self, PyObject * ar Py_RETURN_FALSE; } +static PyObject *py_ue_scheck_box_set_is_checked(ue_PySCheckBox *self, PyObject * args) { + 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; + + sw_check_box->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 */ }; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index a26329821..e017c7196 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -33,9 +33,19 @@ static PyObject *py_ue_sdock_tab_new_tab_manager(ue_PySButton *self, PyObject * return py_ue_new_ftab_manager(tab_manager); } + +static PyObject *py_ue_sdock_tab_bring_to_front(ue_PySButton *self, PyObject * args) { + + TSharedPtr parentWindow = sw_dock_tab->GetParentWindow(); + if(parentWindow.Get() == nullptr) + parentWindow->BringToFront(true); + Py_RETURN_NONE; +} + static PyMethodDef ue_PySDockTab_methods[] = { { "set_label", (PyCFunction)py_ue_sdock_tab_set_label, 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, "" }, { NULL } /* Sentinel */ }; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp new file mode 100644 index 000000000..adbedf79c --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpandableArea.cpp @@ -0,0 +1,102 @@ + +#include "UnrealEnginePythonPrivatePCH.h" + +#include "UEPySExpandableArea.h" + + +#define sw_expandable_area StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) + + +static PyObject *py_ue_sexpandable_area_is_expanded(ue_PySCheckBox *self, PyObject * args) { + + if (sw_expandable_area->IsExpanded()) { + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + +static PyObject *py_ue_sexpandable_area_set_expanded(ue_PySCheckBox *self, PyObject * args) { + PyObject *py_bool; + if (!PyArg_ParseTuple(args, "O:set_expanded", &py_bool)) + { + return NULL; + } + + sw_expandable_area->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, s_compound_widget.s_widget); + 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/UEPySWidget.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp index 8b2b40421..8cadc3f6d 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -331,7 +331,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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 9f423af95..0638a6e00 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -203,6 +203,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; @@ -828,6 +841,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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 52aebf779..63d14770c 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -30,6 +30,7 @@ #include "UEPySPanel.h" #include "UEPySGridPanel.h" #include "UEPySBoxPanel.h" +#include "UEPySExpandableArea.h" #include "UEPySHorizontalBox.h" #include "UEPySVerticalBox.h" #include "UEPySViewport.h" @@ -158,6 +159,11 @@ template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widge 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);\ @@ -191,6 +197,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))));\ @@ -198,6 +207,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)));\ @@ -205,6 +216,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)) {\ @@ -215,6 +227,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);\ @@ -224,6 +238,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) {\ @@ -242,7 +258,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)) {\ @@ -252,6 +268,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);\ @@ -261,6 +279,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);\ @@ -271,6 +292,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); \ @@ -278,6 +301,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)) {\ @@ -286,6 +310,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) {\ @@ -300,6 +346,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)) {\ @@ -313,6 +361,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)) {\ @@ -326,6 +376,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)) {\ @@ -353,6 +405,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)) {\ @@ -369,6 +423,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)) {\ @@ -383,6 +439,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)) {\ @@ -397,12 +455,16 @@ 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)));\ }\ } +#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)) {\ @@ -415,26 +477,12 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); }\ } -// SLATE_DEFAULT_SLOT == SLATE_NAMED_SLOT with difference that slate declarative syntax [] defaults to this slot -#define ue_py_slate_farguments_optional_named_slot(param, attribute) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ - if (value) {\ - if (ue_PySWidget *py_swidget = py_ue_is_swidget(value)) {\ - Py_INCREF(py_swidget);\ - arguments.attribute()\ - [\ - py_swidget->s_widget\ - ];\ - }\ - 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 {\ @@ -443,25 +491,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); \ + if (ue_PySWidget *py_swidget = py_ue_is_swidget(value)) {\ + Py_INCREF(py_swidget);\ + arguments.attribute()\ + [\ + py_swidget->s_widget\ + ];\ }\ 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;\ ue_py_slate_farguments_bool("is_enabled", IsEnabled);\ ue_py_slate_farguments_text("tool_tip_text", ToolTipText);\ @@ -510,6 +560,7 @@ 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); diff --git a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp index 21935b116..91f60a87b 100644 --- a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp +++ b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp @@ -2,6 +2,9 @@ #include "UnrealEnginePythonPrivatePCH.h" #include "UEPyFSlateApplication.h" +#include "Framework/Application/MenuStack.h" +#include "Layout/WidgetPath.h" +#include "Slate/UEPySWidget.h" static PyObject *py_ue_get_average_delta_time(PyObject *cls, PyObject * args) @@ -154,6 +157,37 @@ 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 + ue_PySWidget *parent_widget = py_ue_is_swidget(py_parent_widget); + if (!parent_widget) + { + return PyErr_Format(PyExc_Exception, "argument is not a Widget"); + } + + ue_PySWidget *menu_widget = py_ue_is_swidget(py_menu_widget); + if (!menu_widget) + { + return PyErr_Format(PyExc_Exception, "argument is not a Widget"); + } + + FVector2D CursorPos = FVector2D(x, y); + + FSlateApplication::Get().PushMenu(parent_widget->s_widget, FWidgetPath(), menu_widget->s_widget, CursorPos, FPopupTransitionEffect((FPopupTransitionEffect::ESlideDirection)menuSlideDirection)); + 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, "" }, @@ -167,6 +201,7 @@ 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, "" }, { NULL } /* Sentinel */ }; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 80864125c..8a145999a 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -29,7 +29,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; } @@ -55,7 +60,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 } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 49de5867f..4ad4d6e21 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -1,4 +1,5 @@ #include "UnrealEnginePythonPrivatePCH.h" +#include "ISequencer.h" static PyGetSetDef ue_PyESlateEnums_getseters[] = { { NULL } /* Sentinel */ @@ -124,6 +125,30 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'Hide', 'Automatic', ]), + + EnumDef(name='EMovieSceneDataChangeType', + cppNameScope='EMovieSceneDataChangeType', + values=[ + 'TrackValueChanged', + 'TrackValueChangedRefreshImmediately', + 'MovieSceneStructureItemAdded', + 'MovieSceneStructureItemRemoved', + 'MovieSceneStructureItemsChanged', + 'ActiveMovieSceneChanged', + 'RefreshAllImmediately', + 'Unknown', + ]), + + EnumDef(name='ESlideDirection', + cppNameScope='FPopupTransitionEffect::ESlideDirection', + values=[ + 'None', + 'ComboButton', + 'TopMenu', + 'SubMenu', + 'TypeInPopup', + 'ContextMenu', + ]), ] @@ -220,6 +245,42 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Automatic" , PyLong_FromLong((int)FDetailsViewArgs::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: 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)); + } + //[[[end]]] } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 7b008d1ba..fad27f84e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -29,7 +29,7 @@ static PyObject *py_ue_ftransform_get_relative_transform(ue_PyFTransform *self, static PyObject *py_ue_ftransform_get_matrix(ue_PyFTransform *self, PyObject * args) { - FMatrix matrix = self->transform.ToMatrixWithScale(); + FMatrix matrix = py_ue_ftransform_get(self).ToMatrixWithScale(); UScriptStruct *u_struct = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR("Matrix")); if (!u_struct) { From d0893f16462b51ffde7b86fb61b62756ed7d2957 Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 7 Mar 2018 18:58:30 -0800 Subject: [PATCH 29/64] Missing build fixes from last sync --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 12 ------------ .../UnrealEnginePython/Private/UEPySubclassing.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 0706bcf17..751566d2a 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1401,18 +1401,6 @@ UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) return new_object; } -// hack for avoiding loops in class constructors (thanks to the Unreal.js project for the idea) -UClass *ue_py_class_constructor_placeholder = nullptr; -static void UEPyClassConstructor(UClass *u_class, const FObjectInitializer &ObjectInitializer) -{ - if (UPythonClass *u_py_class_casted = Cast(u_class)) - { - ue_py_class_constructor_placeholder = u_class; - } - u_class->ClassConstructor(ObjectInitializer); - ue_py_class_constructor_placeholder = nullptr; -} - int unreal_engine_py_init(ue_PyUObject *, PyObject *, PyObject *); void unreal_engine_init_py_module() diff --git a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp index 5062c987a..11045f856 100644 --- a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp +++ b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp @@ -1,4 +1,18 @@ #include "UnrealEnginePythonPrivatePCH.h" +#include "UObject/UEPyObject.h" +#include "PythonClass.h" + +// hack for avoiding loops in class constructors (thanks to the Unreal.js project for the idea) +UClass *ue_py_class_constructor_placeholder = nullptr; +static void UEPyClassConstructor(UClass *u_class, const FObjectInitializer &ObjectInitializer) +{ + if (UPythonClass *u_py_class_casted = Cast(u_class)) + { + ue_py_class_constructor_placeholder = u_class; + } + u_class->ClassConstructor(ObjectInitializer); + ue_py_class_constructor_placeholder = nullptr; +} int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) { From e5588228a05e768f7f18b5a0ba99d29bf7ba53b4 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 8 Mar 2018 22:13:37 -0800 Subject: [PATCH 30/64] Build fix: Marking unreal_engine_py_init() as extern --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 751566d2a..160b4d847 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1401,7 +1401,7 @@ UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) return new_object; } -int unreal_engine_py_init(ue_PyUObject *, PyObject *, PyObject *); +extern int unreal_engine_py_init(ue_PyUObject *, PyObject *, PyObject *); void unreal_engine_init_py_module() { From 5719a2a97066ef471c2960fe27b26ae62da1068c Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 8 Mar 2018 22:40:10 -0800 Subject: [PATCH 31/64] FIX: Memory leak in menu_builder.make_widget() --- .../UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp | 5 +++-- .../Private/Slate/UEPyFToolBarBuilder.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index 5bd5020d1..6f37092bd 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -31,8 +31,9 @@ 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->s_widget) TSharedRef(self->menu_builder.MakeWidget()); + //PyObject_New(ue_PySWidget, &ue_PySWidgetType); + //new (&ret->s_widget) TSharedRef(self->menu_builder.MakeWidget()); + ue_PySWidget *ret = py_ue_new_swidget(self->menu_builder.MakeWidget(), &ue_PySWidgetType); return (PyObject *)ret; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp index 8a5fe212f..45615a392 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFToolBarBuilder.cpp @@ -102,9 +102,10 @@ static PyObject *py_ue_ftool_bar_builder_end_block_group(ue_PyFToolBarBuilder *s static PyObject *py_ue_ftool_bar_builder_make_widget(ue_PyFToolBarBuilder *self, PyObject * args) { - ue_PySWidget *ret = (ue_PySWidget *)PyObject_New(ue_PySWidget, &ue_PySWidgetType); - ue_py_setup_swidget(ret); - ret->s_widget = self->tool_bar_builder.MakeWidget(); + //ue_PySWidget *ret = (ue_PySWidget *)PyObject_New(ue_PySWidget, &ue_PySWidgetType); + //ue_py_setup_swidget(ret); + //ret->s_widget = self->tool_bar_builder.MakeWidget(); + ue_PySWidget *ret = py_ue_new_swidget(self->tool_bar_builder.MakeWidget(), &ue_PySWidgetType); return (PyObject *)ret; } From 68a2fdf0fc40dfcd2139aa627cba8e2ca56f42e7 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 10 Mar 2018 18:24:41 -0800 Subject: [PATCH 32/64] Sequencer & Editor & Slate Extensions: Editor: -Adding editor_select_component, move_viewport_cameras_to_actor Slate: -get_visibility, is_valid, docktab.get_parent_window, docktab.get_docking_area Sequencer: -sequencer_get_selected_sections --- .../Private/Slate/UEPySDockTab.cpp | 41 +++++++++- .../Private/Slate/UEPySWidget.cpp | 27 +++++++ .../UnrealEnginePython/Private/UEPyEditor.cpp | 76 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEditor.h | 3 + .../UnrealEnginePython/Private/UEPyModule.cpp | 3 + .../Private/UObject/UEPySequencer.cpp | 54 ++++++++++++- .../Private/UObject/UEPySequencer.h | 7 ++ 7 files changed, 204 insertions(+), 7 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index e017c7196..adce269c5 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -1,8 +1,12 @@ #include "UnrealEnginePythonPrivatePCH.h" - #include "UEPySDockTab.h" +#include "Private/Framework/Docking/SDockingArea.h" +#include "SlateWindowHelper.h" +#include "WidgetPath.h" +#include "IMenu.h" +#include "SlateApplication.h" #define sw_dock_tab StaticCastSharedRef(self->s_border.s_compound_widget.s_widget.s_widget) @@ -37,16 +41,47 @@ static PyObject *py_ue_sdock_tab_new_tab_manager(ue_PySButton *self, PyObject * static PyObject *py_ue_sdock_tab_bring_to_front(ue_PySButton *self, PyObject * args) { TSharedPtr parentWindow = sw_dock_tab->GetParentWindow(); - if(parentWindow.Get() == nullptr) - parentWindow->BringToFront(true); + if (parentWindow.Get() != nullptr) + { + parentWindow->HACK_ForceToFront(); + } Py_RETURN_NONE; } +static PyObject *py_ue_sdock_get_parent_window(ue_PySButton *self, PyObject * args) { + + TSharedPtr ParentWindow = sw_dock_tab->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_INCREF(Py_None); + return Py_None; +} + +static PyObject *py_ue_sdock_get_docking_area(ue_PySButton *self, PyObject * args) { + + TSharedPtr DockingArea = sw_dock_tab->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_INCREF(Py_None); + return Py_None; +} + static PyMethodDef ue_PySDockTab_methods[] = { { "set_label", (PyCFunction)py_ue_sdock_tab_set_label, 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 */ }; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp index 8cadc3f6d..ef0549e9d 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -234,6 +234,20 @@ static PyObject *py_ue_swidget_get_type(ue_PySWidget *self, PyObject * args) return PyUnicode_FromString(TCHAR_TO_UTF8(*(self->s_widget->GetTypeAsString()))); } +static PyObject *py_ue_swidget_get_visibility(ue_PySWidget *self, PyObject * args) +{ + if (self->s_widget->GetVisibility().IsVisible()) + { + Py_INCREF(Py_True); + return Py_True; + } + else + { + Py_INCREF(Py_False); + return Py_False; + } +} + static PyObject *py_ue_swidget_get_cached_geometry(ue_PySWidget *self, PyObject * args) { return py_ue_new_fgeometry(self->s_widget->GetCachedGeometry()); @@ -317,10 +331,23 @@ static PyObject *py_ue_swidget_on_mouse_button_up(ue_PySWidget *self, PyObject * Py_RETURN_FALSE; } +static PyObject *py_ue_swidget_is_valid(ue_PySWidget *self, PyObject * args) +{ + TSharedPtr checkPtr = self->s_widget; + if (checkPtr.IsValid()) + { + Py_RETURN_TRUE; + } + + Py_RETURN_FALSE; +} + static PyMethodDef ue_PySWidget_methods[] = { { "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, "" }, + { "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, "" }, diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index cdc133160..08ed35dba 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -27,6 +27,10 @@ #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" PyObject *py_unreal_engine_editor_play_in_viewport(PyObject * self, PyObject * args) @@ -289,6 +293,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) { @@ -1906,6 +1932,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 && !in_actor) + 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 && !in_component) + { + 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) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 02f123875..1e99b67c7 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -11,6 +11,7 @@ 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_deselect_actors(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 *); @@ -64,6 +65,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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 160b4d847..ba596980d 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -244,6 +244,7 @@ static PyMethodDef unreal_engine_methods[] = { { "get_editor_world", py_unreal_engine_get_editor_world, METH_VARARGS, "" }, { "editor_get_selected_actors", py_unreal_engine_editor_get_selected_actors, 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, "" }, { "import_asset", py_unreal_engine_import_asset, METH_VARARGS, "" }, { "export_assets", py_unreal_engine_export_assets, METH_VARARGS, "" }, @@ -315,6 +316,7 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, @@ -946,6 +948,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_remove_track", (PyCFunction)py_ue_sequencer_remove_track, METH_VARARGS, "" }, #endif { "sequencer_sections", (PyCFunction)py_ue_sequencer_sections, METH_VARARGS, "" }, + { "sequencer_get_selected_sections", (PyCFunction)py_ue_sequencer_get_selected_sections, METH_VARARGS, "" }, { "sequencer_track_sections", (PyCFunction)py_ue_sequencer_track_sections, METH_VARARGS, "" }, { "sequencer_possessables", (PyCFunction)py_ue_sequencer_possessables, METH_VARARGS, "" }, { "sequencer_possessables_guid", (PyCFunction)py_ue_sequencer_possessables_guid, METH_VARARGS, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 8a145999a..a1b741a9b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -20,7 +20,14 @@ #include "Sections/MovieSceneVectorSection.h" #include "Runtime/MovieScene/Public/MovieSceneFolder.h" #include "Runtime/MovieScene/Public/MovieSceneSpawnable.h" +#include "Private/SequencerSelection.h" #endif +#include "MovieSceneSection.h" +#include "Set.h" + +namespace { + const FName LevelSequenceEditorName("LevelSequenceEditor"); +} #if WITH_EDITOR PyObject *py_ue_sequencer_changed(ue_PyUObject *self, PyObject * args) @@ -168,7 +175,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) { @@ -615,6 +622,45 @@ PyObject *py_ue_sequencer_sections(ue_PyUObject *self, PyObject * args) return py_sections; } +// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 +#if WITH_KNL_PYEXT +// 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(); + TSet> sectionList = seqSelection.GetSelectedSections(); + + PyObject *py_sections = PyList_New(0); + for (TWeakObjectPtr section : sectionList) + { + ue_PyUObject *ret = ue_get_python_uobject(section.Get()); + 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 +// @third party code - END Bebylon + PyObject *py_ue_sequencer_track_sections(ue_PyUObject *self, PyObject * args) { @@ -756,9 +802,9 @@ PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args) section_transform->AddKey(time, ty, (EMovieSceneKeyInterpolation)interpolation); section_transform->AddKey(time, tz, (EMovieSceneKeyInterpolation)interpolation); - FTransformKey rx = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::X, transform.GetRotation().X, unwind); - FTransformKey ry = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Y, transform.GetRotation().Y, unwind); - FTransformKey rz = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Z, transform.GetRotation().Z, unwind); + FTransformKey rx = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::X, transform.GetRotation().Rotator().Roll, unwind); + FTransformKey ry = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Y, transform.GetRotation().Rotator().Pitch, unwind); + FTransformKey rz = FTransformKey(EKey3DTransformChannel::Rotation, EAxis::Z, transform.GetRotation().Rotator().Yaw, unwind); section_transform->AddKey(time, rx, (EMovieSceneKeyInterpolation)interpolation); section_transform->AddKey(time, ry, (EMovieSceneKeyInterpolation)interpolation); section_transform->AddKey(time, rz, (EMovieSceneKeyInterpolation)interpolation); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index 4e10c1187..a58d63079 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -32,6 +32,11 @@ PyObject *py_ue_sequencer_remove_master_track(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_remove_track(ue_PyUObject *, PyObject *); #endif PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *); +// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 +#if WITH_KNL_PYEXT +PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args); +#endif +// @third party code - END Bebylon PyObject *py_ue_sequencer_possessables(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_possessables_guid(ue_PyUObject *, PyObject *); @@ -42,5 +47,7 @@ PyObject *py_ue_sequencer_add_master_track(ue_PyUObject *, PyObject *); + + PyObject *py_ue_sequencer_add_track(ue_PyUObject *, PyObject *); From 824d26f25d5de9874d0a86afbef60d3e840d143f Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 13 Mar 2018 05:59:54 -0700 Subject: [PATCH 33/64] Python Plugin: Add support for passing delegate function parameters -Adding support for get_archetype & get_archetype_instances Added get_actors_in_folder to UEPyEditor FIX: Python plugin regression in move_viewport_cameras_to_actor logic --- .../UnrealEnginePython/Private/UEPyEditor.cpp | 37 ++++++++++++++- .../UnrealEnginePython/Private/UEPyEditor.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 46 +++++++++++++++++++ .../Private/UObject/UEPyObject.cpp | 27 +++++++++++ .../Private/UObject/UEPyObject.h | 2 + 5 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 08ed35dba..d01f2cf4d 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -153,6 +153,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) { @@ -1951,7 +1984,7 @@ PyObject *py_unreal_engine_move_viewport_cameras_to_actor(PyObject * self, PyObj TArray Components; AActor* const in_actor = ue_py_check_type(py_actor); - if (py_actor && !in_actor) + if (py_actor != Py_None && in_actor == nullptr) return PyErr_Format(PyExc_Exception, "actor argument is not an actor"); if (in_actor) @@ -1960,7 +1993,7 @@ PyObject *py_unreal_engine_move_viewport_cameras_to_actor(PyObject * self, PyObj } UPrimitiveComponent* const in_component = ue_py_check_type(py_component); - if (py_component && !in_component) + if (py_component != Py_None && in_component == nullptr) { return PyErr_Format(PyExc_Exception, "component argument is not a primitive component"); } diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 1e99b67c7..a871dd46b 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -9,6 +9,7 @@ PyObject *py_unreal_engine_get_editor_world(PyObject *, 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_select_actor(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_select_component(PyObject * self, PyObject * args); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index ba596980d..b3020a446 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -243,6 +243,7 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, { "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, "" }, @@ -493,6 +494,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, "" }, @@ -2430,6 +2434,48 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) return false; } + if (PyCallable_Check(py_obj)) + { + if (auto casted_prop = Cast(prop)) + { + FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(buffer); + new(multiscript_delegate) FMulticastScriptDelegate(); + + FScriptDelegate script_delegate; + //TODO: ikrimae: #PyUE: 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_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_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + return true; + } + else if (auto casted_prop = Cast(prop)) + { + FScriptDelegate* script_delegate = casted_prop->GetPropertyValuePtr_InContainer(buffer); + new(script_delegate) FScriptDelegate(); + + //TODO: ikrimae: #PyUE: 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_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_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + return true; + } + + } + if (py_obj == Py_None) { auto casted_prop_class = Cast(prop); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 161d8d2ed..1349ce255 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -1645,6 +1645,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 74a4151ea..3cf8ad817 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -34,6 +34,8 @@ PyObject *py_ue_auto_root(ue_PyUObject *, PyObject *); PyObject *py_ue_save_config(ue_PyUObject *, 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 From 70ad3dcab6903d35498783561dcd24af9a5761ec Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 14 Mar 2018 02:29:56 -0700 Subject: [PATCH 34/64] Add set_game_mode for feditor_viewport_client_set_game_mode --- .../Private/Wrappers/UEPyFEditorViewportClient.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp index 6a30692df..24ea94bd8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp @@ -95,6 +95,17 @@ static PyObject *py_ue_feditor_viewport_client_set_realtime(ue_PyFEditorViewport 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->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, "" }, @@ -107,6 +118,7 @@ static PyMethodDef ue_PyFEditorViewportClient_methods[] = { { "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_game_mode", (PyCFunction)py_ue_feditor_viewport_client_set_game_mode, METH_VARARGS, "" }, { nullptr } /* Sentinel */ }; From 977a076fd9b1a278a03e9ba0b7d3304cf3b87c1d Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 15 Mar 2018 02:02:16 -0700 Subject: [PATCH 35/64] Add missing WITH_EDITOR guards so packaged game builds correctly --- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 +- .../Private/UObject/UEPySequencer.cpp | 78 ++++++------ .../Private/UObject/UEPySequencer.h | 5 +- .../Private/Wrappers/UEPyESlateEnums.cpp | 115 ++++++++++-------- 4 files changed, 107 insertions(+), 93 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index b3020a446..572100d96 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -950,9 +950,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, "" }, + { "sequencer_get_selected_sections", (PyCFunction)py_ue_sequencer_get_selected_sections, METH_VARARGS, "" }, #endif { "sequencer_sections", (PyCFunction)py_ue_sequencer_sections, METH_VARARGS, "" }, - { "sequencer_get_selected_sections", (PyCFunction)py_ue_sequencer_get_selected_sections, METH_VARARGS, "" }, { "sequencer_track_sections", (PyCFunction)py_ue_sequencer_track_sections, METH_VARARGS, "" }, { "sequencer_possessables", (PyCFunction)py_ue_sequencer_possessables, METH_VARARGS, "" }, { "sequencer_possessables_guid", (PyCFunction)py_ue_sequencer_possessables_guid, METH_VARARGS, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index d73c93a64..d21ddb854 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -622,45 +622,6 @@ PyObject *py_ue_sequencer_sections(ue_PyUObject *self, PyObject * args) return py_sections; } -// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 -#if WITH_KNL_PYEXT -// 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(); - TSet> sectionList = seqSelection.GetSelectedSections(); - - PyObject *py_sections = PyList_New(0); - for (TWeakObjectPtr section : sectionList) - { - ue_PyUObject *ret = ue_get_python_uobject(section.Get()); - 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 -// @third party code - END Bebylon - PyObject *py_ue_sequencer_track_sections(ue_PyUObject *self, PyObject * args) { @@ -982,6 +943,45 @@ PyObject *py_ue_sequencer_remove_track(ue_PyUObject *self, PyObject * args) Py_RETURN_FALSE; } +// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 +#if WITH_KNL_PYEXT +// 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(); + TSet> sectionList = seqSelection.GetSelectedSections(); + + PyObject *py_sections = PyList_New(0); + for (TWeakObjectPtr section : sectionList) + { + ue_PyUObject *ret = ue_get_python_uobject(section.Get()); + 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 +// @third party code - END Bebylon + #endif PyObject *py_ue_sequencer_add_track(ue_PyUObject *self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index a58d63079..e6cd32a67 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -30,13 +30,14 @@ 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 *); -#endif -PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *); // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 #if WITH_KNL_PYEXT PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args); #endif // @third party code - END Bebylon +#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 *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 4ad4d6e21..68a01c512 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -1,5 +1,7 @@ #include "UnrealEnginePythonPrivatePCH.h" +#if WITH_EDITOR #include "ISequencer.h" +#endif static PyGetSetDef ue_PyESlateEnums_getseters[] = { { NULL } /* Sentinel */ @@ -118,6 +120,19 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'UserSized', ]), + EnumDef(name='ESlideDirection', + cppNameScope='FPopupTransitionEffect::ESlideDirection', + values=[ + 'None', + 'ComboButton', + 'TopMenu', + 'SubMenu', + 'TypeInPopup', + 'ContextMenu', + ]), + ] + + editor_native_enums_list = [ EnumDef(name='EEditDefaultsOnlyNodeVisibility', cppNameScope='FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility', values=[ @@ -138,40 +153,36 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'RefreshAllImmediately', 'Unknown', ]), - - EnumDef(name='ESlideDirection', - cppNameScope='FPopupTransitionEffect::ESlideDirection', - values=[ - 'None', - 'ComboButton', - 'TopMenu', - 'SubMenu', - 'TypeInPopup', - 'ContextMenu', - ]), ] - - for enum_def in native_enums_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) + 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} {{ - {enumVar_str} = ue_PyESlateEnums_new(&ue_PyESlateEnumsType, nullptr, nullptr); - PyDict_SetItemString(unreal_engine_dict, "{enum_def.name}", (PyObject*){enumVar_str}); - }} + 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) + """, 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}));'); + 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") - cog.outl("}") - cog.outl("") ]]]*/ // Enum Wrapper: ESizeRule { @@ -181,7 +192,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); } @@ -194,7 +205,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); @@ -211,7 +222,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); @@ -225,12 +236,30 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); + } + + #if WITH_EDITOR // Enum Wrapper: EEditDefaultsOnlyNodeVisibility { PyObject* native_EEditDefaultsOnlyNodeVisibility = PyDict_GetItemString(unreal_engine_dict, "EEditDefaultsOnlyNodeVisibility"); @@ -239,7 +268,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show)); PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Hide" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Hide)); PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Automatic" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic)); @@ -253,7 +282,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); @@ -264,23 +293,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "Unknown" , PyLong_FromLong((int)EMovieSceneDataChangeType::Unknown)); } - // 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)); - } - + #endif //[[[end]]] } From 1e617f0072ca63a9ffe74d1f343c5b3ceecf6bf2 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 19 Mar 2018 09:24:03 -0700 Subject: [PATCH 36/64] Lots of fixes for 4.19 --- ...tSyntaxHighlighterTextLayoutMarshaller.cpp | 2 +- .../Private/PyCommandlet.cpp | 2 +- .../Private/Slate/UEPySTextBlock.cpp | 13 ++++++ .../Private/Slate/UEPySlate.cpp | 4 +- .../UnrealEnginePython/Private/UEPyEditor.cpp | 43 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEditor.h | 3 ++ .../UnrealEnginePython/Private/UEPyEngine.cpp | 18 +++++++- .../UnrealEnginePython/Private/UEPyModule.cpp | 9 ++++ .../UnrealEnginePython/Private/UEPyModule.h | 2 + .../Private/UObject/UEPyObject.cpp | 13 ++++++ .../Private/UObject/UEPyObject.h | 1 + .../Private/UObject/UEPyPhysics.cpp | 12 ++++++ .../Private/UObject/UEPySequencer.cpp | 37 ++++++++++++++-- .../Private/UObject/UEPySequencer.h | 2 + .../Private/Wrappers/UEPyESlateEnums.cpp | 8 ++-- .../UnrealEnginePython.Build.cs | 11 ++--- 16 files changed, 163 insertions(+), 17 deletions(-) diff --git a/Source/PythonEditor/Private/PYRichTextSyntaxHighlighterTextLayoutMarshaller.cpp b/Source/PythonEditor/Private/PYRichTextSyntaxHighlighterTextLayoutMarshaller.cpp index b6303bf18..8a62710a4 100644 --- a/Source/PythonEditor/Private/PYRichTextSyntaxHighlighterTextLayoutMarshaller.cpp +++ b/Source/PythonEditor/Private/PYRichTextSyntaxHighlighterTextLayoutMarshaller.cpp @@ -311,7 +311,7 @@ void FPYRichTextSyntaxHighlighterTextLayoutMarshaller::ParseTokens(const FString FRunInfo RunInfo(TEXT("SyntaxHighlight.PY.Normal")); FTextBlockStyle TextBlockStyle = SyntaxTextStyle.NormalTextStyle; - const bool bIsWhitespace = FString(TokenText).TrimTrailing().IsEmpty(); + const bool bIsWhitespace = FString(TokenText).TrimEnd().IsEmpty(); if(!bIsWhitespace) { bool bHasMatchedSyntax = false; diff --git a/Source/UnrealEnginePython/Private/PyCommandlet.cpp b/Source/UnrealEnginePython/Private/PyCommandlet.cpp index 33c243450..91c8edc64 100644 --- a/Source/UnrealEnginePython/Private/PyCommandlet.cpp +++ b/Source/UnrealEnginePython/Private/PyCommandlet.cpp @@ -30,7 +30,7 @@ int32 UPyCommandlet::Main(const FString& CommandLine) const FRegexPattern myPattern(RegexString); FRegexMatcher myMatcher(myPattern, *CommandLine); myMatcher.FindNext(); - FString PyCommandLine = myMatcher.GetCaptureGroup(0).Trim().TrimTrailing(); + FString PyCommandLine = myMatcher.GetCaptureGroup(0).TrimStartAndEnd(); TArray PyArgv; PyArgv.Add(FString()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp index 1b43e0885..ac56e7b4c 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp @@ -18,6 +18,18 @@ static PyObject *py_ue_stext_block_set_text(ue_PySTextBlock *self, PyObject * ar return (PyObject *)self; } +static PyObject *py_ue_stext_block_set_highlight_text(ue_PySTextBlock *self, PyObject * args) { + char *text; + if (!PyArg_ParseTuple(args, "s:set_text", &text)) { + return NULL; + } + + sw_text_block->SetHighlightText(FText::FromString(FString(UTF8_TO_TCHAR(text)))); + + Py_INCREF(self); + return (PyObject *)self; +} + static PyObject *py_ue_stext_block_set_color_and_opacity(ue_PySTextBlock *self, PyObject * args) { PyObject *py_color; @@ -46,6 +58,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 */ }; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 0638a6e00..c087097d4 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1034,7 +1034,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)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show; + int defaults_show_visibility = (int)EEditDefaultsOnlyNodeVisibility::Show; char *kwlist[] = { (char *)"uobject", @@ -1071,7 +1071,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 = (FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility)defaults_show_visibility; + view_args.DefaultsOnlyVisibility = (EEditDefaultsOnlyNodeVisibility)defaults_show_visibility; TSharedPtr view = PropertyEditorModule.CreateDetailView(view_args); diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index d01f2cf4d..77ec01ef5 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -31,6 +31,7 @@ #include "GameFramework/Actor.h" #include "Editor/EditorEngine.h" #include "Components/ActorComponent.h" +#include "UnrealClient.h" PyObject *py_unreal_engine_editor_play_in_viewport(PyObject * self, PyObject * args) @@ -258,6 +259,48 @@ PyObject *py_unreal_engine_editor_deselect_actors(PyObject * self, PyObject * ar return Py_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_play(PyObject * self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index a871dd46b..91bd32979 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -11,6 +11,9 @@ 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_select_actor(PyObject *, PyObject *); PyObject *py_unreal_engine_editor_select_component(PyObject * self, PyObject * args); PyObject *py_unreal_engine_import_asset(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index b236a9e58..c0325868c 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -11,6 +11,7 @@ #include "PackageTools.h" #include "PackageHelperFunctions.h" #endif +#include "HAL/PlatformApplicationMisc.h" PyObject *py_unreal_engine_log(PyObject * self, PyObject * args) @@ -214,12 +215,20 @@ PyObject *py_unreal_engine_get_up_vector(PyObject * self, PyObject * args) PyObject *py_unreal_engine_get_content_dir(PyObject * self, PyObject * args) { +#if ENGINE_MINOR_VERSION >= 18 + return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::ProjectContentDir())); +#else return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameContentDir())); +#endif } PyObject *py_unreal_engine_get_game_saved_dir(PyObject * self, PyObject * args) { +#if ENGINE_MINOR_VERSION >= 18 + return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::ProjectSavedDir())); +#else return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameSavedDir())); +#endif } PyObject * py_unreal_engine_get_game_user_developer_dir(PyObject *, PyObject *) @@ -1313,15 +1322,22 @@ PyObject *py_unreal_engine_clipboard_copy(PyObject * self, PyObject * args) { return nullptr; } - +#if ENGINE_MINOR_VERSION >= 18 + FPlatformApplicationMisc::ClipboardCopy(UTF8_TO_TCHAR(text)); +#else FGenericPlatformMisc::ClipboardCopy(UTF8_TO_TCHAR(text)); +#endif Py_RETURN_NONE; } PyObject *py_unreal_engine_clipboard_paste(PyObject * self, PyObject * args) { FString clipboard; +#if ENGINE_MINOR_VERSION >= 18 + FPlatformApplicationMisc::ClipboardPaste(clipboard); +#else FGenericPlatformMisc::ClipboardPaste(clipboard); +#endif return PyUnicode_FromString(TCHAR_TO_UTF8(*clipboard)); } PyObject *py_unreal_engine_console_exec(PyObject * self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 572100d96..7e56a17b4 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -92,11 +92,14 @@ 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) @@ -247,6 +250,9 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, { "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, "" }, @@ -583,6 +589,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, "" }, @@ -935,6 +942,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, "" }, diff --git a/Source/UnrealEnginePython/Private/UEPyModule.h b/Source/UnrealEnginePython/Private/UEPyModule.h index 9ba399aa0..d293e4b2c 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.h +++ b/Source/UnrealEnginePython/Private/UEPyModule.h @@ -45,10 +45,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/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 1349ce255..c93b52a9b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -1143,6 +1143,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 3cf8ad817..97dcba202 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -27,6 +27,7 @@ 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 *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp index 318fe287f..d2c297211 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyPhysics.cpp @@ -137,7 +137,11 @@ PyObject *py_ue_add_angular_impulse(ue_PyUObject * self, PyObject * args) if (py_obj_b_vel_change && PyObject_IsTrue(py_obj_b_vel_change)) b_vel_change = true; +#if ENGINE_MINOR_VERSION >= 18 + primitive->AddAngularImpulseInRadians(impulse, f_bone_name, b_vel_change); +#else primitive->AddAngularImpulse(impulse, f_bone_name, b_vel_change); +#endif Py_INCREF(Py_None); return Py_None; @@ -237,7 +241,11 @@ PyObject *py_ue_add_torque(ue_PyUObject * self, PyObject * args) if (py_obj_b_accel_change && PyObject_IsTrue(py_obj_b_accel_change)) b_accel_change = true; +#if ENGINE_MINOR_VERSION >= 18 + primitive->AddTorqueInRadians(torque, f_bone_name, b_accel_change); +#else primitive->AddTorque(torque, f_bone_name, b_accel_change); +#endif Py_INCREF(Py_None); return Py_None; @@ -369,7 +377,11 @@ PyObject *py_ue_set_physics_angular_velocity(ue_PyUObject * self, PyObject * arg f_bone_name = FName(UTF8_TO_TCHAR(bone_name)); } +#if ENGINE_MINOR_VERSION >= 18 + primitive->SetPhysicsAngularVelocityInDegrees(new_ang_vel, add_to_current, f_bone_name); +#else primitive->SetPhysicsAngularVelocity(new_ang_vel, add_to_current, f_bone_name); +#endif Py_INCREF(Py_None); return Py_None; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index d21ddb854..9f7baacf6 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -963,12 +963,13 @@ PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * a FLevelSequenceEditorToolkit *toolkit = static_cast(editor); ISequencer *sequencer = toolkit->GetSequencer().Get(); FSequencerSelection seqSelection = sequencer->GetSelection(); - TSet> sectionList = seqSelection.GetSelectedSections(); + TArray sectionList; + sequencer->GetSelectedSections(sectionList); PyObject *py_sections = PyList_New(0); - for (TWeakObjectPtr section : sectionList) + for (UMovieSceneSection* section : sectionList) { - ue_PyUObject *ret = ue_get_python_uobject(section.Get()); + ue_PyUObject *ret = ue_get_python_uobject(section); if (!ret) { Py_DECREF(py_sections); @@ -1066,5 +1067,35 @@ 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"); +} #endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index e6cd32a67..97e5d49c2 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 *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 68a01c512..11ff89d9b 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -134,7 +134,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) editor_native_enums_list = [ EnumDef(name='EEditDefaultsOnlyNodeVisibility', - cppNameScope='FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility', + cppNameScope='EEditDefaultsOnlyNodeVisibility', values=[ 'Show', 'Hide', @@ -269,9 +269,9 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyDict_SetItemString(unreal_engine_dict, "EEditDefaultsOnlyNodeVisibility", (PyObject*)native_EEditDefaultsOnlyNodeVisibility); } - PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Show" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Show)); - PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Hide" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Hide)); - PyObject_SetAttrString((PyObject*)native_EEditDefaultsOnlyNodeVisibility, "Automatic" , PyLong_FromLong((int)FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic)); + 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 diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 4bc2d9cc3..edf4535b0 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -80,7 +80,7 @@ public UnrealEnginePython(TargetInfo Target) #endif { // @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - Workaround for our deployment process - Definitions.Add("WITH_KNL_PYEXT=1"); + PublicDefinitions.Add("WITH_KNL_PYEXT=1"); // @third party code - END Bebylon @@ -130,7 +130,8 @@ public UnrealEnginePython(TargetInfo Target) "RenderCore", "MovieSceneCapture", "Landscape", - "Foliage" + "Foliage", + "ApplicationCore" // ... add private dependencies that you statically link with here ... } ); @@ -236,7 +237,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) { @@ -261,13 +262,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 ***"); } From 4f76b01b916e40006aa4918d47d69db92598bc02 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 22 Mar 2018 14:07:45 -0700 Subject: [PATCH 37/64] Build fixes to allow for standalone builds with python plugin in 4.19 -SkeletalMesh modification/LOD generation not allowed outside of WITH_EDITOR --- .../UnrealEnginePython/Private/UEPyModule.cpp | 25 ++++++++++--------- .../Private/UObject/UEPySkeletal.cpp | 3 +++ .../Private/UObject/UEPySkeletal.h | 3 +++ .../Wrappers/UEPyFMorphTargetDelta.cpp | 2 +- .../Private/Wrappers/UEPyFSoftSkinVertex.cpp | 6 ++++- .../Private/Wrappers/UEPyFSoftSkinVertex.h | 3 ++- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 7e56a17b4..923585552 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -888,6 +888,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "skeleton_add_bone", (PyCFunction)py_ue_skeleton_add_bone, METH_VARARGS, "" }, #endif +#if WITH_EDITOR #if ENGINE_MINOR_VERSION > 12 { "skeletal_mesh_set_soft_vertices", (PyCFunction)py_ue_skeletal_mesh_set_soft_vertices, METH_VARARGS, "" }, { "skeletal_mesh_get_soft_vertices", (PyCFunction)py_ue_skeletal_mesh_get_soft_vertices, METH_VARARGS, "" }, @@ -906,16 +907,16 @@ static PyMethodDef ue_PyUObject_methods[] = { { "skeletal_mesh_get_required_bones", (PyCFunction)py_ue_skeletal_mesh_get_required_bones, 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, "" }, -#if WITH_EDITOR + #pragma warning(suppress: 4191) { "skeletal_mesh_build_lod", (PyCFunction)py_ue_skeletal_mesh_build_lod, METH_VARARGS | METH_KEYWORDS, "" }, -#endif { "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, "" }, { "morph_target_get_deltas", (PyCFunction)py_ue_morph_target_get_deltas, METH_VARARGS, "" }, +#endif // Timer { "set_timer", (PyCFunction)py_ue_set_timer, METH_VARARGS, "" }, @@ -1458,9 +1459,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); @@ -2445,14 +2446,14 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) if (PyCallable_Check(py_obj)) { - if (auto casted_prop = Cast(prop)) + if (auto casted_multicastdelegate_prop = Cast(prop)) { - FMulticastScriptDelegate* multiscript_delegate = casted_prop->GetPropertyValuePtr_InContainer(buffer); + FMulticastScriptDelegate* multiscript_delegate = casted_multicastdelegate_prop->GetPropertyValuePtr_InContainer(buffer); new(multiscript_delegate) FMulticastScriptDelegate(); FScriptDelegate script_delegate; //TODO: ikrimae: #PyUE: 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_prop->SignatureFunction); + 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")); @@ -2461,16 +2462,16 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) // Should not be needed anymore //// re-assign multicast delegate - //casted_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + //casted_multicastdelegate_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); return true; } - else if (auto casted_prop = Cast(prop)) + else if (auto casted_delegate_prop = Cast(prop)) { - FScriptDelegate* script_delegate = casted_prop->GetPropertyValuePtr_InContainer(buffer); + FScriptDelegate* script_delegate = casted_delegate_prop->GetPropertyValuePtr_InContainer(buffer); new(script_delegate) FScriptDelegate(); //TODO: ikrimae: #PyUE: 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_prop->SignatureFunction); + 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")); @@ -2479,7 +2480,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) // Should not be needed anymore //// re-assign multicast delegate - //casted_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); + //casted_delegate_prop->SetPropertyValue_InContainer(buffer, multiscript_delegate); return true; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp index 5fcc60bdd..1f17d083c 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp @@ -197,6 +197,7 @@ PyObject *py_ue_skeleton_add_bone(ue_PyUObject *self, PyObject * args) } #endif +#if WITH_EDITOR #if ENGINE_MINOR_VERSION > 12 PyObject *py_ue_skeletal_mesh_set_soft_vertices(ue_PyUObject *self, PyObject * args) { @@ -1210,3 +1211,5 @@ PyObject *py_ue_skeletal_mesh_to_import_vertex_map(ue_PyUObject *self, PyObject return py_list; } + +#endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h index e40a40f49..bf3db4a77 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 *); @@ -36,3 +38,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/Wrappers/UEPyFMorphTargetDelta.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp index eeaf91a2c..1330ac56c 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFMorphTargetDelta.cpp @@ -73,7 +73,7 @@ static PyObject *ue_PyFMorphTargetDelta_str(ue_PyFMorphTargetDelta *self) static PyTypeObject ue_PyFMorphTargetDeltaType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FMorphTargetDelta", /* tp_name */ - sizeof(ue_PyFSoftSkinVertex), /* tp_basicsize */ + sizeof(ue_PyFMorphTargetDelta), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ 0, /* tp_print */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp index a94191330..b6f7ee1b2 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.cpp @@ -1,3 +1,5 @@ +#if WITH_EDITOR + #include "UnrealEnginePythonPrivatePCH.h" static PyObject *py_ue_fsoft_skin_vertex_get_color(ue_PyFSoftSkinVertex *self, void *closure) @@ -361,4 +363,6 @@ PyObject *py_ue_new_fsoft_skin_vertex(FSoftSkinVertex ss_vertex) ue_PyFSoftSkinVertex *ret = (ue_PyFSoftSkinVertex *)PyObject_New(ue_PyFSoftSkinVertex, &ue_PyFSoftSkinVertexType); new(&ret->ss_vertex) FSoftSkinVertex(ss_vertex); return (PyObject *)ret; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.h index edc386582..8dbb19d38 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFSoftSkinVertex.h @@ -1,6 +1,6 @@ #pragma once #include "UnrealEnginePython.h" - +#if WITH_EDITOR #include "Runtime/Engine/Public/SkeletalMeshTypes.h" #if ENGINE_MINOR_VERSION > 18 @@ -22,3 +22,4 @@ void ue_python_init_fsoft_skin_vertex(PyObject *); PyObject *py_ue_new_fsoft_skin_vertex(FSoftSkinVertex); ue_PyFSoftSkinVertex *py_ue_is_fsoft_skin_vertex(PyObject *); +#endif \ No newline at end of file From c988d7ccc956dbbef94c9177fbb02731c48a9a09 Mon Sep 17 00:00:00 2001 From: ikrima Date: Thu, 22 Mar 2018 14:08:28 -0700 Subject: [PATCH 38/64] Add IsCameraLocked, set_height_override, set_width_override to SBox & FEditorViewportClient --- .../Private/Slate/UEPySBox.cpp | 31 +++++++++++++++++++ .../Wrappers/UEPyFEditorViewportClient.cpp | 8 +++++ 2 files changed, 39 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp index a64b6946d..1b1029ce2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp @@ -28,8 +28,38 @@ static PyObject *py_ue_sbox_set_content(ue_PySBox *self, PyObject * args) return (PyObject *)self; } +static PyObject *py_ue_sbox_set_height_override(ue_PySBox *self, PyObject * args) +{ + float height_override = 0; + if (!PyArg_ParseTuple(args, "f:set_height_override", &height_override)) + { + return NULL; + } + + if (height_override != 0) + sw_box->SetHeightOverride(height_override); + + Py_RETURN_NONE; +} + +static PyObject *py_ue_sbox_set_width_override(ue_PySBox *self, PyObject * args) +{ + float width_override = 0; + if (!PyArg_ParseTuple(args, "f:set_width_override", &width_override)) + { + return NULL; + } + + if (width_override != 0) + sw_box->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 */ }; @@ -73,6 +103,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/Wrappers/UEPyFEditorViewportClient.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp index 24ea94bd8..a6b7effb5 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFEditorViewportClient.cpp @@ -56,6 +56,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; @@ -113,6 +120,7 @@ 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, "" }, From 2ebee127255f0248b464866e339850f6999508b8 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sun, 25 Mar 2018 14:38:06 -0700 Subject: [PATCH 39/64] Add ETabRole, ue_remove_docktab_from_mapping --- .../Private/Slate/UEPySlate.cpp | 20 +++++++++++++- .../Private/Slate/UEPySlate.h | 1 + .../Private/Wrappers/UEPyESlateEnums.cpp | 26 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index c087097d4..2b4af2137 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -25,6 +25,9 @@ #include "UEPySlate.h" #include "PyNativeWidgetHost.h" +#include +#include +#include "UEPySWidget.h" FReply FPythonSlateDelegate::OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event) { @@ -682,7 +685,9 @@ FLinearColor FPythonSlateDelegate::GetterFLinearColor() const TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &args, bool bShouldAutosize) { TSharedRef dock_tab = SNew(SDockTab).TabRole(ETabRole::NomadTab).ShouldAutosize(bShouldAutosize); - PyObject *py_dock = (PyObject *)ue_py_get_swidget(dock_tab); + ue_PySWidget * py_docktab_widget = ue_py_get_swidget(dock_tab); + PyObject *py_dock = (PyObject *)py_docktab_widget; + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", py_dock); if (!ret) { @@ -692,6 +697,10 @@ TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &a { Py_DECREF(ret); } + + SDockTab::FOnTabClosedCallback tabClosedDelegate; + tabClosedDelegate.BindStatic(&ue_remove_docktab_from_mapping); + dock_tab->SetOnTabClosed(tabClosedDelegate); return dock_tab; } @@ -787,6 +796,15 @@ void ue_py_setup_swidget(ue_PySWidget *self) new(&self->s_widget) TSharedRef(SNullWidget::NullWidget); } +void ue_remove_docktab_from_mapping(TSharedRef dock_tab) +{ + ue_PySWidget * py_docktab_widget = ue_py_get_swidget(dock_tab); + //TODO: sai: #PyUE: #BUG: FIX/HACK for how Python spawned tabs aren't properly garbage collected + // after the tabs are closed as holding onto this reference prevents GC from cleaning up the widget + while (((PyObject *)py_docktab_widget)->ob_refcnt > 0) + Py_DECREF(py_docktab_widget); +} + void ue_py_register_swidget(SWidget *s_widget, ue_PySWidget *py_s_widget) { (*py_slate_mapping)[s_widget] = py_s_widget; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 63d14770c..0131f95ff 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -131,6 +131,7 @@ void ue_py_unregister_swidget(SWidget *); void ue_py_setup_swidget(ue_PySWidget *); +static void ue_remove_docktab_from_mapping(TSharedRef dock_tab); PyObject *ue_py_dict_get_item(PyObject *, const char *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 11ff89d9b..a6814ff33 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -130,6 +130,16 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'TypeInPopup', 'ContextMenu', ]), + + EnumDef(name='ETabRole', + cppNameScope='ETabRole', + values=[ + 'MajorTab', + 'PanelTab', + 'NomadTab', + 'DocumentTab', + 'NumRoles' + ]), ] editor_native_enums_list = [ @@ -259,6 +269,22 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); + } + #if WITH_EDITOR // Enum Wrapper: EEditDefaultsOnlyNodeVisibility { From 3e1be6abc76085effe827e1a153dc2adab0f34b2 Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 26 Mar 2018 14:27:25 -0700 Subject: [PATCH 40/64] Add support for restoring expanded state for treeview --- .../Private/Slate/UEPySPythonTreeView.cpp | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp index f274ced5b..f035f5ce3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp @@ -62,7 +62,21 @@ static PyObject *py_ue_spython_tree_view_get_selected_items(ue_PySPythonTreeView TArray> items = sw_python_tree_view->GetSelectedItems(); - for (auto item : items) { + 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) { + + PyObject *py_list = PyList_New(0); + + TSet > ExpandedItems; + sw_python_tree_view->GetExpandedItems(ExpandedItems); + + for (TSharedPtr& item : ExpandedItems) { PyList_Append(py_list, item->py_object); } @@ -90,9 +104,13 @@ static PyObject *py_ue_spython_tree_view_update_item_source_list(ue_PySPythonTre } values = PyObject_GetIter(values); - if (!values) { + if (!values) + { return PyErr_Format(PyExc_Exception, "argument is not an iterable"); - } + } + + TSet> expanded_items; + sw_python_tree_view->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(). @@ -100,21 +118,34 @@ static PyObject *py_ue_spython_tree_view_update_item_source_list(ue_PySPythonTre TArray> tempNewArray; while (PyObject *item = PyIter_Next(values)) { Py_INCREF(item); - tempNewArray.Add(TSharedPtr(new FPythonItem(item))); + tempNewArray.Add(MakeShared(item)); } - for (TSharedPtr& item : self->item_source_list) + for (TSharedPtr& item : self->item_source_list) { Py_XDECREF(item->py_object); } self->item_source_list.Empty(); Move>>(self->item_source_list, tempNewArray); - Py_RETURN_NONE; + + for (TSharedPtr& old_item : expanded_items) + { + for (TSharedPtr& new_item : self->item_source_list) + { + if (old_item->py_object == new_item->py_object) + { + sw_python_tree_view->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, "" }, @@ -195,7 +226,7 @@ static int ue_py_spython_tree_view_init(ue_PySPythonTreeView *self, PyObject *ar { Py_INCREF(item); // keep track of items - self->item_source_list.Add(TSharedPtr(new FPythonItem(item))); + self->item_source_list.Add(MakeShared(item)); } arguments.TreeItemsSource(&self->item_source_list); From d87a2aef62de67b1b26ef32f272fe738f787a8fc Mon Sep 17 00:00:00 2001 From: ikrima Date: Mon, 2 Apr 2018 18:11:22 -0700 Subject: [PATCH 41/64] FIX: Add proper sdocktab support in the python layer and support persistence of tab layout -RegisterTab python delegate now needs to return SDockTab widget from the python layer -Allows for more control over tab spawning. Also, it's important that the python layer does not hold extra references to the docktab as it will prevent the window closing mechanism in UE4 Editor to work (tab window will close but the tab will be registered as open still) --- .../Private/Slate/UEPySDockTab.cpp | 7 ++++ .../Private/Slate/UEPySDockTab.h | 2 + .../Private/Slate/UEPySlate.cpp | 38 +++++++++---------- .../Private/Slate/UEPySlate.h | 2 - 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index adce269c5..54fbd32e2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -141,3 +141,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 42f28f228..08e5a7773 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.h @@ -15,3 +15,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/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 2b4af2137..1464ee5a1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -28,6 +28,7 @@ #include #include #include "UEPySWidget.h" +#include FReply FPythonSlateDelegate::OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event) { @@ -684,23 +685,26 @@ FLinearColor FPythonSlateDelegate::GetterFLinearColor() const TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &args, bool bShouldAutosize) { - TSharedRef dock_tab = SNew(SDockTab).TabRole(ETabRole::NomadTab).ShouldAutosize(bShouldAutosize); - ue_PySWidget * py_docktab_widget = ue_py_get_swidget(dock_tab); - PyObject *py_dock = (PyObject *)py_docktab_widget; - - 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); } - SDockTab::FOnTabClosedCallback tabClosedDelegate; - tabClosedDelegate.BindStatic(&ue_remove_docktab_from_mapping); - dock_tab->SetOnTabClosed(tabClosedDelegate); + TSharedRef dock_tab = StaticCastSharedRef(py_dock->s_border.s_compound_widget.s_widget.s_widget); + + Py_DECREF(py_dock); + return dock_tab; } @@ -796,15 +800,6 @@ void ue_py_setup_swidget(ue_PySWidget *self) new(&self->s_widget) TSharedRef(SNullWidget::NullWidget); } -void ue_remove_docktab_from_mapping(TSharedRef dock_tab) -{ - ue_PySWidget * py_docktab_widget = ue_py_get_swidget(dock_tab); - //TODO: sai: #PyUE: #BUG: FIX/HACK for how Python spawned tabs aren't properly garbage collected - // after the tabs are closed as holding onto this reference prevents GC from cleaning up the widget - while (((PyObject *)py_docktab_widget)->ob_refcnt > 0) - Py_DECREF(py_docktab_widget); -} - void ue_py_register_swidget(SWidget *s_widget, ue_PySWidget *py_s_widget) { (*py_slate_mapping)[s_widget] = py_s_widget; @@ -1433,8 +1428,11 @@ PyObject *py_unreal_engine_invoke_tab(PyObject * self, PyObject * args) { return NULL; } - - FGlobalTabmanager::Get()->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); + FLevelEditorModule& level_editor_module = FModuleManager::GetModuleChecked("LevelEditor"); + TSharedPtr level_editor_tab_manager = level_editor_module.GetLevelEditorTabManager(); + level_editor_tab_manager->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); + // FIX for nomad tabs not docking properly with editor docking areas is to use the editor tab manager to invoke thems + //FGlobalTabmanager::Get()->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); Py_INCREF(Py_None); return Py_None; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 0131f95ff..1a23ba88b 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -131,8 +131,6 @@ void ue_py_unregister_swidget(SWidget *); void ue_py_setup_swidget(ue_PySWidget *); -static void ue_remove_docktab_from_mapping(TSharedRef dock_tab); - PyObject *ue_py_dict_get_item(PyObject *, const char *); template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widget, PyTypeObject *py_type) From 692a7ad200d87a27a0736ae36cd249a17bb7b6c4 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 7 Apr 2018 17:52:02 -0700 Subject: [PATCH 42/64] Make invoke_tab take in TabManager as argument Adding find_actor_by_label_in_world Extending config support Add gconfig_set_string Add ELoadConfigPropagationFlags SaveConfig/saveconfig to section & load variants Add widget_path support Replace python layer moduleloadchecked() with non-crashing version if module is not found --- .../Private/Slate/UEPySPythonComboBox.cpp | 2 +- .../Private/Slate/UEPySPythonListView.cpp | 2 +- .../Private/Slate/UEPySWidget.cpp | 18 + .../Private/Slate/UEPySlate.cpp | 30 +- .../UnrealEnginePython/Private/UEPyEditor.cpp | 17 + .../UnrealEnginePython/Private/UEPyEditor.h | 1 + .../UnrealEnginePython/Private/UEPyEngine.cpp | 35 + .../UnrealEnginePython/Private/UEPyEngine.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 19 +- .../Private/UObject/UEPyObject.cpp | 682 +++++++++++++++++- .../Private/UObject/UEPyObject.h | 5 +- .../Private/Wrappers/UEPyESlateEnums.cpp | 30 + 12 files changed, 823 insertions(+), 19 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp index 86e88e4b9..c82b2e83e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp @@ -164,7 +164,7 @@ static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *ar self->options_source_list.Add(TSharedPtr(new FPythonItem(item))); } arguments.OptionsSource(&self->options_source_list); - //TODO: ikrimae: #PyUE: #BUG: We are on purpose not doing Py_DECREF(values) because we're stealing the reference from _GetIter + //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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp index 7ffb2c28e..5eb3b1a8b 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonListView.cpp @@ -146,7 +146,7 @@ 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: #PyUE: #BUG: We are on purpose not doing Py_DECREF(values) because we're stealing the reference from _GetIter + //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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp index ef0549e9d..fdf5a0063 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -2,6 +2,7 @@ #include "UnrealEnginePythonPrivatePCH.h" #include "UEPySWidget.h" +#include static PyObject *ue_PySWidget_str(ue_PySWidget *self) { @@ -248,6 +249,21 @@ static PyObject *py_ue_swidget_get_visibility(ue_PySWidget *self, PyObject * arg } } +static PyObject *py_ue_swidget_to_string(ue_PySWidget *self, PyObject * args) +{ + return PyUnicode_FromString(TCHAR_TO_UTF8(*(self->s_widget->ToString()))); +} + +static PyObject *py_ue_swidget_get_widget_path(ue_PySWidget *self, PyObject * args) +{ + FString ret; + FWidgetPath OutWidgetPath; + FSlateApplication::Get().GeneratePathToWidgetUnchecked(self->s_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->s_widget->GetCachedGeometry()); @@ -347,6 +363,8 @@ static PyMethodDef ue_PySWidget_methods[] = { { "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, "" }, diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 1464ee5a1..14e919c99 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1423,19 +1423,29 @@ 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; } - FLevelEditorModule& level_editor_module = FModuleManager::GetModuleChecked("LevelEditor"); - TSharedPtr level_editor_tab_manager = level_editor_module.GetLevelEditorTabManager(); - level_editor_tab_manager->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); - // FIX for nomad tabs not docking properly with editor docking areas is to use the editor tab manager to invoke thems - //FGlobalTabmanager::Get()->InvokeTab(FTabId(FName(UTF8_TO_TCHAR(name)))); - - Py_INCREF(Py_None); - return Py_None; +#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; } diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 77ec01ef5..e35914165 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -2406,6 +2406,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 91bd32979..42ba8fb74 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -123,6 +123,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 0e2fab600..aa06ef311 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -549,6 +549,41 @@ PyObject *py_unreal_engine_get_delta_time(PyObject * self, PyObject * args) return PyFloat_FromDouble(FApp::GetDeltaTime()); } +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_find_object(PyObject * self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index 84d0d7475..1c6b09d9e 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -31,6 +31,7 @@ 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 *); +PyObject *py_unreal_engine_find_actor_by_label_in_world(PyObject *, PyObject *); PyObject *py_unreal_engine_find_object(PyObject *, PyObject *); PyObject *py_unreal_engine_find_class(PyObject *, PyObject *); PyObject *py_unreal_engine_find_struct(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 6e902222c..16947c11e 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -320,6 +320,7 @@ 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, "" }, @@ -409,7 +410,8 @@ 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 @@ -535,7 +537,15 @@ static PyMethodDef ue_PyUObject_methods[] = { #endif #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, "" }, @@ -1568,6 +1578,7 @@ 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)); @@ -2454,7 +2465,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) new(multiscript_delegate) FMulticastScriptDelegate(); FScriptDelegate script_delegate; - //TODO: ikrimae: #PyUE: Not sure if this will auto cleanup when the function parameters are destroyed or if the GWorld owner will force it to keep alive + //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")); @@ -2472,7 +2483,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer) FScriptDelegate* script_delegate = casted_delegate_prop->GetPropertyValuePtr_InContainer(buffer); new(script_delegate) FScriptDelegate(); - //TODO: ikrimae: #PyUE: Not sure if this will auto cleanup when the function parameters are destroyed or if the GWorld owner will force it to keep alive + //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")); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index c93b52a9b..16f1164ca 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -9,6 +9,7 @@ #include "UnrealEd.h" #include "Runtime/Core/Public/HAL/FeedbackContextAnsi.h" #endif +#include PyObject *py_ue_get_class(ue_PyUObject * self, PyObject * args) { @@ -641,12 +642,689 @@ 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 +PyObject *py_ue_save_config_to_section(ue_PyUObject *self, PyObject * args, PyObject *kwargs) +{ ue_py_check(self); - self->ue_object->SaveConfig(); + 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; +} + +PyObject *py_ue_load_config(ue_PyUObject *self, PyObject * args, PyObject *kwargs) +{ + ue_py_check(self); + + 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 +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 + +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; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 97dcba202..7dccbe630 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -32,7 +32,10 @@ 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_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 *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index a6814ff33..6829e7f49 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -2,6 +2,7 @@ #if WITH_EDITOR #include "ISequencer.h" #endif +#include static PyGetSetDef ue_PyESlateEnums_getseters[] = { { NULL } /* Sentinel */ @@ -163,6 +164,17 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'RefreshAllImmediately', 'Unknown', ]), + + EnumDef(name='ELoadConfigPropagationFlags', + cppNameScope='ELoadConfigPropagationFlags', + values=[ + 'LCPF_None', + 'LCPF_ReadParentSections', + 'LCPF_PropagateToChildDefaultObjects', + 'LCPF_PropagateToInstances', + 'LCPF_ReloadingConfigData', + 'LCPF_PersistentFlags', + ]), ] def output_cpp_enums(in_enum_list): @@ -319,6 +331,24 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "Unknown" , PyLong_FromLong((int)EMovieSceneDataChangeType::Unknown)); } + // 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)); + } + + #endif //[[[end]]] } From 92a983404b3770f5ea82b907fb0a1f906abef602 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 7 Apr 2018 17:57:55 -0700 Subject: [PATCH 43/64] Missing comment --- Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 16f1164ca..2bc4af6b6 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -835,6 +835,7 @@ PyObject *py_ue_save_config_to_section(ue_PyUObject *self, PyObject * args, PyOb Py_RETURN_NONE; } +//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition PyObject *py_ue_load_config(ue_PyUObject *self, PyObject * args, PyObject *kwargs) { ue_py_check(self); @@ -929,6 +930,7 @@ void CheckMissingSection(const FString& SectionName, const FString& IniFilename) } #endif +//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition PyObject *py_ue_load_config_from_section(ue_PyUObject *self, PyObject * args, PyObject *kwargs) { ue_py_check(self); From 995df4ebb5b7f1975150fd4b0be4a3a294d770e3 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 7 Apr 2018 19:25:52 -0700 Subject: [PATCH 44/64] Fix Non-editor build errors from py_unreal_engine_find_actor_by_label_in_world --- .../UnrealEnginePython/Private/UEPyEngine.cpp | 71 +++++++++---------- .../UnrealEnginePython/Private/UEPyEngine.h | 2 +- .../Private/UObject/UEPyObject.cpp | 36 +++++----- 3 files changed, 55 insertions(+), 54 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index aa06ef311..1a8f6f917 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -342,6 +342,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; @@ -549,42 +584,6 @@ PyObject *py_unreal_engine_get_delta_time(PyObject * self, PyObject * args) return PyFloat_FromDouble(FApp::GetDeltaTime()); } -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_find_object(PyObject * self, PyObject * args) { char *name; diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index 1c6b09d9e..a0373d169 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -31,7 +31,6 @@ 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 *); -PyObject *py_unreal_engine_find_actor_by_label_in_world(PyObject *, PyObject *); PyObject *py_unreal_engine_find_object(PyObject *, PyObject *); PyObject *py_unreal_engine_find_class(PyObject *, PyObject *); PyObject *py_unreal_engine_find_struct(PyObject *, PyObject *); @@ -43,6 +42,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 diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 4c4ac80ed..17ecaedbf 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -910,23 +910,25 @@ PyObject *py_ue_load_config(ue_PyUObject *self, PyObject * args, PyObject *kwarg /** Checks if a section specified as a long package name can be found as short name in ini. - Used below */ #if !UE_BUILD_SHIPPING -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); - } +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 From b9148b2889935949b19d3eaafb6b9e8f0861e615 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sun, 8 Apr 2018 00:56:22 -0700 Subject: [PATCH 45/64] Extending Tab Management: -Adding insert_new_document_tab to be able to add tabs without a register spawner -Fully exposing SDockTab: -Adding proper named slot for content, tab_well_left/rgith/bg -contentpadding, tab role, -on_tab_closed/activated/on can close, persist visual state, tab color scale Add ELoadConfigPropagationFlags as proper enum. Add ESearchPreference & ETabActivationCause --- .../Private/Slate/UEPySDockTab.cpp | 21 ++- .../Private/Slate/UEPySlate.cpp | 106 ++++++++++++- .../Private/Slate/UEPySlate.h | 5 + .../UnrealEnginePython/Private/UEPyModule.cpp | 1 + .../Private/Wrappers/UEPyESlateEnums.cpp | 149 +++++++++++------- 5 files changed, 220 insertions(+), 62 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index 54fbd32e2..ecf0c7708 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -2,6 +2,7 @@ #include "UnrealEnginePythonPrivatePCH.h" #include "UEPySDockTab.h" +#include "SDockTab.h" #include "Private/Framework/Docking/SDockingArea.h" #include "SlateWindowHelper.h" #include "WidgetPath.h" @@ -119,12 +120,20 @@ PyTypeObject ue_PySDockTabType = { static int ue_py_sdock_tab_init(ue_PySDockTab *self, PyObject *args, PyObject *kwargs) { 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, s_border.s_compound_widget.s_widget); return 0; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 14e919c99..a573c0558 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -185,7 +185,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(); @@ -194,6 +194,62 @@ void FPythonSlateDelegate::OnWindowClosed(const TSharedRef &Window) Py_DECREF(ret); } +void FPythonSlateDelegate::OnTabClosed(TSharedRef Tab) +{ + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", (PyObject *)ue_py_get_swidget(Tab)); + if (!ret) + { + unreal_engine_py_log_error(); + return; + } + Py_DECREF(ret); +} + +void FPythonSlateDelegate::OnTabActivated(TSharedRef Tab, ETabActivationCause TabActivationCause) +{ + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, (char *)"Oi", (PyObject *)ue_py_get_swidget(Tab), (int)TabActivationCause); + if (!ret) + { + unreal_engine_py_log_error(); + return; + } + Py_DECREF(ret); +} + +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; @@ -1448,6 +1504,54 @@ PyObject *py_unreal_engine_invoke_tab(PyObject * self, PyObject * args) Py_RETURN_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.s_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 1a23ba88b..7b094be2e 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -115,6 +115,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 *); @@ -582,6 +583,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/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 8ec30c6bc..7257be5c0 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -222,6 +222,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 diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 6829e7f49..393582f04 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -18,35 +18,35 @@ static void ue_PyESlateEnums_dealloc(ue_PyESlateEnums *self) } static PyTypeObject ue_PyESlateEnumsType = { - PyVarObject_HEAD_INIT(NULL, 0) - "unreal_engine.ESlateEnums", /* tp_name */ - sizeof(ue_PyESlateEnums), /* tp_basicsize */ - 0, /* tp_itemsize */ + PyVarObject_HEAD_INIT(NULL, 0) + "unreal_engine.ESlateEnums", /* tp_name */ + sizeof(ue_PyESlateEnums), /* tp_basicsize */ + 0, /* tp_itemsize */ (destructor)ue_PyESlateEnums_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_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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Unreal Engine ESlateEnums", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, + "Unreal Engine ESlateEnums", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, ue_PyESlateEnums_getseters, }; @@ -141,6 +141,31 @@ void ue_python_init_eslate_enums(PyObject *ue_module) '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', + ]), ] editor_native_enums_list = [ @@ -164,17 +189,6 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'RefreshAllImmediately', 'Unknown', ]), - - EnumDef(name='ELoadConfigPropagationFlags', - cppNameScope='ELoadConfigPropagationFlags', - values=[ - 'LCPF_None', - 'LCPF_ReadParentSections', - 'LCPF_PropagateToChildDefaultObjects', - 'LCPF_PropagateToInstances', - 'LCPF_ReloadingConfigData', - 'LCPF_PersistentFlags', - ]), ] def output_cpp_enums(in_enum_list): @@ -297,6 +311,49 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); + } + #if WITH_EDITOR // Enum Wrapper: EEditDefaultsOnlyNodeVisibility { @@ -331,24 +388,6 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_EMovieSceneDataChangeType, "Unknown" , PyLong_FromLong((int)EMovieSceneDataChangeType::Unknown)); } - // 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)); - } - - #endif //[[[end]]] } From aa28f8278f7f8a3d0324e6d45e2b4d0aef78fffd Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 24 Apr 2018 13:54:35 -0700 Subject: [PATCH 46/64] Massive Slate Extensions: -Add EWidgetMode, ECoordSystem -Add functions to allow widget picking editor_is_space_bar_down, editor_get_widget_mode, editor_get_widget_coord_system_space -Add add_window, destroy_window to FApp -Add ability to set window on closed -FIX: is_item_expanded for treeview -FIX: Tab support serialization -FBX: Add support to get bool & get int for fbx properties --- .../Private/Fbx/UEPyFbxProperty.cpp | 10 ++++ .../Private/Slate/UEPySDockTab.cpp | 20 ++++++++ .../Private/Slate/UEPySPythonTreeView.cpp | 8 ++- .../Private/Slate/UEPySWindow.cpp | 21 ++++++++ .../Private/Slate/UEPySlate.cpp | 14 ++++-- .../UEPyFSlateApplication.cpp | 46 +++++++++++++++++ .../UnrealEnginePython/Private/UEPyEditor.cpp | 50 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEditor.h | 3 ++ .../UnrealEnginePython/Private/UEPyModule.cpp | 3 ++ .../Private/Wrappers/UEPyESlateEnums.cpp | 48 ++++++++++++++++++ 10 files changed, 216 insertions(+), 7 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp b/Source/UnrealEnginePython/Private/Fbx/UEPyFbxProperty.cpp index 62a076746..a66134cd2 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/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index ecf0c7708..e74cb2787 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -24,6 +24,25 @@ static PyObject *py_ue_sdock_tab_set_label(ue_PySButton *self, PyObject * args) return (PyObject *)self; } +static PyObject *py_ue_sdock_tab_set_on_tab_closed(ue_PySButton *self, PyObject * args) +{ + 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()->NewStaticSlateDelegate(py_callable); + onTabClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnTabClosed); + + sw_dock_tab->SetOnTabClosed(onTabClosed); + Py_RETURN_NONE; +} + static PyObject *py_ue_sdock_tab_request_close_tab(ue_PySButton *self, PyObject * args) { sw_dock_tab->RequestCloseTab(); @@ -78,6 +97,7 @@ static PyObject *py_ue_sdock_get_docking_area(ue_PySButton *self, PyObject * arg 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, "" }, diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp index f035f5ce3..43fcb4a8d 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonTreeView.cpp @@ -43,14 +43,18 @@ static PyObject *py_ue_spython_tree_view_set_item_expansion(ue_PySPythonTreeView static PyObject *py_ue_spython_tree_view_is_item_expanded(ue_PySPythonTreeView *self, PyObject * args) { PyObject *py_item; - if (!PyArg_ParseTuple(args, "OO:is_item_expanded", &py_item)) + if (!PyArg_ParseTuple(args, "O:is_item_expanded", &py_item)) { return nullptr; } if (TSharedPtr const* foundItem = sw_python_tree_view->Find(py_item)) { - sw_python_tree_view->IsItemExpanded(*foundItem); + bool bItemExpanded = sw_python_tree_view->IsItemExpanded(*foundItem); + if (bItemExpanded) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; } Py_RETURN_NONE; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp index 7d22b4671..c31134e2a 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp @@ -69,6 +69,26 @@ static PyObject *py_ue_swindow_set_content(ue_PySWindow *self, PyObject * args) return (PyObject *)self; } +static PyObject *py_ue_swindow_set_on_window_closed(ue_PySWindow *self, PyObject * args) +{ + 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()->NewStaticSlateDelegate(py_callable); + onWindowClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnWindowClosed); + + sw_window->SetOnWindowClosed(onWindowClosed); + Py_RETURN_NONE; +} + + static PyObject *py_ue_swindow_set_sizing_rule(ue_PySWindow *self, PyObject * args) { int rule; @@ -142,6 +162,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 a573c0558..275ff50a3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -197,27 +197,31 @@ void FPythonSlateDelegate::OnWindowClosed(const TSharedRef &Window) void FPythonSlateDelegate::OnTabClosed(TSharedRef Tab) { FScopePythonGIL gil; - - PyObject *ret = PyObject_CallFunction(py_callable, (char *)"O", (PyObject *)ue_py_get_swidget(Tab)); + 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(ret); + Py_DECREF((PyObject*)py_dock_tab); + } void FPythonSlateDelegate::OnTabActivated(TSharedRef Tab, ETabActivationCause TabActivationCause) { FScopePythonGIL gil; - - PyObject *ret = PyObject_CallFunction(py_callable, (char *)"Oi", (PyObject *)ue_py_get_swidget(Tab), (int)TabActivationCause); + 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() diff --git a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp index 91f60a87b..1887927eb 100644 --- a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp +++ b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp @@ -188,6 +188,50 @@ static PyObject *py_ue_push_menu(PyObject *cls, PyObject * args) 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) + { + PyErr_Format(PyExc_Exception, "window_to_destroy is not an SWindow"); + } + + const bool showImmediately = (py_show_immediately) ? (PyObject_IsTrue(py_show_immediately)) : true; + + FSlateApplication::Get().AddWindow(StaticCastSharedRef(StaticCastSharedRef(py_window->s_compound_widget.s_widget.s_widget)->AsShared()), 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) + { + PyErr_Format(PyExc_Exception, "window_to_destroy is not an SWindow"); + } + + FSlateApplication::Get().DestroyWindowImmediately(StaticCastSharedRef(StaticCastSharedRef(py_window->s_compound_widget.s_widget.s_widget)->AsShared())); + + 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, "" }, @@ -202,6 +246,8 @@ static PyMethodDef ue_PyFSlateApplication_methods[] = { { "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 e35914165..0f324380d 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -301,6 +301,56 @@ PyObject *py_unreal_engine_editor_is_alt_down(PyObject * self, PyObject * args) } +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) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 42ba8fb74..4eadf1123 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -14,6 +14,9 @@ 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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 7257be5c0..51eb9ab27 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -253,6 +253,9 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 393582f04..7b02caa44 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -189,6 +189,27 @@ void ue_python_init_eslate_enums(PyObject *ue_module) '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): @@ -388,6 +409,33 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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, "None", PyLong_FromLong((int)FWidget::EWidgetMode::WM_None)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Translate", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Translate)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Rotate", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Rotate)); + PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Scale", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Scale)); + } + + // 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, "World", PyLong_FromLong((int)ECoordSystem::COORD_World)); + PyObject_SetAttrString((PyObject*)native_ECoordSystem, "Local", PyLong_FromLong((int)ECoordSystem::COORD_Local)); + } #endif //[[[end]]] } From c6229455b99fd68c2368c7d1f8fd1052958bb176 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 1 May 2018 14:39:41 -0700 Subject: [PATCH 47/64] PYTHON FEATURE: Added enum property support to the subclassing API --- .../Private/UEPySubclassing.cpp | 9 ++++ .../Private/UObject/UEPyObject.cpp | 49 +++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp index 11045f856..9a01af58a 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 diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 17ecaedbf..29d381a54 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -2010,6 +2010,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; @@ -2030,9 +2032,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"); } } @@ -2062,16 +2068,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()) { - return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); + scope = self->ue_object; + u_class = UEnumProperty::StaticClass(); + } + else + { + 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)) { @@ -2297,6 +2312,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; From 03bb2057a084afc4ba97258db5d8ece8f6aee12b Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 12 May 2018 02:19:45 -0700 Subject: [PATCH 48/64] Adding expander arrow for multicolumn listview -Also exposing SExpanderArrow widget to PySlate --- .../Private/Slate/UEPySExpanderArrow.cpp | 89 +++++++++++++++++++ .../Private/Slate/UEPySExpanderArrow.h | 18 ++++ .../Slate/UEPySPythonMultiColumnTableRow.cpp | 30 ++++++- .../Slate/UEPySPythonMultiColumnTableRow.h | 42 +++++++-- .../Private/Slate/UEPySlate.cpp | 1 + .../Private/Slate/UEPySlate.h | 3 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 + 7 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp create mode 100644 Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.h diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp new file mode 100644 index 000000000..9e1a28c82 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySExpanderArrow.cpp @@ -0,0 +1,89 @@ + +#include "UnrealEnginePythonPrivatePCH.h" + +#include "UEPySExpanderArrow.h" + + +#define sw_expander_arrow StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) + +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, s_compound_widget.s_widget, StaticCastSharedRef(py_owner_table_row->s_compound_widget.s_widget.s_widget)); + + 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/UEPySPythonMultiColumnTableRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp index 9cb9eda17..a5f0fbbae 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp @@ -7,16 +7,42 @@ #define sw_python_multicolumn_table_row StaticCastSharedRef(self->s_compound_widget.s_widget.s_widget) +static PyObject *py_ue_spython_multicolumn_table_row_set_first_column_name(ue_PySPythonMultiColumnTableRow *self, PyObject * args) +{ + char* column_name = nullptr; + if (!PyArg_ParseTuple(args, "s:set_first_column_name", &column_name)) + { + return nullptr; + } + + sw_python_multicolumn_table_row->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 */ @@ -57,6 +83,8 @@ 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, s_compound_widget.s_widget, StaticCastSharedRef(py_owner_table_view_base->s_compound_widget.s_widget.s_widget), diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h index dc8028e3a..8bc4a958a 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.h @@ -19,10 +19,10 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow& InOwnerTableView, PyObject *in_py_self) { SetPyObject(in_py_self); - SMultiColumnTableRow >::Construct(FSuperRowType::FArguments(), InOwnerTableView); + FSuperRowType::Construct(FSuperRowType::FArguments(), InOwnerTableView); } - TSharedRef GenerateWidgetForColumn(const FName& ColumnName) + virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override { FScopePythonGIL gil; @@ -51,9 +51,31 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow value = s_widget->s_widget; - Py_DECREF(ret); - return value; + 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() + [ + s_widget->s_widget + ]; + Py_DECREF(ret); + return value; + } + else + { + // Lists do not need an expander arrow + TSharedRef value = s_widget->s_widget; + Py_DECREF(ret); + return value; + } } @@ -87,7 +109,7 @@ class SPythonMultiColumnTableRow : public SMultiColumnTableRow RowPythonObject; + + FName firstColumnName = FName("friendlyName"); }; typedef struct { 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/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 275ff50a3..f5238be83 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -896,6 +896,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); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 7b094be2e..e3c20320c 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -42,6 +42,7 @@ #include "UEPySListView.h" #include "UEPySPythonListView.h" #include "UEPySPythonMultiColumnTableRow.h" +#include "UEPySExpanderArrow.h" #include "UEPySTreeView.h" #include "UEPySPythonTreeView.h" #include "UEPySSplitter.h" @@ -154,7 +155,7 @@ template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widge #define ue_py_snew(T, field) ue_py_snew_base(T, field, RequiredArgs::MakeRequiredArgs(), arguments) -#define ue_py_snew_with_args(T, field, args) ue_py_snew_base(T, field, RequiredArgs::MakeRequiredArgs(args), arguments) +#define ue_py_snew_with_args(T, field, ...) ue_py_snew_base(T, field, RequiredArgs::MakeRequiredArgs(__VA_ARGS__), arguments) ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 51eb9ab27..241eaf9bf 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1625,6 +1625,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)); From 8167bc2474bbaa9be94c3597035a3cb76defe611 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 18 May 2018 00:19:08 -0700 Subject: [PATCH 49/64] Added set_metadata_on_property to UEPyObject to set metadata flags on named properties --- .../UnrealEnginePython/Private/UEPyModule.cpp | 1 + .../Private/UObject/UEPyObject.cpp | 27 +++++++++++++++++++ .../Private/UObject/UEPyObject.h | 1 + 3 files changed, 29 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 241eaf9bf..910b92c77 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -738,6 +738,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 diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 29d381a54..7467052c2 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -406,6 +406,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 4bd433a34..4bc238f32 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -91,6 +91,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 *); From 99fd35a482b8e1543dbfd8bc5968e53d66ddee81 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 18 May 2018 00:19:47 -0700 Subject: [PATCH 50/64] Fix SlateIcon support to actually load textures from icons --- .../Private/Slate/UEPyFSlateIcon.cpp | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp index c0618e126..ca3c2847b 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp @@ -62,6 +62,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 { From 5b555b16b04b6683a9e45585246f78528538aba4 Mon Sep 17 00:00:00 2001 From: ikrima Date: Sat, 26 May 2018 23:55:19 -0700 Subject: [PATCH 51/64] exposed CLASS_HAS_NEWER_VERSION added actor_get_level_sequence and class_has_any_flags added class_has_any_flags to check for flags on UClass added py_ue_static_mesh_get_num_triangles to UEPyStaticMesh added py_ue_sequencer_get_all_spawnables tp UEPySequencer added actor_component_set_can_ever_affect_navigation to UEPyActor --- .../UnrealEnginePython/Private/UEPyEditor.cpp | 37 +++ .../UnrealEnginePython/Private/UEPyEditor.h | 2 + .../UnrealEnginePython/Private/UEPyEngine.cpp | 24 ++ .../UnrealEnginePython/Private/UEPyEngine.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 30 ++- .../Private/UObject/UEPyActor.cpp | 55 +++++ .../Private/UObject/UEPyActor.h | 3 + .../Private/UObject/UEPyMaterial.cpp | 73 ++++++ .../Private/UObject/UEPyMaterial.h | 2 + .../Private/UObject/UEPyObject.cpp | 52 ++++ .../Private/UObject/UEPyObject.h | 2 + .../Private/UObject/UEPySequencer.cpp | 34 +++ .../Private/UObject/UEPySequencer.h | 1 + .../Private/UObject/UEPySkeletal.cpp | 24 ++ .../Private/UObject/UEPySkeletal.h | 1 + .../Private/UObject/UEPyStaticMesh.cpp | 32 +++ .../Private/UObject/UEPyStaticMesh.h | 3 + .../Private/UObject/UEPyWorld.cpp | 22 ++ .../Private/UObject/UEPyWorld.h | 1 + .../Private/Wrappers/UEPyESlateEnums.cpp | 227 ++++++++++++++---- 20 files changed, 576 insertions(+), 50 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 0f324380d..683cc2174 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -674,6 +674,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; diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 4eadf1123..a5fa22ae0 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -7,6 +7,8 @@ #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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.cpp b/Source/UnrealEnginePython/Private/UEPyEngine.cpp index 1a8f6f917..949b6a16d 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEngine.cpp @@ -217,6 +217,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 diff --git a/Source/UnrealEnginePython/Private/UEPyEngine.h b/Source/UnrealEnginePython/Private/UEPyEngine.h index a0373d169..cc607b07e 100644 --- a/Source/UnrealEnginePython/Private/UEPyEngine.h +++ b/Source/UnrealEnginePython/Private/UEPyEngine.h @@ -27,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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 910b92c77..097738c44 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -182,6 +182,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, "" }, @@ -262,9 +265,11 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, @@ -477,6 +482,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, "" }, @@ -489,6 +499,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, "" }, @@ -540,6 +551,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "render_thumbnail", (PyCFunction)py_ue_render_thumbnail, METH_VARARGS, "" }, #endif +// Config #if WITH_EDITOR #pragma warning(suppress: 4191) { "save_config", (PyCFunction)py_ue_save_config, METH_VARARGS | METH_KEYWORDS, "" }, @@ -554,7 +566,6 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_actor_label", (PyCFunction)py_ue_get_actor_label, METH_VARARGS, "" }, { "set_actor_label", (PyCFunction)py_ue_set_actor_label, METH_VARARGS, "" }, - { "get_editor_world_counterpart_actor", (PyCFunction)py_ue_get_editor_world_counterpart_actor, METH_VARARGS, "" }, { "find_actor_by_label", (PyCFunction)py_ue_find_actor_by_label, METH_VARARGS, "" }, @@ -652,6 +663,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 @@ -709,6 +721,7 @@ 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, "" }, @@ -724,6 +737,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, "" }, @@ -771,6 +785,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, "" }, @@ -855,6 +871,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, "" }, @@ -922,6 +939,8 @@ 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, "" }, @@ -986,6 +1005,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, "" }, @@ -997,6 +1017,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, "" }, @@ -1007,6 +1029,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 @@ -1587,7 +1610,8 @@ void unreal_engine_init_py_module() 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)); PyDict_SetItemString(unreal_engine_dict, "RF_PUBLIC", PyLong_FromUnsignedLongLong((uint64)RF_Public)); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp index 3fa9a4120..8420835ee 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.cpp @@ -127,6 +127,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) { @@ -923,6 +941,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) @@ -940,4 +984,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 bdcd71bb9..d27a5d35c 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyActor.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyActor.h @@ -12,12 +12,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 *); @@ -32,6 +34,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/UEPyMaterial.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp index eb4cebbb9..49ba0456b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp @@ -6,6 +6,79 @@ #include "Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h" #include "Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphSchema.h" #endif +#include +#include +#include + +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); +} PyObject *py_ue_set_material_scalar_parameter(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.h index a97a13082..e7aae9b91 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/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 7467052c2..20e10564f 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -67,6 +67,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); @@ -158,6 +179,37 @@ PyObject *py_ue_get_property_struct(ue_PyUObject * self, PyObject * args) return py_ue_new_uscriptstruct(prop->Struct, prop->ContainerPtrToValuePtr(self->ue_object)); } +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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 4bc238f32..f322f924f 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -32,6 +32,7 @@ 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 *); PyObject *py_ue_save_config_to_section(ue_PyUObject *, PyObject *, PyObject *); @@ -77,6 +78,7 @@ 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 *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 83b061f20..ba383933f 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -211,6 +211,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index 0e7d43374..8ffc8366c 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -46,6 +46,7 @@ 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 *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp index 004750037..8a27d57c0 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp @@ -707,6 +707,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 bf3db4a77..04e61d9d2 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.h @@ -25,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 *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp index 350a0b3fe..6c47734e2 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp @@ -18,6 +18,24 @@ PyObject *py_ue_static_mesh_build(ue_PyUObject *self, PyObject * args) { Py_RETURN_NONE; } +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); @@ -31,6 +49,20 @@ PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *self, PyObject * arg Py_RETURN_NONE; } +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 ae17a44e5..8cd748ea7 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/UEPyWorld.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp index fa58027fa..7539e43cb 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp @@ -274,6 +274,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 47cde2bfc..ebcafaf0d 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/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 7b02caa44..c82feea03 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -190,26 +190,81 @@ void ue_python_init_eslate_enums(PyObject *ue_module) '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', - ]), + 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', + ]), + + 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', + ]), + ] def output_cpp_enums(in_enum_list): @@ -409,33 +464,111 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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, "None", PyLong_FromLong((int)FWidget::EWidgetMode::WM_None)); - PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Translate", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Translate)); - PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Rotate", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Rotate)); - PyObject_SetAttrString((PyObject*)native_EWidgetMode, "Scale", PyLong_FromLong((int)FWidget::EWidgetMode::WM_Scale)); - } - - // 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, "World", PyLong_FromLong((int)ECoordSystem::COORD_World)); - PyObject_SetAttrString((PyObject*)native_ECoordSystem, "Local", PyLong_FromLong((int)ECoordSystem::COORD_Local)); - } + // 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)); + } + + // 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)); + } + #endif //[[[end]]] } From 31a7f0a38c56dacdcb3fc13a863ed858249bca58 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 02:45:11 -0700 Subject: [PATCH 52/64] Add support for Data Validation Manager: -Added EDataValidationResult shim -Exposed py_ue_is_data_valid --- .../UnrealEnginePython/Private/UEPyModule.cpp | 3 ++ .../Private/UObject/UEPyObject.cpp | 32 +++++++++++++++++++ .../Private/UObject/UEPyObject.h | 3 ++ .../Private/Wrappers/UEPyESlateEnums.cpp | 21 ++++++++++++ 4 files changed, 59 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 097738c44..aefbe65e0 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -726,6 +726,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "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 diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 20e10564f..41c7b16b4 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -113,6 +113,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) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index f322f924f..f80476d29 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -84,6 +84,9 @@ PyObject *py_ue_set_obj_flags(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 *); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index c82feea03..0753421f1 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -265,6 +265,13 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'SP_NumBits', ]), + EnumDef(name='EDataValidationResult', + cppNameScope='EDataValidationResult', + values=[ + 'Invalid', + 'Valid', + 'NotValidated' + ]), ] def output_cpp_enums(in_enum_list): @@ -569,6 +576,20 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 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)); + } + #endif //[[[end]]] } From ef941ce305355d902905bc5be2945c52d7edb46c Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 08:23:11 -0700 Subject: [PATCH 53/64] FIX: Various regressions from upstream slate refactor slate memory corruption: ue_PySWidget::weakreflist member was not being initialized to nullptr in py_ue_new_swidget() add_viewport_widget_content: Pass in the dropped z_order param widget: re-introduce py_dict; useful to have base python widget be a dictionary as it allows for easy extensions to slate widgets in python with new attributes py_ue_swindow_set_on_window_closed: Use NewSlateDelegate vs NewStaticSlateDelegate so delegate tracker gets GC'ed py_ue_sdock_tab_set_on_tab_closed: same as above --- Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp | 4 ++-- Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp | 7 ++++++- Source/UnrealEnginePython/Private/Slate/UEPySWidget.h | 1 + Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp | 2 +- Source/UnrealEnginePython/Private/Slate/UEPySlate.h | 2 ++ Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp index 72222b865..c906566a3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySDockTab.cpp @@ -23,7 +23,7 @@ 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_PySButton *self, PyObject * args) +static PyObject *py_ue_sdock_tab_set_on_tab_closed(ue_PySDockTab *self, PyObject * args) { ue_py_slate_cast(SDockTab); @@ -37,7 +37,7 @@ static PyObject *py_ue_sdock_tab_set_on_tab_closed(ue_PySButton *self, PyObject return PyErr_Format(PyExc_Exception, "argument is not callable"); SDockTab::FOnTabClosedCallback onTabClosed; - TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewSlateDelegate(py_SDockTab, py_callable); onTabClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnTabClosed); py_SDockTab->SetOnTabClosed(onTabClosed); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp index 4c2ae48d5..deecfce28 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -396,6 +396,7 @@ 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->Widget->GetTypeAsString(), &self->Widget.Get(), self->Widget.GetSharedReferenceCount()); #endif + Py_DECREF(self->py_dict); if (self->weakreflist != nullptr) PyObject_ClearWeakRefs((PyObject *)self); @@ -455,6 +456,7 @@ ue_PySWidget_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { new(&self->Widget) TSharedRef(SNullWidget::NullWidget); self->weakreflist = nullptr; + self->py_dict = self->py_dict = PyDict_New(); } return (PyObject *)self; @@ -463,7 +465,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/UEPySWidget.h b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h index bc4ed8384..72415f7ee 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h @@ -12,6 +12,7 @@ struct ue_PySWidget /* Type-specific fields go here. */ TSharedRef Widget; PyObject *weakreflist; + PyObject *py_dict; }; void ue_python_init_swidget(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp index b1b556872..756e95b20 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWindow.cpp @@ -80,7 +80,7 @@ static PyObject *py_ue_swindow_set_on_window_closed(ue_PySWindow *self, PyObject return PyErr_Format(PyExc_Exception, "argument is not callable"); FOnWindowClosed onWindowClosed; - TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewSlateDelegate(py_SWindow, py_callable); onWindowClosed.BindSP(py_delegate, &FPythonSlateDelegate::OnWindowClosed); py_SWindow->SetOnWindowClosed(onWindowClosed); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index f458485bd..a1280b55b 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -135,6 +135,8 @@ 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; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp index 01488abd9..4a3fc1061 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyViewport.cpp @@ -157,7 +157,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; } From 55f1eba9b5468255877a1cdd70942cf2efb1dfe6 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 08:54:25 -0700 Subject: [PATCH 54/64] Add experimental support for GC'ing StaticSlateDelegates by attaching a context object --- .../Private/Slate/UEPySVerticalBox.cpp | 2 +- .../Private/Slate/UEPySWidget.h | 2 +- .../Private/Slate/UEPySlate.cpp | 14 ++++++++++---- .../UnrealEnginePython/Private/Slate/UEPySlate.h | 8 +++++++- .../UnrealEnginePython/Public/PythonHouseKeeper.h | 15 +++++++++++++-- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp index f6eab351f..dd98f28be 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp @@ -122,7 +122,7 @@ PyTypeObject ue_PySVerticalBoxType = { ue_PySVerticalBox_methods, /* tp_methods */ }; -static int ue_py_svertical_box_init(ue_PySHorizontalBox *self, PyObject *args, PyObject *kwargs) +static int ue_py_svertical_box_init(ue_PySVerticalBox *self, PyObject *args, PyObject *kwargs) { ue_py_slate_setup_farguments(SVerticalBox); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h index 72415f7ee..1bba90464 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.h @@ -11,8 +11,8 @@ struct ue_PySWidget PyObject_HEAD /* Type-specific fields go here. */ TSharedRef Widget; - PyObject *weakreflist; PyObject *py_dict; + PyObject *weakreflist; }; void ue_python_init_swidget(PyObject *); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 4ca948c8f..3e1b38b75 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1423,14 +1423,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); + 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 ; @@ -1449,7 +1453,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; diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index a1280b55b..6f0c50ff1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -550,8 +550,14 @@ struct FPythonItem class FPythonSlateDelegate : public FPythonSmartDelegate { - public: + enum Type { + None, + TabSpawner + }; + Type StaticDelegateType; + FName LifeTimeCtx; + FReply OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event); FReply OnClicked(); diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index 1c665fd8f..78927525f 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -240,16 +240,27 @@ 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; From 616cb31489a5037b3eaa22ee2a17e13d23c54836 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 20:19:24 -0700 Subject: [PATCH 55/64] REGRESSION FIX: Slate delegates are not tracked in slots bc of new logic of using DeferredSlateDelegate tracker -FIX: Added ue_py_slate_track_delegates() macro to manually add deferred delegates to tracker Other cosmetic code fixes as well (wrapping single line if statements with braces) --- .../Private/Slate/UEPySBorder.cpp | 2 +- .../UnrealEnginePython/Private/Slate/UEPySBox.cpp | 2 +- .../Private/Slate/UEPySCanvas.cpp | 2 +- .../Private/Slate/UEPySCheckBox.cpp | 2 +- .../Private/Slate/UEPySHeaderRow.cpp | 2 ++ .../Private/Slate/UEPySHorizontalBox.cpp | 1 + .../Private/Slate/UEPySOverlay.cpp | 2 +- .../Private/Slate/UEPySPythonComboBox.cpp | 2 -- .../Slate/UEPySPythonMultiColumnTableRow.cpp | 2 +- .../Private/Slate/UEPySScrollBox.cpp | 2 +- .../Private/Slate/UEPySSplitter.cpp | 2 +- .../Private/Slate/UEPySVerticalBox.cpp | 4 +--- .../Private/Slate/UEPySWidget.cpp | 4 +++- .../Private/Slate/UEPySlate.cpp | 4 ++-- .../UnrealEnginePython/Private/Slate/UEPySlate.h | 15 +++++++++------ .../SlateApplication/UEPyFSlateApplication.cpp | 6 +++--- .../Private/UObject/UEPyWidgetComponent.cpp | 6 +++--- .../UnrealEnginePython/Public/PythonHouseKeeper.h | 2 ++ 18 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp index ccb311495..ef36c3aa1 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySBorder.cpp @@ -24,7 +24,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 c0adf0a0f..3590ad4ba 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySBox.cpp @@ -14,7 +14,7 @@ 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()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp index 943e88133..cfe7c0ceb 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCanvas.cpp @@ -41,7 +41,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 c8b9990ca..f37002e97 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySCheckBox.cpp @@ -16,7 +16,7 @@ static PyObject *py_ue_scheck_box_set_content(ue_PySCheckBox *self, PyObject * a TSharedPtr child = py_ue_is_swidget(py_content); if (!child.IsValid()) - return nullptr; + { return nullptr; } diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp index c63956968..e2d3d1f14 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySHeaderRow.cpp @@ -46,6 +46,8 @@ static PyObject *py_ue_sheader_row_add_column(ue_PySHeaderRow *self, PyObject *a ue_py_slate_farguments_bool("should_generate_widget", ShouldGenerateWidget); 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 7f769ccba..8ec969184 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySHorizontalBox.cpp @@ -45,6 +45,7 @@ static PyObject *py_ue_shorizontal_box_add_slot(ue_PySHorizontalBox *self, PyObj arguments.AutoWidth(); } + ue_py_slate_track_delegates(py_SHorizontalBox); return 0; }(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp index 9eb9457e7..89e14b5b3 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySOverlay.cpp @@ -32,7 +32,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 04e246c96..125e15131 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonComboBox.cpp @@ -167,8 +167,6 @@ static int ue_py_spython_combo_box_init(ue_PySPythonComboBox *self, PyObject *ar Py_INCREF(item); self->options_source_list.Add(TSharedPtr(new FPythonItem(item))); } - Py_DECREF(values); - 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 diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp index 12260c323..6a1fefa2f 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySPythonMultiColumnTableRow.cpp @@ -88,7 +88,7 @@ static int ue_py_spython_multicolumn_table_row_init(ue_PySPythonMultiColumnTable 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/UEPySScrollBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp index 31a4f6a15..8b81dda07 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySScrollBox.cpp @@ -50,7 +50,7 @@ static PyObject * py_ue_sscroll_box_remove_slot(ue_PySScrollBox *self, PyObject TSharedPtr child = py_ue_is_swidget(py_content); if (!child.IsValid()) - return nullptr; + { return nullptr; } py_SScrollBox->RemoveSlot(child.ToSharedRef()); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp index ae7eae95d..e66668d1d 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySSplitter.cpp @@ -12,7 +12,7 @@ static PyObject *py_ue_ssplitter_add_slot(ue_PySSplitter *self, PyObject * args, 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; }(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp index dd98f28be..e8627c5f2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySVerticalBox.cpp @@ -38,9 +38,7 @@ static PyObject *py_ue_svertical_box_add_slot(ue_PySVerticalBox *self, PyObject TSharedPtr Child = py_ue_is_swidget(py_content); if (!Child.IsValid()) - { - return nullptr; - } + { 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 deecfce28..02ab0c736 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySWidget.cpp @@ -399,7 +399,7 @@ static void ue_PySWidgett_dealloc(ue_PySWidget *self) 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) @@ -454,6 +454,8 @@ 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(); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 3e1b38b75..0f6a5a6b2 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -764,7 +764,7 @@ TSharedRef FPythonSlateDelegate::SpawnPythonTab(const FSpawnTabArgs &a return SNew(SDockTab); } - TSharedRef dock_tab = StaticCastSharedRef(py_dock->s_border.s_compound_widget.s_widget.Widget); + TSharedRef dock_tab = StaticCastSharedRef(((ue_PySWidget*)py_dock)->Widget); Py_DECREF(py_dock); @@ -784,7 +784,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); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 6f0c50ff1..5a881a831 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -141,11 +141,14 @@ template ue_PySWidget *py_ue_new_swidget(TSharedRef s_widge return ret; } +#define ue_py_slate_track_delegates(_swidget_ref) \ + for(TSharedRef Delegate : DeferredSlateDelegates)\ + {\ + 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);\ - for(TSharedRef Delegate : DeferredSlateDelegates)\ - {\ - FUnrealEnginePythonHouseKeeper::Get()->TrackDeferredSlateDelegate(Delegate, ((ue_PySWidget *)self)->Widget);\ - } + 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()) @@ -522,8 +525,8 @@ ue_PySWidget *ue_py_get_swidget(TSharedRef s_widget); #define ue_py_slate_farguments_required_slot(param) { PyObject *value = ue_py_dict_get_item(kwargs, param);\ value = value ? value : PyTuple_GetItem(args, 0);\ TSharedPtr Widget = py_ue_is_swidget(value);\ - if (Widget.IsValid())\ - arguments.AttachWidget(Widget.ToSharedRef());\ + if (Widget.IsValid()) \ + { arguments.AttachWidget(Widget.ToSharedRef()); } \ else\ {\ PyErr_SetString(PyExc_TypeError, "unsupported type for required slot " param); \ diff --git a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp index 96b0e5058..4760ac7a3 100644 --- a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp +++ b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp @@ -170,11 +170,11 @@ static PyObject *py_ue_push_menu(PyObject *cls, PyObject * args) // Parse cursor position as a blueprint struct TSharedPtr parentWidget = py_ue_is_swidget(py_parent_widget); if (!parentWidget.IsValid()) - return nullptr; + { return nullptr; } TSharedPtr menuWidget = py_ue_is_swidget(py_menu_widget); if (!menuWidget.IsValid()) - return nullptr; + { return nullptr; } FVector2D CursorPos = FVector2D(x, y); @@ -200,7 +200,7 @@ static PyObject *py_ue_add_window(PyObject *cls, PyObject * args) const bool showImmediately = (py_show_immediately) ? (PyObject_IsTrue(py_show_immediately)) : true; - FSlateApplication::Get().AddWindow(StaticCastSharedRef(py_window->s_compound_widget.s_widget.Widget), showImmediately); + FSlateApplication::Get().AddWindow(StaticCastSharedRef(((ue_PySWidget*)py_window)->Widget), showImmediately); return py_window_obj; } diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp index a973a8b2d..b56399519 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWidgetComponent.cpp @@ -24,10 +24,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/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index 78927525f..ec0a94a64 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -266,5 +266,7 @@ class FUnrealEnginePythonHouseKeeper TArray PyDelegatesTracker; TArray PySlateDelegatesTracker; + + //TODO: ikrimae: #ThirdParty-Python: #BUG: This implementation memory leaks. These delegates never get cleaned up TArray> PyStaticSlateDelegatesTracker; }; From 7a6c42cffb0cd1878c4b8fd09749cb4f82eddab4 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 20:31:52 -0700 Subject: [PATCH 56/64] Prepare for merge of #b8f4f23f80edaeadf90b0e3cfc660007875a6e30 --- .../Private/Slate/UEPySlate.h | 120 ---------------- .../Private/Slate/UEPySlateDelegate.h | 128 ++++++++++++++++++ 2 files changed, 128 insertions(+), 120 deletions(-) create mode 100644 Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 5a881a831..d9314738a 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -549,123 +549,3 @@ struct FPythonItem py_object = item; } }; - - -class FPythonSlateDelegate : public FPythonSmartDelegate -{ -public: - enum Type { - None, - TabSpawner - }; - Type StaticDelegateType; - FName LifeTimeCtx; - - FReply OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event); - FReply OnClicked(); - - FReply OnKeyDown(const FGeometry &geometry, const FKeyEvent &key_event); - void OnTextChanged(const FText &text); - void OnTextCommitted(const FText &text, ETextCommit::Type commit_type); - void OnInt32Changed(int32 value); - 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, bool bShouldAutosize); - - TSharedRef GenerateRow(TSharedPtr InItem, const TSharedRef& OwnerTable); - void GetChildren(TSharedPtr InItem, TArray>& OutChildren); - -#if WITH_EDITOR - void OnAssetDoubleClicked(const FAssetData& AssetData); - TSharedPtr OnGetAssetContextMenu(const TArray& SelectedAssets); - void OnAssetSelected(const FAssetData& AssetData); - TSharedRef OnExtendContentBrowserMenu(const TArray &SelectedAssets); - void MenuPyAssetBuilder(FMenuBuilder &Builder, TArray SelectedAssets); - void OnAssetChanged(const FAssetData &AssetData); - bool OnShouldFilterAsset(const FAssetData& AssetData); -#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); - TSharedRef OnGetMenuContent(); - void OnSelectionChanged(TSharedPtr py_item, ESelectInfo::Type select_type); - - void SimpleExecuteAction(); - void ExecuteAction(PyObject *py_obj); - - FText GetterFText() const; - FString GetterFString() const; - float GetterFloat() const; - TOptional GetterTFloat() const; - int GetterInt() const; - bool GetterBool() const; - - FVector2D GetterFVector2D() const; - FLinearColor GetterFLinearColor() const; - void CheckBoxChanged(ECheckBoxState state); - - - template T GetterIntT() const - { - FScopePythonGIL gil; - - PyObject *ret = PyObject_CallFunction(py_callable, nullptr); - if (!ret) - { - unreal_engine_py_log_error(); - return (T)0; - } - if (!PyNumber_Check(ret)) - { - PyErr_SetString(PyExc_ValueError, "returned value is not a number"); - Py_DECREF(ret); - return (T)0; - } - - PyObject *py_int = PyNumber_Long(ret); - int n = PyLong_AsLong(py_int); - Py_DECREF(py_int); - Py_DECREF(ret); - return (T)n; - } - - template T GetterStructT() const - { - FScopePythonGIL gil; - - PyObject *ret = PyObject_CallFunction(py_callable, nullptr); - if (!ret) - { - unreal_engine_py_log_error(); - return T(); - } - - T *u_struct = ue_py_check_struct(ret); - if (!u_struct) - { - PyErr_SetString(PyExc_ValueError, "returned value is not a UStruct"); - Py_DECREF(ret); - return T(); - } - - T u_struct_copy = *u_struct; - Py_DECREF(ret); - return u_struct_copy; - } -}; - - diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h new file mode 100644 index 000000000..4b550239d --- /dev/null +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h @@ -0,0 +1,128 @@ +#pragma once + + +#include "SlateBasics.h" +#include "SlateExtras.h" + +#include "PythonSmartDelegate.h" + +struct FPythonItem; + +class FPythonSlateDelegate : public FPythonSmartDelegate +{ +public: + enum Type { + None, + TabSpawner + }; + Type StaticDelegateType; + FName LifeTimeCtx; + + FReply OnMouseEvent(const FGeometry &geometry, const FPointerEvent &pointer_event); + FReply OnClicked(); + + FReply OnKeyDown(const FGeometry &geometry, const FKeyEvent &key_event); + void OnTextChanged(const FText &text); + void OnTextCommitted(const FText &text, ETextCommit::Type commit_type); + void OnInt32Changed(int32 value); + 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, bool bShouldAutosize); + + TSharedRef GenerateRow(TSharedPtr InItem, const TSharedRef& OwnerTable); + void GetChildren(TSharedPtr InItem, TArray>& OutChildren); + +#if WITH_EDITOR + void OnAssetDoubleClicked(const FAssetData& AssetData); + TSharedPtr OnGetAssetContextMenu(const TArray& SelectedAssets); + void OnAssetSelected(const FAssetData& AssetData); + TSharedRef OnExtendContentBrowserMenu(const TArray &SelectedAssets); + void MenuPyAssetBuilder(FMenuBuilder &Builder, TArray SelectedAssets); + void OnAssetChanged(const FAssetData &AssetData); + bool OnShouldFilterAsset(const FAssetData& AssetData); +#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); + TSharedRef OnGetMenuContent(); + void OnSelectionChanged(TSharedPtr py_item, ESelectInfo::Type select_type); + + void SimpleExecuteAction(); + void ExecuteAction(PyObject *py_obj); + + FText GetterFText() const; + FString GetterFString() const; + float GetterFloat() const; + TOptional GetterTFloat() const; + int GetterInt() const; + bool GetterBool() const; + + FVector2D GetterFVector2D() const; + FLinearColor GetterFLinearColor() const; + void CheckBoxChanged(ECheckBoxState state); + + + template T GetterIntT() const + { + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, nullptr); + if (!ret) + { + unreal_engine_py_log_error(); + return (T)0; + } + if (!PyNumber_Check(ret)) + { + PyErr_SetString(PyExc_ValueError, "returned value is not a number"); + Py_DECREF(ret); + return (T)0; + } + + PyObject *py_int = PyNumber_Long(ret); + int n = PyLong_AsLong(py_int); + Py_DECREF(py_int); + Py_DECREF(ret); + return (T)n; + } + + template T GetterStructT() const + { + FScopePythonGIL gil; + + PyObject *ret = PyObject_CallFunction(py_callable, nullptr); + if (!ret) + { + unreal_engine_py_log_error(); + return T(); + } + + T *u_struct = ue_py_check_struct(ret); + if (!u_struct) + { + PyErr_SetString(PyExc_ValueError, "returned value is not a UStruct"); + Py_DECREF(ret); + return T(); + } + + T u_struct_copy = *u_struct; + Py_DECREF(ret); + return u_struct_copy; + } +}; + + From 5491dc79ca2a02570f2273ab4109f058f99c677c Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 22:23:42 -0700 Subject: [PATCH 57/64] REGRESSION: Fix RunFile logic to work if it gets passed a fully qualified path --- .../Private/UnrealEnginePython.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index 521c0ce8b..d80e13888 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"), 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"), filename); + UE_LOG(LogPython, Error, TEXT("Unable to find file %s"), *full_path); return; } From 8c653fcb1a3d460a23b51ae9a29fee741fcec495 Mon Sep 17 00:00:00 2001 From: ikrima Date: Tue, 29 May 2018 22:53:24 -0700 Subject: [PATCH 58/64] Add is_valid() to fassetdata --- .../Private/Wrappers/UEPyFAssetData.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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 From fc36b3a7a048c3fa5f57de316098c0ef3629d8ef Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 20 Jun 2018 04:28:03 -0700 Subject: [PATCH 59/64] FIX: Making standalone builds compile -Adding missing includes for standalone builds -Moving native enum shims into editor only --- .../ConsoleManager/UEPyIConsoleManager.cpp | 2 +- .../Private/Slate/UEPyFSlateIcon.cpp | 2 + .../UnrealEnginePython/Private/UEPyEditor.cpp | 2 +- .../Private/UObject/UEPyMaterial.cpp | 1 + .../Private/Wrappers/UEPyESlateEnums.cpp | 268 ++++++++++-------- .../Private/Wrappers/UEPyFTransform.cpp | 3 + 6 files changed, 161 insertions(+), 117 deletions(-) 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/Slate/UEPyFSlateIcon.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFSlateIcon.cpp index 414a1f139..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) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 305a1d10c..87a97ea87 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -1855,7 +1855,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; diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp index eada5891f..0633b4e2d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "Materials/Material.h" PyObject *py_ue_get_material_instruction_count(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 3d802b807..3eb9b635d 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -7,6 +7,12 @@ #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[] = { { NULL } /* Sentinel */ @@ -91,10 +97,10 @@ void ue_python_init_eslate_enums(PyObject *ue_module) EnumDef = collections.namedtuple('EnumDef', 'name cppNameScope values') native_enums_list = [ - EnumDef(name='ESizeRule', + EnumDef(name='ESizeRule', cppNameScope='SSplitter::ESizeRule', values=[ - 'SizeToContent', + 'SizeToContent', 'FractionOfParent', ]), @@ -170,50 +176,6 @@ void ue_python_init_eslate_enums(PyObject *ue_module) 'UserClickedOnTab', 'SetDirectly', ]), - ] - - 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', - ]), EnumDef(name='EMaterialQualityLevel', cppNameScope='EMaterialQualityLevel', @@ -276,6 +238,65 @@ void ue_python_init_eslate_enums(PyObject *ue_module) '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): @@ -308,7 +329,7 @@ void ue_python_init_eslate_enums(PyObject *ue_module) ]]]*/ // Enum Wrapper: ESizeRule - { + { PyObject* native_ESizeRule = PyDict_GetItemString(unreal_engine_dict, "ESizeRule"); if (native_ESizeRule == nullptr) { @@ -441,73 +462,6 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_ETabActivationCause, "SetDirectly" , PyLong_FromLong((int)ETabActivationCause::SetDirectly)); } - #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)); - } - // Enum Wrapper: EMaterialQualityLevel { PyObject* native_EMaterialQualityLevel = PyDict_GetItemString(unreal_engine_dict, "EMaterialQualityLevel"); @@ -594,7 +548,91 @@ void ue_python_init_eslate_enums(PyObject *ue_module) PyObject_SetAttrString((PyObject*)native_EDataValidationResult, "NotValidated" , PyLong_FromLong((int)EDataValidationResult::NotValidated)); } -#endif + // 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]]] } diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 4c762a06f..40002f007 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -2,6 +2,9 @@ #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) { From eea976672e461b6ed289a2bc401a98b726088a0e Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 20 Jun 2018 04:28:43 -0700 Subject: [PATCH 60/64] FIX: Returning zero vector on error for FVector2D getters -FVector2D() does not initialize the struct --- Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index f9e7de04e..61a088114 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -766,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); @@ -788,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); From e0b561766c5502dcb0f56e2b0ecad6bfa78b713c Mon Sep 17 00:00:00 2001 From: ikrima Date: Wed, 20 Jun 2018 04:30:26 -0700 Subject: [PATCH 61/64] FIX: Logic for get property_struct & is_child_of to properly handle scriptstructs -Extend properties() to allow for EFieldIteratorFlags --- .../Private/UObject/UEPyObject.cpp | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 5d93db92e..2e9844fe8 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -209,10 +209,21 @@ 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) @@ -346,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)) { @@ -1645,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()) @@ -1657,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())); From 022bf7f68bdeb0d2ef7d471757577a5aee282b6e Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 22 Jun 2018 01:28:28 -0700 Subject: [PATCH 62/64] Python fixes with returning uninit FVector2D on Error Python bug fixes on slate attribute macro Add editor_refresh_all_browsers --- .../Private/Slate/UEPySDirectoryPicker.cpp | 8 ++++---- Source/UnrealEnginePython/Private/Slate/UEPySlate.h | 10 ++++++++-- Source/UnrealEnginePython/Private/UEPyEditor.cpp | 7 +++++++ Source/UnrealEnginePython/Private/UEPyEditor.h | 2 ++ Source/UnrealEnginePython/Private/UEPyModule.cpp | 1 + 5 files changed, 22 insertions(+), 6 deletions(-) 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/UEPySlate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h index 06cf52135..9f29ebbf6 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.h @@ -409,8 +409,14 @@ 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;\ + }\ }\ } diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 8ca028aee..edd6933b4 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -206,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(); diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 0b41467f7..282110402 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -66,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 *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 0288f9bb6..f49545c2f 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -342,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, "" }, From bc360548c88c3f11ae69258628ad7f10b040a9b8 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 22 Jun 2018 01:37:54 -0700 Subject: [PATCH 63/64] Remove outdated K&L specific markers as 4.18 exports GetSelectedSections --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 2 ++ Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp | 4 +--- Source/UnrealEnginePython/Private/UObject/UEPySequencer.h | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index f49545c2f..3123e788e 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1068,7 +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 diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 37901d7d9..1b6db9d8d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -989,8 +989,7 @@ PyObject *py_ue_sequencer_remove_track(ue_PyUObject *self, PyObject * args) Py_RETURN_FALSE; } -// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 -#if WITH_KNL_PYEXT +#if ENGINE_MINOR_VERSION >= 18 // Returns the selected sections PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args) { @@ -1027,7 +1026,6 @@ PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * a return py_sections; } #endif -// @third party code - END Bebylon #endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index 9d80ccb5c..f1e409b4d 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -32,11 +32,9 @@ 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 *); -// @third party code - BEGIN Bebylon - #ThirdParty-Python: WITH_KNL_PYEXT - GetSelectedSections() is not exported in vanilla 4.17 -#if WITH_KNL_PYEXT +#if ENGINE_MINOR_VERSION >= 18 PyObject *py_ue_sequencer_get_selected_sections(ue_PyUObject *self, PyObject * args); #endif -// @third party code - END Bebylon PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *, PyObject *); #endif PyObject *py_ue_sequencer_sections(ue_PyUObject *, PyObject *); From 8217094b24c8e020b3ac4a5d31db8b679db6ecd4 Mon Sep 17 00:00:00 2001 From: ikrima Date: Fri, 22 Jun 2018 01:58:42 -0700 Subject: [PATCH 64/64] FIX: Syntax error in in .uplugin file --- Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp | 6 +++--- UnrealEnginePython.uplugin | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 2e9844fe8..44d974bb8 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -792,7 +792,7 @@ PyObject *py_ue_save_config(ue_PyUObject *self, PyObject * args, PyObject *kwarg Py_RETURN_NONE; } -//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition +//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); @@ -961,7 +961,7 @@ PyObject *py_ue_save_config_to_section(ue_PyUObject *self, PyObject * args, PyOb Py_RETURN_NONE; } -//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition +//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); @@ -1058,7 +1058,7 @@ namespace { } #endif -//TODO: ikrimae: #ThirdParty-Python: Codereview's sai addition +//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); diff --git a/UnrealEnginePython.uplugin b/UnrealEnginePython.uplugin index 259a7b2be..91b30df39 100644 --- a/UnrealEnginePython.uplugin +++ b/UnrealEnginePython.uplugin @@ -41,5 +41,5 @@ "Name": "LevelSequenceEditor", "Enabled": true } - ], + ] }