Non-incremental playerdatadef building

This commit is contained in:
momo5502 2016-05-26 13:13:02 +02:00
parent 6517f0be76
commit 5c87509849
4 changed files with 130 additions and 137 deletions

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit d089f04ae53565aff77240172e1007f3959503f4 Subproject commit ed87c1fe2c6e1633cadb62cf54b2723b2b25c280

View File

@ -155,9 +155,8 @@ namespace Components
{ {
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).Install()->Quick(); Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).Install()->Quick();
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick(); Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
}
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).Install()->Quick(); Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).Install()->Quick();
}
// basic checks (hash jumps, both normal and playlist) // basic checks (hash jumps, both normal and playlist)
Utils::Hook::Nop(0x5B97A3, 2); Utils::Hook::Nop(0x5B97A3, 2);

View File

@ -4,35 +4,29 @@ namespace Components
{ {
StructuredData* StructuredData::Singleton = nullptr; StructuredData* StructuredData::Singleton = nullptr;
int StructuredData::IndexCount[StructuredData::ENUM_MAX]; const char* StructuredData::EnumTranslation[ENUM_MAX] =
Game::StructuredDataEnumEntry* StructuredData::Indices[StructuredData::ENUM_MAX];
std::vector<std::string> StructuredData::Entries[StructuredData::ENUM_MAX];
void StructuredData::AddPlayerDataEntry(StructuredData::PlayerDataType type, std::string name)
{ {
if (type >= StructuredData::ENUM_MAX) return; "features",
"weapons",
// Check for duplications "attachements",
auto v = &StructuredData::Entries[type]; "challenges",
if (std::find(v->begin(), v->end(), name) == v->end()) "camos",
{ "perks",
StructuredData::Entries[type].push_back(name); "killstreaks",
} "accolades",
} "cardicons",
"cardtitles",
"cardnameplates",
"teams",
"gametypes"
};
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries) void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
{ {
if (!data || type >= StructuredData::ENUM_MAX) return; if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return;
Game::StructuredDataEnum* dataEnum = &data->enums[type]; Game::StructuredDataEnum* dataEnum = &data->enums[type];
if (StructuredData::IndexCount[type])
{
dataEnum->numIndices = StructuredData::IndexCount[type];
dataEnum->indices = StructuredData::Indices[type];
return;
}
// Find last index so we can add our offset to it. // Find last index so we can add our offset to it.
// This whole procedure is potentially unsafe. // This whole procedure is potentially unsafe.
// If any index changes, everything gets shifted and the stats are fucked. // If any index changes, everything gets shifted and the stats are fucked.
@ -46,11 +40,11 @@ namespace Components
} }
// Calculate new count // Calculate new count
StructuredData::IndexCount[type] = dataEnum->numIndices + entries.size(); unsigned int indexCount = dataEnum->numIndices + entries.size();
// Allocate new entries // Allocate new entries
StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(StructuredData::IndexCount[type]); Game::StructuredDataEnumEntry* indices = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(indexCount);
memcpy(StructuredData::Indices[type], dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices); memcpy(indices, dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices);
for (unsigned int i = 0; i < entries.size(); ++i) for (unsigned int i = 0; i < entries.size(); ++i)
{ {
@ -58,30 +52,31 @@ namespace Components
for (; pos < (dataEnum->numIndices + i); pos++) for (; pos < (dataEnum->numIndices + i); pos++)
{ {
if (StructuredData::Indices[type][pos].key == entries[i]) if (indices[pos].key == entries[i])
{ {
Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].data()); Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].data());
} }
// We found our position // We found our position
if (entries[i] < StructuredData::Indices[type][pos].key) if (entries[i] < indices[pos].key)
{ {
break; break;
} }
} }
for (unsigned int j = dataEnum->numIndices + i; j > pos && j < static_cast<unsigned int>(StructuredData::IndexCount[type]); j--) // TODO directly shift the data using memmove
for (unsigned int j = dataEnum->numIndices + i; j > pos && j < indexCount; j--)
{ {
memcpy(&StructuredData::Indices[type][j], &StructuredData::Indices[type][j - 1], sizeof(Game::StructuredDataEnumEntry)); memcpy(&indices[j], &indices[j - 1], sizeof(Game::StructuredDataEnumEntry));
} }
StructuredData::Indices[type][pos].index = i + lastIndex; indices[pos].index = i + lastIndex;
StructuredData::Indices[type][pos].key = StructuredData::GetSingleton()->MemAllocator.DuplicateString(entries[i]); indices[pos].key = StructuredData::GetSingleton()->MemAllocator.DuplicateString(entries[i]);
} }
// Apply our patches // Apply our patches
dataEnum->numIndices = StructuredData::IndexCount[type]; dataEnum->numIndices = indexCount;
dataEnum->indices = StructuredData::Indices[type]; dataEnum->indices = indices;
} }
StructuredData* StructuredData::GetSingleton() StructuredData* StructuredData::GetSingleton()
@ -99,113 +94,116 @@ namespace Components
// Only execute this when building zones // Only execute this when building zones
if (!ZoneBuilder::IsEnabled()) return; if (!ZoneBuilder::IsEnabled()) return;
// TODO: Increment the version once you change something below
static int version = 156;
// ---------- Weapons ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, "m40a3");
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, "ak47classic");
//StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, "ak74u");
//StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, "peacekeeper");
// ---------- Cardicons ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDICONS, "cardicon_rtrolling");
// ---------- Cardtitles ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDTITLES, "cardtitle_evilchicken");
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDTITLES, "cardtitle_nolaststand");
// Patch handing and initialization
StructuredData::Singleton = this; StructuredData::Singleton = this;
ZeroMemory(StructuredData::IndexCount, sizeof(StructuredData));
// TODO: Write these into fastfiles and only hotpatch them when building fastfiles! AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* restrict)
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, [] (Game::XAssetType type, std::string filename)
{ {
Game::XAssetHeader header = { 0 }; // Only intercept playerdatadef loading
if (filename != "mp/playerdata.def" || type != Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF) return;
if (filename == "mp/playerdata.def") // Store asset
{ Game::StructuredDataDefSet* data = asset.structuredData;
Game::StructuredDataDefSet* data = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, filename.data()).structuredData; if (!data) return;
header.structuredData = data;
if (data) if (data->count != 1)
{ {
// First check if all versions are present Logger::Error("PlayerDataDefSet contains more than 1 definition!");
for (int ver = 155; ver <= version; ++ver) return;
{
bool foundVersion = false;
for (int i = 0; i < data->count; ++i)
{
if (data->data[i].version == ver)
{
foundVersion = true;
break;
}
} }
if (foundVersion && ver == version) if (data->data[0].version != 155)
{
//Logger::Print("PlayerDataDef already patched for version %d, no need to patch anything!\n", version);
return header;
}
else if (!foundVersion && ver != version)
{
Logger::Error("PlayerDataDef for version %d is missing!", ver);
return header;
}
}
if (data->data[data->count - 1].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 header; return;
} }
Logger::Print("Patching PlayerDataDef for version %d...\n", version); std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
// First check if all versions are present
for (int i = 156;; ++i)
{
FileSystem::File definition(Utils::VA("%s/%d.json", filename.data(), i));
if (!definition.Exists()) break;
std::vector<std::vector<std::string>> enumContainer;
std::string errors;
json11::Json defData = json11::Json::parse(definition.GetBuffer(), errors);
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
{
auto enumData = defData[StructuredData::EnumTranslation[pType]];
std::vector<std::string> entryData;
if (enumData.is_array())
{
for (auto rawEntry : enumData.array_items())
{
if (rawEntry.is_string())
{
entryData.push_back(rawEntry.string_value());
}
}
}
enumContainer.push_back(entryData);
}
patchDefinitions[i] = enumContainer;
}
// Nothing to patch
if (patchDefinitions.empty()) return;
// Reallocate the definition // Reallocate the definition
Game::StructuredDataDef* newData = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataDef>(data->count + 1); Game::StructuredDataDef* newData = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size());
memcpy(&newData[1], data->data, sizeof Game::StructuredDataDef * data->count); memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count);
// Fill our new definition with the base data (155) // Prepare the buffers
memcpy(newData, &data->data[data->count - 1], sizeof Game::StructuredDataDef); for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
newData->version = version; {
memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef);
newData[i].version = (patchDefinitions.size() - i) + 155;
// Reallocate the enum array // Reallocate the enum array
Game::StructuredDataEnum* newEnums = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnum>(newData->numEnums); Game::StructuredDataEnum* newEnums = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnum>(data->data->numEnums);
memcpy(newEnums, newData->enums, sizeof Game::StructuredDataEnum * newData->numEnums); memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums);
newData->enums = newEnums; newData[i].enums = newEnums;
}
// Apply new data
data->data = newData;
data->count += patchDefinitions.size();
// Patch the definition // Patch the definition
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i) for (int i = 0; i < data->count; ++i)
{ {
if (StructuredData::Entries[i].size()) // No need to patch version 155
if (newData[i].version == 155) continue;
if(patchDefinitions.find(newData[i].version) != patchDefinitions.end())
{ {
StructuredData::PatchPlayerDataEnum(newData, static_cast<StructuredData::PlayerDataType>(i), StructuredData::Entries[i]); auto patchData = patchDefinitions[newData[i].version];
}
}
// Apply the patch // Invalid patch data
data->data = newData; if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX) continue;
data->count++;
}
}
return header; // Apply the patch data
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
{
if (!patchData[pType].empty())
{
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
}
}
}
}
}); });
} }
StructuredData::~StructuredData() StructuredData::~StructuredData()
{ {
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i)
{
StructuredData::Entries[i].clear();
}
StructuredData::Singleton = nullptr; StructuredData::Singleton = nullptr;
} }
} }

View File

@ -25,18 +25,14 @@ namespace Components
~StructuredData(); ~StructuredData();
const char* GetName() { return "StructuredData"; }; const char* GetName() { return "StructuredData"; };
void AddPlayerDataEntry(PlayerDataType type, std::string name);
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 StructuredData* GetSingleton(); static StructuredData* GetSingleton();
Utils::Memory::Allocator MemAllocator; Utils::Memory::Allocator MemAllocator;
static int IndexCount[ENUM_MAX];
static Game::StructuredDataEnumEntry* Indices[ENUM_MAX];
static std::vector<std::string> Entries[ENUM_MAX];
static StructuredData* Singleton; static StructuredData* Singleton;
static const char* EnumTranslation[ENUM_MAX];
}; };
} }