Exemplo n.º 1
0
        public static void AssertProperty <T>(UStruct unrealStruct, string name, EPropertyFlags flags) where T : UProperty
        {
            UProperty prop = unrealStruct.FindPropertyByName(new FName(name));

            Assert(prop as T != null, unrealStruct.GetName() + "." + name);
            Assert(prop.HasAllPropertyFlags(flags), unrealStruct.GetName() + "." + name + " (flags)");
        }
Exemplo n.º 2
0
 public override void Read(AssetBinaryReader reader)
 {
     base.Read(reader);
     ArrayDim      = (EArrayDim)reader.ReadInt32();
     ElementSize   = reader.ReadInt32();
     PropertyFlags = (EPropertyFlags)reader.ReadUInt64();
     RepIndex      = reader.ReadUInt16();
     RepNotifyFunc = reader.ReadFName();
     BlueprintReplicationCondition = (ELifetimeCondition)reader.ReadByte();
 }
Exemplo n.º 3
0
            private unsafe void HandleInvokeFunctionFromNative(IntPtr obj, FFrame stack, IntPtr result,
                                                               UFunction.FuncInvokerManaged managedFunctionInvoker)
            {
                IntPtr function     = stack.CurrentNativeFunction;
                IntPtr paramsBuffer = stack.Locals;

                if (managedFunctionInvoker != null)
                {
                    // 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 back from the locals buffer
                if (Native_UFunction.HasAnyFunctionFlags(function, EFunctionFlags.HasOutParms))
                {
                    // This assumes that UProperty will be itterated in the exact same order as the caller created stack->OutParms
                    // (we could iterate stack->OutParms until nullptr but it isn't null terminated on release builds)
                    FOutParmRec *outParms = stack.OutParmsPtr;

                    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(outParms->Property == paramProp);

                            // - REMOVING the DestroyValue call. The issue with this DestroyValue call is that PropAddr
                            //   and paramsBuffer can (will?) be refering to the same data which we should have set in
                            //   managedFunctionInvoker. So a call to DestroyValue would be destroying the data we want!
                            //   Though if PropAddr is for some reason still holding onto unknown memory this will leak
                            //   memory and we will need to investigate further.
                            //   - The "refering to the same data" is because of the params Memcpy in UObject::ProcessEvent.
                            //     They wont have the same address but their inital data will be the same and as such
                            //     things like FString data pointer would be pointing to the same address.
                            //     - We may still need to call DestroyValue in the BP/VM code path above.
                            // Destroy the existing memory (this assumed the existing memory is valid or at least memzerod)
                            //Native_UProperty.DestroyValue(paramProp, outParms->PropAddr);

                            // A raw memcpy should be OK since the managed invoker should have set this memory appropriately.
                            FMemory.Memcpy(outParms->PropAddr,
                                           paramsBuffer + Native_UProperty.GetOffset_ForUFunction(paramProp),
                                           Native_UProperty.Get_ElementSize(paramProp));// Should be ArrayDim*ElementSize but ArrayDim should always be 1 for params

                            outParms = outParms->NextOutParamPtr;
                        }
                    }
                }

                // We assume that the caller will clean up the memory held by stack->Locals so we don't iterate over the
                // DestructorLink as we do in HandleInvokeFunctionFromBP. HandleInvokeFunctionFromBP needs to as it creates
                // copies of data when calling stack->Step() which don't occur here as we use the existing stack->Locals buffer.
            }
Exemplo n.º 4
0
        public override void Read(AssetBinaryReader reader)
        {
            base.Read(reader);
            ArrayDim      = (EArrayDim)reader.ReadInt32();
            PropertyFlags = (EPropertyFlags)reader.ReadUInt64();
            RepNotifyFunc = reader.ReadFName();

            if (reader.Asset.GetCustomVersion <FReleaseObjectVersion>() >= FReleaseObjectVersion.PropertiesSerializeRepCondition)
            {
                BlueprintReplicationCondition = (ELifetimeCondition)reader.ReadByte();
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Reimplementation of UFunction::IsSignatureCompatibleWith for debugging purposes
        /// (the native function with engine symbols debugs badly)
        /// </summary>
        internal bool InternalIsSignatureCompatibleWith(UFunction otherFunction, EPropertyFlags ignoreFlags)
        {
            // Early out if they're exactly the same function
            if (this == otherFunction)
            {
                return(true);
            }

            // Run thru the parameter property chains to compare each property
            TFieldIterator <UProperty> iteratorA = new TFieldIterator <UProperty>(this);
            TFieldIterator <UProperty> iteratorB = new TFieldIterator <UProperty>(otherFunction);

            while (iteratorA.Current != null && (iteratorA.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm)))
            {
                if (iteratorB.Current != null && (iteratorB.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm)))
                {
                    // Compare the two properties to make sure their types are identical
                    // Note: currently this requires both to be strictly identical and wouldn't allow functions that differ only by how derived a class is,
                    // which might be desirable when binding delegates, assuming there is directionality in the SignatureIsCompatibleWith call
                    UProperty propA = iteratorA.Current;
                    UProperty propB = iteratorB.Current;

                    EPropertyFlags flags1 = propA.PropertyFlags;
                    EPropertyFlags flags2 = propB.PropertyFlags;

                    if (!ArePropertiesTheSame(propA, propB, false))
                    {
                        // Type mismatch between an argument of A and B
                        return(false);
                    }

                    // Check the flags as well
                    EPropertyFlags propertyMash = propA.PropertyFlags ^ propB.PropertyFlags;
                    if ((propertyMash & ~ignoreFlags) != 0)
                    {
                        return(false);
                    }
                }
                else
                {
                    // B ran out of arguments before A did
                    return(false);
                }
                iteratorA.MoveNext();
                iteratorB.MoveNext();
            }

            // They matched all the way thru A's properties, but it could still be a mismatch if B has remaining parameters
            return(!(iteratorB.Current != null && (iteratorB.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm))));
        }
Exemplo n.º 6
0
            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);
                 *  }
                 * }*/
            }
Exemplo n.º 7
0
 /// <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&amp;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));
 }
Exemplo n.º 8
0
 public void ClearPropertyFlags(EPropertyFlags newFlags)
 {
     Native_UProperty.ClearPropertyFlags(Address, newFlags);
 }
Exemplo n.º 9
0
 public void SetPropertyFlags(EPropertyFlags newFlags)
 {
     Native_UProperty.SetPropertyFlags(Address, newFlags);
 }