Esempio n. 1
0
        public static unsafe void HackVTable(UObject obj)
        {
            // This will swap out the vtable entry and store the old one in our managed UClass

            if (!Native_UObjectBaseUtility.IsA(obj.Address, Runtime.Classes.UClass))
            {
                UClass unrealClass = obj.GetClass();
                if (unrealClass.VTableOriginalFunctions == null)
                {
                    IntPtr *vtable = *(IntPtr **)obj.Address;

                    unrealClass.VTableOriginalFunctions = new Dictionary <int, UClass.VTableOriginalFunc>();
                    foreach (FunctionRedirect redirect in vtableRedirects)
                    {
                        if (!Native_UObjectBaseUtility.IsA(obj.Address, redirect.Class))
                        {
                            continue;
                        }

                        IntPtr originalFunctionAddress = vtable[redirect.VTableIndex];

                        if (originalFunctionAddress != redirect.NativeCallback)
                        {
                            IntPtr originalOwnerClassAddress = FindOriginalVTableOwner(
                                redirect.Class, unrealClass.Address, originalFunctionAddress, redirect.VTableIndex);

                            if (originalOwnerClassAddress != unrealClass.Address)
                            {
                                UClass originalOwnerClass = GCHelper.Find <UClass>(originalOwnerClassAddress);
                                if (originalOwnerClass.VTableOriginalFunctions == null)
                                {
                                    HackVTable(originalOwnerClass.GetDefaultObject());
                                }
                            }

                            IntPtr pageAlignedPtr = FMemory.PageAlignPointer((IntPtr)(&vtable[redirect.VTableIndex]));
                            FMemory.PageProtect(pageAlignedPtr, (IntPtr)IntPtr.Size, true, true);
                            *(&vtable[redirect.VTableIndex]) = redirect.NativeCallback;
                        }
                        else
                        {
                            // The VTable has already been swapped out. Find the original function address.
                            UClass superClass = unrealClass;
                            while ((superClass = superClass.GetSuperClass()) != null && superClass.VTableOriginalFunctions == null)
                            {
                            }

                            Debug.Assert(superClass != null && superClass.VTableOriginalFunctions != null &&
                                         superClass.VTableOriginalFunctions.ContainsKey(redirect.VTableIndex));

                            originalFunctionAddress = superClass.VTableOriginalFunctions[redirect.VTableIndex].FuncAddress;
                        }

                        unrealClass.VTableOriginalFunctions.Add(redirect.VTableIndex, new UClass.VTableOriginalFunc(originalFunctionAddress));
                    }
                }
            }
        }
        private UClass GetActionFactoryClass(UClass unrealClass)
        {
            UClass actionFactoryClass = unrealClass;

            while (actionFactoryClass != null && !actionFactoryClasses.Contains(actionFactoryClass))
            {
                actionFactoryClass = actionFactoryClass.GetSuperClass();
            }
            return(actionFactoryClass);
        }
Esempio n. 3
0
        /// <summary>
        /// This will check for conflicts when finding interface functions. If there is a conflict
        /// the code output is likely to be undesirable.
        /// </summary>
        private void ValidateNoInterfaceFunctionConflict(UClass unrealClass, UFunction function,
                                                         UClass skipInterface, bool skipSelf)
        {
            FName     functionName     = function.GetFName();
            UFunction conflictFunction = null;

            foreach (FImplementedInterface implementedInterface in unrealClass.Interfaces)
            {
                UClass interfaceClass = implementedInterface.InterfaceClass;
                if (interfaceClass != null && interfaceClass != skipInterface)
                {
                    if ((conflictFunction = interfaceClass.FindFunctionByName(functionName, true)) != null)
                    {
                        break;
                    }
                }
            }

            if (conflictFunction == null && !skipSelf)
            {
                conflictFunction = unrealClass.FindFunctionByName(functionName, false);
            }

            if (conflictFunction == null)
            {
                UClass parentClass = unrealClass.GetSuperClass();
                if (parentClass != null)
                {
                    // Search the rest of the hierarchy
                    conflictFunction = parentClass.FindFunctionByName(functionName, true);
                }
            }

            if (conflictFunction != null)
            {
                string warning = "Function redefined in hierarchy where interfaces are used. This is likely going to produce " +
                                 "unexpected results and should be avoided where possible. ImplementedInClass: '" + unrealClass.GetPathName() +
                                 "' InterfaceFunc: '" + function.GetPathName() + "' ConflictFunc: '" + conflictFunction.GetPathName() + "'";
                FMessage.Log(ELogVerbosity.Warning, warning, "USharp-CodeGenerator");
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Searches the class hierarchy to find the original owner of the given function (by function name)
        /// </summary>
        private UClass GetOriginalFunctionOwnerInternal(UFunction function, out UFunction originalFunction,
                                                        out bool isInterfaceImplementation)
        {
            // Interfaces really mess up this function. Two interfaces could potentially provide the same function
            // in the class hierarchy. Or a class up the chain could provide a function but also an interface with
            // the same function name could exist. None of this maps to C# well in terms of ensuring this is all handled
            // properly AND with name conflict resolution (which is what GetOriginalFunctionOwner is partially used for).
            // - We ALWAYS want use the first interface found with the same function name in order to produce valid C#.
            //   (even if this then technically isn't necessarily the original function / owner).
            // - We should log when we find this type of situation where there are functions are redefined in a
            //   class / interface combo (regular class:class conflict should be fine).
            // - TODO: Handle interface hierarchy

            FName functionName = function.GetFName();

            isInterfaceImplementation = false;

            originalFunction = function;
            UClass owner = function.GetOwnerClass();

            if (owner != null)
            {
                // First check the interfaces of THIS class.
                foreach (FImplementedInterface implementedInterface in owner.Interfaces)
                {
                    UClass interfaceClass = implementedInterface.InterfaceClass;
                    if (interfaceClass != null)
                    {
                        UFunction interfaceFunction = interfaceClass.FindFunctionByName(functionName, false);
                        if (interfaceFunction != null)
                        {
                            originalFunction = interfaceFunction;
                            ValidateNoInterfaceFunctionConflict(owner, originalFunction, interfaceClass, true);

                            // We found the original function directly within one of the implemented interfaces.
                            // This means the input function is an implementation for one of the interfaces.
                            isInterfaceImplementation = true;
                            return(interfaceClass);
                        }
                    }
                }

                UClass parentClass = owner.GetSuperClass();
                while (parentClass != null)
                {
                    // Check the interfaces of the parent class.
                    foreach (FImplementedInterface implementedInterface in parentClass.Interfaces)
                    {
                        UClass interfaceClass = implementedInterface.InterfaceClass;
                        if (interfaceClass != null)
                        {
                            UFunction interfaceFunction = interfaceClass.FindFunctionByName(functionName, false);
                            if (interfaceFunction != null)
                            {
                                originalFunction = interfaceFunction;
                                ValidateNoInterfaceFunctionConflict(parentClass, originalFunction, interfaceClass, false);
                                return(interfaceClass);
                            }
                        }
                    }

                    UFunction parentFunction = parentClass.FindFunctionByName(functionName, false);
                    if (parentFunction == null)
                    {
                        break;
                    }
                    originalFunction = parentFunction;
                    owner            = parentClass;
                    parentClass      = parentClass.GetSuperClass();
                }
            }
            return(owner);
        }