[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* enum_ = &enums[i];
if (enum_->indices)
if (enum_->entries)
{
AssertSize(Game::StructuredDataEnumEntry, 8);
buffer->align(Utils::Stream::ALIGN_4);
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* 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<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* 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<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* 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();

View File

@ -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<const char*>(0x497656, clanname);
//Utils::Hook::Set<const char*>(0x497679, clanname);
}
PlayerName::~PlayerName()

View File

@ -29,18 +29,18 @@ namespace Components
// Build index-sorted data vector
std::vector<const char*> 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<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].key = dataVector[i];
indices[i].name = dataVector[i];
}
// Sort alphabetically
@ -76,16 +76,50 @@ namespace Components
const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first);
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
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<std::string, std::string>& patches)
{
for(auto& item : patches)
{
if(item.first == "classes")
{
StructuredData::PatchCustomClassLimit(data, atoi(item.second.data()));
}
}
}
StructuredData::StructuredData()
{
Utils::Hook::Set<BYTE>(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<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
for (int i = 156;; ++i)
@ -119,6 +154,7 @@ namespace Components
if (!definition.exists()) break;
std::vector<std::vector<std::string>> enumContainer;
std::unordered_map<std::string, std::string> 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<Game::StructuredDataDef>(data->count + patchDefinitions.size());
std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count);
Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(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<Game::StructuredDataEnum>(data->data->numEnums);
std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums);
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(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<StructuredData::PlayerDataType>(pType), patchData[pType]);
}
}
StructuredData::PatchAdditionalData(&newData[i], otherData);
}
}
});

View File

@ -32,6 +32,9 @@ namespace Components
private:
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 const char* EnumTranslation[ENUM_MAX];

View File

@ -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
{

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)
{
// Not sure if it conflicts with our TLS variables
//DisableThreadLibraryCalls(hModule);
Steam::Proxy::RunMod();
// Ensure we're working with our desired binary