From a4abdd9dcb7658399c5548bab9efcc97337cb72c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 20 Feb 2017 19:18:07 +0100 Subject: [PATCH] [StructuredData] Add 15 classes code, still not fully working! --- .../AssetInterfaces/IStructuredDataDefSet.cpp | 48 +++--- src/Components/Modules/PlayerName.cpp | 4 + src/Components/Modules/StructuredData.cpp | 91 ++++++++--- src/Components/Modules/StructuredData.hpp | 3 + src/Game/Structs.hpp | 152 ++++++++++-------- src/Main.cpp | 3 + 6 files changed, 192 insertions(+), 109 deletions(-) diff --git a/src/Components/Modules/AssetInterfaces/IStructuredDataDefSet.cpp b/src/Components/Modules/AssetInterfaces/IStructuredDataDefSet.cpp index c4de8810..dc5a3047 100644 --- a/src/Components/Modules/AssetInterfaces/IStructuredDataDefSet.cpp +++ b/src/Components/Modules/AssetInterfaces/IStructuredDataDefSet.cpp @@ -14,27 +14,27 @@ namespace Assets Game::StructuredDataEnum* destEnum = &destEnums[i]; Game::StructuredDataEnum* enum_ = &enums[i]; - if (enum_->indices) + if (enum_->entries) { AssertSize(Game::StructuredDataEnumEntry, 8); buffer->align(Utils::Stream::ALIGN_4); Game::StructuredDataEnumEntry* destIndices = buffer->dest(); - buffer->saveArray(enum_->indices, enum_->numIndices); + buffer->saveArray(enum_->entries, enum_->entryCount); - for (int j = 0; j < enum_->numIndices; ++j) + for (int j = 0; j < enum_->entryCount; ++j) { Game::StructuredDataEnumEntry* destIndex = &destIndices[j]; - Game::StructuredDataEnumEntry* index = &enum_->indices[j]; + Game::StructuredDataEnumEntry* index = &enum_->entries[j]; - if (index->key) + if (index->name) { - buffer->saveString(index->key); - Utils::Stream::ClearPointer(&destIndex->key); + buffer->saveString(index->name); + Utils::Stream::ClearPointer(&destIndex->name); } } - Utils::Stream::ClearPointer(&destEnum->indices); + Utils::Stream::ClearPointer(&destEnum->entries); } } } @@ -51,18 +51,18 @@ namespace Assets Game::StructuredDataStruct* destStruct = &destStructs[i]; Game::StructuredDataStruct* struct_ = &structs[i]; - if (struct_->property) + if (struct_->properties) { AssertSize(Game::StructuredDataStructProperty, 16); buffer->align(Utils::Stream::ALIGN_4); Game::StructuredDataStructProperty* destProperties = buffer->dest(); - buffer->saveArray(struct_->property, struct_->numProperties); + buffer->saveArray(struct_->properties, struct_->propertyCount); - for (int j = 0; j < struct_->numProperties; ++j) + for (int j = 0; j < struct_->propertyCount; ++j) { Game::StructuredDataStructProperty* destProperty = &destProperties[j]; - Game::StructuredDataStructProperty* property = &struct_->property[j]; + Game::StructuredDataStructProperty* property = &struct_->properties[j]; if (property->name) { @@ -71,7 +71,7 @@ namespace Assets } } - Utils::Stream::ClearPointer(&destStruct->property); + Utils::Stream::ClearPointer(&destStruct->properties); } } } @@ -93,25 +93,25 @@ namespace Assets Utils::Stream::ClearPointer(&dest->name); } - if (asset->data) + if (asset->defs) { AssertSize(Game::StructuredDataDef, 52); buffer->align(Utils::Stream::ALIGN_4); Game::StructuredDataDef* destDataArray = buffer->dest(); - buffer->saveArray(asset->data, asset->count); + buffer->saveArray(asset->defs, asset->defCount); - for (int i = 0; i < asset->count; ++i) + for (unsigned int i = 0; i < asset->defCount; ++i) { Game::StructuredDataDef* destData = &destDataArray[i]; - Game::StructuredDataDef* data = &asset->data[i]; + Game::StructuredDataDef* data = &asset->defs[i]; if (data->enums) { AssertSize(Game::StructuredDataEnum, 12); buffer->align(Utils::Stream::ALIGN_4); - this->saveStructuredDataEnumArray(data->enums, data->numEnums, builder); + this->saveStructuredDataEnumArray(data->enums, data->enumCount, builder); Utils::Stream::ClearPointer(&destData->enums); } @@ -120,7 +120,7 @@ namespace Assets AssertSize(Game::StructuredDataStruct, 16); buffer->align(Utils::Stream::ALIGN_4); - this->saveStructuredDataStructArray(data->structs, data->numStructs, builder); + this->saveStructuredDataStructArray(data->structs, data->structCount, builder); Utils::Stream::ClearPointer(&destData->structs); } @@ -129,21 +129,21 @@ namespace Assets AssertSize(Game::StructuredDataIndexedArray, 16); buffer->align(Utils::Stream::ALIGN_4); - buffer->saveArray(data->indexedArrays, data->numIndexedArrays); + buffer->saveArray(data->indexedArrays, data->indexedArrayCount); Utils::Stream::ClearPointer(&destData->indexedArrays); } - if (data->enumArrays) + if (data->enumedArrays) { AssertSize(Game::StructuredDataEnumedArray, 16); buffer->align(Utils::Stream::ALIGN_4); - buffer->saveArray(data->enumArrays, data->numEnumArrays); - Utils::Stream::ClearPointer(&destData->enumArrays); + buffer->saveArray(data->enumedArrays, data->enumedArrayCount); + Utils::Stream::ClearPointer(&destData->enumedArrays); } } - Utils::Stream::ClearPointer(&dest->data); + Utils::Stream::ClearPointer(&dest->defs); } buffer->popBlock(); diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp index 5d62e904..896853ee 100644 --- a/src/Components/Modules/PlayerName.cpp +++ b/src/Components/Modules/PlayerName.cpp @@ -22,6 +22,10 @@ namespace Components Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick(); } #endif + + //const char* clanname = "ZOB"; + //Utils::Hook::Set(0x497656, clanname); + //Utils::Hook::Set(0x497679, clanname); } PlayerName::~PlayerName() diff --git a/src/Components/Modules/StructuredData.cpp b/src/Components/Modules/StructuredData.cpp index bb772992..ecf8b680 100644 --- a/src/Components/Modules/StructuredData.cpp +++ b/src/Components/Modules/StructuredData.cpp @@ -29,18 +29,18 @@ namespace Components // Build index-sorted data vector std::vector dataVector; - for (int i = 0; i < dataEnum->numIndices; ++i) + for (int i = 0; i < dataEnum->entryCount; ++i) { int index = 0; - for (; index < dataEnum->numIndices; ++index) + for (; index < dataEnum->entryCount; ++index) { - if (dataEnum->indices[index].index == i) + if (dataEnum->entries[index].index == i) { break; } } - dataVector.push_back(dataEnum->indices[index].key); + dataVector.push_back(dataEnum->entries[index].name); } // Rebase or add new entries @@ -64,10 +64,10 @@ namespace Components // Map data back to the game structure Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.allocateArray(dataVector.size()); - for (unsigned int i = 0; i < dataVector.size(); ++i) + for (unsigned short i = 0; i < dataVector.size(); ++i) { indices[i].index = i; - indices[i].key = dataVector[i]; + indices[i].name = dataVector[i]; } // Sort alphabetically @@ -76,16 +76,50 @@ namespace Components const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast(first); const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast(second); - return std::string(entry1->key).compare(entry2->key); + return std::string(entry1->name).compare(entry2->name); }); // Apply our patches - dataEnum->numIndices = dataVector.size(); - dataEnum->indices = indices; + dataEnum->entryCount = dataVector.size(); + dataEnum->entries = indices; + } + + void StructuredData::PatchCustomClassLimit(Game::StructuredDataDef* data, int count) + { + const int customClassSize = 64; + + for (int i = 0; i < data->structs[0].propertyCount; ++i) + { + // 3003 is the offset of the customClasses structure + if (data->structs[0].properties[i].offset >= 3643) + { + // -10 because 10 is the default amount of custom classes. + data->structs[0].properties[i].offset += ((count - 10) * customClassSize); + } + } + + // update structure size + data->size += ((count - 10) * customClassSize); + + // Update amount of custom classes + data->indexedArrays[5].arraySize = count; + } + + void StructuredData::PatchAdditionalData(Game::StructuredDataDef* data, std::unordered_map& patches) + { + for(auto& item : patches) + { + if(item.first == "classes") + { + StructuredData::PatchCustomClassLimit(data, atoi(item.second.data())); + } + } } StructuredData::StructuredData() { + Utils::Hook::Set(0x60A2FE, 15); // 15 custom classes + // Only execute this when building zones if (!ZoneBuilder::IsEnabled()) return; @@ -98,19 +132,20 @@ namespace Components Game::StructuredDataDefSet* data = asset.structuredData; if (!data) return; - if (data->count != 1) + if (data->defCount != 1) { Logger::Error("PlayerDataDefSet contains more than 1 definition!"); return; } - if (data->data[0].version != 155) + if (data->defs[0].version != 155) { Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!"); return; } std::map>> patchDefinitions; + std::map> otherPatchDefinitions; // First check if all versions are present for (int i = 156;; ++i) @@ -119,6 +154,7 @@ namespace Components if (!definition.exists()) break; std::vector> enumContainer; + std::unordered_map otherPatches; std::string errors; json11::Json defData = json11::Json::parse(definition.getBuffer(), errors); @@ -155,34 +191,48 @@ namespace Components enumContainer.push_back(entryData); } + auto other = defData["other"]; + + if(other.is_object()) + { + for(auto& item : other.object_items()) + { + if(item.second.is_string()) + { + otherPatches[item.first] = item.second.string_value(); + } + } + } + patchDefinitions[i] = enumContainer; + otherPatchDefinitions[i] = otherPatches; } // Nothing to patch if (patchDefinitions.empty()) return; // Reallocate the definition - Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray(data->count + patchDefinitions.size()); - std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count); + Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray(data->defCount + patchDefinitions.size()); + std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount); // Prepare the buffers for (unsigned int i = 0; i < patchDefinitions.size(); ++i) { - std::memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef); + std::memcpy(&newData[i], data->defs, sizeof Game::StructuredDataDef); newData[i].version = (patchDefinitions.size() - i) + 155; // Reallocate the enum array - Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray(data->data->numEnums); - std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums); + Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray(data->defs->enumCount); + std::memcpy(newEnums, data->defs->enums, sizeof Game::StructuredDataEnum * data->defs->enumCount); newData[i].enums = newEnums; } // Apply new data - data->data = newData; - data->count += patchDefinitions.size(); + data->defs = newData; + data->defCount += patchDefinitions.size(); // Patch the definition - for (int i = 0; i < data->count; ++i) + for (unsigned int i = 0; i < data->defCount; ++i) { // No need to patch version 155 if (newData[i].version == 155) continue; @@ -190,6 +240,7 @@ namespace Components if(patchDefinitions.find(newData[i].version) != patchDefinitions.end()) { auto patchData = patchDefinitions[newData[i].version]; + auto otherData = otherPatchDefinitions[newData[i].version]; // Invalid patch data if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX) @@ -206,6 +257,8 @@ namespace Components StructuredData::PatchPlayerDataEnum(&newData[i], static_cast(pType), patchData[pType]); } } + + StructuredData::PatchAdditionalData(&newData[i], otherData); } } }); diff --git a/src/Components/Modules/StructuredData.hpp b/src/Components/Modules/StructuredData.hpp index 5574d367..1cc39833 100644 --- a/src/Components/Modules/StructuredData.hpp +++ b/src/Components/Modules/StructuredData.hpp @@ -32,6 +32,9 @@ namespace Components private: static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector& entries); + static void PatchAdditionalData(Game::StructuredDataDef* data, std::unordered_map& patches); + + static void PatchCustomClassLimit(Game::StructuredDataDef* data, int count); static Utils::Memory::Allocator MemAllocator; static const char* EnumTranslation[ENUM_MAX]; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 9ff1a83e..9ad84fed 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1448,90 +1448,110 @@ namespace Game FontEntry* characters; } Font; - typedef enum + enum StructuredDataTypeCategory { - STRUCTURED_DATA_INT = 0, - STRUCTURED_DATA_BYTE = 1, - STRUCTURED_DATA_BOOL = 2, - STRUCTURED_DATA_STRING = 3, - STRUCTURED_DATA_ENUM = 4, - STRUCTURED_DATA_STRUCT = 5, - STRUCTURED_DATA_INDEXEDARR = 6, - STRUCTURED_DATA_ENUMARR = 7, - STRUCTURED_DATA_FLOAT = 8, - STRUCTURED_DATA_SHORT = 9 - } StructuredDataType; + DATA_INT = 0x0, + DATA_BYTE = 0x1, + DATA_BOOL = 0x2, + DATA_STRING = 0x3, + DATA_ENUM = 0x4, + DATA_STRUCT = 0x5, + DATA_INDEXED_ARRAY = 0x6, + DATA_ENUM_ARRAY = 0x7, + DATA_FLOAT = 0x8, + DATA_SHORT = 0x9, + DATA_COUNT = 0xA, + }; + +#pragma pack(push,4) + struct StructuredDataEnumEntry + { + const char *name; + unsigned __int16 index; + }; +#pragma pack(pop) + + struct StructuredDataEnum + { + int entryCount; + int reservedEntryCount; + StructuredDataEnumEntry *entries; + }; + + union StructuredDataTypeUnion + { + unsigned int stringDataLength; + int enumIndex; + int structIndex; + int indexedArrayIndex; + int enumedArrayIndex; + }; + + struct StructuredDataType + { + StructuredDataTypeCategory type; + StructuredDataTypeUnion u; + }; typedef struct { - StructuredDataType type; - union - { - int index; - }; + StructuredDataType item; int offset; } StructuredDataItem; - typedef struct +#pragma pack(push,4) + struct StructuredDataStructProperty { - const char* name; - StructuredDataItem item; - } StructuredDataStructProperty; + const char *name; + StructuredDataType item; + int offset; + }; +#pragma pack(pop) - typedef struct + struct StructuredDataStruct { - int numProperties; - StructuredDataStructProperty* property; - int unknown1; - int unknown2; - } StructuredDataStruct; + int propertyCount; + StructuredDataStructProperty *properties; + int size; + unsigned int bitOffset; + }; - typedef struct + struct StructuredDataIndexedArray + { + int arraySize; + StructuredDataType elementType; + unsigned int elementSize; + }; + + struct StructuredDataEnumedArray { int enumIndex; - StructuredDataItem item; - } StructuredDataEnumedArray; + StructuredDataType elementType; + unsigned int elementSize; + }; - typedef struct - { - const char* key; - int index; - } StructuredDataEnumEntry; - - typedef struct - { - int numIndices; - int unknown; - StructuredDataEnumEntry* indices; - } StructuredDataEnum; - - typedef struct - { - int numItems; - StructuredDataItem item; - } StructuredDataIndexedArray; - - typedef struct + struct StructuredDataDef { int version; - unsigned int hash; - int numEnums; - StructuredDataEnum* enums; - int numStructs; - StructuredDataStruct* structs; - int numIndexedArrays; - StructuredDataIndexedArray* indexedArrays; - int numEnumArrays; - StructuredDataEnumedArray* enumArrays; - StructuredDataItem rootItem; - } StructuredDataDef; + unsigned int formatChecksum; + int enumCount; + StructuredDataEnum *enums; + int structCount; + StructuredDataStruct *structs; + int indexedArrayCount; + StructuredDataIndexedArray *indexedArrays; + int enumedArrayCount; + StructuredDataEnumedArray *enumedArrays; + StructuredDataType rootType; + unsigned int size; + }; - typedef struct + struct StructuredDataDefSet { - const char* name; - int count; - StructuredDataDef* data; - } StructuredDataDefSet; + const char *name; + unsigned int defCount; + StructuredDataDef *defs; + }; typedef struct { diff --git a/src/Main.cpp b/src/Main.cpp index 6c01a9ce..17fd1eb3 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -50,6 +50,9 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { + // Not sure if it conflicts with our TLS variables + //DisableThreadLibraryCalls(hModule); + Steam::Proxy::RunMod(); // Ensure we're working with our desired binary