public static ushort GetPropertyRepIndex(IntPtr unrealStruct, string propertyName) { IntPtr property = FindField(unrealStruct, propertyName); return(property == IntPtr.Zero ? (ushort)0 : Native_UProperty.Get_RepIndex(property)); }
private unsafe void HandleInvokeFunctionFromBP(IntPtr obj, FFrame stack, IntPtr result, UFunction.FuncInvokerManaged managedFunctionInvoker) { // NOTE: ScriptCore.cpp uses PropertiesSize instead of ParamsSize. Is it ever any different? (it says alignment // may make them different) If it is different we should probably use PropertiesSize (including in generated code / // IL) as ScriptCore.cpp uses a memcpy of our memory. Debug.Assert(Native_UStruct.Get_PropertiesSize(stack.CurrentNativeFunction) == Native_UFunction.Get_ParmsSize(stack.CurrentNativeFunction)); IntPtr function = stack.CurrentNativeFunction; int paramsSize = Native_UFunction.Get_ParmsSize(function); int numParams = Native_UFunction.Get_NumParms(function); bool hasOutParams = Native_UFunction.HasAnyFunctionFlags(function, EFunctionFlags.HasOutParms); IntPtr *outParamsBufferPtr = stackalloc IntPtr[numParams]; byte * paramsBufferPtr = stackalloc byte[paramsSize]; IntPtr paramsBuffer = (IntPtr)paramsBufferPtr; // We could skip this memzero as stackalloc will (always?) zero memory even though the spec states // "The content of the newly allocated memory is undefined." // https://github.com/dotnet/coreclr/issues/1279 FMemory.Memzero(paramsBuffer, paramsSize); if (hasOutParams) { int paramIndex = 0; foreach (IntPtr param in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { // Not required but using for Debug.Assert() when getting the value stack.MostRecentPropertyAddress = IntPtr.Zero; stack.Step(stack.Object, paramsBuffer + Native_UProperty.GetOffset_ForUFunction(param)); outParamsBufferPtr[paramIndex] = stack.MostRecentPropertyAddress; if (Native_UProperty.HasAnyPropertyFlags(param, EPropertyFlags.ReturnParm)) { // This should be UObject::execEndFunctionParms which will just do "stack->Code--;" for allowing // the caller to use PFINISH aftwards outParamsBufferPtr[paramIndex] = result; } paramIndex++; } } else { foreach (IntPtr param in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { stack.Step(stack.Object, paramsBuffer + Native_UProperty.GetOffset_ForUFunction(param)); } } stack.PFinish();// Skip EX_EndFunctionParms // Call the managed function invoker which will marshal the params from the native params buffer and then call the // target managed function managedFunctionInvoker(paramsBuffer, obj); // Copy out params from the temp buffer //if (hasOutParams) // 4.20 DestructorLink change (see below) { int paramIndex = 0; foreach (IntPtr paramProp in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, false)) { EPropertyFlags paramFlags = Native_UProperty.GetPropertyFlags(paramProp); if ((paramFlags & EPropertyFlags.OutParm) == EPropertyFlags.OutParm && (paramFlags & EPropertyFlags.ConstParm) != EPropertyFlags.ConstParm) { Debug.Assert(outParamsBufferPtr[paramIndex] != IntPtr.Zero); // - See "REMOVING the DestroyValue call" below. // Destroy the existing memory (this assumed the existing memory is valid or at least memzerod) //Native_UProperty.DestroyValue(paramProp, outParamsBufferPtr[paramIndex]); // A raw memcpy should be OK since the managed invoker should have set this memory appropriately. FMemory.Memcpy(outParamsBufferPtr[paramIndex], paramsBuffer + Native_UProperty.GetOffset_ForUFunction(paramProp), Native_UProperty.Get_ElementSize(paramProp));// Should be ArrayDim*ElementSize but ArrayDim should always be 1 for params } else { // 4.20 the original DestructorLink code doesn't work as expected (did it ever work?). DestructorLink seems to only be // used on delegate functions (e.g. /Script/Engine.ActorOnClickedSignature__DelegateSignature). // - For now call destroy everything other than out params (is this safe?) // - TODO: Replace this with custom Stack.Code stepping as described above? Native_UProperty.DestroyValue_InContainer(paramProp, paramsBuffer); } paramIndex++; } } // Parameters are copied when calling stack->Step(). We are responsible for destroying non-blittable types // which were copied (FString, TArray, etc). For C++ this works out well due to the copy constructors etc. // // Example where an FString is constructed from stack->Step(): // UObject::execStringConst(...) { *(FString*)RESULT_PARAM = (ANSICHAR*)Stack.Code; } // // For C# it might be better if we reimplemented all of the IMPLEMENT_VM_FUNCTION functions to reduce the amount // of copying as we currently need ANOTHER copy to get it from the temp buffer into a C# type (which is done // inside the managedFunctionInvoker function) /*foreach (IntPtr paramProp in new NativeReflection.NativeFieldIterator(Runtime.Classes.UProperty, function, * EFieldIteratorType.Destructor, false)) * { * // When is this ever false? It seems to be checked in UObject::ProcessEvent() * // "Destroy local variables except function parameters." - used for BP locals? * Debug.Assert(Native_UProperty.IsInContainer(paramProp, paramsSize)); * * // Out params are copied to the memory maintained by the caller so only destroy "by value" parameters. * if (!Native_UProperty.HasAnyPropertyFlags(paramProp, EPropertyFlags.OutParm)) * { * Native_UProperty.DestroyValue_InContainer(paramProp, paramsBuffer); * } * }*/ }
/// <summary> /// Return offset of property from container base. /// </summary> /// <returns></returns> public int GetOffset_ForUFunction() { return(Native_UProperty.GetOffset_ForUFunction(Address)); }
/// <summary> /// Returns the replication owner, which is the property itself, or NULL if this isn't important for replication. /// It is relevant if the property is a net relevant and not being run in the editor /// </summary> /// <returns></returns> public UProperty GetRepOwner() { return(GCHelper.Find <UProperty>(Native_UProperty.GetRepOwner(Address))); }
/// <summary> /// returns true, if Other is property of exactly the same type /// </summary> /// <param name="other"></param> /// <returns></returns> public bool SameType(UProperty other) { return(Native_UProperty.SameType(Address, other == null ? IntPtr.Zero : other.Address)); }
/// <summary> /// Returns this property's propertyflags /// </summary> /// <returns></returns> public EPropertyFlags GetPropertyFlags() { return(Native_UProperty.GetPropertyFlags(Address)); }
public void ClearPropertyFlags(EPropertyFlags newFlags) { Native_UProperty.ClearPropertyFlags(Address, newFlags); }
/// <summary> /// Copy the value for a single element of this property. /// </summary> /// <param name="dest">the address where the value should be copied to. This should always correspond to the BASE + OFFSET + INDEX * SIZE, where /// BASE = (for member properties) the address of the UObject which contains this data, (for locals/parameters) the address of the space allocated for the function's locals /// OFFSET = the Offset of this UProperty /// INDEX = the index that you want to copy. for properties which are not arrays, this should always be 0 /// SIZE = the ElementSize of this UProperty</param> /// <param name="src">the address of the value to copy from. should be evaluated the same way as Dest</param> public void CopySingleValue(IntPtr dest, IntPtr src) { Native_UProperty.CopySingleValue(Address, dest, src); }
/// <summary> /// Return offset of property from container base. /// </summary> public int GetOffset_ForInternal() { return(Native_UProperty.GetOffset_ForInternal(Address)); }
/// <summary> /// See if the offset of this property is below the supplied container size /// </summary> /// <param name="containerSize"></param> /// <returns></returns> public bool IsInContainer(int containerSize) { return(Native_UProperty.IsInContainer(Address, containerSize)); }
/// <summary> /// See if the offset of this property is below the supplied container size /// </summary> /// <param name="containerClass"></param> /// <returns></returns> public bool IsInContainer(UStruct containerClass) { return(Native_UProperty.IsInContainerStruct(Address, containerClass.Address)); }
public IntPtr ContainerPtrToValuePtrForDefaults(UStruct containerClass, IntPtr container, int arrayIndex = 0) { return(Native_UProperty.ContainerVoidPtrToValuePtrForDefaults(Address, containerClass.Address, container, arrayIndex)); }
private static bool PropertyHasGetTypeHash(IntPtr property) { return(Native_UProperty.HasAllPropertyFlags(property, EPropertyFlags.HasGetValueTypeHash)); }
private IntPtr CreateProperty(IntPtr outer, Type type, string propertyName, EPropertyType propertyType, EPropertyType innerPropertyType1, EPropertyType innerPropertyType2) { propertyType = ManagedUnrealTypes.GetPropertyType(type, propertyType); IntPtr propertyClass = ManagedUnrealTypes.GetPropertyClass(propertyType); if (propertyClass == IntPtr.Zero) { return(IntPtr.Zero); } EObjectFlags objectFlags = EObjectFlags.Public | EObjectFlags.Transient | EObjectFlags.MarkAsNative; IntPtr property = NativeReflection.NewObject(outer, propertyClass, new FName(propertyName), objectFlags); Native_UProperty.SetPropertyFlags(property, EPropertyFlags.BlueprintVisible | EPropertyFlags.BlueprintAssignable | EPropertyFlags.Edit); // Set type specific information switch (propertyType) { case EPropertyType.Array: if (!firstRun) { Native_UArrayProperty.Set_Inner(property, CreateProperty(property, typeof(int), propertyName, innerPropertyType1)); } else { Native_UArrayProperty.Set_Inner(property, CreateProperty(property, type.GenericTypeArguments[0], propertyName, innerPropertyType1)); } break; case EPropertyType.Set: Native_USetProperty.Set_ElementProp(property, CreateProperty(property, type.GenericTypeArguments[0], propertyName, innerPropertyType1)); break; case EPropertyType.Map: Native_UMapProperty.Set_KeyProp(property, CreateProperty(property, type.GenericTypeArguments[0], propertyName, innerPropertyType1)); Native_UMapProperty.Set_ValueProp(property, CreateProperty(property, type.GenericTypeArguments[1], propertyName, innerPropertyType2)); break; case EPropertyType.Class: Native_UClassProperty.SetMetaClass(property, UClass.GetClass(type.GenericTypeArguments[0]).Address); break; case EPropertyType.Object: var v1 = ManagedUnrealTypes.GetStaticClass(type); var v2 = ManagedUnrealTypes.GetStaticClass(typeof(UObject)); Native_UObjectPropertyBase.SetPropertyClass(property, v1 == IntPtr.Zero ? v2 : v1); break; case EPropertyType.LazyObject: case EPropertyType.WeakObject: case EPropertyType.SoftObject: Native_UObjectPropertyBase.SetPropertyClass(property, UClass.GetClass(type.GenericTypeArguments[0]).Address); break; case EPropertyType.SoftClass: Native_USoftClassProperty.SetMetaClass(property, UClass.GetClass(type.GenericTypeArguments[0]).Address); break; case EPropertyType.Enum: Native_UEnumProperty.SetEnum(property, ManagedUnrealTypes.GetEnum(type)); break; case EPropertyType.Delegate: //Native_UDelegateProperty.Set_SignatureFunction(property, ManagedUnrealTypes.GetSignatureFunction(type)); break; case EPropertyType.MulticastDelegate: //Native_UMulticastDelegateProperty.Set_SignatureFunction(property, ManagedUnrealTypes.GetSignatureFunction(type)); break; } Native_UField.AddCppProperty(outer, property); return(property); }
public int GetSize() { return(Native_UProperty.GetSize(Address)); }
/// <summary> /// Return offset of property from container base. /// </summary> /// <returns></returns> public int GetOffset_ReplaceWith_ContainerPtrToValuePtr() { return(Native_UProperty.GetOffset_ReplaceWith_ContainerPtrToValuePtr(Address)); }
/// <summary> /// Determines whether this property value is eligible for copying when duplicating an object /// </summary> /// <returns>true if this property value should be copied into the duplicate object</returns> public bool ShouldDuplicateValue() { return(Native_UProperty.ShouldDuplicateValue(Address)); }
/// <summary> /// Get the pointer to property value in a supplied 'container'. /// You can _only_ call this function on a UObject* or a uint8*. If the property you want is a 'top level' UObject property, you _must_ /// call the function passing in a UObject* and not a uint8*. There are checks inside the function to vertify this. /// </summary> /// <param name="container">UObject* or uint8* to container of property value</param> /// <param name="arrayIndex">In array case, index of array element we want</param> /// <returns></returns> public IntPtr ContainerPtrToValuePtr(IntPtr container, int arrayIndex = 0) { return(Native_UProperty.ContainerVoidPtrToValuePtr(Address, container, arrayIndex)); }
public void SetPropertyFlags(EPropertyFlags newFlags) { Native_UProperty.SetPropertyFlags(Address, newFlags); }
public uint GetValueTypeHash(IntPtr src) { return(Native_UProperty.GetValueTypeHash(Address, src)); }
/// <summary> /// Used to safely check whether all of the passed in flags are set. This is required /// as PropertyFlags currently is a 64 bit data type and bool is a 32 bit data type so /// simply using PropertyFlags&CPF_MyFlagBiggerThanMaxInt won't work correctly when /// assigned directly to an bool. /// </summary> /// <param name="flagsToCheck">Object flags to check for</param> /// <returns>true if all of the passed in flags are set (including no flags passed in), false otherwise</returns> public bool HasAllPropertyFlags(EPropertyFlags flagsToCheck) { return(Native_UProperty.HasAllPropertyFlags(Address, flagsToCheck)); }
public bool ShouldPort(uint portFlags) { return(Native_UProperty.ShouldPort(Address, portFlags)); }
/// <summary> /// Editor-only properties are those that only are used with the editor is present or cannot be removed from serialisation. /// Editor-only properties include: EditorOnly properties /// Properties that cannot be removed from serialisation are: /// Boolean properties (may affect GCC_BITFIELD_MAGIC computation) /// Native properties (native serialisation) /// </summary> /// <returns></returns> public bool IsEditorOnlyProperty() { return(Native_UProperty.IsEditorOnlyProperty(Address)); }
public int GetMinAlignment() { return(Native_UProperty.GetMinAlignment(Address)); }
public bool Update(IntPtr address) { if (Address != address) { Address = address; Size = 0; ArrayDim = 0; IsEditConst = false; IsBlueprintReadOnly = false; GenericArg1Address = IntPtr.Zero; GenericArg1Size = 0; GenericArg1ArrayDim = 0; GenericArg2Address = IntPtr.Zero; GenericArg2Size = 0; GenericArg2ArrayDim = 0; PropertyType = EPropertyType.Unknown; if (address == IntPtr.Zero) { return(true); } EPropertyType propertyType = NativeReflection.GetPropertyType(address); if (propertyType != EPropertyType.Unknown) { PropertyType = propertyType; Size = Native_UProperty.Get_ElementSize(address); ArrayDim = Native_UProperty.Get_ArrayDim(address); IsEditConst = Native_UProperty.HasAnyPropertyFlags(address, EPropertyFlags.EditConst); IsBlueprintReadOnly = Native_UProperty.HasAnyPropertyFlags(address, EPropertyFlags.BlueprintReadOnly); switch (propertyType) { case EPropertyType.Array: GenericArg1Address = Native_UArrayProperty.Get_Inner(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } break; case EPropertyType.Map: GenericArg1Address = Native_UMapProperty.Get_KeyProp(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } GenericArg2Address = Native_UMapProperty.Get_ValueProp(address); if (GenericArg2Address != IntPtr.Zero) { GenericArg2Size = Native_UProperty.Get_ElementSize(GenericArg2Address); GenericArg2ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg2Address); } break; case EPropertyType.Set: GenericArg1Address = Native_USetProperty.Get_ElementProp(address); if (GenericArg1Address != IntPtr.Zero) { GenericArg1Size = Native_UProperty.Get_ElementSize(GenericArg1Address); GenericArg1ArrayDim = Native_UProperty.Get_ArrayDim(GenericArg1Address); } break; } } return(true); } return(false); }
/// <summary> /// Returns true if this property, or in the case of e.g. array or struct properties any sub- property, contains a /// weak UObject reference. /// </summary> /// <returns>true if property (or sub- properties) contain a weak UObject reference, false otherwise</returns> public bool ContainsWeakObjectReference() { return(Native_UProperty.ContainsWeakObjectReference(Address)); }
public bool PassCPPArgsByRef() { return(Native_UProperty.PassCPPArgsByRef(Address)); }
/// <summary> /// Returns true if this property, or in the case of e.g. array or struct properties any sub- property, contains a /// UObject reference that is marked CPF_NeedCtorLink (i.e. instanced keyword). /// </summary> /// <returns>true if property (or sub- properties) contain a UObjectProperty that is marked CPF_NeedCtorLink, false otherwise</returns> public bool ContainsInstancedObjectProperty() { return(Native_UProperty.ContainsInstancedObjectProperty(Address)); }
/// <summary> /// Return offset of property from container base. /// </summary> /// <returns></returns> public int GetOffset_ForGC() { return(Native_UProperty.GetOffset_ForGC(Address)); }
private static bool FindFieldInfo(IntPtr typeClass, IntPtr unrealStruct, string fieldName, out CachedFieldInfo fieldInfo) { if (typeClass == IntPtr.Zero || unrealStruct == IntPtr.Zero || string.IsNullOrEmpty(fieldName)) { fieldInfo = default(CachedFieldInfo); return(false); } if (unrealStruct == lastUnrealStruct) { return(lastUnrealStructChildren.TryGetValue(fieldName, out fieldInfo)); } else if (unrealStruct == lastUnrealFunction) { return(lastUnrealFunctionChildren.TryGetValue(fieldName, out fieldInfo)); } else { Dictionary <string, CachedFieldInfo> fields = null; // For structs we want to get all fields in the hierarchy as we can't struct inheritance in C# // (C++ structs can have inheritance, if we skip checking the hierarchy we wont get all the fields we want) bool isScriptStruct = false; if (Native_UObjectBaseUtility.IsA(unrealStruct, Classes.UFunction)) { fields = lastUnrealFunctionChildren; lastUnrealFunction = unrealStruct; } else { isScriptStruct = Native_UObjectBaseUtility.IsA(unrealStruct, Classes.UScriptStruct); fields = lastUnrealStructChildren; lastUnrealStruct = unrealStruct; } fields.Clear(); foreach (IntPtr field in new NativeReflection.NativeFieldIterator( EClassCastFlags.UFunction | EClassCastFlags.UProperty, unrealStruct, false, isScriptStruct)) { Native_UObjectBaseUtility.GetNameOut(field, ref nameUnsafe.Array); string name = nameUnsafe.Value; // Temporary check for debugging purposes. There shouldn't be any duplicate fields as we aren't looking in the hierarchy. if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debug.Assert(!fields.ContainsKey(name)); } fields[name] = new CachedFieldInfo() { Address = field, Offset = Native_UProperty.GetOffset_ForInternal(field) }; } return(fields.TryGetValue(fieldName, out fieldInfo)); } }