[Json] Sorround with try/catch (#531)

* [Json] Sorround with try/catch

* Minor format fix
This commit is contained in:
Edo 2022-10-16 16:17:42 +01:00 committed by GitHub
parent bff0d22e81
commit c7ae27a664
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 317 additions and 256 deletions

View File

@ -80,7 +80,7 @@ namespace Assets
void IFont_s::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::Font_s *asset = header.font;
const auto* asset = header.font;
if (asset->material)
{
@ -98,154 +98,163 @@ namespace Assets
Components::FileSystem::File fontDefFile(Utils::String::VA("%s.json", name.data()));
Components::FileSystem::File fontFile(Utils::String::VA("%s.ttf", name.data()));
if (fontDefFile.exists() && fontFile.exists())
if (!fontDefFile.exists() || !fontFile.exists())
{
auto fontDef = nlohmann::json::parse(fontDefFile.getBuffer());
return;
}
if (!fontDef.is_object())
nlohmann::json fontDef = nlohmann::json::parse(fontDefFile.getBuffer());
try
{
fontDef = nlohmann::json::parse(fontDefFile.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Components::Logger::Error(Game::ERR_FATAL, "Json Parse Error: {}. Font {} is invalid", ex.what(), name);
return;
}
auto w = fontDef["textureWidth"].get<int>();
auto h = fontDef["textureHeight"].get<int>();
auto size = fontDef["size"].get<int>();
auto yOffset = fontDef["yOffset"].get<int>();
auto* pixels = builder->getAllocator()->allocateArray<uint8_t>(w * h);
// Setup assets
const auto* texName = builder->getAllocator()->duplicateString(Utils::String::VA("if_%s", name.data() + 6 /* skip "fonts/" */));
const auto* fontName = builder->getAllocator()->duplicateString(name);
const auto* glowMaterialName = builder->getAllocator()->duplicateString(Utils::String::VA("%s_glow", name.data()));
auto* image = builder->getAllocator()->allocate<Game::GfxImage>();
std::memcpy(image, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_IMAGE, "gamefonts_pc").image, sizeof(Game::GfxImage));
image->name = texName;
auto* material = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(material, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material, sizeof(Game::Material));
auto textureTable = builder->getAllocator()->allocate<Game::MaterialTextureDef>();
std::memcpy(textureTable, material->textureTable, sizeof(Game::MaterialTextureDef));
material->textureTable = textureTable;
material->textureTable->u.image = image;
material->info.name = fontName;
auto* glowMaterial = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(glowMaterial, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc_glow").material, sizeof(Game::Material));
glowMaterial->textureTable = material->textureTable;
glowMaterial->info.name = glowMaterialName;
std::vector<std::uint16_t> charset;
if (fontDef["charset"].is_array())
{
nlohmann::json::array_t charsetArray = fontDef["charset"];
for (auto& ch : charsetArray)
{
Components::Logger::Error(Game::ERR_FATAL, "Font define {} is invalid", name);
return;
charset.push_back(static_cast<std::uint16_t>(ch.get<int>()));
}
int w = fontDef["textureWidth"].get<int>();
int h = fontDef["textureHeight"].get<int>();
int size = fontDef["size"].get<int>();
int yOffset = fontDef["yOffset"].get<int>();
// order matters
std::ranges::sort(charset);
auto* pixels = builder->getAllocator()->allocateArray<uint8_t>(w * h);
// Setup assets
const auto* texName = builder->getAllocator()->duplicateString(Utils::String::VA("if_%s", name.data() + 6 /* skip "fonts/" */));
const auto* fontName = builder->getAllocator()->duplicateString(name.data());
const auto* glowMaterialName = builder->getAllocator()->duplicateString(Utils::String::VA("%s_glow", name.data()));
auto* image = builder->getAllocator()->allocate<Game::GfxImage>();
std::memcpy(image, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_IMAGE, "gamefonts_pc").image, sizeof(Game::GfxImage));
image->name = texName;
auto* material = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(material, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material, sizeof(Game::Material));
auto textureTable = builder->getAllocator()->allocate<Game::MaterialTextureDef>();
std::memcpy(textureTable, material->textureTable, sizeof(Game::MaterialTextureDef));
material->textureTable = textureTable;
material->textureTable->u.image = image;
material->info.name = fontName;
auto* glowMaterial = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(glowMaterial, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc_glow").material, sizeof(Game::Material));
glowMaterial->textureTable = material->textureTable;
glowMaterial->info.name = glowMaterialName;
std::vector<uint16_t> charset;
if (fontDef["charset"].is_array())
for (std::uint16_t i = 32; i < 128; i++)
{
nlohmann::json::array_t charsetArray = fontDef["charset"];
for (auto& ch : charsetArray)
charset.push_back(static_cast<uint16_t>(ch.get<int>()));
// order matters
std::sort(charset.begin(), charset.end());
for (uint16_t i = 32; i < 128; i++)
if (std::ranges::find(charset, i) == charset.end())
{
if (std::find(charset.begin(), charset.end(), i) == charset.end())
{
Components::Logger::Error(Game::ERR_FATAL, "Font {} missing codepoint {}", name.data(), i);
}
Components::Logger::Error(Game::ERR_FATAL, "Font {} missing codepoint {}", name.data(), i);
}
}
else
{
for (uint16_t i = 32; i < 128; i++)
charset.push_back(i);
}
auto* font = builder->getAllocator()->allocate<Game::Font_s>();
font->fontName = fontName;
font->pixelHeight = size;
font->material = material;
font->glowMaterial = glowMaterial;
font->glyphCount = charset.size();
font->glyphs = builder->getAllocator()->allocateArray<Game::Glyph>(charset.size());
// Generate glyph data
int result = PackFonts(reinterpret_cast<const uint8_t*>(fontFile.getBuffer().data()), charset, font->glyphs, static_cast<float>(size), pixels, w, h, yOffset);
if (result == -1)
{
Components::Logger::Error(Game::ERR_FATAL, "Truetype font {} is broken", name);
}
else if (result < 0)
{
Components::Logger::Error(Game::ERR_FATAL, "Texture size of font {} is not enough", name);
}
else if(h - result > size)
{
Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Texture of font {} have too much left over space: {}\n", name, h - result);
}
header->font = font;
// Save generated materials
Game::XAssetHeader tmpHeader;
tmpHeader.image = image;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_IMAGE, tmpHeader);
tmpHeader.material = material;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
tmpHeader.material = glowMaterial;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
// Save generated image
Utils::IO::CreateDir("userraw\\images");
int fileSize = w * h * 4;
int iwiHeaderSize = static_cast<int>(sizeof(Game::GfxImageFileHeader));
Game::GfxImageFileHeader iwiHeader =
{
{ 'I', 'W', 'i' },
/* version */
8,
/* flags */
2,
/* format */
Game::IMG_FORMAT_BITMAP_RGBA,
0,
/* dimensions(x, y, z) */
{ static_cast<short>(w), static_cast<short>(h), 1 },
/* fileSizeForPicmip (mipSize in bytes + sizeof(GfxImageFileHeader)) */
{ fileSize + iwiHeaderSize, fileSize, fileSize, fileSize }
};
std::string outIwi;
outIwi.resize(fileSize + sizeof(Game::GfxImageFileHeader));
std::memcpy(outIwi.data(), &iwiHeader, sizeof(Game::GfxImageFileHeader));
// Generate RGBA data
auto* rgbaPixels = outIwi.data() + sizeof(Game::GfxImageFileHeader);
for (int i = 0; i < w * h * 4; i += 4)
{
rgbaPixels[i + 0] = static_cast<char>(255);
rgbaPixels[i + 1] = static_cast<char>(255);
rgbaPixels[i + 2] = static_cast<char>(255);
rgbaPixels[i + 3] = static_cast<char>(pixels[i / 4]);
}
Utils::IO::WriteFile(Utils::String::VA("userraw\\images\\%s.iwi", texName), outIwi);
}
else
{
for (std::uint16_t i = 32; i < 128; i++)
{
charset.push_back(i);
}
}
auto* font = builder->getAllocator()->allocate<Game::Font_s>();
font->fontName = fontName;
font->pixelHeight = size;
font->material = material;
font->glowMaterial = glowMaterial;
font->glyphCount = static_cast<int>(charset.size());
font->glyphs = builder->getAllocator()->allocateArray<Game::Glyph>(charset.size());
// Generate glyph data
int result = PackFonts(reinterpret_cast<const uint8_t*>(fontFile.getBuffer().data()), charset, font->glyphs, static_cast<float>(size), pixels, w, h, yOffset);
if (result == -1)
{
Components::Logger::Error(Game::ERR_FATAL, "Truetype font {} is broken", name);
}
else if (result < 0)
{
Components::Logger::Error(Game::ERR_FATAL, "Texture size of font {} is not enough", name);
}
else if(h - result > size)
{
Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Texture of font {} have too much left over space: {}\n", name, h - result);
}
header->font = font;
// Save generated materials
Game::XAssetHeader tmpHeader;
tmpHeader.image = image;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_IMAGE, tmpHeader);
tmpHeader.material = material;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
tmpHeader.material = glowMaterial;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
// Save generated image
Utils::IO::CreateDir("userraw\\images");
int fileSize = w * h * 4;
int iwiHeaderSize = static_cast<int>(sizeof(Game::GfxImageFileHeader));
Game::GfxImageFileHeader iwiHeader =
{
{ 'I', 'W', 'i' },
/* version */
8,
/* flags */
2,
/* format */
Game::IMG_FORMAT_BITMAP_RGBA,
0,
/* dimensions(x, y, z) */
{ static_cast<short>(w), static_cast<short>(h), 1 },
/* fileSizeForPicmip (mipSize in bytes + sizeof(GfxImageFileHeader)) */
{ fileSize + iwiHeaderSize, fileSize, fileSize, fileSize }
};
std::string outIwi;
outIwi.resize(fileSize + sizeof(Game::GfxImageFileHeader));
std::memcpy(outIwi.data(), &iwiHeader, sizeof(Game::GfxImageFileHeader));
// Generate RGBA data
auto* rgbaPixels = outIwi.data() + sizeof(Game::GfxImageFileHeader);
for (auto i = 0; i < w * h * 4; i += 4)
{
rgbaPixels[i + 0] = static_cast<char>(255);
rgbaPixels[i + 1] = static_cast<char>(255);
rgbaPixels[i + 2] = static_cast<char>(255);
rgbaPixels[i + 3] = static_cast<char>(pixels[i / 4]);
}
Utils::IO::WriteFile(Utils::String::VA("userraw\\images\\%s.iwi", texName), outIwi);
}
void IFont_s::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)

View File

@ -30,7 +30,8 @@ namespace Assets
"_add_lin_nofog",
};
std::map<std::string, std::string> techSetCorrespondance = {
static std::unordered_map<std::string, std::string> techSetCorrespondance =
{
{"effect", "effect_blend"},
{"effect", "effect_blend"},
{"effect_nofog", "effect_blend_nofog"},
@ -50,12 +51,6 @@ namespace Assets
{"mc_unlit_nofog", "mc_unlit_blend_nofog_ua"},
{"mc_unlit", "mc_unlit_replace_lin_nocast"},
{"mc_unlit_alphatest", "mc_unlit_blend_lin"}
/*,
{"", ""},
{"", ""},
{"", ""},
{"", ""},
{"", ""},*/
};
Components::FileSystem::File materialFile(Utils::String::VA("materials/%s.iw4xMaterial", name.data()));
@ -64,7 +59,7 @@ namespace Assets
Utils::Stream::Reader reader(builder->getAllocator(), materialFile.getBuffer());
char* magic = reader.readArray<char>(7);
if (std::memcmp(magic, "IW4xMat", 7))
if (std::memcmp(magic, "IW4xMat", 7) != 0)
{
Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, header is invalid!", name);
}
@ -76,7 +71,7 @@ namespace Assets
Components::Logger::Error(Game::ERR_FATAL, "Reading material '{}' failed, expected version is {}, but it was {}!", name, IW4X_MAT_VERSION, version);
}
Game::Material* asset = reader.readObject<Game::Material>();
auto* asset = reader.readObject<Game::Material>();
if (asset->info.name)
{
@ -408,13 +403,13 @@ namespace Assets
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->textureTable);
Game::MaterialTextureDef* destTextureTable = buffer->dest<Game::MaterialTextureDef>();
auto* destTextureTable = buffer->dest<Game::MaterialTextureDef>();
buffer->saveArray(asset->textureTable, asset->textureCount);
for (char i = 0; i < asset->textureCount; ++i)
for (std::uint8_t i = 0; i < asset->textureCount; ++i)
{
Game::MaterialTextureDef* destTextureDef = &destTextureTable[i];
Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
auto* destTextureDef = &destTextureTable[i];
auto* textureDef = &asset->textureTable[i];
if (textureDef->semantic == SEMANTIC_WATER_MAP)
{

View File

@ -12,16 +12,26 @@ namespace Assets
return;
}
Game::snd_alias_list_t* aliasList = builder->getAllocator()->allocate<Game::snd_alias_list_t>();
auto* aliasList = builder->getAllocator()->allocate<Game::snd_alias_list_t>();
if (!aliasList)
{
Components::Logger::Print("Error allocating memory for sound alias structure!\n");
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Failed to allocate memory for sound alias structure!\n");
return;
}
nlohmann::json infoData = nlohmann::json::parse(aliasFile.getBuffer());
nlohmann::json aliasesContainer = infoData["head"];
nlohmann::json infoData;
try
{
infoData = nlohmann::json::parse(aliasFile.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
nlohmann::json aliasesContainer = infoData["head"];
nlohmann::json::array_t aliases = aliasesContainer;
aliasList->count = aliases.size();
@ -34,7 +44,7 @@ namespace Assets
return;
}
aliasList->aliasName = builder->getAllocator()->duplicateString(name.c_str());
aliasList->aliasName = builder->getAllocator()->duplicateString(name);
for (size_t i = 0; i < aliasList->count; i++)
{
@ -288,19 +298,14 @@ namespace Assets
if (volumeFalloffCurve.is_string())
{
std::string fallOffCurve = volumeFalloffCurve.get<std::string>();
auto fallOffCurve = volumeFalloffCurve.get<std::string>();
if (fallOffCurve.size() == 0)
if (fallOffCurve.empty())
{
fallOffCurve = "$default";
}
auto curve = Components::AssetHandler::FindAssetForZone(
Game::XAssetType::ASSET_TYPE_SOUND_CURVE,
fallOffCurve.c_str(),
builder
).sndCurve;
auto curve = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, fallOffCurve, builder).sndCurve;
alias->volumeFalloffCurve = curve;
}
@ -376,9 +381,9 @@ namespace Assets
{
AssertSize(Game::snd_alias_list_t, 12);
Utils::Stream* buffer = builder->getBuffer();
Game::snd_alias_list_t* asset = header.sound;
Game::snd_alias_list_t* dest = buffer->dest<Game::snd_alias_list_t>();
auto* buffer = builder->getBuffer();
auto* asset = header.sound;
auto* dest = buffer->dest<Game::snd_alias_list_t>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
@ -402,7 +407,7 @@ namespace Assets
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->head);
Game::snd_alias_t* destHead = buffer->dest<Game::snd_alias_t>();
auto* destHead = buffer->dest<Game::snd_alias_t>();
buffer->saveArray(asset->head, asset->count);
for (unsigned int i = 0; i < asset->count; ++i)
@ -453,7 +458,7 @@ namespace Assets
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(alias->soundFile);
Game::SoundFile* destSoundFile = buffer->dest<Game::SoundFile>();
auto* destSoundFile = buffer->dest<Game::SoundFile>();
buffer->save(alias->soundFile);
// Save_SoundFileRef
@ -503,7 +508,7 @@ namespace Assets
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(alias->speakerMap);
Game::SpeakerMap* destSoundFile = buffer->dest<Game::SpeakerMap>();
auto* destSoundFile = buffer->dest<Game::SpeakerMap>();
buffer->save(alias->speakerMap);
if (alias->speakerMap->name)

View File

@ -130,12 +130,14 @@ namespace Components
return;
}
std::string error;
const auto banData = nlohmann::json::parse(bans.getBuffer());
if (!banData.is_object())
nlohmann::json banData;
try
{
Logger::Debug("bans.json contains invalid data");
banData = nlohmann::json::parse(bans.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
@ -144,7 +146,7 @@ namespace Components
if (idList.is_array())
{
nlohmann::json::array_t arr = idList;
const nlohmann::json::array_t arr = idList;
for (auto &idEntry : arr)
{
@ -161,7 +163,7 @@ namespace Components
if (ipList.is_array())
{
nlohmann::json::array_t arr = ipList;
const nlohmann::json::array_t arr = ipList;
for (auto &ipEntry : arr)
{

View File

@ -32,15 +32,15 @@ namespace Components
if (needPassword)
{
std::string pass = Dvar::Var("password").get<std::string>();
if (pass.empty())
const auto password = Dvar::Var("password").get<std::string>();
if (password.empty())
{
// shouldn't ever happen but this is safe
Party::ConnectError("A password is required to connect to this server!");
return;
}
Download::CLDownload.hashedPassword = Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(pass), "");
Download::CLDownload.hashedPassword = Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(password), "");
}
Download::CLDownload.running = true;
@ -61,37 +61,50 @@ namespace Components
if (!download) return false;
download->files.clear();
std::string error;
nlohmann::json listData = nlohmann::json::parse(list);
if (!error.empty() || !listData.is_array())
nlohmann::json listData;
try
{
listData = nlohmann::json::parse(list);
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return false;
}
if (!listData.is_array())
{
Logger::Print("Error: {}\n", error);
return false;
}
download->totalBytes = 0;
nlohmann::json::array_t listDataArray = listData;
const nlohmann::json::array_t listDataArray = listData;
for (auto& file : listDataArray)
{
if (!file.is_object()) return false;
auto hash = file["hash"];
auto name = file["name"];
auto size = file["size"];
if (!hash.is_string() || !name.is_string() || !size.is_number()) return false;
Download::ClientDownload::File fileEntry;
fileEntry.name = name.get<std::string>();
fileEntry.hash = hash.get<std::string>();
fileEntry.size = size.get<size_t>();
if (!fileEntry.name.empty())
try
{
download->files.push_back(fileEntry);
download->totalBytes += fileEntry.size;
const auto hash = file.at("hash").get<std::string>();
const auto name = file.at("name").get<std::string>();
const auto size = file.at("size").get<std::size_t>();
Download::ClientDownload::File fileEntry;
fileEntry.name = name;
fileEntry.hash = hash;
fileEntry.size = size;
if (!fileEntry.name.empty())
{
download->files.push_back(fileEntry);
download->totalBytes += fileEntry.size;
}
}
catch (const nlohmann::json::exception& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Error: {}\n", ex.what());
return false;
}
}

View File

@ -327,7 +327,17 @@ namespace Components
const auto parseData = Utils::IO::ReadFile(FavouriteFile);
if (!parseData.empty())
{
const nlohmann::json object = nlohmann::json::parse(parseData);
nlohmann::json object;
try
{
object = nlohmann::json::parse(parseData);
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
if (!object.is_array())
{
Logger::Print("Favourites storage file is invalid!\n");
@ -363,7 +373,16 @@ namespace Components
const auto parseData = Utils::IO::ReadFile(FavouriteFile);
if (!parseData.empty())
{
const nlohmann::json object = nlohmann::json::parse(parseData);
nlohmann::json object;
try
{
object = nlohmann::json::parse(parseData);
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
if (!object.is_array())
{
@ -409,7 +428,17 @@ namespace Components
return;
}
const nlohmann::json object = nlohmann::json::parse(parseData);
nlohmann::json object;
try
{
object = nlohmann::json::parse(parseData);
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
if (!object.is_array())
{
Logger::Print("Favourites storage file is invalid!\n");

View File

@ -4,7 +4,7 @@ namespace Components
{
Utils::Memory::Allocator StructuredData::MemAllocator;
const char* StructuredData::EnumTranslation[ENUM_MAX] =
const char* StructuredData::EnumTranslation[COUNT] =
{
"features",
"weapons",
@ -23,7 +23,7 @@ namespace Components
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
{
if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return;
if (!data || type >= StructuredData::PlayerDataType::COUNT) return;
Game::StructuredDataEnum* dataEnum = &data->enums[type];
@ -192,8 +192,8 @@ namespace Components
return;
}
std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
std::map<int, std::unordered_map<std::string, std::string>> otherPatchDefinitions;
std::unordered_map<int, std::vector<std::vector<std::string>>> patchDefinitions;
std::unordered_map<int, std::unordered_map<std::string, std::string>> otherPatchDefinitions;
// First check if all versions are present
for (int i = 156;; ++i)
@ -205,12 +205,14 @@ namespace Components
std::vector<std::vector<std::string>> enumContainer;
std::unordered_map<std::string, std::string> otherPatches;
std::string errors;
nlohmann::json defData = nlohmann::json::parse(definition.getBuffer());
if (!errors.empty())
nlohmann::json defData;
try
{
Logger::Error(Game::ERR_FATAL, "Parsing patch file '{}' for PlayerDataDef version {} failed: {}", definition.getName(), i, errors);
defData = nlohmann::json::parse(definition.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
return;
}
@ -220,7 +222,7 @@ namespace Components
return;
}
for (std::size_t pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
{
auto enumData = defData[StructuredData::EnumTranslation[pType]];
@ -228,7 +230,7 @@ namespace Components
if (enumData.is_array())
{
for (auto rawEntry : enumData)
for (const auto& rawEntry : enumData)
{
if (rawEntry.is_string())
{
@ -261,7 +263,7 @@ namespace Components
if (patchDefinitions.empty()) return;
// Reallocate the definition
Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
auto* 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
@ -271,7 +273,7 @@ namespace Components
newData[i].version = (patchDefinitions.size() - i) + 155;
// Reallocate the enum array
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->defs->enumCount);
auto* 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;
}
@ -292,14 +294,14 @@ namespace Components
auto otherData = otherPatchDefinitions[newData[i].version];
// Invalid patch data
if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX)
if (patchData.size() != StructuredData::PlayerDataType::COUNT)
{
Logger::Error(Game::ERR_FATAL, "PlayerDataDef patch for version {} wasn't parsed correctly!", newData[i].version);
continue;
}
// Apply the patch data
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
{
if (!patchData[pType].empty())
{

View File

@ -7,20 +7,21 @@ namespace Components
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
FEATURES,
WEAPONS,
ATTACHEMENTS,
CHALLENGES,
CAMOS,
PERKS,
KILLSTREAKS,
ACCOLADES,
CARDICONS,
CARDTITLES,
CARDNAMEPLATES,
TEAMS,
GAMETYPES,
COUNT
};
StructuredData();
@ -34,6 +35,6 @@ namespace Components
static void PatchCustomClassLimit(Game::StructuredDataDef* data, int count);
static Utils::Memory::Allocator MemAllocator;
static const char* EnumTranslation[ENUM_MAX];
static const char* EnumTranslation[COUNT];
};
}

View File

@ -6,7 +6,7 @@ namespace Components
unsigned int Theatre::CurrentSelection;
std::vector<Theatre::DemoInfo> Theatre::Demos;
char Theatre::BaselineSnapshot[131072] = { 0 };
char Theatre::BaselineSnapshot[131072] = {0};
int Theatre::BaselineSnapshotMsgLen;
int Theatre::BaselineSnapshotMsgOff;
@ -18,7 +18,7 @@ namespace Components
void Theatre::RecordGamestateStub()
{
int sequence = (*Game::serverMessageSequence - 1);
const auto sequence = (*Game::serverMessageSequence - 1);
Game::FS_WriteToDemo(&sequence, 4, *Game::demoFile);
}
@ -56,8 +56,8 @@ namespace Components
Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff);
Game::MSG_WriteByte(&buf, 6);
int compressedSize = Game::MSG_WriteBitsCompress(false, reinterpret_cast<char*>(buf.data), cmpData, buf.cursize);
int fileCompressedSize = compressedSize + 4;
const auto compressedSize = Game::MSG_WriteBitsCompress(false, reinterpret_cast<char*>(buf.data), cmpData, buf.cursize);
const auto fileCompressedSize = compressedSize + 4;
int byte8 = 8;
char byte0 = 0;
@ -67,9 +67,9 @@ namespace Components
Game::FS_WriteToDemo(&fileCompressedSize, 4, *Game::demoFile);
Game::FS_WriteToDemo(&byte8, 4, *Game::demoFile);
for (int i = 0; i < compressedSize; i += 1024)
for (auto i = 0; i < compressedSize; i += 1024)
{
int size = std::min(compressedSize - i, 1024);
const auto size = std::min(compressedSize - i, 1024);
if (i + size >= sizeof(cmpData))
{
@ -186,7 +186,7 @@ namespace Components
Theatre::CurrentSelection = 0;
Theatre::Demos.clear();
auto demos = FileSystem::GetFileList("demos/", "dm_13");
const auto demos = FileSystem::GetFileList("demos/", "dm_13");
for (auto demo : demos)
{
@ -194,27 +194,32 @@ namespace Components
if (meta.exists())
{
std::string error;
nlohmann::json metaObject = nlohmann::json::parse(meta.getBuffer());
if (metaObject.is_object())
nlohmann::json metaObject;
try
{
Theatre::DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
demoInfo.author = metaObject["author"].get<std::string>();
demoInfo.gametype = metaObject["gametype"].get<std::string>();
demoInfo.mapname = metaObject["mapname"].get<std::string>();
demoInfo.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>();
demoInfo.timeStamp = _atoi64(timestamp.data());
Theatre::Demos.push_back(demoInfo);
metaObject = nlohmann::json::parse(meta.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
continue;
}
Theatre::DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
demoInfo.author = metaObject["author"].get<std::string>();
demoInfo.gametype = metaObject["gametype"].get<std::string>();
demoInfo.mapname = metaObject["mapname"].get<std::string>();
demoInfo.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>();
demoInfo.timeStamp = _atoi64(timestamp.data());
Theatre::Demos.push_back(demoInfo);
}
}
// Reverse, latest demo first!
std::reverse(Theatre::Demos.begin(), Theatre::Demos.end());
std::ranges::reverse(Theatre::Demos);
}
void Theatre::DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)

View File

@ -226,7 +226,7 @@ namespace Components
Game::XAssetHeader assetHeader = AssetHandler::FindAssetForZone(type, name, this, isSubAsset);
if (!assetHeader.data)
{
{
Logger::Error(Game::ERR_FATAL, "Missing asset '{}' of type '{}'\n", name, Game::DB_GetXAssetTypeName(type));
return false;
}