[StructuredData] Add 15 classes code, still not fully working!
This commit is contained in:
parent
442be57564
commit
a4abdd9dcb
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user