2016-01-12 19:29:22 -05:00
|
|
|
#include "STDInclude.hpp"
|
|
|
|
|
|
|
|
namespace Components
|
|
|
|
{
|
2016-02-06 07:37:23 -05:00
|
|
|
StructuredData* StructuredData::Singleton = nullptr;
|
|
|
|
|
|
|
|
int StructuredData::IndexCount[StructuredData::ENUM_MAX];
|
2016-02-07 06:29:43 -05:00
|
|
|
Game::StructuredDataEnumEntry* StructuredData::Indices[StructuredData::ENUM_MAX];
|
2016-05-25 19:39:33 -04:00
|
|
|
std::vector<std::string> StructuredData::Entries[StructuredData::ENUM_MAX];
|
2016-02-06 07:37:23 -05:00
|
|
|
|
2016-05-25 19:39:33 -04:00
|
|
|
void StructuredData::AddPlayerDataEntry(StructuredData::PlayerDataType type, std::string name)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
if (type >= StructuredData::ENUM_MAX) return;
|
|
|
|
|
|
|
|
// Check for duplications
|
2016-05-25 19:39:33 -04:00
|
|
|
auto v = &StructuredData::Entries[type];
|
|
|
|
if (std::find(v->begin(), v->end(), name) == v->end())
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
StructuredData::Entries[type].push_back(name);
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 19:39:33 -04:00
|
|
|
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
if (!data || type >= StructuredData::ENUM_MAX) return;
|
2016-02-06 07:37:23 -05:00
|
|
|
|
2016-05-25 19:39:33 -04:00
|
|
|
Game::StructuredDataEnum* dataEnum = &data->enums[type];
|
2016-02-06 07:37:23 -05:00
|
|
|
|
|
|
|
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.
|
|
|
|
// This whole procedure is potentially unsafe.
|
|
|
|
// If any index changes, everything gets shifted and the stats are fucked.
|
|
|
|
int lastIndex = 0;
|
2016-02-09 19:22:00 -05:00
|
|
|
for (int i = 0; i < dataEnum->numIndices; ++i)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
if (dataEnum->indices[i].index > lastIndex)
|
|
|
|
{
|
|
|
|
lastIndex = dataEnum->indices[i].index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate new count
|
|
|
|
StructuredData::IndexCount[type] = dataEnum->numIndices + entries.size();
|
|
|
|
|
|
|
|
// Allocate new entries
|
2016-02-07 06:29:43 -05:00
|
|
|
StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnumEntry>(StructuredData::IndexCount[type]);
|
|
|
|
memcpy(StructuredData::Indices[type], dataEnum->indices, sizeof(Game::StructuredDataEnumEntry) * dataEnum->numIndices);
|
2016-02-06 07:37:23 -05:00
|
|
|
|
2016-02-09 19:22:00 -05:00
|
|
|
for (unsigned int i = 0; i < entries.size(); ++i)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
unsigned int pos = 0;
|
|
|
|
|
|
|
|
for (; pos < (dataEnum->numIndices + i); pos++)
|
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
if (StructuredData::Indices[type][pos].key == entries[i])
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].data());
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// We found our position
|
2016-05-25 19:39:33 -04:00
|
|
|
if (entries[i] < StructuredData::Indices[type][pos].key)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-06 20:31:30 -05:00
|
|
|
for (unsigned int j = dataEnum->numIndices + i; j > pos && j < static_cast<unsigned int>(StructuredData::IndexCount[type]); j--)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
2016-02-07 06:29:43 -05:00
|
|
|
memcpy(&StructuredData::Indices[type][j], &StructuredData::Indices[type][j - 1], sizeof(Game::StructuredDataEnumEntry));
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
|
2016-05-25 19:39:33 -04:00
|
|
|
StructuredData::Indices[type][pos].index = i + lastIndex;
|
|
|
|
StructuredData::Indices[type][pos].key = StructuredData::GetSingleton()->MemAllocator.DuplicateString(entries[i]);
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Apply our patches
|
|
|
|
dataEnum->numIndices = StructuredData::IndexCount[type];
|
|
|
|
dataEnum->indices = StructuredData::Indices[type];
|
|
|
|
}
|
|
|
|
|
|
|
|
StructuredData* StructuredData::GetSingleton()
|
|
|
|
{
|
|
|
|
if (!StructuredData::Singleton)
|
|
|
|
{
|
|
|
|
Logger::Error("StructuredData singleton is null!");
|
|
|
|
}
|
|
|
|
|
|
|
|
return StructuredData::Singleton;
|
|
|
|
}
|
|
|
|
|
2016-01-12 19:29:22 -05:00
|
|
|
StructuredData::StructuredData()
|
|
|
|
{
|
2016-03-04 11:02:00 -05:00
|
|
|
// Only execute this when building zones
|
|
|
|
if (!ZoneBuilder::IsEnabled()) return;
|
|
|
|
|
2016-05-25 19:39:33 -04:00
|
|
|
// 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
|
|
|
|
|
2016-02-06 07:37:23 -05:00
|
|
|
StructuredData::Singleton = this;
|
|
|
|
ZeroMemory(StructuredData::IndexCount, sizeof(StructuredData));
|
|
|
|
|
2016-02-07 08:19:55 -05:00
|
|
|
// TODO: Write these into fastfiles and only hotpatch them when building fastfiles!
|
2016-02-06 07:37:23 -05:00
|
|
|
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, [] (Game::XAssetType type, std::string filename)
|
|
|
|
{
|
|
|
|
Game::XAssetHeader header = { 0 };
|
|
|
|
|
|
|
|
if (filename == "mp/playerdata.def")
|
|
|
|
{
|
2016-02-07 06:29:43 -05:00
|
|
|
Game::StructuredDataDefSet* data = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, filename.data()).structuredData;
|
2016-02-06 07:37:23 -05:00
|
|
|
header.structuredData = data;
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
// First check if all versions are present
|
|
|
|
for (int ver = 155; ver <= version; ++ver)
|
|
|
|
{
|
|
|
|
bool foundVersion = false;
|
|
|
|
|
|
|
|
for (int i = 0; i < data->count; ++i)
|
|
|
|
{
|
|
|
|
if (data->data[i].version == ver)
|
|
|
|
{
|
|
|
|
foundVersion = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundVersion && ver == version)
|
|
|
|
{
|
|
|
|
//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!");
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
|
|
|
Logger::Print("Patching PlayerDataDef for version %d...\n", version);
|
|
|
|
|
|
|
|
// Reallocate the definition
|
|
|
|
Game::StructuredDataDef* newData = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataDef>(data->count + 1);
|
|
|
|
memcpy(&newData[1], data->data, sizeof Game::StructuredDataDef * data->count);
|
|
|
|
|
|
|
|
// Fill our new definition with the base data (155)
|
|
|
|
memcpy(newData, &data->data[data->count - 1], sizeof Game::StructuredDataDef);
|
|
|
|
newData->version = version;
|
|
|
|
|
|
|
|
// Reallocate the enum array
|
|
|
|
Game::StructuredDataEnum* newEnums = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::StructuredDataEnum>(newData->numEnums);
|
|
|
|
memcpy(newEnums, newData->enums, sizeof Game::StructuredDataEnum * newData->numEnums);
|
|
|
|
newData->enums = newEnums;
|
|
|
|
|
|
|
|
// Patch the definition
|
2016-02-09 19:22:00 -05:00
|
|
|
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
if (StructuredData::Entries[i].size())
|
|
|
|
{
|
2016-05-25 19:39:33 -04:00
|
|
|
StructuredData::PatchPlayerDataEnum(newData, static_cast<StructuredData::PlayerDataType>(i), StructuredData::Entries[i]);
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
}
|
2016-05-25 19:39:33 -04:00
|
|
|
|
|
|
|
// Apply the patch
|
|
|
|
data->data = newData;
|
|
|
|
data->count++;
|
2016-02-06 07:37:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return header;
|
|
|
|
});
|
2016-01-12 19:29:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
StructuredData::~StructuredData()
|
|
|
|
{
|
2016-02-09 19:22:00 -05:00
|
|
|
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); ++i)
|
2016-02-06 07:37:23 -05:00
|
|
|
{
|
|
|
|
StructuredData::Entries[i].clear();
|
|
|
|
}
|
2016-01-12 19:29:22 -05:00
|
|
|
|
2016-02-06 07:37:23 -05:00
|
|
|
StructuredData::Singleton = nullptr;
|
2016-01-12 19:29:22 -05:00
|
|
|
}
|
|
|
|
}
|