Skip to content

Commit 4a7a3f4

Browse files
author
David
committed
Updated to use FProperty/FFieldClass instead of UProperty.
Currently builds (4.18 and 4.25) and some examples seem to run OK. This requires some changes to the example scripts. Started from Support4.25 pull req but now highly modified.
1 parent b76e101 commit 4a7a3f4

16 files changed

+3355
-184
lines changed

Source/UnrealEnginePython/Private/PythonDelegate.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ void UPythonDelegate::ProcessEvent(UFunction *function, void *Parms)
3737
py_args = PyTuple_New(signature->NumParms);
3838
Py_ssize_t argn = 0;
3939

40+
#if ENGINE_MINOR_VERSION >= 25
41+
TFieldIterator<FProperty> PArgs(signature);
42+
#else
4043
TFieldIterator<UProperty> PArgs(signature);
44+
#endif
4145
for (; PArgs && argn < signature->NumParms && ((PArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++PArgs)
4246
{
47+
#if ENGINE_MINOR_VERSION >= 25
48+
FProperty *prop = *PArgs;
49+
#else
4350
UProperty *prop = *PArgs;
51+
#endif
4452
PyObject *arg = ue_py_convert_property(prop, (uint8 *)Parms, 0);
4553
if (!arg)
4654
{
@@ -63,7 +71,11 @@ void UPythonDelegate::ProcessEvent(UFunction *function, void *Parms)
6371
// currently useless as events do not return a value
6472
/*
6573
if (signature_set) {
74+
#if ENGINE_MINOR_VERSION >= 25
75+
FProperty *return_property = signature->GetReturnProperty();
76+
#else
6677
UProperty *return_property = signature->GetReturnProperty();
78+
#endif
6779
if (return_property && signature->ReturnValueOffset != MAX_uint16) {
6880
if (!ue_py_convert_pyobject(ret, return_property, (uint8 *)Parms)) {
6981
UE_LOG(LogPython, Error, TEXT("Invalid return value type for delegate"));

Source/UnrealEnginePython/Private/PythonFunction.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
3030

3131
// count the number of arguments
3232
Py_ssize_t argn = (Context && !is_static) ? 1 : 0;
33+
#if ENGINE_MINOR_VERSION >= 25
34+
TFieldIterator<FProperty> IArgs(function);
35+
#else
3336
TFieldIterator<UProperty> IArgs(function);
37+
#endif
3438
for (; IArgs && ((IArgs->PropertyFlags & (CPF_Parm | CPF_ReturnParm)) == CPF_Parm); ++IArgs) {
3539
argn++;
3640
}
@@ -56,7 +60,11 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
5660

5761
// is it a blueprint call ?
5862
if (*Stack.Code == EX_EndFunctionParms) {
63+
#if ENGINE_MINOR_VERSION >= 25
64+
for (FProperty *prop = (FProperty *)function->ChildProperties; prop; prop = (FProperty *)prop->Next) {
65+
#else
5966
for (UProperty *prop = (UProperty *)function->Children; prop; prop = (UProperty *)prop->Next) {
67+
#endif
6068
if (prop->PropertyFlags & CPF_ReturnParm)
6169
continue;
6270
if (!on_error) {
@@ -75,7 +83,11 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
7583
//UE_LOG(LogPython, Warning, TEXT("BLUEPRINT CALL"));
7684
frame = (uint8 *)FMemory_Alloca(function->PropertiesSize);
7785
FMemory::Memzero(frame, function->PropertiesSize);
86+
#if ENGINE_MINOR_VERSION >= 25
87+
for (FProperty *prop = (FProperty *)function->ChildProperties; *Stack.Code != EX_EndFunctionParms; prop = (FProperty *)prop->Next) {
88+
#else
7889
for (UProperty *prop = (UProperty *)function->Children; *Stack.Code != EX_EndFunctionParms; prop = (UProperty *)prop->Next) {
90+
#endif
7991
Stack.Step(Stack.Object, prop->ContainerPtrToValuePtr<uint8>(frame));
8092
if (prop->PropertyFlags & CPF_ReturnParm)
8193
continue;
@@ -107,7 +119,11 @@ void UPythonFunction::CallPythonCallable(FFrame& Stack, RESULT_DECL)
107119
}
108120

109121
// get return value (if required)
122+
#if ENGINE_MINOR_VERSION >= 25
123+
FProperty *return_property = function->GetReturnProperty();
124+
#else
110125
UProperty *return_property = function->GetReturnProperty();
126+
#endif
111127
if (return_property && function->ReturnValueOffset != MAX_uint16) {
112128
#if defined(UEPY_MEMORY_DEBUG)
113129
UE_LOG(LogPython, Warning, TEXT("FOUND RETURN VALUE"));

Source/UnrealEnginePython/Private/UEPyAssetUserData.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ PyObject *py_ue_asset_import_data(ue_PyUObject * self, PyObject * args)
88
ue_py_check(self);
99

1010
UStruct *u_struct = (UStruct *)self->ue_object->GetClass();
11+
#if ENGINE_MINOR_VERSION >= 25
12+
FClassProperty *f_property = (FClassProperty *)u_struct->FindPropertyByName(TEXT("AssetImportData"));
13+
if (!f_property)
14+
#else
1115
UClassProperty *u_property = (UClassProperty *)u_struct->FindPropertyByName(TEXT("AssetImportData"));
1216
if (!u_property)
17+
#endif
1318
{
1419
return PyErr_Format(PyExc_Exception, "UObject does not have asset import data.");
1520

1621
}
22+
#if ENGINE_MINOR_VERSION >= 25
23+
UAssetImportData *import_data = (UAssetImportData *)f_property->GetPropertyValue_InContainer(self->ue_object);
24+
#else
1725
UAssetImportData *import_data = (UAssetImportData *)u_property->GetPropertyValue_InContainer(self->ue_object);
26+
#endif
1827
FAssetImportInfo *import_info = &import_data->SourceData;
1928
PyObject *ret = PyList_New(import_info->SourceFiles.Num());
2029
for (int i = 0; i < import_info->SourceFiles.Num(); i++)
@@ -47,8 +56,13 @@ PyObject *py_ue_asset_import_data_set_sources(ue_PyUObject * self, PyObject * ar
4756
TArray<FString> filenames;
4857

4958
UStruct *u_struct = (UStruct *)self->ue_object->GetClass();
59+
#if ENGINE_MINOR_VERSION >= 25
60+
FClassProperty *f_property = (FClassProperty *)u_struct->FindPropertyByName(TEXT("AssetImportData"));
61+
if (!f_property)
62+
#else
5063
UClassProperty *u_property = (UClassProperty *)u_struct->FindPropertyByName(TEXT("AssetImportData"));
5164
if (!u_property)
65+
#endif
5266
{
5367
return PyErr_Format(PyExc_Exception, "UObject does not have asset import data.");
5468
}
@@ -79,7 +93,11 @@ PyObject *py_ue_asset_import_data_set_sources(ue_PyUObject * self, PyObject * ar
7993
}
8094

8195

96+
#if ENGINE_MINOR_VERSION >= 25
97+
UAssetImportData *import_data = (UAssetImportData *)f_property->GetPropertyValue_InContainer(self->ue_object);
98+
#else
8299
UAssetImportData *import_data = (UAssetImportData *)u_property->GetPropertyValue_InContainer(self->ue_object);
100+
#endif
83101
FAssetImportInfo *import_info = &import_data->SourceData;
84102

85103
TArray<FAssetImportInfo::FSourceFile> sources;

Source/UnrealEnginePython/Private/UEPyEngine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,10 @@ PyObject *py_unreal_engine_new_object(PyObject * self, PyObject * args)
593593
outer = ue_py_check_type<UObject>(py_outer);
594594
if (!outer)
595595
return PyErr_Format(PyExc_Exception, "argument is not a UObject");
596+
EXTRA_UE_LOG(LogPython, Warning, TEXT("object creation outer is %s"), *outer->GetName());
596597
}
597598

599+
598600
UObject *new_object = nullptr;
599601
Py_BEGIN_ALLOW_THREADS;
600602
new_object = NewObject<UObject>(outer, obj_class, f_name, (EObjectFlags)flags);
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include "UEPyFPropertiesImporter.h"
2+
3+
4+
#if ENGINE_MINOR_VERSION >= 25
5+
6+
7+
static PyObject *ue_PyFPropertiesImporter_getattro(ue_PyFPropertiesImporter *self, PyObject *attr_name)
8+
{
9+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer called"));
10+
PyObject *py_attr = PyObject_GenericGetAttr((PyObject *)self, attr_name);
11+
if (!py_attr)
12+
{
13+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer attr OK"));
14+
if (PyUnicodeOrString_Check(attr_name))
15+
{
16+
const char *attr = UEPyUnicode_AsUTF8(attr_name);
17+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer attr is string %s"), UTF8_TO_TCHAR(attr));
18+
if (attr[0] != '_')
19+
{
20+
// dont know what to do here
21+
// no - as far as I can see we cannot search for property classes anymore
22+
// we have to explicitly add them
23+
// - so do we need this - just import the explicit property wrap
24+
// actually this would have to be the property class wrap
25+
26+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer field classes %d"), FFieldClass::GetAllFieldClasses().Num());
27+
//for (const FFieldClass* FieldClass : FFieldClass::GetAllFieldClasses())
28+
//{
29+
// EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer field classes %s"), *FieldClass->GetName());
30+
//}
31+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer field classes map %d"), FFieldClass::GetNameToFieldClassMap().Num());
32+
33+
// so apparently there is a map of all field classes and this is how we can look it up
34+
FName FieldTypeStr = FName(UTF8_TO_TCHAR(attr));
35+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer looking for %s"), *FieldTypeStr.ToString());
36+
FFieldClass** f_class_ptr = FFieldClass::GetNameToFieldClassMap().Find(FieldTypeStr);
37+
if (f_class_ptr)
38+
{
39+
EXTRA_UE_LOG(LogPython, Warning, TEXT("magic properties importer found class"));
40+
// swallow old exception
41+
PyErr_Clear();
42+
// if we create python wrapper each time then think we dont want the extra inc ref
43+
// - PyObject_New has already incremented new python objects ref count
44+
// actually this may be OK - we only see this for import statements
45+
// which in general are only done once - so this wrapper will last for lifetime
46+
// of python script - except if we have multiple scripts we will get a different wrapper
47+
// in each script
48+
Py_RETURN_FFIELDCLASS_NOINC(*f_class_ptr);
49+
}
50+
51+
//UClass *u_class = FindObject<UClass>(ANY_PACKAGE, UTF8_TO_TCHAR(attr));
52+
//if (u_class)
53+
//{
54+
// // swallow old exception
55+
// PyErr_Clear();
56+
// Py_RETURN_UOBJECT(u_class);
57+
//}
58+
59+
}
60+
}
61+
}
62+
return py_attr;
63+
}
64+
65+
static PyTypeObject ue_PyFPropertiesImporterType = {
66+
PyVarObject_HEAD_INIT(NULL, 0)
67+
"unreal_engine.FPropertiesImporter", /* tp_name */
68+
sizeof(ue_PyFPropertiesImporter), /* tp_basicsize */
69+
0, /* tp_itemsize */
70+
0, /* tp_dealloc */
71+
0, /* tp_print */
72+
0, /* tp_getattr */
73+
0, /* tp_setattr */
74+
0, /* tp_reserved */
75+
0, /* tp_repr */
76+
0, /* tp_as_number */
77+
0, /* tp_as_sequence */
78+
0, /* tp_as_mapping */
79+
0, /* tp_hash */
80+
0, /* tp_call */
81+
0, /* tp_str */
82+
(getattrofunc)ue_PyFPropertiesImporter_getattro, /* tp_getattro */
83+
0, /* tp_setattro */
84+
0, /* tp_as_buffer */
85+
Py_TPFLAGS_DEFAULT, /* tp_flags */
86+
"Unreal Engine FProperties Importer", /* tp_doc */
87+
0, /* tp_traverse */
88+
0, /* tp_clear */
89+
0, /* tp_richcompare */
90+
0, /* tp_weaklistoffset */
91+
0, /* tp_iter */
92+
0, /* tp_iternext */
93+
0, /* tp_methods */
94+
0,
95+
0,
96+
};
97+
98+
void ue_python_init_fpropertiesimporter(PyObject *ue_module)
99+
{
100+
ue_PyFPropertiesImporterType.tp_new = PyType_GenericNew;
101+
102+
if (PyType_Ready(&ue_PyFPropertiesImporterType) < 0)
103+
return;
104+
105+
Py_INCREF(&ue_PyFPropertiesImporterType);
106+
PyModule_AddObject(ue_module, "PropertiesImporter", (PyObject *)&ue_PyFPropertiesImporterType);
107+
}
108+
109+
PyObject *py_ue_new_fpropertiesimporter()
110+
{
111+
ue_PyFPropertiesImporter *ret = (ue_PyFPropertiesImporter *)PyObject_New(ue_PyFPropertiesImporter, &ue_PyFPropertiesImporterType);
112+
return (PyObject *)ret;
113+
}
114+
115+
116+
#endif
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
4+
5+
#include "UEPyModule.h"
6+
7+
#if ENGINE_MINOR_VERSION >= 25
8+
9+
#include "Runtime/CoreUObject/Public/UObject/Field.h"
10+
11+
// as properties no longer UObjects they wont get imported by the UObjects classes importer
12+
13+
// - this does mean all scripts will need some editing
14+
// - for the moment have to live with this until have some working properties
15+
16+
// as now there is no longer any way I can see so far of getting a list of property classes
17+
// defined we will have to have wrappers for each known property class
18+
// WRONG - there is apparently a list of FFieldClass classes accessed either as
19+
// FFieldClass::GetAllFieldClasses() or a TMap FFieldClass::GetNameToFieldClassMap()
20+
21+
typedef struct
22+
{
23+
PyObject_HEAD
24+
/* Type-specific fields go here. */
25+
} ue_PyFPropertiesImporter;
26+
27+
PyObject *py_ue_new_fpropertiesimporter();
28+
29+
void ue_python_init_fpropertiesimporter(PyObject *);
30+
31+
32+
#endif

0 commit comments

Comments
 (0)