Exemple #1
0
        /// <summary>
        /// Generates the methods of a class.
        /// </summary>
        /// <param name="classObj">The class object.</param>
        /// <returns>Return The methods of the class.</returns>
        private async Task <List <Method> > GenerateMethods(GenericTypes.UEClass classObj)
        {
            var methods = new List <Method>();

            //some classes (AnimBlueprintGenerated...) have multiple members with the same name, so filter them out
            var uniqueMethods = new List <string>();

            // prop can be UEObject, UEField, UEProperty
            for (var prop = (await classObj.GetChildren()).Cast <GenericTypes.UEField>(); prop.IsValid(); prop = await prop.GetNext())
            {
                if (!await prop.IsA <GenericTypes.UEFunction>())
                {
                    continue;
                }

                var function = prop.Cast <GenericTypes.UEFunction>();

                var m = new Method
                {
                    Index    = function.GetIndex(),
                    FullName = await function.GetFullName(),
                    Name     = Generator.GetSafeKeywordsName(NameValidator.MakeValidName(await function.GetName()))
                };

                if (uniqueMethods.Contains(m.FullName))
                {
                    continue;
                }

                uniqueMethods.Add(m.FullName);

                m.IsNative    = (await function.GetFunctionFlags()).HasFlag(UEFunctionFlags.Native);
                m.IsStatic    = (await function.GetFunctionFlags()).HasFlag(UEFunctionFlags.Static);
                m.FlagsString = FunctionFlags.StringifyFlags(await function.GetFunctionFlags());

                var parameters = new List <KeyValuePair <GenericTypes.UEProperty, Method.Parameter> >();
                var unique     = new Dictionary <string, int>();
                for (var param = (await function.GetChildren()).Cast <GenericTypes.UEProperty>(); param.IsValid(); param = (await param.GetNext()).Cast <GenericTypes.UEProperty>())
                {
                    if (await param.GetElementSize() == 0)
                    {
                        continue;
                    }

                    var info = await param.GetInfo();

                    if (info.Type == GenericTypes.UEProperty.PropertyType.Unknown)
                    {
                        continue;
                    }

                    var p = new Method.Parameter(UnrealVersion.Unreal4);

                    if (!p.MakeType(await param.GetPropertyFlags(), out p.ParamType))
                    {
                        //child isn't a parameter
                        continue;
                    }

                    p.PassByReference = false;
                    p.Name            = NameValidator.MakeValidName(await param.GetName());

                    if (!unique.ContainsKey(p.Name))
                    {
                        unique[p.Name] = 1;
                    }
                    else
                    {
                        unique[p.Name]++;
                        p.Name += unique[p.Name];
                    }

                    p.FlagsString = PropertyFlags.StringifyFlags(await param.GetPropertyFlags());
                    p.CppType     = info.CppType;

                    if (await param.IsA <GenericTypes.UEBoolProperty>())
                    {
                        p.CppType = Generator.GetOverrideType("bool");
                    }

                    if (p.ParamType == Method.Parameter.Type.Default)
                    {
                        if (await param.GetArrayDim() > 1)
                        {
                            p.CppType += "*";
                        }
                        else if (info.CanBeReference)
                        {
                            p.PassByReference = true;
                        }
                    }

                    p.Name = Generator.GetSafeKeywordsName(p.Name);
                    parameters.Add(new KeyValuePair <GenericTypes.UEProperty, Method.Parameter>(param, p));
                }

                parameters.Sort((lhs, rhs) => ComparePropertyLess(lhs.Key, rhs.Key).Result ? 0 : 1);

                foreach (var param in parameters)
                {
                    m.Parameters.Add(param.Value);
                }

                methods.Add(m);
            }

            return(methods);
        }
Exemple #2
0
        /// <summary>
        /// Generates the class.
        /// </summary>
        /// <param name="classObj">The class object.</param>
        private async Task GenerateClass(GenericTypes.UEClass classObj)
        {
            var c = new Class
            {
                Name     = await classObj.GetName(),
                FullName = await classObj.GetFullName()
            };

            var logTask = Logger.Log($"Class:   {await GetName() + "." + c.Name,-85} - instance: 0x{classObj.GetAddress().ToInt64():X8}");

            c.NameCpp     = NameValidator.MakeValidName(await classObj.GetNameCpp());
            c.NameCppFull = $"class {c.NameCpp}";

            c.Size = await classObj.GetPropertySize();

            c.InheritedSize = 0;

            int offset = 0;

            var super = await classObj.GetSuper();

            if (super.IsValid() && super != classObj)
            {
                c.InheritedSize = offset = await super.GetPropertySize();

                c.NameCppFull += $" : public {NameValidator.MakeValidName(await super.GetNameCpp())}";
            }

            var predefinedStaticMembers = new List <PredefinedMember>();

            if (Generator.GetPredefinedClassStaticMembers(c.FullName, ref predefinedStaticMembers))
            {
                foreach (var prop in predefinedStaticMembers)
                {
                    var p = new Member
                    {
                        Offset   = 0,
                        Size     = 0,
                        Name     = prop.Name,
                        Type     = prop.Type,
                        IsStatic = true
                    };
                    c.Members.Add(p);
                }
            }

            var predefinedMembers = new List <PredefinedMember>();

            if (Generator.GetPredefinedClassMembers(c.FullName, ref predefinedMembers))
            {
                foreach (var prop in predefinedMembers)
                {
                    var p = new Member
                    {
                        Offset   = 0,
                        Size     = 0,
                        Name     = prop.Name,
                        Type     = prop.Type,
                        IsStatic = false,
                        Comment  = "NOT AUTO-GENERATED PROPERTY"
                    };
                    c.Members.Add(p);
                }
            }
            else
            {
                var properties = new List <GenericTypes.UEProperty>();
                for (var prop = (await classObj.GetChildren()).Cast <GenericTypes.UEProperty>(); prop.IsValid(); prop = (await prop.GetNext()).Cast <GenericTypes.UEProperty>())
                {
                    var elementSizeT   = prop.GetElementSize();
                    var isScriptStruct = prop.IsA <GenericTypes.UEScriptStruct>();
                    var isFunction     = prop.IsA <GenericTypes.UEFunction>();
                    var isEnum         = prop.IsA <GenericTypes.UEEnum>();
                    var isConst        = prop.IsA <GenericTypes.UEConst>();

                    if (await elementSizeT > 0 &&
                        !await isScriptStruct &&
                        !await isFunction &&
                        !await isEnum &&
                        !await isConst &&
                        (!super.IsValid() || (super != classObj && await prop.GetOffset() >= await super.GetPropertySize())))
                    {
                        properties.Add(prop);
                    }
                }

                // As C# sort not same as C++ version, that's not work
                // Anyway after some testes it's not needed !!
                // properties.Sort((x, y) => ComparePropertyLess(x, y).Result ? 0 : 1);

                c.Members = await GenerateMembers(classObj, offset, properties);
            }

            Generator.GetPredefinedClassMethods(c.FullName, ref c.PredefinedMethods);

            if (Generator.SdkType == SdkType.External)
            {
                // ToDO: Add external Read/Write here for external
            }
            else
            {
                if (Generator.ShouldUseStrings)
                {
                    string classStr = Generator.ShouldXorStrings ? $"_xor_(\"{c.FullName}\")" : $"\"{c.FullName}\"";
                    c.PredefinedMethods.Add(PredefinedMethod.Inline($@"	static UClass* StaticClass()
	{{
		static auto ptr = UObject::FindClass({classStr});
		return ptr;
	}}"    )
                                            );
                }
                else
                {
                    c.PredefinedMethods.Add(PredefinedMethod.Inline($@"	static UClass* StaticClass()
	{{
		static auto ptr = UObject::GetObjectCasted<UClass>({classObj.GetIndex()});
		return ptr;
	}}"    )
                                            );
                }

                c.Methods = await GenerateMethods(classObj);

                //search virtual functions
                var patterns = new VirtualFunctionPatterns();
                if (Generator.GetVirtualFunctionPatterns(c.FullName, ref patterns))
                {
                    int    ptrSize       = Utils.GamePointerSize();
                    IntPtr vTableAddress = classObj.Object.VfTable;
                    var    vTable        = new List <IntPtr>();

                    int methodCount = 0;
                    while (methodCount < 150)
                    {
                        // Dereference Pointer
                        IntPtr vAddress = Utils.MemObj.ReadAddress(vTableAddress + (methodCount * ptrSize));

                        // Check valid address
                        int res = Win32.VirtualQueryEx(Utils.MemObj.ProcessHandle, vAddress, out var info, (uint)Marshal.SizeOf <Win32.MemoryBasicInformation>());
                        if (res == 0 || info.Protect.HasFlag(Win32.MemoryProtection.PageNoAccess))
                        {
                            break;
                        }

                        vTable.Add(vAddress);
                        methodCount++;
                    }

                    foreach (var(pattern, funcStr) in patterns)
                    {
                        for (int i = 0; i < methodCount; i++)
                        {
                            if (vTable[i].IsNull())
                            {
                                continue;
                            }

                            var scanResult = await PatternScanner.FindPattern(Utils.MemObj, vTable[i], vTable[i] + 0x300, new List <PatternScanner.Pattern> {
                                pattern
                            }, true);

                            if (!scanResult.ContainsKey(pattern.Name) || scanResult[pattern.Name].Empty())
                            {
                                continue;
                            }

                            c.PredefinedMethods.Add(PredefinedMethod.Inline($@"{funcStr.Replace("%d", i.ToString())}"));
                            break;
                        }
                    }
                }
            }

            // Wait logger
            await logTask;

            Classes.Add(c);
        }
Exemple #3
0
        /// <summary>
        /// Generates the members of a struct or class.
        /// </summary>
        /// <param name="structObj">The structure object.</param>
        /// <param name="offset">The start offset.</param>
        /// <param name="properties">The properties describing the members.</param>
        /// <returns>The members of the struct or class.</returns>
        private async Task <List <Member> > GenerateMembers(GenericTypes.UEStruct structObj, int offset, List <GenericTypes.UEProperty> properties)
        {
            var members                  = new List <Member>();
            var uniqueMemberNames        = new Dictionary <string, int>();
            int unknownDataCounter       = 0;
            var previousBitfieldProperty = new GenericTypes.UEBoolProperty();

            foreach (var prop in properties)
            {
                if (offset < await prop.GetOffset())
                {
                    int size = await prop.GetOffset() - offset;

                    members.Add(CreatePadding(unknownDataCounter++, offset, size, "MISSED OFFSET"));
                }

                var info = await prop.GetInfo();

                if (info.Type != GenericTypes.UEProperty.PropertyType.Unknown)
                {
                    var sp = new Member
                    {
                        Offset = await prop.GetOffset(),
                        Size   = info.Size,
                        Type   = info.CppType,
                        Name   = NameValidator.MakeValidName(await prop.GetName())
                    };

                    if (!uniqueMemberNames.ContainsKey(sp.Name))
                    {
                        uniqueMemberNames[sp.Name] = 1;
                    }
                    else
                    {
                        uniqueMemberNames[sp.Name]++;
                        sp.Name += uniqueMemberNames[sp.Name];
                    }

                    if (await prop.GetArrayDim() > 1)
                    {
                        sp.Name += $"[0x{await prop.GetArrayDim():X}]";
                    }

                    if (await prop.IsA <GenericTypes.UEBoolProperty>() && await prop.Cast <GenericTypes.UEBoolProperty>().IsBitfield())
                    {
                        var boolProp    = prop.Cast <GenericTypes.UEBoolProperty>();
                        var missingBits = await boolProp.GetMissingBitsCount(previousBitfieldProperty);

                        if (missingBits[1] != -1)
                        {
                            if (missingBits[0] > 0)
                            {
                                members.Add(CreateBitfieldPadding(unknownDataCounter++, await previousBitfieldProperty.GetOffset(), info.CppType, missingBits[0]));
                            }
                            if (missingBits[1] > 0)
                            {
                                members.Add(CreateBitfieldPadding(unknownDataCounter++, sp.Offset, info.CppType, missingBits[1]));
                            }
                        }
                        else if (missingBits[0] > 0)
                        {
                            members.Add(CreateBitfieldPadding(unknownDataCounter++, sp.Offset, info.CppType, missingBits[0]));
                        }

                        previousBitfieldProperty = boolProp;
                        sp.Name += " : 1";
                    }

                    sp.Name  = Generator.GetSafeKeywordsName(sp.Name);
                    sp.Flags = (int)await prop.GetPropertyFlags();

                    sp.FlagsString = PropertyFlags.StringifyFlags(await prop.GetPropertyFlags());

                    members.Add(sp);

                    int sizeMismatch = (await prop.GetElementSize() * await prop.GetArrayDim()) - (info.Size * await prop.GetArrayDim());
                    if (sizeMismatch > 0)
                    {
                        members.Add(CreatePadding(unknownDataCounter++, offset, sizeMismatch, "FIX WRONG TYPE SIZE OF PREVIOUS PROPERTY"));
                    }
                }
                else
                {
                    var size = await prop.GetElementSize() * await prop.GetArrayDim();

                    members.Add(CreatePadding(unknownDataCounter++, offset, size, "UNKNOWN PROPERTY: " + await prop.GetFullName()));
                }

                offset = await prop.GetOffset() + await prop.GetElementSize() * await prop.GetArrayDim();
            }

            if (offset < await structObj.GetPropertySize())
            {
                int size = await structObj.GetPropertySize() - offset;

                members.Add(CreatePadding(unknownDataCounter, offset, size, "MISSED OFFSET"));
            }

            return(members);
        }
Exemple #4
0
        /// <summary>
        /// Generates a script structure.
        /// </summary>
        /// <param name="scriptStructObj">The script structure object.</param>
        private async Task GenerateScriptStruct(GenericTypes.UEScriptStruct scriptStructObj)
        {
            var ss = new ScriptStruct
            {
                Name     = await scriptStructObj.GetName(),
                FullName = await scriptStructObj.GetFullName()
            };

            var logTask = Logger.Log($"Struct:  {await GetName() + "." + ss.Name, -85} - instance: 0x{scriptStructObj.GetAddress().ToInt64():X8}");

            ss.NameCpp     = NameValidator.MakeValidName(await scriptStructObj.GetNameCpp());
            ss.NameCppFull = "struct ";

            //some classes need special alignment
            var alignment = Generator.GetClassAlignas(ss.FullName);

            if (alignment == 0)
            {
                ss.NameCppFull += $"alignas({alignment}) ";
            }

            ss.NameCppFull += await NameValidator.MakeUniqueCppName(scriptStructObj);

            ss.Size = await scriptStructObj.GetPropertySize();

            ss.InheritedSize = 0;

            int offset = 0;
            var super  = await scriptStructObj.GetSuper();

            if (super.IsValid() && super != scriptStructObj)
            {
                ss.InheritedSize = offset = await scriptStructObj.GetPropertySize();

                ss.NameCppFull += $" : public {await NameValidator.MakeUniqueCppName(super.Cast<GenericTypes.UEScriptStruct>())}";
            }

            var properties = new List <GenericTypes.UEProperty>();

            for (var prop = (await scriptStructObj.GetChildren()).Cast <GenericTypes.UEProperty>(); prop.IsValid(); prop = (await prop.GetNext()).Cast <GenericTypes.UEProperty>())
            {
                var isScriptStruct = prop.IsA <GenericTypes.UEScriptStruct>();
                var isFunction     = prop.IsA <GenericTypes.UEFunction>();
                var isEnum         = prop.IsA <GenericTypes.UEEnum>();
                var isConst        = prop.IsA <GenericTypes.UEConst>();

                if (await prop.GetElementSize() > 0 &&
                    !await isScriptStruct &&
                    !await isFunction &&
                    !await isEnum &&
                    !await isConst)
                {
                    properties.Add(prop);
                }
            }

            // As C# sort not same as C++ version, that's not work
            // Anyway after some testes it's not needed !!
            // properties.Sort((x, y) => ComparePropertyLess(x, y).Result ? 0 : 1);

            var memberT = GenerateMembers(scriptStructObj, offset, properties);

            if (Generator.SdkType == SdkType.External)
            {
                // ToDO: Add external Read/Write here for external
            }

            Generator.GetPredefinedClassMethods(await scriptStructObj.GetFullName(), ref ss.PredefinedMethods);

            ss.Members = await memberT;
            ScriptStructs.Add(ss);

            // wait logger
            await logTask;
        }