[Json] Sorround with try/catch (#531)
* [Json] Sorround with try/catch * Minor format fix
This commit is contained in:
parent
bff0d22e81
commit
c7ae27a664
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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];
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user