From a7e500b2c7980cce7c86595f943a9186304def7f Mon Sep 17 00:00:00 2001 From: Steven Shan Date: Thu, 22 Mar 2018 14:48:33 -0400 Subject: [PATCH 01/62] updated PlottingGraphWithMatplotlibAndUnrealEnginePython.md --- tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython.md | 2 +- .../plotter.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython.md b/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython.md index 8ff7795c7..4d9c5246a 100644 --- a/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython.md +++ b/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython.md @@ -194,7 +194,7 @@ class PlotComponent: dpi = 72.0 self.texture = ue.create_transient_texture(width, height, EPixelFormat.PF_R8G8B8A8) - self.uobject.get_owner().StaticMesh.OverrideMaterials[0].set_material_texture_parameter('Graph', self.texture) + self.uobject.get_owner().StaticMeshComponent.OverrideMaterials[0].set_material_texture_parameter('Graph', self.texture) self.fig = plt.figure(1) self.fig.set_dpi(dpi) diff --git a/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython_Assets/plotter.py b/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython_Assets/plotter.py index e8e8418a4..6466adee2 100644 --- a/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython_Assets/plotter.py +++ b/tutorials/PlottingGraphsWithMatplotlibAndUnrealEnginePython_Assets/plotter.py @@ -14,7 +14,7 @@ def begin_play(self): dpi = 72.0 self.texture = ue.create_transient_texture(width, height, EPixelFormat.PF_R8G8B8A8) - self.uobject.get_owner().StaticMesh.OverrideMaterials[0].set_material_texture_parameter('Graph', self.texture) + self.uobject.get_owner().StaticMeshComponent.OverrideMaterials[0].set_material_texture_parameter('Graph', self.texture) self.fig = plt.figure(1) self.fig.set_dpi(dpi) From 9690cb39e2244f209ab1727c847cafaf24fc5d46 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 12:29:16 +0200 Subject: [PATCH 02/62] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 072733a46..1885cd358 100644 --- a/README.md +++ b/README.md @@ -943,9 +943,9 @@ We try to do our best to "protect" the user, but you can effectively crash UE fr Contacts and Commercial Support ------------------------------- -If you want to contact us (for help, support, sponsorship), drop a mail to info at 20tab.com or follow @unbit on twitter +If you need commercial support for UnrealEnginePython just drop a mail to info at 20tab.com -We offer commercial support for both UnrealEngine and UnrealEnginePython, again drop a mail to info at 20tab.com for more infos +Follow @unbit on twitter for news about the project Special Thanks -------------- From acf57bb9e5084df282b2e86787a3ceda461689e6 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 12:32:12 +0200 Subject: [PATCH 03/62] fixed build for < 4.21 --- .../Private/UObject/UEPySkeletal.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp index 86747cbfa..3386d4537 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySkeletal.cpp @@ -985,7 +985,11 @@ PyObject *py_ue_skeletal_mesh_build_lod(ue_PyUObject *self, PyObject * args, PyO points_to_map.Add(vertex_index); +#if ENGINE_MINOR_VERSION > 20 SkeletalMeshImportData::FMeshWedge wedge; +#else + FMeshWedge wedge; +#endif wedge.iVertex = vertex_index; wedge.Color = ss_vertex->ss_vertex.Color; for (int32 i = 0; i < MAX_TEXCOORDS; i++) @@ -996,7 +1000,11 @@ PyObject *py_ue_skeletal_mesh_build_lod(ue_PyUObject *self, PyObject * args, PyO for (int32 i = 0; i < MAX_TOTAL_INFLUENCES; i++) { +#if ENGINE_MINOR_VERSION > 20 SkeletalMeshImportData::FVertInfluence influence; +#else + FVertInfluence influence; +#endif influence.VertIndex = wedge_index; influence.BoneIndex = ss_vertex->ss_vertex.InfluenceBones[i]; influence.Weight = ss_vertex->ss_vertex.InfluenceWeights[i] / 255.f; @@ -1018,7 +1026,11 @@ PyObject *py_ue_skeletal_mesh_build_lod(ue_PyUObject *self, PyObject * args, PyO for (int32 i = 0; i < wedges.Num(); i += 3) { +#if ENGINE_MINOR_VERSION > 20 SkeletalMeshImportData::FMeshFace face; +#else + FMeshFace face; +#endif face.iWedge[0] = i; face.iWedge[1] = i + 1; face.iWedge[2] = i + 2; From 08d3638e7f89a3f84e23404408f1e4696abde436 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 13:04:21 +0200 Subject: [PATCH 04/62] added asset metadata tag api --- .../UnrealEnginePython/Private/UEPyModule.cpp | 18 ++-- .../Private/UObject/UEPyObject.cpp | 89 +++++++++++++++++-- .../Private/UObject/UEPyObject.h | 6 ++ examples/asset_metadata_tag.py | 19 ++++ 4 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 examples/asset_metadata_tag.py diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index bfcbcd416..0f66d73a0 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -616,6 +616,12 @@ static PyMethodDef ue_PyUObject_methods[] = { #if WITH_EDITOR { "get_thumbnail", (PyCFunction)py_ue_get_thumbnail, METH_VARARGS, "" }, { "render_thumbnail", (PyCFunction)py_ue_render_thumbnail, METH_VARARGS, "" }, + {"get_metadata_tag", (PyCFunction)py_ue_get_metadata_tag, METH_VARARGS, "" }, + {"set_metadata_tag", (PyCFunction)py_ue_set_metadata_tag, METH_VARARGS, "" }, + { "metadata_tags", (PyCFunction)py_ue_metadata_tags, METH_VARARGS, "" }, + { "has_metadata_tag", (PyCFunction)py_ue_has_metadata_tag, METH_VARARGS, "" }, + {"remove_metadata_tag", (PyCFunction)py_ue_remove_metadata_tag, METH_VARARGS, "" }, + #endif #if WITH_EDITOR @@ -1856,10 +1862,10 @@ ue_PyUObject *ue_get_python_uobject(UObject *ue_obj) UE_LOG(LogPython, Warning, TEXT("CREATED UPyObject at %p for %p %s"), ue_py_object, ue_obj, *ue_obj->GetName()); #endif return ue_py_object; - } + } return ret; - } +} ue_PyUObject *ue_get_python_uobject_inc(UObject *ue_obj) { @@ -2883,8 +2889,8 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * #endif } #endif - } } + } Py_ssize_t tuple_len = PyTuple_Size(args); @@ -2997,7 +3003,7 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * return ret; Py_RETURN_NONE; - } +} PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) { @@ -3057,8 +3063,8 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ { UE_LOG(LogPython, Error, TEXT("function %s is already registered"), UTF8_TO_TCHAR(name)); return nullptr; + } } -} UPythonFunction *function = NewObject(u_class, UTF8_TO_TCHAR(name), RF_Public | RF_Transient | RF_MarkAsNative); function->SetPyCallable(py_callable); @@ -3379,7 +3385,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ #endif return function; - } +} FGuid *ue_py_check_fguid(PyObject *py_obj) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index 43ef8aeca..ad4fc2259 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -482,6 +482,87 @@ PyObject *py_ue_get_metadata(ue_PyUObject * self, PyObject * args) return PyErr_Format(PyExc_TypeError, "the object does not support MetaData"); } +PyObject *py_ue_get_metadata_tag(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + char *metadata_tag_key; + if (!PyArg_ParseTuple(args, "s:get_metadata_tag", &metadata_tag_key)) + { + return nullptr; + } + + const FString& Value = self->ue_object->GetOutermost()->GetMetaData()->GetValue(self->ue_object, UTF8_TO_TCHAR(metadata_tag_key)); + return PyUnicode_FromString(TCHAR_TO_UTF8(*Value)); +} + +PyObject *py_ue_has_metadata_tag(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + char *metadata_tag_key; + if (!PyArg_ParseTuple(args, "s:has_metadata_tag", &metadata_tag_key)) + { + return nullptr; + } + + if (self->ue_object->GetOutermost()->GetMetaData()->HasValue(self->ue_object, UTF8_TO_TCHAR(metadata_tag_key))) + { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +PyObject *py_ue_remove_metadata_tag(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + char *metadata_tag_key; + if (!PyArg_ParseTuple(args, "s:remove_metadata_tag", &metadata_tag_key)) + { + return nullptr; + } + + self->ue_object->GetOutermost()->GetMetaData()->RemoveValue(self->ue_object, UTF8_TO_TCHAR(metadata_tag_key)); + Py_RETURN_NONE; +} + +PyObject *py_ue_set_metadata_tag(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + char *metadata_tag_key; + char *metadata_tag_value; + if (!PyArg_ParseTuple(args, "ss:set_metadata_tag", &metadata_tag_key, &metadata_tag_value)) + { + return nullptr; + } + + self->ue_object->GetOutermost()->GetMetaData()->SetValue(self->ue_object, UTF8_TO_TCHAR(metadata_tag_key), UTF8_TO_TCHAR(metadata_tag_value)); + Py_RETURN_NONE; +} + + +PyObject *py_ue_metadata_tags(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + TMap *TagsMap = self->ue_object->GetOutermost()->GetMetaData()->GetMapForObject(self->ue_object); + if (!TagsMap) + Py_RETURN_NONE; + + PyObject* py_list = PyList_New(0); + for (TPair< FName, FString>& Pair : *TagsMap) + { + PyList_Append(py_list, PyUnicode_FromString(TCHAR_TO_UTF8(*Pair.Key.ToString()))); + } + return py_list; +} + PyObject *py_ue_has_metadata(ue_PyUObject * self, PyObject * args) { @@ -498,11 +579,9 @@ PyObject *py_ue_has_metadata(ue_PyUObject * self, PyObject * args) UClass *u_class = (UClass *)self->ue_object; if (u_class->HasMetaData(FName(UTF8_TO_TCHAR(metadata_key)))) { - Py_INCREF(Py_True); - return Py_True; + Py_RETURN_TRUE; } - Py_INCREF(Py_False); - return Py_False; + Py_RETURN_FALSE; } if (self->ue_object->IsA()) @@ -1850,7 +1929,7 @@ PyObject *py_ue_add_property(ue_PyUObject * self, PyObject * args) // TODO add default value Py_RETURN_UOBJECT(u_property); -} + } PyObject *py_ue_as_dict(ue_PyUObject * self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index d43422274..4f66b78f7 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -97,6 +97,12 @@ PyObject *py_ue_get_metadata(ue_PyUObject *, PyObject *); PyObject *py_ue_set_metadata(ue_PyUObject *, PyObject *); PyObject *py_ue_has_metadata(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_metadata_tag(ue_PyUObject *, PyObject *); +PyObject *py_ue_set_metadata_tag(ue_PyUObject *, PyObject *); +PyObject *py_ue_has_metadata_tag(ue_PyUObject *, PyObject *); +PyObject *py_ue_remove_metadata_tag(ue_PyUObject *, PyObject *); +PyObject *py_ue_metadata_tags(ue_PyUObject *, PyObject *); + PyObject *py_ue_import_custom_properties(ue_PyUObject *, PyObject *); #endif diff --git a/examples/asset_metadata_tag.py b/examples/asset_metadata_tag.py new file mode 100644 index 000000000..dfa036f36 --- /dev/null +++ b/examples/asset_metadata_tag.py @@ -0,0 +1,19 @@ +import unreal_engine as ue +from unreal_engine.classes import EditorAssetLibrary + +asset = ue.get_selected_assets()[0] + +# reflection-based api +EditorAssetLibrary.SetMetadataTag(asset, 'Foo', 'Bar') +for value in EditorAssetLibrary.GetMetadataTagValues(asset): + print(value) +print(EditorAssetLibrary.GetMetadataTag(asset, 'Foo')) + + +# native api +asset.set_metadata_tag('Test001', 'Text002') +asset.set_metadata_tag('Test003', 'Text004') +for key in asset.metadata_tags(): + print(key) +print(asset.has_metadata_tag('Foo')) # bool +print(asset.get_metadata_tag('Test001')) From 030f0f1643b9aab0e1f88815374246e64fc5e1e3 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 13:32:08 +0200 Subject: [PATCH 05/62] added level blueprint api --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 1 + .../Private/UObject/UEPyWorld.cpp | 14 ++++++++++++++ .../UnrealEnginePython/Private/UObject/UEPyWorld.h | 1 + examples/edit_level_blueprint.py | 8 ++++++++ 4 files changed, 24 insertions(+) create mode 100644 examples/edit_level_blueprint.py diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 0f66d73a0..1726b23c0 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -877,6 +877,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "set_current_level", (PyCFunction)py_ue_set_current_level, METH_VARARGS, "" }, #if WITH_EDITOR + { "get_level_script_blueprint", (PyCFunction)py_ue_get_level_script_blueprint, METH_VARARGS, "" }, { "add_foliage_asset", (PyCFunction)py_ue_add_foliage_asset, METH_VARARGS, "" }, { "get_foliage_instances", (PyCFunction)py_ue_get_foliage_instances, METH_VARARGS, "" }, #endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp index 861f10ba6..ec2be2b7c 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp @@ -323,6 +323,20 @@ PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args) } #if WITH_EDITOR +PyObject *py_ue_get_level_script_blueprint(ue_PyUObject *self, PyObject * args) +{ + + ue_py_check(self); + + ULevel *level = ue_py_check_type(self); + if (!level) + { + return PyErr_Format(PyExc_Exception, "uobject is not a ULevel"); + } + + Py_RETURN_UOBJECT((UObject*)level->GetLevelScriptBlueprint()); +} + PyObject *py_ue_world_create_folder(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h index af2c40665..16f07ae7e 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.h @@ -35,5 +35,6 @@ PyObject *py_ue_world_create_folder(ue_PyUObject *, PyObject *); PyObject *py_ue_world_delete_folder(ue_PyUObject *, PyObject *); PyObject *py_ue_world_rename_folder(ue_PyUObject *, PyObject *); PyObject *py_ue_world_folders(ue_PyUObject *, PyObject *); +PyObject *py_ue_get_level_script_blueprint(ue_PyUObject *, PyObject *); #endif diff --git a/examples/edit_level_blueprint.py b/examples/edit_level_blueprint.py new file mode 100644 index 000000000..a7ddd961c --- /dev/null +++ b/examples/edit_level_blueprint.py @@ -0,0 +1,8 @@ +import unreal_engine as ue +from unreal_engine.structs import EdGraphPinType + +world = ue.get_editor_world() +level_bp = world.CurrentLevel.get_level_script_blueprint() +pin = EdGraphPinType(PinCategory='string') +ue.blueprint_add_member_variable(level_bp, 'TestString', pin) +ue.open_editor_for_asset(level_bp) From a8d1778b797f35fbb23a26b0230f77d2edb3488a Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 14:00:19 +0200 Subject: [PATCH 06/62] added sequencer_set_view_range() and sequencer_set_working_range(), #554 and #553 --- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 + .../Private/UObject/UEPySequencer.cpp | 44 +++++++++++++++++++ .../Private/UObject/UEPySequencer.h | 2 + 3 files changed, 48 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 1726b23c0..98c0830dd 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1076,6 +1076,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_get_camera_cut_track", (PyCFunction)py_ue_sequencer_get_camera_cut_track, METH_VARARGS, "" }, #if WITH_EDITOR { "sequencer_set_playback_range", (PyCFunction)py_ue_sequencer_set_playback_range, METH_VARARGS, "" }, + { "sequencer_set_view_range", (PyCFunction)py_ue_sequencer_set_view_range, METH_VARARGS, "" }, + { "sequencer_set_working_range", (PyCFunction)py_ue_sequencer_set_working_range, METH_VARARGS, "" }, { "sequencer_set_section_range", (PyCFunction)py_ue_sequencer_set_section_range, METH_VARARGS, "" }, { "sequencer_folders", (PyCFunction)py_ue_sequencer_folders, METH_VARARGS, "" }, { "sequencer_create_folder", (PyCFunction)py_ue_sequencer_create_folder, METH_VARARGS, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 32b11dd48..128f09b29 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -911,6 +911,50 @@ PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *self, PyObject * args Py_RETURN_NONE; } +PyObject *py_ue_sequencer_set_working_range(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"); + UMovieScene *scene = seq->GetMovieScene(); + + float start_time; + float end_time; + if (!PyArg_ParseTuple(args, "ff:sequencer_set_working_range", &start_time, &end_time)) + { + return nullptr; + } + + scene->SetWorkingRange(start_time, end_time); + + Py_RETURN_NONE; +} + +PyObject *py_ue_sequencer_set_view_range(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"); + UMovieScene *scene = seq->GetMovieScene(); + + float start_time; + float end_time; + if (!PyArg_ParseTuple(args, "ff:sequencer_set_view_range", &start_time, &end_time)) + { + return nullptr; + } + + scene->SetViewRange(start_time, end_time); + + Py_RETURN_NONE; +} + PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index ac22a41a7..64cfe39bb 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -10,6 +10,8 @@ PyObject *py_ue_sequencer_track_sections(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_get_camera_cut_track(ue_PyUObject *, PyObject *); #if WITH_EDITOR PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_set_view_range(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_set_working_range(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_folders(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_create_folder(ue_PyUObject *, PyObject *); From f1e905099327ebd6d41336e309bf146e14373341 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 14:25:37 +0200 Subject: [PATCH 07/62] fixed 4.17 build --- .../Private/Wrappers/UEPyFFoliageInstance.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp index 2bc9e7b0c..951b25ae6 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp @@ -141,12 +141,13 @@ static PyObject *py_ue_ffoliage_instance_get_instance_id(ue_PyFFoliageInstance * return PyLong_FromLong(self->instance_id); } - +#if ENGINE_MINOR_VERSION > 18 static PyObject *py_ue_ffoliage_instance_get_base_component(ue_PyFFoliageInstance *self, void *closure) { get_instance(self); Py_RETURN_UOBJECT(instance->BaseComponent); } +#endif @@ -161,6 +162,9 @@ static PyGetSetDef ue_PyFFoliageInstance_getseters[] = { { (char *)"guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char *)"", NULL }, { (char *)"base_id", (getter)py_ue_ffoliage_instance_get_base_id, nullptr, (char *)"", NULL }, { (char *)"instance_id", (getter)py_ue_ffoliage_instance_get_instance_id, nullptr, (char *)"", NULL }, +#if ENGINE_MINOR_VERSION > 18 + { (char *)"base_component", (getter)py_ue_ffoliage_instance_get_base_component, nullptr, (char *)"", NULL }, +#endif { NULL } /* Sentinel */ }; From b8d73dc95f82ffa20381d17ff932a4c6d135b614 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 14:32:53 +0200 Subject: [PATCH 08/62] fixed 4.19 build --- .../Private/Wrappers/UEPyFFoliageInstance.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp index 951b25ae6..b3205f03e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp @@ -141,7 +141,7 @@ static PyObject *py_ue_ffoliage_instance_get_instance_id(ue_PyFFoliageInstance * return PyLong_FromLong(self->instance_id); } -#if ENGINE_MINOR_VERSION > 18 +#if ENGINE_MINOR_VERSION > 19 static PyObject *py_ue_ffoliage_instance_get_base_component(ue_PyFFoliageInstance *self, void *closure) { get_instance(self); @@ -162,7 +162,7 @@ static PyGetSetDef ue_PyFFoliageInstance_getseters[] = { { (char *)"guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char *)"", NULL }, { (char *)"base_id", (getter)py_ue_ffoliage_instance_get_base_id, nullptr, (char *)"", NULL }, { (char *)"instance_id", (getter)py_ue_ffoliage_instance_get_instance_id, nullptr, (char *)"", NULL }, -#if ENGINE_MINOR_VERSION > 18 +#if ENGINE_MINOR_VERSION > 19 { (char *)"base_component", (getter)py_ue_ffoliage_instance_get_base_component, nullptr, (char *)"", NULL }, #endif { NULL } /* Sentinel */ From b27954804db1ef4a72f94a785708efcea9fea89e Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 20 Oct 2018 16:07:06 +0200 Subject: [PATCH 09/62] fixed 4.21 build --- Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 128f09b29..696905e97 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -94,7 +94,11 @@ static void ImportTransformChannel(const FInterpCurveFloat& Source, FMovieSceneF } FFrameNumber KeyTime = (Source.Points[KeyIndex].InVal * DestFrameRate).RoundToFrame(); +#if ENGINE_MINOR_VERSION > 20 + FMatineeImportTools::SetOrAddKey(ChannelData, KeyTime, Source.Points[KeyIndex].OutVal, ArriveTangent, LeaveTangent, Source.Points[KeyIndex].InterpMode, DestFrameRate); +#else FMatineeImportTools::SetOrAddKey(ChannelData, KeyTime, Source.Points[KeyIndex].OutVal, ArriveTangent, LeaveTangent, Source.Points[KeyIndex].InterpMode); +#endif } Dest->AutoSetTangents(); From 1043b33e59f306f927d70e3e12b24b82668d4ca7 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Tue, 6 Nov 2018 19:57:26 +0100 Subject: [PATCH 10/62] added static_mesh_import_lod() --- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 ++ .../Private/UObject/UEPyStaticMesh.cpp | 21 +++++++++++++++++++ .../Private/UObject/UEPyStaticMesh.h | 1 + 3 files changed, 24 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 98c0830dd..5827f865b 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1137,6 +1137,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "static_mesh_generate_kdop18", (PyCFunction)py_ue_static_mesh_generate_kdop18, METH_VARARGS, "" }, { "static_mesh_generate_kdop26", (PyCFunction)py_ue_static_mesh_generate_kdop26, METH_VARARGS, "" }, + { "static_mesh_import_lod", (PyCFunction)py_ue_static_mesh_import_lod, METH_VARARGS, "" }, + #endif // Viewport diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp index deb05477e..1111ac4ee 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp @@ -6,6 +6,7 @@ #include "Engine/StaticMesh.h" #include "Wrappers/UEPyFRawMesh.h" #include "Editor/UnrealEd/Private/GeomFitUtils.h" +#include "FbxMeshUtils.h" static PyObject *generate_kdop(ue_PyUObject *self, const FVector *directions, uint32 num_directions) { @@ -116,4 +117,24 @@ PyObject *py_ue_static_mesh_get_raw_mesh(ue_PyUObject *self, PyObject * args) return py_ue_new_fraw_mesh(raw_mesh); } +PyObject *py_ue_static_mesh_import_lod(ue_PyUObject *self, PyObject * args) +{ + ue_py_check(self); + + char *filename; + int lod_level; + if (!PyArg_ParseTuple(args, "si:static_mesh_import_lod", &filename, &lod_level)) + return nullptr; + + UStaticMesh *mesh = ue_py_check_type(self); + if (!mesh) + return PyErr_Format(PyExc_Exception, "uobject is not a UStaticMesh"); + + if (FbxMeshUtils::ImportStaticMeshLOD(mesh, FString(UTF8_TO_TCHAR(filename)), lod_level)) + { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + #endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h index 219d68761..9874520cf 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h @@ -14,4 +14,5 @@ PyObject *py_ue_static_mesh_generate_kdop10y(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_generate_kdop10z(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_generate_kdop18(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_generate_kdop26(ue_PyUObject *, PyObject *); +PyObject *py_ue_static_mesh_import_lod(ue_PyUObject *, PyObject *); #endif \ No newline at end of file From 2f72762fd7c9973b4b0101fc3eede247fd3618ba Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 8 Nov 2018 11:41:34 -0700 Subject: [PATCH 11/62] added support for FVector, FRotator, FLinearColor, FColor, FTransform, and FQuat to Python methods that are UFUNCTIONs --- .../UnrealEnginePython/Private/UEPyModule.cpp | 38 ++++++++++++++++++- .../Private/Wrappers/UEPyFColor.cpp | 2 +- .../Private/Wrappers/UEPyFColor.h | 4 +- .../Private/Wrappers/UEPyFLinearColor.cpp | 2 +- .../Private/Wrappers/UEPyFLinearColor.h | 4 +- .../Private/Wrappers/UEPyFQuat.cpp | 2 +- .../Private/Wrappers/UEPyFQuat.h | 4 +- .../Private/Wrappers/UEPyFRotator.cpp | 2 +- .../Private/Wrappers/UEPyFRotator.h | 4 +- .../Private/Wrappers/UEPyFTransform.cpp | 4 +- .../Private/Wrappers/UEPyFTransform.h | 4 +- .../Private/Wrappers/UEPyFVector.cpp | 2 +- .../Private/Wrappers/UEPyFVector.h | 4 +- 13 files changed, 62 insertions(+), 14 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 5827f865b..8b4a174f2 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3151,6 +3151,42 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } + else if ((PyTypeObject *)value == &ue_PyFVectorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)value == &ue_PyFRotatorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)value == &ue_PyFLinearColorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)value == &ue_PyFColorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)value == &ue_PyFTransformType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)value == &ue_PyFQuatType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(value)) { @@ -3179,7 +3215,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ } } } - // TODO add native types (like vectors, rotators...) + if (prop) { prop->SetPropertyFlags(CPF_Parm); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp index d71188d97..0105dd254 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.cpp @@ -103,7 +103,7 @@ static PyObject *ue_PyFColor_str(ue_PyFColor *self) self->color.R, self->color.G, self->color.B, self->color.A); } -static PyTypeObject ue_PyFColorType = { +PyTypeObject ue_PyFColorType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FColor", /* tp_name */ sizeof(ue_PyFColor), /* tp_basicsize */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.h index ef75b1832..d3a1013e7 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFColor.h @@ -11,6 +11,8 @@ typedef struct FColor color; } ue_PyFColor; +extern PyTypeObject ue_PyFColorType; + PyObject *py_ue_new_fcolor(FColor); ue_PyFColor *py_ue_is_fcolor(PyObject *); @@ -18,4 +20,4 @@ void ue_python_init_fcolor(PyObject *); bool py_ue_color_arg(PyObject *, FColor &); -bool py_ue_get_fcolor(PyObject *, FColor &); \ No newline at end of file +bool py_ue_get_fcolor(PyObject *, FColor &); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.cpp index 056411506..5ca0eb83a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.cpp @@ -106,7 +106,7 @@ static PyObject *ue_PyFLinearColor_str(ue_PyFLinearColor *self) PyFloat_FromDouble(self->color.A)); } -static PyTypeObject ue_PyFLinearColorType = { +PyTypeObject ue_PyFLinearColorType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FLinearColor", /* tp_name */ sizeof(ue_PyFLinearColor), /* tp_basicsize */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.h index 986ecd2aa..2ade8c420 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFLinearColor.h @@ -11,6 +11,8 @@ typedef struct FLinearColor color; } ue_PyFLinearColor; +extern PyTypeObject ue_PyFLinearColorType; + PyObject *py_ue_new_flinearcolor(FLinearColor); ue_PyFLinearColor *py_ue_is_flinearcolor(PyObject *); @@ -18,4 +20,4 @@ void ue_python_init_flinearcolor(PyObject *); bool py_ue_linearcolor_arg(PyObject *, FLinearColor &); -bool py_ue_get_flinearcolor(PyObject *, FLinearColor &); \ No newline at end of file +bool py_ue_get_flinearcolor(PyObject *, FLinearColor &); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp index 74d914848..41faf7383 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.cpp @@ -152,7 +152,7 @@ static PyObject *ue_PyFQuat_str(ue_PyFQuat *self) PyFloat_FromDouble(self->quat.X), PyFloat_FromDouble(self->quat.Y), PyFloat_FromDouble(self->quat.Z), PyFloat_FromDouble(self->quat.W)); } -static PyTypeObject ue_PyFQuatType = { +PyTypeObject ue_PyFQuatType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FQuat", /* tp_name */ sizeof(ue_PyFQuat), /* tp_basicsize */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h index 1a39ce0a8..94bd2cf9e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFQuat.h @@ -11,9 +11,11 @@ typedef struct FQuat quat; } ue_PyFQuat; +extern PyTypeObject ue_PyFQuatType; + PyObject *py_ue_new_fquat(FQuat); ue_PyFQuat *py_ue_is_fquat(PyObject *); void ue_python_init_fquat(PyObject *); -bool py_ue_quat_arg(PyObject *, FQuat &); \ No newline at end of file +bool py_ue_quat_arg(PyObject *, FQuat &); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp index edcc35348..3558faa5b 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.cpp @@ -93,7 +93,7 @@ static PyObject *ue_PyFRotator_str(ue_PyFRotator *self) PyFloat_FromDouble(self->rot.Roll), PyFloat_FromDouble(self->rot.Pitch), PyFloat_FromDouble(self->rot.Yaw)); } -static PyTypeObject ue_PyFRotatorType = { +PyTypeObject ue_PyFRotatorType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FRotator", /* tp_name */ sizeof(ue_PyFRotator), /* tp_basicsize */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h index a4ea71a84..2d3f6df4c 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFRotator.h @@ -10,9 +10,11 @@ typedef struct { FRotator rot; } ue_PyFRotator; +extern PyTypeObject ue_PyFRotatorType; + PyObject *py_ue_new_frotator(FRotator); ue_PyFRotator *py_ue_is_frotator(PyObject *); void ue_python_init_frotator(PyObject *); -bool py_ue_rotator_arg(PyObject *, FRotator &); \ No newline at end of file +bool py_ue_rotator_arg(PyObject *, FRotator &); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp index 11548407a..b3a6b654a 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.cpp @@ -220,7 +220,7 @@ static PyObject *ue_PyFTransform_str(ue_PyFTransform *self) } -static PyTypeObject ue_PyFTransformType = { +PyTypeObject ue_PyFTransformType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FTransform", /* tp_name */ sizeof(ue_PyFTransform), /* tp_basicsize */ @@ -435,4 +435,4 @@ bool py_ue_transform_arg(PyObject *args, FTransform &t) t.SetRotation(FRotator(pitch, yaw, roll).Quaternion()); t.SetScale3D(FVector(sx, sy, sz)); return true; -} \ No newline at end of file +} diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h index 3cb64312f..86f58e0f9 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFTransform.h @@ -10,8 +10,10 @@ typedef struct { FTransform transform; } ue_PyFTransform; +extern PyTypeObject ue_PyFTransformType; + PyObject *py_ue_new_ftransform(FTransform); ue_PyFTransform *py_ue_is_ftransform(PyObject *); void ue_python_init_ftransform(PyObject *); -bool py_ue_transform_arg(PyObject *, FTransform &); \ No newline at end of file +bool py_ue_transform_arg(PyObject *, FTransform &); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index 3380d82df..430e1caa2 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -151,7 +151,7 @@ static PyObject *ue_PyFVector_str(ue_PyFVector *self) PyFloat_FromDouble(self->vec.X), PyFloat_FromDouble(self->vec.Y), PyFloat_FromDouble(self->vec.Z)); } -static PyTypeObject ue_PyFVectorType = { +PyTypeObject ue_PyFVectorType = { PyVarObject_HEAD_INIT(NULL, 0) "unreal_engine.FVector", /* tp_name */ sizeof(ue_PyFVector), /* tp_basicsize */ diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h index e23935943..b7b0853e8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.h @@ -11,9 +11,11 @@ typedef struct FVector vec; } ue_PyFVector; +extern PyTypeObject ue_PyFVectorType; + PyObject *py_ue_new_fvector(FVector); ue_PyFVector *py_ue_is_fvector(PyObject *); void ue_python_init_fvector(PyObject *); -bool py_ue_vector_arg(PyObject *, FVector &); \ No newline at end of file +bool py_ue_vector_arg(PyObject *, FVector &); From 378fe7df642972927de16bf5d1da0309e18d9e4c Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 9 Nov 2018 11:04:31 -0700 Subject: [PATCH 12/62] also support native structs as return types --- .../UnrealEnginePython/Private/UEPyModule.cpp | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 8b4a174f2..26d7c1e90 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3258,6 +3258,42 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } + else if ((PyTypeObject *)py_return_value == &ue_PyFVectorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)py_return_value == &ue_PyFRotatorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)py_return_value == &ue_PyFLinearColorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)py_return_value == &ue_PyFColorType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)py_return_value == &ue_PyFTransformType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } + else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value)) { @@ -3286,7 +3322,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ } } } - // TODO add native types (like vectors, rotators...) + if (prop) { prop->SetPropertyFlags(CPF_Parm | CPF_OutParm | CPF_ReturnParm); From da04e62f0ab7a5a08a1884dbb1986055d46f6bdd Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 10 Nov 2018 10:34:09 +0100 Subject: [PATCH 13/62] fixed 4.21 --- .../Private/SlateApplication/UEPyFSlateApplication.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp index 358bf174d..33982e626 100644 --- a/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp +++ b/Source/UnrealEnginePython/Private/SlateApplication/UEPyFSlateApplication.cpp @@ -157,7 +157,11 @@ static PyObject *py_ue_process_key_char_event(PyObject *cls, PyObject * args) static PyObject *py_ue_create(PyObject *cls, PyObject * args) { #if ENGINE_MINOR_VERSION > 18 +#if ENGINE_MINOR_VERSION > 20 + FSlateApplication::InitHighDPI(true); +#else FSlateApplication::InitHighDPI(); +#endif #endif FSlateApplication::Create(); From 7611c527d41a8692c847a0a9129c548d7a12fafb Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sat, 17 Nov 2018 14:44:19 +0100 Subject: [PATCH 14/62] fixed save_package() in 4.21 --- Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index ad4fc2259..e7fcb7de5 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -2116,7 +2116,7 @@ PyObject *py_ue_save_package(ue_PyUObject * self, PyObject * args) package->FileName = *FPackageName::LongPackageNameToFilename(package->GetPathName(), bIsMap ? FPackageName::GetMapPackageExtension() : FPackageName::GetAssetPackageExtension()); } - if (UPackage::SavePackage(package, u_object, RF_NoFlags, *package->FileName.ToString())) + if (UPackage::SavePackage(package, u_object, RF_Standalone, *package->FileName.ToString())) { FAssetRegistryModule::AssetCreated(u_object); Py_RETURN_UOBJECT(u_object); From ed1e6d8a4c2c8bcb3630d85adda2d0d266f6721c Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 22 Nov 2018 16:44:46 -0700 Subject: [PATCH 15/62] added support for UEnums in function args and return values --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 26d7c1e90..009bc5ac1 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3214,6 +3214,14 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop = prop_base; } } + else if (py_obj->ue_object->IsA()) + { + UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + prop_enum->SetEnum((UEnum*)py_obj->ue_object); + prop_enum->AddCppProperty(prop_underlying); + prop = prop_enum; + } } if (prop) @@ -3321,6 +3329,14 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop = prop_base; } } + else if (py_obj->ue_object->IsA()) + { + UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + prop_enum->SetEnum((UEnum*)py_obj->ue_object); + prop_enum->AddCppProperty(prop_underlying); + prop = prop_enum; + } } if (prop) From 376e9c507491ec515d99f4910d6837c319b4f86b Mon Sep 17 00:00:00 2001 From: dave Date: Sat, 24 Nov 2018 17:01:39 -0700 Subject: [PATCH 16/62] added support for structs and class objects in function params and return values --- .../UnrealEnginePython/Private/UEPyModule.cpp | 151 ++++++++++++------ 1 file changed, 104 insertions(+), 47 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 009bc5ac1..5e7cef9cc 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -2642,9 +2642,18 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (auto casted_prop = Cast(prop)) { - // ensure the object type is correct, otherwise crash could happen (soon or later) - if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass)) - return false; + // if the property specifies an interface, the object must be of a class that implements it + if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface)) + { + if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass)) + return false; + } + else + { + // ensure the object type is correct, otherwise crash could happen (soon or later) + if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass)) + return false; + } casted_prop->SetObjectPropertyValue_InContainer(buffer, ue_obj->ue_object, index); @@ -3187,32 +3196,50 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } + else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type)) + { + // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) + PyObject *type_args = PyObject_GetAttrString(value, "__args__"); + if (!type_args) + { + UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (PyTuple_Size(type_args) != 1) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + PyObject *py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + if (!py_obj) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (!py_obj->ue_object->IsA()) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); + return nullptr; + } + UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_class->SetMetaClass((UClass*)py_obj->ue_object); + prop_class->PropertyClass = UClass::StaticClass(); + prop = prop_class; + Py_DECREF(type_args); + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(value)) { if (py_obj->ue_object->IsA()) { UClass *p_u_class = (UClass *)py_obj->ue_object; - if (p_u_class->IsChildOf()) - { - UClassProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - if (p_u_class == UClass::StaticClass()) - { - prop_base->SetMetaClass(UObject::StaticClass()); - } - else - { - prop_base->SetMetaClass(p_u_class->GetClass()); - } - prop_base->PropertyClass = UClass::StaticClass(); - prop = prop_base; - } - else - { - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_base->SetPropertyClass(p_u_class); - prop = prop_base; - } + UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_base->SetPropertyClass(p_u_class); + prop = prop_base; } else if (py_obj->ue_object->IsA()) { @@ -3221,6 +3248,12 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_enum->SetEnum((UEnum*)py_obj->ue_object); prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; + } + else if (py_obj->ue_object->IsA()) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; + prop = prop_struct; } } @@ -3302,33 +3335,51 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } + else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type)) + { + // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) + PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__"); + if (!type_args) + { + UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (PyTuple_Size(type_args) != 1) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + PyObject *py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + if (!py_obj) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (!py_obj->ue_object->IsA()) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); + return nullptr; + } + UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_class->SetMetaClass((UClass*)py_obj->ue_object); + prop_class->PropertyClass = UClass::StaticClass(); + prop = prop_class; + Py_DECREF(type_args); + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value)) { - if (py_obj->ue_object->IsA()) - { - UClass *p_u_class = (UClass *)py_obj->ue_object; - if (p_u_class->IsChildOf()) - { - UClassProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - if (p_u_class == UClass::StaticClass()) - { - prop_base->SetMetaClass(UObject::StaticClass()); - } - else - { - prop_base->SetMetaClass(p_u_class->GetClass()); - } - prop_base->PropertyClass = UClass::StaticClass(); - prop = prop_base; - } - else - { - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_base->SetPropertyClass(p_u_class); - prop = prop_base; - } - } + if (py_obj->ue_object->IsA()) + { + UClass *p_u_class = (UClass *)py_obj->ue_object; + UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_base->SetPropertyClass(p_u_class); + prop = prop_base; + } else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3336,6 +3387,12 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_enum->SetEnum((UEnum*)py_obj->ue_object); prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; + } + else if (py_obj->ue_object->IsA()) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; + prop = prop_struct; } } From 6544d279c71715fe23e43c0db058c3beab2b04b1 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 10:32:19 +0100 Subject: [PATCH 17/62] fixed #612 --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 5e7cef9cc..f91021b4f 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -2587,7 +2587,8 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in if (casted_prop->Struct == py_u_struct->u_struct) { uint8 *dest = casted_prop->ContainerPtrToValuePtr(buffer, index); - FMemory::Memcpy(dest, py_u_struct->u_struct_ptr, py_u_struct->u_struct->GetStructureSize()); + py_u_struct->u_struct->InitializeStruct(dest); + py_u_struct->u_struct->CopyScriptStruct(dest, py_u_struct->u_struct_ptr); return true; } } From 44f90bde22b48486117f3e92abe16502081ecfe5 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 11:22:35 +0100 Subject: [PATCH 18/62] added submenu support, #603 --- .../Private/Slate/UEPyFMenuBuilder.cpp | 27 +++++++++++++++++++ .../Private/Slate/UEPySlate.cpp | 18 +++++++++++-- .../Private/Slate/UEPySlateDelegate.h | 1 + .../Private/UnrealEnginePython.cpp | 4 +++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index d0d5a5549..3157ec4f0 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -63,6 +63,32 @@ static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyO Py_RETURN_NONE; } +static PyObject *py_ue_fmenu_builder_add_sub_menu(ue_PyFMenuBuilder *self, PyObject * args) +{ + char *label; + char *tooltip; + PyObject *py_callable; + PyObject *py_bool = nullptr; + if (!PyArg_ParseTuple(args, "ssO|O:add_sub_menu", &label, &tooltip, &py_callable, &py_bool)) + return nullptr; + + if (!PyCallable_Check(py_callable)) + { + return PyErr_Format(PyExc_Exception, "argument is not callable"); + } + + + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); + + FNewMenuDelegate menu_delegate; + menu_delegate.BindSP(py_delegate, &FPythonSlateDelegate::SubMenuPyBuilder); + + + self->menu_builder.AddSubMenu(FText::FromString(UTF8_TO_TCHAR(label)), FText::FromString(UTF8_TO_TCHAR(tooltip)), menu_delegate, (py_bool && PyObject_IsTrue(py_bool)) ? true : false); + + Py_RETURN_NONE; +} + static PyObject *py_ue_fmenu_builder_add_menu_separator(ue_PyFMenuBuilder *self, PyObject * args) { char *name = nullptr; @@ -130,6 +156,7 @@ static PyMethodDef ue_PyFMenuBuilder_methods[] = { { "add_menu_entry", (PyCFunction)py_ue_fmenu_builder_add_menu_entry, METH_VARARGS, "" }, { "add_menu_separator", (PyCFunction)py_ue_fmenu_builder_add_menu_separator, METH_VARARGS, "" }, { "add_search_widget", (PyCFunction)py_ue_fmenu_builder_add_search_widget, METH_VARARGS, "" }, + { "add_sub_menu", (PyCFunction)py_ue_fmenu_builder_add_sub_menu, METH_VARARGS, "" }, #if WITH_EDITOR { "add_asset_actions", (PyCFunction)py_ue_fmenu_builder_add_asset_actions, METH_VARARGS, "" }, #endif diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index ae0fade73..f51285857 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -416,6 +416,20 @@ void FPythonSlateDelegate::MenuPyAssetBuilder(FMenuBuilder &Builder, TArray FPythonSlateDelegate::OnExtendContentBrowserMenu(const TArray& SelectedAssets) { TSharedRef Extender(new FExtender()); @@ -1321,6 +1335,7 @@ PyObject *py_unreal_engine_add_menu_bar_extension(PyObject * self, PyObject * ar if (!PyCallable_Check(py_callable)) return PyErr_Format(PyExc_Exception, "argument is not callable"); + TSharedRef *commands = new TSharedRef(new FPythonSlateCommands()); commands->Get().Setup(command_name, py_callable); @@ -1332,8 +1347,7 @@ PyObject *py_unreal_engine_add_menu_bar_extension(PyObject * self, PyObject * ar ExtensibleModule.GetMenuExtensibilityManager()->AddExtender(extender); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject *py_unreal_engine_add_tool_bar_extension(PyObject * self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h index f2290e0d8..61b79d01c 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h @@ -45,6 +45,7 @@ class FPythonSlateDelegate : public FPythonSmartDelegate void OnAssetSelected(const FAssetData& AssetData); TSharedRef OnExtendContentBrowserMenu(const TArray &SelectedAssets); void MenuPyAssetBuilder(FMenuBuilder &Builder, TArray SelectedAssets); + void SubMenuPyBuilder(FMenuBuilder &Builder); void OnAssetChanged(const FAssetData &AssetData); bool OnShouldFilterAsset(const FAssetData& AssetData); #endif diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index bb79b8c8f..cabe29259 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -362,7 +362,11 @@ void FUnrealEnginePythonModule::StartupModule() const int32 MaxPathVarLen = 32768; FString OrigPathVar = FString::ChrN(MaxPathVarLen, TEXT('\0')); +#if ENGINE_MINOR_VERSION >= 21 + OrigPathVar = FPlatformMisc::GetEnvironmentVariable(TEXT("PATH")); +#else FPlatformMisc::GetEnvironmentVariable(TEXT("PATH"), OrigPathVar.GetCharArray().GetData(), MaxPathVarLen); +#endif // Get the current path and remove elements with python in them, we don't want any conflicts const TCHAR* PathDelimiter = FPlatformMisc::GetPathVarDelimiter(); From 3eb78c53e6883406b20ca9e1b4ca8455356e773d Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 11:23:12 +0100 Subject: [PATCH 19/62] added example for submenu --- examples/sub_menu.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 examples/sub_menu.py diff --git a/examples/sub_menu.py b/examples/sub_menu.py new file mode 100644 index 000000000..9d7901f2f --- /dev/null +++ b/examples/sub_menu.py @@ -0,0 +1,30 @@ +import unreal_engine as ue + +def open_submenu001(builder): + builder.begin_section('submenu001', 'i am a tooltip') + builder.add_menu_entry('sub_one', 'tooltip', lambda: ue.log('hello from submenu001')) + builder.add_menu_entry('sub_one_2', 'tooltip 2', lambda: ue.log('hello again')) + builder.end_section() + +def open_sub_submenu(builder): + builder.begin_section('sub_submenu003', 'i am a tooltip for the submenu') + builder.add_menu_entry('sub_sub_three', 'tooltip', lambda: ue.log('hello from sub_submenu003')) + builder.end_section() + +def open_submenu002(builder): + builder.begin_section('submenu002', 'i am a tooltip') + builder.add_menu_entry('sub_two', 'tooltip', lambda: ue.log('hello from submenu002')) + builder.add_sub_menu('sub sub menu', 'tooltip !', open_sub_submenu) + builder.end_section() + + +def open_menu(builder): + builder.begin_section('test1', 'test2') + builder.add_menu_entry('one', 'two', lambda: ue.log('ciao 1')) + builder.add_sub_menu('i am a submenu', 'tooltip for the submenu', open_submenu001) + builder.add_menu_entry('three', 'four', lambda: ue.log('ciao 2')) + builder.add_sub_menu('i am another submenu', 'tooltip for the second submenu', open_submenu002) + builder.end_section() + + +ue.add_menu_bar_extension('SimpleMenuBarExtension', open_menu) \ No newline at end of file From c2901db4d48de6deae2a9f5232208f229f21293d Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 12:06:57 +0100 Subject: [PATCH 20/62] closed #575 --- .../Private/Slate/UEPySlate.cpp | 22 ++++++++++--------- .../Private/Slate/UEPySlateDelegate.h | 2 +- .../UnrealEnginePython/Private/UEPyModule.cpp | 2 +- .../Private/Wrappers/UEPyFFoliageInstance.cpp | 9 +++++++- .../Private/Wrappers/UEPyFFoliageInstance.h | 2 ++ 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index f51285857..0cc988240 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -417,6 +417,18 @@ void FPythonSlateDelegate::MenuPyAssetBuilder(FMenuBuilder &Builder, TArray FPythonSlateDelegate::OnExtendContentBrowserMenu(const TArray& SelectedAssets) +{ + TSharedRef Extender(new FExtender()); + + Extender->AddMenuExtension((char *)"GetAssetActions", EExtensionHook::After, nullptr, FMenuExtensionDelegate::CreateSP(this, &FPythonSlateDelegate::MenuPyAssetBuilder, SelectedAssets)); + + return Extender; +} + +#endif + + void FPythonSlateDelegate::SubMenuPyBuilder(FMenuBuilder &Builder) { FScopePythonGIL gil; @@ -430,16 +442,6 @@ void FPythonSlateDelegate::SubMenuPyBuilder(FMenuBuilder &Builder) Py_DECREF(ret); } -TSharedRef FPythonSlateDelegate::OnExtendContentBrowserMenu(const TArray& SelectedAssets) -{ - TSharedRef Extender(new FExtender()); - - Extender->AddMenuExtension((char *)"GetAssetActions", EExtensionHook::After, nullptr, FMenuExtensionDelegate::CreateSP(this, &FPythonSlateDelegate::MenuPyAssetBuilder, SelectedAssets)); - - return Extender; -} - -#endif TSharedRef FPythonSlateDelegate::OnGenerateWidget(TSharedPtr py_item) { diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h index 61b79d01c..f74f9fe34 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlateDelegate.h @@ -45,12 +45,12 @@ class FPythonSlateDelegate : public FPythonSmartDelegate void OnAssetSelected(const FAssetData& AssetData); TSharedRef OnExtendContentBrowserMenu(const TArray &SelectedAssets); void MenuPyAssetBuilder(FMenuBuilder &Builder, TArray SelectedAssets); - void SubMenuPyBuilder(FMenuBuilder &Builder); void OnAssetChanged(const FAssetData &AssetData); bool OnShouldFilterAsset(const FAssetData& AssetData); #endif void OnWindowClosed(const TSharedRef &Window); + void SubMenuPyBuilder(FMenuBuilder &Builder); TSharedPtr OnContextMenuOpening(); TSharedRef OnGenerateWidget(TSharedPtr py_item); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index f91021b4f..3904df579 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1697,9 +1697,9 @@ void unreal_engine_init_py_module() ue_python_init_enumsimporter(new_unreal_engine_module); ue_python_init_ustructsimporter(new_unreal_engine_module); +#if WITH_EDITOR ue_python_init_ffoliage_instance(new_unreal_engine_module); -#if WITH_EDITOR ue_python_init_fslowtask(new_unreal_engine_module); ue_python_init_swidget(new_unreal_engine_module); ue_python_init_farfilter(new_unreal_engine_module); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp index b3205f03e..1dbab35cd 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp @@ -6,6 +6,8 @@ #include "Components/ActorComponent.h" #include "Runtime/Foliage/Public/InstancedFoliageActor.h" +#if WITH_EDITOR + #define get_instance(x) FFoliageInstance *instance = get_foliage_instance(x);\ if (!instance)\ return nullptr; @@ -14,6 +16,8 @@ if (!instance)\ return -1; + + static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance *self) { if (!self->foliage_actor.IsValid()) @@ -45,6 +49,7 @@ static PyObject *ue_PyFFoliageInstance_str(ue_PyFFoliageInstance *self) self->instance_id); } + static PyObject *py_ue_ffoliage_instance_get_location(ue_PyFFoliageInstance *self, void *closure) { get_instance(self); @@ -257,4 +262,6 @@ PyObject *py_ue_new_ffoliage_instance(AInstancedFoliageActor *foliage_actor, UFo ret->foliage_type = TWeakObjectPtr(foliage_type); ret->instance_id = instance_id; return (PyObject *)ret; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.h index 409b37fad..ab65fc3c8 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.h +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.h @@ -1,6 +1,7 @@ #pragma once #include "UnrealEnginePython.h" +#if WITH_EDITOR #include "InstancedFoliage.h" typedef struct @@ -14,3 +15,4 @@ typedef struct void ue_python_init_ffoliage_instance(PyObject *); PyObject *py_ue_new_ffoliage_instance(AInstancedFoliageActor *foliage_actor, UFoliageType *foliage_type, int32 instance_id); +#endif From d5386c3b4c44394c175fd84e907e80a24b8b8476 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 13:08:16 +0100 Subject: [PATCH 21/62] added get_asset_identifier_referencers() --- .../UnrealEnginePython/Private/UEPyEditor.cpp | 38 ++++++++++++++++--- .../UnrealEnginePython/Private/UEPyEditor.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 1 + 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index f23f7c59e..3af0860f9 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -639,10 +639,11 @@ PyObject *py_unreal_engine_create_asset(PyObject * self, PyObject * args) PyObject *py_unreal_engine_get_asset_referencers(PyObject * self, PyObject * args) { char *path; + int depency_type = (int)EAssetRegistryDependencyType::All; - if (!PyArg_ParseTuple(args, "s:get_asset_referencers", &path)) + if (!PyArg_ParseTuple(args, "s|i:get_asset_referencers", &path, &depency_type)) { - return NULL; + return nullptr; } if (!GEditor) @@ -650,7 +651,7 @@ PyObject *py_unreal_engine_get_asset_referencers(PyObject * self, PyObject * arg FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked("AssetRegistry"); TArray referencers; - AssetRegistryModule.Get().GetReferencers(UTF8_TO_TCHAR(path), referencers); + AssetRegistryModule.Get().GetReferencers(UTF8_TO_TCHAR(path), referencers, (EAssetRegistryDependencyType::Type) depency_type); PyObject *referencers_list = PyList_New(0); for (FName name : referencers) @@ -660,11 +661,38 @@ PyObject *py_unreal_engine_get_asset_referencers(PyObject * self, PyObject * arg return referencers_list; } +PyObject *py_unreal_engine_get_asset_identifier_referencers(PyObject * self, PyObject * args) +{ + char *path; + int depency_type = (int)EAssetRegistryDependencyType::All; + + if (!PyArg_ParseTuple(args, "s|i:get_asset_identifier_referencers", &path, &depency_type)) + { + return nullptr; + } + + if (!GEditor) + return PyErr_Format(PyExc_Exception, "no GEditor found"); + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked("AssetRegistry"); + TArray referencers; + AssetRegistryModule.Get().GetReferencers(FAssetIdentifier::FromString(UTF8_TO_TCHAR(path)), referencers, (EAssetRegistryDependencyType::Type) depency_type); + + PyObject *referencers_list = PyList_New(0); + for (FAssetIdentifier identifier : referencers) + { + PyList_Append(referencers_list, PyUnicode_FromString(TCHAR_TO_UTF8(*identifier.ToString()))); + } + return referencers_list; +} + + PyObject *py_unreal_engine_get_asset_dependencies(PyObject * self, PyObject * args) { char *path; + int depency_type = (int)EAssetRegistryDependencyType::All; - if (!PyArg_ParseTuple(args, "s:get_asset_dependencies", &path)) + if (!PyArg_ParseTuple(args, "s|i:get_asset_dependencies", &path, &depency_type)) { return NULL; } @@ -674,7 +702,7 @@ PyObject *py_unreal_engine_get_asset_dependencies(PyObject * self, PyObject * ar FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked("AssetRegistry"); TArray dependencies; - AssetRegistryModule.Get().GetDependencies(UTF8_TO_TCHAR(path), dependencies); + AssetRegistryModule.Get().GetDependencies(UTF8_TO_TCHAR(path), dependencies, (EAssetRegistryDependencyType::Type) depency_type); PyObject *dependencies_list = PyList_New(0); for (FName name : dependencies) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index f179c1788..d3399c8fd 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -95,6 +95,7 @@ PyObject *py_unreal_engine_create_material_instance(PyObject *, PyObject *); PyObject *py_unreal_engine_allow_actor_script_execution_in_editor(PyObject *, PyObject *); PyObject *py_unreal_engine_get_asset_referencers(PyObject *, PyObject *); +PyObject *py_unreal_engine_get_asset_identifier_referencers(PyObject *, PyObject *); PyObject *py_unreal_engine_get_asset_dependencies(PyObject *, PyObject *); PyObject *py_unreal_engine_open_editor_for_asset(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 3904df579..435890662 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -341,6 +341,7 @@ static PyMethodDef unreal_engine_methods[] = { { "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, "" }, + { "get_asset_identifier_referencers", py_unreal_engine_get_asset_identifier_referencers, METH_VARARGS, "" }, { "get_asset_dependencies", py_unreal_engine_get_asset_dependencies, METH_VARARGS, "" }, { "rename_asset", py_unreal_engine_rename_asset, METH_VARARGS, "" }, From 5031be3ef5473b07517c5734ab7a6dea92ae3931 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 13:13:16 +0100 Subject: [PATCH 22/62] added ue.get_long_package_asset_name() --- Source/UnrealEnginePython/Private/UEPyEditor.cpp | 13 +++++++++++++ Source/UnrealEnginePython/Private/UEPyEditor.h | 1 + Source/UnrealEnginePython/Private/UEPyModule.cpp | 1 + 3 files changed, 15 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 3af0860f9..4d117dff4 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -725,6 +725,19 @@ PyObject *py_unreal_engine_get_long_package_path(PyObject * self, PyObject * arg return PyUnicode_FromString(TCHAR_TO_UTF8(*(package_path))); } +PyObject *py_unreal_engine_get_long_package_asset_name(PyObject * self, PyObject * args) +{ + char *path; + if (!PyArg_ParseTuple(args, "s:get_long_package_asset_name", &path)) + { + return NULL; + } + + const FString asset_name = FPackageName::GetLongPackageAssetName(UTF8_TO_TCHAR(path)); + + return PyUnicode_FromString(TCHAR_TO_UTF8(*(asset_name))); +} + PyObject *py_unreal_engine_rename_asset(PyObject * self, PyObject * args) { char *path; diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index d3399c8fd..788a76ad3 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -42,6 +42,7 @@ PyObject *py_unreal_engine_duplicate_asset(PyObject *, PyObject *); PyObject *py_unreal_engine_delete_asset(PyObject *, PyObject *); PyObject *py_unreal_engine_get_long_package_path(PyObject *, PyObject *); +PyObject *py_unreal_engine_get_long_package_asset_name(PyObject *, PyObject *); PyObject *py_unreal_engine_create_blueprint(PyObject *, PyObject *); PyObject *py_unreal_engine_compile_blueprint(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 435890662..2bc1a4108 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -349,6 +349,7 @@ static PyMethodDef unreal_engine_methods[] = { { "delete_asset", py_unreal_engine_delete_asset, METH_VARARGS, "" }, { "get_long_package_path", py_unreal_engine_get_long_package_path, METH_VARARGS, "" }, + { "get_long_package_asset_name", py_unreal_engine_get_long_package_asset_name, METH_VARARGS, "" }, { "editor_command_build", py_unreal_engine_editor_command_build, METH_VARARGS, "" }, { "editor_command_build_lighting", py_unreal_engine_editor_command_build_lighting, METH_VARARGS, "" }, From 3afec1d83d125f110a1c319b6ee0dbb7ba73c555 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 13:45:56 +0100 Subject: [PATCH 23/62] improved sequencer api --- .../UnrealEnginePython/Private/UEPyModule.cpp | 246 +++++++++--------- .../Private/UObject/UEPySequencer.cpp | 40 +++ .../Private/UObject/UEPySequencer.h | 2 + 3 files changed, 166 insertions(+), 122 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 2bc1a4108..9156d5e79 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -1081,6 +1081,8 @@ static PyMethodDef ue_PyUObject_methods[] = { { "sequencer_set_view_range", (PyCFunction)py_ue_sequencer_set_view_range, METH_VARARGS, "" }, { "sequencer_set_working_range", (PyCFunction)py_ue_sequencer_set_working_range, METH_VARARGS, "" }, { "sequencer_set_section_range", (PyCFunction)py_ue_sequencer_set_section_range, METH_VARARGS, "" }, + { "sequencer_get_playback_range", (PyCFunction)py_ue_sequencer_get_playback_range, METH_VARARGS, "" }, + { "sequencer_get_selection_range", (PyCFunction)py_ue_sequencer_get_selection_range, METH_VARARGS, "" }, { "sequencer_folders", (PyCFunction)py_ue_sequencer_folders, METH_VARARGS, "" }, { "sequencer_create_folder", (PyCFunction)py_ue_sequencer_create_folder, METH_VARARGS, "" }, { "sequencer_set_display_name", (PyCFunction)py_ue_sequencer_set_display_name, METH_VARARGS, "" }, @@ -1960,7 +1962,7 @@ void unreal_engine_py_log_error() } PyErr_Clear(); - } +} // retrieve a UWorld from a generic UObject (if possible) UWorld *ue_get_uworld(ue_PyUObject *py_obj) @@ -2645,18 +2647,18 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (auto casted_prop = Cast(prop)) { - // if the property specifies an interface, the object must be of a class that implements it - if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface)) - { - if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass)) - return false; - } - else - { - // ensure the object type is correct, otherwise crash could happen (soon or later) - if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass)) - return false; - } + // if the property specifies an interface, the object must be of a class that implements it + if (casted_prop->PropertyClass->HasAnyClassFlags(CLASS_Interface)) + { + if (!ue_obj->ue_object->GetClass()->ImplementsInterface(casted_prop->PropertyClass)) + return false; + } + else + { + // ensure the object type is correct, otherwise crash could happen (soon or later) + if (!ue_obj->ue_object->IsA(casted_prop->PropertyClass)) + return false; + } casted_prop->SetObjectPropertyValue_InContainer(buffer, ue_obj->ue_object, index); @@ -3199,65 +3201,65 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type)) - { - // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) - PyObject *type_args = PyObject_GetAttrString(value, "__args__"); - if (!type_args) - { - UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); - return nullptr; - } - if (PyTuple_Size(type_args) != 1) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); - return nullptr; - } - PyObject *py_class = PyTuple_GetItem(type_args, 0); - ue_PyUObject *py_obj = ue_is_pyuobject(py_class); - if (!py_obj) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); - return nullptr; - } - if (!py_obj->ue_object->IsA()) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); - return nullptr; - } - UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_class->SetMetaClass((UClass*)py_obj->ue_object); - prop_class->PropertyClass = UClass::StaticClass(); - prop = prop_class; - Py_DECREF(type_args); - } + else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type)) + { + // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) + PyObject *type_args = PyObject_GetAttrString(value, "__args__"); + if (!type_args) + { + UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (PyTuple_Size(type_args) != 1) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + PyObject *py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + if (!py_obj) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (!py_obj->ue_object->IsA()) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); + return nullptr; + } + UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_class->SetMetaClass((UClass*)py_obj->ue_object); + prop_class->PropertyClass = UClass::StaticClass(); + prop = prop_class; + Py_DECREF(type_args); + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(value)) { if (py_obj->ue_object->IsA()) { UClass *p_u_class = (UClass *)py_obj->ue_object; - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_base->SetPropertyClass(p_u_class); - prop = prop_base; - } - else if (py_obj->ue_object->IsA()) - { - UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); - prop_enum->SetEnum((UEnum*)py_obj->ue_object); - prop_enum->AddCppProperty(prop_underlying); - prop = prop_enum; - } - else if (py_obj->ue_object->IsA()) - { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; - prop = prop_struct; - } + UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_base->SetPropertyClass(p_u_class); + prop = prop_base; + } + else if (py_obj->ue_object->IsA()) + { + UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + prop_enum->SetEnum((UEnum*)py_obj->ue_object); + prop_enum->AddCppProperty(prop_underlying); + prop = prop_enum; + } + else if (py_obj->ue_object->IsA()) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; + prop = prop_struct; + } } if (prop) @@ -3338,65 +3340,65 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type)) - { - // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) - PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__"); - if (!type_args) - { - UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); - return nullptr; - } - if (PyTuple_Size(type_args) != 1) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); - return nullptr; - } - PyObject *py_class = PyTuple_GetItem(type_args, 0); - ue_PyUObject *py_obj = ue_is_pyuobject(py_class); - if (!py_obj) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); - return nullptr; - } - if (!py_obj->ue_object->IsA()) - { - Py_DECREF(type_args); - UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); - return nullptr; - } - UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_class->SetMetaClass((UClass*)py_obj->ue_object); - prop_class->PropertyClass = UClass::StaticClass(); - prop = prop_class; - Py_DECREF(type_args); - } + else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type)) + { + // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) + PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__"); + if (!type_args) + { + UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (PyTuple_Size(type_args) != 1) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); + return nullptr; + } + PyObject *py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + if (!py_obj) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a ue_PyUObject"), UTF8_TO_TCHAR(name)); + return nullptr; + } + if (!py_obj->ue_object->IsA()) + { + Py_DECREF(type_args); + UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); + return nullptr; + } + UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_class->SetMetaClass((UClass*)py_obj->ue_object); + prop_class->PropertyClass = UClass::StaticClass(); + prop = prop_class; + Py_DECREF(type_args); + } } else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value)) { - if (py_obj->ue_object->IsA()) - { - UClass *p_u_class = (UClass *)py_obj->ue_object; - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_base->SetPropertyClass(p_u_class); - prop = prop_base; - } - else if (py_obj->ue_object->IsA()) - { - UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); - prop_enum->SetEnum((UEnum*)py_obj->ue_object); - prop_enum->AddCppProperty(prop_underlying); - prop = prop_enum; - } - else if (py_obj->ue_object->IsA()) - { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; - prop = prop_struct; - } + if (py_obj->ue_object->IsA()) + { + UClass *p_u_class = (UClass *)py_obj->ue_object; + UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_base->SetPropertyClass(p_u_class); + prop = prop_base; + } + else if (py_obj->ue_object->IsA()) + { + UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + prop_enum->SetEnum((UEnum*)py_obj->ue_object); + prop_enum->AddCppProperty(prop_underlying); + prop = prop_enum; + } + else if (py_obj->ue_object->IsA()) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; + prop = prop_struct; + } } if (prop) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 696905e97..b1325302a 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -915,6 +915,26 @@ PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *self, PyObject * args Py_RETURN_NONE; } +PyObject *py_ue_sequencer_get_playback_range(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"); + UMovieScene *scene = seq->GetMovieScene(); + +#if ENGINE_MINOR_VERSION < 20 + scene->GetPlaybackRange(); +#else + TRange range = scene->GetPlaybackRange(); + + return Py_BuildValue("(OO)", py_ue_new_fframe_number(range.GetLowerBoundValue()), py_ue_new_fframe_number(range.GetUpperBoundValue())); + +#endif +} + PyObject *py_ue_sequencer_set_working_range(ue_PyUObject *self, PyObject * args) { @@ -1013,6 +1033,26 @@ PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *self, PyObject * args) Py_RETURN_NONE; } +PyObject *py_ue_sequencer_get_selection_range(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"); + UMovieScene *scene = seq->GetMovieScene(); + +#if ENGINE_MINOR_VERSION < 20 + scene->GetSelectionRange(); +#else + TRange range = scene->GetSelectionRange(); + + return Py_BuildValue("(OO)", py_ue_new_fframe_number(range.GetLowerBoundValue()), py_ue_new_fframe_number(range.GetUpperBoundValue())); + +#endif +} + PyObject *py_ue_sequencer_section_add_key(ue_PyUObject *self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h index 64cfe39bb..83185d612 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.h @@ -13,6 +13,8 @@ PyObject *py_ue_sequencer_set_playback_range(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_set_view_range(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_set_working_range(ue_PyUObject *, PyObject *); PyObject *py_ue_sequencer_set_section_range(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_get_playback_range(ue_PyUObject *, PyObject *); +PyObject *py_ue_sequencer_get_selection_range(ue_PyUObject *, PyObject *); 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 *); From 240407bfa4b222a1d6f60e046b35f9175c43e2e3 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 13:54:34 +0100 Subject: [PATCH 24/62] fixed build for 4.15 --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 8 ++++++++ .../UnrealEnginePython/Private/UObject/UEPySequencer.cpp | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 9156d5e79..5cc289c17 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3195,12 +3195,14 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } +#if ENGINE_MINOR_VERSION > 15 else if ((PyTypeObject *)value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } +#endif else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type)) { // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) @@ -3246,6 +3248,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } +#if ENGINE_MINOR_VERSION > 15 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3254,6 +3257,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; } +#endif else if (py_obj->ue_object->IsA()) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3334,12 +3338,14 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } +#if ENGINE_MINOR_VERSION > 15 else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } +#endif else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type)) { // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) @@ -3385,6 +3391,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } +#if ENGINE_MINOR_VERSION > 15 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3393,6 +3400,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; } +#endif else if (py_obj->ue_object->IsA()) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index b1325302a..7d506be0e 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -926,7 +926,8 @@ PyObject *py_ue_sequencer_get_playback_range(ue_PyUObject *self, PyObject * args UMovieScene *scene = seq->GetMovieScene(); #if ENGINE_MINOR_VERSION < 20 - scene->GetPlaybackRange(); + TRange range = scene->GetPlaybackRange(); + return Py_BuildValue("(ff)", range.GetLowerBoundValue(), range.GetUpperBoundValue()); #else TRange range = scene->GetPlaybackRange(); @@ -1044,7 +1045,8 @@ PyObject *py_ue_sequencer_get_selection_range(ue_PyUObject *self, PyObject * arg UMovieScene *scene = seq->GetMovieScene(); #if ENGINE_MINOR_VERSION < 20 - scene->GetSelectionRange(); + TRange range = scene->GetSelectionRange(); + return Py_BuildValue("(ff)", range.GetLowerBoundValue(), range.GetUpperBoundValue()); #else TRange range = scene->GetSelectionRange(); From b0dc3e5aa6e33c716bcb4ac7807cba1a21bb4086 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 14:07:12 +0100 Subject: [PATCH 25/62] fixed 4.16 --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 5cc289c17..7a4b28046 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3195,7 +3195,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 15 +#if ENGINE_MINOR_VERSION > 16 else if ((PyTypeObject *)value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3248,7 +3248,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } -#if ENGINE_MINOR_VERSION > 15 +#if ENGINE_MINOR_VERSION > 16 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3338,7 +3338,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 15 +#if ENGINE_MINOR_VERSION > 16 else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3391,7 +3391,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } -#if ENGINE_MINOR_VERSION > 15 +#if ENGINE_MINOR_VERSION > 16 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); From c87bacf15584a7abcbfc7753ba7e489784425b93 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 14:11:52 +0100 Subject: [PATCH 26/62] fixed 4.17 --- .../UnrealEnginePython/Private/UEPyModule.cpp | 8 +++--- tools/release_win64.py | 26 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 7a4b28046..07e778f22 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3195,7 +3195,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 16 +#if ENGINE_MINOR_VERSION > 17 else if ((PyTypeObject *)value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3248,7 +3248,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } -#if ENGINE_MINOR_VERSION > 16 +#if ENGINE_MINOR_VERSION > 17 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3338,7 +3338,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 16 +#if ENGINE_MINOR_VERSION > 17 else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3391,7 +3391,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_base->SetPropertyClass(p_u_class); prop = prop_base; } -#if ENGINE_MINOR_VERSION > 16 +#if ENGINE_MINOR_VERSION > 17 else if (py_obj->ue_object->IsA()) { UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); diff --git a/tools/release_win64.py b/tools/release_win64.py index c07ffa3f7..bee239f42 100644 --- a/tools/release_win64.py +++ b/tools/release_win64.py @@ -5,8 +5,11 @@ import shutil import zipfile -UE_VERSIONS = ['4.15', '4.16', '4.17', '4.18', '4.19', '4.20'] -PYTHON_VERSIONS = ["C:/Program Files/Python36", "C:/Program Files/Python37", "C:/Python27"] +UE_VERSIONS = ['4.15', '4.16', '4.17', '4.18', '4.19', '4.20', '4.21'] +PYTHON_VERSIONS = ["C:/Program Files/Python37", "C:/Program Files/Python36", "C:/Python27"] +MSBUILD = 'C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/MSBuild/15.0/Bin/MSBuild.exe' +UE_PATH = 'C:/Program Files/Epic Games' +PROJECTS_PATH = 'C:/Users/rober/Documents/Unreal Projects' RELEASE_DIR = sys.argv[1].rstrip('/') @@ -20,28 +23,27 @@ def msbuild(project, python_version): base_environ = os.environ base_environ.update({'PYTHONHOME': python_version}) base_environ.update({'UEP_ENABLE_UNITY_BUILD': '1'}) - #vs = '"C:/Program Files (x86)/MSBuild/14.0/Bin/MSBuild.exe"' - vs = '"C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/MSBuild/15.0/Bin/MSBuild.exe"' - process = subprocess.Popen('{0} {1} /m /t:Rebuild /p:Configuration="Development Editor" /p:Platform=Win64'.format(vs, project), env=base_environ) + vs = '"{}"'.format(MSBUILD) + process = subprocess.Popen('{0} "{1}" /m /t:Rebuild /p:Configuration="Development Editor" /p:Platform=Win64'.format(vs, project), env=base_environ) while process.poll() is None: time.sleep(0.5) if process.returncode != 0: sys.exit(process.returncode) def commandlet(version, project): - ue_editor = os.path.join('D:/', 'UE_{0}'.format(version), 'Engine/Binaries/Win64/UE4Editor-Cmd.exe') - process = subprocess.Popen('{0} D:/{1}/{2}.uproject -run=PyCommandlet D:/{3}/Plugins/UnrealEnginePython/tools/release_check.py'.format(ue_editor, project, project, project)) + ue_editor = os.path.join(UE_PATH, 'UE_{0}'.format(version), 'Engine/Binaries/Win64/UE4Editor-Cmd.exe') + process = subprocess.Popen('{0} {1}/{2}/{3}.uproject -run=PyCommandlet {1}/{4}/Plugins/UnrealEnginePython/tools/release_check.py'.format(ue_editor, PROJECTS_PATH, project, project, project)) while process.poll() is None: time.sleep(0.5) # ignore return code, has too much different meanings for commandlets def git(project): - process = subprocess.Popen('git checkout master', cwd='D:/{0}/Plugins/UnrealEnginePython'.format(project)) + process = subprocess.Popen('git checkout master', cwd='{0}/{1}/Plugins/UnrealEnginePython'.format(PROJECTS_PATH, project)) while process.poll() is None: time.sleep(0.5) if process.returncode != 0: sys.exit(process.returncode) - process = subprocess.Popen('git pull', cwd='D:/{0}/Plugins/UnrealEnginePython'.format(project)) + process = subprocess.Popen('git pull', cwd='{0}/{1}/Plugins/UnrealEnginePython'.format(PROJECTS_PATH, project)) while process.poll() is None: time.sleep(0.5) if process.returncode != 0: @@ -51,7 +53,7 @@ def git(project): main_start = time.time() for ue_version in UE_VERSIONS: project = 'PyTest{0}'.format(ue_version.replace('.', '')) - sln = os.path.join('D:/', project, '{0}.sln'.format(project)) + sln = os.path.join(PROJECTS_PATH, project, '{0}.sln'.format(project)) git(project) for python_version in PYTHON_VERSIONS: python_sanitized = os.path.basename(python_version).lower() @@ -62,9 +64,9 @@ def git(project): commandlet(ue_version, project) end = time.time() for item in ('UE4Editor.modules', 'UE4Editor-UnrealEnginePython.dll', 'UE4Editor-PythonConsole.dll', 'UE4Editor-PythonEditor.dll', 'UE4Editor-PythonAutomation.dll'): - shutil.copyfile('D:/{0}/Plugins/UnrealEnginePython/Binaries/Win64/{1}'.format(project, item), '{0}/UnrealEnginePython/Binaries/Win64/{1}'.format(RELEASE_DIR, item)) + shutil.copyfile('{0}/{1}/Plugins/UnrealEnginePython/Binaries/Win64/{2}'.format(PROJECTS_PATH, project, item), '{0}/UnrealEnginePython/Binaries/Win64/{1}'.format(RELEASE_DIR, item)) if python_sanitized == 'python36': - shutil.copyfile('D:/{0}/Plugins/UnrealEnginePython/Binaries/Win64/{1}'.format(project, item), '{0}/Embedded/UnrealEnginePython/Binaries/Win64/{1}'.format(RELEASE_DIR, item)) + shutil.copyfile('{0}/{1}/Plugins/UnrealEnginePython/Binaries/Win64/{2}'.format(PROJECTS_PATH, project, item), '{0}/Embedded/UnrealEnginePython/Binaries/Win64/{1}'.format(RELEASE_DIR, item)) filename = 'UnrealEnginePython_{0}_{1}_{2}_win64.zip'.format(os.path.basename(RELEASE_DIR), ue_version.replace('.','_'), python_sanitized) zh = zipfile.ZipFile(os.path.join(RELEASE_DIR, filename), 'w', zipfile.ZIP_DEFLATED) zipdir(os.path.join(RELEASE_DIR, 'UnrealEnginePython'), zh, RELEASE_DIR) From 56a6f3044179e67978794eb4a037d092ae8b79f9 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 Nov 2018 14:16:16 +0100 Subject: [PATCH 27/62] fixed 4.18 --- Source/UnrealEnginePython/Private/UEPyModule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 07e778f22..e89ccc9f6 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -3195,7 +3195,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 17 +#if ENGINE_MINOR_VERSION > 18 else if ((PyTypeObject *)value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3338,7 +3338,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } -#if ENGINE_MINOR_VERSION > 17 +#if ENGINE_MINOR_VERSION > 18 else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); From de7f156a29c3620e6b6702fa4bde90054ce03916 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 4 Dec 2018 16:18:52 -0700 Subject: [PATCH 28/62] added FVector2D wrapper --- .../UnrealEnginePython/Private/UEPyModule.cpp | 33 +- .../Private/Wrappers/UEPyFVector2D.cpp | 350 ++++++++++++++++++ .../Private/Wrappers/UEPyFVector2D.h | 21 ++ 3 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp create mode 100644 Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.h diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index e89ccc9f6..4b299e0fd 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -51,6 +51,7 @@ #include "Wrappers/UEPyESlateEnums.h" #include "Wrappers/UEPyFVector.h" +#include "Wrappers/UEPyFVector2D.h" #include "Wrappers/UEPyFHitResult.h" #include "Wrappers/UEPyFRotator.h" #include "Wrappers/UEPyFTransform.h" @@ -1656,6 +1657,7 @@ void unreal_engine_init_py_module() } ue_python_init_fvector(new_unreal_engine_module); + ue_python_init_fvector2d(new_unreal_engine_module); ue_python_init_frotator(new_unreal_engine_module); ue_python_init_ftransform(new_unreal_engine_module); ue_python_init_fhitresult(new_unreal_engine_module); @@ -2105,12 +2107,16 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) { if (auto casted_struct = Cast(casted_prop->Struct)) { - // check for FVector if (casted_struct == TBaseStructure::Get()) { FVector vec = *casted_prop->ContainerPtrToValuePtr(buffer, index); return py_ue_new_fvector(vec); } + if (casted_struct == TBaseStructure::Get()) + { + FVector2D vec = *casted_prop->ContainerPtrToValuePtr(buffer, index); + return py_ue_new_fvector2d(vec); + } if (casted_struct == TBaseStructure::Get()) { FRotator rot = *casted_prop->ContainerPtrToValuePtr(buffer, index); @@ -2516,6 +2522,19 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } + if (ue_PyFVector2D *py_vec = py_ue_is_fvector2d(py_obj)) + { + if (auto casted_prop = Cast(prop)) + { + if (casted_prop->Struct == TBaseStructure::Get()) + { + *casted_prop->ContainerPtrToValuePtr(buffer, index) = py_vec->vec; + return true; + } + } + return false; + } + if (ue_PyFRotator *py_rot = py_ue_is_frotator(py_obj)) { if (auto casted_prop = Cast(prop)) @@ -3171,6 +3190,12 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } + else if ((PyTypeObject *)value == &ue_PyFVector2DType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } else if ((PyTypeObject *)value == &ue_PyFRotatorType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); @@ -3314,6 +3339,12 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } + else if ((PyTypeObject *)py_return_value == &ue_PyFVector2DType) + { + UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + prop_struct->Struct = TBaseStructure::Get(); + prop = prop_struct; + } else if ((PyTypeObject *)py_return_value == &ue_PyFRotatorType) { UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp new file mode 100644 index 000000000..c206e9964 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp @@ -0,0 +1,350 @@ +#include "UEPyFVector2D.h" + +static PyObject *py_ue_fvector2d_length(ue_PyFVector2D *self, PyObject * args) +{ + return PyFloat_FromDouble(self->vec.Size()); +} + +static PyObject *py_ue_fvector2d_length_squared(ue_PyFVector2D *self, PyObject * args) +{ + return PyFloat_FromDouble(self->vec.SizeSquared()); +} + +static PyObject *py_ue_fvector2d_normalized(ue_PyFVector2D *self, PyObject * args) +{ + FVector2D vec = self->vec; + vec.Normalize(); + return py_ue_new_fvector2d(vec); +} + +static PyObject *py_ue_fvector2d_dot(ue_PyFVector2D *self, PyObject * args) +{ + PyObject *py_obj; + if (!PyArg_ParseTuple(args, "O:dot", &py_obj)) + return NULL; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(py_obj); + if (!py_vec) + return PyErr_Format(PyExc_TypeError, "argument is not a FVector2D"); + return PyFloat_FromDouble(FVector2D::DotProduct(self->vec, py_vec->vec)); +} + +static PyObject *py_ue_fvector2d_cross(ue_PyFVector2D *self, PyObject * args) +{ + PyObject *py_obj; + if (!PyArg_ParseTuple(args, "O:cross", &py_obj)) + return NULL; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(py_obj); + if (!py_vec) + return PyErr_Format(PyExc_TypeError, "argument is not a FVector2D"); + return PyFloat_FromDouble(FVector2D::CrossProduct(self->vec, py_vec->vec)); +} + +static PyMethodDef ue_PyFVector2D_methods[] = { + + { "length", (PyCFunction)py_ue_fvector2d_length, METH_VARARGS, "" }, + { "size", (PyCFunction)py_ue_fvector2d_length, METH_VARARGS, "" }, + { "size_squared", (PyCFunction)py_ue_fvector2d_length_squared, METH_VARARGS, "" }, + { "length_squared", (PyCFunction)py_ue_fvector2d_length_squared, METH_VARARGS, "" }, + { "normalized", (PyCFunction)py_ue_fvector2d_normalized, METH_VARARGS, "" }, + { "dot", (PyCFunction)py_ue_fvector2d_dot, METH_VARARGS, "" }, + { "cross", (PyCFunction)py_ue_fvector2d_cross, METH_VARARGS, "" }, + { NULL } /* Sentinel */ +}; + +static PyObject *py_ue_fvector2d_get_x(ue_PyFVector2D *self, void *closure) +{ + return PyFloat_FromDouble(self->vec.X); +} + +static int py_ue_fvector2d_set_x(ue_PyFVector2D *self, PyObject *value, void *closure) +{ + if (value && PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + self->vec.X = PyFloat_AsDouble(f_value); + Py_DECREF(f_value); + return 0; + } + PyErr_SetString(PyExc_TypeError, "value is not numeric"); + return -1; +} + +static PyObject *py_ue_fvector2d_get_y(ue_PyFVector2D *self, void *closure) +{ + return PyFloat_FromDouble(self->vec.Y); +} + +static int py_ue_fvector2d_set_y(ue_PyFVector2D *self, PyObject *value, void *closure) +{ + if (value && PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + self->vec.Y = PyFloat_AsDouble(f_value); + Py_DECREF(f_value); + return 0; + } + PyErr_SetString(PyExc_TypeError, "value is not numeric"); + return -1; +} + + +static PyGetSetDef ue_PyFVector2D_getseters[] = { + {(char *) "x", (getter)py_ue_fvector2d_get_x, (setter)py_ue_fvector2d_set_x, (char *)"", NULL }, + {(char *) "y", (getter)py_ue_fvector2d_get_y, (setter)py_ue_fvector2d_set_y, (char *)"", NULL }, + { NULL } /* Sentinel */ +}; + +static PyObject *ue_PyFVector2D_str(ue_PyFVector2D *self) +{ + return PyUnicode_FromFormat("", + PyFloat_FromDouble(self->vec.X), PyFloat_FromDouble(self->vec.Y)); +} + +PyTypeObject ue_PyFVector2DType = { + PyVarObject_HEAD_INIT(NULL, 0) + "unreal_engine.FVector2D", /* tp_name */ + sizeof(ue_PyFVector2D), /* 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 */ + (reprfunc)ue_PyFVector2D_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ +#if PY_MAJOR_VERSION < 3 + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT, /* tp_flags */ +#endif + "Unreal Engine FVector2D", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ue_PyFVector2D_methods, /* tp_methods */ + 0, + ue_PyFVector2D_getseters, +}; + + +static PyObject *ue_py_fvector2d_add(ue_PyFVector2D *self, PyObject *value) +{ + FVector2D vec = self->vec; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(value); + if (py_vec) + { + vec += py_vec->vec; + } + else if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + vec.X += f; + vec.Y += f; + Py_DECREF(f_value); + } + return py_ue_new_fvector2d(vec); +} + +static PyObject *ue_py_fvector2d_sub(ue_PyFVector2D *self, PyObject *value) +{ + FVector2D vec = self->vec; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(value); + if (py_vec) + { + vec -= py_vec->vec; + } + else if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + vec.X -= f; + vec.Y -= f; + Py_DECREF(f_value); + } + return py_ue_new_fvector2d(vec); +} + +static PyObject *ue_py_fvector2d_mul(ue_PyFVector2D *self, PyObject *value) +{ + FVector2D vec = self->vec; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(value); + if (py_vec) + { + vec *= py_vec->vec; + } + else if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + vec *= f; + Py_DECREF(f_value); + } + return py_ue_new_fvector2d(vec); +} + +static PyObject *ue_py_fvector2d_div(ue_PyFVector2D *self, PyObject *value) +{ + FVector2D vec = self->vec; + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(value); + if (py_vec) + { + if (py_vec->vec.X == 0 || py_vec->vec.Y == 0) + return PyErr_Format(PyExc_ZeroDivisionError, "division by zero"); + vec /= py_vec->vec; + } + else if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + if (f == 0) + return PyErr_Format(PyExc_ZeroDivisionError, "division by zero"); + vec /= f; + Py_DECREF(f_value); + } + return py_ue_new_fvector2d(vec); +} + +PyNumberMethods ue_PyFVector2D_number_methods; + +static Py_ssize_t ue_py_fvector2d_seq_length(ue_PyFVector2D *self) +{ + return 2; +} + +static PyObject *ue_py_fvector2d_seq_item(ue_PyFVector2D *self, Py_ssize_t i) +{ + switch (i) + { + case 0: + return PyFloat_FromDouble(self->vec.X); + case 1: + return PyFloat_FromDouble(self->vec.Y); + } + return PyErr_Format(PyExc_IndexError, "FVector2D has only 2 items"); +} + +PySequenceMethods ue_PyFVector2D_sequence_methods; + +static int ue_py_fvector2d_init(ue_PyFVector2D *self, PyObject *args, PyObject *kwargs) +{ + float x = 0, y = 0; + if (!PyArg_ParseTuple(args, "|ff", &x, &y)) + return -1; + + if (PyTuple_Size(args) == 1) + { + y = x; + } + + self->vec.X = x; + self->vec.Y = y; + + return 0; +} + +static PyObject *ue_py_fvector2d_richcompare(ue_PyFVector2D *vec1, PyObject *b, int op) +{ + ue_PyFVector2D *vec2 = py_ue_is_fvector2d(b); + if (!vec2 || (op != Py_EQ && op != Py_NE)) + { + return PyErr_Format(PyExc_NotImplementedError, "can only compare with another FVector2D"); + } + + if (op == Py_EQ) + { + if (vec1->vec.X == vec2->vec.X && + vec1->vec.Y == vec2->vec.Y) + { + Py_INCREF(Py_True); + return Py_True; + } + Py_INCREF(Py_False); + return Py_False; + } + + if (vec1->vec.X == vec2->vec.X && + vec1->vec.Y == vec2->vec.Y) + { + Py_INCREF(Py_False); + return Py_False; + } + Py_INCREF(Py_True); + return Py_True; +} + +void ue_python_init_fvector2d(PyObject *ue_module) +{ + ue_PyFVector2DType.tp_new = PyType_GenericNew; + + ue_PyFVector2DType.tp_init = (initproc)ue_py_fvector2d_init; + ue_PyFVector2DType.tp_richcompare = (richcmpfunc)ue_py_fvector2d_richcompare; + + memset(&ue_PyFVector2D_number_methods, 0, sizeof(PyNumberMethods)); + ue_PyFVector2DType.tp_as_number = &ue_PyFVector2D_number_methods; + ue_PyFVector2D_number_methods.nb_add = (binaryfunc)ue_py_fvector2d_add; + ue_PyFVector2D_number_methods.nb_subtract = (binaryfunc)ue_py_fvector2d_sub; + ue_PyFVector2D_number_methods.nb_multiply = (binaryfunc)ue_py_fvector2d_mul; + ue_PyFVector2D_number_methods.nb_true_divide = (binaryfunc)ue_py_fvector2d_div; + + memset(&ue_PyFVector2D_sequence_methods, 0, sizeof(PySequenceMethods)); + ue_PyFVector2DType.tp_as_sequence = &ue_PyFVector2D_sequence_methods; + ue_PyFVector2D_sequence_methods.sq_length = (lenfunc)ue_py_fvector2d_seq_length; + ue_PyFVector2D_sequence_methods.sq_item = (ssizeargfunc)ue_py_fvector2d_seq_item; + + if (PyType_Ready(&ue_PyFVector2DType) < 0) + return; + + Py_INCREF(&ue_PyFVector2DType); + PyModule_AddObject(ue_module, "FVector2D", (PyObject *)&ue_PyFVector2DType); +} + +PyObject *py_ue_new_fvector2d(FVector2D vec) +{ + ue_PyFVector2D *ret = (ue_PyFVector2D *)PyObject_New(ue_PyFVector2D, &ue_PyFVector2DType); + ret->vec = vec; + return (PyObject *)ret; +} + +ue_PyFVector2D *py_ue_is_fvector2d(PyObject *obj) +{ + if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFVector2DType)) + return nullptr; + return (ue_PyFVector2D *)obj; +} + +bool py_ue_vector2d_arg(PyObject *args, FVector2D &vec) +{ + + if (PyTuple_Size(args) == 1) + { + PyObject *arg = PyTuple_GetItem(args, 0); + ue_PyFVector2D *py_vec = py_ue_is_fvector2d(arg); + if (!py_vec) + { + PyErr_Format(PyExc_TypeError, "argument is not a FVector2D"); + return false; + } + vec = py_vec->vec; + return true; + } + + float x, y; + if (!PyArg_ParseTuple(args, "ff", &x, &y)) + return false; + vec.X = x; + vec.Y = y; + return true; +} + diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.h b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.h new file mode 100644 index 000000000..b9c2f4d73 --- /dev/null +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.h @@ -0,0 +1,21 @@ +#pragma once + + + +#include "UEPyModule.h" + +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + FVector2D vec; +} ue_PyFVector2D; + +extern PyTypeObject ue_PyFVector2DType; + +PyObject *py_ue_new_fvector2d(FVector2D); +ue_PyFVector2D *py_ue_is_fvector2d(PyObject *); + +void ue_python_init_fvector2d(PyObject *); + +bool py_ue_vector2d_arg(PyObject *, FVector2D &); From 875191d152f50e97696c070b1828f7adc9dda2c6 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 4 Dec 2018 16:44:21 -0700 Subject: [PATCH 29/62] Fixed division bug in FVector --- Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index 430e1caa2..d2f48a418 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -363,7 +363,7 @@ void ue_python_init_fvector(PyObject *ue_module) ue_PyFVector_number_methods.nb_add = (binaryfunc)ue_py_fvector_add; ue_PyFVector_number_methods.nb_subtract = (binaryfunc)ue_py_fvector_sub; ue_PyFVector_number_methods.nb_multiply = (binaryfunc)ue_py_fvector_mul; - ue_PyFVector_number_methods.nb_divmod = (binaryfunc)ue_py_fvector_div; + ue_PyFVector_number_methods.nb_true_divide = (binaryfunc)ue_py_fvector_div; memset(&ue_PyFVector_sequence_methods, 0, sizeof(PySequenceMethods)); ue_PyFVectorType.tp_as_sequence = &ue_PyFVector_sequence_methods; From 85d96608467a4724bef5d66b7a8ff41a09c4f284 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 4 Dec 2018 17:05:27 -0700 Subject: [PATCH 30/62] added get_static_mesh_bounds method --- .../UnrealEnginePython/Private/UEPyModule.cpp | 1 + .../Private/UObject/UEPyStaticMesh.cpp | 19 +++++++++++++++++-- .../Private/UObject/UEPyStaticMesh.h | 4 +++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index e89ccc9f6..542b5a42f 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -751,6 +751,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "vlog_cylinder", (PyCFunction)py_ue_vlog_cylinder, METH_VARARGS, "" }, // StaticMesh + { "get_static_mesh_bounds", (PyCFunction)py_ue_static_mesh_get_bounds, METH_VARARGS, "" }, #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, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp index 1111ac4ee..eaf1a1cf8 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.cpp @@ -1,9 +1,24 @@ #include "UEPyStaticMesh.h" +#include "Engine/StaticMesh.h" +PyObject *py_ue_static_mesh_get_bounds(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"); + + FBoxSphereBounds bounds = mesh->GetBounds(); + UScriptStruct *u_struct = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR("BoxSphereBounds")); + if (!u_struct) + { + return PyErr_Format(PyExc_Exception, "unable to get BoxSphereBounds struct"); + } + return py_ue_new_owned_uscriptstruct(u_struct, (uint8 *)&bounds); +} #if WITH_EDITOR -#include "Engine/StaticMesh.h" #include "Wrappers/UEPyFRawMesh.h" #include "Editor/UnrealEd/Private/GeomFitUtils.h" #include "FbxMeshUtils.h" @@ -137,4 +152,4 @@ PyObject *py_ue_static_mesh_import_lod(ue_PyUObject *self, PyObject * args) Py_RETURN_FALSE; } -#endif \ No newline at end of file +#endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h index 9874520cf..46a8c76be 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyStaticMesh.h @@ -4,6 +4,8 @@ #include "UEPyModule.h" +PyObject *py_ue_static_mesh_get_bounds(ue_PyUObject *self, PyObject * args); + #if WITH_EDITOR PyObject *py_ue_static_mesh_build(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_create_body_setup(ue_PyUObject *, PyObject *); @@ -15,4 +17,4 @@ PyObject *py_ue_static_mesh_generate_kdop10z(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_generate_kdop18(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_generate_kdop26(ue_PyUObject *, PyObject *); PyObject *py_ue_static_mesh_import_lod(ue_PyUObject *, PyObject *); -#endif \ No newline at end of file +#endif From 2492243cdcfc3f3e59486032e2e5dff4d2d6d4f8 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 6 Dec 2018 16:07:35 -0700 Subject: [PATCH 31/62] added support for FVector floor division --- .../Private/Wrappers/UEPyFVector.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp index d2f48a418..113c3bb62 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector.cpp @@ -277,6 +277,24 @@ static PyObject *ue_py_fvector_div(ue_PyFVector *self, PyObject *value) return py_ue_new_fvector(vec); } +static PyObject *ue_py_fvector_floor_div(ue_PyFVector *self, PyObject *value) +{ + FVector vec = self->vec; + if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + if (f == 0) + return PyErr_Format(PyExc_ZeroDivisionError, "division by zero"); + vec.X = floor(vec.X / f); + vec.Y = floor(vec.Y / f); + vec.Z = floor(vec.Z / f); + Py_DECREF(f_value); + return py_ue_new_fvector(vec); + } + return PyErr_Format(PyExc_TypeError, "value is not numeric"); +} + PyNumberMethods ue_PyFVector_number_methods; static Py_ssize_t ue_py_fvector_seq_length(ue_PyFVector *self) @@ -364,6 +382,7 @@ void ue_python_init_fvector(PyObject *ue_module) ue_PyFVector_number_methods.nb_subtract = (binaryfunc)ue_py_fvector_sub; ue_PyFVector_number_methods.nb_multiply = (binaryfunc)ue_py_fvector_mul; ue_PyFVector_number_methods.nb_true_divide = (binaryfunc)ue_py_fvector_div; + ue_PyFVector_number_methods.nb_floor_divide = (binaryfunc)ue_py_fvector_floor_div; memset(&ue_PyFVector_sequence_methods, 0, sizeof(PySequenceMethods)); ue_PyFVectorType.tp_as_sequence = &ue_PyFVector_sequence_methods; From b6d281e6ee5e4797db2ec8e2da7da67accf1863b Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 6 Dec 2018 16:21:34 -0700 Subject: [PATCH 32/62] added floor division support to FVector2D --- .../Private/Wrappers/UEPyFVector2D.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp index c206e9964..20855cf56 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFVector2D.cpp @@ -216,6 +216,23 @@ static PyObject *ue_py_fvector2d_div(ue_PyFVector2D *self, PyObject *value) return py_ue_new_fvector2d(vec); } +static PyObject *ue_py_fvector2d_floor_div(ue_PyFVector2D *self, PyObject *value) +{ + FVector2D vec = self->vec; + if (PyNumber_Check(value)) + { + PyObject *f_value = PyNumber_Float(value); + float f = PyFloat_AsDouble(f_value); + if (f == 0) + return PyErr_Format(PyExc_ZeroDivisionError, "division by zero"); + vec.X = floor(vec.X / f); + vec.Y = floor(vec.Y / f); + Py_DECREF(f_value); + return py_ue_new_fvector2d(vec); + } + return PyErr_Format(PyExc_TypeError, "value is not numeric"); +} + PyNumberMethods ue_PyFVector2D_number_methods; static Py_ssize_t ue_py_fvector2d_seq_length(ue_PyFVector2D *self) @@ -297,6 +314,7 @@ void ue_python_init_fvector2d(PyObject *ue_module) ue_PyFVector2D_number_methods.nb_subtract = (binaryfunc)ue_py_fvector2d_sub; ue_PyFVector2D_number_methods.nb_multiply = (binaryfunc)ue_py_fvector2d_mul; ue_PyFVector2D_number_methods.nb_true_divide = (binaryfunc)ue_py_fvector2d_div; + ue_PyFVector2D_number_methods.nb_floor_divide = (binaryfunc)ue_py_fvector2d_floor_div; memset(&ue_PyFVector2D_sequence_methods, 0, sizeof(PySequenceMethods)); ue_PyFVector2DType.tp_as_sequence = &ue_PyFVector2D_sequence_methods; From ae7fd91cc3dc86d25b43ea6d42bb289364ecdf58 Mon Sep 17 00:00:00 2001 From: Tom Rota Date: Sun, 9 Dec 2018 12:16:25 -0500 Subject: [PATCH 33/62] Added TCHAR_TO_WCHAR to fix issue 602 --- Source/UnrealEnginePython/Private/PyCommandlet.cpp | 2 +- Source/UnrealEnginePython/Private/UnrealEnginePython.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/PyCommandlet.cpp b/Source/UnrealEnginePython/Private/PyCommandlet.cpp index 9b22ae818..3a1643ae9 100644 --- a/Source/UnrealEnginePython/Private/PyCommandlet.cpp +++ b/Source/UnrealEnginePython/Private/PyCommandlet.cpp @@ -91,7 +91,7 @@ int32 UPyCommandlet::Main(const FString& CommandLine) #if PY_MAJOR_VERSION >= 3 argv[i] = (wchar_t*)malloc(PyArgv[i].Len() + 1); #if PLATFORM_MAC || PLATFORM_LINUX - wcsncpy(argv[i], *PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1); + wcsncpy(argv[i], (const wchar_t *) TCHAR_TO_WCHAR(*PyArgv[i].ReplaceEscapedCharWithChar()), PyArgv[i].Len() + 1); #elif PLATFORM_ANDROID wcsncpy(argv[i], (const wchar_t *)*PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1); #else diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index cabe29259..8527d0a82 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -116,7 +116,7 @@ void FUnrealEnginePythonModule::UESetupPythonInterpreter(bool verbose) for (int32 i = 0; i < Args.Num(); i++) { #if PY_MAJOR_VERSION >= 3 - argv[i] = (wchar_t *)(*Args[i]); + argv[i] = (wchar_t *)(TCHAR_TO_WCHAR(*Args[i])); #else argv[i] = TCHAR_TO_UTF8(*Args[i]); #endif From 14deb53bafd17c8d8ed202994caa297cf938eee6 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 12 Dec 2018 18:35:35 +0100 Subject: [PATCH 34/62] Restore Windows stdio flags after Python initialisation. Python forcibly sets the file mode for stdin, stdout, and stderr to O_BINARY for several reasons. This causes wprintf() to output UTF-16 instead of going through the proper text conversion. As a result, standard output was all messed up after the module was initialised. The Python developers do not really consider this a bug because they are not familiar with wprintf() (https://bugs.python.org/issue16587). Unfortunately this is what UE4 uses for logging. --- .../Private/UnrealEnginePython.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index bb79b8c8f..8d8e2c1b2 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -34,9 +34,14 @@ const char *ue4_module_options = "linux_global_symbols"; #include "Runtime/Core/Public/Misc/CommandLine.h" #include "Runtime/Core/Public/Misc/ConfigCacheIni.h" #include "Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h" +#include "Runtime/Core/Public/GenericPlatform/GenericPlatformMisc.h" #include "Runtime/Core/Public/HAL/FileManagerGeneric.h" +#if PLATFORM_WINDOWS +#include +#endif + #if PLATFORM_ANDROID #include "Android/AndroidJNI.h" #include "Android/AndroidApplication.h" @@ -447,6 +452,22 @@ void FUnrealEnginePythonModule::StartupModule() Py_Initialize(); +#if PLATFORM_WINDOWS + // Restore stdio state after Py_Initialize set it to O_BINARY, otherwise + // everything that the engine will output is going to be encoded in UTF-16. + // The behaviour is described here: https://bugs.python.org/issue16587 + _setmode(fileno(stdin), O_TEXT); + _setmode(fileno(stdout), O_TEXT); + _setmode(fileno(stderr), O_TEXT); + + // Also restore the user-requested UTF-8 flag if relevant (behaviour copied + // from LaunchEngineLoop.cpp). + if (FParse::Param(FCommandLine::Get(), TEXT("UTF8Output"))) + { + FPlatformMisc::SetUTF8Output(); + } +#endif + PyEval_InitThreads(); #if WITH_EDITOR From ab0ac86352f9f2b2bea749442919affb278ef560 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 12 Dec 2018 19:29:01 +0100 Subject: [PATCH 35/62] =?UTF-8?q?Use=20C++=20conformant=20=E2=80=9C=5Ffile?= =?UTF-8?q?no=E2=80=9D=20instead=20of=20=E2=80=9Cfileno=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/UnrealEnginePython/Private/UnrealEnginePython.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index 5665e4746..e4334b320 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -460,9 +460,9 @@ void FUnrealEnginePythonModule::StartupModule() // Restore stdio state after Py_Initialize set it to O_BINARY, otherwise // everything that the engine will output is going to be encoded in UTF-16. // The behaviour is described here: https://bugs.python.org/issue16587 - _setmode(fileno(stdin), O_TEXT); - _setmode(fileno(stdout), O_TEXT); - _setmode(fileno(stderr), O_TEXT); + _setmode(_fileno(stdin), O_TEXT); + _setmode(_fileno(stdout), O_TEXT); + _setmode(_fileno(stderr), O_TEXT); // Also restore the user-requested UTF-8 flag if relevant (behaviour copied // from LaunchEngineLoop.cpp). From 9e4f393d987e4a8d48dabe5759e9098f500314ac Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 13 Dec 2018 10:45:27 +0100 Subject: [PATCH 36/62] Add backwards compatibility macro for TCHAR_TO_WCHAR. This macro was only introduced in UE4.20. We copy it if wchar_t and TCHAR differ in size. --- Source/UnrealEnginePython/Private/UEPyModule.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyModule.h b/Source/UnrealEnginePython/Private/UEPyModule.h index b193e0a10..08e599d52 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.h +++ b/Source/UnrealEnginePython/Private/UEPyModule.h @@ -14,6 +14,15 @@ #include "Wrappers/UEPyFColor.h" #include "Wrappers/UEPyFLinearColor.h" +// backward compatibility for UE4.20 TCHAR_TO_WCHAR +#ifndef TCHAR_TO_WCHAR + // SIZEOF_WCHAR_T is provided by pyconfig.h + #if SIZEOF_WCHAR_T == (PLATFORM_TCHAR_IS_4_BYTES ? 4 : 2) + #define TCHAR_TO_WCHAR(str) str + #else + #define TCHAR_TO_WCHAR(str) (wchar_t*)StringCast(static_cast(str)).Get() + #endif +#endif UWorld *ue_get_uworld(ue_PyUObject *); From 38599ea244580caf18b1ab0dc6774fb2f283a6a0 Mon Sep 17 00:00:00 2001 From: Tom Rota Date: Thu, 13 Dec 2018 11:27:48 -0500 Subject: [PATCH 37/62] Adds version checking before calling TCHAR_TO_WCHAR --- Source/UnrealEnginePython/Private/PyCommandlet.cpp | 4 ++++ Source/UnrealEnginePython/Private/UnrealEnginePython.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Source/UnrealEnginePython/Private/PyCommandlet.cpp b/Source/UnrealEnginePython/Private/PyCommandlet.cpp index 3a1643ae9..701f05348 100644 --- a/Source/UnrealEnginePython/Private/PyCommandlet.cpp +++ b/Source/UnrealEnginePython/Private/PyCommandlet.cpp @@ -91,7 +91,11 @@ int32 UPyCommandlet::Main(const FString& CommandLine) #if PY_MAJOR_VERSION >= 3 argv[i] = (wchar_t*)malloc(PyArgv[i].Len() + 1); #if PLATFORM_MAC || PLATFORM_LINUX + #if ENGINE_MINOR_VERSION >= 20 wcsncpy(argv[i], (const wchar_t *) TCHAR_TO_WCHAR(*PyArgv[i].ReplaceEscapedCharWithChar()), PyArgv[i].Len() + 1); + #else + wcsncpy(argv[i], *PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1); + #endif #elif PLATFORM_ANDROID wcsncpy(argv[i], (const wchar_t *)*PyArgv[i].ReplaceEscapedCharWithChar(), PyArgv[i].Len() + 1); #else diff --git a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp index e4334b320..211124849 100644 --- a/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp +++ b/Source/UnrealEnginePython/Private/UnrealEnginePython.cpp @@ -121,7 +121,11 @@ void FUnrealEnginePythonModule::UESetupPythonInterpreter(bool verbose) for (int32 i = 0; i < Args.Num(); i++) { #if PY_MAJOR_VERSION >= 3 + #if ENGINE_MINOR_VERSION >= 20 argv[i] = (wchar_t *)(TCHAR_TO_WCHAR(*Args[i])); + #else + argv[i] = (wchar_t *)(*Args[i]); + #endif #else argv[i] = TCHAR_TO_UTF8(*Args[i]); #endif From bfe470b4026d28062d2391a039d0a4e8f5e1fa74 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 14 Dec 2018 14:20:17 -0700 Subject: [PATCH 38/62] look for python in alternate custom location --- Source/UnrealEnginePython/UnrealEnginePython.Build.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 6e7727d0b..96b48121d 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -292,6 +292,11 @@ private string DiscoverPythonPath(string[] knownPaths, string binaryPath) if (!string.IsNullOrEmpty(environmentPath)) paths.Insert(0, environmentPath); + // look in an alternate custom location + environmentPath = System.Environment.GetEnvironmentVariable("UNREALENGINEPYTHONHOME"); + if (!string.IsNullOrEmpty(environmentPath)) + paths.Insert(0, environmentPath); + foreach (string path in paths) { string actualPath = path; From fda6204af11d6846bf316a3204c6b142b4da46d0 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Fri, 28 Dec 2018 12:59:18 +0100 Subject: [PATCH 39/62] fixed typo --- .../UnrealEnginePython/Private/Wrappers/UEPyFFrameNumber.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFrameNumber.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFrameNumber.cpp index bb939c680..b2dc0a0df 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFrameNumber.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFrameNumber.cpp @@ -10,7 +10,7 @@ static PyObject *ue_PyFFrameNumber_str(ue_PyFFrameNumber *self) static PyTypeObject ue_PyFFrameNumberType = { PyVarObject_HEAD_INIT(NULL, 0) - "unreal_engine.FMFrameNumber", /* tp_name */ + "unreal_engine.FFrameNumber", /* tp_name */ sizeof(ue_PyFFrameNumber), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ @@ -80,4 +80,4 @@ PyObject *py_ue_new_fframe_number(FFrameNumber frame_number) return (PyObject *)ret; } -#endif \ No newline at end of file +#endif From b9fb9291d68612a02789cc552da50c93e011747b Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Sun, 13 Jan 2019 10:24:05 +0100 Subject: [PATCH 40/62] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1885cd358..46264da12 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Once the plugin is installed and enabled, you get access to the 'PythonConsole' All of the exposed engine features are under the 'unreal_engine' virtual module (it is completely coded in c into the plugin, so do not expect to run 'import unreal_engine' from a standard python shell) -The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19 and 4.20 +The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20 and 4.21 We support official python.org releases as well as IntelPython and Anaconda distributions. From dc6e93cd2a87a0d77e03c3a9d423f2a32c2f776d Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 18 Feb 2019 21:55:08 -0700 Subject: [PATCH 41/62] added support for uobj.unbind_event --- .../Private/PythonDelegate.cpp | 9 ++++- .../UnrealEnginePython/Private/UEPyModule.cpp | 40 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyModule.h | 1 + .../Private/UObject/UEPyObject.cpp | 19 +++++++++ .../Private/UObject/UEPyObject.h | 3 +- .../Public/PythonDelegate.h | 1 + .../Public/PythonHouseKeeper.h | 11 +++++ 7 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Source/UnrealEnginePython/Private/PythonDelegate.cpp b/Source/UnrealEnginePython/Private/PythonDelegate.cpp index 0ed596d4b..e7e4c6699 100644 --- a/Source/UnrealEnginePython/Private/PythonDelegate.cpp +++ b/Source/UnrealEnginePython/Private/PythonDelegate.cpp @@ -1,6 +1,7 @@ #include "PythonDelegate.h" #include "UEPyModule.h" +#include "UEPyCallable.h" UPythonDelegate::UPythonDelegate() { @@ -101,6 +102,12 @@ void UPythonDelegate::PyInputAxisHandler(float value) Py_DECREF(ret); } +bool UPythonDelegate::UsesPyCallable(PyObject *other) +{ + ue_PyCallable *other_callable = (ue_PyCallable*)other; + ue_PyCallable *this_callable = (ue_PyCallable*)py_callable; + return other_callable->u_function == this_callable->u_function && other_callable->u_target == this_callable->u_target; +} UPythonDelegate::~UPythonDelegate() { @@ -110,4 +117,4 @@ UPythonDelegate::~UPythonDelegate() #if defined(UEPY_MEMORY_DEBUG) UE_LOG(LogPython, Warning, TEXT("PythonDelegate %p callable XDECREF'ed"), this); #endif -} \ No newline at end of file +} diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 704593c8d..993828a86 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -607,6 +607,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "set_name", (PyCFunction)py_ue_set_name, METH_VARARGS, "" }, { "bind_event", (PyCFunction)py_ue_bind_event, METH_VARARGS, "" }, + { "unbind_event", (PyCFunction)py_ue_unbind_event, METH_VARARGS, "" }, { "delegate_bind_ufunction", (PyCFunction)py_ue_delegate_bind_ufunction, METH_VARARGS, "" }, { "get_py_proxy", (PyCFunction)py_ue_get_py_proxy, METH_VARARGS, "" }, @@ -3044,6 +3045,45 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * Py_RETURN_NONE; } +PyObject *ue_unbind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) +{ + UProperty *u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name)); + if (!u_property) + { + if (fail_on_wrong_property) + return PyErr_Format(PyExc_Exception, "unable to find event property %s", TCHAR_TO_UTF8(*event_name)); + Py_RETURN_NONE; + } + + if (auto casted_prop = Cast(u_property)) + { + UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->FindDelegate(u_obj->ue_object, py_callable); + if (py_delegate != nullptr) + { + FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object); + multiscript_delegate.Remove(py_delegate, FName("PyFakeCallable")); + + // re-assign multicast delegate + casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); + } + } + else if (auto casted_prop_delegate = Cast(u_property)) + { + FScriptDelegate script_delegate = casted_prop_delegate->GetPropertyValue_InContainer(u_obj->ue_object); + script_delegate.Unbind(); + + // re-assign multicast delegate + casted_prop_delegate->SetPropertyValue_InContainer(u_obj->ue_object, script_delegate); + } + else + { + if (fail_on_wrong_property) + return PyErr_Format(PyExc_Exception, "property %s is not an event", TCHAR_TO_UTF8(*event_name)); + } + + Py_RETURN_NONE; +} + PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) { diff --git a/Source/UnrealEnginePython/Private/UEPyModule.h b/Source/UnrealEnginePython/Private/UEPyModule.h index 08e599d52..9d865cb16 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.h +++ b/Source/UnrealEnginePython/Private/UEPyModule.h @@ -35,6 +35,7 @@ void ue_bind_events_for_py_class_by_attribute(UObject *, PyObject *); void ue_autobind_events_for_pyclass(ue_PyUObject *, PyObject *); PyObject *ue_bind_pyevent(ue_PyUObject *, FString, PyObject *, bool); +PyObject *ue_unbind_pyevent(ue_PyUObject *, FString, PyObject *, bool); PyObject *py_ue_ufunction_call(UFunction *, UObject *, PyObject *, int, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index e7fcb7de5..d11031775 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -1517,6 +1517,25 @@ PyObject *py_ue_bind_event(ue_PyUObject * self, PyObject * args) return ue_bind_pyevent(self, FString(event_name), py_callable, true); } +PyObject *py_ue_unbind_event(ue_PyUObject * self, PyObject * args) +{ + ue_py_check(self); + + char *event_name; + PyObject *py_callable; + if (!PyArg_ParseTuple(args, "sO:bind_event", &event_name, &py_callable)) + { + return NULL; + } + + if (!PyCallable_Check(py_callable)) + { + return PyErr_Format(PyExc_Exception, "object is not callable"); + } + + return ue_unbind_pyevent(self, FString(event_name), py_callable, true); +} + PyObject *py_ue_delegate_bind_ufunction(ue_PyUObject * self, PyObject * args) { ue_py_check(self); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h index 4f66b78f7..6fb4678fe 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.h +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.h @@ -51,6 +51,7 @@ PyObject *py_ue_enum_user_defined_names(ue_PyUObject *, PyObject *); PyObject *py_ue_bind_event(ue_PyUObject *, PyObject *); +PyObject *py_ue_unbind_event(ue_PyUObject *, PyObject *); PyObject *py_ue_add_function(ue_PyUObject *, PyObject *); PyObject *py_ue_add_property(ue_PyUObject *, PyObject *); @@ -111,4 +112,4 @@ PyObject *py_ue_render_thumbnail(ue_PyUObject *, PyObject *); PyObject *py_ue_to_bytes(ue_PyUObject *, PyObject *); PyObject *py_ue_to_bytearray(ue_PyUObject *, PyObject *); -PyObject *py_ue_from_bytes(ue_PyUObject *, PyObject *); \ No newline at end of file +PyObject *py_ue_from_bytes(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Public/PythonDelegate.h b/Source/UnrealEnginePython/Public/PythonDelegate.h index 01d0f70b7..be46aa511 100644 --- a/Source/UnrealEnginePython/Public/PythonDelegate.h +++ b/Source/UnrealEnginePython/Public/PythonDelegate.h @@ -13,6 +13,7 @@ class UPythonDelegate : public UObject ~UPythonDelegate(); virtual void ProcessEvent(UFunction *function, void *Parms) override; void SetPyCallable(PyObject *callable); + bool UsesPyCallable(PyObject *callable); void SetSignature(UFunction *original_signature); void PyInputHandler(); diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index ed36ecc63..dcde4d3a7 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -238,6 +238,17 @@ class FUnrealEnginePythonHouseKeeper : public FGCObject return Garbaged; } + UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable) + { + for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; + if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable)) + return Tracker.Delegate; + } + return nullptr; + } + UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature) { UPythonDelegate *Delegate = NewObject(); From 30e723241336db7241f4215d50773803161ce6f3 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Thu, 7 Mar 2019 08:07:02 +0100 Subject: [PATCH 42/62] preliminary support for 4.22 --- .../Private/Slate/UEPySImage.h | 4 ++++ .../UnrealEnginePython/Private/UEPyEditor.cpp | 17 +++++++++++++---- .../Private/UObject/UEPyLandscape.cpp | 4 ++++ .../UnrealEnginePython.Build.cs | 2 -- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySImage.h b/Source/UnrealEnginePython/Private/Slate/UEPySImage.h index fb608ef55..584e14e50 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySImage.h +++ b/Source/UnrealEnginePython/Private/Slate/UEPySImage.h @@ -5,7 +5,11 @@ #include "UEPySLeafWidget.h" +#if ENGINE_MINOR_VERSION > 21 +#include "Runtime/SlateCore/Public/Widgets/Images/SImage.h" +#else #include "Runtime/Slate/Public/Widgets/Images/SImage.h" +#endif #include "Runtime/SlateCore/Public/Styling/SlateBrush.h" extern PyTypeObject ue_PySImageType; diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index 4d117dff4..e994cf121 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -286,7 +286,7 @@ PyObject *py_unreal_engine_editor_play(PyObject * self, PyObject * args) Py_END_ALLOW_THREADS; Py_RETURN_NONE; - } +} PyObject *py_unreal_engine_editor_select_actor(PyObject * self, PyObject * args) { @@ -462,7 +462,7 @@ PyObject *py_unreal_engine_import_asset(PyObject * self, PyObject * args) } Py_RETURN_NONE; - } +} PyObject *py_unreal_engine_editor_tick(PyObject * self, PyObject * args) { @@ -796,7 +796,7 @@ PyObject *py_unreal_engine_rename_asset(PyObject * self, PyObject * args) #endif Py_RETURN_NONE; - } +} PyObject *py_unreal_engine_duplicate_asset(PyObject * self, PyObject * args) { @@ -1879,7 +1879,11 @@ PyObject *py_unreal_engine_editor_on_asset_post_import(PyObject * self, PyObject return PyErr_Format(PyExc_Exception, "object is not a callable"); TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewPythonSmartDelegate(py_callable); +#if ENGINE_MINOR_VERSION > 21 + GEditor->GetEditorSubsystem()->OnAssetPostImport.AddSP(py_delegate, &FPythonSmartDelegate::PyFOnAssetPostImport); +#else FEditorDelegates::OnAssetPostImport.AddSP(py_delegate, &FPythonSmartDelegate::PyFOnAssetPostImport); +#endif Py_RETURN_NONE; } @@ -2115,7 +2119,7 @@ PyObject *py_unreal_engine_add_level_to_world(PyObject *self, PyObject * args) #endif Py_RETURN_UOBJECT(level_streaming); - } +} PyObject *py_unreal_engine_move_selected_actors_to_level(PyObject *self, PyObject * args) { @@ -2533,7 +2537,11 @@ PyObject *py_unreal_engine_unregister_settings(PyObject * self, PyObject * args) PyObject *py_unreal_engine_all_viewport_clients(PyObject * self, PyObject * args) { +#if ENGINE_MINOR_VERSION > 21 + TArray clients = GEditor->GetAllViewportClients(); +#else TArray clients = GEditor->AllViewportClients; +#endif PyObject *py_list = PyList_New(0); for (FEditorViewportClient *client : clients) { @@ -2647,5 +2655,6 @@ PyObject *py_unreal_engine_export_assets(PyObject * self, PyObject * args) Py_RETURN_NONE; } + #endif diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp index 883a6ba0f..fbd27d2df 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp @@ -85,10 +85,14 @@ PyObject *py_ue_landscape_export_to_raw_mesh(ue_PyUObject *self, PyObject * args if (!landscape) return PyErr_Format(PyExc_Exception, "uobject is not a ULandscapeProxy"); +#if ENGINE_MINOR_VERSION > 21 + return PyErr_Format(PyExc_Exception, "MeshDescription struct is still unsupported");; +#else FRawMesh raw_mesh; if (!landscape->ExportToRawMesh(lod, raw_mesh)) return PyErr_Format(PyExc_Exception, "unable to export landscape to FRawMesh"); return py_ue_new_fraw_mesh(raw_mesh); +#endif } #endif diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 96b48121d..51394b033 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -100,7 +100,6 @@ public UnrealEnginePython(TargetInfo Target) PublicIncludePaths.AddRange( new string[] { - "UnrealEnginePython/Public", // ... add public include paths required here ... } ); @@ -108,7 +107,6 @@ public UnrealEnginePython(TargetInfo Target) PrivateIncludePaths.AddRange( new string[] { - "UnrealEnginePython/Private", // ... add other private include paths required here ... } ); From e2802a5cdf361a0dfa74c63e6ce1d645ae431612 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Thu, 7 Mar 2019 08:23:34 +0100 Subject: [PATCH 43/62] use FRichCurve instead of FInterpCurveFloat in Sequencer api --- .../Private/UObject/UEPySequencer.cpp | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp index 7d506be0e..8858a7936 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPySequencer.cpp @@ -68,6 +68,51 @@ static bool magic_get_frame_number(UMovieScene *MovieScene, PyObject *py_obj, FF } #if WITH_EDITOR +#if ENGINE_MINOR_VERSION > 21 +static void ImportTransformChannel(const FRichCurve& Source, FMovieSceneFloatChannel* Dest, FFrameRate DestFrameRate, bool bNegateTangents) +{ + TMovieSceneChannelData ChannelData = Dest->GetData(); + ChannelData.Reset(); + double DecimalRate = DestFrameRate.AsDecimal(); + for (int32 KeyIndex = 0; KeyIndex < Source.Keys.Num(); ++KeyIndex) + { + float ArriveTangent = Source.Keys[KeyIndex].ArriveTangent; + if (KeyIndex > 0) + { + ArriveTangent = ArriveTangent / ((Source.Keys[KeyIndex].Value - Source.Keys[KeyIndex - 1].Value) * DecimalRate); + } + + float LeaveTangent = Source.Keys[KeyIndex].LeaveTangent; + if (KeyIndex < Source.Keys.Num() - 1) + { + LeaveTangent = LeaveTangent / ((Source.Keys[KeyIndex + 1].Value - Source.Keys[KeyIndex].Value) * DecimalRate); + } + + if (bNegateTangents) + { + ArriveTangent = -ArriveTangent; + LeaveTangent = -LeaveTangent; + } + + FFrameNumber KeyTime = (Source.Keys[KeyIndex].Value * DestFrameRate).RoundToFrame(); + if (ChannelData.FindKey(KeyTime) == INDEX_NONE) + { + FMovieSceneFloatValue NewKey(Source.Keys[KeyIndex].Value); + + NewKey.InterpMode = Source.Keys[KeyIndex].InterpMode; + NewKey.TangentMode = Source.Keys[KeyIndex].TangentMode; + NewKey.Tangent.ArriveTangent = ArriveTangent / DestFrameRate.AsDecimal(); + NewKey.Tangent.LeaveTangent = LeaveTangent / DestFrameRate.AsDecimal(); + NewKey.Tangent.TangentWeightMode = RCTWM_WeightedNone; + NewKey.Tangent.ArriveTangentWeight = 0.0f; + NewKey.Tangent.LeaveTangentWeight = 0.0f; + ChannelData.AddKey(KeyTime, NewKey); + } + } + + Dest->AutoSetTangents(); +} +#else static void ImportTransformChannel(const FInterpCurveFloat& Source, FMovieSceneFloatChannel* Dest, FFrameRate DestFrameRate, bool bNegateTangents) { TMovieSceneChannelData ChannelData = Dest->GetData(); @@ -103,18 +148,27 @@ static void ImportTransformChannel(const FInterpCurveFloat& Source, FMovieSceneF Dest->AutoSetTangents(); } +#endif static bool ImportFBXTransform(FString NodeName, UMovieScene3DTransformSection* TransformSection, UnFbx::FFbxCurvesAPI& CurveAPI) { // Look for transforms explicitly + FTransform DefaultTransform; + +#if ENGINE_MINOR_VERSION > 21 + FRichCurve Translation[3]; + FRichCurve EulerRotation[3]; + FRichCurve Scale[3]; +#else FInterpCurveFloat Translation[3]; FInterpCurveFloat EulerRotation[3]; FInterpCurveFloat Scale[3]; - FTransform DefaultTransform; +#endif CurveAPI.GetConvertedTransformCurveData(NodeName, Translation[0], Translation[1], Translation[2], EulerRotation[0], EulerRotation[1], EulerRotation[2], Scale[0], Scale[1], Scale[2], DefaultTransform); + TransformSection->Modify(); FFrameRate FrameRate = TransformSection->GetTypedOuter()->GetTickResolution(); @@ -1594,9 +1648,15 @@ PyObject *py_ue_sequencer_import_fbx_transform(ue_PyUObject *self, PyObject * ar continue; // Look for transforms explicitly +#if ENGINE_MINOR_VERSION > 21 + FRichCurve Translation[3]; + FRichCurve EulerRotation[3]; + FRichCurve Scale[3]; +#else FInterpCurveFloat Translation[3]; FInterpCurveFloat EulerRotation[3]; FInterpCurveFloat Scale[3]; +#endif FTransform DefaultTransform; #if ENGINE_MINOR_VERSION >= 18 CurveAPI.GetConvertedTransformCurveData(NodeName, Translation[0], Translation[1], Translation[2], EulerRotation[0], EulerRotation[1], EulerRotation[2], Scale[0], Scale[1], Scale[2], DefaultTransform); From 020763ac04138323abf99b0d09fc600f0762bbd9 Mon Sep 17 00:00:00 2001 From: Devin Curry Date: Tue, 12 Mar 2019 10:46:02 -0700 Subject: [PATCH 44/62] Add break_all_links() and get_linked_to() for blueprint pins --- .../Private/Blueprint/UEPyEdGraphPin.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraphPin.cpp b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraphPin.cpp index dca7bf864..283079f31 100644 --- a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraphPin.cpp +++ b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraphPin.cpp @@ -80,9 +80,49 @@ static PyObject *py_ue_edgraphpin_break_link_to(ue_PyEdGraphPin *self, PyObject Py_RETURN_NONE; } +static PyObject *py_ue_edgraphpin_break_all_pin_links(ue_PyEdGraphPin *self, PyObject * args) +{ + PyObject *py_notify_nodes = nullptr; + if (!PyArg_ParseTuple(args, "O:break_all_pin_links", &py_notify_nodes)) + { + return NULL; + } + + bool notify_nodes = true; + if (py_notify_nodes && !PyObject_IsTrue(py_notify_nodes)) + notify_nodes = false; + + self->pin->BreakAllPinLinks(notify_nodes); + + if (UBlueprint *bp = Cast(self->pin->GetOwningNode()->GetGraph()->GetOuter())) + { + FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(bp); + } + + Py_RETURN_NONE; +} + +static PyObject *py_ue_edgraphpin_get_linked_to(ue_PyEdGraphPin * self, PyObject * args) +{ + PyObject *pins = PyList_New(0); + + TArray Links = self->pin->LinkedTo; + + for (int32 i = 0; i < Links.Num(); i++) + { + UEdGraphPin *pin = Links[i]; + ue_PyUObject *item = (ue_PyUObject *)py_ue_new_edgraphpin(pin); + if (item) + PyList_Append(pins, (PyObject *)item); + } + return pins; +} + static PyMethodDef ue_PyEdGraphPin_methods[] = { { "make_link_to", (PyCFunction)py_ue_edgraphpin_make_link_to, METH_VARARGS, "" }, { "break_link_to", (PyCFunction)py_ue_edgraphpin_break_link_to, METH_VARARGS, "" }, + { "break_all_pin_links", (PyCFunction)py_ue_edgraphpin_break_all_pin_links, METH_VARARGS, "" }, + { "get_linked_to", (PyCFunction)py_ue_edgraphpin_get_linked_to, METH_VARARGS, "" }, { "connect", (PyCFunction)py_ue_edgraphpin_connect, METH_VARARGS, "" }, { NULL } /* Sentinel */ }; From 1da9fbc7002c2f1c33762cf97064b09faf85bcb1 Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 13 Mar 2019 17:11:14 -0600 Subject: [PATCH 45/62] fixed 4.19 build --- Source/UnrealEnginePython/UnrealEnginePython.Build.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 51394b033..48d6618c1 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -107,6 +107,9 @@ public UnrealEnginePython(TargetInfo Target) PrivateIncludePaths.AddRange( new string[] { +#if !UE_4_22_OR_LATER + "UnrealEnginePython/Private", +#endif // ... add other private include paths required here ... } ); From 8ed4abccdc503f91154ff8bd791e464292319a47 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 14 Mar 2019 10:05:50 -0600 Subject: [PATCH 46/62] Split PythonHouseKeeper into .h and .cpp file for easier debugging --- .../Private/PythonHouseKeeper.cpp | 255 +++++++++++++ .../Public/PythonHouseKeeper.h | 340 +++--------------- .../UnrealEnginePython.Build.cs | 3 - 3 files changed, 309 insertions(+), 289 deletions(-) create mode 100644 Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp diff --git a/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp new file mode 100644 index 000000000..ea9d5dda3 --- /dev/null +++ b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp @@ -0,0 +1,255 @@ +#pragma once + +#include "PythonHouseKeeper.h" + +void FUnrealEnginePythonHouseKeeper::AddReferencedObjects(FReferenceCollector& InCollector) +{ + InCollector.AddReferencedObjects(PythonTrackedObjects); +} + +FUnrealEnginePythonHouseKeeper *FUnrealEnginePythonHouseKeeper::Get() +{ + static FUnrealEnginePythonHouseKeeper *Singleton; + if (!Singleton) + { + Singleton = new FUnrealEnginePythonHouseKeeper(); + // register a new delegate for the GC +#if ENGINE_MINOR_VERSION >= 18 + FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); +#else + FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); +#endif + } + return Singleton; +} + +void FUnrealEnginePythonHouseKeeper::RunGCDelegate() +{ + FScopePythonGIL gil; + RunGC(); +} + +int32 FUnrealEnginePythonHouseKeeper::RunGC() +{ + int32 Garbaged = PyUObjectsGC(); + Garbaged += DelegatesGC(); + return Garbaged; +} + +bool FUnrealEnginePythonHouseKeeper::IsValidPyUObject(ue_PyUObject *PyUObject) +{ + if (!PyUObject) + return false; + + UObject *Object = PyUObject->ue_object; + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return false; + } + + if (!Tracker->Owner.IsValid()) + return false; + + return true; + +} + +void FUnrealEnginePythonHouseKeeper::TrackUObject(UObject *Object) +{ + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return; + } + if (Tracker->bPythonOwned) + return; + Tracker->bPythonOwned = true; + // when a new ue_PyUObject spawns, it has a reference counting of two + Py_DECREF(Tracker->PyUObject); + Tracker->PyUObject->owned = 1; + PythonTrackedObjects.Add(Object); +} + +void FUnrealEnginePythonHouseKeeper::UntrackUObject(UObject *Object) +{ + PythonTrackedObjects.Remove(Object); +} + +void FUnrealEnginePythonHouseKeeper::RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject) +{ + UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject)); +} + +void FUnrealEnginePythonHouseKeeper::UnregisterPyUObject(UObject *Object) +{ + UObjectPyMapping.Remove(Object); +} + +ue_PyUObject *FUnrealEnginePythonHouseKeeper::GetPyUObject(UObject *Object) +{ + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return nullptr; + } + + if (!Tracker->Owner.IsValid(true)) + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt); +#endif + if (!Tracker->bPythonOwned) + Py_DECREF((PyObject *)Tracker->PyUObject); + UnregisterPyUObject(Object); + return nullptr; +} + + return Tracker->PyUObject; +} + +uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC() +{ + uint32 Garbaged = 0; + TArray BrokenList; + for (auto &UObjectPyItem : UObjectPyMapping) + { + UObject *Object = UObjectPyItem.Key; + FPythonUOjectTracker &Tracker = UObjectPyItem.Value; +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object); +#endif + if (!Tracker.Owner.IsValid(true)) + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt); +#endif + BrokenList.Add(Object); + Garbaged++; + } + else + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName()); +#endif +} + } + + for (UObject *Object : BrokenList) + { + FPythonUOjectTracker &Tracker = UObjectPyMapping[Object]; + if (!Tracker.bPythonOwned) + Py_DECREF((PyObject *)Tracker.PyUObject); + UnregisterPyUObject(Object); + } + + return Garbaged; + +} + + +int32 FUnrealEnginePythonHouseKeeper::DelegatesGC() +{ + int32 Garbaged = 0; +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num()); +#endif + for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; + if (!Tracker.Owner.IsValid(true)) + { + Tracker.Delegate->RemoveFromRoot(); + PyDelegatesTracker.RemoveAt(i); + Garbaged++; + } + + } + +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num()); +#endif + + for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i]; + if (!Tracker.Owner.IsValid()) + { + PySlateDelegatesTracker.RemoveAt(i); + Garbaged++; + } + + } + return Garbaged; + } + +UPythonDelegate *FUnrealEnginePythonHouseKeeper::FindDelegate(UObject *Owner, PyObject *PyCallable) +{ + for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; + if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable)) + return Tracker.Delegate; + } + return nullptr; +} + +UPythonDelegate *FUnrealEnginePythonHouseKeeper::NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature) +{ + UPythonDelegate *Delegate = NewObject(); + + Delegate->AddToRoot(); + Delegate->SetPyCallable(PyCallable); + Delegate->SetSignature(Signature); + + FPythonDelegateTracker Tracker(Delegate, Owner); + PyDelegatesTracker.Add(Tracker); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); + PySlateDelegatesTracker.Add(Tracker); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewDeferredSlateDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewPythonSmartDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSmartDelegate()); + Delegate->SetPyCallable(PyCallable); + + PyStaticSmartDelegatesTracker.Add(Delegate); + + return Delegate; +} + +void FUnrealEnginePythonHouseKeeper::TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner) +{ + FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); + PySlateDelegatesTracker.Add(Tracker); +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewStaticSlateDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + PyStaticSlateDelegatesTracker.Add(Delegate); + + return Delegate; +} + diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index dcde4d3a7..ccd9edb01 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -11,304 +11,72 @@ class FUnrealEnginePythonHouseKeeper : public FGCObject { - - struct FPythonUOjectTracker - { - FWeakObjectPtr Owner; - ue_PyUObject *PyUObject; - bool bPythonOwned; - - FPythonUOjectTracker(UObject *Object, ue_PyUObject *InPyUObject) - { - Owner = FWeakObjectPtr(Object); - PyUObject = InPyUObject; - bPythonOwned = false; - } - }; - - struct FPythonDelegateTracker - { - FWeakObjectPtr Owner; - UPythonDelegate *Delegate; - - FPythonDelegateTracker(UPythonDelegate *DelegateToTrack, UObject *DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) - { - } - - ~FPythonDelegateTracker() - { - } - }; - - - struct FPythonSWidgetDelegateTracker - { - TWeakPtr Owner; - TSharedPtr Delegate; - - FPythonSWidgetDelegateTracker(TSharedRef DelegateToTrack, TSharedRef DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) - { - } - - ~FPythonSWidgetDelegateTracker() - { - } - }; - -public: - - virtual void AddReferencedObjects(FReferenceCollector& InCollector) override - { - InCollector.AddReferencedObjects(PythonTrackedObjects); - } - - static FUnrealEnginePythonHouseKeeper *Get() - { - static FUnrealEnginePythonHouseKeeper *Singleton; - if (!Singleton) - { - Singleton = new FUnrealEnginePythonHouseKeeper(); - // register a new delegate for the GC -#if ENGINE_MINOR_VERSION >= 18 - FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); -#else - FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); -#endif - } - return Singleton; - } - - void RunGCDelegate() - { - FScopePythonGIL gil; - RunGC(); - } - - int32 RunGC() - { - int32 Garbaged = PyUObjectsGC(); - Garbaged += DelegatesGC(); - return Garbaged; - } - - bool IsValidPyUObject(ue_PyUObject *PyUObject) - { - if (!PyUObject) - return false; - - UObject *Object = PyUObject->ue_object; - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return false; - } - - if (!Tracker->Owner.IsValid()) - return false; - - return true; - - } - - void TrackUObject(UObject *Object) - { - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return; - } - if (Tracker->bPythonOwned) - return; - Tracker->bPythonOwned = true; - // when a new ue_PyUObject spawns, it has a reference counting of two - Py_DECREF(Tracker->PyUObject); - Tracker->PyUObject->owned = 1; - PythonTrackedObjects.Add(Object); - } - - void UntrackUObject(UObject *Object) - { - PythonTrackedObjects.Remove(Object); - } - - void RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject) - { - UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject)); - } - - void UnregisterPyUObject(UObject *Object) - { - UObjectPyMapping.Remove(Object); - } - - ue_PyUObject *GetPyUObject(UObject *Object) - { - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return nullptr; - } - - if (!Tracker->Owner.IsValid(true)) - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt); -#endif - if (!Tracker->bPythonOwned) - Py_DECREF((PyObject *)Tracker->PyUObject); - UnregisterPyUObject(Object); - return nullptr; - } - - return Tracker->PyUObject; -} - - uint32 PyUObjectsGC() - { - uint32 Garbaged = 0; - TArray BrokenList; - for (auto &UObjectPyItem : UObjectPyMapping) - { - UObject *Object = UObjectPyItem.Key; - FPythonUOjectTracker &Tracker = UObjectPyItem.Value; -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object); -#endif - if (!Tracker.Owner.IsValid(true)) - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt); -#endif - BrokenList.Add(Object); - Garbaged++; - } - else - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName()); -#endif - } - } - - for (UObject *Object : BrokenList) - { - FPythonUOjectTracker &Tracker = UObjectPyMapping[Object]; - if (!Tracker.bPythonOwned) - Py_DECREF((PyObject *)Tracker.PyUObject); - UnregisterPyUObject(Object); - } - - return Garbaged; - - } - - - int32 DelegatesGC() - { - int32 Garbaged = 0; -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num()); -#endif - for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; - if (!Tracker.Owner.IsValid(true)) - { - Tracker.Delegate->RemoveFromRoot(); - PyDelegatesTracker.RemoveAt(i); - Garbaged++; - } - - } - -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num()); -#endif - - for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i]; - if (!Tracker.Owner.IsValid()) - { - PySlateDelegatesTracker.RemoveAt(i); - Garbaged++; - } - - } - return Garbaged; - } - - UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable) + struct FPythonUOjectTracker { - for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; - if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable)) - return Tracker.Delegate; + FWeakObjectPtr Owner; + ue_PyUObject *PyUObject; + bool bPythonOwned; + + FPythonUOjectTracker(UObject *Object, ue_PyUObject *InPyUObject) + { + Owner = FWeakObjectPtr(Object); + PyUObject = InPyUObject; + bPythonOwned = false; } - return nullptr; - } - - UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature) - { - UPythonDelegate *Delegate = NewObject(); - - Delegate->AddToRoot(); - Delegate->SetPyCallable(PyCallable); - Delegate->SetSignature(Signature); - - FPythonDelegateTracker Tracker(Delegate, Owner); - PyDelegatesTracker.Add(Tracker); + }; - return Delegate; - } - - TSharedRef NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); - - FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); - PySlateDelegatesTracker.Add(Tracker); - - return Delegate; - } - - TSharedRef NewDeferredSlateDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); - - return Delegate; - } + struct FPythonDelegateTracker + { + FWeakObjectPtr Owner; + UPythonDelegate *Delegate; - TSharedRef NewPythonSmartDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSmartDelegate()); - Delegate->SetPyCallable(PyCallable); + FPythonDelegateTracker(UPythonDelegate *DelegateToTrack, UObject *DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) + { + } - PyStaticSmartDelegatesTracker.Add(Delegate); + ~FPythonDelegateTracker() + { + } + }; - return Delegate; - } + struct FPythonSWidgetDelegateTracker + { + TWeakPtr Owner; + TSharedPtr Delegate; - void TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner) - { - FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); - PySlateDelegatesTracker.Add(Tracker); - } + FPythonSWidgetDelegateTracker(TSharedRef DelegateToTrack, TSharedRef DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) + { + } - TSharedRef NewStaticSlateDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); + ~FPythonSWidgetDelegateTracker() + { + } + }; - PyStaticSlateDelegatesTracker.Add(Delegate); +public: - return Delegate; - } + virtual void AddReferencedObjects(FReferenceCollector& InCollector) override; + static FUnrealEnginePythonHouseKeeper *Get(); + int32 RunGC(); + bool IsValidPyUObject(ue_PyUObject *PyUObject); + void TrackUObject(UObject *Object); + void UntrackUObject(UObject *Object); + void RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject); + void UnregisterPyUObject(UObject *Object); + ue_PyUObject *GetPyUObject(UObject *Object); + UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable); + UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature); + TSharedRef NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable); + TSharedRef NewDeferredSlateDelegate(PyObject *PyCallable); + TSharedRef NewPythonSmartDelegate(PyObject *PyCallable); + void TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner); + TSharedRef NewStaticSlateDelegate(PyObject *PyCallable); private: + void RunGCDelegate(); + uint32 PyUObjectsGC(); + int32 DelegatesGC(); + TMap UObjectPyMapping; TArray PyDelegatesTracker; diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 48d6618c1..51394b033 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -107,9 +107,6 @@ public UnrealEnginePython(TargetInfo Target) PrivateIncludePaths.AddRange( new string[] { -#if !UE_4_22_OR_LATER - "UnrealEnginePython/Private", -#endif // ... add other private include paths required here ... } ); From 79aef1e4c78497495f574790962dd835c269ca58 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Tue, 23 Apr 2019 16:21:14 +0200 Subject: [PATCH 47/62] fixed non editor build --- Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp index ec2be2b7c..61cf5c247 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp @@ -316,8 +316,11 @@ PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args) if (!level) return PyErr_Format(PyExc_Exception, "argument is not a ULevel"); +#if WITH_EDITOR + if (world->SetCurrentLevel(level)) Py_RETURN_TRUE; +#endif Py_RETURN_FALSE; } From 62016f5eaa0d7f8481d7943b4c15aa1b119fee37 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Tue, 23 Apr 2019 16:23:45 +0200 Subject: [PATCH 48/62] fix for 4.22 --- Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp index 61cf5c247..19a31299b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyWorld.cpp @@ -316,7 +316,7 @@ PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args) if (!level) return PyErr_Format(PyExc_Exception, "argument is not a ULevel"); -#if WITH_EDITOR +#if WITH_EDITOR || ENGINE_MINOR_VERSION < 22 if (world->SetCurrentLevel(level)) Py_RETURN_TRUE; From 76ae4b11bfd1cf46db0b191657c0ec2263b12741 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Fri, 26 Apr 2019 18:02:14 +0200 Subject: [PATCH 49/62] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46264da12..17e845c1c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Once the plugin is installed and enabled, you get access to the 'PythonConsole' All of the exposed engine features are under the 'unreal_engine' virtual module (it is completely coded in c into the plugin, so do not expect to run 'import unreal_engine' from a standard python shell) -The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20 and 4.21 +The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 4.21 and 4.22 We support official python.org releases as well as IntelPython and Anaconda distributions. From 2b92282224328c06d81ca2635eab605a5b54d19c Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 8 May 2019 10:14:01 +0200 Subject: [PATCH 50/62] added 4.22 to automatic build system --- tools/release_win64.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release_win64.py b/tools/release_win64.py index bee239f42..4ea5beb89 100644 --- a/tools/release_win64.py +++ b/tools/release_win64.py @@ -5,7 +5,7 @@ import shutil import zipfile -UE_VERSIONS = ['4.15', '4.16', '4.17', '4.18', '4.19', '4.20', '4.21'] +UE_VERSIONS = ['4.17', '4.18', '4.19', '4.20', '4.21', '4.22'] PYTHON_VERSIONS = ["C:/Program Files/Python37", "C:/Program Files/Python36", "C:/Python27"] MSBUILD = 'C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/MSBuild/15.0/Bin/MSBuild.exe' UE_PATH = 'C:/Program Files/Epic Games' From 282eaa5f7730f96541cc706b05952a8bf814e92c Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 8 May 2019 11:25:28 +0200 Subject: [PATCH 51/62] start from 4.20 for automatic builds --- tools/release_win64.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release_win64.py b/tools/release_win64.py index 4ea5beb89..057800496 100644 --- a/tools/release_win64.py +++ b/tools/release_win64.py @@ -5,7 +5,7 @@ import shutil import zipfile -UE_VERSIONS = ['4.17', '4.18', '4.19', '4.20', '4.21', '4.22'] +UE_VERSIONS = ['4.20', '4.21', '4.22'] PYTHON_VERSIONS = ["C:/Program Files/Python37", "C:/Program Files/Python36", "C:/Python27"] MSBUILD = 'C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/MSBuild/15.0/Bin/MSBuild.exe' UE_PATH = 'C:/Program Files/Epic Games' From 6a43ea4f250a39f9ad1686dfd90770d9ae4ea8f3 Mon Sep 17 00:00:00 2001 From: Elvis Dowson Date: Tue, 4 Jun 2019 11:58:03 +0400 Subject: [PATCH 52/62] .gitignore: Ignore Intermediate folder. Signed-off-by: Elvis Dowson --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a8f0b03d6..e43464f53 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,7 @@ ENV/ .ropeproject Binaries/ +Intermediate/ python35/ python27/ *.un~ From 02dd03dfd26f72d3d6252febff1d79bdb037cf97 Mon Sep 17 00:00:00 2001 From: Elvis Dowson Date: Tue, 4 Jun 2019 12:02:04 +0400 Subject: [PATCH 53/62] PythonHouseKeeper: Fix compile error: #pragma once in main file This commit fixes the following error: PythonHouseKeeper.cpp:1:9: error: #pragma once in main file [-Werror,-Wpragma-once-outside-header] #pragma once ^ Signed-off-by: Elvis Dowson --- Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp index ea9d5dda3..dc014e386 100644 --- a/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp +++ b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp @@ -1,4 +1,3 @@ -#pragma once #include "PythonHouseKeeper.h" From e928f718c3f6ba82998f681f58f07ebc101db93f Mon Sep 17 00:00:00 2001 From: Elvis Dowson Date: Tue, 4 Jun 2019 12:03:18 +0400 Subject: [PATCH 54/62] PythonAutomationModule: Update for UE4.22. Signed-off-by: Elvis Dowson --- Source/PythonAutomation/Public/PythonAutomationModule.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/PythonAutomation/Public/PythonAutomationModule.h b/Source/PythonAutomation/Public/PythonAutomationModule.h index c0f9c6d16..bc19a062e 100644 --- a/Source/PythonAutomation/Public/PythonAutomationModule.h +++ b/Source/PythonAutomation/Public/PythonAutomationModule.h @@ -3,7 +3,11 @@ #pragma once #include "CoreMinimal.h" +#if ENGINE_MAJOR_VERSION==4 && ENGINE_MINOR_VERSION>=22 +#include "Modules/ModuleInterface.h" +#else #include "ModuleInterface.h" +#endif class FPythonAutomationModule : public IModuleInterface { From bc4b7915125d5e78b3a65dd1df00f1fdf0ad00c3 Mon Sep 17 00:00:00 2001 From: Fabian Elmers Date: Fri, 14 Jun 2019 14:36:07 -0700 Subject: [PATCH 55/62] Adding edgraph functions graph_reconstruct_node() and graph_remove_node() --- .../Private/Blueprint/UEPyEdGraph.cpp | 121 ++++++++++++++++++ .../Private/Blueprint/UEPyEdGraph.h | 3 + .../UnrealEnginePython/Private/UEPyModule.cpp | 3 + 3 files changed, 127 insertions(+) diff --git a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.cpp b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.cpp index 6f75053ba..a3e53b7c5 100644 --- a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.cpp +++ b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.cpp @@ -381,6 +381,127 @@ PyObject *py_ue_graph_add_node(ue_PyUObject * self, PyObject * args) Py_RETURN_UOBJECT(node); } +PyObject *py_ue_graph_remove_node(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + PyObject *py_node_class; + int x = 0; + int y = 0; + + char *metadata = nullptr; + PyObject *py_data = nullptr; + + if (!PyArg_ParseTuple(args, "O|iisO:graph_remove_node", &py_node_class, &x, &y, &metadata, &py_data)) + { + return nullptr; + } + + UEdGraph *graph = ue_py_check_type(self); + if (!graph) + return PyErr_Format(PyExc_Exception, "uobject is not a UEdGraph"); + + UObject *u_obj = ue_py_check_type(py_node_class); + if (!u_obj) + return PyErr_Format(PyExc_Exception, "argument is not a UObject"); + + UEdGraphNode *node = nullptr; + + if (UClass *u_class = Cast(u_obj)) + { + if (!u_class->IsChildOf()) + { + return PyErr_Format(PyExc_Exception, "argument is not a child of UEdGraphNode"); + } + node = NewObject(graph, u_class); + node->PostLoad(); + } + else + { + node = Cast(u_obj); + if (node) + { + if (node->GetOuter() != graph) + + node->Rename(*node->GetName(), graph); + } + } + + if (!node) + return PyErr_Format(PyExc_Exception, "argument is not a supported type"); + + graph->RemoveNode(node); + + if (UBlueprint *bp = Cast(node->GetGraph()->GetOuter())) + { + FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(bp); + } + + Py_RETURN_NONE; +} + +PyObject *py_ue_graph_reconstruct_node(ue_PyUObject * self, PyObject * args) +{ + + ue_py_check(self); + + PyObject *py_node_class; + int x = 0; + int y = 0; + + char *metadata = nullptr; + PyObject *py_data = nullptr; + + if (!PyArg_ParseTuple(args, "O|iisO:graph_reconstruct_node", &py_node_class, &x, &y, &metadata, &py_data)) + { + return nullptr; + } + + UEdGraph *graph = ue_py_check_type(self); + if (!graph) + return PyErr_Format(PyExc_Exception, "uobject is not a UEdGraph"); + + UObject *u_obj = ue_py_check_type(py_node_class); + if (!u_obj) + return PyErr_Format(PyExc_Exception, "argument is not a UObject"); + + UEdGraphNode *node = nullptr; + + if (UClass *u_class = Cast(u_obj)) + { + if (!u_class->IsChildOf()) + { + return PyErr_Format(PyExc_Exception, "argument is not a child of UEdGraphNode"); + } + node = NewObject(graph, u_class); + node->PostLoad(); + } + else + { + node = Cast(u_obj); + if (node) + { + if (node->GetOuter() != graph) + + node->Rename(*node->GetName(), graph); + } + } + + if (!node) + return PyErr_Format(PyExc_Exception, "argument is not a supported type"); + + //graph->RemoveNode(node); + node->ReconstructNode(); + + if (UBlueprint *bp = Cast(node->GetGraph()->GetOuter())) + { + FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(bp); + } + + Py_RETURN_NONE; +} + PyObject *py_ue_graph_add_node_dynamic_cast(ue_PyUObject * self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.h b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.h index 03061426b..e0fd0fe69 100644 --- a/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.h +++ b/Source/UnrealEnginePython/Private/Blueprint/UEPyEdGraph.h @@ -16,6 +16,9 @@ PyObject *py_ue_graph_add_node(ue_PyUObject *, PyObject *); PyObject *py_ue_graph_add_node_dynamic_cast(ue_PyUObject *, PyObject *); PyObject *py_ue_graph_add_node_event(ue_PyUObject *, PyObject *); +PyObject *py_ue_graph_reconstruct_node(ue_PyUObject *, PyObject *); +PyObject *py_ue_graph_remove_node(ue_PyUObject *, PyObject *); + PyObject *py_ue_graph_get_good_place_for_new_node(ue_PyUObject *, PyObject *); PyObject *py_ue_node_pins(ue_PyUObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 993828a86..66aab749b 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -664,6 +664,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "graph_add_node_event", (PyCFunction)py_ue_graph_add_node_event, METH_VARARGS, "" }, { "graph_get_good_place_for_new_node", (PyCFunction)py_ue_graph_get_good_place_for_new_node, METH_VARARGS, "" }, + { "graph_reconstruct_node", (PyCFunction)py_ue_graph_reconstruct_node, METH_VARARGS, "" }, + { "graph_remove_node", (PyCFunction)py_ue_graph_remove_node, METH_VARARGS, "" }, + { "node_pins", (PyCFunction)py_ue_node_pins, METH_VARARGS, "" }, { "node_get_title", (PyCFunction)py_ue_node_get_title, METH_VARARGS, "" }, { "node_find_pin", (PyCFunction)py_ue_node_find_pin, METH_VARARGS, "" }, From 15f9eea0caddaa0d8237e260de9f63d039282fbc Mon Sep 17 00:00:00 2001 From: Michael Chapman Date: Sun, 30 Jun 2019 01:51:37 +1000 Subject: [PATCH 56/62] Add remove_component_from_blueprint Add support for removing components from blueprints to compliment existing add component functionality --- .../UnrealEnginePython/Private/UEPyEditor.cpp | 31 +++++++++++++++++++ .../UnrealEnginePython/Private/UEPyEditor.h | 1 + .../UnrealEnginePython/Private/UEPyModule.cpp | 1 + 3 files changed, 33 insertions(+) diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.cpp b/Source/UnrealEnginePython/Private/UEPyEditor.cpp index e994cf121..1b3df7bca 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.cpp +++ b/Source/UnrealEnginePython/Private/UEPyEditor.cpp @@ -1473,6 +1473,37 @@ PyObject *py_unreal_engine_get_blueprint_components(PyObject * self, PyObject * } +PyObject *py_unreal_engine_remove_component_from_blueprint(PyObject *self, PyObject *args) +{ + PyObject *py_blueprint; + char *name; + char *parentName = nullptr; + + if (!PyArg_ParseTuple(args, "Os|s:remove_component_from_blueprint", &py_blueprint, &name, &parentName)) + { + return NULL; + } + + if (!ue_is_pyuobject(py_blueprint)) + { + return PyErr_Format(PyExc_Exception, "argument is not a UObject"); + } + + ue_PyUObject *py_obj = (ue_PyUObject *)py_blueprint; + if (!py_obj->ue_object->IsA()) + return PyErr_Format(PyExc_Exception, "uobject is not a UBlueprint"); + UBlueprint *bp = (UBlueprint *)py_obj->ue_object; + + bp->Modify(); + USCS_Node *ComponentNode = bp->SimpleConstructionScript->FindSCSNode(UTF8_TO_TCHAR(name)); + if (ComponentNode) + { + bp->SimpleConstructionScript->RemoveNode(ComponentNode); + } + + Py_RETURN_NONE; +} + PyObject *py_unreal_engine_add_component_to_blueprint(PyObject * self, PyObject * args) { diff --git a/Source/UnrealEnginePython/Private/UEPyEditor.h b/Source/UnrealEnginePython/Private/UEPyEditor.h index 788a76ad3..31c8028e1 100644 --- a/Source/UnrealEnginePython/Private/UEPyEditor.h +++ b/Source/UnrealEnginePython/Private/UEPyEditor.h @@ -52,6 +52,7 @@ PyObject *py_unreal_engine_reload_blueprint(PyObject *, PyObject *); PyObject *py_unreal_engine_replace_blueprint(PyObject *, PyObject *); PyObject *py_unreal_engine_create_blueprint_from_actor(PyObject *, PyObject *); PyObject *py_unreal_engine_add_component_to_blueprint(PyObject *, PyObject *); +PyObject *py_unreal_engine_remove_component_from_blueprint(PyObject *, PyObject *); PyObject *py_unreal_engine_blueprint_add_member_variable(PyObject *, PyObject *); PyObject *py_unreal_engine_blueprint_add_new_timeline(PyObject *, PyObject *); diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index 993828a86..ed7a1d4b8 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -389,6 +389,7 @@ static PyMethodDef unreal_engine_methods[] = { { "blueprint_get_all_graphs", py_unreal_engine_blueprint_get_all_graphs, METH_VARARGS, "" }, { "blueprint_mark_as_structurally_modified", py_unreal_engine_blueprint_mark_as_structurally_modified, METH_VARARGS, "" }, { "add_component_to_blueprint", py_unreal_engine_add_component_to_blueprint, METH_VARARGS, "" }, + { "remove_component_from_blueprint", py_unreal_engine_remove_component_from_blueprint, METH_VARARGS, "" }, { "get_blueprint_components", py_unreal_engine_get_blueprint_components, METH_VARARGS, "" }, { "create_material_instance", py_unreal_engine_create_material_instance, METH_VARARGS, "" }, { "message_dialog_open", py_unreal_engine_message_dialog_open, METH_VARARGS, "" }, From 7b33998d15fb77a386b21b3d219ac7f0efe7b88e Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Mon, 9 Sep 2019 07:46:55 +0200 Subject: [PATCH 57/62] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17e845c1c..ee231ff61 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Once the plugin is installed and enabled, you get access to the 'PythonConsole' All of the exposed engine features are under the 'unreal_engine' virtual module (it is completely coded in c into the plugin, so do not expect to run 'import unreal_engine' from a standard python shell) -The currently supported Unreal Engine versions are 4.12, 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 4.21 and 4.22 +The minimal supported Unreal Engine version is 4.12, while the latest is 4.23 We support official python.org releases as well as IntelPython and Anaconda distributions. From 11d550b62272844b8dcd28c9bfe5ddd92ff20ab4 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Tue, 10 Sep 2019 19:33:39 +0200 Subject: [PATCH 58/62] first round of 4.23 patches --- .../Private/Slate/UEPyFMenuBuilder.cpp | 76 +-- .../UnrealEnginePython/Private/UEPyModule.cpp | 559 +++++++++--------- .../Private/UEPySubclassing.cpp | 9 + .../Private/UObject/UEPyAnimSequence.cpp | 2 + .../Private/UObject/UEPyFoliage.cpp | 17 +- .../Private/UObject/UEPyLandscape.cpp | 33 +- .../Private/UObject/UEPyMaterial.cpp | 4 + .../Private/Wrappers/UEPyESlateEnums.cpp | 4 + .../Private/Wrappers/UEPyFFoliageInstance.cpp | 80 +-- .../UnrealEnginePython.Build.cs | 2 +- 10 files changed, 432 insertions(+), 354 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp index 3157ec4f0..3e0b978ed 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPyFMenuBuilder.cpp @@ -2,10 +2,10 @@ #include "Wrappers/UEPyESlateEnums.h" -static PyObject *py_ue_fmenu_builder_begin_section(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_begin_section(ue_PyFMenuBuilder* self, PyObject* args) { - char *name; - char *text; + char* name; + char* text; if (!PyArg_ParseTuple(args, "ss:begin_section", &name, &text)) return nullptr; @@ -14,27 +14,31 @@ static PyObject *py_ue_fmenu_builder_begin_section(ue_PyFMenuBuilder *self, PyOb Py_RETURN_NONE; } -static PyObject *py_ue_fmenu_builder_end_section(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_end_section(ue_PyFMenuBuilder* self, PyObject* args) { self->menu_builder.EndSection(); Py_RETURN_NONE; } -static PyObject *py_ue_fmenu_builder_make_widget(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_make_widget(ue_PyFMenuBuilder* self, PyObject* args) { - ue_PySWidget *ret = (ue_PySWidget *)PyObject_New(ue_PySWidget, &ue_PySWidgetType); + ue_PySWidget* ret = (ue_PySWidget*)PyObject_New(ue_PySWidget, &ue_PySWidgetType); new (&ret->Widget) TSharedRef(self->menu_builder.MakeWidget()); - return (PyObject *)ret; + return (PyObject*)ret; } -static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder* self, PyObject* args) { - char *label; - char *tooltip; - PyObject *py_callable; - PyObject *py_obj = nullptr; + char* label; + char* tooltip; + PyObject* py_callable; + PyObject* py_obj = nullptr; +#if ENGINE_MINOR_VERSION >= 23 + int ui_action_type = (int)EUserInterfaceActionType::Button; +#else int ui_action_type = EUserInterfaceActionType::Button; +#endif if (!PyArg_ParseTuple(args, "ssO|Oi:add_menu_entry", &label, &tooltip, &py_callable, &py_obj, &ui_action_type)) return nullptr; @@ -58,17 +62,21 @@ static PyObject *py_ue_fmenu_builder_add_menu_entry(ue_PyFMenuBuilder *self, PyO } self->menu_builder.AddMenuEntry(FText::FromString(UTF8_TO_TCHAR(label)), FText::FromString(UTF8_TO_TCHAR(tooltip)), FSlateIcon(), FUIAction(handler), NAME_None, +#if ENGINE_MINOR_VERSION >= 23 + (EUserInterfaceActionType)ui_action_type); +#else (EUserInterfaceActionType::Type)ui_action_type); +#endif Py_RETURN_NONE; } -static PyObject *py_ue_fmenu_builder_add_sub_menu(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_add_sub_menu(ue_PyFMenuBuilder* self, PyObject* args) { - char *label; - char *tooltip; - PyObject *py_callable; - PyObject *py_bool = nullptr; + char* label; + char* tooltip; + PyObject* py_callable; + PyObject* py_bool = nullptr; if (!PyArg_ParseTuple(args, "ssO|O:add_sub_menu", &label, &tooltip, &py_callable, &py_bool)) return nullptr; @@ -77,7 +85,7 @@ static PyObject *py_ue_fmenu_builder_add_sub_menu(ue_PyFMenuBuilder *self, PyObj return PyErr_Format(PyExc_Exception, "argument is not callable"); } - + TSharedRef py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewStaticSlateDelegate(py_callable); FNewMenuDelegate menu_delegate; @@ -89,9 +97,9 @@ static PyObject *py_ue_fmenu_builder_add_sub_menu(ue_PyFMenuBuilder *self, PyObj Py_RETURN_NONE; } -static PyObject *py_ue_fmenu_builder_add_menu_separator(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_add_menu_separator(ue_PyFMenuBuilder* self, PyObject* args) { - char *name = nullptr; + char* name = nullptr; if (!PyArg_ParseTuple(args, "|s:add_menu_separator", &name)) return nullptr; @@ -107,9 +115,9 @@ static PyObject *py_ue_fmenu_builder_add_menu_separator(ue_PyFMenuBuilder *self, } #if WITH_EDITOR -static PyObject *py_ue_fmenu_builder_add_asset_actions(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_add_asset_actions(ue_PyFMenuBuilder* self, PyObject* args) { - PyObject *py_assets; + PyObject* py_assets; if (!PyArg_ParseTuple(args, "O:add_asset_actions", &py_assets)) return nullptr; @@ -120,10 +128,10 @@ static PyObject *py_ue_fmenu_builder_add_asset_actions(ue_PyFMenuBuilder *self, return PyErr_Format(PyExc_Exception, "argument is not iterable"); } - TArray u_objects; - while (PyObject *item = PyIter_Next(py_assets)) + TArray u_objects; + while (PyObject * item = PyIter_Next(py_assets)) { - UObject *u_object = ue_py_check_type(item); + UObject* u_object = ue_py_check_type(item); if (u_object) { u_objects.Add(u_object); @@ -142,7 +150,7 @@ static PyObject *py_ue_fmenu_builder_add_asset_actions(ue_PyFMenuBuilder *self, } #endif -static PyObject *py_ue_fmenu_builder_add_search_widget(ue_PyFMenuBuilder *self, PyObject * args) +static PyObject* py_ue_fmenu_builder_add_search_widget(ue_PyFMenuBuilder* self, PyObject* args) { self->menu_builder.AddSearchWidget(); @@ -164,13 +172,13 @@ static PyMethodDef ue_PyFMenuBuilder_methods[] = { }; -static PyObject *ue_PyFMenuBuilder_str(ue_PyFMenuBuilder *self) +static PyObject* ue_PyFMenuBuilder_str(ue_PyFMenuBuilder* self) { return PyUnicode_FromFormat("", &self->menu_builder); } -static void ue_py_fmenu_builder_dealloc(ue_PyFMenuBuilder *self) +static void ue_py_fmenu_builder_dealloc(ue_PyFMenuBuilder* self) { #if PY_MAJOR_VERSION < 3 self->ob_type->tp_free((PyObject*)self); @@ -210,14 +218,14 @@ static PyTypeObject ue_PyFMenuBuilderType = { ue_PyFMenuBuilder_methods, /* tp_methods */ }; -static int ue_py_fmenu_builder_init(ue_PyFMenuBuilder *self, PyObject *args, PyObject *kwargs) +static int ue_py_fmenu_builder_init(ue_PyFMenuBuilder* self, PyObject* args, PyObject* kwargs) { new(&self->menu_builder) FMenuBuilder(true, nullptr); return 0; } -void ue_python_init_fmenu_builder(PyObject *ue_module) +void ue_python_init_fmenu_builder(PyObject* ue_module) { ue_PyFMenuBuilderType.tp_new = PyType_GenericNew; @@ -227,12 +235,12 @@ void ue_python_init_fmenu_builder(PyObject *ue_module) return; Py_INCREF(&ue_PyFMenuBuilderType); - PyModule_AddObject(ue_module, "FMenuBuilder", (PyObject *)&ue_PyFMenuBuilderType); + PyModule_AddObject(ue_module, "FMenuBuilder", (PyObject*)& ue_PyFMenuBuilderType); } -PyObject *py_ue_new_fmenu_builder(FMenuBuilder menu_builder) +PyObject* py_ue_new_fmenu_builder(FMenuBuilder menu_builder) { - ue_PyFMenuBuilder *ret = (ue_PyFMenuBuilder *)PyObject_New(ue_PyFMenuBuilder, &ue_PyFMenuBuilderType); + ue_PyFMenuBuilder* ret = (ue_PyFMenuBuilder*)PyObject_New(ue_PyFMenuBuilder, &ue_PyFMenuBuilderType); new(&ret->menu_builder) FMenuBuilder(menu_builder); - return (PyObject *)ret; + return (PyObject*)ret; } diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index e02525792..b725ae7f0 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -137,7 +137,7 @@ static PyModuleDef unreal_engine_module = { -1, NULL, }; -static PyObject *init_unreal_engine(void); +static PyObject* init_unreal_engine(void); @@ -148,21 +148,21 @@ void init_unreal_engine_builtin() #endif -static PyObject *py_unreal_engine_py_gc(PyObject * self, PyObject * args) +static PyObject* py_unreal_engine_py_gc(PyObject* self, PyObject* args) { int32 Garbaged = FUnrealEnginePythonHouseKeeper::Get()->RunGC(); return PyLong_FromLong(Garbaged); } -static PyObject *py_unreal_engine_exec(PyObject * self, PyObject * args) +static PyObject* py_unreal_engine_exec(PyObject* self, PyObject* args) { - char *filename = nullptr; + char* filename = nullptr; if (!PyArg_ParseTuple(args, "s:exec", &filename)) { return NULL; } - FUnrealEnginePythonModule &PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); + FUnrealEnginePythonModule& PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); Py_BEGIN_ALLOW_THREADS; PythonModule.RunFile(filename); Py_END_ALLOW_THREADS; @@ -171,14 +171,14 @@ static PyObject *py_unreal_engine_exec(PyObject * self, PyObject * args) #if PLATFORM_MAC -static PyObject *py_unreal_engine_exec_in_main_thread(PyObject * self, PyObject * args) +static PyObject* py_unreal_engine_exec_in_main_thread(PyObject* self, PyObject* args) { - char *filename = nullptr; + char* filename = nullptr; if (!PyArg_ParseTuple(args, "s:exec_in_main_thread", &filename)) { return NULL; } - FUnrealEnginePythonModule &PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); + FUnrealEnginePythonModule& PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); Py_BEGIN_ALLOW_THREADS; PythonModule.RunFileInMainThread(filename); Py_END_ALLOW_THREADS; @@ -186,7 +186,7 @@ static PyObject *py_unreal_engine_exec_in_main_thread(PyObject * self, PyObject } #endif -static PyObject *py_ue_get_py_proxy(ue_PyUObject *self, PyObject * args) +static PyObject* py_ue_get_py_proxy(ue_PyUObject* self, PyObject* args) { ue_py_check(self); @@ -194,13 +194,13 @@ static PyObject *py_ue_get_py_proxy(ue_PyUObject *self, PyObject * args) if (self->py_proxy) { Py_INCREF(self->py_proxy); - return (PyObject *)self->py_proxy; + return (PyObject*)self->py_proxy; } Py_RETURN_NONE; } -static PyObject *py_unreal_engine_shutdown(PyObject *self, PyObject * args) +static PyObject* py_unreal_engine_shutdown(PyObject* self, PyObject* args) { GIsRequestingExit = true; @@ -208,10 +208,10 @@ static PyObject *py_unreal_engine_shutdown(PyObject *self, PyObject * args) Py_RETURN_NONE; } -static PyObject *py_unreal_engine_set_brutal_finalize(PyObject *self, PyObject * args) +static PyObject* py_unreal_engine_set_brutal_finalize(PyObject* self, PyObject* args) { - PyObject *py_bool = nullptr; + PyObject* py_bool = nullptr; if (!PyArg_ParseTuple(args, "|O:set_brutal_finalize", &py_bool)) { return nullptr; @@ -219,7 +219,7 @@ static PyObject *py_unreal_engine_set_brutal_finalize(PyObject *self, PyObject * bool bBrutalFinalize = !py_bool || PyObject_IsTrue(py_bool); - FUnrealEnginePythonModule &PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); + FUnrealEnginePythonModule& PythonModule = FModuleManager::GetModuleChecked("UnrealEnginePython"); PythonModule.BrutalFinalize = bBrutalFinalize; Py_RETURN_NONE; } @@ -757,7 +757,7 @@ static PyMethodDef ue_PyUObject_methods[] = { { "vlog_cylinder", (PyCFunction)py_ue_vlog_cylinder, METH_VARARGS, "" }, // StaticMesh - { "get_static_mesh_bounds", (PyCFunction)py_ue_static_mesh_get_bounds, METH_VARARGS, "" }, + { "get_static_mesh_bounds", (PyCFunction)py_ue_static_mesh_get_bounds, METH_VARARGS, "" }, #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, "" }, @@ -1181,7 +1181,7 @@ static PyMethodDef ue_PyUObject_methods[] = { // destructor -static void ue_pyobject_dealloc(ue_PyUObject *self) +static void ue_pyobject_dealloc(ue_PyUObject* self) { #if defined(UEPY_MEMORY_DEBUG) UE_LOG(LogPython, Warning, TEXT("Destroying ue_PyUObject %p mapped to UObject %p"), self, self->ue_object); @@ -1198,38 +1198,38 @@ static void ue_pyobject_dealloc(ue_PyUObject *self) Py_XDECREF(self->py_dict); - Py_TYPE(self)->tp_free((PyObject *)self); + Py_TYPE(self)->tp_free((PyObject*)self); } -static PyObject *ue_PyUObject_getattro(ue_PyUObject *self, PyObject *attr_name) +static PyObject* ue_PyUObject_getattro(ue_PyUObject* self, PyObject* attr_name) { ue_py_check(self); - PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, attr_name); + PyObject* ret = PyObject_GenericGetAttr((PyObject*)self, attr_name); if (!ret) { if (PyUnicodeOrString_Check(attr_name)) { - const char *attr = UEPyUnicode_AsUTF8(attr_name); + const char* attr = UEPyUnicode_AsUTF8(attr_name); // first check for property - UStruct *u_struct = nullptr; + UStruct* u_struct = nullptr; if (self->ue_object->IsA()) { - u_struct = (UStruct *)self->ue_object; + u_struct = (UStruct*)self->ue_object; } else { - u_struct = (UStruct *)self->ue_object->GetClass(); + u_struct = (UStruct*)self->ue_object->GetClass(); } - UProperty *u_property = u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(attr))); + UProperty* u_property = u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(attr))); if (u_property) { // swallow previous exception PyErr_Clear(); - return ue_py_convert_property(u_property, (uint8 *)self->ue_object, 0); + return ue_py_convert_property(u_property, (uint8*)self->ue_object, 0); } - UFunction *function = self->ue_object->FindFunction(FName(UTF8_TO_TCHAR(attr))); + UFunction* function = self->ue_object->FindFunction(FName(UTF8_TO_TCHAR(attr))); // retry wth K2_ prefix if (!function) { @@ -1242,8 +1242,8 @@ static PyObject *ue_PyUObject_getattro(ue_PyUObject *self, PyObject *attr_name) { if (self->ue_object->IsA()) { - UClass *u_class = (UClass *)self->ue_object; - UObject *cdo = u_class->GetDefaultObject(); + UClass* u_class = (UClass*)self->ue_object; + UObject* cdo = u_class->GetDefaultObject(); if (cdo) { function = cdo->FindFunction(FName(UTF8_TO_TCHAR(attr))); @@ -1263,7 +1263,7 @@ static PyObject *ue_PyUObject_getattro(ue_PyUObject *self, PyObject *attr_name) #if ENGINE_MINOR_VERSION >= 15 if (self->ue_object->IsA()) { - UUserDefinedEnum *u_enum = (UUserDefinedEnum *)self->ue_object; + UUserDefinedEnum* u_enum = (UUserDefinedEnum*)self->ue_object; PyErr_Clear(); FString attr_as_string = FString(UTF8_TO_TCHAR(attr)); for (auto item : u_enum->DisplayNameMap) @@ -1282,7 +1282,7 @@ static PyObject *ue_PyUObject_getattro(ue_PyUObject *self, PyObject *attr_name) #endif if (self->ue_object->IsA()) { - UEnum *u_enum = (UEnum *)self->ue_object; + UEnum* u_enum = (UEnum*)self->ue_object; PyErr_Clear(); #if ENGINE_MINOR_VERSION > 15 int32 value = u_enum->GetIndexByName(FName(UTF8_TO_TCHAR(attr))); @@ -1309,25 +1309,25 @@ static PyObject *ue_PyUObject_getattro(ue_PyUObject *self, PyObject *attr_name) return ret; } -static int ue_PyUObject_setattro(ue_PyUObject *self, PyObject *attr_name, PyObject *value) +static int ue_PyUObject_setattro(ue_PyUObject* self, PyObject* attr_name, PyObject* value) { ue_py_check_int(self); // first of all check for UProperty if (PyUnicodeOrString_Check(attr_name)) { - const char *attr = UEPyUnicode_AsUTF8(attr_name); + const char* attr = UEPyUnicode_AsUTF8(attr_name); // first check for property - UStruct *u_struct = nullptr; + UStruct* u_struct = nullptr; if (self->ue_object->IsA()) { - u_struct = (UStruct *)self->ue_object; + u_struct = (UStruct*)self->ue_object; } else { - u_struct = (UStruct *)self->ue_object->GetClass(); + u_struct = (UStruct*)self->ue_object->GetClass(); } - UProperty *u_property = u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(attr))); + UProperty* u_property = u_struct->FindPropertyByName(FName(UTF8_TO_TCHAR(attr))); if (u_property) { #if WITH_EDITOR @@ -1341,9 +1341,9 @@ static int ue_PyUObject_setattro(ue_PyUObject *self, PyObject *attr_name, PyObje if (self->ue_object->HasAnyFlags(RF_ArchetypeObject | RF_ClassDefaultObject)) { - TArray Instances; + TArray Instances; self->ue_object->GetArchetypeInstances(Instances); - for (UObject *Instance : Instances) + for (UObject* Instance : Instances) { Instance->PreEditChange(u_property); if (ue_py_convert_pyobject(value, u_property, (uint8*)Instance, 0)) @@ -1372,10 +1372,10 @@ static int ue_PyUObject_setattro(ue_PyUObject *self, PyObject *attr_name, PyObje return -1; } } - return PyObject_GenericSetAttr((PyObject *)self, attr_name, value); + return PyObject_GenericSetAttr((PyObject*)self, attr_name, value); } -static PyObject *ue_PyUObject_str(ue_PyUObject *self) +static PyObject* ue_PyUObject_str(ue_PyUObject* self) { ue_py_check(self); @@ -1388,13 +1388,13 @@ static PyObject *ue_PyUObject_str(ue_PyUObject *self) #endif } -static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject *kw) +static PyObject* ue_PyUObject_call(ue_PyUObject* self, PyObject* args, PyObject* kw) { ue_py_check(self); // if it is a class, create a new object if (self->ue_object->IsA()) { - UClass *u_class = (UClass *)self->ue_object; + UClass* u_class = (UClass*)self->ue_object; if (u_class->HasAnyClassFlags(CLASS_Abstract)) { return PyErr_Format(PyExc_Exception, "abstract classes cannot be instantiated"); @@ -1403,16 +1403,16 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject { return PyErr_Format(PyExc_Exception, "you cannot use __call__ on actors, they have to be spawned"); } - PyObject *py_name = nullptr; - PyObject *py_outer = Py_None; + PyObject* py_name = nullptr; + PyObject* py_outer = Py_None; if (!PyArg_ParseTuple(args, "|OO:new_object", &py_name, &py_outer)) { return NULL; } int num_args = py_name ? 3 : 1; - PyObject *py_args = PyTuple_New(num_args); - Py_INCREF((PyObject *)self); - PyTuple_SetItem(py_args, 0, (PyObject *)self); + PyObject* py_args = PyTuple_New(num_args); + Py_INCREF((PyObject*)self); + PyTuple_SetItem(py_args, 0, (PyObject*)self); if (py_name) { Py_INCREF(py_outer); @@ -1420,7 +1420,7 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject Py_INCREF(py_name); PyTuple_SetItem(py_args, 2, py_name); } - ue_PyUObject *ret = (ue_PyUObject *)py_unreal_engine_new_object(nullptr, py_args); + ue_PyUObject* ret = (ue_PyUObject*)py_unreal_engine_new_object(nullptr, py_args); Py_DECREF(py_args); if (!ret) { @@ -1430,23 +1430,23 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject // UObject crated explicitely from python, will be managed by python... FUnrealEnginePythonHouseKeeper::Get()->TrackUObject(ret->ue_object); - return (PyObject *)ret; + return (PyObject*)ret; } // if it is a uscriptstruct, instantiate a new struct if (self->ue_object->IsA()) { - UScriptStruct *u_script_struct = (UScriptStruct *)self->ue_object; - uint8 *data = (uint8*)FMemory::Malloc(u_script_struct->GetStructureSize()); + UScriptStruct* u_script_struct = (UScriptStruct*)self->ue_object; + uint8* data = (uint8*)FMemory::Malloc(u_script_struct->GetStructureSize()); u_script_struct->InitializeStruct(data); #if WITH_EDITOR u_script_struct->InitializeDefaultValue(data); #endif if (kw) { - PyObject *struct_keys = PyObject_GetIter(kw); + PyObject* struct_keys = PyObject_GetIter(kw); for (;;) { - PyObject *key = PyIter_Next(struct_keys); + PyObject* key = PyIter_Next(struct_keys); if (!key) { if (PyErr_Occurred()) @@ -1458,9 +1458,9 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject } if (!PyUnicodeOrString_Check(key)) continue; - const char *struct_key = UEPyUnicode_AsUTF8(key); + const char* struct_key = UEPyUnicode_AsUTF8(key); - PyObject *value = PyDict_GetItem(kw, key); + PyObject* value = PyDict_GetItem(kw, key); if (!value) { if (PyErr_Occurred()) @@ -1471,7 +1471,7 @@ static PyObject *ue_PyUObject_call(ue_PyUObject *self, PyObject *args, PyObject break; } - UProperty *u_property = ue_struct_get_field_from_name(u_script_struct, (char *)struct_key); + UProperty* u_property = ue_struct_get_field_from_name(u_script_struct, (char*)struct_key); if (u_property) { if (!ue_py_convert_pyobject(value, u_property, data, 0)) @@ -1529,12 +1529,12 @@ static PyTypeObject ue_PyUObjectType = { -UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) +UClass* unreal_engine_new_uclass(char* name, UClass* outer_parent) { bool is_overwriting = false; - UObject *outer = GetTransientPackage(); - UClass *parent = UObject::StaticClass(); + UObject* outer = GetTransientPackage(); + UClass* parent = UObject::StaticClass(); if (outer_parent) { @@ -1542,7 +1542,7 @@ UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) outer = parent->GetOuter(); } - UClass *new_object = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); + UClass* new_object = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); if (!new_object) { new_object = NewObject(outer, UTF8_TO_TCHAR(name), RF_Public | RF_Transient | RF_MarkAsNative); @@ -1557,13 +1557,13 @@ UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) if (is_overwriting && new_object->Children) { - UField *u_field = new_object->Children; + UField* u_field = new_object->Children; while (u_field) { if (u_field->IsA()) { UE_LOG(LogPython, Warning, TEXT("removing function %s"), *u_field->GetName()); - new_object->RemoveFunctionFromFunctionMap((UFunction *)u_field); + new_object->RemoveFunctionFromFunctionMap((UFunction*)u_field); FLinkerLoad::InvalidateExport(u_field); } u_field = u_field->Next; @@ -1633,14 +1633,14 @@ UClass *unreal_engine_new_uclass(char *name, UClass *outer_parent) -int unreal_engine_py_init(ue_PyUObject *, PyObject *, PyObject *); +int unreal_engine_py_init(ue_PyUObject*, PyObject*, PyObject*); void unreal_engine_init_py_module() { #if PY_MAJOR_VERSION >= 3 - PyObject *new_unreal_engine_module = PyImport_AddModule("unreal_engine"); + PyObject * new_unreal_engine_module = PyImport_AddModule("unreal_engine"); #else - PyObject *new_unreal_engine_module = Py_InitModule3("unreal_engine", NULL, unreal_engine_py_doc); + PyObject* new_unreal_engine_module = Py_InitModule3("unreal_engine", NULL, unreal_engine_py_doc); #endif ue_PyUObjectType.tp_new = PyType_GenericNew; ue_PyUObjectType.tp_init = (initproc)unreal_engine_py_init; @@ -1650,14 +1650,14 @@ void unreal_engine_init_py_module() return; Py_INCREF(&ue_PyUObjectType); - PyModule_AddObject(new_unreal_engine_module, "UObject", (PyObject *)&ue_PyUObjectType); + PyModule_AddObject(new_unreal_engine_module, "UObject", (PyObject*)& ue_PyUObjectType); - PyObject *unreal_engine_dict = PyModule_GetDict(new_unreal_engine_module); + PyObject* unreal_engine_dict = PyModule_GetDict(new_unreal_engine_module); - PyMethodDef *unreal_engine_function; + PyMethodDef* unreal_engine_function; for (unreal_engine_function = unreal_engine_methods; unreal_engine_function->ml_name != NULL; unreal_engine_function++) { - PyObject *func = PyCFunction_New(unreal_engine_function, NULL); + PyObject* func = PyCFunction_New(unreal_engine_function, NULL); PyDict_SetItemString(unreal_engine_dict, unreal_engine_function->ml_name, func); Py_DECREF(func); } @@ -1745,9 +1745,9 @@ void unreal_engine_init_py_module() ue_python_init_ivoice_capture(new_unreal_engine_module); - ue_py_register_magic_module((char *)"unreal_engine.classes", py_ue_new_uclassesimporter); - ue_py_register_magic_module((char *)"unreal_engine.enums", py_ue_new_enumsimporter); - ue_py_register_magic_module((char *)"unreal_engine.structs", py_ue_new_ustructsimporter); + ue_py_register_magic_module((char*)"unreal_engine.classes", py_ue_new_uclassesimporter); + ue_py_register_magic_module((char*)"unreal_engine.enums", py_ue_new_enumsimporter); + ue_py_register_magic_module((char*)"unreal_engine.structs", py_ue_new_ustructsimporter); PyDict_SetItemString(unreal_engine_dict, "ENGINE_MAJOR_VERSION", PyLong_FromLong(ENGINE_MAJOR_VERSION)); @@ -1851,18 +1851,18 @@ void unreal_engine_init_py_module() // utility functions -ue_PyUObject *ue_get_python_uobject(UObject *ue_obj) +ue_PyUObject* ue_get_python_uobject(UObject* ue_obj) { if (!ue_obj) return nullptr; - ue_PyUObject *ret = FUnrealEnginePythonHouseKeeper::Get()->GetPyUObject(ue_obj); + ue_PyUObject* ret = FUnrealEnginePythonHouseKeeper::Get()->GetPyUObject(ue_obj); if (!ret) { if (!ue_obj->IsValidLowLevel() || ue_obj->IsPendingKillOrUnreachable()) return nullptr; - ue_PyUObject *ue_py_object = (ue_PyUObject *)PyObject_New(ue_PyUObject, &ue_PyUObjectType); + ue_PyUObject* ue_py_object = (ue_PyUObject*)PyObject_New(ue_PyUObject, &ue_PyUObjectType); if (!ue_py_object) { return nullptr; @@ -1884,9 +1884,9 @@ ue_PyUObject *ue_get_python_uobject(UObject *ue_obj) } -ue_PyUObject *ue_get_python_uobject_inc(UObject *ue_obj) +ue_PyUObject* ue_get_python_uobject_inc(UObject* ue_obj) { - ue_PyUObject *ret = ue_get_python_uobject(ue_obj); + ue_PyUObject* ret = ue_get_python_uobject(ue_obj); if (ret) { Py_INCREF(ret); @@ -1896,9 +1896,9 @@ ue_PyUObject *ue_get_python_uobject_inc(UObject *ue_obj) void unreal_engine_py_log_error() { - PyObject *type = NULL; - PyObject *value = NULL; - PyObject *traceback = NULL; + PyObject* type = NULL; + PyObject* value = NULL; + PyObject* traceback = NULL; PyErr_Fetch(&type, &value, &traceback); PyErr_NormalizeException(&type, &value, &traceback); @@ -1909,9 +1909,9 @@ void unreal_engine_py_log_error() return; } - char *msg = NULL; + char* msg = NULL; #if PY_MAJOR_VERSION >= 3 - PyObject *zero = PyUnicode_AsUTF8String(PyObject_Str(value)); + PyObject * zero = PyUnicode_AsUTF8String(PyObject_Str(value)); if (zero) { msg = PyBytes_AsString(zero); @@ -1934,19 +1934,19 @@ void unreal_engine_py_log_error() return; } - PyObject *traceback_module = PyImport_ImportModule("traceback"); + PyObject* traceback_module = PyImport_ImportModule("traceback"); if (!traceback_module) { PyErr_Clear(); return; } - PyObject *traceback_dict = PyModule_GetDict(traceback_module); - PyObject *format_exception = PyDict_GetItemString(traceback_dict, "format_exception"); + PyObject* traceback_dict = PyModule_GetDict(traceback_module); + PyObject* format_exception = PyDict_GetItemString(traceback_dict, "format_exception"); if (format_exception) { - PyObject *ret = PyObject_CallFunctionObjArgs(format_exception, type, value, traceback, NULL); + PyObject* ret = PyObject_CallFunctionObjArgs(format_exception, type, value, traceback, NULL); if (!ret) { PyErr_Clear(); @@ -1956,7 +1956,7 @@ void unreal_engine_py_log_error() { for (int i = 0; i < PyList_Size(ret); i++) { - PyObject *item = PyList_GetItem(ret, i); + PyObject* item = PyList_GetItem(ret, i); if (item) { UE_LOG(LogPython, Error, TEXT("%s"), UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(PyObject_Str(item)))); @@ -1973,23 +1973,23 @@ void unreal_engine_py_log_error() } // retrieve a UWorld from a generic UObject (if possible) -UWorld *ue_get_uworld(ue_PyUObject *py_obj) +UWorld* ue_get_uworld(ue_PyUObject* py_obj) { if (py_obj->ue_object->IsA()) { - return (UWorld *)py_obj->ue_object; + return (UWorld*)py_obj->ue_object; } if (py_obj->ue_object->IsA()) { - AActor *actor = (AActor *)py_obj->ue_object; + AActor* actor = (AActor*)py_obj->ue_object; return actor->GetWorld(); } if (py_obj->ue_object->IsA()) { - UActorComponent *component = (UActorComponent *)py_obj->ue_object; + UActorComponent* component = (UActorComponent*)py_obj->ue_object; return component->GetWorld(); } @@ -1997,23 +1997,23 @@ UWorld *ue_get_uworld(ue_PyUObject *py_obj) } // retrieve actor from component (if possible) -AActor *ue_get_actor(ue_PyUObject *py_obj) +AActor* ue_get_actor(ue_PyUObject* py_obj) { if (py_obj->ue_object->IsA()) { - return (AActor *)py_obj->ue_object; + return (AActor*)py_obj->ue_object; } if (py_obj->ue_object->IsA()) { - UActorComponent *tmp_component = (UActorComponent *)py_obj->ue_object; + UActorComponent* tmp_component = (UActorComponent*)py_obj->ue_object; return tmp_component->GetOwner(); } return nullptr; } // convert a property to a python object -PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) +PyObject* ue_py_convert_property(UProperty* prop, uint8* buffer, int32 index) { if (auto casted_prop = Cast(prop)) { @@ -2064,7 +2064,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) #if ENGINE_MINOR_VERSION >= 15 if (auto casted_prop = Cast(prop)) { - void *prop_addr = casted_prop->ContainerPtrToValuePtr(buffer, index); + void* prop_addr = casted_prop->ContainerPtrToValuePtr(buffer, index); uint64 enum_index = casted_prop->GetUnderlyingProperty()->GetUnsignedIntPropertyValue(prop_addr); return PyLong_FromUnsignedLong(enum_index); } @@ -2156,7 +2156,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) if (auto casted_prop = Cast(prop)) { auto value = casted_prop->GetPropertyValue_InContainer(buffer, index); - UObject *strong_obj = value.Get(); + UObject* strong_obj = value.Get(); if (strong_obj) { Py_RETURN_UOBJECT(strong_obj); @@ -2179,20 +2179,20 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) { FScriptArrayHelper_InContainer array_helper(casted_prop, buffer, index); - UProperty *array_prop = casted_prop->Inner; + UProperty* array_prop = casted_prop->Inner; // check for TArray, so we can use bytearray optimization if (auto uint8_tarray = Cast(array_prop)) { - uint8 *buf = array_helper.GetRawPtr(); - return PyByteArray_FromStringAndSize((char *)buf, array_helper.Num()); + uint8* buf = array_helper.GetRawPtr(); + return PyByteArray_FromStringAndSize((char*)buf, array_helper.Num()); } - PyObject *py_list = PyList_New(0); + PyObject* py_list = PyList_New(0); for (int i = 0; i < array_helper.Num(); i++) { - PyObject *item = ue_py_convert_property(array_prop, array_helper.GetRawPtr(i), 0); + PyObject* item = ue_py_convert_property(array_prop, array_helper.GetRawPtr(i), 0); if (!item) { Py_DECREF(py_list); @@ -2210,23 +2210,23 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) { FScriptMapHelper_InContainer map_helper(casted_prop, buffer, index); - PyObject *py_dict = PyDict_New(); + PyObject* py_dict = PyDict_New(); for (int32 i = 0; i < map_helper.Num(); i++) { if (map_helper.IsValidIndex(i)) { - uint8 *ptr = map_helper.GetPairPtr(i); + uint8* ptr = map_helper.GetPairPtr(i); - PyObject *py_key = ue_py_convert_property(map_helper.KeyProp, ptr, 0); + PyObject* py_key = ue_py_convert_property(map_helper.KeyProp, ptr, 0); if (!py_key) { Py_DECREF(py_dict); return NULL; } - PyObject *py_value = ue_py_convert_property(map_helper.ValueProp, ptr, 0); + PyObject* py_value = ue_py_convert_property(map_helper.ValueProp, ptr, 0); if (!py_value) { Py_DECREF(py_dict); @@ -2247,7 +2247,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index) } // convert a python object to a property -bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, int32 index) +bool ue_py_convert_pyobject(PyObject* py_obj, UProperty* prop, uint8* buffer, int32 index) { if (PyBool_Check(py_obj)) @@ -2270,42 +2270,42 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); + PyObject* py_long = PyNumber_Long(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyLong_AsLong(py_long), index); Py_DECREF(py_long); return true; } if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); + PyObject* py_long = PyNumber_Long(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyLong_AsUnsignedLong(py_long), index); Py_DECREF(py_long); return true; } if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); + PyObject* py_long = PyNumber_Long(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyLong_AsLongLong(py_long), index); Py_DECREF(py_long); return true; } if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); + PyObject* py_long = PyNumber_Long(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyLong_AsUnsignedLongLong(py_long), index); Py_DECREF(py_long); return true; } if (auto casted_prop = Cast(prop)) { - PyObject *py_float = PyNumber_Float(py_obj); + PyObject* py_float = PyNumber_Float(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyFloat_AsDouble(py_float), index); Py_DECREF(py_float); return true; } if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); + PyObject* py_long = PyNumber_Long(py_obj); casted_prop->SetPropertyValue_InContainer(buffer, PyLong_AsUnsignedLong(py_long), index); Py_DECREF(py_long); return true; @@ -2313,8 +2313,8 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in #if ENGINE_MINOR_VERSION >= 15 if (auto casted_prop = Cast(prop)) { - PyObject *py_long = PyNumber_Long(py_obj); - void *prop_addr = casted_prop->ContainerPtrToValuePtr(buffer, index); + PyObject* py_long = PyNumber_Long(py_obj); + void* prop_addr = casted_prop->ContainerPtrToValuePtr(buffer, index); casted_prop->GetUnderlyingProperty()->SetIntPropertyValue(prop_addr, (uint64)PyLong_AsUnsignedLong(py_long)); Py_DECREF(py_long); return true; @@ -2355,7 +2355,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { Py_ssize_t pybytes_len = PyBytes_Size(py_obj); - uint8 *buf = (uint8 *)PyBytes_AsString(py_obj); + uint8* buf = (uint8*)PyBytes_AsString(py_obj); // fix array helper size @@ -2387,7 +2387,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { Py_ssize_t pybytes_len = PyByteArray_Size(py_obj); - uint8 *buf = (uint8 *)PyByteArray_AsString(py_obj); + uint8* buf = (uint8*)PyByteArray_AsString(py_obj); // fix array helper size @@ -2416,7 +2416,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { FScriptArrayHelper_InContainer helper(casted_prop, buffer, index); - UProperty *array_prop = casted_prop->Inner; + UProperty* array_prop = casted_prop->Inner; Py_ssize_t pylist_len = PyList_Size(py_obj); // fix array helper size @@ -2431,7 +2431,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in for (int i = 0; i < (int)pylist_len; i++) { - PyObject *py_item = PyList_GetItem(py_obj, i); + PyObject* py_item = PyList_GetItem(py_obj, i); if (!ue_py_convert_pyobject(py_item, array_prop, helper.GetRawPtr(i), 0)) { return false; @@ -2449,7 +2449,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { FScriptArrayHelper_InContainer helper(casted_prop, buffer, index); - UProperty *array_prop = casted_prop->Inner; + UProperty* array_prop = casted_prop->Inner; Py_ssize_t pytuple_len = PyTuple_Size(py_obj); // fix array helper size @@ -2464,7 +2464,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in for (int i = 0; i < (int)pytuple_len; i++) { - PyObject *py_item = PyTuple_GetItem(py_obj, i); + PyObject* py_item = PyTuple_GetItem(py_obj, i); if (!ue_py_convert_pyobject(py_item, array_prop, helper.GetRawPtr(i), 0)) { return false; @@ -2483,8 +2483,8 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { FScriptMapHelper_InContainer map_helper(casted_prop, buffer, index); - PyObject *py_key = nullptr; - PyObject *py_value = nullptr; + PyObject* py_key = nullptr; + PyObject* py_value = nullptr; Py_ssize_t pos = 0; map_helper.EmptyValues(); @@ -2492,7 +2492,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in { int32 hindex = map_helper.AddDefaultValue_Invalid_NeedsRehash(); - uint8 *ptr = map_helper.GetPairPtr(hindex); + uint8* ptr = map_helper.GetPairPtr(hindex); if (!ue_py_convert_pyobject(py_key, casted_prop->KeyProp, ptr, 0)) { @@ -2515,7 +2515,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in // structs - if (ue_PyFVector *py_vec = py_ue_is_fvector(py_obj)) + if (ue_PyFVector * py_vec = py_ue_is_fvector(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2528,7 +2528,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFVector2D *py_vec = py_ue_is_fvector2d(py_obj)) + if (ue_PyFVector2D * py_vec = py_ue_is_fvector2d(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2541,7 +2541,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFRotator *py_rot = py_ue_is_frotator(py_obj)) + if (ue_PyFRotator * py_rot = py_ue_is_frotator(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2554,7 +2554,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFTransform *py_transform = py_ue_is_ftransform(py_obj)) + if (ue_PyFTransform * py_transform = py_ue_is_ftransform(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2567,7 +2567,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFColor *py_color = py_ue_is_fcolor(py_obj)) + if (ue_PyFColor * py_color = py_ue_is_fcolor(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2581,7 +2581,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFLinearColor *py_color = py_ue_is_flinearcolor(py_obj)) + if (ue_PyFLinearColor * py_color = py_ue_is_flinearcolor(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2594,7 +2594,7 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (ue_PyFHitResult *py_hit = py_ue_is_fhitresult(py_obj)) + if (ue_PyFHitResult * py_hit = py_ue_is_fhitresult(py_obj)) { if (auto casted_prop = Cast(prop)) { @@ -2610,12 +2610,12 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in // generic structs if (py_ue_is_uscriptstruct(py_obj)) { - ue_PyUScriptStruct *py_u_struct = (ue_PyUScriptStruct *)py_obj; + ue_PyUScriptStruct* py_u_struct = (ue_PyUScriptStruct*)py_obj; if (auto casted_prop = Cast(prop)) { if (casted_prop->Struct == py_u_struct->u_struct) { - uint8 *dest = casted_prop->ContainerPtrToValuePtr(buffer, index); + uint8* dest = casted_prop->ContainerPtrToValuePtr(buffer, index); py_u_struct->u_struct->InitializeStruct(dest); py_u_struct->u_struct->CopyScriptStruct(dest, py_u_struct->u_struct_ptr); return true; @@ -2624,9 +2624,9 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in return false; } - if (PyObject_IsInstance(py_obj, (PyObject *)&ue_PyUObjectType)) + if (PyObject_IsInstance(py_obj, (PyObject*)& ue_PyUObjectType)) { - ue_PyUObject *ue_obj = (ue_PyUObject *)py_obj; + ue_PyUObject* ue_obj = (ue_PyUObject*)py_obj; if (ue_obj->ue_object->IsA()) { if (auto casted_prop = Cast(prop)) @@ -2739,24 +2739,24 @@ bool ue_py_convert_pyobject(PyObject *py_obj, UProperty *prop, uint8 *buffer, in // check if a python object is a wrapper to a UObject -ue_PyUObject *ue_is_pyuobject(PyObject *obj) +ue_PyUObject* ue_is_pyuobject(PyObject* obj) { - if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyUObjectType)) + if (!PyObject_IsInstance(obj, (PyObject*)& ue_PyUObjectType)) return nullptr; - return (ue_PyUObject *)obj; + return (ue_PyUObject*)obj; } -void ue_bind_events_for_py_class_by_attribute(UObject *u_obj, PyObject *py_class) +void ue_bind_events_for_py_class_by_attribute(UObject* u_obj, PyObject* py_class) { // attempt to register events - PyObject *attrs = PyObject_Dir(py_class); + PyObject* attrs = PyObject_Dir(py_class); if (!attrs) return; - AActor *actor = Cast(u_obj); + AActor* actor = Cast(u_obj); if (!actor) { - UActorComponent *component = Cast(u_obj); + UActorComponent* component = Cast(u_obj); if (!component) return; actor = component->GetOwner(); @@ -2765,14 +2765,14 @@ void ue_bind_events_for_py_class_by_attribute(UObject *u_obj, PyObject *py_class Py_ssize_t len = PyList_Size(attrs); for (Py_ssize_t i = 0; i < len; i++) { - PyObject *py_attr_name = PyList_GetItem(attrs, i); + PyObject* py_attr_name = PyList_GetItem(attrs, i); if (!py_attr_name || !PyUnicodeOrString_Check(py_attr_name)) continue; - PyObject *item = PyObject_GetAttrString(py_class, UEPyUnicode_AsUTF8(py_attr_name)); + PyObject* item = PyObject_GetAttrString(py_class, UEPyUnicode_AsUTF8(py_attr_name)); if (item && PyCallable_Check(item)) { // check for ue_event signature - PyObject *event_signature = PyObject_GetAttrString(item, (char*)"ue_event"); + PyObject* event_signature = PyObject_GetAttrString(item, (char*)"ue_event"); if (event_signature) { if (PyUnicodeOrString_Check(event_signature)) @@ -2797,7 +2797,7 @@ void ue_bind_events_for_py_class_by_attribute(UObject *u_obj, PyObject *py_class else { bool found = false; - for (UActorComponent *component : actor->GetComponents()) + for (UActorComponent* component : actor->GetComponents()) { if (component->GetFName() == FName(*parts[0])) { @@ -2834,23 +2834,23 @@ void ue_bind_events_for_py_class_by_attribute(UObject *u_obj, PyObject *py_class } // automatically bind events based on class methods names -void ue_autobind_events_for_pyclass(ue_PyUObject *u_obj, PyObject *py_class) +void ue_autobind_events_for_pyclass(ue_PyUObject* u_obj, PyObject* py_class) { - PyObject *attrs = PyObject_Dir(py_class); + PyObject* attrs = PyObject_Dir(py_class); if (!attrs) return; Py_ssize_t len = PyList_Size(attrs); for (Py_ssize_t i = 0; i < len; i++) { - PyObject *py_attr_name = PyList_GetItem(attrs, i); + PyObject* py_attr_name = PyList_GetItem(attrs, i); if (!py_attr_name || !PyUnicodeOrString_Check(py_attr_name)) continue; FString attr_name = UTF8_TO_TCHAR(UEPyUnicode_AsUTF8(py_attr_name)); if (!attr_name.StartsWith("on_", ESearchCase::CaseSensitive)) continue; // check if the attr is a callable - PyObject *item = PyObject_GetAttrString(py_class, TCHAR_TO_UTF8(*attr_name)); + PyObject* item = PyObject_GetAttrString(py_class, TCHAR_TO_UTF8(*attr_name)); if (item && PyCallable_Check(item)) { TArray parts; @@ -2874,24 +2874,24 @@ void ue_autobind_events_for_pyclass(ue_PyUObject *u_obj, PyObject *py_class) Py_DECREF(attrs); } -static void py_ue_destroy_params(UFunction *u_function, uint8 *buffer) +static void py_ue_destroy_params(UFunction* u_function, uint8* buffer) { // destroy params TFieldIterator DArgs(u_function); for (; DArgs && (DArgs->PropertyFlags & CPF_Parm); ++DArgs) { - UProperty *prop = *DArgs; + UProperty* prop = *DArgs; prop->DestroyValue_InContainer(buffer); } } -PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject *args, int argn, PyObject *kwargs) +PyObject* py_ue_ufunction_call(UFunction* u_function, UObject* u_obj, PyObject* args, int argn, PyObject* kwargs) { // check for __super call if (kwargs) { - PyObject *is_super_call = PyDict_GetItemString(kwargs, (char *)"__super"); + PyObject* is_super_call = PyDict_GetItemString(kwargs, (char*)"__super"); if (is_super_call) { if (!u_function->GetSuperFunction()) @@ -2903,12 +2903,12 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * } //NOTE: u_function->PropertiesSize maps to local variable uproperties + ufunction paramaters uproperties - uint8 *buffer = (uint8 *)FMemory_Alloca(u_function->ParmsSize); + uint8* buffer = (uint8*)FMemory_Alloca(u_function->ParmsSize); FMemory::Memzero(buffer, u_function->ParmsSize); // initialize args for (TFieldIterator IArgs(u_function); IArgs && IArgs->HasAnyPropertyFlags(CPF_Parm); ++IArgs) { - UProperty *prop = *IArgs; + UProperty* prop = *IArgs; if (!prop->HasAnyPropertyFlags(CPF_ZeroConstructor)) { prop->InitializeValue_InContainer(buffer); @@ -2944,10 +2944,10 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * TFieldIterator PArgs(u_function); for (; PArgs && ((PArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++PArgs) { - UProperty *prop = *PArgs; + UProperty* prop = *PArgs; if (argn < tuple_len) { - PyObject *py_arg = PyTuple_GetItem(args, argn); + PyObject* py_arg = PyTuple_GetItem(args, argn); if (!py_arg) { py_ue_destroy_params(u_function, buffer); @@ -2961,8 +2961,8 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * } else if (kwargs) { - char *prop_name = TCHAR_TO_UTF8(*prop->GetName()); - PyObject *dict_value = PyDict_GetItemString(kwargs, prop_name); + char* prop_name = TCHAR_TO_UTF8(*prop->GetName()); + PyObject* dict_value = PyDict_GetItemString(kwargs, prop_name); if (dict_value) { if (!ue_py_convert_pyobject(dict_value, prop, buffer, 0)) @@ -2986,13 +2986,13 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * u_obj->ProcessEvent(u_function, buffer); Py_END_ALLOW_THREADS; - PyObject *ret = nullptr; + PyObject* ret = nullptr; int has_ret_param = 0; TFieldIterator Props(u_function); for (; Props; ++Props) { - UProperty *prop = *Props; + UProperty* prop = *Props; if (prop->GetPropertyFlags() & CPF_ReturnParm) { ret = ue_py_convert_property(prop, buffer, 0); @@ -3009,7 +3009,7 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * if (has_out_params > 0) { - PyObject *multi_ret = PyTuple_New(has_out_params + has_ret_param); + PyObject* multi_ret = PyTuple_New(has_out_params + has_ret_param); if (ret) { PyTuple_SetItem(multi_ret, 0, ret); @@ -3017,13 +3017,13 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * TFieldIterator OProps(u_function); for (; OProps; ++OProps) { - UProperty *prop = *OProps; + UProperty* prop = *OProps; if (prop->HasAnyPropertyFlags(CPF_OutParm) && (prop->IsA() || prop->HasAnyPropertyFlags(CPF_ConstParm) == false)) { // skip return param as it must be always the first if (prop->GetPropertyFlags() & CPF_ReturnParm) continue; - PyObject *py_out = ue_py_convert_property(prop, buffer, 0); + PyObject* py_out = ue_py_convert_property(prop, buffer, 0); if (!py_out) { Py_DECREF(multi_ret); @@ -3049,9 +3049,9 @@ PyObject *py_ue_ufunction_call(UFunction *u_function, UObject *u_obj, PyObject * Py_RETURN_NONE; } -PyObject *ue_unbind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) +PyObject* ue_unbind_pyevent(ue_PyUObject* u_obj, FString event_name, PyObject* py_callable, bool fail_on_wrong_property) { - UProperty *u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name)); + UProperty* u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name)); if (!u_property) { if (fail_on_wrong_property) @@ -3061,20 +3061,29 @@ PyObject *ue_unbind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *p if (auto casted_prop = Cast(u_property)) { - UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->FindDelegate(u_obj->ue_object, py_callable); - if (py_delegate != nullptr) - { - FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object); - multiscript_delegate.Remove(py_delegate, FName("PyFakeCallable")); + UPythonDelegate* py_delegate = FUnrealEnginePythonHouseKeeper::Get()->FindDelegate(u_obj->ue_object, py_callable); + if (py_delegate != nullptr) + { +#if ENGINE_MINOR_VERSION < 23 + FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object); +#else + FMulticastScriptDelegate multiscript_delegate = *casted_prop->GetMulticastDelegate(u_obj->ue_object); +#endif - // re-assign multicast delegate - casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); - } + multiscript_delegate.Remove(py_delegate, FName("PyFakeCallable")); + + // re-assign multicast delegate +#if ENGINE_MINOR_VERSION < 23 + casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); +#else + casted_prop->SetMulticastDelegate(u_obj->ue_object, multiscript_delegate); +#endif + } } else if (auto casted_prop_delegate = Cast(u_property)) { FScriptDelegate script_delegate = casted_prop_delegate->GetPropertyValue_InContainer(u_obj->ue_object); - script_delegate.Unbind(); + script_delegate.Unbind(); // re-assign multicast delegate casted_prop_delegate->SetPropertyValue_InContainer(u_obj->ue_object, script_delegate); @@ -3088,10 +3097,10 @@ PyObject *ue_unbind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *p Py_RETURN_NONE; } -PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_callable, bool fail_on_wrong_property) +PyObject* ue_bind_pyevent(ue_PyUObject* u_obj, FString event_name, PyObject* py_callable, bool fail_on_wrong_property) { - UProperty *u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name)); + UProperty* u_property = u_obj->ue_object->GetClass()->FindPropertyByName(FName(*event_name)); if (!u_property) { if (fail_on_wrong_property) @@ -3101,10 +3110,14 @@ PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_ if (auto casted_prop = Cast(u_property)) { +#if ENGINE_MINOR_VERSION < 23 FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(u_obj->ue_object); +#else + FMulticastScriptDelegate multiscript_delegate = *casted_prop->GetMulticastDelegate(u_obj->ue_object); +#endif FScriptDelegate script_delegate; - UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(u_obj->ue_object, py_callable, casted_prop->SignatureFunction); + UPythonDelegate* py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(u_obj->ue_object, py_callable, casted_prop->SignatureFunction); // fake UFUNCTION for bypassing checks script_delegate.BindUFunction(py_delegate, FName("PyFakeCallable")); @@ -3112,13 +3125,17 @@ PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_ multiscript_delegate.Add(script_delegate); // re-assign multicast delegate +#if ENGINE_MINOR_VERSION < 23 casted_prop->SetPropertyValue_InContainer(u_obj->ue_object, multiscript_delegate); +#else + casted_prop->SetMulticastDelegate(u_obj->ue_object, multiscript_delegate); +#endif } else if (auto casted_prop_delegate = Cast(u_property)) { FScriptDelegate script_delegate = casted_prop_delegate->GetPropertyValue_InContainer(u_obj->ue_object); - UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(u_obj->ue_object, py_callable, casted_prop_delegate->SignatureFunction); + UPythonDelegate* py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(u_obj->ue_object, py_callable, casted_prop_delegate->SignatureFunction); // fake UFUNCTION for bypassing checks script_delegate.BindUFunction(py_delegate, FName("PyFakeCallable")); @@ -3134,10 +3151,10 @@ PyObject *ue_bind_pyevent(ue_PyUObject *u_obj, FString event_name, PyObject *py_ Py_RETURN_NONE; } -UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_callable, uint32 function_flags) +UFunction* unreal_engine_add_function(UClass* u_class, char* name, PyObject* py_callable, uint32 function_flags) { - UFunction *parent_function = u_class->GetSuperClass()->FindFunctionByName(UTF8_TO_TCHAR(name)); + UFunction* parent_function = u_class->GetSuperClass()->FindFunctionByName(UTF8_TO_TCHAR(name)); // if the function is not available in the parent // check for name collision if (!parent_function) @@ -3149,7 +3166,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ } } - UPythonFunction *function = NewObject(u_class, UTF8_TO_TCHAR(name), RF_Public | RF_Transient | RF_MarkAsNative); + UPythonFunction* function = NewObject(u_class, UTF8_TO_TCHAR(name), RF_Public | RF_Transient | RF_MarkAsNative); function->SetPyCallable(py_callable); #if ENGINE_MINOR_VERSION < 18 @@ -3167,34 +3184,34 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ // iterate all arguments using inspect.signature() // this is required to maintaining args order - PyObject *inspect = PyImport_ImportModule("inspect"); + PyObject* inspect = PyImport_ImportModule("inspect"); if (!inspect) { return NULL; } - PyObject *signature = PyObject_CallMethod(inspect, (char *)"signature", (char *)"O", py_callable); + PyObject* signature = PyObject_CallMethod(inspect, (char*)"signature", (char*)"O", py_callable); if (!signature) { return NULL; } - PyObject *parameters = PyObject_GetAttrString(signature, "parameters"); + PyObject* parameters = PyObject_GetAttrString(signature, "parameters"); if (!parameters) { return NULL; } - PyObject *annotations = PyObject_GetAttrString(py_callable, "__annotations__"); + PyObject* annotations = PyObject_GetAttrString(py_callable, "__annotations__"); - UField **next_property = &function->Children; - UProperty **next_property_link = &function->PropertyLink; + UField** next_property = &function->Children; + UProperty** next_property_link = &function->PropertyLink; - PyObject *parameters_keys = PyObject_GetIter(parameters); + PyObject* parameters_keys = PyObject_GetIter(parameters); // do not process args if no annotations are available while (annotations) { - PyObject *key = PyIter_Next(parameters_keys); + PyObject* key = PyIter_Next(parameters_keys); if (!key) { if (PyErr_Occurred()) @@ -3204,79 +3221,79 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ if (!PyUnicodeOrString_Check(key)) continue; - const char *p_name = UEPyUnicode_AsUTF8(key); + const char* p_name = UEPyUnicode_AsUTF8(key); - PyObject *value = PyDict_GetItem(annotations, key); + PyObject* value = PyDict_GetItem(annotations, key); if (!value) continue; - UProperty *prop = nullptr; + UProperty* prop = nullptr; if (PyType_Check(value)) { - if ((PyTypeObject *)value == &PyFloat_Type) + if ((PyTypeObject*)value == &PyFloat_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)value == &PyUnicode_Type) + else if ((PyTypeObject*)value == &PyUnicode_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)value == &PyBool_Type) + else if ((PyTypeObject*)value == &PyBool_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)value == &PyLong_Type) + else if ((PyTypeObject*)value == &PyLong_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)value == &ue_PyFVectorType) + else if ((PyTypeObject*)value == &ue_PyFVectorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)value == &ue_PyFVector2DType) + else if ((PyTypeObject*)value == &ue_PyFVector2DType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)value == &ue_PyFRotatorType) + else if ((PyTypeObject*)value == &ue_PyFRotatorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)value == &ue_PyFLinearColorType) + else if ((PyTypeObject*)value == &ue_PyFLinearColorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)value == &ue_PyFColorType) + else if ((PyTypeObject*)value == &ue_PyFColorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)value == &ue_PyFTransformType) + else if ((PyTypeObject*)value == &ue_PyFTransformType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } #if ENGINE_MINOR_VERSION > 18 - else if ((PyTypeObject *)value == &ue_PyFQuatType) + else if ((PyTypeObject*)value == &ue_PyFQuatType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } #endif - else if (PyObject_IsInstance(value, (PyObject *)&PyType_Type)) + else if (PyObject_IsInstance(value, (PyObject*)& PyType_Type)) { // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) - PyObject *type_args = PyObject_GetAttrString(value, "__args__"); + PyObject* type_args = PyObject_GetAttrString(value, "__args__"); if (!type_args) { UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); @@ -3288,8 +3305,8 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); return nullptr; } - PyObject *py_class = PyTuple_GetItem(type_args, 0); - ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + PyObject* py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject* py_obj = ue_is_pyuobject(py_class); if (!py_obj) { Py_DECREF(type_args); @@ -3302,27 +3319,27 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); return nullptr; } - UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UClassProperty* prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_class->SetMetaClass((UClass*)py_obj->ue_object); prop_class->PropertyClass = UClass::StaticClass(); prop = prop_class; Py_DECREF(type_args); } } - else if (ue_PyUObject *py_obj = ue_is_pyuobject(value)) + else if (ue_PyUObject * py_obj = ue_is_pyuobject(value)) { if (py_obj->ue_object->IsA()) { - UClass *p_u_class = (UClass *)py_obj->ue_object; - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UClass* p_u_class = (UClass*)py_obj->ue_object; + UObjectProperty* prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_base->SetPropertyClass(p_u_class); prop = prop_base; } #if ENGINE_MINOR_VERSION > 17 else if (py_obj->ue_object->IsA()) { - UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + UEnumProperty* prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty* prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); prop_enum->SetEnum((UEnum*)py_obj->ue_object); prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; @@ -3330,7 +3347,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ #endif else if (py_obj->ue_object->IsA()) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; prop = prop_struct; } @@ -3354,78 +3371,78 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ // check for return value if (annotations) { - PyObject *py_return_value = PyDict_GetItemString(annotations, "return"); + PyObject* py_return_value = PyDict_GetItemString(annotations, "return"); if (py_return_value) { UE_LOG(LogPython, Warning, TEXT("Return Value found")); - UProperty *prop = nullptr; - char *p_name = (char *) "ReturnValue"; + UProperty* prop = nullptr; + char* p_name = (char*) "ReturnValue"; if (PyType_Check(py_return_value)) { - if ((PyTypeObject *)py_return_value == &PyFloat_Type) + if ((PyTypeObject*)py_return_value == &PyFloat_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)py_return_value == &PyUnicode_Type) + else if ((PyTypeObject*)py_return_value == &PyUnicode_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)py_return_value == &PyBool_Type) + else if ((PyTypeObject*)py_return_value == &PyBool_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)py_return_value == &PyLong_Type) + else if ((PyTypeObject*)py_return_value == &PyLong_Type) { prop = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); } - else if ((PyTypeObject *)py_return_value == &ue_PyFVectorType) + else if ((PyTypeObject*)py_return_value == &ue_PyFVectorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)py_return_value == &ue_PyFVector2DType) + else if ((PyTypeObject*)py_return_value == &ue_PyFVector2DType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)py_return_value == &ue_PyFRotatorType) + else if ((PyTypeObject*)py_return_value == &ue_PyFRotatorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)py_return_value == &ue_PyFLinearColorType) + else if ((PyTypeObject*)py_return_value == &ue_PyFLinearColorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)py_return_value == &ue_PyFColorType) + else if ((PyTypeObject*)py_return_value == &ue_PyFColorType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } - else if ((PyTypeObject *)py_return_value == &ue_PyFTransformType) + else if ((PyTypeObject*)py_return_value == &ue_PyFTransformType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } #if ENGINE_MINOR_VERSION > 18 - else if ((PyTypeObject *)py_return_value == &ue_PyFQuatType) + else if ((PyTypeObject*)py_return_value == &ue_PyFQuatType) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = TBaseStructure::Get(); prop = prop_struct; } #endif - else if (PyObject_IsInstance(py_return_value, (PyObject *)&PyType_Type)) + else if (PyObject_IsInstance(py_return_value, (PyObject*)& PyType_Type)) { // Method annotation like foo:typing.Type[Pawn] produces annotations like typing.Type[Pawn], with .__args__ = (Pawn,) - PyObject *type_args = PyObject_GetAttrString(py_return_value, "__args__"); + PyObject* type_args = PyObject_GetAttrString(py_return_value, "__args__"); if (!type_args) { UE_LOG(LogPython, Error, TEXT("missing type info on %s"), UTF8_TO_TCHAR(name)); @@ -3437,8 +3454,8 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ UE_LOG(LogPython, Error, TEXT("exactly one class is allowed in type info for %s"), UTF8_TO_TCHAR(name)); return nullptr; } - PyObject *py_class = PyTuple_GetItem(type_args, 0); - ue_PyUObject *py_obj = ue_is_pyuobject(py_class); + PyObject* py_class = PyTuple_GetItem(type_args, 0); + ue_PyUObject* py_obj = ue_is_pyuobject(py_class); if (!py_obj) { Py_DECREF(type_args); @@ -3451,27 +3468,27 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ UE_LOG(LogPython, Error, TEXT("type for %s must be a UClass"), UTF8_TO_TCHAR(name)); return nullptr; } - UClassProperty *prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UClassProperty* prop_class = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_class->SetMetaClass((UClass*)py_obj->ue_object); prop_class->PropertyClass = UClass::StaticClass(); prop = prop_class; Py_DECREF(type_args); } } - else if (ue_PyUObject *py_obj = ue_is_pyuobject(py_return_value)) + else if (ue_PyUObject * py_obj = ue_is_pyuobject(py_return_value)) { if (py_obj->ue_object->IsA()) { - UClass *p_u_class = (UClass *)py_obj->ue_object; - UObjectProperty *prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UClass* p_u_class = (UClass*)py_obj->ue_object; + UObjectProperty* prop_base = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_base->SetPropertyClass(p_u_class); prop = prop_base; } #if ENGINE_MINOR_VERSION > 17 else if (py_obj->ue_object->IsA()) { - UEnumProperty *prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); - UNumericProperty *prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); + UEnumProperty* prop_enum = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UNumericProperty* prop_underlying = NewObject(prop_enum, TEXT("UnderlyingType"), RF_Public); prop_enum->SetEnum((UEnum*)py_obj->ue_object); prop_enum->AddCppProperty(prop_underlying); prop = prop_enum; @@ -3479,7 +3496,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ #endif else if (py_obj->ue_object->IsA()) { - UStructProperty *prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); + UStructProperty* prop_struct = NewObject(function, UTF8_TO_TCHAR(p_name), RF_Public); prop_struct->Struct = (UScriptStruct*)py_obj->ue_object; prop = prop_struct; } @@ -3512,11 +3529,11 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ TFieldIterator It(parent_function); while (It) { - UProperty *p = *It; + UProperty* p = *It; if (p->PropertyFlags & CPF_Parm) { UE_LOG(LogPython, Warning, TEXT("Parent PROP: %s %d/%d %d %d %d %s %p"), *p->GetName(), (int)p->PropertyFlags, (int)UFunction::GetDefaultIgnoredSignatureCompatibilityFlags(), (int)(p->PropertyFlags & ~UFunction::GetDefaultIgnoredSignatureCompatibilityFlags()), p->GetSize(), p->GetOffset_ForGC(), *p->GetClass()->GetName(), p->GetClass()); - UClassProperty *ucp = Cast(p); + UClassProperty* ucp = Cast(p); if (ucp) { UE_LOG(LogPython, Warning, TEXT("Parent UClassProperty = %p %s %p %s"), ucp->PropertyClass, *ucp->PropertyClass->GetName(), ucp->MetaClass, *ucp->MetaClass->GetName()); @@ -3528,11 +3545,11 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ TFieldIterator It2(function); while (It2) { - UProperty *p = *It2; + UProperty* p = *It2; if (p->PropertyFlags & CPF_Parm) { UE_LOG(LogPython, Warning, TEXT("Function PROP: %s %d/%d %d %d %d %s %p"), *p->GetName(), (int)p->PropertyFlags, (int)UFunction::GetDefaultIgnoredSignatureCompatibilityFlags(), (int)(p->PropertyFlags & ~UFunction::GetDefaultIgnoredSignatureCompatibilityFlags()), p->GetSize(), p->GetOffset_ForGC(), *p->GetClass()->GetName(), p->GetClass()); - UClassProperty *ucp = Cast(p); + UClassProperty* ucp = Cast(p); if (ucp) { UE_LOG(LogPython, Warning, TEXT("Function UClassProperty = %p %s %p %s"), ucp->PropertyClass, *ucp->PropertyClass->GetName(), ucp->MetaClass, *ucp->MetaClass->GetName()); @@ -3552,7 +3569,7 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ TFieldIterator props(function, EFieldIteratorFlags::ExcludeSuper); for (; props; ++props) { - UProperty *p = *props; + UProperty* p = *props; if (p->HasAnyPropertyFlags(CPF_Parm)) { function->NumParms++; @@ -3581,9 +3598,9 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ #endif #if ENGINE_MINOR_VERSION > 18 - function->SetNativeFunc((FNativeFuncPtr)&UPythonFunction::CallPythonCallable); + function->SetNativeFunc((FNativeFuncPtr)& UPythonFunction::CallPythonCallable); #else - function->SetNativeFunc((Native)&UPythonFunction::CallPythonCallable); + function->SetNativeFunc((Native)& UPythonFunction::CallPythonCallable); #endif function->Next = u_class->Children; @@ -3626,24 +3643,24 @@ UFunction *unreal_engine_add_function(UClass *u_class, char *name, PyObject *py_ return function; } -FGuid *ue_py_check_fguid(PyObject *py_obj) +FGuid* ue_py_check_fguid(PyObject* py_obj) { - ue_PyUScriptStruct *ue_py_struct = py_ue_is_uscriptstruct(py_obj); + ue_PyUScriptStruct* ue_py_struct = py_ue_is_uscriptstruct(py_obj); if (!ue_py_struct) { return nullptr; } - if (ue_py_struct->u_struct == FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid"))) + if (ue_py_struct->u_struct == FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char*)"Guid"))) { return (FGuid*)ue_py_struct->u_struct_ptr; } return nullptr; } -uint8 * do_ue_py_check_struct(PyObject *py_obj, UScriptStruct* chk_u_struct) +uint8* do_ue_py_check_struct(PyObject* py_obj, UScriptStruct* chk_u_struct) { - ue_PyUScriptStruct *ue_py_struct = py_ue_is_uscriptstruct(py_obj); + ue_PyUScriptStruct* ue_py_struct = py_ue_is_uscriptstruct(py_obj); if (!ue_py_struct) { return nullptr; @@ -3657,9 +3674,9 @@ uint8 * do_ue_py_check_struct(PyObject *py_obj, UScriptStruct* chk_u_struct) return nullptr; } -bool do_ue_py_check_childstruct(PyObject *py_obj, UScriptStruct* parent_u_struct) +bool do_ue_py_check_childstruct(PyObject* py_obj, UScriptStruct* parent_u_struct) { - ue_PyUScriptStruct *ue_py_struct = py_ue_is_uscriptstruct(py_obj); + ue_PyUScriptStruct* ue_py_struct = py_ue_is_uscriptstruct(py_obj); if (!ue_py_struct) { return false; @@ -3671,10 +3688,10 @@ bool do_ue_py_check_childstruct(PyObject *py_obj, UScriptStruct* parent_u_struct #if PY_MAJOR_VERSION >= 3 -static PyObject *init_unreal_engine() +static PyObject * init_unreal_engine() { - PyObject *new_unreal_engine_module = PyModule_Create(&unreal_engine_module); + PyObject* new_unreal_engine_module = PyModule_Create(&unreal_engine_module); if (!new_unreal_engine_module) return nullptr; diff --git a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp index 870a62474..548a83935 100644 --- a/Source/UnrealEnginePython/Private/UEPySubclassing.cpp +++ b/Source/UnrealEnginePython/Private/UEPySubclassing.cpp @@ -346,7 +346,12 @@ int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) { if (auto casted_prop = Cast(u_property)) { +#if ENGINE_MINOR_VERSION >= 23 + FMulticastScriptDelegate multiscript_delegate = *casted_prop->GetMulticastDelegate(ObjectInitializer.GetObj()); +#else + FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(ObjectInitializer.GetObj()); +#endif FScriptDelegate script_delegate; UPythonDelegate *py_delegate = FUnrealEnginePythonHouseKeeper::Get()->NewDelegate(ObjectInitializer.GetObj(), mc_value, casted_prop->SignatureFunction); @@ -357,7 +362,11 @@ int unreal_engine_py_init(ue_PyUObject *self, PyObject *args, PyObject *kwds) multiscript_delegate.Add(script_delegate); // re-assign multicast delegate +#if ENGINE_MINOR_VERSION >= 23 + casted_prop->SetMulticastDelegate(ObjectInitializer.GetObj(), multiscript_delegate); +#else casted_prop->SetPropertyValue_InContainer(ObjectInitializer.GetObj(), multiscript_delegate); +#endif } else { diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.cpp index 7eafe7b51..2674c0d1b 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyAnimSequence.cpp @@ -105,6 +105,7 @@ PyObject *py_ue_anim_extract_root_motion(ue_PyUObject * self, PyObject * args) #if WITH_EDITOR #if ENGINE_MINOR_VERSION > 13 +#if ENGINE_MINOR_VERSION < 23 PyObject *py_ue_anim_sequence_update_compressed_track_map_from_raw(ue_PyUObject * self, PyObject * args) { ue_py_check(self); @@ -117,6 +118,7 @@ PyObject *py_ue_anim_sequence_update_compressed_track_map_from_raw(ue_PyUObject Py_RETURN_NONE; } +#endif PyObject *py_ue_anim_sequence_get_raw_animation_data(ue_PyUObject * self, PyObject * args) diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyFoliage.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyFoliage.cpp index e474fda19..0a9498d2a 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyFoliage.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyFoliage.cpp @@ -37,8 +37,11 @@ PyObject *py_ue_get_foliage_types(ue_PyUObject *self, PyObject * args) PyObject *py_list = PyList_New(0); TArray FoliageTypes; - +#if ENGINE_MINOR_VERSION >=23 + foliage_actor->FoliageInfos.GetKeys(FoliageTypes); +#else foliage_actor->FoliageMeshes.GetKeys(FoliageTypes); +#endif for (UFoliageType *FoliageType : FoliageTypes) { @@ -68,12 +71,20 @@ PyObject *py_ue_get_foliage_instances(ue_PyUObject *self, PyObject * args) if (!foliage_type) return PyErr_Format(PyExc_Exception, "argument is not a UFoliageType"); +#if ENGINE_MINOR_VERSION >= 23 + if (!foliage_actor->FoliageInfos.Contains(foliage_type)) +#else if (!foliage_actor->FoliageMeshes.Contains(foliage_type)) +#endif { return PyErr_Format(PyExc_Exception, "specified UFoliageType not found in AInstancedFoliageActor"); } +#if ENGINE_MINOR_VERSION >= 23 + FFoliageInfo& info = foliage_actor->FoliageInfos[foliage_type].Get(); +#else FFoliageMeshInfo& info = foliage_actor->FoliageMeshes[foliage_type].Get(); +#endif PyObject *py_list = PyList_New(0); @@ -111,7 +122,11 @@ PyObject *py_ue_add_foliage_asset(ue_PyUObject *self, PyObject * args) AInstancedFoliageActor *ifa = AInstancedFoliageActor::GetInstancedFoliageActorForCurrentLevel(world, true); if (u_object->IsA()) { +#if ENGINE_MINOR_VERSION >= 23 + foliage_type = ifa->GetLocalFoliageTypeForSource(u_object); +#else foliage_type = ifa->GetLocalFoliageTypeForMesh((UStaticMesh *)u_object); +#endif if (!foliage_type) { ifa->AddMesh((UStaticMesh *)u_object, &foliage_type); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp index fbd27d2df..adacab7ec 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyLandscape.cpp @@ -8,35 +8,35 @@ #include "Runtime/Landscape/Classes/LandscapeInfo.h" #include "GameFramework/GameModeBase.h" -PyObject *py_ue_create_landscape_info(ue_PyUObject *self, PyObject * args) +PyObject* py_ue_create_landscape_info(ue_PyUObject* self, PyObject* args) { ue_py_check(self); - ALandscapeProxy *landscape = ue_py_check_type(self); + ALandscapeProxy* landscape = ue_py_check_type(self); if (!landscape) return PyErr_Format(PyExc_Exception, "uobject is not a ULandscapeProxy"); Py_RETURN_UOBJECT(landscape->CreateLandscapeInfo()); } -PyObject *py_ue_get_landscape_info(ue_PyUObject *self, PyObject * args) +PyObject* py_ue_get_landscape_info(ue_PyUObject* self, PyObject* args) { ue_py_check(self); - ALandscapeProxy *landscape = ue_py_check_type(self); + ALandscapeProxy* landscape = ue_py_check_type(self); if (!landscape) return PyErr_Format(PyExc_Exception, "uobject is not a ULandscapeProxy"); - ULandscapeInfo *info = landscape->GetLandscapeInfo(); + ULandscapeInfo* info = landscape->GetLandscapeInfo(); if (!info) Py_RETURN_NONE; Py_RETURN_UOBJECT(info); } -PyObject *py_ue_landscape_import(ue_PyUObject *self, PyObject * args) +PyObject* py_ue_landscape_import(ue_PyUObject* self, PyObject* args) { ue_py_check(self); @@ -51,7 +51,7 @@ PyObject *py_ue_landscape_import(ue_PyUObject *self, PyObject * args) if (!PyArg_ParseTuple(args, "iiiiy*|i:landscape_import", §ion_size, §ions_per_component, &component_x, &component_y, &heightmap_buffer, &layer_type)) return nullptr; - ALandscapeProxy *landscape = ue_py_check_type(self); + ALandscapeProxy* landscape = ue_py_check_type(self); if (!landscape) return PyErr_Format(PyExc_Exception, "uobject is not a ULandscapeProxy"); @@ -62,16 +62,29 @@ PyObject *py_ue_landscape_import(ue_PyUObject *self, PyObject * args) if (heightmap_buffer.len < (Py_ssize_t)(size_x * size_y * sizeof(uint16))) return PyErr_Format(PyExc_Exception, "not enough heightmap data, expecting %lu bytes", size_x * size_y * sizeof(uint16)); - uint16 *data = (uint16 *)heightmap_buffer.buf; + uint16* data = (uint16*)heightmap_buffer.buf; TArray infos; +#if ENGINE_MINOR_VERSION < 23 landscape->Import(FGuid::NewGuid(), 0, 0, size_x - 1, size_y - 1, sections_per_component, section_size, data, nullptr, infos, (ELandscapeImportAlphamapType)layer_type); +#else + TMap> HeightDataPerLayers; + TArray HeightData; + for (uint32 i = 0; i < (heightmap_buffer.len / sizeof(uint16)); i++) + { + HeightData.Add(data[i]); + } + HeightDataPerLayers.Add(FGuid(), HeightData); + TMap> MaterialLayersInfo; + MaterialLayersInfo.Add(FGuid(), infos); + landscape->Import(FGuid::NewGuid(), 0, 0, size_x - 1, size_y - 1, sections_per_component, section_size, HeightDataPerLayers, nullptr, MaterialLayersInfo, (ELandscapeImportAlphamapType)layer_type); +#endif Py_RETURN_NONE; } -PyObject *py_ue_landscape_export_to_raw_mesh(ue_PyUObject *self, PyObject * args) +PyObject* py_ue_landscape_export_to_raw_mesh(ue_PyUObject* self, PyObject* args) { ue_py_check(self); @@ -81,7 +94,7 @@ PyObject *py_ue_landscape_export_to_raw_mesh(ue_PyUObject *self, PyObject * args if (!PyArg_ParseTuple(args, "|i:landscape_import", &lod)) return nullptr; - ALandscapeProxy *landscape = ue_py_check_type(self); + ALandscapeProxy* landscape = ue_py_check_type(self); if (!landscape) return PyErr_Format(PyExc_Exception, "uobject is not a ULandscapeProxy"); diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp index 90b47da3a..c958094f6 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyMaterial.cpp @@ -505,7 +505,11 @@ PyObject *py_ue_static_mesh_set_collision_for_lod(ue_PyUObject *self, PyObject * enabled = true; } +#if ENGINE_MINOR_VERSION >= 23 + FMeshSectionInfo info = mesh->GetSectionInfoMap().Get(lod_index, material_index); +#else FMeshSectionInfo info = mesh->SectionInfoMap.Get(lod_index, material_index); +#endif info.bEnableCollision = enabled; mesh->SectionInfoMap.Set(lod_index, material_index, info); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp index 4352312ba..7ffa2d05e 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyESlateEnums.cpp @@ -80,7 +80,11 @@ void ue_python_init_eslate_enums(PyObject *ue_module) }; #if ENGINE_MINOR_VERSION > 15 +#if ENGINE_MINOR_VERSION >= 23 +#define ADD_NATIVE_ENUM(EnumType, EnumVal) add_native_enum(#EnumType "." #EnumVal, (uint8)EnumType::EnumVal) +#else #define ADD_NATIVE_ENUM(EnumType, EnumVal) add_native_enum(#EnumType "." #EnumVal, (uint8)EnumType::Type::EnumVal) +#endif ADD_NATIVE_ENUM(EUserInterfaceActionType, None); ADD_NATIVE_ENUM(EUserInterfaceActionType, Button); ADD_NATIVE_ENUM(EUserInterfaceActionType, ToggleButton); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp index 1dbab35cd..eb48a0631 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp @@ -18,7 +18,7 @@ -static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance *self) +static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance* self) { if (!self->foliage_actor.IsValid()) { @@ -32,7 +32,13 @@ static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance *self) return nullptr; } +#if ENGINE_MINOR_VERSION >= 23 + auto FoliageInfo = self->foliage_actor->FoliageInfos[self->foliage_type.Get()]; + FFoliageInfo& info = info; +#else + FFoliageMeshInfo& info = self->foliage_actor->FoliageMeshes[self->foliage_type.Get()].Get(); +#endif if (self->instance_id >= 0 && self->instance_id < info.Instances.Num()) { @@ -43,25 +49,25 @@ static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance *self) return nullptr; } -static PyObject *ue_PyFFoliageInstance_str(ue_PyFFoliageInstance *self) +static PyObject* ue_PyFFoliageInstance_str(ue_PyFFoliageInstance* self) { return PyUnicode_FromFormat("", self->instance_id); } -static PyObject *py_ue_ffoliage_instance_get_location(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_location(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return py_ue_new_fvector(instance->Location); } -static int py_ue_ffoliage_instance_set_location(ue_PyFFoliageInstance *self, PyObject *value, void *closure) +static int py_ue_ffoliage_instance_set_location(ue_PyFFoliageInstance* self, PyObject* value, void* closure) { set_instance(self); if (value) { - ue_PyFVector *vec = py_ue_is_fvector(value); + ue_PyFVector* vec = py_ue_is_fvector(value); if (vec) { TArray instances; @@ -77,12 +83,12 @@ static int py_ue_ffoliage_instance_set_location(ue_PyFFoliageInstance *self, PyO return -1; } -static int py_ue_ffoliage_instance_set_rotation(ue_PyFFoliageInstance *self, PyObject *value, void *closure) +static int py_ue_ffoliage_instance_set_rotation(ue_PyFFoliageInstance* self, PyObject* value, void* closure) { set_instance(self); if (value) { - ue_PyFRotator *rot = py_ue_is_frotator(value); + ue_PyFRotator* rot = py_ue_is_frotator(value); if (rot) { TArray instances; @@ -98,56 +104,56 @@ static int py_ue_ffoliage_instance_set_rotation(ue_PyFFoliageInstance *self, PyO return -1; } -static PyObject *py_ue_ffoliage_instance_get_draw_scale3d(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_draw_scale3d(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return py_ue_new_fvector(instance->DrawScale3D); } -static PyObject *py_ue_ffoliage_instance_get_flags(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_flags(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return PyLong_FromUnsignedLong(instance->Flags); } -static PyObject *py_ue_ffoliage_instance_get_pre_align_rotation(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_pre_align_rotation(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return py_ue_new_frotator(instance->PreAlignRotation); } -static PyObject *py_ue_ffoliage_instance_get_rotation(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_rotation(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return py_ue_new_frotator(instance->Rotation); } -static PyObject *py_ue_ffoliage_instance_get_zoffset(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_zoffset(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return PyFloat_FromDouble(instance->ZOffset); } -static PyObject *py_ue_ffoliage_instance_get_procedural_guid(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_procedural_guid(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); FGuid guid = instance->ProceduralGuid; - return py_ue_new_owned_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&guid); + return py_ue_new_owned_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char*)"Guid")), (uint8*)& guid); } -static PyObject *py_ue_ffoliage_instance_get_base_id(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_base_id(ue_PyFFoliageInstance* self, void* closure) { get_instance(self); return PyLong_FromLong(instance->BaseId); } -static PyObject *py_ue_ffoliage_instance_get_instance_id(ue_PyFFoliageInstance *self, void *closure) +static PyObject* py_ue_ffoliage_instance_get_instance_id(ue_PyFFoliageInstance* self, void* closure) { return PyLong_FromLong(self->instance_id); } #if ENGINE_MINOR_VERSION > 19 -static PyObject *py_ue_ffoliage_instance_get_base_component(ue_PyFFoliageInstance *self, void *closure) +static PyObject * py_ue_ffoliage_instance_get_base_component(ue_PyFFoliageInstance * self, void* closure) { get_instance(self); Py_RETURN_UOBJECT(instance->BaseComponent); @@ -157,39 +163,39 @@ static PyObject *py_ue_ffoliage_instance_get_base_component(ue_PyFFoliageInstanc static PyGetSetDef ue_PyFFoliageInstance_getseters[] = { - { (char *)"location", (getter)py_ue_ffoliage_instance_get_location, (setter)py_ue_ffoliage_instance_set_location, (char *)"", NULL }, - { (char *)"draw_scale3d", (getter)py_ue_ffoliage_instance_get_draw_scale3d, nullptr, (char *)"", NULL }, - { (char *)"flags", (getter)py_ue_ffoliage_instance_get_flags, nullptr, (char *)"", NULL }, - { (char *)"pre_align_rotation", (getter)py_ue_ffoliage_instance_get_pre_align_rotation, nullptr, (char *)"", NULL }, - { (char *)"rotation", (getter)py_ue_ffoliage_instance_get_rotation, (setter)py_ue_ffoliage_instance_set_rotation, (char *)"", NULL }, - { (char *)"zoffset", (getter)py_ue_ffoliage_instance_get_zoffset, nullptr, (char *)"", NULL }, - { (char *)"procedural_guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char *)"", NULL }, - { (char *)"guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char *)"", NULL }, - { (char *)"base_id", (getter)py_ue_ffoliage_instance_get_base_id, nullptr, (char *)"", NULL }, - { (char *)"instance_id", (getter)py_ue_ffoliage_instance_get_instance_id, nullptr, (char *)"", NULL }, + { (char*)"location", (getter)py_ue_ffoliage_instance_get_location, (setter)py_ue_ffoliage_instance_set_location, (char*)"", NULL }, + { (char*)"draw_scale3d", (getter)py_ue_ffoliage_instance_get_draw_scale3d, nullptr, (char*)"", NULL }, + { (char*)"flags", (getter)py_ue_ffoliage_instance_get_flags, nullptr, (char*)"", NULL }, + { (char*)"pre_align_rotation", (getter)py_ue_ffoliage_instance_get_pre_align_rotation, nullptr, (char*)"", NULL }, + { (char*)"rotation", (getter)py_ue_ffoliage_instance_get_rotation, (setter)py_ue_ffoliage_instance_set_rotation, (char*)"", NULL }, + { (char*)"zoffset", (getter)py_ue_ffoliage_instance_get_zoffset, nullptr, (char*)"", NULL }, + { (char*)"procedural_guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char*)"", NULL }, + { (char*)"guid", (getter)py_ue_ffoliage_instance_get_procedural_guid, nullptr, (char*)"", NULL }, + { (char*)"base_id", (getter)py_ue_ffoliage_instance_get_base_id, nullptr, (char*)"", NULL }, + { (char*)"instance_id", (getter)py_ue_ffoliage_instance_get_instance_id, nullptr, (char*)"", NULL }, #if ENGINE_MINOR_VERSION > 19 - { (char *)"base_component", (getter)py_ue_ffoliage_instance_get_base_component, nullptr, (char *)"", NULL }, + { (char*)"base_component", (getter)py_ue_ffoliage_instance_get_base_component, nullptr, (char*)"", NULL }, #endif { NULL } /* Sentinel */ }; -static PyObject *py_ue_ffoliage_instance_get_instance_world_transform(ue_PyFFoliageInstance *self, PyObject * args) +static PyObject* py_ue_ffoliage_instance_get_instance_world_transform(ue_PyFFoliageInstance* self, PyObject* args) { get_instance(self); return py_ue_new_ftransform(instance->GetInstanceWorldTransform()); } -static PyObject *py_ue_ffoliage_instance_align_to_normal(ue_PyFFoliageInstance *self, PyObject * args) +static PyObject* py_ue_ffoliage_instance_align_to_normal(ue_PyFFoliageInstance* self, PyObject* args) { get_instance(self); - PyObject *py_vec; + PyObject* py_vec; float align_max_angle = 0; if (!PyArg_ParseTuple(args, "O|f:align_to_normal", &py_vec, &align_max_angle)) return nullptr; - ue_PyFVector *vec = py_ue_is_fvector(py_vec); + ue_PyFVector* vec = py_ue_is_fvector(py_vec); if (!vec) { return PyErr_Format(PyExc_Exception, "argument is not an FVector"); @@ -244,7 +250,7 @@ static PyTypeObject ue_PyFFoliageInstanceType = { ue_PyFFoliageInstance_getseters, }; -void ue_python_init_ffoliage_instance(PyObject *ue_module) +void ue_python_init_ffoliage_instance(PyObject* ue_module) { ue_PyFFoliageInstanceType.tp_new = PyType_GenericNew; @@ -252,16 +258,16 @@ void ue_python_init_ffoliage_instance(PyObject *ue_module) return; Py_INCREF(&ue_PyFFoliageInstanceType); - PyModule_AddObject(ue_module, "FoliageInstance", (PyObject *)&ue_PyFFoliageInstanceType); + PyModule_AddObject(ue_module, "FoliageInstance", (PyObject*)& ue_PyFFoliageInstanceType); } -PyObject *py_ue_new_ffoliage_instance(AInstancedFoliageActor *foliage_actor, UFoliageType *foliage_type, int32 instance_id) +PyObject* py_ue_new_ffoliage_instance(AInstancedFoliageActor* foliage_actor, UFoliageType* foliage_type, int32 instance_id) { - ue_PyFFoliageInstance *ret = (ue_PyFFoliageInstance *)PyObject_New(ue_PyFFoliageInstance, &ue_PyFFoliageInstanceType); + ue_PyFFoliageInstance* ret = (ue_PyFFoliageInstance*)PyObject_New(ue_PyFFoliageInstance, &ue_PyFFoliageInstanceType); ret->foliage_actor = TWeakObjectPtr(foliage_actor); ret->foliage_type = TWeakObjectPtr(foliage_type); ret->instance_id = instance_id; - return (PyObject *)ret; + return (PyObject*)ret; } #endif \ No newline at end of file diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 51394b033..92376225e 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -18,7 +18,7 @@ public class UnrealEnginePython : ModuleRules private string[] windowsKnownPaths = { - "C:/Program Files/Python37", + // "C:/Program Files/Python37", "C:/Program Files/Python36", "C:/Program Files/Python35", "C:/Python27", From 038192d7814d1aee182766028640d238204fefa4 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 11 Sep 2019 05:27:13 +0200 Subject: [PATCH 59/62] completed porting to 4.23. fixes #777 --- .../Private/Slate/UEPySTextBlock.cpp | 4 ++++ Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp | 5 ++++- Source/UnrealEnginePython/Private/UEPyModule.cpp | 2 ++ .../UnrealEnginePython/Private/UObject/UEPyObject.cpp | 4 ++++ .../Private/Wrappers/UEPyFFoliageInstance.cpp | 11 +++++++++-- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp index a994186a5..92df02d50 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySTextBlock.cpp @@ -70,7 +70,11 @@ static int ue_py_stext_block_init(ue_PySTextBlock *self, PyObject *args, PyObjec ue_py_slate_farguments_float("line_height_percentage", LineHeightPercentage); ue_py_slate_farguments_struct("margin", Margin, FMargin); ue_py_slate_farguments_float("min_desired_width", MinDesiredWidth); +#if ENGINE_MINOR_VERSION >= 23 + ue_py_slate_farguments_event("on_double_clicked", OnDoubleClicked, FPointerEventHandler, OnMouseEvent); +#else ue_py_slate_farguments_event("on_double_clicked", OnDoubleClicked, FOnClicked, OnClicked); +#endif ue_py_slate_farguments_flinear_color("shadow_color_and_opacity", ShadowColorAndOpacity); ue_py_slate_farguments_fvector2d("shadow_offset", ShadowOffset); ue_py_slate_farguments_text("text", Text); diff --git a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp index 0cc988240..2e705a303 100644 --- a/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp +++ b/Source/UnrealEnginePython/Private/Slate/UEPySlate.cpp @@ -1020,8 +1020,11 @@ class FPythonSlateCommands : public TCommands virtual void RegisterCommands() override { commands = MakeShareable(new FUICommandList); - +#if ENGINE_MINOR_VERSION >= 23 + MakeUICommand_InternalUseOnly(this, command, nullptr, *name, *name, TCHAR_TO_UTF8(*name), *name, *name, EUserInterfaceActionType::Button, FInputGesture()); +#else UI_COMMAND_Function(this, command, nullptr, *name, *name, TCHAR_TO_UTF8(*name), *name, *name, EUserInterfaceActionType::Button, FInputGesture()); +#endif commands->MapAction(command, FExecuteAction::CreateRaw(this, &FPythonSlateCommands::Callback), FCanExecuteAction()); } diff --git a/Source/UnrealEnginePython/Private/UEPyModule.cpp b/Source/UnrealEnginePython/Private/UEPyModule.cpp index b725ae7f0..56954d32e 100644 --- a/Source/UnrealEnginePython/Private/UEPyModule.cpp +++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp @@ -744,7 +744,9 @@ static PyMethodDef ue_PyUObject_methods[] = { { "get_raw_animation_data", (PyCFunction)py_ue_anim_sequence_get_raw_animation_data, METH_VARARGS, "" }, { "get_raw_animation_track", (PyCFunction)py_ue_anim_sequence_get_raw_animation_track, METH_VARARGS, "" }, { "add_new_raw_track", (PyCFunction)py_ue_anim_sequence_add_new_raw_track, METH_VARARGS, "" }, +#if ENGINE_MINOR_VERSION <23 { "update_compressed_track_map_from_raw", (PyCFunction)py_ue_anim_sequence_update_compressed_track_map_from_raw, METH_VARARGS, "" }, +#endif { "update_raw_track", (PyCFunction)py_ue_anim_sequence_update_raw_track, METH_VARARGS, "" }, { "apply_raw_anim_changes", (PyCFunction)py_ue_anim_sequence_apply_raw_anim_changes, METH_VARARGS, "" }, { "add_key_to_sequence", (PyCFunction)py_ue_anim_add_key_to_sequence, METH_VARARGS, "" }, diff --git a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp index d11031775..3b2983b99 100644 --- a/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp +++ b/Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp @@ -1084,7 +1084,11 @@ PyObject *py_ue_broadcast(ue_PyUObject *self, PyObject *args) if (auto casted_prop = Cast(u_property)) { +#if ENGINE_MINOR_VERSION >= 23 + FMulticastScriptDelegate multiscript_delegate = *casted_prop->GetMulticastDelegate(self->ue_object); +#else FMulticastScriptDelegate multiscript_delegate = casted_prop->GetPropertyValue_InContainer(self->ue_object); +#endif uint8 *parms = (uint8 *)FMemory_Alloca(casted_prop->SignatureFunction->PropertiesSize); FMemory::Memzero(parms, casted_prop->SignatureFunction->PropertiesSize); diff --git a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp index eb48a0631..2ed7ffa2d 100644 --- a/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp +++ b/Source/UnrealEnginePython/Private/Wrappers/UEPyFFoliageInstance.cpp @@ -33,8 +33,7 @@ static FFoliageInstance* get_foliage_instance(ue_PyFFoliageInstance* self) } #if ENGINE_MINOR_VERSION >= 23 - auto FoliageInfo = self->foliage_actor->FoliageInfos[self->foliage_type.Get()]; - FFoliageInfo& info = info; + FFoliageInfo& info = self->foliage_actor->FoliageInfos[self->foliage_type.Get()].Get(); #else FFoliageMeshInfo& info = self->foliage_actor->FoliageMeshes[self->foliage_type.Get()].Get(); @@ -72,7 +71,11 @@ static int py_ue_ffoliage_instance_set_location(ue_PyFFoliageInstance* self, PyO { TArray instances; instances.Add(self->instance_id); +#if ENGINE_MINOR_VERSION >= 23 + FFoliageInfo& info = self->foliage_actor->FoliageInfos[self->foliage_type.Get()].Get(); +#else FFoliageMeshInfo& info = self->foliage_actor->FoliageMeshes[self->foliage_type.Get()].Get(); +#endif info.PreMoveInstances(self->foliage_actor.Get(), instances); instance->Location = vec->vec; info.PostMoveInstances(self->foliage_actor.Get(), instances); @@ -93,7 +96,11 @@ static int py_ue_ffoliage_instance_set_rotation(ue_PyFFoliageInstance* self, PyO { TArray instances; instances.Add(self->instance_id); +#if ENGINE_MINOR_VERSION >= 23 + FFoliageInfo& info = self->foliage_actor->FoliageInfos[self->foliage_type.Get()].Get(); +#else FFoliageMeshInfo& info = self->foliage_actor->FoliageMeshes[self->foliage_type.Get()].Get(); +#endif info.PreMoveInstances(self->foliage_actor.Get(), instances); instance->Rotation = rot->rot; info.PostMoveInstances(self->foliage_actor.Get(), instances); From b0366cbada1e6b7c951258f35ad3868e45f19ca4 Mon Sep 17 00:00:00 2001 From: Hamilton Greene Date: Tue, 26 Nov 2019 23:21:34 -0500 Subject: [PATCH 60/62] Add ; to the end of the Linux UnrealEnginePython.Build.cs pythonHome example Adding for consistency with the other examples. --- Source/UnrealEnginePython/UnrealEnginePython.Build.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 92376225e..a6fe71946 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -14,7 +14,7 @@ public class UnrealEnginePython : ModuleRules // this is an example for Homebrew on Mac //private string pythonHome = "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/"; // on Linux an include;libs syntax is expected: - //private string pythonHome = "/usr/local/include/python3.6;/usr/local/lib/libpython3.6.so" + //private string pythonHome = "/usr/local/include/python3.6;/usr/local/lib/libpython3.6.so"; private string[] windowsKnownPaths = { From bb2f38df55f0f860b161c5bf54554f36eebb5f38 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 4 Mar 2020 11:31:52 +0100 Subject: [PATCH 61/62] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index ee231ff61..a7fa3522a 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,16 @@ Funny snippets for working with StaticMesh and SkeletalMesh assets: https://gith More tutorials: https://github.com/20tab/UnrealEnginePython/tree/master/tutorials +# Project Status (IMPORTANT) + +Currently (as march 2020) the project is basically dead: between 2016 and 2018 20tab invested lot of resources in it but unfortunately epic (during 2018) decided to suddenly release its own implementation and the request made for a megagrant in 2019 by the original plugin author was rejected too. + +Albeit this plugin (still) has way more features than the Epic one, this is not enough to allow 20tab to continue investing in it. + +If you are interested in game logic scripting/modding in Unreal Engine 4 consider giving a look at the LuaMachine project (https://github.com/rdeioris/LuaMachine/). + +The plugin should work up to unreal engine version 4.23 and there are forks/pull requests for 4.24. Since 4.25 Epic refactored the UProperty subsystem, so if you want to port the plugin to a version >= 4.25 you should make a lot of search & replace (basically renaming UProperty to FProperty and Cast to CastField should be enough) + # How and Why ? This is a plugin embedding a whole Python VM (versions 3.x [the default and suggested one] and 2.7) In Unreal Engine 4 (both the editor and runtime). From 4b5da5bf4ca598e8d0f67eb938749bc381a67d6c Mon Sep 17 00:00:00 2001 From: Gabriele Giaccari Date: Fri, 17 Apr 2020 09:38:21 +0200 Subject: [PATCH 62/62] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7fa3522a..68ed706f1 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ More tutorials: https://github.com/20tab/UnrealEnginePython/tree/master/tutorial # Project Status (IMPORTANT) -Currently (as march 2020) the project is basically dead: between 2016 and 2018 20tab invested lot of resources in it but unfortunately epic (during 2018) decided to suddenly release its own implementation and the request made for a megagrant in 2019 by the original plugin author was rejected too. +Currently (as april 2020) the project is on hold: between 2016 and 2018 20tab invested lot of resources in it but unfortunately epic (during 2018) decided to suddenly release its own implementation and the request made for a megagrant in 2019 by the original plugin author was rejected too. -Albeit this plugin (still) has way more features than the Epic one, this is not enough to allow 20tab to continue investing in it. +As this plugin (still) has way more features than the Epic one and many contributors, **we are currently looking for new maintainers** helping us to keep it alive, checking PR and issues. If you are interested in working on it a few hours a week, drop us a line at info@20tab.com to discuss about it. If you are interested in game logic scripting/modding in Unreal Engine 4 consider giving a look at the LuaMachine project (https://github.com/rdeioris/LuaMachine/).