Skip to content

Commit

Permalink
fixes from modus
Browse files Browse the repository at this point in the history
  • Loading branch information
dfb committed Jan 25, 2019
1 parent a62627d commit 4d28b90
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
45 changes: 38 additions & 7 deletions Content/Scripts/fm/subclassing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,38 @@
'''
from . common import *
import _fmsubclassing as fms
import types
from unreal_engine import classes as engine_classes

# Define the flags you can use with the ufunction decorator - see Runtime\CoreUObject\Public\UObject\Script.h to add more
class FuncFlag(int): pass
Event = FuncFlag(0x00000800 | 0x08000000)
Static = FuncFlag(0x00002000)
Reliable = FuncFlag(0x00000080)
Multicast = FuncFlag(0x00004000)
Server = FuncFlag(0x00200000)
Client = FuncFlag(0x01000000)
Pure = BlueprintPure = FuncFlag(0x10000000)

# decorator that is roughly equivalent to UFUNCTION() in C++ - use this on a method in a subclass to cause it to
# be exposed as callable
# TODO: add support for pure=True, etc.
def ufunction(f):
f.ufunction = True
return f
# be exposed as callable. Anything the decorator is used on is automatically marked as native, public, and BlueprintCallable,
# so those flags are never needed. The decorator can be used in two ways:
# @ufunction
# @ufunction(...one or more FuncFlags...)
def ufunction(f, *args):
if isinstance(f, types.FunctionType):
# Used without params
assert not args, args
f.ufunc_flags = () # the presence of this function member is enough
return f
else:
# With params
def wrap(f):
for arg in args:
assert isinstance(arg, FuncFlag), 'Invalid ufunction param %s for %s' % (arg, f)
f.ufunc_flags = args
return f
return wrap

# used for declaring UPROPERTYs. Use when creating class vars: myVar = uproperty(FVector, FVector(1,2,3)). By default, implies BlueprintReadWrite.
# TODO: add support for replication, editanywhere, BPReadOnly, repnotify, and other flags. myVar = uproperty(default, *kwFlags)
Expand Down Expand Up @@ -133,16 +157,23 @@ def ProcessBridgeDescendentClassMethods(metaclass, newPyClass):
for k,v in list(newPyClass.__dict__.items()):
if k.startswith('__') or k in ('engineClass',):
continue
if not callable(v) or not getattr(v, 'ufunction', None):
if not callable(v):
continue
flags = getattr(v, 'ufunc_flags', None)
if flags is None:
continue
funcName, func = k,v

funcFlags = 0
for flag in flags:
funcFlags |= flag

# Add the method to the class but under a different name so it doesn't get stomped by the stuff below
hiddenFuncName = '_orig_' + funcName
setattr(newPyClass, hiddenFuncName, func)

# Expose a UFUNCTION in C++ that calls this method
fms.add_ufunction(newPyClass.engineClass, funcName, func)
fms.add_ufunction(newPyClass.engineClass, funcName, func, funcFlags)

# Make it so that from Python you can use that name to call the UFUNCTION version in UE4 (so that things
# like replication work)
Expand Down
6 changes: 3 additions & 3 deletions Source/UnrealEnginePython/Private/FMModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,15 @@ static PyObject *add_ufunction(PyObject *self, PyObject *args)
PyObject *pyEngineClass;
char *funcName;
PyObject *pyFunc;
if (!PyArg_ParseTuple(args, "OsO", &pyEngineClass, &funcName, &pyFunc))
unsigned int extraFlags;
if (!PyArg_ParseTuple(args, "OsOI", &pyEngineClass, &funcName, &pyFunc, &extraFlags))
return NULL;

UClass *engineClass = ue_py_check_type<UClass>(pyEngineClass);
if (!engineClass)
return PyErr_Format(PyExc_Exception, "Provide the UClass to attach the function to");

// TODO: compute correct set of function flags
uint32 funcFlags = FUNC_Native | FUNC_BlueprintCallable | FUNC_Public;
uint32 funcFlags = FUNC_Native | FUNC_BlueprintCallable | FUNC_Public | extraFlags;
UPythonFunction *newFunc = (UPythonFunction *)unreal_engine_add_function(engineClass, funcName, pyFunc, funcFlags);
if (newFunc)
{
Expand Down

0 comments on commit 4d28b90

Please sign in to comment.