diff --git a/src/mods/vr/CVarManager.cpp b/src/mods/vr/CVarManager.cpp index 17bbe8a7..1d2b75d0 100644 --- a/src/mods/vr/CVarManager.cpp +++ b/src/mods/vr/CVarManager.cpp @@ -20,6 +20,7 @@ constexpr std::string_view cvars_standard_txt_name = "cvars_standard.txt"; constexpr std::string_view cvars_data_txt_name = "cvars_data.txt"; +constexpr std::string_view user_script_txt_name = "user_script.txt"; CVarManager::CVarManager() { ZoneScopedN(__FUNCTION__); @@ -85,6 +86,11 @@ void CVarManager::on_pre_engine_tick(sdk::UGameEngine* engine, float delta) { cvar->update(); cvar->freeze(); } + + if(m_should_execute_console_script) { + execute_console_script(engine, user_script_txt_name.data()); + m_should_execute_console_script = false; + } } void CVarManager::on_draw_ui() { @@ -168,6 +174,9 @@ void CVarManager::on_config_load(const utility::Config& cfg, bool set_defaults) } // TODO: Add arbitrary cvars from the other configs the user can add. + + // calling UEngine::exec here causes a crash, defer to on_pre_engine_tick() + m_should_execute_console_script = true; } void CVarManager::dump_commands() { @@ -758,4 +767,66 @@ void CVarManager::CVarData::draw_ui() try { } } catch (...) { ImGui::TextWrapped("Failed to read cvar data: %s", utility::narrow(m_name).c_str()); -} \ No newline at end of file +} + +static inline void trim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); +} + +void CVarManager::execute_console_script(sdk::UGameEngine* engine, const std::string& filename) { + ZoneScopedN(__FUNCTION__); + + if(!engine) { + spdlog::error("[execute_console_script] engine is null"); + return; + } + + spdlog::info("[execute_console_script] Loading {}...", filename); + + const auto cscript_txt = Framework::get_persistent_dir(filename); + + if (!std::filesystem::exists(cscript_txt)) { + return; + } + + std::ifstream cscript_file(utility::widen(cscript_txt.string())); + + if (!cscript_file) { + spdlog::error("[execute_console_script] Failed to open file {}...", filename); + return; + } + + for (std::string line{}; getline(cscript_file, line); ) { + trim(line); + + // handle comments + if(line.starts_with('#') || line.starts_with(';')) { + continue; + } + + if(line.contains('#')) { + line = line.substr(0, line.find_first_of('#')); + trim(line); + } + + if(line.contains(';')) { + line = line.substr(0, line.find_first_of(';')); + trim(line); + } + + if(line.length() == 0) { + continue; + } + + spdlog::debug("[execute_console_script] Attempting to execute \"{}\"", line); + engine->exec(utility::widen(line)); + } + + spdlog::debug("[execute_console_script] done"); +} diff --git a/src/mods/vr/CVarManager.hpp b/src/mods/vr/CVarManager.hpp index d683d328..94d94b5e 100644 --- a/src/mods/vr/CVarManager.hpp +++ b/src/mods/vr/CVarManager.hpp @@ -23,6 +23,8 @@ class CVarManager final : public ModComponent { void dump_commands(); void spawn_console(); + void execute_console_script(sdk::UGameEngine* engine, const std::string& filename); + bool is_hzbo_frozen_and_enabled() const { if (m_hzbo == nullptr) { return false; @@ -194,6 +196,7 @@ class CVarManager final : public ModComponent { bool m_wants_display_console{false}; bool m_native_console_spawned{false}; + bool m_should_execute_console_script{false}; static inline std::vector> s_default_standard_cvars { // Bools