Paths: the last few written as text go through UTF-8, so a non-ASCII name no longer throws

path::string() uses the ANSI code page and throws on a character it lacks (a Cyrillic folder on
an English Windows). The remaining places it was used now go through path_utf8:

- Mods: a deck folder or a mod folder named outside the code page no longer leaves the Board Break
  decks empty, or the Mods folder ignored altogether.
- Game and mod archives: a file under Win32 with such a name is passed over instead of stopping
  the read.
- pose-dump no longer ends the multiplayer session when the game folder is not ASCII.
- The item browser's status line and a Board Break warning no longer fail on such a path.
- Launcher: system fonts are named to ImGui in UTF-8, which it reads.
This commit is contained in:
AyeZeeBB committed 2026-10-16 18:12:34 -05:00
1 parent 571d57f603
commit 320086381c
6 files changed
+17 -11

No files matched your search

+4 -3
View File
@@ -74,12 +74,13 @@ GameArchives::GameArchives(fs::path root, const native_db::Node& layout) : root_
const auto win32 = root_ / "Win32";
for (fs::recursive_directory_iterator it(win32, error), end; it != end && !error; it.increment(error)) {
if (!it->is_regular_file(error) || error) { error.clear(); continue; }
if (lower(it->path().extension().string()) != ".cas") continue;
const auto index = archive_index(it->path().stem().string());
if (lower(path_utf8(it->path().extension())) != ".cas") continue;
const auto index = archive_index(path_utf8(it->path().stem()));
if (!index) continue;
// Relative to Win32, because read() adds that itself.
const auto directory = fs::relative(it->path().parent_path(), win32, error).generic_string();
const auto relative = fs::relative(it->path().parent_path(), win32, error).generic_u8string();
if (error) { error.clear(); continue; }
const std::string directory(relative.begin(), relative.end());
directories_[directory].insert(*index);
}
for (const auto& [directory, archives] : directories_) byArchives[archives].push_back(directory);
+4 -3
View File
@@ -1,4 +1,5 @@
#include "mod_catalog.h"
#include "Engine/Core/Platform/path_text.h"
#include "builtin_packs.h"
#include "mod_merge.h"
@@ -128,7 +129,7 @@ std::vector<std::pair<std::string, fs::path>> decks_inside(const fs::path& mod)
std::error_code error;
for (fs::directory_iterator at(mod / L"decks", error), end; !error && at != end; at.increment(error)) {
if (!at->is_directory(error) || !fs::is_regular_file(at->path() / L"layout.toc", error)) continue;
auto name = lower(at->path().filename().string());
auto name = lower(path_utf8(at->path().filename()));
if (deck_name(name)) found.emplace_back(std::move(name), at->path());
}
std::sort(found.begin(), found.end(), [](const auto& a, const auto& b) { return deck_before(a.first, b.first); });
@@ -144,7 +145,7 @@ std::vector<std::pair<std::string, fs::path>> installed_decks() {
auto inside = decks_inside(at->path());
for (auto& one : inside) decks.emplace_back(std::move(one.first), at->path());
if (!inside.empty()) continue;
if (auto deck = board_break_deck_of(at->path().filename().string()); !deck.empty()) decks.emplace_back(std::move(deck), at->path());
if (auto deck = board_break_deck_of(path_utf8(at->path().filename())); !deck.empty()) decks.emplace_back(std::move(deck), at->path());
}
std::stable_sort(decks.begin(), decks.end(), [](const auto& a, const auto& b) { return deck_before(a.first, b.first); });
return decks;
@@ -230,7 +231,7 @@ std::filesystem::path board_break_deck_folder(std::string_view deck) noexcept {
const auto inside = decks_inside(at->path());
for (const auto& one : inside)
if (one.first == wanted) return one.second;
if (inside.empty() && board_break_deck_of(at->path().filename().string()) == wanted) return at->path();
if (inside.empty() && board_break_deck_of(path_utf8(at->path().filename())) == wanted) return at->path();
}
} catch (...) {}
return {};
+2 -1
View File
@@ -1,4 +1,5 @@
#include "board_break_audio.h"
#include "Engine/Core/Platform/path_text.h"
#include "Engine/Core/Log/logging.h"
#include <Windows.h>
#include <mmsystem.h>
@@ -137,7 +138,7 @@ void load(Kind kind, const std::vector<std::filesystem::path>& files) noexcept {
Sound sound;
if (read_wave(file, sound)) read.push_back(std::move(sound));
else logging::log(logging::Level::warning, logging::Channel::skater, "Board Break: {} is not a wave file it can play.",
file.filename().string());
path_utf8(file.filename()));
} catch (...) {}
}
std::lock_guard lock(e.mutex);
+2 -1
View File
@@ -1,4 +1,5 @@
#include "item_browser.h"
#include "Engine/Core/Platform/path_text.h"
#include "local_customization_runtime.h"
#include "Engine/Core/Json/json.h"
#include "Engine/Core/Log/logging.h"
@@ -507,7 +508,7 @@ void log_roots(State& s, const md::Context& context) {
void log_status(const State& s) {
logging::log(Level::info, Channel::customization, "Item browser: {} grid(s), search \"{}\", filter {}, {} favorite(s), file {}.",
s.grids.size(), s.search, filter_names[static_cast<std::size_t>(s.filter)], s.favorites.keys.size(),
s.favorites.file.string());
path_utf8(s.favorites.file));
for (const auto& grid : s.grids) {
std::string focus = "-";
if (grid.focused >= 0 && static_cast<std::size_t>(grid.focused) < grid.shown.size())
@@ -1,4 +1,5 @@
#include "session_internal.h"
#include "Engine/Core/Platform/path_text.h"
#include "Extension/Multiplayer/Steam/steam_social.h"
#include "Extension/Multiplayer/Hud/native_indicators.h"
#include "Extension/Multiplayer/Hud/native_player_ui.h"
@@ -435,11 +436,11 @@ std::string start_pose_dump(Session &s, std::string_view argument) {
s.pose_dump.close();
s.pose_dump.clear();
s.pose_dump.open(file, std::ios::binary | std::ios::trunc);
if (!s.pose_dump) return "Could not write " + file.string() + ".";
if (!s.pose_dump) return "Could not write " + path_utf8(file) + ".";
s.pose_dump.write("RSPD1\n", 6);
s.pose_dump_until = now_us() + static_cast<std::uint64_t>(seconds) * 1000000;
s.pose_dump_count = 0;
return "Recording your poses for " + std::to_string(seconds) + " s to " + file.string() + ". Skate as you normally would.";
return "Recording your poses for " + std::to_string(seconds) + " s to " + path_utf8(file) + ". Skate as you normally would.";
}
std::string edit_direct_connections(Session &s, std::string_view argument) {
const auto enabled = parse_switch(argument, s.prefer_direct);
+2 -1
View File
@@ -2,6 +2,7 @@
#include "gui_internal.h"
#include "gui_renderer.h"
#include "Engine/Core/Platform/path_text.h"
#include "Engine/Core/Log/logging.h"
@@ -254,7 +255,7 @@ ImFont* system_font(const wchar_t* file, float size) {
const auto path = fs::path(windows.data()) / L"Fonts" / file;
std::error_code error;
if (!fs::is_regular_file(path, error)) return nullptr;
return ImGui::GetIO().Fonts->AddFontFromFileTTF(path.string().c_str(), S(size));
return ImGui::GetIO().Fonts->AddFontFromFileTTF(path_utf8(path).c_str(), S(size)); // (ImGui reads UTF-8)
}
Fonts load_fonts() {