Structureddata stuff. Not the best implementation, but better than our old one :P

This commit is contained in:
momo5502 2016-02-06 13:37:23 +01:00
parent b4be34c8a8
commit c1ef716e5c
20 changed files with 220 additions and 42 deletions

View File

@ -13,8 +13,8 @@ namespace Components
virtual void Load(Game::XAssetHeader* header, std::string name, ZoneBuilder::Zone* builder) { /*ErrorTypeNotSupported(this);*/ };
};
typedef Game::XAssetHeader(*Callback)(Game::XAssetType, const char*);
typedef bool(*RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, const char* name);
typedef Game::XAssetHeader(*Callback)(Game::XAssetType type, std::string name);
typedef bool(*RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, std::string name);
AssetHandler();
~AssetHandler();

View File

@ -10,6 +10,11 @@ namespace Components
std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount);
if (FastFiles::Exists("patch_iw4x"))
{
data.push_back({ "patch_iw4x", 1, 0 });
}
// Load custom weapons, if present (force that later on)
if (FastFiles::Exists("weapons_mp"))
{

View File

@ -116,7 +116,7 @@ namespace Components
Localization::Localization()
{
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE, [] (Game::XAssetType, const char* filename)
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE, [] (Game::XAssetType, std::string filename)
{
Game::XAssetHeader header = { 0 };

View File

@ -50,7 +50,7 @@ namespace Components
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
}
bool Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name)
bool Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name)
{
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end())
{
@ -63,7 +63,7 @@ namespace Components
if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS)
{
static std::string mapEntities;
FileSystem::File ents(Utils::VA("%s.ents", name));
FileSystem::File ents(name + ".ents");
if (ents.Exists())
{
mapEntities = ents.GetBuffer();

View File

@ -19,7 +19,7 @@ namespace Components
static std::vector<std::string> CurrentDependencies;
static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname);
static bool LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name);
static bool LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name);
static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
void ReallocateEntryPool();

View File

@ -506,16 +506,16 @@ namespace Components
Menus::MenuList.clear();
}
Game::XAssetHeader Menus::MenuLoad(Game::XAssetType type, const char* filename)
Game::XAssetHeader Menus::MenuLoad(Game::XAssetType type, std::string filename)
{
return { Game::Menus_FindByName(Game::uiContext, filename) };
return { Game::Menus_FindByName(Game::uiContext, filename.data()) };
}
Game::XAssetHeader Menus::MenuFileLoad(Game::XAssetType type, const char* filename)
Game::XAssetHeader Menus::MenuFileLoad(Game::XAssetType type, std::string filename)
{
Game::XAssetHeader header = { 0 };
Game::MenuList* menuList = Game::DB_FindXAssetHeader(type, filename).menuList;
Game::MenuList* menuList = Game::DB_FindXAssetHeader(type, filename.data()).menuList;
header.menuList = menuList;
// Free the last menulist and ui context, as we have to rebuild it with the new menus
@ -538,7 +538,7 @@ namespace Components
{
if (FileSystem::File(filename).Exists())
{
header.menuList = Menus::LoadScriptMenu(filename);
header.menuList = Menus::LoadScriptMenu(filename.data());
// Reset, if we didn't find scriptmenus
if (!header.menuList)

View File

@ -19,8 +19,8 @@ namespace Components
static std::map<std::string, Game::MenuList*> MenuListList;
static std::vector<std::string> CustomMenus;
static Game::XAssetHeader MenuLoad(Game::XAssetType type, const char* filename);
static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, const char* filename);
static Game::XAssetHeader MenuLoad(Game::XAssetType type, std::string filename);
static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, std::string filename);
static Game::MenuList* LoadMenuList(Game::MenuList* menuList);
static Game::MenuList* LoadScriptMenu(const char* menu);

View File

@ -9,13 +9,13 @@ namespace Components
MusicalTalent::SoundAliasList[Utils::StrToLower(sound)] = file;
}
Game::XAssetHeader MusicalTalent::ManipulateAliases(Game::XAssetType type, const char* filename)
Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename)
{
Game::XAssetHeader header = { 0 };
if (MusicalTalent::SoundAliasList.find(Utils::StrToLower(filename)) != MusicalTalent::SoundAliasList.end())
{
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename).aliasList;
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).aliasList;
if (aliases)
{
@ -33,7 +33,7 @@ namespace Components
MusicalTalent::MusicalTalent()
{
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ManipulateAliases);
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases);
MusicalTalent::Replace("music_mainmenu_mp", "hz_boneyard_intro_LR_1.mp3");
}

View File

@ -11,6 +11,6 @@ namespace Components
private:
static std::map<std::string, const char*> SoundAliasList;
static Game::XAssetHeader ManipulateAliases(Game::XAssetType type, const char* filename);
static Game::XAssetHeader ModifyAliases(Game::XAssetType type, std::string filename);
};
}

View File

@ -18,14 +18,14 @@ namespace Components
return hash;
}
Game::StringTable* StringTable::LoadObject(const char* filename)
Game::StringTable* StringTable::LoadObject(std::string filename)
{
Game::StringTable* table = nullptr;
FileSystem::File rawTable(filename);
if (rawTable.Exists())
{
Utils::CSV parsedTable(rawTable.GetBuffer(), false);
Utils::CSV parsedTable(rawTable.GetBuffer(), false, false);
table = Utils::Memory::AllocateArray<Game::StringTable>(1);
@ -67,10 +67,7 @@ namespace Components
StringTable::StringTable()
{
// Disable StringTable loading until our StructuredData handler is finished!
#ifdef ENABLE_STRINGTABLES
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRINGTABLE, [] (Game::XAssetType, const char* filename)
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRINGTABLE, [] (Game::XAssetType, std::string filename)
{
Game::XAssetHeader header = { 0 };
@ -85,7 +82,6 @@ namespace Components
return header;
});
#endif
}
StringTable::~StringTable()

View File

@ -11,6 +11,6 @@ namespace Components
static std::map<std::string, Game::StringTable*> StringTableMap;
static int Hash(const char* data);
static Game::StringTable* LoadObject(const char* filename);
static Game::StringTable* LoadObject(std::string filename);
};
}

View File

@ -2,6 +2,92 @@
namespace Components
{
StructuredData* StructuredData::Singleton = nullptr;
int StructuredData::IndexCount[StructuredData::ENUM_MAX];
Game::structuredDataEnumIndex_t* StructuredData::Indices[StructuredData::ENUM_MAX];
std::vector<StructuredData::EnumEntry> StructuredData::Entries[StructuredData::ENUM_MAX];
void StructuredData::AddPlayerDataEntry(StructuredData::PlayerDataType type, int index, std::string name)
{
if (type >= StructuredData::ENUM_MAX) return;
// Check for duplications
for (auto entry : StructuredData::Entries[type])
{
if (entry.name == name || entry.statOffset == index)
{
return;
}
}
StructuredData::Entries[type].push_back({ name, index });
}
void StructuredData::PatchPlayerDataEnum(Game::structuredDataDef_t* data, StructuredData::PlayerDataType type, std::vector<StructuredData::EnumEntry>& entries)
{
if (!data || !data->data) return;
Game::structuredDataEnum_t* dataEnum = &data->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.
// This whole procedure is potentially unsafe.
// If any index changes, everything gets shifted and the stats are fucked.
int lastIndex = 0;
for (int i = 0; i < dataEnum->numIndices; i++)
{
if (dataEnum->indices[i].index > lastIndex)
{
lastIndex = dataEnum->indices[i].index;
}
}
// Calculate new count
StructuredData::IndexCount[type] = dataEnum->numIndices + entries.size();
// Allocate new entries
StructuredData::Indices[type] = StructuredData::GetSingleton()->MemAllocator.AllocateArray<Game::structuredDataEnumIndex_t>(StructuredData::IndexCount[type]);
memcpy(StructuredData::Indices[type], dataEnum->indices, sizeof(Game::structuredDataEnumIndex_t) * dataEnum->numIndices);
for (unsigned int i = 0; i < entries.size(); i++)
{
unsigned int pos = 0;
for (; pos < (dataEnum->numIndices + i); pos++)
{
if (StructuredData::Indices[type][pos].key == entries[i].name)
{
Logger::Error("Duplicate playerdatadef entry found: %s", entries[i].name.data());
}
// We found our position
if (entries[i].name < StructuredData::Indices[type][pos].key)
{
break;
}
}
for (unsigned int j = dataEnum->numIndices + i; j > pos; j--)
{
StructuredData::Indices[type][j] = StructuredData::Indices[type][j - 1];
}
StructuredData::Indices[type][pos].index = entries[i].statOffset + lastIndex;
StructuredData::Indices[type][pos].key = StructuredData::GetSingleton()->MemAllocator.DuplicateString(entries[i].name);
}
// Apply our patches
dataEnum->numIndices = StructuredData::IndexCount[type];
dataEnum->indices = StructuredData::Indices[type];
}
void StructuredData::DumpDataDef(Game::structuredDataDef_t* dataDef)
{
if (!dataDef || !dataDef->data) return;
@ -16,17 +102,72 @@ namespace Components
Utils::WriteFile(Utils::VA("raw/%s.json", dataDef->name), definition.dump());
}
StructuredData* StructuredData::GetSingleton()
{
if (!StructuredData::Singleton)
{
Logger::Error("StructuredData singleton is null!");
}
return StructuredData::Singleton;
}
StructuredData::StructuredData()
{
StructuredData::Singleton = this;
ZeroMemory(StructuredData::IndexCount, sizeof(StructuredData));
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, [] (Game::XAssetType type, std::string filename)
{
Game::XAssetHeader header = { 0 };
if (filename == "mp/playerdata.def")
{
Game::structuredDataDef_t* data = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, filename.data()).structuredData;
header.structuredData = data;
if (data)
{
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); i++)
{
if (StructuredData::Entries[i].size())
{
StructuredData::PatchPlayerDataEnum(data, static_cast<StructuredData::PlayerDataType>(i), StructuredData::Entries[i]);
}
}
}
}
return header;
});
Command::Add("dumpDataDef", [] (Command::Params params)
{
if (params.Length() < 2) return;
StructuredData::DumpDataDef(Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF, params[1]).structuredData);
});
// ---------- Weapons ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, 1, "m40a3");
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, 2, "ak47classic");
//StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, 3, "ak74u");
//StructuredData::AddPlayerDataEntry(StructuredData::ENUM_WEAPONS, 4, "peacekeeper");
// ---------- Cardicons ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDICONS, 1, "cardicon_rtrolling");
// ---------- Cardtitles ----------
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDTITLES, 1, "cardtitle_evilchicken");
StructuredData::AddPlayerDataEntry(StructuredData::ENUM_CARDTITLES, 2, "cardtitle_nolaststand");
}
StructuredData::~StructuredData()
{
for (int i = 0; i < ARR_SIZE(StructuredData::Entries); i++)
{
StructuredData::Entries[i].clear();
}
StructuredData::Singleton = nullptr;
}
}

View File

@ -3,11 +3,47 @@ namespace Components
class StructuredData : public Component
{
public:
enum PlayerDataType
{
ENUM_FEATURES,
ENUM_WEAPONS,
ENUM_ATTACHEMENTS,
ENUM_CHALLENGES,
ENUM_CAMOS,
ENUM_PERKS,
ENUM_KILLSTREAKS,
ENUM_ACCOLADES,
ENUM_CARDICONS,
ENUM_CARDTITLES,
ENUM_CARDNAMEPLATES,
ENUM_TEAMS,
ENUM_GAMETYPES,
ENUM_MAX
};
StructuredData();
~StructuredData();
const char* GetName() { return "StructuredData"; };
void AddPlayerDataEntry(PlayerDataType type, int index, std::string name);
private:
struct EnumEntry
{
std::string name;
int statOffset;
};
static void DumpDataDef(Game::structuredDataDef_t* dataDef);
static void PatchPlayerDataEnum(Game::structuredDataDef_t* data, PlayerDataType type, std::vector<EnumEntry>& entries);
static StructuredData* GetSingleton();
Utils::Memory::Allocator MemAllocator;
static int IndexCount[ENUM_MAX];
static Game::structuredDataEnumIndex_t* Indices[ENUM_MAX];
static std::vector<EnumEntry> Entries[ENUM_MAX];
static StructuredData* Singleton;
};
}

View File

@ -2,14 +2,14 @@
namespace Components
{
Game::XAssetHeader Weapon::WeaponFileLoad(Game::XAssetType type, const char* filename)
Game::XAssetHeader Weapon::WeaponFileLoad(Game::XAssetType type, std::string filename)
{
Game::XAssetHeader header = { 0 };
// Try loading raw weapon
if (FileSystem::File(Utils::VA("weapons/mp/%s", filename)).Exists())
if (FileSystem::File(Utils::VA("weapons/mp/%s", filename.data())).Exists())
{
header.data = Game::BG_LoadWeaponDef_LoadObj(filename);
header.data = Game::BG_LoadWeaponDef_LoadObj(filename.data());
}
return header;

View File

@ -7,6 +7,6 @@ namespace Components
const char* GetName() { return "Weapon"; };
private:
static Game::XAssetHeader WeaponFileLoad(Game::XAssetType type, const char* filename);
static Game::XAssetHeader WeaponFileLoad(Game::XAssetType type, std::string filename);
};
}

View File

@ -447,7 +447,7 @@ namespace Components
static_assert(sizeof(Game::XFile) == 40, "Invalid XFile structure!");
static_assert(Game::MAX_XFILE_COUNT == 8, "XFile block enum is invalid!");
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, const char* name)
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string name)
{
// static void* blocTable = 0;
//

View File

@ -2,9 +2,9 @@
namespace Utils
{
CSV::CSV(std::string file, bool isFile)
CSV::CSV(std::string file, bool isFile, bool allowComments)
{
CSV::Parse(file, isFile);
CSV::Parse(file, isFile, allowComments);
}
CSV::~CSV()
@ -64,7 +64,7 @@ namespace Utils
return "";
}
void CSV::Parse(std::string file, bool isFile)
void CSV::Parse(std::string file, bool isFile, bool allowComments)
{
std::string buffer;
@ -84,12 +84,12 @@ namespace Utils
for (auto row : rows)
{
CSV::ParseRow(row);
CSV::ParseRow(row, allowComments);
}
}
}
void CSV::ParseRow(std::string row)
void CSV::ParseRow(std::string row, bool allowComments)
{
bool isString = false;
std::string element;
@ -119,7 +119,7 @@ namespace Utils
//++i;
continue;
}
else if (!isString && row[i] == '#') // Skip comments. I know CSVs usually don't have comments, but in this case it's useful
else if (!isString && row[i] == '#' && allowComments) // Skip comments. I know CSVs usually don't have comments, but in this case it's useful
{
return;
}

View File

@ -3,7 +3,7 @@ namespace Utils
class CSV
{
public:
CSV(std::string file, bool isFile = true);
CSV(std::string file, bool isFile = true, bool allowComments = true);
~CSV();
int GetRows();
@ -14,8 +14,8 @@ namespace Utils
private:
void Parse(std::string file, bool isFile = true);
void ParseRow(std::string row);
void Parse(std::string file, bool isFile = true, bool allowComments = true);
void ParseRow(std::string row, bool allowComments = true);
std::vector<std::vector<std::string>> DataMap;
};
}

View File

@ -25,9 +25,9 @@ namespace Utils
return input;
}
bool EndsWith(const char* haystack, const char* needle)
bool EndsWith(std::string haystack, std::string needle)
{
return (strstr(haystack, needle) == (haystack + strlen(haystack) - strlen(needle)));
return (strstr(haystack.data(), needle.data()) == (haystack.data() + haystack.size() - needle.size()));
}
std::vector<std::string> Explode(const std::string& str, char delim)

View File

@ -4,7 +4,7 @@ namespace Utils
{
const char *VA(const char *fmt, ...);
std::string StrToLower(std::string input);
bool EndsWith(const char* haystack, const char* needle);
bool EndsWith(std::string haystack, std::string needle);
std::vector<std::string> Explode(const std::string& str, char delim);
void Replace(std::string &string, std::string find, std::string replace);
bool StartsWith(std::string haystack, std::string needle);