Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Added console scrolling, the latest console commands are saved
  • Loading branch information
knallpsi committed Feb 7, 2026
commit 031c3851cd452d6c4902967cbf51f959941708a0
191 changes: 160 additions & 31 deletions src/xrEngine/XR_IOConsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,73 @@ bool CConsole::is_mark(Console_mark type)

////////////////////////////////////////////////////////////////////////////////////////////////////

// Log callback for console
void ConsoleLogCallback(LPCSTR line) {
Console->AddLogEntry(line);
}

CConsole::CConsole()
: m_hShader_back(NULL)
{
m_log_line_counter = 0;

m_bHistoryLoaded = false;

m_cur_cmd.reserve(64);
m_last_cmd.reserve(64);
for (u32 i = 0; i < m_log_history.GetSize(); ++i)
{
m_log_history.Get(i).reserve(256);
}

m_editor = xr_new<text_editor::line_editor>((u32)CONSOLE_BUF_SIZE);
m_cmd_history_max = cmd_history_max;
m_disable_tips = false;
Register_callbacks();
Device.seqResolutionChanged.Add(this);

xrLogger::AddLogCallback(ConsoleLogCallback);

}

void CConsole::SaveHistory()
{
// Открываем файл на запись в папке app_data (где логи и настройки)
IWriter* W = FS.w_open("$app_data_root$", "console_history.txt");
if (W)
{
// Проходим по вектору истории и записываем каждую команду новой строкой
for (const auto& cmd : m_cmd_history)
{
if (cmd.size() > 0)
{
W->w_string(cmd.c_str());
}
}
FS.w_close(W);
}
}

void CConsole::LoadHistory()
{
if (m_bHistoryLoaded) return;

IReader* R = FS.r_open("$app_data_root$", "console_history.txt");
if (R)
{
string1024 line;
while (!R->eof() && m_cmd_history.size() < m_cmd_history_max)
{
R->r_string(line, sizeof(line));
if (xr_strlen(line) > 0)
{
m_cmd_history.push_back(line);
}
}
FS.r_close(R);
reset_cmd_history_idx();
}
m_bHistoryLoaded = true;
}

void CConsole::Initialize()
Expand All @@ -151,10 +210,12 @@ void CConsole::Initialize()

m_mouse_pos.x = 0;
m_mouse_pos.y = 0;
m_last_cmd = NULL;

m_cmd_history.reserve(m_cmd_history_max + 2);
m_cmd_history.clear_not_free();

reset_cmd_history_idx();

reset_cmd_history_idx();

m_tips.reserve(MAX_TIPS_COUNT + 1);
Expand All @@ -164,7 +225,6 @@ void CConsole::Initialize()

m_tips_mode = 0;
m_prev_length_str = 0;
m_cur_cmd = NULL;
reset_selected_tip();

// Commands
Expand All @@ -174,6 +234,8 @@ void CConsole::Initialize()

CConsole::~CConsole()
{
SaveHistory();
xrLogger::RemoveLogCallback(ConsoleLogCallback);
xr_delete(m_hShader_back);
xr_delete(m_editor);
Destroy();
Expand All @@ -187,6 +249,24 @@ void CConsole::Destroy()
Commands.clear();
}

void CConsole::AddLogEntry(LPCSTR line)
{
xrCriticalSectionGuard guard(&m_log_history_guard);
m_log_history.Get(m_log_history.GetHead()) = line;
m_log_history.MoveHead(1);
m_log_line_counter++;
}

void CConsole::ClearLog()
{
xrCriticalSectionGuard guard(&m_log_history_guard);
for (u32 i = 0; i < m_log_history.GetSize(); ++i)
{
m_log_history.Get(i).clear();
}
m_log_line_counter = 0;
}

void CConsole::AddCommand(IConsole_Command* cc)
{
Commands[cc->Name()] = cc;
Expand Down Expand Up @@ -221,7 +301,7 @@ void CConsole::OutFont(LPCSTR text, float& pos_y)
int sz = 0;
int ln = 0;
PSTR one_line = (PSTR)_alloca((CONSOLE_BUF_SIZE + 1) * sizeof(char));

while (text[sz] && (ln + sz < CONSOLE_BUF_SIZE - 5)) // перенос строк
{
one_line[ln + sz] = text[sz];
Expand Down Expand Up @@ -387,33 +467,48 @@ void CConsole::OnRender()
}

// ---------------------
u32 log_line = LogFile.size() - 1;
ypos -= LDIST;
for (int i = log_line - scroll_delta; i >= 0; --i)
m_log_history_guard.Enter();
u32 log_size = m_log_history.GetSize();
u32 total_filled = std::min(m_log_line_counter, log_size);

u32 newest_idx = m_log_history.GetHead();

float temp_y = ypos;

if (total_filled > 0)
{
ypos -= LDIST;
if (ypos < -1.0f)
{
break;
}
LPCSTR ls = LogFile[i].c_str();
if (scroll_delta > (int)total_filled - 1)
scroll_delta = std::max(0, (int)total_filled - 1);
if (scroll_delta < 0) scroll_delta = 0;

if (!ls)
for (u32 i = (u32)scroll_delta; i < total_filled; ++i)
{
continue;
const xr_string& logLine = m_log_history.GetLooped(newest_idx - 1 - i);

if (logLine.empty()) continue;

temp_y -= LDIST;

if (temp_y < -1.0f)
break;

LPCSTR ls = logLine.c_str();
Console_mark cm = (Console_mark)ls[0];
pFont->SetColor(get_mark_color(cm));

float line_y = temp_y;
OutFont(ls, line_y);

temp_y = line_y;
}
Console_mark cm = (Console_mark)ls[0];
pFont->SetColor(get_mark_color(cm));
//u8 b = (is_mark( cm ))? 2 : 0;
//OutFont( ls + b, ypos );
OutFont(ls, ypos);
}
m_log_history_guard.Leave();

string16 q;
itoa(log_line, q, 10);
itoa(m_log_line_counter, q, 10);
u32 qn = xr_strlen(q);
pFont->SetColor(total_font_color);
pFont->OutI(0.95f - 0.03f * qn, fMaxY - 2.0f * LDIST, "[%d]", log_line);
pFont->OutI(0.95f - 0.03f * qn, fMaxY - 2.0f * LDIST, "[%d]", m_log_line_counter);

pFont->OnRender();
pFont2->OnRender();
Expand Down Expand Up @@ -599,11 +694,12 @@ void CConsole::ExecuteCommand(LPCSTR cmd_str, bool record_cmd)
c[0] = mark2;
c[1] = 0;

if (m_last_cmd.c_str() == 0 || xr_strcmp(m_last_cmd, edt) != 0)
if (m_last_cmd.c_str() == 0 || xr_strcmp(m_last_cmd.c_str(), edt) != 0)
{
Log(c, edt);
Msg("%s %s", c, edt);
add_cmd_history(edt);
m_last_cmd = edt;
SaveHistory();
}
}
text_editor::split_cmd(first, last, edt);
Expand Down Expand Up @@ -643,12 +739,12 @@ void CConsole::ExecuteCommand(LPCSTR cmd_str, bool record_cmd)
}
else
{
Log("! Command disabled.");
Msg("! Command disabled.");
}
}
else
{
Log("! Unknown command: ", first);
Msg("! Unknown command: %s", first);
}

if (record_cmd)
Expand All @@ -661,10 +757,14 @@ void CConsole::Show()
{
//SECUROM_MARKER_HIGH_SECURITY_ON(11)

if (bVisible)
if (bVisible) return;

if (!m_bHistoryLoaded)
{
return;
LoadHistory();
//m_bHistoryLoaded = true;
}

bVisible = true;

GetCursorPos(&m_mouse_pos);
Expand All @@ -675,7 +775,7 @@ void CConsole::Show()
reset_selected_tip();
update_tips();

m_editor->IR_Capture();
this->IR_Capture();
Device.seqRender.Add(this, 1);
Device.seqFrame.Add(this);

Expand Down Expand Up @@ -708,7 +808,22 @@ void CConsole::Hide()

Device.seqFrame.Remove(this);
Device.seqRender.Remove(this);
m_editor->IR_Release();
this->IR_Release();
}

void CConsole::IR_OnKeyboardPress(int dik)
{
static_cast<IInputReceiver*>(m_editor)->IR_OnKeyboardPress(dik);
}

void CConsole::IR_OnKeyboardRelease(int dik)
{
static_cast<IInputReceiver*>(m_editor)->IR_OnKeyboardRelease(dik);
}

void CConsole::IR_OnKeyboardHold(int dik)
{
static_cast<IInputReceiver*>(m_editor)->IR_OnKeyboardHold(dik);
}

void CConsole::SelectCommand()
Expand Down Expand Up @@ -884,7 +999,7 @@ void CConsole::update_tips()
m_temp_tips.clear_not_free();
m_tips.clear_not_free();

m_cur_cmd = NULL;
m_cur_cmd.clear();
if (!bVisible)
{
return;
Expand Down Expand Up @@ -934,7 +1049,7 @@ void CConsole::update_tips()

cc->fill_tips(m_temp_tips, mode);
m_tips_mode = 2;
m_cur_cmd._set(first);
m_cur_cmd = first;
select_for_filter(last, m_temp_tips, m_tips);

if (m_tips.size() == 0)
Expand Down Expand Up @@ -968,6 +1083,20 @@ void CConsole::update_tips()
}
}

void CConsole::DumpHistoryToLog()
{
if (m_cmd_history.empty()) return;

Msg("~ [x-ray]: console history start");

for (const auto& cmd : m_cmd_history)
{
Msg("- [history]: %s", cmd.c_str());
}

Msg("~ [x-ray]: console history end");
}

void CConsole::select_for_filter(LPCSTR filter_str, vecTips& in_v, vecTipsEx& out_v)
{
out_v.clear_not_free();
Expand Down
Loading