[StructuredData] Add 15 classes code, still not fully working!

This commit is contained in:
momo5502 2017-02-20 19:18:07 +01:00
parent 442be57564
commit a4abdd9dcb
6 changed files with 192 additions and 109 deletions

View File

@ -14,27 +14,27 @@ namespace Assets
Game::StructuredDataEnum* destEnum = &destEnums[i]; Game::StructuredDataEnum* destEnum = &destEnums[i];
Game::StructuredDataEnum* enum_ = &enums[i]; Game::StructuredDataEnum* enum_ = &enums[i];
if (enum_->indices) if (enum_->entries)
{ {
AssertSize(Game::StructuredDataEnumEntry, 8); AssertSize(Game::StructuredDataEnumEntry, 8);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataEnumEntry* destIndices = buffer->dest<Game::StructuredDataEnumEntry>(); Game::StructuredDataEnumEntry* destIndices = buffer->dest<Game::StructuredDataEnumEntry>();
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* 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); buffer->saveString(index->name);
Utils::Stream::ClearPointer(&destIndex->key); 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* destStruct = &destStructs[i];
Game::StructuredDataStruct* struct_ = &structs[i]; Game::StructuredDataStruct* struct_ = &structs[i];
if (struct_->property) if (struct_->properties)
{ {
AssertSize(Game::StructuredDataStructProperty, 16); AssertSize(Game::StructuredDataStructProperty, 16);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataStructProperty* destProperties = buffer->dest<Game::StructuredDataStructProperty>(); Game::StructuredDataStructProperty* destProperties = buffer->dest<Game::StructuredDataStructProperty>();
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* destProperty = &destProperties[j];
Game::StructuredDataStructProperty* property = &struct_->property[j]; Game::StructuredDataStructProperty* property = &struct_->properties[j];
if (property->name) 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); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->data) if (asset->defs)
{ {
AssertSize(Game::StructuredDataDef, 52); AssertSize(Game::StructuredDataDef, 52);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataDef* destDataArray = buffer->dest<Game::StructuredDataDef>(); Game::StructuredDataDef* destDataArray = buffer->dest<Game::StructuredDataDef>();
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* destData = &destDataArray[i];
Game::StructuredDataDef* data = &asset->data[i]; Game::StructuredDataDef* data = &asset->defs[i];
if (data->enums) if (data->enums)
{ {
AssertSize(Game::StructuredDataEnum, 12); AssertSize(Game::StructuredDataEnum, 12);
buffer->align(Utils::Stream::ALIGN_4); 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); Utils::Stream::ClearPointer(&destData->enums);
} }
@ -120,7 +120,7 @@ namespace Assets
AssertSize(Game::StructuredDataStruct, 16); AssertSize(Game::StructuredDataStruct, 16);
buffer->align(Utils::Stream::ALIGN_4); 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); Utils::Stream::ClearPointer(&destData->structs);
} }
@ -129,21 +129,21 @@ namespace Assets
AssertSize(Game::StructuredDataIndexedArray, 16); AssertSize(Game::StructuredDataIndexedArray, 16);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(data->indexedArrays, data->numIndexedArrays); buffer->saveArray(data->indexedArrays, data->indexedArrayCount);
Utils::Stream::ClearPointer(&destData->indexedArrays); Utils::Stream::ClearPointer(&destData->indexedArrays);
} }
if (data->enumArrays) if (data->enumedArrays)
{ {
AssertSize(Game::StructuredDataEnumedArray, 16); AssertSize(Game::StructuredDataEnumedArray, 16);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(data->enumArrays, data->numEnumArrays); buffer->saveArray(data->enumedArrays, data->enumedArrayCount);
Utils::Stream::ClearPointer(&destData->enumArrays); Utils::Stream::ClearPointer(&destData->enumedArrays);
} }
} }
Utils::Stream::ClearPointer(&dest->data); Utils::Stream::ClearPointer(&dest->defs);
} }
buffer->popBlock(); buffer->popBlock();

View File

@ -22,6 +22,10 @@ namespace Components
Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick(); Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick();
} }
#endif #endif
//const char* clanname = "ZOB";
//Utils::Hook::Set<const char*>(0x497656, clanname);
//Utils::Hook::Set<const char*>(0x497679, clanname);
} }
PlayerName::~PlayerName() PlayerName::~PlayerName()

View File

@ -29,18 +29,18 @@ namespace Components
// Build index-sorted data vector // Build index-sorted data vector
std::vector<const char*> dataVector; std::vector<const char*> dataVector;
for (int i = 0; i < dataEnum->numIndices; ++i) for (int i = 0; i < dataEnum->entryCount; ++i)
{ {
int index = 0; 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; break;
} }
} }
dataVector.push_back(dataEnum->indices[index].key); dataVector.push_back(dataEnum->entries[index].name);
} }
// Rebase or add new entries // Rebase or add new entries
@ -64,10 +64,10 @@ namespace Components
// Map data back to the game structure // Map data back to the game structure
Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnumEntry>(dataVector.size()); Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnumEntry>(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].index = i;
indices[i].key = dataVector[i]; indices[i].name = dataVector[i];
} }
// Sort alphabetically // Sort alphabetically
@ -76,16 +76,50 @@ namespace Components
const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first); const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first);
const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second); const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second);
return std::string(entry1->key).compare(entry2->key); return std::string(entry1->name).compare(entry2->name);
}); });
// Apply our patches // Apply our patches
dataEnum->numIndices = dataVector.size(); dataEnum->entryCount = dataVector.size();
dataEnum->indices = indices; 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<std::string, std::string>& patches)
{
for(auto& item : patches)
{
if(item.first == "classes")
{
StructuredData::PatchCustomClassLimit(data, atoi(item.second.data()));
}
}
} }
StructuredData::StructuredData() StructuredData::StructuredData()
{ {
Utils::Hook::Set<BYTE>(0x60A2FE, 15); // 15 custom classes
// Only execute this when building zones // Only execute this when building zones
if (!ZoneBuilder::IsEnabled()) return; if (!ZoneBuilder::IsEnabled()) return;
@ -98,19 +132,20 @@ namespace Components
Game::StructuredDataDefSet* data = asset.structuredData; Game::StructuredDataDefSet* data = asset.structuredData;
if (!data) return; if (!data) return;
if (data->count != 1) if (data->defCount != 1)
{ {
Logger::Error("PlayerDataDefSet contains more than 1 definition!"); Logger::Error("PlayerDataDefSet contains more than 1 definition!");
return; return;
} }
if (data->data[0].version != 155) if (data->defs[0].version != 155)
{ {
Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!"); Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!");
return; return;
} }
std::map<int, std::vector<std::vector<std::string>>> patchDefinitions; std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
std::map<int, std::unordered_map<std::string, std::string>> otherPatchDefinitions;
// First check if all versions are present // First check if all versions are present
for (int i = 156;; ++i) for (int i = 156;; ++i)
@ -119,6 +154,7 @@ namespace Components
if (!definition.exists()) break; if (!definition.exists()) break;
std::vector<std::vector<std::string>> enumContainer; std::vector<std::vector<std::string>> enumContainer;
std::unordered_map<std::string, std::string> otherPatches;
std::string errors; std::string errors;
json11::Json defData = json11::Json::parse(definition.getBuffer(), errors); json11::Json defData = json11::Json::parse(definition.getBuffer(), errors);
@ -155,34 +191,48 @@ namespace Components
enumContainer.push_back(entryData); 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; patchDefinitions[i] = enumContainer;
otherPatchDefinitions[i] = otherPatches;
} }
// Nothing to patch // Nothing to patch
if (patchDefinitions.empty()) return; if (patchDefinitions.empty()) return;
// Reallocate the definition // Reallocate the definition
Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size()); Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count); std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount);
// Prepare the buffers // Prepare the buffers
for (unsigned int i = 0; i < patchDefinitions.size(); ++i) 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; newData[i].version = (patchDefinitions.size() - i) + 155;
// Reallocate the enum array // Reallocate the enum array
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->data->numEnums); Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->defs->enumCount);
std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums); std::memcpy(newEnums, data->defs->enums, sizeof Game::StructuredDataEnum * data->defs->enumCount);
newData[i].enums = newEnums; newData[i].enums = newEnums;
} }
// Apply new data // Apply new data
data->data = newData; data->defs = newData;
data->count += patchDefinitions.size(); data->defCount += patchDefinitions.size();
// Patch the definition // 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 // No need to patch version 155
if (newData[i].version == 155) continue; if (newData[i].version == 155) continue;
@ -190,6 +240,7 @@ namespace Components
if(patchDefinitions.find(newData[i].version) != patchDefinitions.end()) if(patchDefinitions.find(newData[i].version) != patchDefinitions.end())
{ {
auto patchData = patchDefinitions[newData[i].version]; auto patchData = patchDefinitions[newData[i].version];
auto otherData = otherPatchDefinitions[newData[i].version];
// Invalid patch data // Invalid patch data
if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX) if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX)
@ -206,6 +257,8 @@ namespace Components
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]); StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
} }
} }
StructuredData::PatchAdditionalData(&newData[i], otherData);
} }
} }
}); });

View File

@ -32,6 +32,9 @@ namespace Components
private: private:
static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector<std::string>& entries); static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector<std::string>& entries);
static void PatchAdditionalData(Game::StructuredDataDef* data, std::unordered_map<std::string, std::string>& patches);
static void PatchCustomClassLimit(Game::StructuredDataDef* data, int count);
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static const char* EnumTranslation[ENUM_MAX]; static const char* EnumTranslation[ENUM_MAX];

View File

@ -1448,90 +1448,110 @@ namespace Game
FontEntry* characters; FontEntry* characters;
} Font; } Font;
typedef enum enum StructuredDataTypeCategory
{ {
STRUCTURED_DATA_INT = 0, DATA_INT = 0x0,
STRUCTURED_DATA_BYTE = 1, DATA_BYTE = 0x1,
STRUCTURED_DATA_BOOL = 2, DATA_BOOL = 0x2,
STRUCTURED_DATA_STRING = 3, DATA_STRING = 0x3,
STRUCTURED_DATA_ENUM = 4, DATA_ENUM = 0x4,
STRUCTURED_DATA_STRUCT = 5, DATA_STRUCT = 0x5,
STRUCTURED_DATA_INDEXEDARR = 6, DATA_INDEXED_ARRAY = 0x6,
STRUCTURED_DATA_ENUMARR = 7, DATA_ENUM_ARRAY = 0x7,
STRUCTURED_DATA_FLOAT = 8, DATA_FLOAT = 0x8,
STRUCTURED_DATA_SHORT = 9 DATA_SHORT = 0x9,
} StructuredDataType; 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 typedef struct
{ {
StructuredDataType type; StructuredDataType item;
union
{
int index;
};
int offset; int offset;
} StructuredDataItem; } StructuredDataItem;
typedef struct #pragma pack(push,4)
struct StructuredDataStructProperty
{ {
const char* name; const char *name;
StructuredDataItem item; StructuredDataType item;
} StructuredDataStructProperty; int offset;
};
#pragma pack(pop)
typedef struct struct StructuredDataStruct
{ {
int numProperties; int propertyCount;
StructuredDataStructProperty* property; StructuredDataStructProperty *properties;
int unknown1; int size;
int unknown2; unsigned int bitOffset;
} StructuredDataStruct; };
typedef struct struct StructuredDataIndexedArray
{
int arraySize;
StructuredDataType elementType;
unsigned int elementSize;
};
struct StructuredDataEnumedArray
{ {
int enumIndex; int enumIndex;
StructuredDataItem item; StructuredDataType elementType;
} StructuredDataEnumedArray; unsigned int elementSize;
};
typedef struct struct StructuredDataDef
{
const char* key;
int index;
} StructuredDataEnumEntry;
typedef struct
{
int numIndices;
int unknown;
StructuredDataEnumEntry* indices;
} StructuredDataEnum;
typedef struct
{
int numItems;
StructuredDataItem item;
} StructuredDataIndexedArray;
typedef struct
{ {
int version; int version;
unsigned int hash; unsigned int formatChecksum;
int numEnums; int enumCount;
StructuredDataEnum* enums; StructuredDataEnum *enums;
int numStructs; int structCount;
StructuredDataStruct* structs; StructuredDataStruct *structs;
int numIndexedArrays; int indexedArrayCount;
StructuredDataIndexedArray* indexedArrays; StructuredDataIndexedArray *indexedArrays;
int numEnumArrays; int enumedArrayCount;
StructuredDataEnumedArray* enumArrays; StructuredDataEnumedArray *enumedArrays;
StructuredDataItem rootItem; StructuredDataType rootType;
} StructuredDataDef; unsigned int size;
};
typedef struct struct StructuredDataDefSet
{ {
const char* name; const char *name;
int count; unsigned int defCount;
StructuredDataDef* data; StructuredDataDef *defs;
} StructuredDataDefSet; };
typedef struct typedef struct
{ {

View File

@ -50,6 +50,9 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l
{ {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{ {
// Not sure if it conflicts with our TLS variables
//DisableThreadLibraryCalls(hModule);
Steam::Proxy::RunMod(); Steam::Proxy::RunMod();
// Ensure we're working with our desired binary // Ensure we're working with our desired binary