Merge branch 'feat/logger'
Sistema de log unificat (Log:: wrapper sobre SDL_Log) substituint els 176 std::cout/std::cerr dispersos per source/. API basada en std::format, filtre runtime via AEE_LOG (sintaxi *:info,Tag:debug), i marcadors literals via Log::raw(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
866e133aa9
38 files changed
+435
-244
No files matched your search
@@ -104,6 +104,7 @@ set(APP_SOURCES
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/core/resources/palette_loader.cpp
|
||||
source/utils/easing.cpp
|
||||
source/utils/log.cpp
|
||||
source/utils/utils.cpp
|
||||
source/game/debug_config.cpp
|
||||
source/game/options.cpp
|
||||
@@ -218,8 +219,10 @@ target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3)
|
||||
add_executable(pack_resources EXCLUDE_FROM_ALL
|
||||
tools/pack_resources/pack_resources.cpp
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/utils/log.cpp
|
||||
)
|
||||
target_include_directories(pack_resources PRIVATE "${CMAKE_SOURCE_DIR}/source")
|
||||
target_link_libraries(pack_resources PRIVATE SDL3::SDL3)
|
||||
target_compile_options(pack_resources PRIVATE -Wall -Wextra -Wpedantic)
|
||||
|
||||
# --- REGENERACIÓ AUTOMÀTICA DE build/resources.pack ---
|
||||
@@ -365,6 +368,7 @@ if(BUILD_TESTS)
|
||||
source/core/resources/resource_helper.cpp
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/game/map/map.cpp
|
||||
source/utils/log.cpp
|
||||
${ENTITY_SOURCES_BASE}
|
||||
)
|
||||
target_include_directories(test_entities_smoke PRIVATE
|
||||
@@ -394,6 +398,7 @@ if(BUILD_TESTS)
|
||||
source/core/resources/resource_helper.cpp
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/game/map/map.cpp
|
||||
source/utils/log.cpp
|
||||
${ENTITY_SOURCES_BASE}
|
||||
source/game/entities/concrete/whip_attack.cpp
|
||||
)
|
||||
@@ -418,6 +423,7 @@ if(BUILD_TESTS)
|
||||
source/core/input/key_config.cpp
|
||||
source/core/resources/resource_helper.cpp
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/utils/log.cpp
|
||||
)
|
||||
target_include_directories(test_scene_flow PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/source"
|
||||
@@ -457,6 +463,7 @@ if(BUILD_TESTS)
|
||||
source/core/resources/resource_helper.cpp
|
||||
source/core/resources/resource_pack.cpp
|
||||
source/utils/easing.cpp
|
||||
source/utils/log.cpp
|
||||
)
|
||||
target_include_directories(test_game_fsm PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/source"
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "core/audio/jail_audio.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace AudioEffects {
|
||||
|
||||
@@ -46,11 +46,11 @@ namespace AudioEffects {
|
||||
} else if (spec.format == SDL_AUDIO_U8) {
|
||||
bytes_per_sample = 1;
|
||||
} else {
|
||||
std::cerr << "AudioEffects: format de so no suportat (només U8 o S16)\n";
|
||||
Log::error("AudioEffects", "format de so no suportat (només U8 o S16)");
|
||||
return false;
|
||||
}
|
||||
if (spec.channels < 1 || spec.channels > 2) {
|
||||
std::cerr << "AudioEffects: el so ha de ser mono o estèreo\n";
|
||||
Log::error("AudioEffects", "el so ha de ser mono o estèreo");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "core/audio/sound_effects_config.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -27,7 +27,7 @@ auto SoundEffectsConfig::get() -> SoundEffectsConfig& {
|
||||
void SoundEffectsConfig::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "SoundEffectsConfig: no s'ha pogut obrir " << file_path << " — cap preset d'efecte disponible\n";
|
||||
Log::warn("SoundEffectsConfig", "no s'ha pogut obrir {} — cap preset d'efecte disponible", file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ void SoundEffectsConfig::load(const std::string& file_path) {
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "SoundEffectsConfig: " << echoes_.size() << " preset(s) d'eco i " << reverbs_.size() << " de reverb des de " << file_path << '\n';
|
||||
Log::info("SoundEffectsConfig", "{} preset(s) d'eco i {} de reverb des de {}", echoes_.size(), reverbs_.size(), file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "SoundEffectsConfig: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
Log::error("SoundEffectsConfig", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -167,8 +167,7 @@ void GamepadBindings::load(const std::string& file_path) {
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(CONTENT);
|
||||
if (!yaml.contains("gamepads") || !yaml["gamepads"].is_sequence()) {
|
||||
std::cerr << "GamepadBindings: secció 'gamepads' absent o invàlida a "
|
||||
<< file_path << '\n';
|
||||
Log::error("GamepadBindings", "secció 'gamepads' absent o invàlida a {}", file_path);
|
||||
return;
|
||||
}
|
||||
for (const auto& entry : yaml["gamepads"]) {
|
||||
@@ -188,11 +187,9 @@ void GamepadBindings::load(const std::string& file_path) {
|
||||
}
|
||||
configs_.push_back(std::move(cfg));
|
||||
}
|
||||
std::cout << "GamepadBindings: " << configs_.size() << " mandos carregats de "
|
||||
<< file_path << '\n';
|
||||
Log::info("GamepadBindings", "{} mandos carregats de {}", configs_.size(), file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "GamepadBindings: error parsejant " << file_path << ": "
|
||||
<< e.what() << '\n';
|
||||
Log::error("GamepadBindings", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +212,7 @@ auto GamepadBindings::save() -> bool {
|
||||
|
||||
std::ofstream file(file_path_, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "GamepadBindings: no es pot escriure " << file_path_ << '\n';
|
||||
Log::error("GamepadBindings", "no es pot escriure {}", file_path_);
|
||||
return false;
|
||||
}
|
||||
file << out.str();
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "core/input/gamepad_manager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "core/locale/locale.hpp"
|
||||
#include "core/rendering/notification_presets.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -94,8 +94,7 @@ void GamepadManager::addGamepad(SDL_JoystickID jid, bool notify) {
|
||||
if (!SDL_IsGamepad(jid)) { return; }
|
||||
SDL_Gamepad* pad = SDL_OpenGamepad(jid);
|
||||
if (pad == nullptr) {
|
||||
std::cout << "GamepadManager: SDL_OpenGamepad(" << jid
|
||||
<< ") ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("GamepadManager", "SDL_OpenGamepad({}) ha fallat: {}", jid, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
std::string name = uniqueName(prettyName(SDL_GetGamepadName(pad)));
|
||||
@@ -104,8 +103,7 @@ void GamepadManager::addGamepad(SDL_JoystickID jid, bool notify) {
|
||||
// reconnexió es resoldrà per nom.
|
||||
const char* raw_path = SDL_GetGamepadPath(pad);
|
||||
std::string path = (raw_path != nullptr) ? raw_path : "";
|
||||
std::cout << "GamepadManager: connectat " << name
|
||||
<< (path.empty() ? "" : " [" + path + "]") << '\n';
|
||||
Log::info("GamepadManager", "connectat {}{}", name, path.empty() ? std::string{} : " [" + path + "]");
|
||||
entries_.push_back(Entry{.pad = pad, .instance_id = jid, .pretty_name = name, .path = path});
|
||||
|
||||
// Hot-plug: si alguna assignació pendent encaixa amb aquest mando,
|
||||
@@ -129,7 +127,7 @@ void GamepadManager::removeGamepad(SDL_JoystickID jid) {
|
||||
std::string name = std::move(it->pretty_name);
|
||||
SDL_Gamepad* pad = it->pad;
|
||||
if (pad != nullptr) { SDL_CloseGamepad(pad); }
|
||||
std::cout << "GamepadManager: desconnectat " << name << '\n';
|
||||
Log::info("GamepadManager", "desconnectat {}", name);
|
||||
entries_.erase(it);
|
||||
|
||||
// Qualsevol assignació que apuntava a aquest mando queda amb `pad`
|
||||
@@ -145,8 +143,7 @@ void GamepadManager::removeGamepad(SDL_JoystickID jid) {
|
||||
void GamepadManager::init() {
|
||||
if (initialized_) { return; }
|
||||
if (!SDL_InitSubSystem(SDL_INIT_GAMEPAD)) {
|
||||
std::cout << "GamepadManager: SDL_INIT_GAMEPAD ha fallat: "
|
||||
<< SDL_GetError() << '\n';
|
||||
Log::error("GamepadManager", "SDL_INIT_GAMEPAD ha fallat: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
// `gamecontrollerdb.txt` és opcional. Viu a l'arrel del projecte
|
||||
@@ -161,10 +158,9 @@ void GamepadManager::init() {
|
||||
}
|
||||
const int ADDED = SDL_AddGamepadMappingsFromFile(db_path.c_str());
|
||||
if (ADDED < 0) {
|
||||
std::cout << "GamepadManager: no s'ha pogut carregar " << db_path
|
||||
<< ": " << SDL_GetError() << '\n';
|
||||
Log::warn("GamepadManager", "no s'ha pogut carregar {}: {}", db_path, SDL_GetError());
|
||||
} else {
|
||||
std::cout << "GamepadManager: " << ADDED << " mappings carregats de " << db_path << '\n';
|
||||
Log::info("GamepadManager", "{} mappings carregats de {}", ADDED, db_path);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
@@ -175,7 +171,7 @@ void GamepadManager::init() {
|
||||
}
|
||||
SDL_free(ids);
|
||||
}
|
||||
std::cout << "GamepadManager: " << entries_.size() << " mando(s) detectat(s) a l'inici\n";
|
||||
Log::info("GamepadManager", "{} mando(s) detectat(s) a l'inici", entries_.size());
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
@@ -268,8 +264,7 @@ void GamepadManager::assignToPlayer(int player_id, const std::string& name, cons
|
||||
if (a.pad != nullptr) {
|
||||
for (auto& other : assignments_) {
|
||||
if (&other != &a && other.pad == a.pad) {
|
||||
std::cout << "GamepadManager: mando " << a.name
|
||||
<< " reassignat (last-wins)\n";
|
||||
Log::info("GamepadManager", "mando {} reassignat (last-wins)", a.name);
|
||||
other.pad = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -277,11 +272,9 @@ void GamepadManager::assignToPlayer(int player_id, const std::string& name, cons
|
||||
// Traç de l'assignació persistida (vinculada o pendent) perquè quede
|
||||
// visible a la consola igual que les autoassignacions.
|
||||
if (a.pad != nullptr) {
|
||||
std::cout << "GamepadManager: assignat " << a.name
|
||||
<< " → P" << (player_id + 1) << '\n';
|
||||
Log::info("GamepadManager", "assignat {} → P{}", a.name, player_id + 1);
|
||||
} else {
|
||||
std::cout << "GamepadManager: P" << (player_id + 1) << " pendent ("
|
||||
<< (a.name.empty() ? a.path : a.name) << " no connectat)\n";
|
||||
Log::info("GamepadManager", "P{} pendent ({} no connectat)", player_id + 1, a.name.empty() ? a.path : a.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,8 +300,7 @@ auto GamepadManager::autoAssignFreeSlots() -> std::vector<AutoAssigned> {
|
||||
slot.name = e.pretty_name;
|
||||
slot.path = e.path;
|
||||
assigned.push_back(AutoAssigned{.player_id = pid, .name = e.pretty_name, .path = e.path});
|
||||
std::cout << "GamepadManager: auto-assigned " << e.pretty_name
|
||||
<< " → P" << (pid + 1) << '\n';
|
||||
Log::info("GamepadManager", "auto-assigned {} → P{}", e.pretty_name, pid + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "core/input/key_config.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
auto KeyConfig::get() -> KeyConfig& {
|
||||
static KeyConfig instance_;
|
||||
@@ -15,7 +15,7 @@ auto KeyConfig::get() -> KeyConfig& {
|
||||
void KeyConfig::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "KeyConfig: no s'ha pogut obrir " << file_path << '\n';
|
||||
Log::error("KeyConfig", "no s'ha pogut obrir {}", file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void KeyConfig::load(const std::string& file_path) {
|
||||
const auto* end = begin + bytes.size();
|
||||
auto yaml = fkyaml::node::deserialize(begin, end);
|
||||
if (!yaml.contains("keys") || !yaml["keys"].is_sequence()) {
|
||||
std::cerr << "KeyConfig: falta la secció 'keys' a " << file_path << '\n';
|
||||
Log::error("KeyConfig", "falta la secció 'keys' a {}", file_path);
|
||||
return;
|
||||
}
|
||||
bindings_.clear();
|
||||
@@ -34,14 +34,14 @@ void KeyConfig::load(const std::string& file_path) {
|
||||
const auto CODE = entry["code"].get_value<std::string>();
|
||||
const SDL_Scancode SC = SDL_GetScancodeFromName(CODE.c_str());
|
||||
if (SC == SDL_SCANCODE_UNKNOWN) {
|
||||
std::cerr << "KeyConfig: codi SDL desconegut '" << CODE << "' per id '" << ID << "'\n";
|
||||
Log::warn("KeyConfig", "codi SDL desconegut '{}' per id '{}'", CODE, ID);
|
||||
continue;
|
||||
}
|
||||
bindings_[ID] = SC;
|
||||
}
|
||||
std::cout << "KeyConfig: " << bindings_.size() << " bindings des de " << file_path << '\n';
|
||||
Log::info("KeyConfig", "{} bindings des de {}", bindings_.size(), file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "KeyConfig: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
Log::error("KeyConfig", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "core/locale/locale.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -36,7 +36,7 @@ auto Locale::get() -> Locale& {
|
||||
void Locale::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "Locale: no s'ha pogut obrir " << file_path << '\n';
|
||||
Log::error("Locale", "no s'ha pogut obrir {}", file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,15 +46,15 @@ void Locale::load(const std::string& file_path) {
|
||||
auto yaml = fkyaml::node::deserialize(begin, end);
|
||||
strings_.clear();
|
||||
flatten(yaml, "", strings_);
|
||||
std::cout << "Locale: " << strings_.size() << " traduccions des de " << file_path << '\n';
|
||||
Log::info("Locale", "{} traduccions des de {}", strings_.size(), file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Locale: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
Log::error("Locale", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
auto Locale::text(const std::string& key) const -> std::string {
|
||||
auto it = strings_.find(key);
|
||||
if (it != strings_.end()) { return it->second; }
|
||||
std::cerr << "Locale: clau no trobada: " << key << '\n';
|
||||
Log::warn("Locale", "clau no trobada: {}", key);
|
||||
return key;
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "core/rendering/gif.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace GIF {
|
||||
|
||||
namespace {
|
||||
@@ -111,7 +112,7 @@ namespace GIF {
|
||||
while (cur_code != -1) {
|
||||
out[dictionary[cur_code].len - 1] = dictionary[cur_code].byte;
|
||||
if (dictionary[cur_code].prev == cur_code) {
|
||||
std::cerr << "Internal error; self-reference detected." << '\n';
|
||||
Log::error("GIF", "internal error; self-reference detected.");
|
||||
throw std::runtime_error("Internal error in decompress: self-reference");
|
||||
}
|
||||
cur_code = dictionary[cur_code].prev;
|
||||
@@ -155,8 +156,7 @@ namespace GIF {
|
||||
|
||||
if (prev > -1 && code_length < LZW_MAX_CODE_LENGTH) {
|
||||
if (code > dictionary_ind) {
|
||||
std::cerr << "code = " << std::hex << code
|
||||
<< ", but dictionary_ind = " << dictionary_ind << '\n';
|
||||
Log::error("GIF", "code = {:x}, but dictionary_ind = {}", code, dictionary_ind);
|
||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||
}
|
||||
|
||||
@@ -167,8 +167,7 @@ namespace GIF {
|
||||
|
||||
// Verifica que 'code' sea un índice válido antes de usarlo.
|
||||
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
|
||||
std::cerr << "Invalid LZW code " << code
|
||||
<< ", dictionary size " << dictionary.size() << '\n';
|
||||
Log::error("GIF", "invalid LZW code {}, dictionary size {}", code, dictionary.size());
|
||||
throw std::runtime_error("LZW error: invalid code encountered");
|
||||
}
|
||||
|
||||
@@ -287,7 +286,7 @@ namespace GIF {
|
||||
} else if (block_type == IMAGE_DESCRIPTOR) {
|
||||
return processImageDescriptor(buffer);
|
||||
} else {
|
||||
std::cerr << "Unrecognized block type " << std::hex << static_cast<int>(block_type) << '\n';
|
||||
Log::error("GIF", "unrecognized block type {:x}", static_cast<int>(block_type));
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
block_type = *buffer++;
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
#include "core/rendering/canvas.hpp"
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -112,11 +112,11 @@ void Screen::createSdl() {
|
||||
backend->setVSync(config_.vsync);
|
||||
if (backend->init(window_, canvas_width_, canvas_height_)) {
|
||||
gpu_driver_ = backend->getDriverName();
|
||||
std::cout << "Screen: path GPU actiu (driver: " << gpu_driver_ << ")\n";
|
||||
Log::info("Screen", "path GPU actiu (driver: {})", gpu_driver_);
|
||||
shader_backend_ = std::move(backend);
|
||||
return;
|
||||
}
|
||||
std::cerr << "Screen: GPU no disponible, fallback a SDL_Renderer\n";
|
||||
Log::warn("Screen", "GPU no disponible, fallback a SDL_Renderer");
|
||||
}
|
||||
gpu_driver_ = "sdl";
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "core/rendering/sdl3gpu/pipelines/crtpi_pipeline.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/rendering/sdl3gpu/shader_factory.hpp"
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "core/rendering/sdl3gpu/msl/crtpi_frag.msl.h"
|
||||
@@ -29,7 +29,7 @@ namespace Rendering {
|
||||
SDL_GPUShader* frag = createShaderSPIRV(device_, kcrtpi_frag_spv, kcrtpi_frag_spv_size, "main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||
#endif
|
||||
if (vert == nullptr || frag == nullptr) {
|
||||
std::cerr << "CrtPiPipeline: creació de shaders fallida: " << SDL_GetError() << '\n';
|
||||
Log::error("CrtPiPipeline", "creació de shaders fallida: {}", SDL_GetError());
|
||||
if (vert != nullptr) { SDL_ReleaseGPUShader(device_, vert); }
|
||||
if (frag != nullptr) { SDL_ReleaseGPUShader(device_, frag); }
|
||||
return false;
|
||||
@@ -57,7 +57,7 @@ namespace Rendering {
|
||||
SDL_ReleaseGPUShader(device_, frag);
|
||||
|
||||
if (pipeline_ == nullptr) {
|
||||
std::cerr << "CrtPiPipeline: creació del pipeline ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("CrtPiPipeline", "creació del pipeline ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/rendering/sdl3gpu/shader_factory.hpp"
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "core/rendering/sdl3gpu/msl/postfx_frag.msl.h"
|
||||
@@ -59,11 +59,11 @@ namespace Rendering {
|
||||
const char* driver = preferred_driver_.empty() ? nullptr : preferred_driver_.c_str();
|
||||
device_ = SDL_CreateGPUDevice(FORMAT, false, driver);
|
||||
if (device_ == nullptr) {
|
||||
std::cerr << "SDL3GPUShader: SDL_CreateGPUDevice ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("SDL3GPUShader", "SDL_CreateGPUDevice ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
|
||||
std::cerr << "SDL3GPUShader: SDL_ClaimWindowForGPUDevice ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("SDL3GPUShader", "SDL_ClaimWindowForGPUDevice ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, bestPresentMode(vsync_));
|
||||
@@ -82,7 +82,7 @@ namespace Rendering {
|
||||
fragment_shader_ = createShaderSPIRV(device_, kpostfx_frag_spv, kpostfx_frag_spv_size, "main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||
#endif
|
||||
if (vertex_shader_ == nullptr || fragment_shader_ == nullptr) {
|
||||
std::cerr << "SDL3GPUShader: SDL_CreateGPUShader ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("SDL3GPUShader", "SDL_CreateGPUShader ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -105,7 +105,7 @@ namespace Rendering {
|
||||
|
||||
pipeline_ = SDL_CreateGPUGraphicsPipeline(device_, &info);
|
||||
if (pipeline_ == nullptr) {
|
||||
std::cerr << "SDL3GPUShader: SDL_CreateGPUGraphicsPipeline ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("SDL3GPUShader", "SDL_CreateGPUGraphicsPipeline ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -137,7 +137,7 @@ namespace Rendering {
|
||||
sampler_ = SDL_CreateGPUSampler(device_, &samp_info);
|
||||
|
||||
if (scene_texture_ == nullptr || upload_buffer_ == nullptr || sampler_ == nullptr) {
|
||||
std::cerr << "SDL3GPUShader: creació de recursos GPU ha fallat: " << SDL_GetError() << '\n';
|
||||
Log::error("SDL3GPUShader", "creació de recursos GPU ha fallat: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "core/rendering/sprite/animated_sprite.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include "core/rendering/surface.hpp"
|
||||
#include "core/resources/resource_cache.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
// El parser pure de YAML d'animacions (parseAnimationsFromYaml + helpers)
|
||||
// viu a `animated_sprite_parser.cpp` perquè és testable sense Surface ni
|
||||
@@ -74,10 +74,10 @@ AnimatedSprite::AnimatedSprite(const AnimationResource& cached_data) {
|
||||
if (!first.frames.empty()) { setClip(first.frames[0].rect); }
|
||||
}
|
||||
} catch (const fkyaml::exception& e) {
|
||||
std::cerr << "YAML parsing error in animation " << cached_data.name << ": " << e.what() << '\n';
|
||||
Log::error("AnimatedSprite", "YAML parsing error in animation {}: {}", cached_data.name, e.what());
|
||||
throw;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error loading animation " << cached_data.name << ": " << e.what() << '\n';
|
||||
Log::error("AnimatedSprite", "Error loading animation {}: {}", cached_data.name, e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name) {
|
||||
if (current_animation_ == name) { return; }
|
||||
auto it = animations_.find(name);
|
||||
if (it == animations_.end()) {
|
||||
std::cout << "** Warning: could not find \"" << name << "\" animation" << '\n';
|
||||
Log::warn("AnimatedSprite", "could not find \"{}\" animation", name);
|
||||
return;
|
||||
}
|
||||
current_animation_ = name;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
@@ -63,7 +62,7 @@ Surface::Surface(const std::string& file_path) {
|
||||
palette_[i] = Rendering::OPAQUE_ALPHA | rgb[i];
|
||||
}
|
||||
|
||||
printWithDots("Surface : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Surface", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
void Surface::clear(Uint8 color) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -11,6 +10,7 @@
|
||||
#include "core/rendering/sprite/sprite.hpp"
|
||||
#include "core/rendering/surface.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
// Decodifica el pròxim codepoint UTF-8 de la cadena i avança 'pos' al byte
|
||||
@@ -55,7 +55,7 @@ auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> {
|
||||
|
||||
auto file_data = Resource::Helper::loadFile(file_path);
|
||||
if (file_data.empty()) {
|
||||
std::cerr << "Error: Fitxer no trobat " << getFileName(file_path) << '\n';
|
||||
Log::error("Text File", "fitxer no trobat: {}", getFileName(file_path));
|
||||
throw std::runtime_error("Fitxer no trobat: " + getFileName(file_path));
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> {
|
||||
}
|
||||
}
|
||||
|
||||
printWithDots("Text File : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Text File", getFileName(file_path), "[ LOADED ]");
|
||||
return tf;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "core/resources/resource_cache.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "core/audio/jail_audio.hpp"
|
||||
#include "core/resources/palette_loader.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
// Deleters dels recursos d'àudio: necessiten veure el tipus complet de
|
||||
@@ -37,19 +37,19 @@ namespace Resource {
|
||||
throw std::runtime_error("Cache: cannot load animation " + file_path);
|
||||
}
|
||||
animations_.emplace_back(AnimationResource{.name = name, .yaml_data = std::move(bytes)});
|
||||
printWithDots("Animation : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Animation", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
void Cache::loadPalette(const std::string& name, const std::string& file_path) {
|
||||
auto palette = PaletteLoader::loadFromFile(file_path);
|
||||
palettes_.emplace_back(PaletteResource{.name = name, .palette = palette});
|
||||
printWithDots("Palette : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Palette", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
|
||||
auto it = std::ranges::find_if(surfaces_, [&name](const auto& s) { return s.name == name; });
|
||||
if (it == surfaces_.end()) {
|
||||
std::cerr << "Cache: surface not found: " << name << '\n';
|
||||
Log::error("Cache", "surface not found: {}", name);
|
||||
throw std::runtime_error("Surface not found: " + name);
|
||||
}
|
||||
return it->surface;
|
||||
@@ -58,7 +58,7 @@ namespace Resource {
|
||||
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& {
|
||||
auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; });
|
||||
if (it == animations_.end()) {
|
||||
std::cerr << "Cache: animation not found: " << name << '\n';
|
||||
Log::error("Cache", "animation not found: {}", name);
|
||||
throw std::runtime_error("Animation not found: " + name);
|
||||
}
|
||||
return *it;
|
||||
@@ -67,7 +67,7 @@ namespace Resource {
|
||||
auto Cache::getPalette(const std::string& name) -> const Palette& {
|
||||
auto it = std::ranges::find_if(palettes_, [&name](const auto& p) { return p.name == name; });
|
||||
if (it == palettes_.end()) {
|
||||
std::cerr << "Cache: palette not found: " << name << '\n';
|
||||
Log::error("Cache", "palette not found: {}", name);
|
||||
throw std::runtime_error("Palette not found: " + name);
|
||||
}
|
||||
return it->palette;
|
||||
@@ -83,7 +83,7 @@ namespace Resource {
|
||||
throw std::runtime_error("Cache: Ja::loadMusic failed for " + file_path);
|
||||
}
|
||||
musics_.emplace_back(MusicResource{.name = name, .music = std::unique_ptr<Ja::Music, MusicDeleter>(raw)});
|
||||
printWithDots("Music : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Music", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
void Cache::loadSound(const std::string& name, const std::string& file_path) {
|
||||
@@ -96,13 +96,13 @@ namespace Resource {
|
||||
throw std::runtime_error("Cache: Ja::loadSound failed for " + file_path);
|
||||
}
|
||||
sounds_.emplace_back(SoundResource{.name = name, .sound = std::unique_ptr<Ja::Sound, SoundDeleter>(raw)});
|
||||
printWithDots("Sound : ", getFileName(file_path), "[ LOADED ]");
|
||||
printWithDots("Sound", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
auto Cache::getMusic(const std::string& name) -> Ja::Music* {
|
||||
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; });
|
||||
if (it == musics_.end()) {
|
||||
std::cerr << "Cache: music not found: " << name << '\n';
|
||||
Log::error("Cache", "music not found: {}", name);
|
||||
throw std::runtime_error("Music not found: " + name);
|
||||
}
|
||||
return it->music.get();
|
||||
@@ -111,7 +111,7 @@ namespace Resource {
|
||||
auto Cache::getSound(const std::string& name) -> Ja::Sound* {
|
||||
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; });
|
||||
if (it == sounds_.end()) {
|
||||
std::cerr << "Cache: sound not found: " << name << '\n';
|
||||
Log::error("Cache", "sound not found: {}", name);
|
||||
throw std::runtime_error("Sound not found: " + name);
|
||||
}
|
||||
return it->sound.get();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "core/resources/resource_pack.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace Resource::Helper {
|
||||
|
||||
@@ -27,14 +27,14 @@ namespace Resource::Helper {
|
||||
// Silenciem si veníem de prefer_disk: aleshores caurem
|
||||
// al pack i no és cap error real que el fitxer no estigui
|
||||
// al disc.
|
||||
if (verbose) { std::cerr << "Resource::Helper: cannot open " << FULL << '\n'; }
|
||||
if (verbose) { Log::error("Resource::Helper", "cannot open {}", FULL); }
|
||||
return {};
|
||||
}
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<std::uint8_t> data(static_cast<std::size_t>(size));
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), size)) {
|
||||
std::cerr << "Resource::Helper: failed to read " << FULL << '\n';
|
||||
Log::error("Resource::Helper", "failed to read {}", FULL);
|
||||
return {};
|
||||
}
|
||||
return data;
|
||||
@@ -52,14 +52,11 @@ namespace Resource::Helper {
|
||||
g_pack_loaded = g_pack.loadPack(pack_file);
|
||||
|
||||
if (g_pack_loaded) {
|
||||
std::cout << "Resource::Helper: pack loaded (" << g_pack.getResourceCount()
|
||||
<< " entries) from " << pack_file << '\n';
|
||||
Log::info("Resource::Helper", "pack loaded ({} entries) from {}", g_pack.getResourceCount(), pack_file);
|
||||
} else if (enable_fallback) {
|
||||
std::cout << "Resource::Helper: no pack at " << pack_file
|
||||
<< " — using filesystem fallback\n";
|
||||
Log::info("Resource::Helper", "no pack at {} — using filesystem fallback", pack_file);
|
||||
} else {
|
||||
std::cerr << "Resource::Helper: FATAL — no pack at " << pack_file
|
||||
<< " and fallback disabled\n";
|
||||
Log::critical("Resource::Helper", "FATAL — no pack at {} and fallback disabled", pack_file);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace Resource {
|
||||
|
||||
@@ -40,14 +41,14 @@ namespace Resource {
|
||||
std::array<char, 4> header{};
|
||||
file.read(header.data(), 4);
|
||||
if (std::string(header.data(), 4) != MAGIC) {
|
||||
std::cerr << "Resource::Pack: invalid pack file format (bad magic): " << pack_file << '\n';
|
||||
Log::error("Resource::Pack", "invalid pack file format (bad magic): {}", pack_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::uint32_t version = 0;
|
||||
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||
if (version != VERSION) {
|
||||
std::cerr << "Resource::Pack: unsupported pack version: " << version << '\n';
|
||||
Log::error("Resource::Pack", "unsupported pack version: {}", version);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ namespace Resource {
|
||||
auto Pack::savePack(const std::string& pack_file) const -> bool {
|
||||
std::ofstream file(pack_file, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "Resource::Pack: could not create pack file: " << pack_file << '\n';
|
||||
Log::error("Resource::Pack", "could not create pack file: {}", pack_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ namespace Resource {
|
||||
auto Pack::addFile(const std::string& filename, const std::string& filepath) -> bool {
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "Resource::Pack: could not open file: " << filepath << '\n';
|
||||
Log::error("Resource::Pack", "could not open file: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ namespace Resource {
|
||||
|
||||
std::vector<std::uint8_t> file_data(file_size);
|
||||
if (!file.read(reinterpret_cast<char*>(file_data.data()), file_size)) {
|
||||
std::cerr << "Resource::Pack: could not read file: " << filepath << '\n';
|
||||
Log::error("Resource::Pack", "could not read file: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ namespace Resource {
|
||||
|
||||
auto Pack::addDirectory(const std::string& directory) -> bool {
|
||||
if (!std::filesystem::exists(directory)) {
|
||||
std::cerr << "Resource::Pack: directory does not exist: " << directory << '\n';
|
||||
Log::error("Resource::Pack", "directory does not exist: {}", directory);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ namespace Resource {
|
||||
|
||||
const PackEntry& entry = it->second;
|
||||
if (entry.offset + entry.size > data_.size()) {
|
||||
std::cerr << "Resource::Pack: invalid resource data: " << filename << '\n';
|
||||
Log::error("Resource::Pack", "invalid resource data: {}", filename);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -179,7 +180,7 @@ namespace Resource {
|
||||
|
||||
std::uint32_t checksum = calculateChecksum(result);
|
||||
if (checksum != entry.checksum) {
|
||||
std::cerr << "Resource::Pack: checksum mismatch for: " << filename << '\n';
|
||||
Log::error("Resource::Pack", "checksum mismatch for: {}", filename);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <any>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -42,10 +40,11 @@
|
||||
#include "game/scenes/title_scene.hpp"
|
||||
#include "game/ui/service_menu.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
Director::Director() {
|
||||
if (!SDL_Init(0)) {
|
||||
std::fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
|
||||
Log::critical("Director", "SDL_Init failed: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
// Sistema de recursos: el pack viu al costat del binari (build/), el
|
||||
@@ -66,7 +65,7 @@ Director::Director() {
|
||||
constexpr bool ENABLE_FALLBACK = false;
|
||||
#endif
|
||||
if (!Resource::Helper::initializeResourceSystem(pack_file, ENABLE_FALLBACK)) {
|
||||
std::fprintf(stderr, "Director: sistema de recursos no disponible; avortem\n");
|
||||
Log::critical("Director", "sistema de recursos no disponible; avortem");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ Director::Director() {
|
||||
|
||||
Options::setConfigFile(system_folder_ + "config.yaml");
|
||||
if (!Options::loadFromFile()) {
|
||||
std::cerr << "Director: no s'ha pogut carregar ni desar config.yaml a " << system_folder_ << '\n';
|
||||
Log::error("Director", "no s'ha pogut carregar ni desar config.yaml a {}", system_folder_);
|
||||
}
|
||||
|
||||
// Vinculacions de mando per dispositiu — fitxer aïllat de `config.yaml`
|
||||
@@ -97,12 +96,12 @@ Director::Director() {
|
||||
// es crea amb presets per defecte (off, crt, ntsc).
|
||||
Options::setPostFXFile(system_folder_ + Defaults::Video::POSTFX_FILE);
|
||||
if (!Options::loadPostFXFromFile()) {
|
||||
std::cerr << "Director: no s'ha pogut carregar ni desar postfx.yaml.\n";
|
||||
Log::error("Director", "no s'ha pogut carregar ni desar postfx.yaml.");
|
||||
}
|
||||
// Presets del shader CRT-Pi (shaders/crtpi.yaml).
|
||||
Options::setCrtPiFile(system_folder_ + Defaults::Video::CRTPI_FILE);
|
||||
if (!Options::loadCrtPiFromFile()) {
|
||||
std::cerr << "Director: no s'ha pogut carregar ni desar crtpi.yaml.\n";
|
||||
Log::error("Director", "no s'ha pogut carregar ni desar crtpi.yaml.");
|
||||
}
|
||||
|
||||
// Screen es configura ara (subsystem + finestra + GPU/renderer); la seua
|
||||
@@ -295,8 +294,7 @@ Director::Director() {
|
||||
const auto START = DebugConfig::StartScene::LOGO;
|
||||
const auto STARTING_PLAYERS = DebugConfig::StartingPlayers::BOTH;
|
||||
#endif
|
||||
std::cout << "Director: start_scene=" << DebugConfig::toString(START)
|
||||
<< " starting_players=" << DebugConfig::toString(STARTING_PLAYERS) << '\n';
|
||||
Log::info("Director", "start_scene={} starting_players={}", DebugConfig::toString(START), DebugConfig::toString(STARTING_PLAYERS));
|
||||
|
||||
switch (START) {
|
||||
case DebugConfig::StartScene::LOGO:
|
||||
@@ -351,7 +349,7 @@ void Director::createSystemFolder() {
|
||||
// Subcarpeta per als presets de shaders. std::filesystem és tolerant si ja existeix.
|
||||
std::filesystem::create_directories(system_folder_ + "shaders/", error);
|
||||
if (error) {
|
||||
std::cerr << "Director: no s'ha pogut crear " << system_folder_ << ": " << error.message() << '\n';
|
||||
Log::error("Director", "no s'ha pogut crear {}: {}", system_folder_, error.message());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +431,7 @@ void Director::switchSceneIfRequested() {
|
||||
// l'escena en aquest mateix frame — l'usuari ha cancel·lat l'estat
|
||||
// de joc explícitament i no ens interessa mantenir-ne la sortida.
|
||||
if (auto menu_req = ServiceMenu::get().takePendingSceneRequest(); menu_req.has_value()) {
|
||||
std::cout << "Director: scene transition (menu) → " << toString(menu_req->next) << '\n';
|
||||
Log::info("Director", "scene transition (menu) → {}", toString(menu_req->next));
|
||||
current_scene_ = buildScene(menu_req->next, menu_req->params);
|
||||
return;
|
||||
}
|
||||
@@ -445,10 +443,10 @@ void Director::switchSceneIfRequested() {
|
||||
if (!request.has_value()) { return; }
|
||||
try {
|
||||
const auto& req = std::any_cast<const ExitRequest&>(request);
|
||||
std::cout << "Director: scene transition → " << toString(req.next) << '\n';
|
||||
Log::info("Director", "scene transition → {}", toString(req.next));
|
||||
current_scene_ = buildScene(req.next, req.params);
|
||||
} catch (const std::bad_any_cast&) {
|
||||
std::cerr << "Director: exit_request_ amb tipus inesperat — ignorant\n";
|
||||
Log::error("Director", "exit_request_ amb tipus inesperat — ignorant");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "core/ui/ui_config.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
@@ -9,6 +8,7 @@
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/easing.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace {
|
||||
if (!node.contains(key)) { return; }
|
||||
const int VALUE = node[key].get_value<int>();
|
||||
if (VALUE < 0 || VALUE > 255) {
|
||||
std::cerr << "UiConfig: índex '" << key << "'=" << VALUE << " fora de rang 0..255 — ignorat\n";
|
||||
Log::warn("UiConfig", "índex '{}'={} fora de rang 0..255 — ignorat", key, VALUE);
|
||||
return;
|
||||
}
|
||||
dst = static_cast<Uint8>(VALUE);
|
||||
@@ -183,7 +183,7 @@ auto UiConfig::curveByName(const std::string& name) -> CurveFn {
|
||||
const auto& reg = curveRegistry();
|
||||
const auto IT = reg.find(name);
|
||||
if (IT == reg.end()) {
|
||||
std::cerr << "UiConfig: corba '" << name << "' desconeguda — s'usa linear\n";
|
||||
Log::warn("UiConfig", "corba '{}' desconeguda — s'usa linear", name);
|
||||
return &Easing::linear;
|
||||
}
|
||||
return IT->second;
|
||||
@@ -192,7 +192,7 @@ auto UiConfig::curveByName(const std::string& name) -> CurveFn {
|
||||
void UiConfig::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "UiConfig: no s'ha pogut obrir " << file_path << " — s'usaran els defaults compilats\n";
|
||||
Log::warn("UiConfig", "no s'ha pogut obrir {} — s'usaran els defaults compilats", file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -345,8 +345,8 @@ void UiConfig::load(const std::string& file_path) {
|
||||
readCurve(n, "slide_out_curve", notifier_.slide_out_curve);
|
||||
}
|
||||
|
||||
std::cout << "UiConfig: carregat des de " << file_path << '\n';
|
||||
Log::info("UiConfig", "carregat des de {}", file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "UiConfig: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
Log::error("UiConfig", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace DebugConfig {
|
||||
|
||||
@@ -53,12 +53,12 @@ namespace DebugConfig {
|
||||
if (!yaml.contains("start_scene")) { return StartScene::GAME; }
|
||||
const auto RAW = yaml["start_scene"].get_value<std::string>();
|
||||
if (!isKnown(RAW)) {
|
||||
std::cerr << "debug.yaml: start_scene \"" << RAW << "\" invàlid, arrancant a GAME\n";
|
||||
Log::warn("debug.yaml", "start_scene \"{}\" invàlid, arrancant a GAME", RAW);
|
||||
return StartScene::GAME;
|
||||
}
|
||||
return fromName(RAW);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "debug.yaml: error parsejant: " << e.what() << " — arrancant a GAME\n";
|
||||
Log::error("debug.yaml", "error parsejant: {} — arrancant a GAME", e.what());
|
||||
return StartScene::GAME;
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ namespace DebugConfig {
|
||||
}
|
||||
const auto CONTENT = readFile(file_path);
|
||||
if (CONTENT.empty()) {
|
||||
std::cerr << "debug.yaml: fitxer buit a " << file_path << ", arrancant a GAME\n";
|
||||
Log::warn("debug.yaml", "fitxer buit a {}, arrancant a GAME", file_path);
|
||||
return StartScene::GAME;
|
||||
}
|
||||
return parseStartScene(CONTENT);
|
||||
@@ -85,12 +85,12 @@ namespace DebugConfig {
|
||||
if (!yaml.contains("starting_players")) { return StartingPlayers::BOTH; }
|
||||
const auto RAW = yaml["starting_players"].get_value<std::string>();
|
||||
if (!isKnownPlayers(RAW)) {
|
||||
std::cerr << "debug.yaml: starting_players \"" << RAW << "\" invàlid, arrancant amb BOTH\n";
|
||||
Log::warn("debug.yaml", "starting_players \"{}\" invàlid, arrancant amb BOTH", RAW);
|
||||
return StartingPlayers::BOTH;
|
||||
}
|
||||
return playersFromName(RAW);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "debug.yaml: error parsejant starting_players: " << e.what() << " — arrancant amb BOTH\n";
|
||||
Log::error("debug.yaml", "error parsejant starting_players: {} — arrancant amb BOTH", e.what());
|
||||
return StartingPlayers::BOTH;
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ namespace DebugConfig {
|
||||
if (!yaml.contains("starting_level")) { return std::nullopt; }
|
||||
const auto& sl = yaml["starting_level"];
|
||||
if (!sl.contains("pyramid") || !sl.contains("room")) {
|
||||
std::cerr << "debug.yaml: starting_level necessita els camps `pyramid` i `room` — ignorat\n";
|
||||
Log::warn("debug.yaml", "starting_level necessita els camps `pyramid` i `room` — ignorat");
|
||||
return std::nullopt;
|
||||
}
|
||||
return StartingLevel{
|
||||
@@ -118,7 +118,7 @@ namespace DebugConfig {
|
||||
.room = sl["room"].get_value<int>(),
|
||||
};
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "debug.yaml: error parsejant starting_level: " << e.what() << " — ignorat\n";
|
||||
Log::error("debug.yaml", "error parsejant starting_level: {} — ignorat", e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ namespace DebugConfig {
|
||||
if (std::filesystem::exists(file_path, error)) { return; }
|
||||
std::ofstream file(file_path);
|
||||
if (!file) {
|
||||
std::cerr << "debug.yaml: no s'ha pogut crear " << file_path << '\n';
|
||||
Log::error("debug.yaml", "no s'ha pogut crear {}", file_path);
|
||||
return;
|
||||
}
|
||||
file << "# debug.yaml — ajust personal de dev (no versionat).\n";
|
||||
@@ -173,7 +173,7 @@ namespace DebugConfig {
|
||||
file << "# clau, comença a la primera (P1-R1).\n";
|
||||
file << "start_scene: GAME\n";
|
||||
file << "starting_players: BOTH\n";
|
||||
std::cout << "debug.yaml: creat a " << file_path << " amb start_scene=GAME starting_players=BOTH\n";
|
||||
Log::info("debug.yaml", "creat a {} amb start_scene=GAME starting_players=BOTH", file_path);
|
||||
}
|
||||
|
||||
} // namespace DebugConfig
|
||||
@@ -3,13 +3,13 @@
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace {
|
||||
if (!s.empty() && s.front() == '#') { s.erase(0, 1); }
|
||||
dst = static_cast<std::uint32_t>(std::stoul(s, nullptr, 0));
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "EditorConfig: color '" << key << "' invàlid (" << e.what() << ") — ignorat\n";
|
||||
Log::warn("EditorConfig", "color '{}' invàlid ({}) — ignorat", key, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ auto EditorConfig::get() -> EditorConfig& {
|
||||
void EditorConfig::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "EditorConfig: no s'ha pogut obrir " << file_path << " — s'usaran els defaults compilats\n";
|
||||
Log::warn("EditorConfig", "no s'ha pogut obrir {} — s'usaran els defaults compilats", file_path);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -76,9 +76,9 @@ void EditorConfig::load(const std::string& file_path) {
|
||||
readArgb(c, "picker_hover", picker_hover_argb_);
|
||||
}
|
||||
|
||||
std::cout << "EditorConfig: carregat des de " << file_path << '\n';
|
||||
Log::info("EditorConfig", "carregat des de {}", file_path);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "EditorConfig: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
Log::error("EditorConfig", "error parsejant {}: {}", file_path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// stand-alone) enllacen `entity_manager.cpp` sense arrossegar aquest fitxer.
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -22,6 +21,7 @@
|
||||
#include "game/entities/player.hpp"
|
||||
#include "game/map/map.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
// Render centralitzat al manager per confinar la dependència cap a
|
||||
// `Surface`. Les entitats exposen `getSurface()` + `getPixelRect()` i el
|
||||
@@ -237,12 +237,12 @@ namespace {
|
||||
try {
|
||||
tmpl = EntityLoader::loadTemplate(type);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "EntityManager: " << e.what() << '\n';
|
||||
Log::error("EntityManager", "{}", e.what());
|
||||
return nullptr;
|
||||
}
|
||||
auto entity = EntityFactory::instance().create(type, tmpl);
|
||||
if (entity == nullptr) {
|
||||
std::cerr << "EntityManager: tipus desconegut '" << type << "'\n";
|
||||
Log::error("EntityManager", "tipus desconegut '{}'", type);
|
||||
return nullptr;
|
||||
}
|
||||
sprite_out = readSpriteInfo(tmpl, type);
|
||||
@@ -267,7 +267,7 @@ namespace {
|
||||
namespace {
|
||||
auto placeSarcophagus(EntityManager& manager, std::unique_ptr<Entity> entity, const SpriteInfo& sprite, const fkyaml::node& spawn) -> bool {
|
||||
if (!spawn.contains("sarc_position")) {
|
||||
std::cerr << "EntityManager: sarcophagus sense sarc_position\n";
|
||||
Log::error("EntityManager", "sarcophagus sense sarc_position");
|
||||
return false;
|
||||
}
|
||||
const auto& sp = spawn["sarc_position"];
|
||||
@@ -304,7 +304,7 @@ namespace {
|
||||
// un `Sarcophagus`. Usant el retorn de `release` al ctor del nou
|
||||
// `unique_ptr` evitem el lint `bugprone-unused-return-value`.
|
||||
if (dynamic_cast<Sarcophagus*>(entity.get()) == nullptr) {
|
||||
std::cerr << "EntityManager: la factory no ha creat un Sarcophagus\n";
|
||||
Log::error("EntityManager", "la factory no ha creat un Sarcophagus");
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<Sarcophagus> sarc(static_cast<Sarcophagus*>(entity.release()));
|
||||
@@ -323,7 +323,7 @@ namespace {
|
||||
// queden tapats — comportament intencional.
|
||||
auto placeDoor(EntityManager& manager, std::unique_ptr<Entity> entity, const SpriteInfo& sprite) -> bool {
|
||||
if (Map::door_col <= 0 || Map::tile_size <= 0) {
|
||||
std::cerr << "EntityManager: door requereix `geometry.door_col` definit al mapa\n";
|
||||
Log::error("EntityManager", "door requereix `geometry.door_col` definit al mapa");
|
||||
return false;
|
||||
}
|
||||
const float CENTER_X = static_cast<float>((Map::door_col * Map::tile_size) + Map::tilemap_origin_x) + (static_cast<float>(Map::tile_size) / 2.0F);
|
||||
@@ -343,7 +343,7 @@ namespace {
|
||||
|
||||
auto placeGeneric(EntityManager& manager, std::unique_ptr<Entity> entity, const std::string& type, const SpriteInfo& sprite, const std::string& anchor, const fkyaml::node& spawn) -> bool {
|
||||
if (!spawn.contains("position")) {
|
||||
std::cerr << "EntityManager: " << type << " sense position\n";
|
||||
Log::error("EntityManager", "{} sense position", type);
|
||||
return false;
|
||||
}
|
||||
const auto& p = spawn["position"];
|
||||
@@ -444,10 +444,8 @@ void EntityManager::loadFromLevel(const std::string& level_yaml_path) {
|
||||
++decal_broadcast;
|
||||
}
|
||||
if (decal_broadcast > 0) {
|
||||
std::cout << "EntityManager: " << decal_broadcast
|
||||
<< " tile_painted broadcast inicial (decals de sòl)\n";
|
||||
Log::info("EntityManager", "{} tile_painted broadcast inicial (decals de sòl)", decal_broadcast);
|
||||
}
|
||||
|
||||
std::cout << "EntityManager: " << LOADED << " entitats carregades des de "
|
||||
<< level_yaml_path << '\n';
|
||||
Log::info("EntityManager", "{} entitats carregades des de {}", LOADED, level_yaml_path);
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "game/levels/level_manager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace Levels {
|
||||
|
||||
@@ -46,8 +46,7 @@ namespace Levels {
|
||||
throw std::runtime_error("LevelManager: la seqüència de " + PATH + " és buida");
|
||||
}
|
||||
index_ = 0;
|
||||
std::cout << "LevelManager: " << entries_.size() << " sales carregades de "
|
||||
<< PATH << " (començant a " << currentLabel() << ")\n";
|
||||
Log::info("LevelManager", "{} sales carregades de {} (començant a {})", entries_.size(), PATH, currentLabel());
|
||||
}
|
||||
|
||||
auto LevelManager::currentPath() const -> const std::string& {
|
||||
@@ -67,22 +66,20 @@ namespace Levels {
|
||||
auto LevelManager::advance() -> bool {
|
||||
if (index_ + 1 >= count()) { return false; }
|
||||
++index_;
|
||||
std::cout << "LevelManager: avança a " << currentLabel()
|
||||
<< " (" << currentPath() << ")\n";
|
||||
Log::info("LevelManager", "avança a {} ({})", currentLabel(), currentPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelManager::restart() {
|
||||
index_ = 0;
|
||||
std::cout << "LevelManager: restart a " << currentLabel() << '\n';
|
||||
Log::info("LevelManager", "restart a {}", currentLabel());
|
||||
}
|
||||
|
||||
void LevelManager::setIndex(int new_index) {
|
||||
const int CLAMPED = std::clamp(new_index, 0, count() - 1);
|
||||
if (CLAMPED != index_) {
|
||||
index_ = CLAMPED;
|
||||
std::cout << "LevelManager: setIndex(" << new_index << ") → "
|
||||
<< currentLabel() << " (" << currentPath() << ")\n";
|
||||
Log::info("LevelManager", "setIndex({}) → {} ({})", new_index, currentLabel(), currentPath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +87,11 @@ namespace Levels {
|
||||
for (std::size_t i = 0; i < entries_.size(); ++i) {
|
||||
if (entries_[i].pyramid == pyramid && entries_[i].room == room) {
|
||||
index_ = static_cast<int>(i);
|
||||
std::cout << "LevelManager: starting_point P" << pyramid << "-R" << room
|
||||
<< " trobat a l'índex " << i << " (" << currentPath() << ")\n";
|
||||
Log::info("LevelManager", "starting_point P{}-R{} trobat a l'índex {} ({})", pyramid, room, i, currentPath());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::cerr << "LevelManager: starting_point P" << pyramid << "-R" << room
|
||||
<< " no trobat a levels.yaml — es manté l'índex actual ("
|
||||
<< currentLabel() << ")\n";
|
||||
Log::warn("LevelManager", "starting_point P{}-R{} no trobat a levels.yaml — es manté l'índex actual ({})", pyramid, room, currentLabel());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "game/map/map.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -90,11 +90,7 @@ namespace Map {
|
||||
// canviarà el flag a true quan transiti a OPEN.
|
||||
door_open = false;
|
||||
|
||||
std::cout << "Map: geometria " << grid_cols << "x" << grid_rows
|
||||
<< " sarcs " << sarc_w << "x" << sarc_h
|
||||
<< " pitch " << pitch_x << "x" << pitch_y
|
||||
<< " door_col " << door_col
|
||||
<< " des de " << yaml_path << '\n';
|
||||
Log::info("Map", "geometria {}x{} sarcs {}x{} pitch {}x{} door_col {} des de {}", grid_cols, grid_rows, sarc_w, sarc_h, pitch_x, pitch_y, door_col, yaml_path);
|
||||
}
|
||||
|
||||
auto getSarcRect(int col, int row) -> SDL_FRect {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
|
||||
#include "core/rendering/screen.hpp"
|
||||
@@ -11,6 +10,7 @@
|
||||
#include "core/resources/resource_cache.hpp"
|
||||
#include "game/map/map.hpp"
|
||||
#include "game/map/tilemap.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
// CONTRACTE BUS DE PINTAT
|
||||
// -----------------------
|
||||
@@ -89,9 +89,7 @@ PaintLayer::PaintLayer(const Tilemap& tilemap, EventBus* bus)
|
||||
});
|
||||
}
|
||||
|
||||
std::cout << "PaintLayer: " << cols_ << "x" << rows_ << " tiles ("
|
||||
<< width_px_ << "x" << height_px_ << " px), tileset "
|
||||
<< tileset_path_ << '\n';
|
||||
Log::info("PaintLayer", "{}x{} tiles ({}x{} px), tileset {}", cols_, rows_, width_px_, height_px_, tileset_path_);
|
||||
}
|
||||
|
||||
PaintLayer::~PaintLayer() {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
@@ -12,6 +11,7 @@
|
||||
#include "core/resources/resource_cache.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "game/map/tilemap_writer.hpp"
|
||||
@@ -97,8 +97,7 @@ Tilemap::Tilemap(const std::string& yaml_path) {
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Tilemap: " << cols_ << "x" << rows_ << " tiles ("
|
||||
<< width_px_ << "x" << height_px_ << " px) des de " << yaml_path << '\n';
|
||||
Log::info("Tilemap", "{}x{} tiles ({}x{} px) des de {}", cols_, rows_, width_px_, height_px_, yaml_path);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
+11
-12
@@ -3,7 +3,6 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -12,6 +11,7 @@
|
||||
#include "core/input/gamepad_manager.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace {
|
||||
std::ofstream dst(path + ".bak", std::ios::binary);
|
||||
if (!dst) { return; }
|
||||
dst << src.rdbuf();
|
||||
std::cout << "Options: còpia de seguretat a " << path << ".bak\n";
|
||||
Log::info("Options", "còpia de seguretat a {}.bak", path);
|
||||
}
|
||||
|
||||
void parseWindow(const fkyaml::node& yaml) {
|
||||
@@ -463,7 +463,7 @@ namespace {
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(CONTENT);
|
||||
if (!yaml.contains("presets") || !yaml["presets"].is_sequence()) {
|
||||
std::cout << "Options: " << kind_label << " manca `presets:`; reescrivint amb defaults.\n";
|
||||
Log::warn("Options", "{} manca `presets:`; reescrivint amb defaults.", kind_label);
|
||||
backupFile(path);
|
||||
presets = defaults_fn();
|
||||
return save_fn();
|
||||
@@ -475,15 +475,15 @@ namespace {
|
||||
presets.push_back(preset);
|
||||
}
|
||||
if (presets.empty()) {
|
||||
std::cout << "Options: " << kind_label << " sense presets; reescrivint amb defaults.\n";
|
||||
Log::warn("Options", "{} sense presets; reescrivint amb defaults.", kind_label);
|
||||
backupFile(path);
|
||||
presets = defaults_fn();
|
||||
return save_fn();
|
||||
}
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << "Options: error parsejant " << kind_label << ": " << e.what() << '\n';
|
||||
std::cout << "Options: reescrivint el fitxer amb presets per defecte.\n";
|
||||
Log::error("Options", "error parsejant {}: {}", kind_label, e.what());
|
||||
Log::info("Options", "reescrivint el fitxer amb presets per defecte.");
|
||||
backupFile(path);
|
||||
presets = defaults_fn();
|
||||
return save_fn();
|
||||
@@ -655,8 +655,7 @@ namespace Options {
|
||||
// amb els defaults de la versió nova. El fitxer original queda
|
||||
// a `<path>.bak` per si l'usuari volia preservar tuning manual.
|
||||
if (file_version != Texts::VERSION) {
|
||||
std::cout << "Options: config.yaml versió \"" << file_version
|
||||
<< "\" != \"" << Texts::VERSION << "\"; reescrivint amb defaults.\n";
|
||||
Log::warn("Options", "config.yaml versió \"{}\" != \"{}\"; reescrivint amb defaults.", file_version, Texts::VERSION);
|
||||
backupFile(g_config_file_path);
|
||||
return saveToFile();
|
||||
}
|
||||
@@ -679,8 +678,8 @@ namespace Options {
|
||||
if (CHANGED) { saveToFile(); }
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << "Options: error parsejant config.yaml: " << e.what() << '\n';
|
||||
std::cout << "Options: reescrivint el fitxer amb defaults.\n";
|
||||
Log::error("Options", "error parsejant config.yaml: {}", e.what());
|
||||
Log::info("Options", "reescrivint el fitxer amb defaults.");
|
||||
backupFile(g_config_file_path);
|
||||
return saveToFile();
|
||||
}
|
||||
@@ -843,7 +842,7 @@ namespace Options {
|
||||
const auto IT = std::ranges::find_if(g_crtpi_presets,
|
||||
[](const CrtPiPreset& preset) { return preset.name == g_video.shader.current_crtpi_preset; });
|
||||
if (IT == g_crtpi_presets.end()) {
|
||||
std::cout << "Options: preset CrtPi \"" << g_video.shader.current_crtpi_preset << "\" no trobat; aplicant defaults.\n";
|
||||
Log::warn("Options", "preset CrtPi \"{}\" no trobat; aplicant defaults.", g_video.shader.current_crtpi_preset);
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
@@ -871,7 +870,7 @@ namespace Options {
|
||||
const auto IT = std::ranges::find_if(g_postfx_presets,
|
||||
[](const PostFXPreset& preset) { return preset.name == g_video.shader.current_postfx_preset; });
|
||||
if (IT == g_postfx_presets.end()) {
|
||||
std::cout << "Options: preset PostFX \"" << g_video.shader.current_postfx_preset << "\" no trobat; aplicant passthrough.\n";
|
||||
Log::warn("Options", "preset PostFX \"{}\" no trobat; aplicant passthrough.", g_video.shader.current_postfx_preset);
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
@@ -41,6 +40,7 @@
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/easing.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -290,13 +290,12 @@ GameScene::GameScene(Config config)
|
||||
// re-emissions es filtren per estat per no re-entrar mai des d'una
|
||||
// transició ja en marxa.
|
||||
entity_manager_.getBus().subscribe("level_complete", [this](const Event& ev) {
|
||||
std::cout << "[LEVEL COMPLETE] player_id=" << ev.player_id << '\n';
|
||||
Log::info("LEVEL COMPLETE", "player_id={}", ev.player_id);
|
||||
if (state_ == RoomFsm::State::PLAYING) { setState(RoomFsm::State::ROOM_OUTRO); }
|
||||
});
|
||||
entity_manager_.getBus().subscribe("player_hit", [](const Event& ev) {
|
||||
const auto* dmg = std::get_if<int>(&ev.payload);
|
||||
std::cout << "[PLAYER HIT] player_id=" << ev.player_id
|
||||
<< " dmg=" << (dmg != nullptr ? *dmg : 0) << '\n';
|
||||
Log::info("PLAYER HIT", "player_id={} dmg={}", ev.player_id, dmg != nullptr ? *dmg : 0);
|
||||
});
|
||||
// `player_killed` el publica un hazard letal (mòmia amb
|
||||
// `kills_outright`) després del `player_hit`. Aquí resolem el
|
||||
@@ -556,8 +555,7 @@ void GameScene::loadRoom(const std::string& yaml_path) {
|
||||
hud_->setPyramidRoom(mgr.currentPyramid(), mgr.currentRoom());
|
||||
}
|
||||
|
||||
std::cout << "[ROOM] load " << yaml_path << ": entities reloaded, paint cleared, "
|
||||
<< ACTIVE_COUNT << " active player(s) disabled (awaiting spawn cinematic)\n";
|
||||
Log::info("ROOM", "load {}: entities reloaded, paint cleared, {} active player(s) disabled (awaiting spawn cinematic)", yaml_path, ACTIVE_COUNT);
|
||||
}
|
||||
|
||||
void GameScene::advanceToNextRoom() {
|
||||
@@ -565,7 +563,7 @@ void GameScene::advanceToNextRoom() {
|
||||
if (!mgr.advance()) {
|
||||
// Política temporal mentre no hi haja pantalla de "Fi de joc":
|
||||
// arribar al final del levels.yaml fa loop a la primera sala.
|
||||
std::cout << "[ROOM] final del levels.yaml — bucle a la primera sala\n";
|
||||
Log::info("ROOM", "final del levels.yaml — bucle a la primera sala");
|
||||
mgr.restart();
|
||||
}
|
||||
loadRoom(mgr.currentPath());
|
||||
@@ -576,9 +574,9 @@ void GameScene::enterRoomIntro() {
|
||||
// Anotem la transició al log si veníem d'un altre estat; si ja
|
||||
// estàvem a INTRO (cas típic d'un salt debug) també queda ben clar.
|
||||
if (state_ != RoomFsm::State::ROOM_INTRO) {
|
||||
std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> ROOM_INTRO\n";
|
||||
Log::info("ROOM", "{} -> ROOM_INTRO", RoomFsm::stateName(state_));
|
||||
} else {
|
||||
std::cout << "[ROOM] ROOM_INTRO restart (cinemàtica reiniciada)\n";
|
||||
Log::info("ROOM", "ROOM_INTRO restart (cinemàtica reiniciada)");
|
||||
}
|
||||
state_ = RoomFsm::State::ROOM_INTRO;
|
||||
transition_ = {};
|
||||
@@ -602,7 +600,7 @@ void GameScene::enterRoomIntro() {
|
||||
|
||||
auto* audio = Audio::get();
|
||||
if (audio == nullptr) {
|
||||
std::cout << "[ROOM] INTRO: Audio absent — sense música, timeline només contra text\n";
|
||||
Log::warn("ROOM", "INTRO: Audio absent — sense música, timeline només contra text");
|
||||
return;
|
||||
}
|
||||
audio->stopMusic();
|
||||
@@ -611,10 +609,9 @@ void GameScene::enterRoomIntro() {
|
||||
if (Audio::getMusicState() == Audio::MusicState::PLAYING) {
|
||||
const int DUR_MS = Audio::getMusicDurationMs("room_intro.ogg");
|
||||
transition_config_.intro_music_tail_ms = std::max(0, DUR_MS - TEXT_TOTAL_MS);
|
||||
std::cout << "[ROOM] INTRO: música " << DUR_MS << " ms, music_tail "
|
||||
<< transition_config_.intro_music_tail_ms << " ms\n";
|
||||
Log::info("ROOM", "INTRO: música {} ms, music_tail {} ms", DUR_MS, transition_config_.intro_music_tail_ms);
|
||||
} else {
|
||||
std::cout << "[ROOM] INTRO: música no arrencada — timeline només contra text\n";
|
||||
Log::warn("ROOM", "INTRO: música no arrencada — timeline només contra text");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +635,7 @@ void GameScene::respawnPlayersInstant() {
|
||||
state_ = RoomFsm::State::PLAYING;
|
||||
intro_completed_ = true;
|
||||
transition_ = {};
|
||||
std::cout << "[ROOM] post-editor: spawn instantani, estat -> PLAYING\n";
|
||||
Log::info("ROOM", "post-editor: spawn instantani, estat -> PLAYING");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -671,11 +668,11 @@ void GameScene::triggerPlayerSpawn(std::size_t slot_index) {
|
||||
// al YAML, l'arma queda buida i el LAND és sec igualment.
|
||||
players_[slot_index]->armNextLandReverb(transition_config_.intro_land_reverb_preset);
|
||||
|
||||
std::cout << "[ROOM] spawn cinematic P" << (slot_index + 1) << ": airborne entry\n";
|
||||
Log::info("ROOM", "spawn cinematic P{}: airborne entry", slot_index + 1);
|
||||
}
|
||||
|
||||
void GameScene::dispatchPlayerKilled(int player_id) {
|
||||
std::cout << "[PLAYER KILLED] player_id=" << player_id << '\n';
|
||||
Log::info("PLAYER KILLED", "player_id={}", player_id);
|
||||
const auto IT = std::ranges::find_if(players_, [player_id](const auto& p) {
|
||||
return p && p->getId() == player_id;
|
||||
});
|
||||
@@ -713,7 +710,7 @@ void GameScene::spawnDuePlayers() {
|
||||
|
||||
void GameScene::setState(RoomFsm::State new_state) {
|
||||
if (new_state == state_) { return; }
|
||||
std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> " << RoomFsm::stateName(new_state) << '\n';
|
||||
Log::info("ROOM", "{} -> {}", RoomFsm::stateName(state_), RoomFsm::stateName(new_state));
|
||||
state_ = new_state;
|
||||
transition_ = {};
|
||||
// Reset defensiu dels flags de cicle quan tornem a INTRO via aquest
|
||||
@@ -742,7 +739,7 @@ void GameScene::setState(RoomFsm::State new_state) {
|
||||
const int TEXT_TOTAL_MS = transition_config_.outro_text_enter_ms + transition_config_.outro_text_hold_ms + transition_config_.outro_text_exit_ms;
|
||||
transition_config_.outro_music_tail_ms = 0;
|
||||
if (audio == nullptr) {
|
||||
std::cout << "[ROOM] OUTRO: Audio absent — sense música, timeline només contra text\n";
|
||||
Log::warn("ROOM", "OUTRO: Audio absent — sense música, timeline només contra text");
|
||||
} else {
|
||||
audio->stopMusic();
|
||||
audio->setOnMusicEnded({});
|
||||
@@ -750,10 +747,9 @@ void GameScene::setState(RoomFsm::State new_state) {
|
||||
if (Audio::getMusicState() == Audio::MusicState::PLAYING) {
|
||||
const int DUR_MS = Audio::getMusicDurationMs("room_outro.ogg");
|
||||
transition_config_.outro_music_tail_ms = std::max(0, DUR_MS - TEXT_TOTAL_MS);
|
||||
std::cout << "[ROOM] OUTRO: música " << DUR_MS << " ms, music_tail "
|
||||
<< transition_config_.outro_music_tail_ms << " ms\n";
|
||||
Log::info("ROOM", "OUTRO: música {} ms, music_tail {} ms", DUR_MS, transition_config_.outro_music_tail_ms);
|
||||
} else {
|
||||
std::cout << "[ROOM] OUTRO: música no arrencada — timeline només contra text\n";
|
||||
Log::warn("ROOM", "OUTRO: música no arrencada — timeline només contra text");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1075,7 +1071,7 @@ void GameScene::handlePauseInput() {
|
||||
pause_.curve = GOING_TO_PAUSE ? UiConfig::get().pauseEnterCurve() : UiConfig::get().pauseExitCurve();
|
||||
pause_.state = GOING_TO_PAUSE ? PauseState::ENTERING : PauseState::EXITING;
|
||||
|
||||
std::cout << "[PAUSE] " << (GOING_TO_PAUSE ? "entering" : "exiting") << " from_scale=" << pause_.from_scale << " duration_ms=" << pause_.duration_ms << '\n';
|
||||
Log::info("PAUSE", "{} from_scale={} duration_ms={}", GOING_TO_PAUSE ? "entering" : "exiting", pause_.from_scale, pause_.duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1212,7 +1208,7 @@ void GameScene::update(int delta_ms) {
|
||||
// (creuar → player_exited → level_complete → OUTRO) es manté.
|
||||
// Mateixos gates que el salt entre sales.
|
||||
if (pause_.state == PauseState::IDLE && !editor_.active() && detectOpenDoor()) {
|
||||
std::cout << "[DEBUG] força obertura de la porta\n";
|
||||
Log::info("DEBUG", "força obertura de la porta");
|
||||
entity_manager_.forceOpenDoor();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -20,13 +19,12 @@
|
||||
#include "game/scenes/scene_flow.hpp"
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int NAME_Y_OFFSET = -8;
|
||||
constexpr int TIMER_Y_OFFSET = 8;
|
||||
// TODO: migrar a un logger unificat quan es decideixi (veure INC-03 a
|
||||
// docs/audit-core-rendering.md).
|
||||
const char* const SCENE_NAME = "INTRO";
|
||||
|
||||
} // namespace
|
||||
@@ -34,7 +32,7 @@ namespace {
|
||||
IntroScene::IntroScene(std::shared_ptr<Text> font, DebugConfig::StartingPlayers starting_players)
|
||||
: font_(std::move(font)),
|
||||
starting_players_(starting_players) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " start (players=" << DebugConfig::toString(starting_players_) << ")\n";
|
||||
Log::info("scene", "{} start (players={})", SCENE_NAME, DebugConfig::toString(starting_players_));
|
||||
}
|
||||
|
||||
IntroScene::~IntroScene() = default;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "core/audio/audio.hpp"
|
||||
@@ -19,19 +18,17 @@
|
||||
#include "game/scenes/placeholder_input.hpp"
|
||||
#include "game/scenes/scene_flow.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: migrar a un logger unificat quan es decideixi (veure INC-03 a
|
||||
// docs/audit-core-rendering.md). De moment std::cout per rastrejar el
|
||||
// flux d'escenes als smoke runs.
|
||||
const char* const SCENE_NAME = "LOGO";
|
||||
|
||||
} // namespace
|
||||
|
||||
LogoScene::LogoScene(std::shared_ptr<Surface> logo, bool reset)
|
||||
: logo_(std::move(logo)) {
|
||||
std::cout << "[scene] " << SCENE_NAME << (reset ? " start (reset)\n" : " start\n");
|
||||
Log::info("scene", "{} start{}", SCENE_NAME, reset ? " (reset)" : "");
|
||||
if (reset) {
|
||||
if (auto* audio = Audio::get(); audio != nullptr) {
|
||||
audio->stopMusic();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "game/scenes/room_fsm.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
|
||||
#include "core/locale/locale.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace RoomFsm {
|
||||
|
||||
auto bytes = Resource::Helper::loadFile(yaml_path);
|
||||
if (bytes.empty()) {
|
||||
std::cout << "RoomFsm: " << yaml_path << " absent — uso fallbacks compilats\n";
|
||||
Log::warn("RoomFsm", "{} absent — uso fallbacks compilats", yaml_path);
|
||||
return cfg;
|
||||
}
|
||||
const auto* begin = reinterpret_cast<const char*>(bytes.data());
|
||||
@@ -83,9 +83,7 @@ namespace RoomFsm {
|
||||
cfg.text_panel_height_px = readChildInt(n, "height_px", cfg.text_panel_height_px);
|
||||
}
|
||||
|
||||
std::cout << "RoomFsm: timings carregats des de " << yaml_path
|
||||
<< " (intro fade " << cfg.intro_fade_in_ms
|
||||
<< "ms, outro fade " << cfg.outro_fade_out_ms << "ms)\n";
|
||||
Log::info("RoomFsm", "timings carregats des de {} (intro fade {}ms, outro fade {}ms)", yaml_path, cfg.intro_fade_in_ms, cfg.outro_fade_out_ms);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -26,6 +25,7 @@
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/easing.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -72,7 +72,7 @@ TitleScene::TitleScene(std::shared_ptr<Text> condensed_font, std::shared_ptr<Tex
|
||||
game_logo_(std::move(game_logo)),
|
||||
mini_logo_(std::move(mini_logo)),
|
||||
timer_ms_(UiConfig::get().titleDurationMs()) {
|
||||
std::cout << "[scene] " << SCENE_NAME << " start\n";
|
||||
Log::info("scene", "{} start", SCENE_NAME);
|
||||
const auto& hh = UiConfig::get().titleHeatHaze();
|
||||
if (hh.enabled) {
|
||||
heat_haze_.emplace(Effects::HeatHaze::Params{
|
||||
@@ -190,7 +190,7 @@ void TitleScene::enterStarting(DebugConfig::StartingPlayers players) {
|
||||
if (auto* audio = Audio::get(); audio != nullptr) {
|
||||
audio->fadeOutMusic(UiConfig::get().titleMusicFadeOutMs());
|
||||
}
|
||||
std::cout << "[scene] " << SCENE_NAME << " STARTING (players=" << DebugConfig::toString(players) << ")\n";
|
||||
Log::info("scene", "{} STARTING (players={})", SCENE_NAME, DebugConfig::toString(players));
|
||||
}
|
||||
|
||||
void TitleScene::tickIdle(int delta_ms, bool p1_start, bool p2_start) {
|
||||
@@ -255,7 +255,7 @@ void TitleScene::enterAttract() {
|
||||
if (attract_fade_) {
|
||||
attract_fade_->begin(UiConfig::get().titleAttractFadeToBlackMs());
|
||||
}
|
||||
std::cout << "[scene] " << SCENE_NAME << " ATTRACT_OUT\n";
|
||||
Log::info("scene", "{} ATTRACT_OUT", SCENE_NAME);
|
||||
}
|
||||
|
||||
void TitleScene::advanceToIntro(DebugConfig::StartingPlayers players) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
@@ -19,6 +18,7 @@
|
||||
#include "utils/defaults.hpp"
|
||||
#include "utils/defines.hpp"
|
||||
#include "utils/easing.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -127,17 +127,16 @@ Hud::Hud(EventBus& bus, std::shared_ptr<Text> font)
|
||||
blk.flash_ms_left = UiConfig::get().hudFlashMs();
|
||||
blk.shake_ms_left = UiConfig::get().hudShakeMs();
|
||||
blk.shake_intensity = 1.5F;
|
||||
std::cout << "[HUD] player_hit p" << (IDX + 1) << " dmg=" << (dmg != nullptr ? *dmg : 0)
|
||||
<< " lives=" << players_[IDX].lives << '\n';
|
||||
Log::info("HUD", "player_hit p{} dmg={} lives={}", IDX + 1, dmg != nullptr ? *dmg : 0, players_[IDX].lives);
|
||||
}));
|
||||
|
||||
subs_.push_back(bus_.subscribe("level_complete", [](const Event& /*ev*/) {
|
||||
// TODO: capturar `this` i cridar setMode(*, Mode::Win) per als
|
||||
// tres blocs quan el mode Win estiga implementat.
|
||||
std::cout << "[HUD] level_complete (mode Win pendent)\n";
|
||||
Log::info("HUD", "level_complete (mode Win pendent)");
|
||||
}));
|
||||
|
||||
std::cout << "[HUD] init: 3 blocks ready (entry " << ENTRY_MS << " ms)\n";
|
||||
Log::info("HUD", "init: 3 blocks ready (entry {} ms)", ENTRY_MS);
|
||||
}
|
||||
|
||||
Hud::~Hud() {
|
||||
|
||||
+6
-3
@@ -3,18 +3,21 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "core/system/director.hpp"
|
||||
#include "core/system/event_buffer.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
// Logger primer de tot perquè l'arrencada del Director ja emet logs.
|
||||
Log::init();
|
||||
// Marcador d'inici: ha de ser la PRIMERA línia de log del programa.
|
||||
std::cout << "Game start\n";
|
||||
// `raw` per emetre el text pelat sense el prefix "tag: ".
|
||||
Log::raw(Log::Level::INFO, "Game start");
|
||||
|
||||
// Construïm el Director amb make_unique i l'entreguem en cru a SDL.
|
||||
// El SDL_AppQuit reclamarà la propietat amb un altre unique_ptr (RAII).
|
||||
@@ -43,5 +46,5 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
||||
std::unique_ptr<Director> director(static_cast<Director*>(appstate));
|
||||
}
|
||||
// Marcador de fi: ha de ser l'ÚLTIMA línia de log del programa.
|
||||
std::cout << "Bye!\n";
|
||||
Log::raw(Log::Level::INFO, "Bye!");
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Log {
|
||||
|
||||
namespace {
|
||||
|
||||
std::mutex g_mutex;
|
||||
std::unordered_map<std::string, int> g_categories;
|
||||
int g_next_category = SDL_LOG_CATEGORY_CUSTOM;
|
||||
// Prioritat per defecte aplicada a tota CUSTOM nova. Es modifica només
|
||||
// si l'usuari ha posat `*:level` (o un nivell pelat) a AEE_LOG.
|
||||
SDL_LogPriority g_default_priority = SDL_LOG_PRIORITY_INFO;
|
||||
|
||||
auto categoryFor(std::string_view tag) -> int {
|
||||
std::lock_guard lk{g_mutex};
|
||||
const std::string KEY{tag};
|
||||
auto it = g_categories.find(KEY);
|
||||
if (it != g_categories.end()) { return it->second; }
|
||||
const int CAT = g_next_category++;
|
||||
g_categories.emplace(KEY, CAT);
|
||||
// Cada categoria CUSTOM neix amb la prioritat default de l'app
|
||||
// (sense aquesta línia, SDL retorna ERROR per a qualsevol CUSTOM
|
||||
// no inicialitzada, silenciant els nostres `info`).
|
||||
SDL_SetLogPriority(CAT, g_default_priority);
|
||||
return CAT;
|
||||
}
|
||||
|
||||
auto toSDL(Level lvl) -> SDL_LogPriority {
|
||||
switch (lvl) {
|
||||
case Level::TRACE:
|
||||
return SDL_LOG_PRIORITY_TRACE;
|
||||
case Level::DEBUG:
|
||||
return SDL_LOG_PRIORITY_DEBUG;
|
||||
case Level::INFO:
|
||||
return SDL_LOG_PRIORITY_INFO;
|
||||
case Level::WARN:
|
||||
return SDL_LOG_PRIORITY_WARN;
|
||||
case Level::ERROR:
|
||||
return SDL_LOG_PRIORITY_ERROR;
|
||||
case Level::CRITICAL:
|
||||
return SDL_LOG_PRIORITY_CRITICAL;
|
||||
}
|
||||
return SDL_LOG_PRIORITY_INFO;
|
||||
}
|
||||
|
||||
// Parser tolerant de noms de prioritat. Sinònims acceptats per costum:
|
||||
// verbose↔debug, warning↔warn, err↔error, fatal/crit↔critical.
|
||||
auto parsePriority(std::string_view s) -> SDL_LogPriority {
|
||||
std::string lower(s.size(), '\0');
|
||||
std::ranges::transform(s, lower.begin(), [](char c) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
});
|
||||
if (lower == "trace") { return SDL_LOG_PRIORITY_TRACE; }
|
||||
if (lower == "debug" || lower == "verbose") { return SDL_LOG_PRIORITY_DEBUG; }
|
||||
if (lower == "info") { return SDL_LOG_PRIORITY_INFO; }
|
||||
if (lower == "warn" || lower == "warning") { return SDL_LOG_PRIORITY_WARN; }
|
||||
if (lower == "error" || lower == "err") { return SDL_LOG_PRIORITY_ERROR; }
|
||||
if (lower == "critical" || lower == "crit" || lower == "fatal") {
|
||||
return SDL_LOG_PRIORITY_CRITICAL;
|
||||
}
|
||||
return SDL_LOG_PRIORITY_INFO;
|
||||
}
|
||||
|
||||
auto trim(std::string_view s) -> std::string_view {
|
||||
while (!s.empty() && (std::isspace(static_cast<unsigned char>(s.front())) != 0)) {
|
||||
s.remove_prefix(1);
|
||||
}
|
||||
while (!s.empty() && (std::isspace(static_cast<unsigned char>(s.back())) != 0)) {
|
||||
s.remove_suffix(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Itera entrades d'una especificació AEE_LOG separades per `,`,
|
||||
// saltant les buides.
|
||||
template <typename Fn>
|
||||
void forEachEntry(std::string_view spec, Fn fn) {
|
||||
std::size_t i = 0;
|
||||
while (i <= spec.size()) {
|
||||
const std::size_t COMMA = spec.find(',', i);
|
||||
const std::size_t END = (COMMA == std::string_view::npos) ? spec.size() : COMMA;
|
||||
const std::string_view ENTRY = trim(spec.substr(i, END - i));
|
||||
i = (COMMA == std::string_view::npos) ? spec.size() + 1 : COMMA + 1;
|
||||
if (!ENTRY.empty()) { fn(ENTRY); }
|
||||
}
|
||||
}
|
||||
|
||||
// Una entrada AEE_LOG global aplica a totes les categories (SDL i
|
||||
// CUSTOM). Forma curta `level` ↔ tag explícit `*:level`.
|
||||
void applyGlobalEntry(std::string_view entry) {
|
||||
const std::size_t COLON = entry.rfind(':');
|
||||
const bool IS_BARE = (COLON == std::string_view::npos);
|
||||
const std::string_view TAG =
|
||||
IS_BARE ? std::string_view{} : trim(entry.substr(0, COLON));
|
||||
if (!IS_BARE && TAG != "*" && !TAG.empty()) { return; }
|
||||
const SDL_LogPriority PRIO =
|
||||
parsePriority(IS_BARE ? entry : trim(entry.substr(COLON + 1)));
|
||||
SDL_SetLogPriorities(PRIO);
|
||||
g_default_priority = PRIO;
|
||||
}
|
||||
|
||||
// Override per tag concret (sobreescriu el global per a aquesta
|
||||
// categoria). Si la categoria és nova es registra al vol.
|
||||
void applyTagEntry(std::string_view entry) {
|
||||
const std::size_t COLON = entry.rfind(':');
|
||||
if (COLON == std::string_view::npos) { return; }
|
||||
const std::string_view TAG = trim(entry.substr(0, COLON));
|
||||
if (TAG == "*" || TAG.empty()) { return; }
|
||||
const SDL_LogPriority PRIO = parsePriority(trim(entry.substr(COLON + 1)));
|
||||
SDL_SetLogPriority(categoryFor(TAG), PRIO);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void log(Level lvl, std::string_view tag, std::string_view msg) {
|
||||
// `"%s"` + cos com a argument: si `msg` conté `%` (rar però possible
|
||||
// en paths o rutes amb urlencoded), no s'interpreta com a format spec.
|
||||
const std::string BODY = std::format("{}: {}", tag, msg);
|
||||
SDL_LogMessage(categoryFor(tag), toSDL(lvl), "%s", BODY.c_str());
|
||||
}
|
||||
|
||||
void raw(Level lvl, std::string_view msg) {
|
||||
const std::string TEXT{msg};
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, toSDL(lvl), "%s", TEXT.c_str());
|
||||
}
|
||||
|
||||
void init() {
|
||||
// No toquem cap categoria SDL nativa per defecte: així preservem el
|
||||
// silenci de SDL_LOG_CATEGORY_GPU, RENDER, etc. (default = ERROR), i
|
||||
// només el que arriba via Log::* es veu, mantenint l'output històric.
|
||||
g_default_priority = SDL_LOG_PRIORITY_INFO;
|
||||
|
||||
const char* env = std::getenv("AEE_LOG");
|
||||
if (env == nullptr || *env == '\0') { return; }
|
||||
|
||||
// Tags poden contenir `::` (p. ex. `Resource::Helper`); busquem el
|
||||
// separador amb rfind. Dues passades per fer l'override per-tag
|
||||
// insensible a l'ordre (`Tag:debug,*:warn` deixa Tag a debug).
|
||||
const std::string_view SPEC{env};
|
||||
forEachEntry(SPEC, applyGlobalEntry);
|
||||
forEachEntry(SPEC, applyTagEntry);
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
// Logger lleuger embolicant `SDL_Log*`. Una sola entrada per nivell, format
|
||||
// type-safe via `std::format`. Filtre runtime amb la variable d'entorn
|
||||
// AEE_LOG (sintaxi `*:info,Resource::Helper:warn,scene:debug`). Ús típic:
|
||||
//
|
||||
// Log::info("Resource::Helper", "pack loaded ({} entries)", n);
|
||||
// Log::warn("Options", "preset \"{}\" no trobat; aplicant defaults.", name);
|
||||
// Log::error("Director", "no s'ha pogut carregar config.yaml a {}", path);
|
||||
//
|
||||
namespace Log {
|
||||
|
||||
enum class Level : std::uint8_t {
|
||||
TRACE,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR,
|
||||
CRITICAL,
|
||||
};
|
||||
|
||||
// Llig AEE_LOG i configura les prioritats SDL. Crida una sola vegada,
|
||||
// tan aviat com sigui possible (abans del primer `Log::*`).
|
||||
void init();
|
||||
|
||||
// Backend usat per les funcions per nivell. Composa "tag: msg" i ho
|
||||
// entrega a SDL_LogMessage amb la categoria registrada per al tag.
|
||||
void log(Level lvl, std::string_view tag, std::string_view msg);
|
||||
|
||||
// Variant sense prefix de tag — ús reservat per a marcadors literals
|
||||
// (p. ex. "Game start" / "Bye!"). Cau a SDL_LOG_CATEGORY_APPLICATION,
|
||||
// així AEE_LOG global encara els pot silenciar.
|
||||
void raw(Level lvl, std::string_view msg);
|
||||
|
||||
template <typename... Args>
|
||||
void trace(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::TRACE, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename... Args>
|
||||
void debug(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::DEBUG, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename... Args>
|
||||
void info(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::INFO, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename... Args>
|
||||
void warn(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::WARN, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename... Args>
|
||||
void error(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::ERROR, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename... Args>
|
||||
void critical(std::string_view tag, std::format_string<Args...> fmt, Args&&... args) {
|
||||
log(Level::CRITICAL, tag, std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
+13
-9
@@ -1,18 +1,22 @@
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "utils/log.hpp"
|
||||
|
||||
auto getFileName(const std::string& path) -> std::string {
|
||||
return std::filesystem::path(path).filename().string();
|
||||
}
|
||||
|
||||
void printWithDots(const std::string& text1, const std::string& text2, const std::string& text3) {
|
||||
std::cout.setf(std::ios::left, std::ios::adjustfield);
|
||||
std::cout << text1;
|
||||
std::cout.width(50 - text1.length() - text3.length());
|
||||
std::cout.fill('.');
|
||||
std::cout << text2;
|
||||
std::cout << text3 << '\n';
|
||||
void printWithDots(const std::string& tag, const std::string& filename, const std::string& status) {
|
||||
// Reprodueix l'alineació històrica (amplada total ≈ 50). El logger anteposa
|
||||
// automàticament "tag: ", per això aquí només componem el cos.
|
||||
constexpr std::size_t TOTAL_WIDTH = 50;
|
||||
const std::size_t PREFIX_LEN = tag.size() + 2; // "{tag}: "
|
||||
const std::size_t USED = PREFIX_LEN + status.size();
|
||||
const std::size_t FIELD = (USED < TOTAL_WIDTH) ? (TOTAL_WIDTH - USED) : 0;
|
||||
std::string body = filename;
|
||||
if (body.size() < FIELD) { body.resize(FIELD, '.'); }
|
||||
Log::info(tag, "{}{}", body, status);
|
||||
}
|
||||
@@ -3,4 +3,6 @@
|
||||
#include <string>
|
||||
|
||||
auto getFileName(const std::string& path) -> std::string;
|
||||
void printWithDots(const std::string& text1, const std::string& text2, const std::string& text3);
|
||||
// Línia de càrrega amb alineació de punts: "{tag}: filename..........{status}".
|
||||
// Embolcalla `Log::info`, amb la qual cosa respecta `AEE_LOG`.
|
||||
void printWithDots(const std::string& tag, const std::string& filename, const std::string& status);
|
||||
Reference in new issue
Block a user