Skip to content

Commit c65cdfc

Browse files
committed
Added FStructBaseChain to UStruct for faster IsA type checks.
1 parent 9e6682c commit c65cdfc

5 files changed

Lines changed: 104 additions & 7 deletions

File tree

Dumper/Engine/Private/OffsetFinder/OffsetFinder.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,49 @@ int32_t OffsetFinder::FindMinAlignmentOffset()
743743
return FindOffset(Infos);
744744
}
745745

746+
int32_t OffsetFinder::FindStructBaseChainOffset()
747+
{
748+
// UStruct inherits from FStructBaseChain, so the members of base chain should come right after UField
749+
750+
UEStruct Struct = ObjectArray::FindStructFast("Struct");
751+
if (!Struct)
752+
Struct = ObjectArray::FindStructFast("struct");
753+
754+
const int32 UStructStart = Struct.GetSuper().GetStructSize();
755+
const int32 UStructEnd = UStructStart + Struct.GetStructSize();
756+
757+
// If the members of UStruct come right after UField, FStructBaseChain either doesn't exist or is empty
758+
if (UStructStart == Off::UStruct::ChildProperties || UStructStart == Off::UStruct::Children)
759+
return OffsetNotFound;
760+
761+
auto CountSuperClasses = [](const UEStruct InStruct) -> int32
762+
{
763+
int32 Count = 0;
764+
765+
UEStruct CurrentSuper = InStruct.GetSuper();
766+
while (CurrentSuper)
767+
{
768+
Count++;
769+
CurrentSuper = CurrentSuper.GetSuper();
770+
}
771+
772+
return Count;
773+
};
774+
775+
/* Pair<UStruct, NumSuperClasses> */
776+
std::vector<std::pair<void*, int32_t>> Infos;
777+
778+
UEStruct APlayerController = ObjectArray::FindClassFast("PlayerController");
779+
UEStruct AActor = ObjectArray::FindClassFast("Actor");
780+
781+
Infos.push_back({ Struct.GetAddress(), CountSuperClasses(Struct) });
782+
Infos.push_back({ APlayerController.GetAddress(), CountSuperClasses(APlayerController) });
783+
Infos.push_back({ AActor.GetAddress(), CountSuperClasses(AActor) });
784+
785+
// FStructBaseChain::NumStructBasesInChainMinusOne is at offset 0x8, after a pointer
786+
return FindOffset(Infos, UStructStart, UStructEnd) - sizeof(void*);
787+
}
788+
746789
/* UFunction */
747790
int32_t OffsetFinder::FindFunctionFlagsOffset()
748791
{

Dumper/Engine/Private/OffsetFinder/Offsets.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ void Off::Init()
349349
std::cerr << std::format("Off::FFieldClass::CastFlags: 0x{:X}\n\n", Off::FFieldClass::CastFlags);
350350
}
351351

352+
Off::UStruct::StructBaseChain = OffsetFinder::FindStructBaseChainOffset();
353+
if (Off::UStruct::StructBaseChain != OffsetFinder::OffsetNotFound)
354+
std::cerr << std::format("Off::UStruct::StructBaseChain: 0x{:X}\n", Off::UStruct::StructBaseChain);
355+
352356
Off::UClass::ClassDefaultObject = OffsetFinder::FindDefaultObjectOffset();
353357
std::cerr << std::format("Off::UClass::ClassDefaultObject: 0x{:X}\n", Off::UClass::ClassDefaultObject);
354358

Dumper/Engine/Public/OffsetFinder/OffsetFinder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ namespace OffsetFinder
107107
int32_t FindChildPropertiesOffset();
108108
int32_t FindStructSizeOffset();
109109
int32_t FindMinAlignmentOffset();
110+
int32_t FindStructBaseChainOffset();
110111

111112
/* UFunction */
112113
int32_t FindFunctionFlagsOffset();

Dumper/Engine/Public/OffsetFinder/Offsets.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ namespace Off
195195

196196
namespace UStruct
197197
{
198+
/* Optional offset, if available we can generate a faster IsA implementation for the SDK. */
199+
inline int32 StructBaseChain = -1;
200+
198201
inline int32 SuperStruct;
199202
inline int32 Children;
200203
inline int32 ChildProperties;

Dumper/Generator/Private/Generators/CppGenerator.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,15 @@ void CppGenerator::InitPredefinedMembers()
18931893
});
18941894
}
18951895

1896+
if (Off::UStruct::StructBaseChain != -1)
1897+
{
1898+
UStructPredefs.Members.push_back({
1899+
.Comment = "NOT AUTO-GENERATED PROPERTY",
1900+
.Type = "struct FStructBaseChain", .Name = "BaseChain", .Offset = Off::UStruct::StructBaseChain, .Size = sizeof(void*) + sizeof(int32) + sizeof(uint32) /* PAD */, .ArrayDim = 0x1, .Alignment = alignof(void*),
1901+
.bIsStatic = false, .bIsZeroSizeMember = false, .bIsBitField = false, .BitIndex = 0xFF
1902+
});
1903+
}
1904+
18961905
PredefinedElements& UFunctionPredefs = PredefinedMembers[ObjectArray::FindClassFast("Function").GetIndex()];
18971906
UFunctionPredefs.Members =
18981907
{
@@ -2507,11 +2516,7 @@ R"({{
25072516

25082517
PredefinedElements& UStructPredefs = PredefinedMembers[UStructIdx];
25092518

2510-
UStructPredefs.Functions =
2511-
{
2512-
PredefinedFunction {
2513-
.CustomComment = "Checks if this class has a certain base",
2514-
.ReturnType = "bool", .NameWithParams = "IsSubclassOf(const UStruct* Base)", .Body =
2519+
const char* IsStructOfTypeCode =
25152520
R"({
25162521
if (!Base)
25172522
return false;
@@ -2523,7 +2528,25 @@ R"({
25232528
}
25242529
25252530
return false;
2526-
})",
2531+
})";
2532+
2533+
if (Off::UStruct::StructBaseChain != -1)
2534+
{
2535+
IsStructOfTypeCode =
2536+
R"({
2537+
if (!Base)
2538+
return false;
2539+
2540+
const int32 NumParentStructBasesInChainMinusOne = Base->BaseChain.NumStructBasesInChainMinusOne;
2541+
return NumParentStructBasesInChainMinusOne <= BaseChain.NumStructBasesInChainMinusOne && BaseChain.StructBaseChainArray[NumParentStructBasesInChainMinusOne] == &Base->BaseChain;
2542+
})";
2543+
}
2544+
2545+
UStructPredefs.Functions =
2546+
{
2547+
PredefinedFunction {
2548+
.CustomComment = "Checks if this class has a certain base",
2549+
.ReturnType = "bool", .NameWithParams = "IsSubclassOf(const UStruct* Base)", .Body = IsStructOfTypeCode,
25272550
.bIsStatic = false, .bIsConst = true, .bIsBodyInline = false
25282551
},
25292552
PredefinedFunction {
@@ -4697,6 +4720,28 @@ class TSubclassOf
46974720
};
46984721
)";
46994722

4723+
/* struct FStructBaseChain */
4724+
PredefinedStruct FStructBaseChain = PredefinedStruct{
4725+
.UniqueName = "FStructBaseChain", .Size = sizeof(void*) + sizeof(int32), .Alignment = alignof(void*), .bUseExplictAlignment = false, .bIsFinal = false, .bIsClass = false, .bIsUnion = false, .Super = nullptr
4726+
};
4727+
4728+
FStructBaseChain.Properties =
4729+
{
4730+
PredefinedMember {
4731+
.Comment = "NOT AUTO-GENERATED PROPERTY",
4732+
.Type = "FStructBaseChain**", .Name = "StructBaseChainArray", .Offset = 0x0, .Size = sizeof(void*), .ArrayDim = 0x1, .Alignment = alignof(void*),
4733+
.bIsStatic = false, .bIsZeroSizeMember = false, .bIsBitField = false, .BitIndex = 0xFF
4734+
},
4735+
PredefinedMember {
4736+
.Comment = "NOT AUTO-GENERATED PROPERTY",
4737+
.Type = "int32", .Name = "NumStructBasesInChainMinusOne", .Offset = sizeof(void*), .Size = sizeof(int32), .ArrayDim = 0x1, .Alignment = alignof(void*),
4738+
.bIsStatic = false, .bIsZeroSizeMember = false, .bIsBitField = false, .BitIndex = 0xFF
4739+
},
4740+
};
4741+
4742+
GenerateStruct(&FStructBaseChain, BasicHpp, BasicCpp, BasicHpp, AssertionsFile);
4743+
4744+
47004745
const int32 TextDataSize = (Off::InSDK::Text::InTextDataStringOffset + sizeof(FString));
47014746

47024747
/* class FTextData */
@@ -4713,7 +4758,8 @@ class TSubclassOf
47134758
},
47144759
};
47154760

4716-
BasicHpp << R"(namespace FTextImpl
4761+
BasicHpp << R"(
4762+
namespace FTextImpl
47174763
{)";
47184764
GenerateStruct(&FTextData, BasicHpp, BasicCpp, BasicHpp, AssertionsFile);
47194765
BasicHpp << "}\n";

0 commit comments

Comments
 (0)