20tab / UnrealEnginePython

Embed Python in Unreal Engine 4
MIT License
2.76k stars 750 forks source link

Struct values returning garbage when accessed from Python #632

Open mrpropellers opened 5 years ago

mrpropellers commented 5 years ago

Using tagged release for commit 56a6f304 built from source, UE 4.18, and Python 3.4 on Windows 10. I have a USTRUCT which is a member of a UCLASS defined like so:

USTRUCT(BlueprintType)
struct FCartPoint
{
GENERATED_STRUCT_BODY()

UPROPERTY(BlueprintReadonly)
int x;

UPROPERTY(BlueprintReadonly)
int y;
// + some constructors/accessors etc.
}

UCLASS()
class PROJECT_API APointHolder : public AActor
{
GENERATED_BODY()
protected:
FCartPoint MyPoint;

public:
UFUNCTION(BlueprintCallable)
FCartPoint GetPoint() const {
  UE_LOG(LogTemp, Log, TEXT("Point: (%d, %d)"), MyPoint.x, MyPoint.y)
  return MyPoint;
}
}

In Python doing this:

p = actor.GetPoint()
ue.log("p by members: (%d, %d) -- p by get_field: (%d, %d)" % (p.x, p.y, p.get_field('x'), p.get_field('y')))

When ran, the log output from GetPoint prints the values I've assigned, but all the values printed from python appear to just be random blocks of memory typecast to int, and p.x != p.get_field('x') - they appear to be pointing at different locations as the values it spits out are unrelated.

dfb commented 5 years ago

FWIW, this problem also causes UE4 to crash if the struct contains properties that are in turn pointers to other things (e.g. if you have a struct with an FString property).

I fixed it locally by changing UEPyModule.cpp's ue_py_convert_property function to call py_ue_new_owned_uscriptstruct instead of py_ue_new_uscriptstruct. Not sure if that's the correct fix or not, but so far it seems to be working in every case that was previously failing.

--- a/Source/UnrealEnginePython/Private/UEPyModule.cpp
+++ b/Source/UnrealEnginePython/Private/UEPyModule.cpp
@@ -2143,7 +2143,7 @@ PyObject *ue_py_convert_property(UProperty *prop, uint8 *buffer, int32 index)
                                FLinearColor color = *casted_prop->ContainerPtrToValuePtr<FLinearColor>(buffer, index);
                                return py_ue_new_flinearcolor(color);
                        }
-                       return py_ue_new_uscriptstruct(casted_struct, casted_prop->ContainerPtrToValuePtr<uint8>(buffer, index));
+                       return py_ue_new_owned_uscriptstruct(casted_struct, casted_prop->ContainerPtrToValuePtr<uint8>(buffer, index));
                }
                return PyErr_Format(PyExc_TypeError, "unsupported UStruct type");
        }
mrpropellers commented 5 years ago

Applying that patch seems to have fixed the case that was failing in my regression tests as well, thanks! Hopefully this can get merged in soon.