Files
Hat Kid a5ef456e8b loader: allow manual reload of fr3 data (#4304)
This adds some buttons to the loader debug menu and GOAL functions to
allow you to manually force a reload of a level's FR3 data (including
the common level), allowing for live texture replacements, model swaps
and custom level modifications without requiring a game restart or
waiting for the loader to fully discard a level.
2026-06-07 16:45:33 +02:00

77 lines
2.7 KiB
C++

#pragma once
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include "common/custom_data/Tfrag3Data.h"
#include "common/util/FileUtil.h"
#include "common/util/Timer.h"
#include "game/graphics/opengl_renderer/loader/common.h"
#include "game/graphics/texture/TexturePool.h"
class Loader {
public:
static constexpr float TIE_LOAD_BUDGET = 1.5f;
static constexpr float SHARED_TEXTURE_LOAD_BUDGET = 3.f;
Loader(const fs::path& base_path, int max_levels);
~Loader();
void update(TexturePool& tex_pool);
void update_blocking(TexturePool& tex_pool);
const LevelData* get_tfrag3_level(const std::string& level_name);
std::optional<MercRef> get_merc_model(const char* model_name);
const tfrag3::Level& load_common(TexturePool& tex_pool, const std::string& name);
void set_want_levels(const std::vector<std::string>& levels);
void set_active_levels(const std::vector<std::string>& levels);
std::vector<LevelData*> get_in_use_levels();
void draw_debug_window();
void debug_print_loaded_levels();
void request_reload_all() { m_want_reload = true; }
void request_reload_level(const std::string& name) { m_single_level_to_reload = name; }
void request_reload_common() { m_want_reload_common = true; }
private:
void loader_thread();
bool upload_textures(Timer& timer, LevelData& data, TexturePool& texture_pool);
const std::string* get_most_unloadable_level();
void unload_level_data(const std::string& name, LevelData& lev, TexturePool& tex_pool);
void do_reload(TexturePool& tex_pool);
void do_reload_common(TexturePool& tex_pool);
void do_reload_level(const std::string& name, TexturePool& tex_pool);
// used by game and loader thread
std::unordered_map<std::string, std::unique_ptr<LevelData>> m_initializing_tfrag3_levels;
LevelData m_common_level;
std::string m_level_to_load;
std::thread m_loader_thread;
std::mutex m_loader_mutex;
std::condition_variable m_loader_cv;
std::condition_variable m_file_load_done_cv;
bool m_want_shutdown = false;
std::atomic<bool> m_want_reload{false};
std::atomic<bool> m_want_reload_common{false};
std::string m_single_level_to_reload;
std::string m_selected_level_for_reload;
uint64_t m_id = 0;
// used only by game thread
std::unordered_map<std::string, std::unique_ptr<LevelData>> m_loaded_tfrag3_levels;
std::unordered_map<std::string, std::vector<MercRef>> m_all_merc_models;
std::vector<std::string> m_desired_levels;
std::vector<std::string> m_active_levels;
std::vector<std::unique_ptr<LoaderStage>> m_loader_stages;
std::vector<GLuint> m_garbage_textures;
std::vector<GLuint> m_garbage_buffers;
fs::path m_base_path;
int m_max_levels = 0;
};