Better font replacement system

This commit is contained in:
fed 2023-03-03 10:14:50 +01:00
parent 74db7b53c6
commit 209184007c
17 changed files with 94 additions and 166 deletions

View File

@ -0,0 +1 @@
ttf,fonts/defaultBold.otf
1 ttf fonts/defaultBold.otf

View File

@ -1,4 +1,5 @@
ara_h2_mod_common
ara_h2_mod_font_default_bold
deu_h2_mod_common
eng_h2_mod_common
eng_h2_mod_patch_af_caves
@ -7,6 +8,9 @@ ens_h2_mod_patch_af_caves
cze_h2_mod_common
fra_h2_mod_common
h2_mod_common
h2_mod_font_default
h2_mod_font_default_bold
h2_mod_font_bank
h2_mod_patch_af_caves
h2_mod_patch_dc_whitehouse
h2_mod_patch_ending

View File

@ -0,0 +1 @@
ttf,fonts/default.otf
1 ttf fonts/default.otf

View File

@ -0,0 +1 @@
ttf,fonts/defaultBold.otf
1 ttf fonts/defaultBold.otf

View File

@ -0,0 +1 @@
ttf,fonts/mix.ttf
1 ttf fonts/mix.ttf

View File

@ -1,6 +1,2 @@
stringtable,font_replacements.csv
ttf,fonts/ibmplexsansarabic-semibold_custom.ttf
ttf,fonts/mix.ttf
ttf,fonts/mix_gothic.ttf
ttf,fonts/mix_open.ttf
stringtable,font_zones.csv
localize,branding

1 stringtable font_replacements.csv font_zones.csv
ttf fonts/ibmplexsansarabic-semibold_custom.ttf
ttf fonts/mix.ttf
ttf fonts/mix_gothic.ttf
ttf fonts/mix_open.ttf
2 localize branding branding

BIN
data/zonetool/fonts/mix.ttf Normal file

Binary file not shown.

View File

@ -1,25 +0,0 @@
arabic,fonts/bank.ttf,fonts/mix_gothic.ttf,
arabic,fonts/default.otf,fonts/mix.ttf,
arabic,fonts/defaultBold.otf,fonts/ibmplexsansarabic-semibold_custom.ttf,
czech,fonts/bank.ttf,fonts/mix_gothic.ttf,
czech,fonts/default.otf,fonts/mix.ttf,
czech,fonts/defaultBold.otf,fonts/mix_open.ttf,
japanese_full,fonts/default.otf,fonts/mix.ttf,
japanese_full,fonts/defaultBold.otf,fonts/mix_open.ttf,
japanese_partial,fonts/default.otf,fonts/mix.ttf,
japanese_partial,fonts/defaultBold.otf,fonts/mix_open.ttf,
korean,fonts/default.otf,fonts/mix.ttf,
korean,fonts/defaultBold.otf,fonts/mix_open.ttf,
polish,fonts/bank.ttf,fonts/mix_gothic.ttf,
polish,fonts/default.otf,fonts/mix.ttf,
polish,fonts/defaultBold.otf,fonts/mix_open.ttf,
russian,fonts/bank.ttf,fonts/mix_gothic.ttf,
russian,fonts/default.otf,fonts/mix.ttf,
russian,fonts/defaultBold.otf,fonts/mix_open.ttf,
russian_partial,fonts/bank.ttf,fonts/mix_gothic.ttf,
russian_partial,fonts/default.otf,fonts/mix.ttf,
russian_partial,fonts/defaultBold.otf,fonts/mix_open.ttf,
simplified_chinese,fonts/default.otf,fonts/mix.ttf,
simplified_chinese,fonts/defaultBold.otf,fonts/mix_open.ttf,
traditional_chinese,fonts/default.otf,fonts/mix.ttf,
traditional_chinese,fonts/defaultBold.otf,fonts/mix_open.ttf,
1 arabic fonts/bank.ttf fonts/mix_gothic.ttf
2 arabic fonts/default.otf fonts/mix.ttf
3 arabic fonts/defaultBold.otf fonts/ibmplexsansarabic-semibold_custom.ttf
4 czech fonts/bank.ttf fonts/mix_gothic.ttf
5 czech fonts/default.otf fonts/mix.ttf
6 czech fonts/defaultBold.otf fonts/mix_open.ttf
7 japanese_full fonts/default.otf fonts/mix.ttf
8 japanese_full fonts/defaultBold.otf fonts/mix_open.ttf
9 japanese_partial fonts/default.otf fonts/mix.ttf
10 japanese_partial fonts/defaultBold.otf fonts/mix_open.ttf
11 korean fonts/default.otf fonts/mix.ttf
12 korean fonts/defaultBold.otf fonts/mix_open.ttf
13 polish fonts/bank.ttf fonts/mix_gothic.ttf
14 polish fonts/default.otf fonts/mix.ttf
15 polish fonts/defaultBold.otf fonts/mix_open.ttf
16 russian fonts/bank.ttf fonts/mix_gothic.ttf
17 russian fonts/default.otf fonts/mix.ttf
18 russian fonts/defaultBold.otf fonts/mix_open.ttf
19 russian_partial fonts/bank.ttf fonts/mix_gothic.ttf
20 russian_partial fonts/default.otf fonts/mix.ttf
21 russian_partial fonts/defaultBold.otf fonts/mix_open.ttf
22 simplified_chinese fonts/default.otf fonts/mix.ttf
23 simplified_chinese fonts/defaultBold.otf fonts/mix_open.ttf
24 traditional_chinese fonts/default.otf fonts/mix.ttf
25 traditional_chinese fonts/defaultBold.otf fonts/mix_open.ttf

View File

@ -0,0 +1,11 @@
*,h2_mod_font_mix
arabic,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
czech,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
japanese_full,h2_mod_font_default,h2_mod_font_default_bold
japanese_partial,h2_mod_font_default,h2_mod_font_default_bold
korean,h2_mod_font_default,h2_mod_font_default_bold
polish,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
russian,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
russian_partial,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
simplified_chinese,h2_mod_font_default,h2_mod_font_default_bold
traditional_chinese,h2_mod_font_default,h2_mod_font_default_bold
1 *,h2_mod_font_mix
2 arabic,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
3 czech,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
4 japanese_full,h2_mod_font_default,h2_mod_font_default_bold
5 japanese_partial,h2_mod_font_default,h2_mod_font_default_bold
6 korean,h2_mod_font_default,h2_mod_font_default_bold
7 polish,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
8 russian,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
9 russian_partial,h2_mod_font_bank,h2_mod_font_default,h2_mod_font_default_bold
10 simplified_chinese,h2_mod_font_default,h2_mod_font_default_bold
11 traditional_chinese,h2_mod_font_default,h2_mod_font_default_bold

View File

@ -6,6 +6,7 @@
#include "command.hpp"
#include "console.hpp"
#include "mods.hpp"
#include "fonts.hpp"
#include <utils/hook.hpp>
#include <utils/concurrency.hpp>
@ -104,27 +105,6 @@ namespace fastfiles
a.jmp(0x140415E29);
}
bool try_load_zone(const std::string& name, bool localized, bool game = false)
{
if (localized)
{
const auto language = game::SEH_GetCurrentLanguageCode();
try_load_zone(language + "_"s + name, false);
}
if (!fastfiles::exists(name))
{
return false;
}
game::XZoneInfo info{};
info.name = name.data();
info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM;
info.freeFlags = 0;
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC);
return true;
}
bool try_add_zone(std::vector<game::XZoneInfo>& zones,
utils::memory::allocator& allocator, const std::string& name,
bool localized, bool game = false)
@ -148,19 +128,6 @@ namespace fastfiles
return true;
}
void load_mod_zones()
{
try_load_zone("mod", true);
const auto mod_zones = mods::get_mod_zones();
for (const auto& zone : mod_zones)
{
if (zone.alloc_flags & game::DB_ZONE_COMMON)
{
try_load_zone(zone.name, true);
}
}
}
void add_mod_zones(std::vector<game::XZoneInfo>& zones, utils::memory::allocator& allocator)
{
try_add_zone(zones, allocator, "mod", true);
@ -194,6 +161,7 @@ namespace fastfiles
push_zones(zones, zone_info, zone_count);
game::DB_LoadXAssets(zones.data(), static_cast<int>(zones.size()), sync_mode);
fonts::load_font_zones();
}
void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zone_info,
@ -632,6 +600,27 @@ namespace fastfiles
});
}
bool try_load_zone(const std::string& name, bool localized, bool game)
{
if (localized)
{
const auto language = game::SEH_GetCurrentLanguageCode();
try_load_zone(language + "_"s + name, false);
}
if (!fastfiles::exists(name))
{
return false;
}
game::XZoneInfo info{};
info.name = name.data();
info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM;
info.freeFlags = 0;
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC);
return true;
}
class component final : public component_interface
{
public:
@ -691,7 +680,7 @@ namespace fastfiles
}
const auto name = params.get(1);
if (!try_load_zone(name, false))
if (!fastfiles::try_load_zone(name, false))
{
console::warn("loadzone: zone \"%s\" could not be found!\n", name);
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "game/game.hpp"
#include <utils/memory.hpp>
namespace fastfiles
{
@ -8,4 +9,5 @@ namespace fastfiles
std::string get_current_fastfile();
bool exists(const std::string& zone);
bool try_load_zone(const std::string& name, bool localized, bool game = false);
}

View File

@ -7,6 +7,7 @@
#include "command.hpp"
#include "language.hpp"
#include "config.hpp"
#include "fastfiles.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
@ -49,89 +50,6 @@ namespace fonts
utils::memory::allocator font_allocator;
game::StringTable* get_font_replacements_table()
{
if (!game::DB_XAssetExists(game::ASSET_TYPE_STRINGTABLE, "font_replacements.csv"))
{
return nullptr;
}
return game::DB_FindXAssetHeader(game::ASSET_TYPE_STRINGTABLE, "font_replacements.csv", false).stringTable;
}
struct font_replacement
{
const char* target_font;
const char* new_font;
};
std::vector<font_replacement>& get_font_replacements()
{
static std::vector<font_replacement> replacements = {};
return replacements;
}
void load_font_replacements()
{
static auto loaded = false;
if (loaded)
{
return;
}
loaded = true;
auto& replacements = get_font_replacements();
const auto disabled = config::get<bool>("disable_custom_fonts");
if (disabled.has_value() && disabled.value() && language::current() != game::LANGUAGE_CZECH)
{
return;
}
const auto table = get_font_replacements_table();
if (table == nullptr)
{
return;
}
const auto current_language = language::current();
for (auto row = 0; row < table->rowCount; row++)
{
if (table->columnCount < 3)
{
continue;
}
const auto row_values = &table->values[(row * table->columnCount)];
const auto lang = row_values[0].string;
if (std::strcmp(lang, game::languages[current_language].name))
{
continue;
}
const auto font = utils::memory::get_allocator()->duplicate_string(row_values[1].string);
const auto replacement = utils::memory::get_allocator()->duplicate_string(row_values[2].string);
replacements.emplace_back(font, replacement);
}
return;
}
const char* get_font_replacement(const char* name)
{
const auto& replacements = get_font_replacements();
for (const auto& replacement : replacements)
{
if (!std::strcmp(name, replacement.target_font))
{
return replacement.new_font;
}
}
return name;
}
utils::concurrency::container<font_data_t> font_data;
game::TTF* create_font(const std::string& name, const std::string& data)
@ -203,20 +121,6 @@ namespace fonts
return result;
}
utils::hook::detour r_register_font_hook;
void* r_register_font_stub(const char* name, int size)
{
const auto name_ = get_font_replacement(name);
return r_register_font_hook.invoke<void*>(name_, size);
}
utils::hook::detour cl_init_renderer_hook;
void* cl_init_renderer_stub()
{
load_font_replacements();
return cl_init_renderer_hook.invoke<void*>();
}
game::Font_s* bank_font = nullptr;
utils::hook::detour ui_get_font_handle_hook;
@ -359,14 +263,53 @@ namespace fonts
});
}
void load_font_zones()
{
const auto disabled = config::get<bool>("disable_custom_fonts");
if (disabled.has_value() && disabled.value() && language::current() != game::LANGUAGE_CZECH)
{
return;
}
const auto table = game::DB_FindXAssetHeader(game::ASSET_TYPE_STRINGTABLE, "font_zones.csv", 0).stringTable;
if (table == nullptr)
{
return;
}
const auto lang = language::current();
const auto lang_name = game::languages[lang].name;
for (auto row = 0; row < table->rowCount; row++)
{
if (table->columnCount < 3)
{
continue;
}
const auto row_values = &table->values[(row * table->columnCount)];
const auto lang_value = row_values[0].string;
if (std::strcmp(lang_value, lang_name) && lang_value != "*"s)
{
continue;
}
for (auto col = 1; col < table->columnCount; col++)
{
const auto zone = row_values[col].string;
if (zone != nullptr)
{
fastfiles::try_load_zone(zone, true);
}
}
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
utils::hook::call(0x140747096, db_find_xasset_header_stub);
r_register_font_hook.create(0x140746FE0, r_register_font_stub);
cl_init_renderer_hook.create(0x1403D5AA0, cl_init_renderer_stub);
// add custom fonts to hud elem fonts
ui_asset_cache_hook.create(0x140606090, ui_asset_cache_stub);

View File

@ -1,7 +1,11 @@
#pragma once
#include "game/game.hpp"
#include <utils/memory.hpp>
namespace fonts
{
void add(const std::string& name, const std::string& data);
void clear();
void load_font_zones();
}