// Copyright 20Tab S.r.l. #include "UEPyEngine.h" #include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetMathLibrary.h" #include "Developer/DesktopPlatform/Public/IDesktopPlatform.h" #include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h" #if WITH_EDITOR #include "PackageTools.h" #include "Editor.h" #endif #include "UnrealEngine.h" #include "Runtime/Engine/Classes/Engine/GameViewportClient.h" #if ENGINE_MINOR_VERSION >= 18 #include "HAL/PlatformApplicationMisc.h" #endif #include "Runtime/Launch/Public/LaunchEngineLoop.h" PyObject *py_unreal_engine_log(PyObject * self, PyObject * args) { PyObject *py_message; if (!PyArg_ParseTuple(args, "O:log", &py_message)) { return NULL; } PyObject *stringified = PyObject_Str(py_message); if (!stringified) return PyErr_Format(PyExc_Exception, "argument cannot be casted to string"); char *message = PyUnicode_AsUTF8(stringified); UE_LOG(LogPython, Log, TEXT("%s"), UTF8_TO_TCHAR(message)); Py_DECREF(stringified); Py_INCREF(Py_None); return Py_None; } PyObject *py_unreal_engine_log_warning(PyObject * self, PyObject * args) { PyObject *py_message; if (!PyArg_ParseTuple(args, "O:log_warning", &py_message)) { return NULL; } PyObject *stringified = PyObject_Str(py_message); if (!stringified) return PyErr_Format(PyExc_Exception, "argument cannot be casted to string"); char *message = PyUnicode_AsUTF8(stringified); UE_LOG(LogPython, Warning, TEXT("%s"), UTF8_TO_TCHAR(message)); Py_DECREF(stringified); Py_INCREF(Py_None); return Py_None; } PyObject *py_unreal_engine_log_error(PyObject * self, PyObject * args) { PyObject *py_message; if (!PyArg_ParseTuple(args, "O:log_error", &py_message)) { return NULL; } PyObject *stringified = PyObject_Str(py_message); if (!stringified) return PyErr_Format(PyExc_Exception, "argument cannot be casted to string"); char *message = PyUnicode_AsUTF8(stringified); UE_LOG(LogPython, Error, TEXT("%s"), UTF8_TO_TCHAR(message)); Py_DECREF(stringified); Py_INCREF(Py_None); return Py_None; } PyObject *py_unreal_engine_add_on_screen_debug_message(PyObject * self, PyObject * args) { int key; float time_to_display; PyObject *py_message; if (!PyArg_ParseTuple(args, "ifO:add_on_screen_debug_message", &key, &time_to_display, &py_message)) { return NULL; } if (!GEngine) { Py_INCREF(Py_None); return Py_None; } PyObject *stringified = PyObject_Str(py_message); if (!stringified) return PyErr_Format(PyExc_Exception, "argument cannot be casted to string"); char *message = PyUnicode_AsUTF8(stringified); GEngine->AddOnScreenDebugMessage(key, time_to_display, FColor::Green, FString::Printf(TEXT("%s"), UTF8_TO_TCHAR(message))); Py_DECREF(stringified); Py_INCREF(Py_None); return Py_None; } PyObject *py_unreal_engine_print_string(PyObject * self, PyObject * args) { PyObject *py_message; float timeout = 2.0; PyObject *py_color = nullptr; if (!PyArg_ParseTuple(args, "O|fO:print_string", &py_message, &timeout, &py_color)) { return NULL; } if (!GEngine) { Py_RETURN_NONE; } FColor color = FColor::Cyan; if (py_color) { ue_PyFColor *f_color = py_ue_is_fcolor(py_color); if (!f_color) return PyErr_Format(PyExc_Exception, "argument is not a FColor"); color = f_color->color; } PyObject *stringified = PyObject_Str(py_message); if (!stringified) return PyErr_Format(PyExc_Exception, "argument cannot be casted to string"); char *message = PyUnicode_AsUTF8(stringified); GEngine->AddOnScreenDebugMessage(-1, timeout, color, FString(UTF8_TO_TCHAR(message))); Py_DECREF(stringified); Py_RETURN_NONE; } PyObject *py_unreal_engine_get_forward_vector(PyObject * self, PyObject * args) { FRotator rot; if (!py_ue_rotator_arg(args, rot)) return NULL; FVector vec = UKismetMathLibrary::GetForwardVector(rot); return py_ue_new_fvector(vec); } PyObject *py_unreal_engine_get_right_vector(PyObject * self, PyObject * args) { FRotator rot; if (!py_ue_rotator_arg(args, rot)) return NULL; FVector vec = UKismetMathLibrary::GetRightVector(rot); return py_ue_new_fvector(vec); } PyObject *py_unreal_engine_get_up_vector(PyObject * self, PyObject * args) { FRotator rot; if (!py_ue_rotator_arg(args, rot)) return NULL; FVector vec = UKismetMathLibrary::GetUpVector(rot); return py_ue_new_fvector(vec); } PyObject *py_unreal_engine_get_content_dir(PyObject * self, PyObject * args) { #if ENGINE_MINOR_VERSION >= 18 return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::ProjectContentDir())); #else return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameContentDir())); #endif } PyObject *py_unreal_engine_get_game_saved_dir(PyObject * self, PyObject * args) { #if ENGINE_MINOR_VERSION >= 18 return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::ProjectSavedDir())); #else return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameSavedDir())); #endif } PyObject * py_unreal_engine_get_game_user_developer_dir(PyObject *, PyObject *) { return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GameUserDeveloperDir())); } PyObject *py_unreal_engine_convert_relative_path_to_full(PyObject * self, PyObject * args) { char *path; if (!PyArg_ParseTuple(args, "s:convert_relative_path_to_full", &path)) { return NULL; } return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::ConvertRelativePathToFull(UTF8_TO_TCHAR(path)))); } PyObject *py_unreal_engine_object_path_to_package_name(PyObject * self, PyObject * args) { char *path; if (!PyArg_ParseTuple(args, "s:object_path_to_package_name", &path)) { return NULL; } return PyUnicode_FromString(TCHAR_TO_UTF8(*FPackageName::ObjectPathToPackageName(UTF8_TO_TCHAR(path)))); } PyObject *py_unreal_engine_get_path(PyObject * self, PyObject * args) { char *path; if (!PyArg_ParseTuple(args, "s:get_path", &path)) { return NULL; } return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GetPath(UTF8_TO_TCHAR(path)))); } PyObject *py_unreal_engine_get_base_filename(PyObject * self, PyObject * args) { char *path; if (!PyArg_ParseTuple(args, "s:get_base_filename", &path)) { return NULL; } return PyUnicode_FromString(TCHAR_TO_UTF8(*FPaths::GetBaseFilename(UTF8_TO_TCHAR(path)))); } PyObject *py_unreal_engine_create_world(PyObject * self, PyObject * args) { int world_type = 0; if (!PyArg_ParseTuple(args, "|i:create_world", &world_type)) { return NULL; } UWorld *world = UWorld::CreateWorld((EWorldType::Type)world_type, false); Py_RETURN_UOBJECT(world); } PyObject *py_unreal_engine_find_class(PyObject * self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:find_class", &name)) { return NULL; } UClass *u_class = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); if (!u_class) return PyErr_Format(PyExc_Exception, "unable to find class %s", name); Py_RETURN_UOBJECT(u_class); } PyObject *py_unreal_engine_find_enum(PyObject * self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:find_enum", &name)) { return NULL; } UEnum *u_enum = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); if (!u_enum) return PyErr_Format(PyExc_Exception, "unable to find enum %s", name); Py_RETURN_UOBJECT(u_enum); } PyObject *py_unreal_engine_load_package(PyObject * self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:load_package", &name)) { return nullptr; } UPackage *u_package = LoadPackage(nullptr, UTF8_TO_TCHAR(name), LOAD_None); if (!u_package) return PyErr_Format(PyExc_Exception, "unable to load package %s", name); Py_RETURN_UOBJECT(u_package); } #if WITH_EDITOR PyObject *py_unreal_engine_unload_package(PyObject * self, PyObject * args) { PyObject *obj; if (!PyArg_ParseTuple(args, "O:unload_package", &obj)) { return NULL; } UPackage* packageToUnload = ue_py_check_type(obj); if (!packageToUnload) { return PyErr_Format(PyExc_Exception, "argument is not a UPackage"); } FText outErrorMsg; if (!PackageTools::UnloadPackages({ packageToUnload }, outErrorMsg)) { return PyErr_Format(PyExc_Exception, TCHAR_TO_UTF8(*outErrorMsg.ToString())); } Py_RETURN_NONE; } #endif PyObject *py_unreal_engine_load_class(PyObject * self, PyObject * args) { char *name; char *filename = nullptr; if (!PyArg_ParseTuple(args, "s|s:load_class", &name, &filename)) { return NULL; } TCHAR *t_filename = (TCHAR *)0; if (filename) t_filename = UTF8_TO_TCHAR(filename); UObject *u_class = StaticLoadObject(UClass::StaticClass(), NULL, UTF8_TO_TCHAR(name), t_filename); if (!u_class) return PyErr_Format(PyExc_Exception, "unable to find class %s", name); Py_RETURN_UOBJECT(u_class); } PyObject *py_unreal_engine_load_enum(PyObject * self, PyObject * args) { char *name; char *filename = nullptr; if (!PyArg_ParseTuple(args, "s|s:load_enum", &name, &filename)) { return NULL; } TCHAR *t_filename = (TCHAR *)0; if (filename) t_filename = UTF8_TO_TCHAR(filename); UObject *u_enum = StaticLoadObject(UEnum::StaticClass(), NULL, UTF8_TO_TCHAR(name), t_filename); if (!u_enum) return PyErr_Format(PyExc_Exception, "unable to find enum %s", name); Py_RETURN_UOBJECT(u_enum); } PyObject *py_unreal_engine_find_struct(PyObject * self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:find_struct", &name)) { return NULL; } UScriptStruct *u_struct = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); if (!u_struct) return PyErr_Format(PyExc_Exception, "unable to find struct %s", name); Py_RETURN_UOBJECT(u_struct); } PyObject *py_unreal_engine_load_struct(PyObject * self, PyObject * args) { char *name; char *filename = nullptr; if (!PyArg_ParseTuple(args, "s|s:load_struct", &name, &filename)) { return NULL; } TCHAR *t_filename = (TCHAR *)0; if (filename) t_filename = UTF8_TO_TCHAR(filename); UObject *u_struct = StaticLoadObject(UScriptStruct::StaticClass(), NULL, UTF8_TO_TCHAR(name), t_filename); if (!u_struct) return PyErr_Format(PyExc_Exception, "unable to find struct %s", name); Py_RETURN_UOBJECT(u_struct); } PyObject *py_unreal_engine_load_object(PyObject * self, PyObject * args) { PyObject *obj; char *name; char *filename = nullptr; if (!PyArg_ParseTuple(args, "Os|s:load_object", &obj, &name, &filename)) { return NULL; } if (!ue_is_pyuobject(obj)) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } ue_PyUObject *py_obj = (ue_PyUObject *)obj; if (!py_obj->ue_object->IsA()) { return PyErr_Format(PyExc_Exception, "argument is not a UClass"); } UClass *u_class = (UClass *)py_obj->ue_object; TCHAR *t_filename = (TCHAR *)0; if (filename) t_filename = UTF8_TO_TCHAR(filename); UObject *u_object = StaticLoadObject(u_class, NULL, UTF8_TO_TCHAR(name), t_filename); if (!u_object) return PyErr_Format(PyExc_Exception, "unable to load object %s", name); Py_RETURN_UOBJECT(u_object); } PyObject *py_unreal_engine_string_to_guid(PyObject * self, PyObject * args) { char *str; if (!PyArg_ParseTuple(args, "s:string_to_guid", &str)) { return nullptr; } FGuid guid; if (FGuid::Parse(FString(str), guid)) { return py_ue_new_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&guid); } return PyErr_Format(PyExc_Exception, "unable to build FGuid"); } PyObject *py_unreal_engine_new_guid(PyObject * self, PyObject * args) { FGuid guid = FGuid::NewGuid(); return py_ue_new_uscriptstruct(FindObject(ANY_PACKAGE, UTF8_TO_TCHAR((char *)"Guid")), (uint8 *)&guid); } PyObject *py_unreal_engine_guid_to_string(PyObject * self, PyObject * args) { PyObject *py_guid; if (!PyArg_ParseTuple(args, "O:guid_to_string", &py_guid)) { return nullptr; } FGuid *guid = ue_py_check_fguid(py_guid); if (!guid) return PyErr_Format(PyExc_Exception, "object is not a FGuid"); return PyUnicode_FromString(TCHAR_TO_UTF8(*guid->ToString())); } PyObject *py_unreal_engine_slate_tick(PyObject * self, PyObject * args) { Py_BEGIN_ALLOW_THREADS; FSlateApplication::Get().PumpMessages(); FSlateApplication::Get().Tick(); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } PyObject *py_unreal_engine_engine_tick(PyObject * self, PyObject * args) { float delta_seconds = FApp::GetDeltaTime(); PyObject *py_idle = nullptr; if (!PyArg_ParseTuple(args, "|fO:engine_tick", &delta_seconds, &py_idle)) { return nullptr; } bool bIdle = false; if (py_idle && PyObject_IsTrue(py_idle)) bIdle = true; Py_BEGIN_ALLOW_THREADS; GEngine->Tick(delta_seconds, bIdle); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } PyObject *py_unreal_engine_tick_rendering_tickables(PyObject * self, PyObject * args) { Py_BEGIN_ALLOW_THREADS; TickRenderingTickables(); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } PyObject *py_unreal_engine_get_delta_time(PyObject * self, PyObject * args) { return PyFloat_FromDouble(FApp::GetDeltaTime()); } PyObject *py_unreal_engine_find_object(PyObject * self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:find_object", &name)) { return NULL; } UObject *u_object = FindObject(ANY_PACKAGE, UTF8_TO_TCHAR(name)); if (!u_object) return PyErr_Format(PyExc_Exception, "unable to find object %s", name); Py_RETURN_UOBJECT(u_object); } PyObject *py_unreal_engine_new_object(PyObject * self, PyObject * args) { PyObject *obj; PyObject *py_outer = NULL; char *name = nullptr; uint64 flags = (uint64)(RF_Public); if (!PyArg_ParseTuple(args, "O|OsK:new_object", &obj, &py_outer, &name, &flags)) { return nullptr; } UClass *obj_class = ue_py_check_type(obj); if (!obj_class) return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); FName f_name = NAME_None; if (name && strlen(name) > 0) { f_name = FName(UTF8_TO_TCHAR(name)); } UObject *outer = GetTransientPackage(); if (py_outer && py_outer != Py_None) { outer = ue_py_check_type(py_outer); if (!outer) return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } UObject *new_object = nullptr; Py_BEGIN_ALLOW_THREADS; new_object = NewObject(outer, obj_class, f_name, (EObjectFlags)flags); if (new_object) new_object->PostLoad(); Py_END_ALLOW_THREADS; if (!new_object) return PyErr_Format(PyExc_Exception, "unable to create object"); Py_RETURN_UOBJECT(new_object); } PyObject *py_unreal_engine_get_mutable_default(PyObject * self, PyObject * args) { PyObject *obj; if (!PyArg_ParseTuple(args, "O|Os:get_mutable_default", &obj)) { return NULL; } if (!ue_is_pyuobject(obj)) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } ue_PyUObject *py_obj = (ue_PyUObject *)obj; if (!py_obj->ue_object->IsA()) return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); UClass *obj_class = (UClass *)py_obj->ue_object; UObject *mutable_object = GetMutableDefault(obj_class); if (!mutable_object) return PyErr_Format(PyExc_Exception, "unable to create object"); Py_RETURN_UOBJECT(mutable_object); } PyObject *py_unreal_engine_new_class(PyObject * self, PyObject * args) { PyObject *py_parent; char *name; if (!PyArg_ParseTuple(args, "Os:new_class", &py_parent, &name)) { return NULL; } UClass *parent = nullptr; if (py_parent != Py_None) { if (!ue_is_pyuobject(py_parent)) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } ue_PyUObject *py_obj = (ue_PyUObject *)py_parent; if (!py_obj->ue_object->IsA()) return PyErr_Format(PyExc_Exception, "uobject is not a UClass"); parent = (UClass *)py_obj->ue_object; } UClass *new_object = unreal_engine_new_uclass(name, parent); if (!new_object) return PyErr_Format(PyExc_Exception, "unable to create UClass"); Py_RETURN_UOBJECT(new_object); } PyObject *py_unreal_engine_all_classes(PyObject * self, PyObject * args) { PyObject *ret = PyList_New(0); for (TObjectIterator Itr; Itr; ++Itr) { ue_PyUObject *py_obj = ue_get_python_uobject(*Itr); if (!py_obj) continue; PyList_Append(ret, (PyObject *)py_obj); } return ret; } PyObject *py_unreal_engine_all_worlds(PyObject * self, PyObject * args) { PyObject *ret = PyList_New(0); for (TObjectIterator Itr; Itr; ++Itr) { ue_PyUObject *py_obj = ue_get_python_uobject(*Itr); if (!py_obj) continue; PyList_Append(ret, (PyObject *)py_obj); } return ret; } PyObject *py_unreal_engine_tobject_iterator(PyObject * self, PyObject * args) { PyObject *py_class; if (!PyArg_ParseTuple(args, "O:tobject_iterator", &py_class)) { return NULL; } UClass *u_class = ue_py_check_type(py_class); if (!u_class) { return PyErr_Format(PyExc_TypeError, "argument is not a UClass"); } PyObject *ret = PyList_New(0); for (TObjectIterator Itr; Itr; ++Itr) { if (!(*Itr)->IsA(u_class)) continue; ue_PyUObject *py_obj = ue_get_python_uobject(*Itr); if (!py_obj) continue; PyList_Append(ret, (PyObject *)py_obj); } return ret; } PyObject *py_unreal_engine_create_and_dispatch_when_ready(PyObject * self, PyObject * args) { PyObject *py_callable; if (!PyArg_ParseTuple(args, "O:create_and_dispatch_when_ready", &py_callable)) { return NULL; } if (!PyCallable_Check(py_callable)) return PyErr_Format(PyExc_TypeError, "argument is not callable"); Py_INCREF(py_callable); FGraphEventRef task = FFunctionGraphTask::CreateAndDispatchWhenReady([&]() { FScopePythonGIL gil; PyObject *ret = PyObject_CallObject(py_callable, nullptr); if (ret) { Py_DECREF(ret); } else { unreal_engine_py_log_error(); } Py_DECREF(py_callable); }, TStatId(), nullptr, ENamedThreads::GameThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(task); // TODO Implement signal triggering in addition to WaitUntilTaskCompletes // FTaskGraphInterface::Get().TriggerEventWhenTaskCompletes Py_INCREF(Py_None); return Py_None; } PyObject *py_unreal_engine_get_game_viewport_size(PyObject *self, PyObject * args) { if (!GEngine->GameViewport) { return PyErr_Format(PyExc_Exception, "unable to get GameViewport"); } FVector2D size; GEngine->GameViewport->GetViewportSize(size); return Py_BuildValue("(ff)", size.X, size.Y); } PyObject *py_unreal_engine_get_resolution(PyObject *self, PyObject * args) { return Py_BuildValue("(ff)", GSystemResolution.ResX, GSystemResolution.ResY); } PyObject *py_unreal_engine_get_viewport_screenshot(PyObject *self, PyObject * args) { if (!GEngine->GameViewport) { Py_INCREF(Py_None); return Py_None; } PyObject *py_bool = nullptr; bool as_int_list = false; if (!PyArg_ParseTuple(args, "|O:get_viewport_screenshot", &py_bool)) { return NULL; } if (py_bool && PyObject_IsTrue(py_bool)) as_int_list = true; FViewport *viewport = GEngine->GameViewport->Viewport; TArray bitmap; bool success = GetViewportScreenShot(viewport, bitmap); if (!success) { Py_INCREF(Py_None); return Py_None; } if (as_int_list) { PyObject *bitmap_tuple = PyTuple_New(bitmap.Num() * 4); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i * 4, PyLong_FromLong(bitmap[i].R)); PyTuple_SetItem(bitmap_tuple, i * 4 + 1, PyLong_FromLong(bitmap[i].G)); PyTuple_SetItem(bitmap_tuple, i * 4 + 2, PyLong_FromLong(bitmap[i].B)); PyTuple_SetItem(bitmap_tuple, i * 4 + 3, PyLong_FromLong(bitmap[i].A)); } return bitmap_tuple; } PyObject *bitmap_tuple = PyTuple_New(bitmap.Num()); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i, py_ue_new_fcolor(bitmap[i])); } return bitmap_tuple; } PyObject *py_unreal_engine_get_viewport_size(PyObject *self, PyObject * args) { if (!GEngine->GameViewport) { Py_INCREF(Py_None); return Py_None; } FViewport *viewport = GEngine->GameViewport->Viewport; PyObject *tuple_size = PyTuple_New(2); FIntPoint point = viewport->GetSizeXY(); PyTuple_SetItem(tuple_size, 0, PyLong_FromLong(point.X)); PyTuple_SetItem(tuple_size, 1, PyLong_FromLong(point.Y)); return tuple_size; } #if WITH_EDITOR PyObject *py_unreal_engine_editor_get_active_viewport_screenshot(PyObject *self, PyObject * args) { FViewport *viewport = GEditor->GetActiveViewport(); if (!viewport) { Py_INCREF(Py_None); return Py_None; } PyObject *py_bool = nullptr; bool as_int_list = false; if (!PyArg_ParseTuple(args, "|O:editor_get_active_viewport_screenshot", &py_bool)) { return NULL; } if (py_bool && PyObject_IsTrue(py_bool)) as_int_list = true; TArray bitmap; bool success = GetViewportScreenShot(viewport, bitmap); if (!success) { Py_INCREF(Py_None); return Py_None; } if (as_int_list) { PyObject *bitmap_tuple = PyTuple_New(bitmap.Num() * 4); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i * 4, PyLong_FromLong(bitmap[i].R)); PyTuple_SetItem(bitmap_tuple, i * 4 + 1, PyLong_FromLong(bitmap[i].G)); PyTuple_SetItem(bitmap_tuple, i * 4 + 2, PyLong_FromLong(bitmap[i].B)); PyTuple_SetItem(bitmap_tuple, i * 4 + 3, PyLong_FromLong(bitmap[i].A)); } return bitmap_tuple; } PyObject *bitmap_tuple = PyTuple_New(bitmap.Num()); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i, py_ue_new_fcolor(bitmap[i])); } return bitmap_tuple; } PyObject *py_unreal_engine_editor_get_active_viewport_size(PyObject *self, PyObject * args) { FViewport *viewport = GEditor->GetActiveViewport(); if (!viewport) { Py_INCREF(Py_None); return Py_None; } PyObject *tuple_size = PyTuple_New(2); FIntPoint point = viewport->GetSizeXY(); PyTuple_SetItem(tuple_size, 0, PyLong_FromLong(point.X)); PyTuple_SetItem(tuple_size, 1, PyLong_FromLong(point.Y)); return tuple_size; } PyObject *py_unreal_engine_editor_get_pie_viewport_screenshot(PyObject *self, PyObject * args) { FViewport *viewport = GEditor->GetPIEViewport(); if (!viewport) { Py_INCREF(Py_None); return Py_None; } PyObject *py_bool = nullptr; bool as_int_list = false; if (!PyArg_ParseTuple(args, "|O:editor_get_pie_viewport_screenshot", &py_bool)) { return NULL; } if (py_bool && PyObject_IsTrue(py_bool)) as_int_list = true; TArray bitmap; bool success = GetViewportScreenShot(viewport, bitmap); if (!success) { Py_INCREF(Py_None); return Py_None; } if (as_int_list) { PyObject *bitmap_tuple = PyTuple_New(bitmap.Num() * 4); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i * 4, PyLong_FromLong(bitmap[i].R)); PyTuple_SetItem(bitmap_tuple, i * 4 + 1, PyLong_FromLong(bitmap[i].G)); PyTuple_SetItem(bitmap_tuple, i * 4 + 2, PyLong_FromLong(bitmap[i].B)); PyTuple_SetItem(bitmap_tuple, i * 4 + 3, PyLong_FromLong(bitmap[i].A)); } return bitmap_tuple; } PyObject *bitmap_tuple = PyTuple_New(bitmap.Num()); for (int i = 0; i < bitmap.Num(); i++) { PyTuple_SetItem(bitmap_tuple, i, py_ue_new_fcolor(bitmap[i])); } return bitmap_tuple; } PyObject *py_unreal_engine_editor_get_pie_viewport_size(PyObject *self, PyObject * args) { FViewport *viewport = GEditor->GetPIEViewport(); if (!viewport) { Py_INCREF(Py_None); return Py_None; } PyObject *tuple_size = PyTuple_New(2); FIntPoint point = viewport->GetSizeXY(); PyTuple_SetItem(tuple_size, 0, PyLong_FromLong(point.X)); PyTuple_SetItem(tuple_size, 1, PyLong_FromLong(point.Y)); return tuple_size; } #endif PyObject *py_unreal_engine_create_package(PyObject *self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:create_package", &name)) { return nullptr; } UPackage *u_package = (UPackage *)StaticFindObject(nullptr, ANY_PACKAGE, UTF8_TO_TCHAR(name), true); // create a new package if it does not exist if (u_package) { return PyErr_Format(PyExc_Exception, "package %s already exists", TCHAR_TO_UTF8(*u_package->GetPathName())); } u_package = CreatePackage(nullptr, UTF8_TO_TCHAR(name)); if (!u_package) return PyErr_Format(PyExc_Exception, "unable to create package"); u_package->FileName = *FPackageName::LongPackageNameToFilename(UTF8_TO_TCHAR(name), FPackageName::GetAssetPackageExtension()); u_package->FullyLoad(); u_package->MarkPackageDirty(); Py_RETURN_UOBJECT(u_package); } PyObject *py_unreal_engine_get_or_create_package(PyObject *self, PyObject * args) { char *name; if (!PyArg_ParseTuple(args, "s:get_or_create_package", &name)) { return nullptr; } UPackage *u_package = (UPackage *)StaticFindObject(nullptr, ANY_PACKAGE, UTF8_TO_TCHAR(name), true); // create a new package if it does not exist if (!u_package) { u_package = CreatePackage(nullptr, UTF8_TO_TCHAR(name)); if (!u_package) return PyErr_Format(PyExc_Exception, "unable to create package"); u_package->FileName = *FPackageName::LongPackageNameToFilename(UTF8_TO_TCHAR(name), FPackageName::GetAssetPackageExtension()); u_package->FullyLoad(); u_package->MarkPackageDirty(); } Py_RETURN_UOBJECT(u_package); } PyObject *py_unreal_engine_get_transient_package(PyObject *self, PyObject * args) { Py_RETURN_UOBJECT(GetTransientPackage()); } PyObject *py_unreal_engine_open_file_dialog(PyObject *self, PyObject * args) { char *title; char *default_path = (char *)""; char *default_file = (char *)""; char *file_types = (char *)""; PyObject *py_multiple = nullptr; if (!PyArg_ParseTuple(args, "s|sssO:open_file_dialog", &title, &default_path, &default_file, &file_types, &py_multiple)) return nullptr; IDesktopPlatform *DesktopPlatform = FDesktopPlatformModule::Get(); if (!DesktopPlatform) return PyErr_Format(PyExc_Exception, "unable to get reference to DesktopPlatform module"); TSharedPtr ParentWindow = FGlobalTabmanager::Get()->GetRootWindow(); if (!ParentWindow.IsValid()) return PyErr_Format(PyExc_Exception, "unable to get the Root Window"); if (!ParentWindow->GetNativeWindow().IsValid()) return PyErr_Format(PyExc_Exception, "unable to get Native Root Window"); TArray files; if (!DesktopPlatform->OpenFileDialog(ParentWindow->GetNativeWindow()->GetOSWindowHandle(), FString(UTF8_TO_TCHAR(title)), FString(UTF8_TO_TCHAR(default_path)), FString(UTF8_TO_TCHAR(default_file)), FString(UTF8_TO_TCHAR(file_types)), (py_multiple && PyObject_IsTrue(py_multiple)) ? EFileDialogFlags::Multiple : EFileDialogFlags::None, files)) { Py_RETURN_NONE; } PyObject *py_list = PyList_New(0); for (FString file : files) { PyList_Append(py_list, PyUnicode_FromString(TCHAR_TO_UTF8(*file))); } return py_list; } PyObject *py_unreal_engine_open_directory_dialog(PyObject *self, PyObject * args) { char *title; char *default_path = (char *)""; if (!PyArg_ParseTuple(args, "s|s:open_directory_dialog", &title, &default_path)) return nullptr; IDesktopPlatform *DesktopPlatform = FDesktopPlatformModule::Get(); if (!DesktopPlatform) return PyErr_Format(PyExc_Exception, "unable to get reference to DesktopPlatform module"); TSharedPtr ParentWindow = FGlobalTabmanager::Get()->GetRootWindow(); if (!ParentWindow.IsValid()) return PyErr_Format(PyExc_Exception, "unable to get the Root Window"); if (!ParentWindow->GetNativeWindow().IsValid()) return PyErr_Format(PyExc_Exception, "unable to get Native Root Window"); FString choosen_dir; if (!DesktopPlatform->OpenDirectoryDialog(ParentWindow->GetNativeWindow()->GetOSWindowHandle(), FString(UTF8_TO_TCHAR(title)), FString(UTF8_TO_TCHAR(default_path)), choosen_dir)) { Py_RETURN_NONE; } return PyUnicode_FromString(TCHAR_TO_UTF8(*choosen_dir)); } PyObject *py_unreal_engine_open_font_dialog(PyObject *self, PyObject * args) { IDesktopPlatform *DesktopPlatform = FDesktopPlatformModule::Get(); if (!DesktopPlatform) return PyErr_Format(PyExc_Exception, "unable to get reference to DesktopPlatform module"); TSharedPtr ParentWindow = FGlobalTabmanager::Get()->GetRootWindow(); if (!ParentWindow.IsValid()) return PyErr_Format(PyExc_Exception, "unable to get the Root Window"); if (!ParentWindow->GetNativeWindow().IsValid()) return PyErr_Format(PyExc_Exception, "unable to get Native Root Window"); FString font_name; float height; EFontImportFlags flags; if (!DesktopPlatform->OpenFontDialog(ParentWindow->GetNativeWindow()->GetOSWindowHandle(), font_name, height, flags)) { Py_RETURN_NONE; } return Py_BuildValue((char*)"(sfi)", TCHAR_TO_UTF8(*font_name), height, flags); } PyObject *py_unreal_engine_save_file_dialog(PyObject *self, PyObject * args) { char *title; char *default_path = (char *)""; char *default_file = (char *)""; char *file_types = (char *)""; PyObject *py_multiple = nullptr; if (!PyArg_ParseTuple(args, "s|sssO:save_file_dialog", &title, &default_path, &default_file, &file_types, &py_multiple)) return nullptr; IDesktopPlatform *DesktopPlatform = FDesktopPlatformModule::Get(); if (!DesktopPlatform) return PyErr_Format(PyExc_Exception, "unable to get reference to DesktopPlatform module"); TSharedPtr ParentWindow = FGlobalTabmanager::Get()->GetRootWindow(); if (!ParentWindow.IsValid()) return PyErr_Format(PyExc_Exception, "unable to get the Root Window"); if (!ParentWindow->GetNativeWindow().IsValid()) return PyErr_Format(PyExc_Exception, "unable to get Native Root Window"); TArray files; if (!DesktopPlatform->SaveFileDialog(ParentWindow->GetNativeWindow()->GetOSWindowHandle(), FString(UTF8_TO_TCHAR(title)), FString(UTF8_TO_TCHAR(default_path)), FString(UTF8_TO_TCHAR(default_file)), FString(UTF8_TO_TCHAR(file_types)), (py_multiple && PyObject_IsTrue(py_multiple)) ? EFileDialogFlags::Multiple : EFileDialogFlags::None, files)) { Py_RETURN_NONE; } PyObject *py_list = PyList_New(0); for (FString file : files) { PyList_Append(py_list, PyUnicode_FromString(TCHAR_TO_UTF8(*file))); } return py_list; } PyObject *py_unreal_engine_copy_properties_for_unrelated_objects(PyObject * self, PyObject * args, PyObject *kwargs) { PyObject *old_py_object; PyObject *new_py_object; PyObject *py_aggressive_default_subobject_replacement = nullptr; PyObject *py_copy_deprecated_properties = nullptr; PyObject *py_do_delta = nullptr; PyObject *py_notify_object_replacement = nullptr; PyObject *py_preserve_root_component = nullptr; PyObject *py_replace_object_class_references = nullptr; PyObject *py_skip_compiler_generated_defaults = nullptr; static char *kw_names[] = { (char *)"old_object", (char *)"new_object", (char *)"aggressive_default_subobject_replacement", (char *)"copy_deprecated_properties", (char *)"do_delta", (char *)"notify_object_replacement", (char *)"preserve_root_component", (char *)"replace_object_class_references", (char *)"skip_compiler_generated_defaults", nullptr }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|OOOOOOO:copy_properties_for_unrelated_objects", kw_names, &old_py_object, &new_py_object, &py_aggressive_default_subobject_replacement, &py_copy_deprecated_properties, &py_do_delta, &py_notify_object_replacement, &py_preserve_root_component, &py_replace_object_class_references, &py_skip_compiler_generated_defaults)) { return nullptr; } UObject *old_object = ue_py_check_type(old_py_object); if (!old_object) return PyErr_Format(PyExc_Exception, "argument is not a UObject"); UObject *new_object = ue_py_check_type(new_py_object); if (!new_object) return PyErr_Format(PyExc_Exception, "argument is not a UObject"); UEngine::FCopyPropertiesForUnrelatedObjectsParams params; params.bAggressiveDefaultSubobjectReplacement = (py_aggressive_default_subobject_replacement && PyObject_IsTrue(py_aggressive_default_subobject_replacement)); params.bCopyDeprecatedProperties = (py_copy_deprecated_properties && PyObject_IsTrue(py_copy_deprecated_properties)); params.bDoDelta = (py_do_delta && PyObject_IsTrue(py_do_delta)); params.bNotifyObjectReplacement = (py_notify_object_replacement && PyObject_IsTrue(py_notify_object_replacement)); params.bPreserveRootComponent = (py_preserve_root_component && PyObject_IsTrue(py_preserve_root_component)); params.bReplaceObjectClassReferences = (py_replace_object_class_references && PyObject_IsTrue(py_replace_object_class_references)); params.bSkipCompilerGeneratedDefaults = (py_skip_compiler_generated_defaults && PyObject_IsTrue(py_skip_compiler_generated_defaults)); GEngine->CopyPropertiesForUnrelatedObjects( old_object, new_object, params); Py_RETURN_NONE; } PyObject *py_unreal_engine_set_random_seed(PyObject * self, PyObject * args) { int seed; if (!PyArg_ParseTuple(args, "i:set_random_seed", &seed)) { return nullptr; } // Thanks to Sven Mika (Ducandu GmbH) for spotting this FMath::RandInit(seed); FGenericPlatformMath::SRandInit(seed); FGenericPlatformMath::RandInit(seed); Py_RETURN_NONE; } PyObject *py_unreal_engine_clipboard_copy(PyObject * self, PyObject * args) { char *text; if (!PyArg_ParseTuple(args, "s:clipboard_copy", &text)) { return nullptr; } #if ENGINE_MINOR_VERSION >= 18 FPlatformApplicationMisc::ClipboardCopy(UTF8_TO_TCHAR(text)); #else FGenericPlatformMisc::ClipboardCopy(UTF8_TO_TCHAR(text)); #endif Py_RETURN_NONE; } PyObject *py_unreal_engine_clipboard_paste(PyObject * self, PyObject * args) { FString clipboard; #if ENGINE_MINOR_VERSION >= 18 FPlatformApplicationMisc::ClipboardPaste(clipboard); #else FGenericPlatformMisc::ClipboardPaste(clipboard); #endif return PyUnicode_FromString(TCHAR_TO_UTF8(*clipboard)); }