Skip to content

Commit a2025ed

Browse files
authored
Console window improvement (#1753)
* Don't let console steal focus from the game * Print all lua log to debug console + allow spawn debug console at startup
1 parent 995f20d commit a2025ed

5 files changed

Lines changed: 64 additions & 17 deletions

File tree

csharp-api/REFrameworkNET/Plugin.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,21 @@ using namespace System;
2121
using namespace System::Runtime;
2222

2323
extern "C" __declspec(dllexport) bool reframework_plugin_initialize(const REFrameworkPluginInitializeParam* param) {
24+
HWND prev = GetForegroundWindow();
25+
2426
// Create a console
2527
AllocConsole();
2628

29+
HWND console = GetConsoleWindow();
30+
31+
ShowWindow(console, SW_HIDE);
32+
ShowWindow(console, SW_SHOWNOACTIVATE);
33+
34+
if (prev)
35+
{
36+
SetForegroundWindow(prev);
37+
}
38+
2739
return REFrameworkNET::PluginManager::Entry(param);
2840
}
2941

src/REFramework.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <Dbt.h>
1010

1111
#include <spdlog/sinks/basic_file_sink.h>
12+
#include <spdlog/sinks/dist_sink.h>
13+
#include <spdlog/sinks/wincolor_sink.h>
14+
#include <spdlog/sinks/msvc_sink.h>
1215

1316
// minhook, used for AllocateBuffer
1417
extern "C" {
@@ -255,6 +258,9 @@ REFramework::REFramework(HMODULE reframework_module)
255258
{
256259

257260
s_reframework_module = reframework_module;
261+
m_dist_sink = std::make_shared<spdlog::sinks::dist_sink_mt>();
262+
263+
m_logger->sinks().push_back(m_dist_sink);
258264

259265
std::scoped_lock __{m_startup_mutex};
260266
const auto& gi = sdk::GameIdentity::get();
@@ -2536,3 +2542,21 @@ void REFramework::deinit_d3d12() {
25362542
ImGui::GetIO().BackendRendererUserData = nullptr;
25372543
m_d3d12 = {};
25382544
}
2545+
2546+
void REFramework::open_console() {
2547+
if (m_console_setup) {
2548+
SetForegroundWindow(GetConsoleWindow());
2549+
return;
2550+
}
2551+
2552+
AllocConsole();
2553+
2554+
std::shared_ptr<spdlog::sinks::dist_sink_mt> dist_sink = std::static_pointer_cast<spdlog::sinks::dist_sink_mt>(m_dist_sink);
2555+
dist_sink->add_sink(std::make_shared<spdlog::sinks::wincolor_stdout_sink_st>());
2556+
dist_sink->add_sink(std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>());
2557+
dist_sink->add_sink(std::make_shared<spdlog::sinks::msvc_sink_mt>());
2558+
2559+
SetForegroundWindow(GetConsoleWindow());
2560+
2561+
m_console_setup = true;
2562+
}

src/REFramework.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class REFramework {
160160
}
161161

162162
private:
163-
void save_config();
163+
void save_config();
164164
void consume_input();
165165
void init_fonts();
166166
void invalidate_device_objects();
@@ -171,6 +171,7 @@ class REFramework {
171171
public:
172172
bool hook_d3d11();
173173
bool hook_d3d12();
174+
void open_console();
174175

175176
private:
176177
bool initialize();
@@ -239,6 +240,7 @@ class REFramework {
239240
std::unique_ptr<WindowsMessageHook> m_windows_message_hook;
240241
std::unique_ptr<DInputHook> m_dinput_hook;
241242
std::shared_ptr<spdlog::logger> m_logger;
243+
spdlog::sink_ptr m_dist_sink;
242244
Patch::Ptr m_set_cursor_pos_patch{};
243245

244246
std::string m_error{""};
@@ -259,6 +261,7 @@ class REFramework {
259261

260262
bool m_sent_message{false};
261263
bool m_message_hook_requested{false};
264+
bool m_console_setup{false};
262265

263266
RendererType m_renderer_type{RendererType::D3D11};
264267

src/mods/ScriptRunner.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ void error(const char* str) {
4949
}
5050

5151
void debug(const char* str) {
52-
OutputDebugString(str);
53-
fprintf(stderr, "%s\n", str);
5452
spdlog::debug(str);
5553
}
5654
}
@@ -956,6 +954,18 @@ void ScriptRunner::hook_battle_rule() {
956954
}
957955

958956
void ScriptRunner::on_frame() {
957+
if (!m_console_startup_checked) {
958+
// Delay because C# API hides it
959+
if (m_console_startup_delay_frames > 0) {
960+
m_console_startup_delay_frames--;
961+
} else {
962+
m_console_startup_checked = true;
963+
964+
if (m_open_debug_console_at_startup->value()) {
965+
g_framework->open_console();
966+
}
967+
}
968+
}
959969
if (!m_scene_okay) try {
960970
if (!m_checked_scene_once) {
961971
m_checked_scene_once = true;
@@ -1088,15 +1098,13 @@ void ScriptRunner::on_draw_ui() {
10881098
ImGui::SameLine();
10891099

10901100
if (ImGui::Button("Spawn Debug Console")) {
1091-
if (!m_console_spawned) {
1092-
AllocConsole();
1093-
freopen("CONIN$", "r", stdin);
1094-
freopen("CONOUT$", "w", stdout);
1095-
freopen("CONOUT$", "w", stderr);
1101+
g_framework->open_console();
1102+
}
10961103

1097-
m_console_spawned = true;
1098-
}
1104+
if (m_open_debug_console_at_startup->draw("Open Debug Console at Startup")) {
1105+
g_framework->request_save_config();
10991106
}
1107+
11001108
//Garbage collection currently only showing from main lua state, might rework to show total later?
11011109
if (ImGui::TreeNode("Garbage Collection Stats")) {
11021110
std::scoped_lock _{ m_access_mutex };
@@ -1284,11 +1292,7 @@ void ScriptRunner::on_gui_draw_element(REComponent* gui_element, void* primitive
12841292
}
12851293

12861294
void ScriptRunner::spew_error(const std::string& p) {
1287-
OutputDebugString(p.c_str());
1288-
1289-
if (m_console_spawned) {
1290-
fprintf(stderr, "%s\n", p.c_str());
1291-
}
1295+
fprintf(stderr, "%s\n", p.c_str());
12921296

12931297
if (m_log_to_disk->value()) {
12941298
spdlog::error(p);

src/mods/ScriptRunner.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,11 @@ class ScriptRunner : public Mod {
426426
bool m_checked_scene_once{false};
427427
bool m_scene_okay{false};
428428
bool m_has_any_transform_updates{false};
429-
bool m_console_spawned{false};
430429
bool m_needs_first_reset{true};
431430
bool m_last_online_match_state{false};
432431
bool m_attempted_hook_battle_rule{false};
432+
bool m_console_startup_checked{false};
433+
int m_console_startup_delay_frames{2};
433434
std::optional<uint8_t> m_last_battle_type{};
434435
const ModToggle::Ptr m_log_to_disk{ ModToggle::create(generate_name("LogToDisk"), false) };
435436

@@ -470,14 +471,17 @@ class ScriptRunner : public Mod {
470471
ModSlider::create(generate_name("GarbageCollectionMajorMultiplier"), 1.0f, 1000.0f, 100.0f)
471472
};
472473

474+
const ModToggle::Ptr m_open_debug_console_at_startup{ ModToggle::create(generate_name("OpenDebugConsoleAtStartup"), false) };
475+
473476
ValueList m_options{
474477
*m_log_to_disk,
475478
*m_gc_handler,
476479
*m_gc_type,
477480
*m_gc_mode,
478481
*m_gc_budget,
479482
*m_gc_minor_multiplier,
480-
*m_gc_major_multiplier
483+
*m_gc_major_multiplier,
484+
*m_open_debug_console_at_startup
481485
};
482486

483487
// Resets the ScriptState and runs autorun scripts again.

0 commit comments

Comments
 (0)