public SDKClassInfo(IntPtr address, RemoteProcess remoteProcess, PEImageBuffer peImageBuffer)
        {
            ClassInfo     typeInfo     = remoteProcess.Read <ClassInfo>(address);
            ClassInfoData typeInfoData = remoteProcess.Read <ClassInfoData>(typeInfo.m_InfoData);

            Name         = $"{remoteProcess.ReadString(typeInfoData.m_Name, 255)}";
            ThisTypeInfo = address;
            Type         = typeInfoData.GetNewEntryType();
            Flags        = typeInfoData.m_Flags;
            Alignment    = typeInfoData.m_Alignment;
            TotalSize    = typeInfoData.m_TotalSize;
            FieldCount   = typeInfoData.m_FieldCount;
            ParentClass  = typeInfoData.m_SuperClass;
            var superClassInfo = new SDKTypeInfo(ParentClass, remoteProcess);

            ParentClassName = $"{superClassInfo.Name}";

            // debug
            if (Name == "PoseTrackKeyframe")
            {
                Name = Name;
            }
            // end debug

            // fill fields list
            if (FieldCount == 0)
            {
                if ((ParentClass != IntPtr.Zero) && (TotalSize > superClassInfo.TotalSize))
                {
                    SDKFieldEntry fieldEntry;

                    fieldEntry.fieldType         = "char";
                    fieldEntry.fieldInternalType = "Uint8";
                    fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                    fieldEntry.fieldName         = $"_0x{superClassInfo.TotalSize.ToString("X4")}[{TotalSize - superClassInfo.TotalSize}]";
                    fieldEntry.fieldOffset       = superClassInfo.TotalSize;
                    fieldEntry.fieldSize         = TotalSize - superClassInfo.TotalSize;
                    fieldEntry.lastFieldOffset   = 0;
                    fieldEntry.lastFieldSize     = 0;

                    Fields.Add(fieldEntry);

                    FieldCount++;
                }
                else if ((ParentClass == IntPtr.Zero) || (Name == ParentClassName))
                {
                    // reference oddity for (Name == ParentClassName) fb::IglooSubsystem : has itself as parent, 0 fields
                    SDKFieldEntry fieldEntry;

                    fieldEntry.fieldType         = "char";
                    fieldEntry.fieldInternalType = "Uint8";
                    fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                    fieldEntry.fieldName         = $"_0x000[{TotalSize}]";
                    fieldEntry.fieldOffset       = 0;
                    fieldEntry.fieldSize         = TotalSize;
                    fieldEntry.lastFieldOffset   = 0;
                    fieldEntry.lastFieldSize     = 0;

                    Fields.Add(fieldEntry);

                    FieldCount++;
                }
            }
            else //if (FieldCount > 0)
            {
                for (int i = 0; i < FieldCount; i++)
                {
                    var fieldInfoData = remoteProcess.Read <FieldInfoData>((IntPtr)((Int64)typeInfoData.m_Fields + (i * 0x18)));

                    SDKFieldEntry fieldEntry;
                    var           fieldTypeInfo = new SDKTypeInfo(fieldInfoData.m_FieldTypePtr, remoteProcess);

                    // fix the odd field type with flags as 0x0000 or 0x2000
                    if ((fieldInfoData.m_Flags == 0) || (fieldInfoData.m_Flags == 0x2000))
                    {
                        fieldEntry.fieldType = fieldTypeInfo.FixTypeName(fieldTypeInfo.Name);
                    }
                    else
                    {
                        fieldEntry.fieldType = fieldTypeInfo.GetCppType(); //fieldTypeInfo.Name;
                    }
                    fieldEntry.fieldInternalType = fieldTypeInfo.Name;
                    fieldEntry.fieldBasicType    = fieldTypeInfo.Type;//fieldInfoData.GetEntryType();

                    fieldEntry.fieldName       = remoteProcess.ReadString(fieldInfoData.m_Name, 255);
                    fieldEntry.fieldOffset     = fieldInfoData.m_FieldOffset;
                    fieldEntry.fieldSize       = fieldTypeInfo.TotalSize;
                    fieldEntry.lastFieldOffset = lastFieldOffset;
                    fieldEntry.lastFieldSize   = lastFieldSize;

                    // fix error with some bools being flagged as int16_t
                    if ((fieldEntry.fieldType == "int16_t") && (fieldEntry.fieldSize == 1))
                    {
                        fieldEntry.fieldType         = "bool";
                        fieldEntry.fieldInternalType = "Boolean";
                        fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Boolean;
                    }


                    Fields.Add(fieldEntry);

                    lastFieldOffset = fieldEntry.fieldOffset;
                    lastFieldSize   = fieldTypeInfo.TotalSize;
                }

                // the field array isn't sorted in offset order so fix that
                Fields = Fields.OrderBy(x => x.fieldOffset).ToList();

                // check if pads needed
                for (int i = 1; i < FieldCount; i++)
                {
                    lastFieldOffset = Fields.ElementAt(i - 1).fieldOffset;
                    lastFieldSize   = Fields.ElementAt(i - 1).fieldSize;

                    SDKFieldEntry fieldEntry;
                    fieldEntry = Fields.ElementAt(i);

                    fieldEntry.lastFieldOffset = lastFieldOffset;
                    fieldEntry.lastFieldSize   = lastFieldSize;

                    Fields[i] = fieldEntry;
                }

                for (int i = 0; i < FieldCount; i++)
                {
                    SDKFieldEntry fieldEntry;

                    if (i == (FieldCount - 1))
                    {
                        // last class member so check against total size
                        if (TotalSize > (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize))
                        {
                            fieldEntry.fieldType         = "char";
                            fieldEntry.fieldInternalType = "Uint8";
                            fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                            fieldEntry.fieldName         = $"_0x{(Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize).ToString("X4")}[{TotalSize - (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize)}]";
                            fieldEntry.fieldOffset       = Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize;
                            fieldEntry.fieldSize         = TotalSize - (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize);
                            fieldEntry.lastFieldOffset   = Fields.ElementAt(i).fieldOffset;
                            fieldEntry.lastFieldSize     = Fields.ElementAt(i).fieldSize;

                            Fields.Add(fieldEntry);

                            FieldCount++;
                        }
                    }

                    if ((i == 0) && (ParentClass != IntPtr.Zero))
                    {
                        // first class member so check against parent size
                        if (superClassInfo.TotalSize < Fields.ElementAt(i).fieldOffset)
                        {
                            var debug = Fields.ElementAt(i).fieldOffset;
                            fieldEntry.fieldType         = "char";
                            fieldEntry.fieldInternalType = "Uint8";
                            fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                            fieldEntry.fieldName         = $"_0x{superClassInfo.TotalSize.ToString("X4")}[{Fields.ElementAt(i).fieldOffset - superClassInfo.TotalSize}]";
                            fieldEntry.fieldOffset       = superClassInfo.TotalSize;
                            fieldEntry.fieldSize         = Fields.ElementAt(i).fieldOffset - superClassInfo.TotalSize;
                            fieldEntry.lastFieldOffset   = 0; // superClassInfo.TotalSize;
                            fieldEntry.lastFieldSize     = superClassInfo.TotalSize;

                            Fields.Insert(0, fieldEntry);

                            i++;
                            FieldCount++;
                        }
                    }
                    else
                    {
                        // inter-field pads. seems to be correct now :)
                        if (Fields.ElementAt(i).fieldOffset > (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize))
                        {
                            fieldEntry.fieldType         = "char";
                            fieldEntry.fieldInternalType = "Uint8";
                            fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                            fieldEntry.fieldName         = $"_0x{(Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize).ToString("X4")}[{Fields.ElementAt(i).fieldOffset - (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize)}]";
                            fieldEntry.fieldOffset       = Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize;
                            fieldEntry.fieldSize         = Fields.ElementAt(i).fieldOffset - (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize);
                            fieldEntry.lastFieldOffset   = Fields.ElementAt(i).fieldOffset;
                            fieldEntry.lastFieldSize     = Fields.ElementAt(i).fieldSize;

                            Fields.Insert(i, fieldEntry);

                            i++;
                            FieldCount++;
                        }
                    }
                }
            }

            RuntimeId       = typeInfo.m_RuntimeId;
            Next            = typeInfo.m_Next;
            DefaultInstance = typeInfo.m_DefaultInstance;
            ClassId         = typeInfo.m_ClassId;
            GetVtable(remoteProcess, peImageBuffer);
        }
        public SDKValueTypeInfo(IntPtr address, RemoteProcess remoteProcess)
        {
            ValueTypeInfo     typeInfo     = remoteProcess.Read <ValueTypeInfo>(address);
            ValueTypeInfoData typeInfoData = remoteProcess.Read <ValueTypeInfoData>(typeInfo.m_InfoData);

            Name         = $"{remoteProcess.ReadString(typeInfoData.m_Name, 255)}";
            ThisTypeInfo = address;
            Type         = typeInfoData.GetNewEntryType();
            Flags        = typeInfoData.m_Flags;
            Alignment    = typeInfoData.m_Alignment;
            TotalSize    = typeInfoData.m_TotalSize;
            FieldCount   = typeInfoData.m_FieldCount;
            RuntimeId    = typeInfo.m_RuntimeId;
            Next         = typeInfo.m_Next;

            // fill fields list
            if (FieldCount == 0)
            {
                SDKFieldEntry fieldEntry;

                fieldEntry.fieldType         = "char";
                fieldEntry.fieldInternalType = "Uint8";
                fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                fieldEntry.fieldName         = $"_0x000[{TotalSize}]";
                fieldEntry.fieldOffset       = 0;
                fieldEntry.fieldSize         = TotalSize;
                fieldEntry.lastFieldOffset   = 0;
                fieldEntry.lastFieldSize     = 0;

                Fields.Add(fieldEntry);

                FieldCount++;
            }
            else
            {
                for (int i = 0; i < FieldCount; i++)
                {
                    var fieldInfoData = remoteProcess.Read <FieldInfoData>((IntPtr)((Int64)typeInfoData.m_Fields + (i * 0x18)));

                    SDKFieldEntry fieldEntry;
                    var           fieldTypeInfo = new SDKTypeInfo(fieldInfoData.m_FieldTypePtr, remoteProcess);

                    // fix the odd field type with flags as 0x0000 or 0x2000
                    if ((fieldInfoData.m_Flags == 0) || (fieldInfoData.m_Flags == 0x2000))
                    {
                        fieldEntry.fieldType = fieldTypeInfo.FixTypeName(fieldTypeInfo.Name);
                    }
                    else
                    {
                        fieldEntry.fieldType = fieldTypeInfo.GetCppType(); //fieldTypeInfo.Name;
                    }

                    fieldEntry.fieldInternalType = fieldTypeInfo.Name;
                    fieldEntry.fieldBasicType    = fieldTypeInfo.Type;//fieldInfoData.GetEntryType();

                    fieldEntry.fieldName       = remoteProcess.ReadString(fieldInfoData.m_Name, 255);
                    fieldEntry.fieldOffset     = fieldInfoData.m_FieldOffset;
                    fieldEntry.fieldSize       = fieldTypeInfo.TotalSize;
                    fieldEntry.lastFieldOffset = lastFieldOffset;
                    fieldEntry.lastFieldSize   = lastFieldSize;

                    // fix error with some bools being flagged as int16_t
                    if ((fieldEntry.fieldType == "int16_t") && (fieldEntry.fieldSize == 1))
                    {
                        fieldEntry.fieldType = "bool";
                    }


                    Fields.Add(fieldEntry);

                    lastFieldOffset = fieldEntry.fieldOffset;
                    lastFieldSize   = fieldTypeInfo.TotalSize;
                }

                // the field array isn't always sorted in offset order so fix that
                Fields = Fields.OrderBy(x => x.fieldOffset).ToList();

                // check if pads needed
                for (int i = 1; i < FieldCount; i++)
                {
                    lastFieldOffset = Fields.ElementAt(i - 1).fieldOffset;
                    lastFieldSize   = Fields.ElementAt(i - 1).fieldSize;

                    SDKFieldEntry fieldEntry;
                    fieldEntry = Fields.ElementAt(i);

                    fieldEntry.lastFieldOffset = lastFieldOffset;
                    fieldEntry.lastFieldSize   = lastFieldSize;

                    Fields[i] = fieldEntry;
                }

                for (int i = 0; i < FieldCount; i++)
                {
                    SDKFieldEntry fieldEntry;

                    if (i == (FieldCount - 1))
                    {
                        // last class member so check against total size
                        if (TotalSize > (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize))
                        {
                            fieldEntry.fieldType         = "char";
                            fieldEntry.fieldInternalType = "Uint8";
                            fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                            fieldEntry.fieldName         = $"_0x{(Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize).ToString("X4")}[{TotalSize - (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize)}]";
                            fieldEntry.fieldOffset       = Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize;
                            fieldEntry.fieldSize         = TotalSize - (Fields.ElementAt(i).fieldOffset + Fields.ElementAt(i).fieldSize);
                            fieldEntry.lastFieldOffset   = Fields.ElementAt(i).fieldOffset;
                            fieldEntry.lastFieldSize     = Fields.ElementAt(i).fieldSize;

                            Fields.Add(fieldEntry);

                            FieldCount++;
                        }
                    }
                    else
                    {
                        // inter-field pads. seems to be correct now :)
                        if (Fields.ElementAt(i).fieldOffset > (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize))
                        {
                            fieldEntry.fieldType         = "char";
                            fieldEntry.fieldInternalType = "Uint8";
                            fieldEntry.fieldBasicType    = BasicTypesEnum.kTypeCode_Uint8;
                            fieldEntry.fieldName         = $"_0x{(Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize).ToString("X4")}[{Fields.ElementAt(i).fieldOffset - (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize)}]";
                            fieldEntry.fieldOffset       = Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize;
                            fieldEntry.fieldSize         = Fields.ElementAt(i).fieldOffset - (Fields.ElementAt(i).lastFieldOffset + Fields.ElementAt(i).lastFieldSize);
                            fieldEntry.lastFieldOffset   = Fields.ElementAt(i).fieldOffset;
                            fieldEntry.lastFieldSize     = Fields.ElementAt(i).fieldSize;

                            Fields.Insert(i, fieldEntry);

                            i++;
                            FieldCount++;
                        }
                    }
                }
            }
        }