From b5fbf0ee55e68a7977948567d76df42e8e02293d Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Tue, 25 Jun 2024 19:24:02 +0200 Subject: [PATCH 1/8] fixing crashes and sdk generation --- UEDumper/Engine/Core/Core.cpp | 2 +- UEDumper/Engine/Generation/SDK.cpp | 16 +++- UEDumper/Engine/Generation/packageSorter.h | 96 ++++++++++++--------- UEDumper/Engine/Userdefined/Offsets.h | 6 +- UEDumper/Engine/Userdefined/UEdefinitions.h | 5 +- UEDumper/Frontend/Windows/LogWindow.cpp | 33 +++++-- UEDumper/Frontend/Windows/LogWindow.h | 1 + 7 files changed, 101 insertions(+), 58 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index f888868e..5ea2a380 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -1055,7 +1055,7 @@ void EngineCore::generatePackages(int64_t& finishedPackages, int64_t& totalPacka auto& generatedStruc = dataVector.back(); generatedStruc.isClass = isClass; - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "CORE", "Total member count: %d | Function count: %d", generatedStruc.cookedMembers.size(), generatedStruc.functions.size()); + windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "CORE", "Total member count: %d | Function count: %d", generatedStruc.definedMembers.size(), generatedStruc.functions.size()); } else if (object->IsA()) diff --git a/UEDumper/Engine/Generation/SDK.cpp b/UEDumper/Engine/Generation/SDK.cpp index 4cd3b132..660c9d40 100644 --- a/UEDumper/Engine/Generation/SDK.cpp +++ b/UEDumper/Engine/Generation/SDK.cpp @@ -646,16 +646,26 @@ void SDKGeneration::Generate(int& progressDone, int& totalProgress, int featureF totalProgress = sortedPackages.size(); progressDone = 0; + int tooLongNames = 0; for (auto& pack : sortedPackages) { + std::string packageName = pack->package.packageName; + if(packageName.length() > 100) + { + packageName = "tooLongPackage_" + std::to_string(tooLongNames++); + masterHeader << "// Package name has been changed because the name was too long. Original name:" << std::endl; + masterHeader << "// " << pack->package.packageName << std::endl; + } + windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "SDK GEN", "Baking package %s", pack->package.packageName.c_str()); - masterHeader << "#include \"SDK/" + pack->package.packageName + ".h\"" << std::endl; + + masterHeader << "#include \"SDK/" + packageName + ".h\"" << std::endl; if (pack->package.packageName == "BasicType") generateBasicType(); else { - std::string packageName = pack->package.packageName + ".h"; - std::ofstream package(SDKPath / packageName); + std::string _packageName = packageName + ".h"; + std::ofstream package(SDKPath / _packageName); printCredits(package); generatePackage(package, pack->package, featureFlags, originalPackageToMerged); package.close(); diff --git a/UEDumper/Engine/Generation/packageSorter.h b/UEDumper/Engine/Generation/packageSorter.h index caab304b..627b5137 100644 --- a/UEDumper/Engine/Generation/packageSorter.h +++ b/UEDumper/Engine/Generation/packageSorter.h @@ -34,10 +34,14 @@ inline std::vector sortPackages(int& progressDone, int& totalPro anyMergeFound = false; //a new vector we fill up this round and then replace the newPackages vector std::vector _newPackages{}; + + std::vector mergePackages{}; //this just acts as a temporary identifier to make sure when we queue a package to be merged we dont chack that package //otherwise when a abd b should merge obviously b and a have to merge too resulting in a duplicate merge std::vector skippedPackageDueToMerge{}; + std::vector packagesThatHaveBeenMerged{}; + //go over all packages for (auto& pack : newPackages) { @@ -48,7 +52,7 @@ inline std::vector sortPackages(int& progressDone, int& totalPro //reset the boolean bool mergefound = false; //go over all dependencies of the root package - for (auto& dependencyPackage : pack.package.dependencyPackages) + for (auto dependencyPackage : pack.package.dependencyPackages) { //go over all dependencies of the dependency package for (auto& dependencyOfDependencyPackage : dependencyPackage->dependencyPackages) @@ -63,6 +67,7 @@ inline std::vector sortPackages(int& progressDone, int& totalPro windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "merge found with %s and %s origin %s", dependencyPackage->packageName.c_str(), dependencyOfDependencyPackage->packageName.c_str(), pack.package.packageName.c_str()); + anyMergeFound = true; mergefound = true; //add him to the merges @@ -77,10 +82,14 @@ inline std::vector sortPackages(int& progressDone, int& totalPro } + skippedPackageDueToMerge.push_back(pack.package.packageName); + //if a merge has been found, recreate the entire package if (mergefound) { MergedPackage p; + //create a unique index + p.package.index = newPackages.size() + 100 + mergePackages.size(); //first sort out own references and remove dups std::set totalDependencyPackage; std::string name = "merged"; @@ -109,6 +118,7 @@ inline std::vector sortPackages(int& progressDone, int& totalPro p.package.dependencyPackages.insert(dependencyPackage); } _newPackages.push_back(p); + mergePackages.push_back(p); } //no merge? just add @@ -117,64 +127,64 @@ inline std::vector sortPackages(int& progressDone, int& totalPro progressDone++; } + //clear the vector and overwrite newPackages.clear(); - newPackages.insert(newPackages.end(), _newPackages.begin(), _newPackages.end()); - } while (anyMergeFound); - - progressDone = 0; - totalProgress = newPackages.size(); - //we cant get rid of all duplicates so we do it here just to check - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Eliminating double merges...."); - bool eraseDone = false; - do - { - //reset flag - eraseDone = false; + //we use this to already detect duplicate merges and to clear out any packages that got added before merged + //ie if a solo package got added into the vector before it got merged with other pkgs, it can stay there forever + //because merges will be always last in the loop - //iterate over all packages - for (auto& [mergedPackages, package] : newPackages) + if(mergePackages.size() > 0) { - //keep a tracker, a for int i loop would do the same - int tracker = -1; - for (auto& p1 : newPackages) + std::vector cleanedPackages{}; + + std::unordered_set blacklistedPkgs; + + for (auto& pack : mergePackages) { - tracker++; - //own package? skip - if (package.packageName == p1.package.packageName) - continue; - //are the merged packages a different size? then its guaranteed not a dup - if (mergedPackages.size() != p1.mergedPackages.size()) + //we do this so we prevent two merged packages blacklisting each other + if (blacklistedPkgs.contains(pack.package.index)) continue; + for (auto& cmpPack : _newPackages) + { + //we looking at the exact same package? - //sort the merged packages - std::ranges::sort(mergedPackages); - std::ranges::sort(p1.mergedPackages); + if (blacklistedPkgs.contains(cmpPack.package.index)) + continue; - //not the same? skip - if (mergedPackages != p1.mergedPackages) - continue; + if (cmpPack.package.index == pack.package.index) + continue; - //always a duplicate then + std::unordered_set elements(pack.mergedPackages.begin(), pack.mergedPackages.end()); - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", - "deleted %s because its same to %s", p1.package.packageName.c_str(), package.packageName.c_str()); + for(const auto& p1 : cmpPack.mergedPackages) + { + if(elements.contains(p1)) + { + blacklistedPkgs.insert(cmpPack.package.index); + break; + } + } + + } + } - //delete p1 package - newPackages.erase(newPackages.begin() + tracker); - //set this flag to recheck - eraseDone = true; - //break as we are done with this package - break; + for(auto& cmpPack : _newPackages) + { + if (blacklistedPkgs.contains(cmpPack.package.index)) + continue; + cleanedPackages.push_back(cmpPack); } - //completely break through and redo - if (eraseDone) - break; + + newPackages.insert(newPackages.end(), cleanedPackages.begin(), cleanedPackages.end()); } - } while (eraseDone); + else + newPackages.insert(newPackages.end(), _newPackages.begin(), _newPackages.end()); + + } while (anyMergeFound); progressDone = 0; totalProgress = newPackages.size(); diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index 6b113cce..7cef130d 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -104,9 +104,9 @@ inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0xDEADBEEF }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0xDEADBEEF }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x8EEA180 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x8F90B20 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x9100398 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); diff --git a/UEDumper/Engine/Userdefined/UEdefinitions.h b/UEDumper/Engine/Userdefined/UEdefinitions.h index f622429b..d5c3c288 100644 --- a/UEDumper/Engine/Userdefined/UEdefinitions.h +++ b/UEDumper/Engine/Userdefined/UEdefinitions.h @@ -45,7 +45,7 @@ //supported unreal engine versions, dont edit -#define UE_NOT_SET 99 +#define UE_NOT_SET 99 #define UE_4_19 0 #define UE_4_20 1 #define UE_4_21 2 @@ -64,10 +64,11 @@ /* UE version settings */ //set your games ue version -#define UE_VERSION UE_NOT_SET +#define UE_VERSION UE_5_03 /* SDK generation */ +//if this is set to true, the SDK will contain static asserts to check whether the struct sizes and members actually match their offsets #define WRITE_STATIC_ASSERT_TESTS TRUE diff --git a/UEDumper/Frontend/Windows/LogWindow.cpp b/UEDumper/Frontend/Windows/LogWindow.cpp index 3db14f21..8431860b 100644 --- a/UEDumper/Frontend/Windows/LogWindow.cpp +++ b/UEDumper/Frontend/Windows/LogWindow.cpp @@ -6,7 +6,6 @@ windows::LogWindow::LogWindow() { - } void windows::LogWindow::Log(logLevels level, const std::string& origin, const char* fmt, ...) @@ -29,9 +28,15 @@ void windows::LogWindow::Log(logLevels level, const std::string& origin, const c l.originandTime = "[" + oss.str() + " - " + origin + "]:"; l.level = level; +#if _DEBUG + printf("%s %s\n", l.originandTime.c_str(), l.message); +#endif + + logMutex.lock(); logs.push_back(l); if (ENUM(level) & ENUM(logLevels::LOGLEVEL_NORMAL)) displayLogs.push_back(l); + logMutex.unlock(); } int windows::LogWindow::getLogLevel() @@ -122,8 +127,14 @@ void windows::LogWindow::render() if (ImGui::BeginListBox("##loglistbox", ImVec2(ImGui::GetWindowSize().x - 15, ImGui::GetWindowSize().y - 50))) { for (int i = selectedLogRange; i < logSize && i < selectedLogRange + logRange; i++) { - const auto& log = _logs[i]; + + logMutex.lock(); + const auto log = _logs[i]; + logMutex.unlock(); const bool is_selected = (selectedLog == i); + + + memset(buf, 0, sizeof(log::message) + 51); sprintf_s(buf, sizeof(log::message) + 50, "%d %s %s", i, log.originandTime.c_str(), log.message); if (ENUM(log.level) & ENUM(logLevels::LOGLEVEL_WARNING)) @@ -139,16 +150,17 @@ void windows::LogWindow::render() if (is_selected && ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("%s", logs[i].message); + ImGui::Text("%s", log.message); ImGui::EndTooltip(); } ImGui::PopStyleColor(); + } - if (oldSize != logs.size()) + if (oldSize != logSize) { ImGui::SetScrollHereY(1.0f); - oldSize = logs.size(); + oldSize = logSize; } ImGui::EndListBox(); @@ -164,11 +176,13 @@ void windows::LogWindow::renderEditPopup() if (ImGui::Button("Export Log")) { std::ofstream file(EngineSettings::getWorkingDirectory() / "log.txt"); + logMutex.lock(); for (size_t i = 0; i < logs.size(); i++) { file << i << " " << logs[i].originandTime << " " << logs[i].message << std::endl; } file.close(); + logMutex.unlock(); Log(logLevels::LOGLEVEL_INFO, "LOGWINDOW", "Saved log to %s/%s!", EngineSettings::getWorkingDirectory().string().c_str(), "log.txt"); } } @@ -177,7 +191,14 @@ std::string windows::LogWindow::getLastLogMessage() { //returning a copy and not a reference //also returning a index rather than calling back because i dont trust back - return logs[logs.size() - 1].message; + + logMutex.lock(); + + std::string msg = logs[logs.size() - 1].message; + + logMutex.unlock(); + + return msg; } float windows::LogWindow::getLogWindowYSize() diff --git a/UEDumper/Frontend/Windows/LogWindow.h b/UEDumper/Frontend/Windows/LogWindow.h index 425485bc..1385a630 100644 --- a/UEDumper/Frontend/Windows/LogWindow.h +++ b/UEDumper/Frontend/Windows/LogWindow.h @@ -33,6 +33,7 @@ namespace windows char message[201]; logLevels level; }; + static inline std::mutex logMutex = {}; static inline std::vector logs{}; static inline std::vector displayLogs{}; static inline int oldSize = 0; From c09e848cc088924e458c1937e609debb201ee9d5 Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Mon, 15 Jul 2024 15:30:45 +0200 Subject: [PATCH 2/8] SDK generation finally fixed for 99% of games --- UEDumper/Engine/Core/Core.cpp | 68 +++- UEDumper/Engine/Core/EngineStructs.h | 4 +- UEDumper/Engine/Generation/MDK.cpp | 347 +++----------------- UEDumper/Engine/Generation/SDK.cpp | 81 +++-- UEDumper/Engine/Userdefined/Offsets.h | 6 +- UEDumper/Engine/Userdefined/UEdefinitions.h | 6 +- UEDumper/Frontend/Windows/DumpProgress.cpp | 2 +- UEDumper/Resources/Dumpspace/dumpspace.cpp | 15 +- UEDumper/Settings/EngineSettings.h | 2 + 9 files changed, 172 insertions(+), 359 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index 5ea2a380..8cda5210 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -361,6 +361,7 @@ bool EngineCore::generateStructOrClass(UStruct* object, std::vectorgetOffset(); + if (type.propertyType == PropertyType::Unknown) { windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_ONLY_LOG, "CORE", "Struct %s: %s at offset 0x%llX is unknown prop! Missing support?", object->getCName().c_str(), member.name.c_str(), member.offset); @@ -661,7 +662,16 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) if (endOffset - startOffset > 1) { //fill that with a unknownmember instead of bits - genUnknownMember(startOffset + 1, endOffset, 3); + //if the start bit is 0, which indicates the last defined bit was a 8th bit, + //we dont have to increase the startOffset as it would directly fit, however of the + //startbit is something else, we have to increase the start offset + //----case 1 ---- + // 0x10: 00000000 <- last defined bit was 8th, function gets called with 0x11 startOffset and startbit 0 + // 0x11: unknown + //----case 2 ---- + // 0x10: 0000---- <- last defined bit was 4th, function gets called with 0x10 startoffset and startbit 5 + // 0x11: unknown + genUnknownMember(startBit == 0 ? startOffset : startOffset + 1, endOffset, 3); //check if the end is < 0, then we can just stop if (endBit == 0) return; @@ -726,7 +736,7 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_ERROR, "ENGINECORE", "%s maxSize is zero! SDK for %s may not work correctly!", inherStruct->fullName.c_str(), eStruct.fullName.c_str()); printf("%s maxSize is zero! SDK for %s may not work correctly!\n", inherStruct->fullName.c_str(), eStruct.fullName.c_str()); } - genUnknownMember(inherStruct->maxSize, eStruct.definedMembers[0].offset, 3); + genUnknownMember(inherStruct->maxSize, eStruct.definedMembers[0].offset, 8); } } else if(!eStruct.definedMembers.empty()) @@ -741,7 +751,7 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) //we are hoping (very hard) that definedmembers array is 1. sorted and 2. checked for collisions for (int i = 0; i < eStruct.definedMembers.size() - 1; i++) { - const auto& currentMember = eStruct.definedMembers[i]; + auto& currentMember = eStruct.definedMembers[i]; const auto& nextMember = eStruct.definedMembers[i + 1]; //bit shit @@ -796,6 +806,22 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) //0x2 [0x4] //0x6 unk[0x1] //0x7 [0x2] + + + //set the real size + if(!currentMember.type.isPointer()) + { + if (const auto classObject = getInfoOfObject(currentMember.type.name)) + { + if (classObject->type == ObjectInfo::OI_Struct || classObject->type == ObjectInfo::OI_Class) + { + const auto cclass = static_cast(classObject->target); + currentMember.size = cclass->maxSize * (currentMember.arrayDim <= 0 ? 1 : currentMember.arrayDim); + } + } + } + + if (nextMember.offset - (currentMember.offset + currentMember.size) > 0) { genUnknownMember(currentMember.offset + currentMember.size, nextMember.offset, 6); @@ -1164,6 +1190,7 @@ void EngineCore::finishPackages() { std::unordered_map enumLookupTable; std::unordered_map enumMap = {}; + std::unordered_set duplicatedClassNames{}; int duplicatedNames = 0; //were done, now we do packageObjectInfos caching, we couldnt do before because pointers are all on stack data and not in the static package vec for (int i = 0; i < packages.size(); i++) @@ -1183,7 +1210,11 @@ void EngineCore::finishPackages() if (packageObjectInfos.contains(struc.cppName)) { windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_WARNING, "ENGINECORE", "Duplicate name found: %s", struc.cppName.c_str()); + + if (!duplicatedClassNames.contains(struc.cppName)) + duplicatedClassNames.insert(struc.cppName); struc.cppName += "dup_" + std::to_string(duplicatedNames++); + } packageObjectInfos.insert(std::pair(struc.cppName, ObjectInfo(true, OI_type, &struc))); package.combinedStructsAndClasses.push_back(&struc); @@ -1198,6 +1229,13 @@ void EngineCore::finishPackages() packageObjectInfos.insert(std::pair(func.cppName, ObjectInfo(true, ObjectInfo::OI_Function, &func))); } + + //empty structs have a size of 1 + if(!struc.isClass && struc.maxSize == 0) + { + struc.size = 1; + struc.maxSize = 1; + } } }; @@ -1254,6 +1292,18 @@ void EngineCore::finishPackages() } } + //this check works only with broken structs + if(struc->supers.size() > 0) + { + //is the super max size is greater than the max size of the struct itself we have some weird cringe struc + auto super = struc->supers[0]; + if(super->maxSize > struc->maxSize) + { + struc->maxSize = super->maxSize; + struc->size = super->maxSize; + } + } + for (auto& var : struc->definedMembers) { if (!var.type.clickable) @@ -1262,6 +1312,18 @@ void EngineCore::finishPackages() if (!info || !info->valid) continue; + //if the type is a type where dumplicate classes exist, we have to erase it + //theres no way to know which one of the dup classes it refers to + //or maybe there is a way? maybe in the future with pointers or so.... + if(duplicatedClassNames.contains(var.type.name)) + { + var.type.clickable = false; + var.type.propertyType = PropertyType::Int8Property; + var.arrayDim = var.size; + var.name += "_unkBecDupClass_" + var.type.name; + var.type.name = TYPE_UCHAR; + } + var.type.info = info; for (auto& subtype : var.type.subTypes) diff --git a/UEDumper/Engine/Core/EngineStructs.h b/UEDumper/Engine/Core/EngineStructs.h index 76b87406..fbb73670 100644 --- a/UEDumper/Engine/Core/EngineStructs.h +++ b/UEDumper/Engine/Core/EngineStructs.h @@ -177,7 +177,7 @@ struct fieldType } else { - if ((propertyType == PropertyType::ObjectProperty || propertyType == PropertyType::ClassProperty) && clickable) + if (isPointer()) { typeStr += "*"; } @@ -236,7 +236,7 @@ namespace EngineStructs fieldType type; //type of the member std::string name; //name of the member int offset = 0; //offset of the member (real offset) - int size = 0; //size of the member + int size = 0; //total size of the member (size * arrayDim) int arrayDim = 0; // the number of elements if it's an array (e.g. int16_t foobar[123]) bool missed = false; //if the member is actually a missed member and is just used to fill up bytes bool isBit = false; //if the member is a bit (": 1") diff --git a/UEDumper/Engine/Generation/MDK.cpp b/UEDumper/Engine/Generation/MDK.cpp index 0dcc4684..ca5679c1 100644 --- a/UEDumper/Engine/Generation/MDK.cpp +++ b/UEDumper/Engine/Generation/MDK.cpp @@ -9,6 +9,7 @@ #include "Frontend/Windows/LogWindow.h" #include "Settings/EngineSettings.h" #include "BasicType.h" +#include "packageSorter.h" void MDKGeneration::printCredits(std::ofstream& stream) { @@ -77,20 +78,34 @@ void MDKGeneration::generateBasicType() void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs::Package& package) { //flag some invalid characters in a name - auto generateValidVarName = [](const std::string& str) - { - std::string result = ""; - for (const char c : str) + auto generateValidVarName = [](const std::string& str, bool allowBrackets = false) { - if (static_cast(c) < 0 || !std::isalnum(c)) - result += '_'; - else - result += c; + std::string result = ""; + for (const char c : str) + { + if (c == ' ') + continue; + if (static_cast(c) < 0 || !std::isalnum(c)) + { + if (allowBrackets && (c == '[' || c == ']')) + result += c; + else + result += '_'; + } - } - //guaranteed 0 termination - return result; - }; + else + result += c; + + } + + const static std::unordered_set reservedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE" }; + + if (std::isdigit(result[0])) result = "_" + result; + if (reservedNames.contains(result)) result += "0"; + + //guaranteed 0 termination + return result; + }; for (auto& dependencies : package.dependencyPackages) { @@ -147,7 +162,7 @@ void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs:: continue; char finalBuf[600]; - std::string memberName = member.name; + std::string memberName = generateValidVarName(member.name, true); if (member.name.empty()) memberName = "noname"; @@ -161,9 +176,6 @@ void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs:: char nameBuf[500]; - if (memberName == "bool" || memberName == "char" || memberName == "int" || memberName == "float" || memberName == "TRUE" || memberName == "FALSE") { - memberName += "_"; - } if (alreadyDefinedMembers.contains(memberName)) { int j = alreadyDefinedMembers[memberName]; @@ -234,14 +246,14 @@ void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs:: stream << "{" << std::endl; int j = 0; - std::vector usedNames{ "float", "int", "bool", "double", "long", "char"}; + std::vector usedNames{}; for (const auto& member : enu.members) { j++; char memberBuf[300]; - std::string fir = member.first; + std::string fir = generateValidVarName(member.first); if (std::ranges::find(usedNames, fir) != usedNames.end()) fir += std::to_string(j); @@ -311,304 +323,39 @@ void MDKGeneration::generate(int& progressDone, int& totalProgress) )"; - struct MergedPackage - { - std::vector mergedPackages; - EngineStructs::Package package; - }; - std::vector newPackages; - - for (auto& pack : EngineCore::getPackages()) - { - MergedPackage p; - p.mergedPackages = { &pack }; - p.package = pack; - newPackages.push_back(p); - } - - totalProgress = newPackages.size(); - - bool anyMergeFound = false; - - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Merging packages..."); - do - { - progressDone = 0; - anyMergeFound = false; - //a new vector we fill up this round and then replace the newPackages vector - std::vector _newPackages{}; - //this just acts as a temporary identifier, it just has to be smth unique per package - std::vector skippedPackageDueToMerge{}; - for (auto& pack : newPackages) - { - //skip this if package is listed as a merge with a package processed before - if (std::ranges::find(skippedPackageDueToMerge, pack.package.packageName) != skippedPackageDueToMerge.end()) - continue; - bool mergefound = false; - for (auto& neighbour : pack.package.dependencyPackages) - { - for (auto& neighbourNeighbour : neighbour->dependencyPackages) - { - if (std::ranges::find(pack.mergedPackages, neighbourNeighbour) == pack.mergedPackages.end()) - continue; - - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", - "merge found with %s and %s origin %s", neighbour->packageName.c_str(), neighbourNeighbour->packageName.c_str(), pack.package.packageName.c_str()); - - anyMergeFound = true; - mergefound = true; - //add him to the merges - pack.mergedPackages.push_back(neighbour); - skippedPackageDueToMerge.push_back(neighbour->packageName); - - break; - } - } - //if a merge has been found, recreate the entire package - if (mergefound) - { - MergedPackage p; - //first sort out own references and remove dups - std::set neighbours; - std::string name = "merged"; - //merge all the mininal needed stuff together - for (auto& mergedpack : pack.mergedPackages) - { - name += "_" + mergedpack->packageName; - //add da items - p.package.enums.insert(p.package.enums.end(), mergedpack->enums.begin(), mergedpack->enums.end()); - p.package.combinedStructsAndClasses.insert(p.package.combinedStructsAndClasses.end(), mergedpack->combinedStructsAndClasses.begin(), mergedpack->combinedStructsAndClasses.end()); - for (auto& neighbour : mergedpack->dependencyPackages) - { - //skip these packages that get merged, so if 1 and 2 merge, 2 neighbour 1 and 1 neighbour 2 get skipped - if (std::ranges::find(pack.mergedPackages, neighbour) == pack.mergedPackages.end()) - { - neighbours.insert(neighbour); - } - } - } - p.mergedPackages.insert(p.mergedPackages.end(), pack.mergedPackages.begin(), pack.mergedPackages.end()); - p.package.packageName = name; - //add the depenencies - for (auto& neighbour : neighbours) - { - p.package.dependencyPackages.insert(neighbour); - } - _newPackages.push_back(p); - - } - //no merge? just add - else - _newPackages.push_back(pack); - - progressDone++; - } - newPackages.clear(); - newPackages.insert(newPackages.end(), _newPackages.begin(), _newPackages.end()); - } while (anyMergeFound); - - progressDone = 0; - totalProgress = newPackages.size(); - - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Eliminating double merges...."); - bool eraseDone = false; - do - { - eraseDone = false; - - for (auto& p : newPackages) - { - int tracker = -1; - for (auto& p1 : newPackages) - { - tracker++; - if (p.package.packageName == p1.package.packageName) - continue; - if (p.mergedPackages.size() != p1.mergedPackages.size()) - continue; - - - - std::ranges::sort(p.mergedPackages); - std::ranges::sort(p1.mergedPackages); - - if (p.mergedPackages != p1.mergedPackages) - continue; - - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", - "deleted %s because its same to %s", p1.package.packageName.c_str(), p.package.packageName.c_str()); - - //delete p1 package - newPackages.erase(newPackages.begin() + tracker); - eraseDone = true; - break; - - } - //completely break through and redo - if (eraseDone) - break; - } - } while (eraseDone); - - progressDone = 0; - totalProgress = newPackages.size(); - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Reordering structs"); - - bool didReordering = false; - do - { - didReordering = false; - - for (auto& [mergedPackages, package] : newPackages) - { - progressDone++; - std::vector orderedStructsAndClasses; - for (auto& item : package.combinedStructsAndClasses) - { - auto currentIt = std::ranges::find( - orderedStructsAndClasses, item); - //is it not in? then add - if (currentIt == orderedStructsAndClasses.end()) - { - orderedStructsAndClasses.push_back(item); - currentIt = orderedStructsAndClasses.end() - 1; - } - if (!item->inherited) - continue; - - //check if the inherited struct is part of this package - if (std::ranges::find(mergedPackages, item->supers[0]->owningPackage) != mergedPackages.end()) - { - auto neededIt = std::ranges::find(orderedStructsAndClasses, item->supers[0]); - if (neededIt > currentIt) - { - //not in the list? - if (neededIt == orderedStructsAndClasses.end()) - { - orderedStructsAndClasses.insert(currentIt, item->supers[0]); - continue; - } - //move up - didReordering = true; - auto it = *neededIt; - orderedStructsAndClasses.erase(neededIt); - orderedStructsAndClasses.insert(currentIt, it); - } - } - } - //we have to create new vecotr, if we erase item vector now, pointers are invalid - std::vector newitems; - for (auto& pair : orderedStructsAndClasses) - { - newitems.push_back(pair); - } - package.combinedStructsAndClasses.clear(); - package.combinedStructsAndClasses.insert(package.combinedStructsAndClasses.begin(), newitems.begin(), newitems.end()); - - } - - } while (didReordering); - - - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Reordering packages"); - std::vector orderedPackages; - - const float one_thousand = 1000; - // Max number of iterations before we give up - // Using some very large number - it's to prevent infinite loops, not break too early before convergence - const auto maxIterations = 20 * one_thousand; - progressDone = 0; - totalProgress = maxIterations; // Note: we may converge before this and end up with a Microsoft style progress bar that magically jumps to 100% while (didReordering && progressDone < totalProgress); - - do - { - progressDone++; - didReordering = false; - for (auto& p : newPackages) - { - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "fixing package imports of %s", p.package.packageName.c_str()); - auto currentPackageIt = std::ranges::find( - orderedPackages, &p); - - //is it not in? then add - if (currentPackageIt == orderedPackages.end()) - { - orderedPackages.push_back(&p); - currentPackageIt = orderedPackages.end() - 1; - } - for (auto& neighbour : p.package.dependencyPackages) - { - //iterate through all merged package until we find the neighbour this class needs, so - //we can ensure the dependeny is before our current packafwe - for (auto& p_ : newPackages) - { - //check the mergedpackages if this is the package were actually looking for - //we have to look through the merged because maybe the package we need as dependency is merged with another package - if (std::ranges::find(p_.mergedPackages, neighbour) != p_.mergedPackages.end()) - { - auto neededPackageIt = std::ranges::find(orderedPackages, &p_); - if (neededPackageIt > currentPackageIt) //also if that merge is not in the list before - { - didReordering = true; - if (neededPackageIt == orderedPackages.end()) - { - //printf("inserting %s before %s because it needs it and isnt in it or above\n", p_.package.packageName.c_str(), p.package.packageName.c_str()); - orderedPackages.insert(currentPackageIt, &p_); - currentPackageIt = std::ranges::find( - orderedPackages, &p); - break; - //currentPackageIt = orderedPackages.end() - 1; - } - else - { - auto it = *neededPackageIt; - orderedPackages.erase(neededPackageIt); - currentPackageIt = std::ranges::find( - orderedPackages, &p); - orderedPackages.insert(currentPackageIt, it); - currentPackageIt = std::ranges::find( - orderedPackages, &p); - break; - //std::rotate(currentPackageIt, neededPackageIt, neededPackageIt + 1); - //printf("inserted %s before %s because it was too high up\n", newNeededPackageIt.operator*()->package.packageName.c_str(), currentPackageIt.operator*()->package.packageName.c_str()); - } - } - } - - } - } - } - } while (didReordering && progressDone < totalProgress); - if (didReordering) - { - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_ERROR, "MDK GEN", "Unable to resolve cyclic import dependencies after %.2fK iterations", progressDone / one_thousand); - } - else - { - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Converged imports after %.2fK iterations", progressDone / one_thousand); - progressDone = totalProgress; - } + const auto sortedPackages = sortPackages(progressDone, totalProgress, newPackages); puts("------sorted packages------"); - for (auto& pack : orderedPackages) + for (auto& pack : sortedPackages) { printf("%s\n", pack->package.packageName.c_str()); } puts("---------------------------"); + totalProgress = sortedPackages.size(); progressDone = 0; - for (auto& pack : orderedPackages) + int tooLongNames = 0; + for (auto& pack : sortedPackages) { - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Baking package %s", pack->package.packageName.c_str()); + std::string packageName = pack->package.packageName; + if (packageName.length() > 100) + { + packageName = "tooLongPackage_" + std::to_string(tooLongNames++); + masterHeader << "// Package name has been changed because the name was too long. Original name:" << std::endl; + masterHeader << "// " << pack->package.packageName << std::endl; + } + + windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Baking package %s", packageName.c_str()); + masterHeader << "#include \"MDK/" + pack->package.packageName + ".h\"" << std::endl; if (pack->package.packageName == "BasicType") generateBasicType(); else { - std::string packageName = pack->package.packageName + ".h"; - std::ofstream package(SDKPath / packageName); + std::string _packageName = packageName + ".h"; + std::ofstream package(SDKPath / _packageName); printCredits(package); generatePackage(package, pack->package); package.close(); diff --git a/UEDumper/Engine/Generation/SDK.cpp b/UEDumper/Engine/Generation/SDK.cpp index 660c9d40..9cb60e51 100644 --- a/UEDumper/Engine/Generation/SDK.cpp +++ b/UEDumper/Engine/Generation/SDK.cpp @@ -92,15 +92,21 @@ void SDKGeneration::generatePackage( ) { stream << "#pragma once\n"; //flag some invalid characters in a name - auto generateValidVarName = [](const std::string& str) + auto generateValidVarName = [](const std::string& str, bool allowBrackets = false) { std::string result = ""; for (const char c : str) { if (c == ' ') continue; - else if (static_cast(c) < 0 || !std::isalnum(c)) - result += '_'; + if (static_cast(c) < 0 || !std::isalnum(c)) + { + if(allowBrackets && (c == '[' || c == ']')) + result += c; + else + result += '_'; + } + else result += c; @@ -136,6 +142,8 @@ void SDKGeneration::generatePackage( stream << "\n"; + stream << "#pragma pack(push, 0x1)\n" << std::endl; + auto generateForwardDecls = [&](const std::vector& DataStruc) { std::set forwardDeclTypes; // ordered in case SDK is in VCS @@ -243,7 +251,16 @@ void SDKGeneration::generatePackage( for (const auto& struc : DataStruc) { char buf[1024] = { 0 }; - sprintf_s(buf, "static_assert(sizeof(%s) == 0x%04X); // %d bytes (0x%06X - 0x%06X)", generateValidVarName(struc->cppName).c_str(), struc->maxSize, struc->maxSize, struc->getInheritedSize(), struc->maxSize); + + //maxsize has been decresed to 0 because of a super struct, we have to "fix it" + //for the static assert as single structs with no member cant be 0 bytes + + uint64_t actualSize = struc->maxSize; + + if(struc->size == 1 && struc->maxSize == 0) + actualSize = 1; + + sprintf_s(buf, "static_assert(sizeof(%s) == 0x%04X); // %d bytes (0x%06X - 0x%06X)", generateValidVarName(struc->cppName).c_str(), actualSize, struc->maxSize, struc->getInheritedSize(), actualSize); stream << buf << std::endl; } }; @@ -253,13 +270,13 @@ void SDKGeneration::generatePackage( for (const auto& struc : DataStruc) { const auto klass = generateValidVarName(struc->cppName); - std::vector usedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE" }; + std::vector usedNames{}; int j = 0; for (int i = 0; i < struc->cookedMembers.size(); i++) { const auto member = struc->getMemberForIndex(i); - std::string name = member->name; + std::string name = generateValidVarName(member->name, true); if (std::isdigit(name[0])) name = "_" + name; @@ -291,42 +308,25 @@ void SDKGeneration::generatePackage( continue; allnames.push_back(generateValidVarName(struc->cppName)); - bool needsHelp = false; - if (struc->cookedMembers.size() > 0) - { - if (struc->minAlignment > 0 && (struc->maxSize % struc->minAlignment) > 0) - { - needsHelp = true; - } - } - if (struc->isClass) stream << "/// Class " << struc->fullName << std::endl; else { stream << "/// Struct " << struc->fullName << std::endl; - if (struc->maxSize == 0) - { - // it's an empty struct, but by default will take up 1 byte - struc->size = 0x1; - struc->maxSize = 0x1; - } } char buf[256] = { 0 }; sprintf_s( buf, - "Size: 0x%04X (%d bytes) (0x%06X - 0x%06X) align %s pad: 0x%04X", - struc->size - struc->getInheritedSize(), - struc->size - struc->getInheritedSize(), + "Size: 0x%04X (%d bytes) (0x%06X - 0x%06X) align %s MaxSize: 0x%04X", + struc->size, + struc->size, struc->getInheritedSize(), struc->size, (struc->minAlignment > 0 ? std::to_string(struc->minAlignment) : "n/a").c_str(), - needsHelp ? struc->maxSize % struc->minAlignment : 0 + struc->maxSize ); stream << "/// " << buf << std::endl; - if (needsHelp) stream << "#pragma pack(push, 0x1)" << std::endl; - if (struc->isClass) stream << "class "; else @@ -353,7 +353,7 @@ void SDKGeneration::generatePackage( if (struc->isClass) stream << "public:" << std::endl; - std::vector usedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE"}; + std::vector usedNames{}; int j = 0; @@ -363,9 +363,7 @@ void SDKGeneration::generatePackage( const auto member = struc->getMemberForIndex(i); char finalBuf[600]; char nameBuf[500]; - std::string name = member->name; - - + std::string name = generateValidVarName(member->name, true); if (name.empty()) name = "noname"; @@ -418,7 +416,6 @@ void SDKGeneration::generatePackage( if (alreadyGeneratedFunctions.contains(func.fullName)) { // some blueprint functions will be duplicated with exact same signatures, offsets, the lot windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_WARNING, "SDK GEN", "WARNING: Duplicate function %s in struct %s. Skipping...", func.fullName.c_str(), struc->fullName.c_str()); - printf("WARNING: Duplicate function %s in struct %s. Skipping...\n", func.fullName.c_str(), struc->fullName.c_str()); continue; } alreadyGeneratedFunctions.insert(func.fullName); @@ -493,11 +490,7 @@ void SDKGeneration::generatePackage( vtableIndex++; } - if (needsHelp) - { - stream << "};\n#pragma pack(pop)\n\n"; - } - else stream << "};\n\n"; + stream << "};\n\n"; } @@ -520,14 +513,14 @@ void SDKGeneration::generatePackage( stream << "{" << std::endl; int j = 0; - std::vector usedNames{ "float", "int", "bool", "double", "long", "char"}; + std::vector usedNames{}; for (const auto& member : enu.members) { j++; char memberBuf[300]; - std::string fir = member.first; + std::string fir = generateValidVarName(member.first); if (std::ranges::find(usedNames, fir) != usedNames.end()) fir += std::to_string(j); @@ -548,10 +541,10 @@ void SDKGeneration::generatePackage( std::vector structs; std::vector classes; - for (auto package : package.combinedStructsAndClasses) + for (auto cpackage : package.combinedStructsAndClasses) { - if (package->isClass) classes.push_back(package); - else structs.push_back(package); + if (cpackage->isClass) classes.push_back(cpackage); + else structs.push_back(cpackage); } generateStruct(structs); @@ -562,6 +555,8 @@ void SDKGeneration::generatePackage( generateStruct(package.combinedStructsAndClasses); } + stream << "#pragma pack(pop)\n\n" << std::endl; + // add static asserts for objects if (featureFlags & FeatureFlags::SDK::STATIC_ASSERTS_OBJECT_SIZE) generateStaticAssertsForObjectSizes(package.combinedStructsAndClasses); @@ -657,7 +652,7 @@ void SDKGeneration::Generate(int& progressDone, int& totalProgress, int featureF masterHeader << "// " << pack->package.packageName << std::endl; } - windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "SDK GEN", "Baking package %s", pack->package.packageName.c_str()); + windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "SDK GEN", "Baking package %s", packageName.c_str()); masterHeader << "#include \"SDK/" + packageName + ".h\"" << std::endl; if (pack->package.packageName == "BasicType") diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index 7cef130d..0e53cc98 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -104,9 +104,9 @@ inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x8EEA180 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x8F90B20 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x9100398 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x8F2AE80 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x8FD1820 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x6F67C48 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); diff --git a/UEDumper/Engine/Userdefined/UEdefinitions.h b/UEDumper/Engine/Userdefined/UEdefinitions.h index d5c3c288..879f90d4 100644 --- a/UEDumper/Engine/Userdefined/UEdefinitions.h +++ b/UEDumper/Engine/Userdefined/UEdefinitions.h @@ -35,8 +35,10 @@ #define RELEASE_1_9_FINAL 17 #define RELEASE_1_10_BETA 18 #define RELEASE_1_10_FINAL 19 +#define RELEASE_1_11_BETA 20 +#define RELEASE_1_11_FINAL 21 -#define DUMPER_VERSION RELEASE_1_10_BETA +#define DUMPER_VERSION RELEASE_1_11_BETA /// This file contains engine definitions that you have to edit depending on the game! @@ -67,7 +69,7 @@ #define UE_VERSION UE_5_03 -/* SDK generation */ +/* SDK and MDK generation */ //if this is set to true, the SDK will contain static asserts to check whether the struct sizes and members actually match their offsets #define WRITE_STATIC_ASSERT_TESTS TRUE diff --git a/UEDumper/Frontend/Windows/DumpProgress.cpp b/UEDumper/Frontend/Windows/DumpProgress.cpp index 63cb72e1..f6672c9e 100644 --- a/UEDumper/Frontend/Windows/DumpProgress.cpp +++ b/UEDumper/Frontend/Windows/DumpProgress.cpp @@ -177,7 +177,7 @@ bool windows::DumpProgress::render() skip: { //- } - ImGui::Text(LogWindow::getLastLogMessage().c_str()); + ImGui::TextWrapped(LogWindow::getLastLogMessage().c_str()); } ImGui::EndChild(); return false; diff --git a/UEDumper/Resources/Dumpspace/dumpspace.cpp b/UEDumper/Resources/Dumpspace/dumpspace.cpp index 025f2439..b70ddb89 100644 --- a/UEDumper/Resources/Dumpspace/dumpspace.cpp +++ b/UEDumper/Resources/Dumpspace/dumpspace.cpp @@ -44,8 +44,13 @@ namespace Dumpspace j["version"] = version; j["data"] = nlohmann::json(offsets); + nlohmann::json credit; + credit["dumper_used"] = "UEDumper"; + credit["dumper_link"] = "https://github.com/Spuckwaffel/UEDumper"; + j["credit"] = credit; + std::ofstream file(directory / "OffsetsInfo.json"); - file << j.dump(); + file << j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); } void DumpClasses(const std::filesystem::path& directory) { @@ -55,7 +60,7 @@ namespace Dumpspace j["data"] = classes; std::ofstream file(directory / "ClassesInfo.json"); - file << j.dump(); + file << j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); } void DumpFunctions(const std::filesystem::path& directory) { @@ -65,7 +70,7 @@ namespace Dumpspace j["data"] = functions; std::ofstream file(directory / "FunctionsInfo.json"); - file << j.dump(); + file << j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); } void DumpStructs(const std::filesystem::path& directory) { @@ -75,7 +80,7 @@ namespace Dumpspace j["data"] = structs; std::ofstream file(directory / "StructsInfo.json"); - file << j.dump(); + file << j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); } void DumpEnums(const std::filesystem::path& directory) { @@ -85,7 +90,7 @@ namespace Dumpspace j["data"] = enums; std::ofstream file(directory / "EnumsInfo.json"); - file << j.dump(); + file << j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace); } void Dump(std::filesystem::path directory) { diff --git a/UEDumper/Settings/EngineSettings.h b/UEDumper/Settings/EngineSettings.h index 626251e3..7e995840 100644 --- a/UEDumper/Settings/EngineSettings.h +++ b/UEDumper/Settings/EngineSettings.h @@ -51,6 +51,8 @@ class EngineSettings "Version 1.9 Release", "Version 1.10 BETA", "Version 1.10 Release", + "Version 1.11 BETA", + "Version 1.11 Release", }; private: From de5ec88c3e54b3d7fe093b0c4459e1fae674c883 Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Mon, 15 Jul 2024 15:38:42 +0200 Subject: [PATCH 3/8] fixed offsets --- UEDumper/Engine/Userdefined/Offsets.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index 0e53cc98..6b113cce 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -104,9 +104,9 @@ inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x8F2AE80 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x8FD1820 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x6F67C48 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0xDEADBEEF }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); From f62d458933c6506a72496f5222abe3c9da213d0f Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Thu, 18 Jul 2024 03:18:52 +0200 Subject: [PATCH 4/8] Added many structs so compilations work better and now using more props - Borderlands3 (90 GB) compiles now --- UEDumper/Engine/Core/Core.cpp | 34 +++-- UEDumper/Engine/Core/EngineStructs.h | 1 + UEDumper/Engine/Core/ObjectsManager.h | 2 +- UEDumper/Engine/Generation/BasicType.h | 114 ++++++++++++++++ UEDumper/Engine/Generation/SDK.cpp | 6 + UEDumper/Engine/UEClasses/UnrealClasses.cpp | 27 +++- UEDumper/Engine/UEClasses/UnrealClasses.h | 14 +- UEDumper/Engine/Userdefined/Offsets.h | 6 +- .../Engine/Userdefined/StructDefinitions.h | 123 ++++++++++++++++++ UEDumper/Engine/Userdefined/UEdefinitions.h | 2 +- UEDumper/Engine/structs.h | 88 +++++++++++++ 11 files changed, 392 insertions(+), 25 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index 8cda5210..303cc7c9 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -626,6 +626,24 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) eStruct.cookedMembers.clear(); + auto checkRealMemberSize = [&](EngineStructs::Member* currentMember) + { + //set the real size + if (!currentMember->type.isPointer()) + { + if (const auto classObject = getInfoOfObject(currentMember->type.name)) + { + if (classObject->type == ObjectInfo::OI_Struct || classObject->type == ObjectInfo::OI_Class) + { + const auto cclass = static_cast(classObject->target); + if(!cclass->noFixedSize) + currentMember->size = cclass->maxSize * (currentMember->arrayDim <= 0 ? 1 : currentMember->arrayDim); + } + } + } + }; + + auto genUnknownMember = [&](int from, int to, int special) { EngineStructs::Member unknown; @@ -808,18 +826,7 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) //0x7 [0x2] - //set the real size - if(!currentMember.type.isPointer()) - { - if (const auto classObject = getInfoOfObject(currentMember.type.name)) - { - if (classObject->type == ObjectInfo::OI_Struct || classObject->type == ObjectInfo::OI_Class) - { - const auto cclass = static_cast(classObject->target); - currentMember.size = cclass->maxSize * (currentMember.arrayDim <= 0 ? 1 : currentMember.arrayDim); - } - } - } + checkRealMemberSize(¤tMember); if (nextMember.offset - (currentMember.offset + currentMember.size) > 0) @@ -835,7 +842,8 @@ void EngineCore::cookMemberArray(EngineStructs::Struct & eStruct) } //add the last member eStruct.cookedMembers.push_back(std::pair(true, eStruct.definedMembers.size() - 1)); - const auto& last = eStruct.getMemberForIndex(eStruct.cookedMembers.size() - 1); + auto last = eStruct.getMemberForIndex(eStruct.cookedMembers.size() - 1); + checkRealMemberSize(last); if (last->offset + last->size < eStruct.maxSize) genUnknownMember(last->offset + last->size, eStruct.maxSize, 7); } diff --git a/UEDumper/Engine/Core/EngineStructs.h b/UEDumper/Engine/Core/EngineStructs.h index fbb73670..abaf81d6 100644 --- a/UEDumper/Engine/Core/EngineStructs.h +++ b/UEDumper/Engine/Core/EngineStructs.h @@ -340,6 +340,7 @@ namespace EngineStructs std::vector superOfOthers{}; //all the structs that use this class as a super bool inherited = false; //if the struct is inherited int maxSize = 0; //the maximum size this struct is "allowed" to have, as size is not accurate due to padding and trailing + bool noFixedSize = false; // if this boolean is true, the current struct or class has no specific fixed size, meaning it can change (template classes) int minAlignment = 0; //minimal alignment defined by ue int size = 0; //propertiesSize, possibly wrong, use maxSize int unknownCount = 0; //keep track of all missed vars, only used for the package viewer to edit unknowndata diff --git a/UEDumper/Engine/Core/ObjectsManager.h b/UEDumper/Engine/Core/ObjectsManager.h index 73586f4f..ee7b2b65 100644 --- a/UEDumper/Engine/Core/ObjectsManager.h +++ b/UEDumper/Engine/Core/ObjectsManager.h @@ -269,7 +269,7 @@ class ObjectsManager #ifdef _DEBUG if (gamePtr < 0x100) { // if your pointer is less than 0x100, it's likely invalid and there's a bug. Check your structs - DebugBreak(); + //DebugBreak(); } #endif if(!gUObjectManager.linkedUObjectPtrs.contains(gamePtr)) diff --git a/UEDumper/Engine/Generation/BasicType.h b/UEDumper/Engine/Generation/BasicType.h index e5b33497..8bbb218d 100644 --- a/UEDumper/Engine/Generation/BasicType.h +++ b/UEDumper/Engine/Generation/BasicType.h @@ -292,6 +292,120 @@ class TEnumAsByte definedStructs.push_back(dStruct); + dStruct.name = "FWeakObjectPtr"; + dStruct.definition = + R"( +class FWeakObjectPtr +{ +public: + int32_t ObjectIndex; + int32_t ObjectSerialNumber; +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "TWeakObjectPtr"; + dStruct.definition = + R"( +template +class TWeakObjectPtr : public FWeakObjectPtr +{ +public: +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "TPersistentObjectPtr"; + dStruct.definition = + R"( +template +class TPersistentObjectPtr +{ +public: + FWeakObjectPtr WeakPtr; + int32_t TagAtLastTest; + TObjectID ObjectID; +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "FUniqueObjectGuid"; + dStruct.definition = + R"( +class FUniqueObjectGuid final +{ +public: + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "TLazyObjectPtr"; + dStruct.definition = + R"( +template +class TLazyObjectPtr : public TPersistentObjectPtr +{ +public: +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "FSoftObjectPath_"; + dStruct.definition = + R"( +struct FSoftObjectPath_ +{ +public: + FName AssetPathName; + FString SubPathString; +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "FSoftObjectPtr"; + dStruct.definition = + R"( +class FSoftObjectPtr : public TPersistentObjectPtr +{ +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "TSoftObjectPtr"; + dStruct.definition = + R"( +template +class TSoftObjectPtr : public FSoftObjectPtr +{ +public: +}; +)"; + + definedStructs.push_back(dStruct); + + dStruct.name = "TSoftClassPtr"; + dStruct.definition = + R"( +template +class TSoftClassPtr : public FSoftObjectPtr +{ +public: +}; +)"; + + definedStructs.push_back(dStruct); + dStruct.name = "TPair"; dStruct.definition = R"( diff --git a/UEDumper/Engine/Generation/SDK.cpp b/UEDumper/Engine/Generation/SDK.cpp index 9cb60e51..bc903e4d 100644 --- a/UEDumper/Engine/Generation/SDK.cpp +++ b/UEDumper/Engine/Generation/SDK.cpp @@ -503,8 +503,14 @@ void SDKGeneration::generatePackage( //first we generate enums + std::unordered_set definedEnums; + for (const auto& enu : package.enums) { + if (definedEnums.contains(enu.cppName)) + continue; + definedEnums.insert(enu.cppName); + stream << "/// Enum " << enu.fullName << std::endl; char buf[100] = { 0 }; sprintf_s(buf, "Size: 0x%02d (%d bytes)", enu.size, enu.size); diff --git a/UEDumper/Engine/UEClasses/UnrealClasses.cpp b/UEDumper/Engine/UEClasses/UnrealClasses.cpp index 89db90e6..bc562017 100644 --- a/UEDumper/Engine/UEClasses/UnrealClasses.cpp +++ b/UEDumper/Engine/UEClasses/UnrealClasses.cpp @@ -191,9 +191,10 @@ std::string UObject::getSecondPackageName() const bool UObject::IsA(const UClass* staticClass) const { if (!ClassPrivate) return false; + UClass* oldSup = nullptr; for (auto super = getClass(); super; super = super->getSuper()) { - if (!super) + if (!super || oldSup == super) return false; std::string fullname = super->getFullName(); if (super == staticClass) @@ -201,6 +202,7 @@ bool UObject::IsA(const UClass* staticClass) const //printf("%s\n", fullname.c_str()); return true; } + oldSup = super; } return false; @@ -443,6 +445,16 @@ fieldType UProperty::getType() if (const auto cast = castTo(); cast->getPropertyClass()) return{ true, PropertyType::WeakObjectProperty, UObjectPropertyBase::weakTypeName(), cast->getSubTypes() }; }; + if (IsA()) + { + if (const auto cast = castTo(); cast->getPropertyClass()) + return{ true, PropertyType::SoftObjectProperty, UObjectPropertyBase::softTypeName(), cast->getSubTypes() }; + }; + if (IsA()) + { + if (const auto cast = castTo(); cast->getPropertyClass()) + return{ true, PropertyType::LazyObjectProperty, UObjectPropertyBase::lazyTypeName(), cast->getSubTypes() }; + }; if (IsA()) { if (const auto cast = castTo(); cast->getPropertyClass()) @@ -565,6 +577,11 @@ UClass* UWeakObjectProperty::staticClass() return ObjectsManager::findObject("/Script/CoreUObject.WeakObjectProperty"); } +UClass* USoftObjectProperty::staticClass() +{ + return ObjectsManager::findObject("/Script/CoreUObject.SoftObjectProperty"); +} + UProperty* UInterfaceProperty::getInterfaceClass() const { UREADORNULL(UProperty, InterfaceClass) @@ -575,10 +592,10 @@ UClass* UInterfaceProperty::staticClass() return ObjectsManager::findObject("/Script/CoreUObject.InterfaceProperty"); } -std::string UWeakObjectProperty::typeName() -{ - return "struct TWeakObjectPtr()->typeName() + ">"; -} +//std::string UWeakObjectProperty::typeName() +//{ +// return "struct TWeakObjectPtr()->typeName() + ">"; +//} UClass* UClassProperty::getMetaClass() const { diff --git a/UEDumper/Engine/UEClasses/UnrealClasses.h b/UEDumper/Engine/UEClasses/UnrealClasses.h index d539e173..394b3d07 100644 --- a/UEDumper/Engine/UEClasses/UnrealClasses.h +++ b/UEDumper/Engine/UEClasses/UnrealClasses.h @@ -625,6 +625,7 @@ class UObjectPropertyBase : public UProperty std::string typeName() const { return getPropertyClass()->getCName(); } static std::string weakTypeName() { return "TWeakObjectPtr"; } + static std::string softTypeName() { return "TSoftObjectPtr"; } static std::string lazyTypeName() { return "TLazyObjectPtr"; } //only use on wak or lazy types! std::vector getSubTypes() const { return std::vector{ {true, PropertyType::ObjectProperty, getPropertyClass()->getCName()}}; } @@ -679,7 +680,16 @@ class UWeakObjectProperty : public UObjectPropertyBase public: using UObjectPropertyBase::UObjectPropertyBase; - std::string typeName(); + //std::string typeName(); + static UClass* staticClass(); +}; + +class USoftObjectProperty : public UObjectPropertyBase +{ +public: + using UObjectPropertyBase::UObjectPropertyBase; + + //std::string typeName(); static UClass* staticClass(); }; @@ -1029,7 +1039,7 @@ class FSoftClassProperty : public FProperty UClass* getMetaClass() const; - static std::string typeName() { return "TWeakObjectPtr"; } + static std::string typeName() { return "TSoftObjectPtr"; } std::vector getSubTypes() const { return std::vector{ {true, PropertyType::ObjectProperty, getMetaClass()->getCName()}}; } diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index 6b113cce..3795982b 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -104,9 +104,9 @@ inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0xDEADBEEF }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0xDEADBEEF }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x69E81E8 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x69ECDB0 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x6B1D668 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); diff --git a/UEDumper/Engine/Userdefined/StructDefinitions.h b/UEDumper/Engine/Userdefined/StructDefinitions.h index 8c044224..a92d8446 100644 --- a/UEDumper/Engine/Userdefined/StructDefinitions.h +++ b/UEDumper/Engine/Userdefined/StructDefinitions.h @@ -195,6 +195,115 @@ inline void addStructs() //add it EngineCore::createStruct(TenumAsByte); + EngineStructs::Struct FweakObjectPtr; + FweakObjectPtr.fullName = "/Custom/FWeakObjectPtr"; + FweakObjectPtr.cppName = "FWeakObjectPtr"; + FweakObjectPtr.isClass = true; + FweakObjectPtr.size = sizeof(FWeakObjectPtr); + FweakObjectPtr.maxSize = FweakObjectPtr.size; + FweakObjectPtr.definedMembers = std::vector{ + {{false, PropertyType::IntProperty, TYPE_I32}, "ObjectIndex", 0, 4}, + {{false, PropertyType::IntProperty, TYPE_I32}, "ObjectSerialNumber", 4, 4}, + }; + //add it + EngineCore::createStruct(FweakObjectPtr); + + EngineStructs::Struct TweakObjectPtr; + TweakObjectPtr.fullName = "/Custom/TWeakObjectPtr"; + TweakObjectPtr.cppName = "TWeakObjectPtr"; + TweakObjectPtr.isClass = true; + TweakObjectPtr.size = sizeof(TWeakObjectPtr); + TweakObjectPtr.maxSize = TweakObjectPtr.size; + TweakObjectPtr.superNames = { "FWeakObjectPtr" }; + TweakObjectPtr.definedMembers = std::vector{ + }; + //add it + EngineCore::createStruct(TweakObjectPtr); + + EngineStructs::Struct TpersistentObjectPtr; + TpersistentObjectPtr.fullName = "/Custom/TPersistentObjectPtr"; + TpersistentObjectPtr.cppName = "TPersistentObjectPtr"; + TpersistentObjectPtr.isClass = true; + TpersistentObjectPtr.size = sizeof(TPersistentObjectPtr); + TpersistentObjectPtr.maxSize = TpersistentObjectPtr.size; + TpersistentObjectPtr.noFixedSize = true; + TpersistentObjectPtr.definedMembers = std::vector{ + {{true, PropertyType::ObjectProperty, "FWeakObjectPtr"}, "WeakPtr", 0, 8}, + {{false, PropertyType::IntProperty, TYPE_I32}, "TagAtLastTest", 8, 4}, + {{false, PropertyType::ObjectProperty, "TObjectID"}, "ObjectID", 12, 4}, + }; + //add it + EngineCore::createStruct(TpersistentObjectPtr); + + EngineStructs::Struct FuniqueObjectGuid; + FuniqueObjectGuid.fullName = "/Custom/FUniqueObjectGuid"; + FuniqueObjectGuid.cppName = "FUniqueObjectGuid"; + FuniqueObjectGuid.isClass = true; + FuniqueObjectGuid.size = sizeof(FUniqueObjectGuid); + FuniqueObjectGuid.maxSize = FuniqueObjectGuid.size; + FuniqueObjectGuid.definedMembers = std::vector{ + {{false, PropertyType::UInt32Property, TYPE_UI32}, "A", 0, 4}, + {{false, PropertyType::UInt32Property, TYPE_UI32}, "B", 4, 4}, + {{false, PropertyType::UInt32Property, TYPE_UI32}, "C", 8, 4}, + {{false, PropertyType::UInt32Property, TYPE_UI32}, "D", 12, 4}, + }; + //add it + EngineCore::createStruct(FuniqueObjectGuid); + + EngineStructs::Struct TlazyObjectPtr; + TlazyObjectPtr.fullName = "/Custom/TLazyObjectPtr"; + TlazyObjectPtr.cppName = "TLazyObjectPtr"; + TlazyObjectPtr.isClass = true; + TlazyObjectPtr.size = sizeof(TLazyObjectPtr); + TlazyObjectPtr.maxSize = TlazyObjectPtr.size; + TlazyObjectPtr.noFixedSize = true; + TlazyObjectPtr.superNames = { "TPersistentObjectPtr" }; + TlazyObjectPtr.definedMembers = std::vector{ + {{true, PropertyType::ObjectProperty, "FWeakObjectPtr"}, "WeakPtr", 0, 8}, + {{false, PropertyType::IntProperty, TYPE_I32}, "TagAtLastTest", 8, 4}, + {{false, PropertyType::ObjectProperty, "TObjectID"}, "ObjectID", 12, 4}, + }; + //add it + EngineCore::createStruct(TlazyObjectPtr); + + EngineStructs::Struct FsoftObjectPtr; + FsoftObjectPtr.fullName = "/Custom/FSoftObjectPtr"; + FsoftObjectPtr.cppName = "FSoftObjectPtr"; + FsoftObjectPtr.isClass = true; + FsoftObjectPtr.size = sizeof(FSoftObjectPtr); + FsoftObjectPtr.noFixedSize = true; + FsoftObjectPtr.maxSize = FsoftObjectPtr.size; + FsoftObjectPtr.definedMembers = std::vector{ + }; + //add it + EngineCore::createStruct(FsoftObjectPtr); + + EngineStructs::Struct TsoftObjectPtr; + TsoftObjectPtr.fullName = "/Custom/TSoftObjectPtr"; + TsoftObjectPtr.cppName = "TSoftObjectPtr"; + TsoftObjectPtr.isClass = true; + TsoftObjectPtr.size = sizeof(TSoftObjectPtr); + TsoftObjectPtr.noFixedSize = true; + TsoftObjectPtr.maxSize = TsoftObjectPtr.size; + TsoftObjectPtr.superNames = { "FSoftObjectPtr" }; + TsoftObjectPtr.definedMembers = std::vector{ + }; + //add it + EngineCore::createStruct(TsoftObjectPtr); + + EngineStructs::Struct TsoftClassPtr; + TsoftClassPtr.fullName = "/Custom/TSoftClassPtr"; + TsoftClassPtr.cppName = "TSoftClassPtr"; + TsoftClassPtr.isClass = true; + TsoftClassPtr.size = sizeof(TSoftClassPtr); + TsoftClassPtr.noFixedSize = true; + TsoftClassPtr.maxSize = TsoftClassPtr.size; + TsoftClassPtr.superNames = { "FSoftObjectPtr" }; + TsoftClassPtr.definedMembers = std::vector{ + }; + //add it + EngineCore::createStruct(TsoftClassPtr); + EngineStructs::Struct FtextData; FtextData.fullName = "/Custom/FTextData"; FtextData.cppName = "FTextData"; @@ -219,6 +328,20 @@ inline void addStructs() }; //add it EngineCore::createStruct(Ftext); + + EngineStructs::Struct Tmap; + Tmap.fullName = "/Custom/TMap"; + Tmap.cppName = "TMap"; + Tmap.isClass = false; + Tmap.size = sizeof(TMap); + Tmap.maxSize = Tmap.size; + Tmap.noFixedSize = true; + Tmap.definedMembers = std::vector{ + {{true, PropertyType::ObjectProperty, "TArray"}, "Data", 0, 16}, + {{false, PropertyType::ArrayProperty, TYPE_UCHAR}, "UnknownData01[0x40]", 16, 0x40}, + }; + //add it + EngineCore::createStruct(Tmap); } inline void addEnums() diff --git a/UEDumper/Engine/Userdefined/UEdefinitions.h b/UEDumper/Engine/Userdefined/UEdefinitions.h index 879f90d4..f9fdad9f 100644 --- a/UEDumper/Engine/Userdefined/UEdefinitions.h +++ b/UEDumper/Engine/Userdefined/UEdefinitions.h @@ -66,7 +66,7 @@ /* UE version settings */ //set your games ue version -#define UE_VERSION UE_5_03 +#define UE_VERSION UE_4_20 /* SDK and MDK generation */ diff --git a/UEDumper/Engine/structs.h b/UEDumper/Engine/structs.h index 0a0cd6e4..cbc997c2 100644 --- a/UEDumper/Engine/structs.h +++ b/UEDumper/Engine/structs.h @@ -289,6 +289,94 @@ class TEnumAsByte uint8_t value; }; + +/// Definition for FWeakObjectPtr + +class FWeakObjectPtr +{ +public: + int32_t ObjectIndex; + int32_t ObjectSerialNumber; +}; + + +/// Definition for TWeakObjectPtr + +template +class TWeakObjectPtr : public FWeakObjectPtr +{ +public: +}; + + +/// Definition for TPersistentObjectPtr + +template +class TPersistentObjectPtr +{ +public: + FWeakObjectPtr WeakPtr; + int32_t TagAtLastTest; + TObjectID ObjectID; +}; + + +/// Definition for FUniqueObjectGuid + +class FUniqueObjectGuid final +{ +public: + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; +}; + + +/// Definition for TLazyObjectPtr + +template +class TLazyObjectPtr : public TPersistentObjectPtr +{ +public: +}; + + +/// Definition for FSoftObjectPath_ + +struct FSoftObjectPath_ +{ +public: + class FName AssetPathName; + class FString SubPathString; +}; + + +/// Definition for FSoftObjectPtr + +class FSoftObjectPtr : public TPersistentObjectPtr +{ +}; + + +/// Definition for TSoftObjectPtr + +template +class TSoftObjectPtr : public FSoftObjectPtr +{ +public: +}; + + +/// Definition for TSoftClassPtr + +template +class TSoftClassPtr : public FSoftObjectPtr +{ +public: +}; + + template class TPair { From d76c9fe8e6e84d19b468cb501865dbf6534268f9 Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Sat, 20 Jul 2024 11:42:52 +0200 Subject: [PATCH 5/8] Added a fix in the generation that checks if subtypes are clickable otherwise gibberish gets added to dependencypackages --- UEDumper/Engine/Core/Core.cpp | 28 +++++++++++---------- UEDumper/Engine/Generation/MDK.cpp | 2 +- UEDumper/Engine/Generation/SDK.cpp | 2 +- UEDumper/Engine/UEClasses/UnrealClasses.h | 2 ++ UEDumper/Engine/Userdefined/Offsets.h | 6 ++--- UEDumper/Engine/Userdefined/UEdefinitions.h | 2 +- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index 303cc7c9..0fa8a71c 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -1264,6 +1264,9 @@ void EngineCore::finishPackages() { auto& package = packages[i]; + if (package.packageName == "AnimatedTexture") + DebugBreak(); + for (const auto& struc : package.combinedStructsAndClasses) { for (const auto& var : struc->definedMembers) @@ -1277,7 +1280,7 @@ void EngineCore::finishPackages() for (auto& name : struc->superNames) { const auto info = getInfoOfObject(name); - if (!info || !info->valid) + if (!info || !info->valid || (info->type != ObjectInfo::OI_Class && info->type != ObjectInfo::OI_Struct)) continue; //get the super struct auto superStruc = static_cast(info->target); @@ -1336,6 +1339,8 @@ void EngineCore::finishPackages() for (auto& subtype : var.type.subTypes) { + if (!subtype.clickable) + continue; const auto subInfo = getInfoOfObject(subtype.name); if (!subInfo || !subInfo->valid) continue; @@ -1344,18 +1349,16 @@ void EngineCore::finishPackages() if (subtype.propertyType != PropertyType::ObjectProperty && subtype.propertyType != PropertyType::ClassProperty) { - //casting is fine even if its a enum as owningpackage is the first package - const auto targetStruc = static_cast(subInfo->target); - if (targetStruc->owningPackage->index != package.index) - package.dependencyPackages.insert(targetStruc->owningPackage); + const auto targetPack = subInfo->type == ObjectInfo::OI_Enum ? static_cast(subInfo->target)->owningPackage : static_cast(subInfo->target)->owningPackage; + if (targetPack->index != package.index) + package.dependencyPackages.insert(targetPack); } } + const auto targetPack = info->type == ObjectInfo::OI_Enum ? static_cast(info->target)->owningPackage : static_cast(info->target)->owningPackage; + if (targetPack->index != package.index) + package.dependencyPackages.insert(targetPack); - //casting is fine even if its a enum as owningpackage is the first package - const auto targetStruc = static_cast(info->target); - if (targetStruc->owningPackage->index != package.index) - package.dependencyPackages.insert(targetStruc->owningPackage); } } @@ -1371,10 +1374,9 @@ void EngineCore::finishPackages() { type.info = info; - //casting is fine even if its a enum as owningpackage is the first package - const auto targetStruc = static_cast(info->target); - if (targetStruc->owningPackage->index != package.index) - package.dependencyPackages.insert(targetStruc->owningPackage); + const auto targetPack = info->type == ObjectInfo::OI_Enum ? static_cast(info->target)->owningPackage : static_cast(info->target)->owningPackage; + if (targetPack->index != package.index) + package.dependencyPackages.insert(targetPack); } } }; diff --git a/UEDumper/Engine/Generation/MDK.cpp b/UEDumper/Engine/Generation/MDK.cpp index ca5679c1..d0a7e394 100644 --- a/UEDumper/Engine/Generation/MDK.cpp +++ b/UEDumper/Engine/Generation/MDK.cpp @@ -98,7 +98,7 @@ void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs:: } - const static std::unordered_set reservedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE" }; + const static std::unordered_set reservedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE", "try" }; if (std::isdigit(result[0])) result = "_" + result; if (reservedNames.contains(result)) result += "0"; diff --git a/UEDumper/Engine/Generation/SDK.cpp b/UEDumper/Engine/Generation/SDK.cpp index bc903e4d..2be93d06 100644 --- a/UEDumper/Engine/Generation/SDK.cpp +++ b/UEDumper/Engine/Generation/SDK.cpp @@ -112,7 +112,7 @@ void SDKGeneration::generatePackage( } - const static std::unordered_set reservedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE" }; + const static std::unordered_set reservedNames{ "float", "int", "bool", "double", "long", "char", "TRUE", "FALSE", "try" }; if (std::isdigit(result[0])) result = "_" + result; if (reservedNames.contains(result)) result += "0"; diff --git a/UEDumper/Engine/UEClasses/UnrealClasses.h b/UEDumper/Engine/UEClasses/UnrealClasses.h index 394b3d07..374f2749 100644 --- a/UEDumper/Engine/UEClasses/UnrealClasses.h +++ b/UEDumper/Engine/UEClasses/UnrealClasses.h @@ -123,6 +123,8 @@ class UField : public UObject { public: using UObject::UObject; + int pad; + /** Next Field in the linked list */ UField* Next; diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index 3795982b..cf328b3b 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -104,9 +104,9 @@ inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x69E81E8 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x69ECDB0 }); - offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x6B1D668 }); + offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GNAMES", 0, "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00\x0F\x10\x03", "xxx????x????xx?????xxx" }); + offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GOBJECTS", 0,"\x48\x8B\x05\x00\x00\x00\x00\x48\x8B\x0C\xC8\x48\x8D\x1C\xD1\xEB\x03\x49\x8B\xDD", "xxx????xxxxxxxxxxxxx" }); + offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0, "\x48\x8B\x1D\x00\x00\x00\x00\x48\x85\xDB\x74\x3B\x41", "xxx????xxxxxx" }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); diff --git a/UEDumper/Engine/Userdefined/UEdefinitions.h b/UEDumper/Engine/Userdefined/UEdefinitions.h index f9fdad9f..f826a18d 100644 --- a/UEDumper/Engine/Userdefined/UEdefinitions.h +++ b/UEDumper/Engine/Userdefined/UEdefinitions.h @@ -66,7 +66,7 @@ /* UE version settings */ //set your games ue version -#define UE_VERSION UE_4_20 +#define UE_VERSION UE_4_27 /* SDK and MDK generation */ From 82293368de0865cab5dac9d0e6bbb026bda444c6 Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Sat, 20 Jul 2024 11:43:34 +0200 Subject: [PATCH 6/8] removed the debugbreak --- UEDumper/Engine/Core/Core.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index 0fa8a71c..9b4496b8 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -1264,9 +1264,6 @@ void EngineCore::finishPackages() { auto& package = packages[i]; - if (package.packageName == "AnimatedTexture") - DebugBreak(); - for (const auto& struc : package.combinedStructsAndClasses) { for (const auto& var : struc->definedMembers) From 6c01844ea7659882e9efd93f308fec0f93cc6d0d Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Sat, 20 Jul 2024 12:08:21 +0200 Subject: [PATCH 7/8] reads for 1.11 release --- UEDumper/Engine/Core/Core.cpp | 2 +- UEDumper/Engine/Generation/MDK.cpp | 2 +- UEDumper/Engine/Generation/SDK.cpp | 2 +- UEDumper/Engine/Generation/packageSorter.h | 4 +- UEDumper/Engine/Userdefined/Offsets.h | 44 +++++---------------- UEDumper/Engine/Userdefined/UEdefinitions.h | 2 +- UEDumper/Engine/structs.h | 4 +- 7 files changed, 17 insertions(+), 43 deletions(-) diff --git a/UEDumper/Engine/Core/Core.cpp b/UEDumper/Engine/Core/Core.cpp index 9b4496b8..3f73b0e3 100644 --- a/UEDumper/Engine/Core/Core.cpp +++ b/UEDumper/Engine/Core/Core.cpp @@ -1018,7 +1018,7 @@ void EngineCore::generatePackages(int64_t& finishedPackages, int64_t& totalPacka for (auto& enu : package.enums) { if (usedNames.contains(enu.cppName)) { windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_WARNING, "CORE", "Enum redefinitio in package %s! %s has already been defined in package %s", package.packageName.c_str(), enu.cppName.c_str(), usedNames[enu.cppName].c_str()); - printf("Enum redefinition in package %s! %s has already been defined in package %s\n", enu.cppName.c_str(), usedNames[enu.cppName].c_str()); + printf("Enum redefinition in package %s! %s has already been defined in package %s\n", package.packageName.c_str(), enu.cppName.c_str(), usedNames[enu.cppName].c_str()); } usedNames.insert({ enu.cppName, package.packageName }); } diff --git a/UEDumper/Engine/Generation/MDK.cpp b/UEDumper/Engine/Generation/MDK.cpp index d0a7e394..e4d64a88 100644 --- a/UEDumper/Engine/Generation/MDK.cpp +++ b/UEDumper/Engine/Generation/MDK.cpp @@ -240,7 +240,7 @@ void MDKGeneration::generatePackage(std::ofstream& stream, const EngineStructs:: { stream << "/// Enum " << enu.fullName << std::endl; char buf[100] = { 0 }; - sprintf_s(buf, "Size: 0x%02d", enu.members.size()); + sprintf_s(buf, "Size: 0x%02lld", enu.members.size()); stream << "/// " << buf << std::endl; stream << "enum class " << generateValidVarName(enu.cppName) << " : " << enu.type << std::endl; stream << "{" << std::endl; diff --git a/UEDumper/Engine/Generation/SDK.cpp b/UEDumper/Engine/Generation/SDK.cpp index 2be93d06..3023c330 100644 --- a/UEDumper/Engine/Generation/SDK.cpp +++ b/UEDumper/Engine/Generation/SDK.cpp @@ -260,7 +260,7 @@ void SDKGeneration::generatePackage( if(struc->size == 1 && struc->maxSize == 0) actualSize = 1; - sprintf_s(buf, "static_assert(sizeof(%s) == 0x%04X); // %d bytes (0x%06X - 0x%06X)", generateValidVarName(struc->cppName).c_str(), actualSize, struc->maxSize, struc->getInheritedSize(), actualSize); + sprintf_s(buf, "static_assert(sizeof(%s) == 0x%04llX); // %d bytes (0x%06X - 0x%06llX)", generateValidVarName(struc->cppName).c_str(), actualSize, struc->maxSize, struc->getInheritedSize(), actualSize); stream << buf << std::endl; } }; diff --git a/UEDumper/Engine/Generation/packageSorter.h b/UEDumper/Engine/Generation/packageSorter.h index 627b5137..3261bddf 100644 --- a/UEDumper/Engine/Generation/packageSorter.h +++ b/UEDumper/Engine/Generation/packageSorter.h @@ -345,10 +345,10 @@ inline std::vector sortPackages(int& progressDone, int& totalPro windows::LogWindow::Log(windows::LogWindow::logLevels::LOGLEVEL_INFO, "MDK GEN", "Reordering packages"); std::vector orderedPackages; - const float one_thousand = 1000; + constexpr auto one_thousand = 1000; // Max number of iterations before we give up // Using some very large number - it's to prevent infinite loops, not break too early before convergence - const auto maxIterations = 20 * one_thousand; + constexpr auto maxIterations = 20 * one_thousand; progressDone = 0; totalProgress = maxIterations; // Note: we may converge before this and end up with a Microsoft style progress bar that magically jumps to 100% while (didReordering && progressDone < totalProgress); diff --git a/UEDumper/Engine/Userdefined/Offsets.h b/UEDumper/Engine/Userdefined/Offsets.h index cf328b3b..8405af71 100644 --- a/UEDumper/Engine/Userdefined/Offsets.h +++ b/UEDumper/Engine/Userdefined/Offsets.h @@ -96,46 +96,20 @@ struct Offset //gobjects: 48 8B 05 ? ? ? ? 48 8B 0C C8 48 8D 04 D1 48 85 C0 /// Example: -/// offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DH, "OFFSET_GNAMES", 0, "\x4C\x8B\x0D\x73\x3C\x94\x03", "xxxxxxx" }); -/// offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x4D01930 }); -/// offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x4E0EFF0 }); +/// Signatures need OFFSET_SIGNATURE_FOLLOW or OFFSET_SINGNATURE_DIRECT +/// offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GNAMES", 0, "\x4C\x8B\x0D\x73\x3C\x94\x03", "xxxxxxx" }); +/// Addresses need OFFSET_ADDRESS +/// offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x4D01930 }); +/// Use OFFSET_LIVE_EDITOR to display the address in the live editor +/// offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x4E0EFF0 }); inline std::vector setOffsets() { std::vector offsets; - offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GNAMES", 0, "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00\x0F\x10\x03", "xxx????x????xx?????xxx" }); - offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GOBJECTS", 0,"\x48\x8B\x05\x00\x00\x00\x00\x48\x8B\x0C\xC8\x48\x8D\x1C\xD1\xEB\x03\x49\x8B\xDD", "xxx????xxxxxxxxxxxxx" }); - offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0, "\x48\x8B\x1D\x00\x00\x00\x00\x48\x85\xDB\x74\x3B\x41", "xxx????xxxxxx" }); - - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GNAMES", 0x562D340 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH, "OFFSET_GOBJECTS", 0x545C6E0 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DH | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x581A7E0 }); - - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x3CA2540 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x3CDE9E0 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x3E22258 }); - - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x5B8D390 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x5B918B8 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x5C80950 }); - - //offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GNAMES", 0, "\x4C\x8B\x0D\x73\x3C\x94\x03", "xxxxxxx" }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x4D01930 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x4E0EFF0 }); - - //offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DS, "OFFSET_GNAMES", 0, - // "\x48\x8d\x0d\x00\x00\x00\x00\xe8\x00\x00\x00\x00\xc6\x05\x00\x00\x00\x00\x00\x0f\x10\x03", "xxx????x????xx?????xxx" }); - - //offsets.push_back({ OFFSET_SIGNATURE_FOLLOW | OFFSET_DH, "OFFSET_GOBJECTS", 0, "\x48\x8b\x05\x00\x00\x00\x00\x48\x8b\x14\xc8\x49\x63\xc0\x48\x8d\x0c\x40\x48\x39\x34\xca", "xxx????xxxxxxxxxxxxxxx"}); - - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0x5F48000 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0x5F60C78 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0x607E6C8 }); - - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 124224808 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 122913320 }); - //offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 122940512 }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GNAMES", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS, "OFFSET_GOBJECTS", 0xDEADBEEF }); + offsets.push_back({ OFFSET_ADDRESS | OFFSET_DS | OFFSET_LIVE_EDITOR, "OFFSET_GWORLD", 0xDEADBEEF }); return offsets; } diff --git a/UEDumper/Engine/Userdefined/UEdefinitions.h b/UEDumper/Engine/Userdefined/UEdefinitions.h index f826a18d..f3257096 100644 --- a/UEDumper/Engine/Userdefined/UEdefinitions.h +++ b/UEDumper/Engine/Userdefined/UEdefinitions.h @@ -38,7 +38,7 @@ #define RELEASE_1_11_BETA 20 #define RELEASE_1_11_FINAL 21 -#define DUMPER_VERSION RELEASE_1_11_BETA +#define DUMPER_VERSION RELEASE_1_11_FINAL /// This file contains engine definitions that you have to edit depending on the game! diff --git a/UEDumper/Engine/structs.h b/UEDumper/Engine/structs.h index cbc997c2..5767e3b9 100644 --- a/UEDumper/Engine/structs.h +++ b/UEDumper/Engine/structs.h @@ -347,8 +347,8 @@ class TLazyObjectPtr : public TPersistentObjectPtr struct FSoftObjectPath_ { public: - class FName AssetPathName; - class FString SubPathString; + FName AssetPathName; + FString SubPathString; }; From 1c135b9bd3c1cf84a610d9f3db4fb3db10d95655 Mon Sep 17 00:00:00 2001 From: Spuckwaffel Date: Sat, 20 Jul 2024 12:13:17 +0200 Subject: [PATCH 8/8] removed pad. oop --- UEDumper/Engine/UEClasses/UnrealClasses.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/UEDumper/Engine/UEClasses/UnrealClasses.h b/UEDumper/Engine/UEClasses/UnrealClasses.h index 374f2749..394b3d07 100644 --- a/UEDumper/Engine/UEClasses/UnrealClasses.h +++ b/UEDumper/Engine/UEClasses/UnrealClasses.h @@ -123,8 +123,6 @@ class UField : public UObject { public: using UObject::UObject; - int pad; - /** Next Field in the linked list */ UField* Next;