feat: Implement lazy loading for dungeon rooms and refactor room graphics handling

- Introduced lazy loading for room data to optimize performance and reduce initial load times.
- Updated DungeonEditor and DungeonRoomLoader to handle room graphics rendering directly from room objects.
- Refactored methods to accept room references instead of IDs for better clarity and type safety.
- Enhanced tab management in the DungeonEditor UI for improved user experience.
This commit is contained in:
scawful
2025-10-04 15:14:17 -04:00
parent 5bb696e431
commit 28dc394a7c
19 changed files with 799 additions and 468 deletions

109
src/util/log.cc Normal file
View File

@@ -0,0 +1,109 @@
#include "util/log.h"
#include <chrono>
#include <iomanip>
#include <iostream>
namespace yaze {
namespace util {
// Helper function to convert LogLevel enum to a string representation.
static const char* LogLevelToString(LogLevel level) {
switch (level) {
case LogLevel::YAZE_DEBUG:
return "YAZE_DEBUG";
case LogLevel::INFO:
return "INFO";
case LogLevel::WARNING:
return "WARN";
case LogLevel::ERROR:
return "ERROR";
case LogLevel::FATAL:
return "FATAL";
}
return "UNKN";
}
// --- LogManager Implementation ---
LogManager& LogManager::instance() {
static LogManager instance;
return instance;
}
LogManager::LogManager()
: min_level_(LogLevel::INFO), all_categories_enabled_(true) {}
LogManager::~LogManager() {
if (log_stream_.is_open()) {
log_stream_.close();
}
}
void LogManager::configure(LogLevel level, const std::string& file_path,
const std::set<std::string>& categories) {
min_level_.store(level);
if (categories.empty()) {
all_categories_enabled_.store(true);
enabled_categories_.clear();
} else {
all_categories_enabled_.store(false);
enabled_categories_ = categories;
}
// If a file path is provided, close any existing stream and open the new file.
if (!file_path.empty() && file_path != log_file_path_) {
if (log_stream_.is_open()) {
log_stream_.close();
}
// Open in append mode to preserve history.
log_stream_.open(file_path, std::ios::out | std::ios::app);
log_file_path_ = file_path;
}
}
void LogManager::log(LogLevel level, absl::string_view category,
absl::string_view message) {
// 1. Filter by log level.
if (level < min_level_.load()) {
return;
}
// 2. Filter by category.
if (!all_categories_enabled_.load()) {
if (enabled_categories_.find(std::string(category)) ==
enabled_categories_.end()) {
return;
}
}
// 3. Format the complete log message.
// [HH:MM:SS.ms] [LEVEL] [category] message
auto now = std::chrono::system_clock::now();
auto now_tt = std::chrono::system_clock::to_time_t(now);
auto now_tm = *std::localtime(&now_tt);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) %
1000;
std::string final_message = absl::StrFormat(
"[%02d:%02d:%02d.%03d] [%-5s] [%s] %s\n", now_tm.tm_hour, now_tm.tm_min,
now_tm.tm_sec, ms.count(), LogLevelToString(level), category, message);
// 4. Write to the configured sink (file or stderr).
if (log_stream_.is_open()) {
log_stream_ << final_message;
log_stream_.flush(); // Ensure immediate write for debugging.
} else {
std::cerr << final_message;
}
// 5. Abort on FATAL error.
if (level == LogLevel::FATAL) {
std::abort();
}
}
} // namespace util
} // namespace yaze

View File

@@ -1,20 +1,26 @@
#ifndef YAZE_UTIL_LOG_H
#define YAZE_UTIL_LOG_H
#include <atomic>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
#include "app/core/features.h"
#include "absl/strings/string_view.h"
namespace yaze {
namespace util {
static std::string g_log_file_path = "yaze_log.txt";
// Static variables for library state
static std::string g_log_file_path = "";
// Set custom log file path
inline void SetLogFile(const std::string& filepath) {
@@ -50,7 +56,91 @@ static void logf(const absl::FormatSpec<Args...> &format, const Args &...args) {
fout.flush(); // Ensure immediate write for debugging
}
/**
* @enum LogLevel
* @brief Defines the severity levels for log messages.
* This allows for filtering messages based on their importance.
*/
enum class LogLevel { YAZE_DEBUG, INFO, WARNING, ERROR, FATAL };
/**
* @class LogManager
* @brief A singleton that manages all logging configuration and output.
*
* It is designed to be configured once at application startup, typically from
* command-line arguments. It supports filtering by level and category, and can
* direct output to stderr (default) or a specified file.
*/
class LogManager {
public:
// Singleton access
static LogManager& instance();
// Deleted constructors for singleton pattern
LogManager(const LogManager&) = delete;
void operator=(const LogManager&) = delete;
/**
* @brief Configures the logging system.
* @param level The minimum log level to record.
* @param file_path The path to the log file. If empty, logs to stderr.
* @param categories A set of specific categories to enable. If empty, all
* categories are enabled.
*/
void configure(LogLevel level, const std::string& file_path,
const std::set<std::string>& categories);
/**
* @brief The primary logging function.
* @param level The severity level of the message.
* @param category The category of the message (e.g., "Graphics", "Agent").
* @param message The formatted log message.
*/
void log(LogLevel level, absl::string_view category,
absl::string_view message);
private:
LogManager();
~LogManager();
// Configuration state
std::atomic<LogLevel> min_level_;
std::set<std::string> enabled_categories_;
std::atomic<bool> all_categories_enabled_;
// Output sink
std::ofstream log_stream_;
std::string log_file_path_;
};
// logf mapping
#define logf LOG_INFO
// --- Public Logging Macros ---
// These macros provide a convenient and efficient API for logging.
// The `do-while(0)` loop ensures they behave like a single statement.
// The level check avoids the cost of string formatting if the message won't be
// logged.
#define LOG(level, category, format, ...) \
do { \
yaze::util::LogManager::instance().log( \
level, category, absl::StrFormat(format, ##__VA_ARGS__)); \
} while (0)
#define LOG_DEBUG(category, format, ...) \
LOG(yaze::util::LogLevel::YAZE_DEBUG, category, format, ##__VA_ARGS__)
#define LOG_INFO(category, format, ...) \
LOG(yaze::util::LogLevel::INFO, category, format, ##__VA_ARGS__)
#define LOG_WARN(category, format, ...) \
LOG(yaze::util::LogLevel::WARNING, category, format, ##__VA_ARGS__)
#define LOG_ERROR(category, format, ...) \
LOG(yaze::util::LogLevel::ERROR, category, format, ##__VA_ARGS__)
#define LOG_FATAL(category, format, ...) \
LOG(yaze::util::LogLevel::FATAL, category, format, ##__VA_ARGS__)
} // namespace util
} // namespace yaze
#endif // YAZE_UTIL_LOG_H
#endif // YAZE_UTIL_LOG_H

View File

@@ -14,6 +14,7 @@ set(YAZE_UTIL_SRC
util/bps.cc
util/flag.cc
util/hex.cc
util/log.cc
)
add_library(yaze_util STATIC ${YAZE_UTIL_SRC})