Merge pull request #8243 from Robyt3/Console-Scrolling-Fix

Fix potential client crash and console not keeping scrolling position when console backlog is full
This commit is contained in:
Dennis Felsing 2024-04-21 15:46:59 +00:00 committed by GitHub
commit 18d8e987f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 8 deletions

View file

@ -123,11 +123,21 @@ void *CRingBufferBase::Allocate(int Size)
return (void *)(pBlock + 1); return (void *)(pBlock + 1);
} }
void CRingBufferBase::SetPopCallback(std::function<void(void *pCurrent)> PopCallback)
{
m_PopCallback = std::move(PopCallback);
}
int CRingBufferBase::PopFirst() int CRingBufferBase::PopFirst()
{ {
if(m_pConsume->m_Free) if(m_pConsume->m_Free)
return 0; return 0;
if(m_PopCallback)
{
m_PopCallback(m_pConsume + 1);
}
// set the free flag // set the free flag
m_pConsume->m_Free = 1; m_pConsume->m_Free = 1;

View file

@ -5,6 +5,8 @@
#include <base/system.h> #include <base/system.h>
#include <functional>
class CRingBufferBase class CRingBufferBase
{ {
class CItem class CItem
@ -25,6 +27,8 @@ class CRingBufferBase
int m_Size; int m_Size;
int m_Flags; int m_Flags;
std::function<void(void *pCurrent)> m_PopCallback = nullptr;
CItem *NextBlock(CItem *pItem); CItem *NextBlock(CItem *pItem);
CItem *PrevBlock(CItem *pItem); CItem *PrevBlock(CItem *pItem);
CItem *MergeBack(CItem *pItem); CItem *MergeBack(CItem *pItem);
@ -39,6 +43,7 @@ protected:
void Init(void *pMemory, int Size, int Flags); void Init(void *pMemory, int Size, int Flags);
int PopFirst(); int PopFirst();
void SetPopCallback(const std::function<void(void *pCurrent)> PopCallback);
public: public:
enum enum
@ -55,6 +60,12 @@ class CTypedRingBuffer : public CRingBufferBase
public: public:
T *Allocate(int Size) { return (T *)CRingBufferBase::Allocate(Size); } T *Allocate(int Size) { return (T *)CRingBufferBase::Allocate(Size); }
int PopFirst() { return CRingBufferBase::PopFirst(); } int PopFirst() { return CRingBufferBase::PopFirst(); }
void SetPopCallback(std::function<void(T *pCurrent)> PopCallback)
{
CRingBufferBase::SetPopCallback([PopCallback](void *pCurrent) {
PopCallback((T *)pCurrent);
});
}
T *Prev(T *pCurrent) { return (T *)CRingBufferBase::Prev(pCurrent); } T *Prev(T *pCurrent) { return (T *)CRingBufferBase::Prev(pCurrent); }
T *Next(T *pCurrent) { return (T *)CRingBufferBase::Next(pCurrent); } T *Next(T *pCurrent) { return (T *)CRingBufferBase::Next(pCurrent); }

View file

@ -208,6 +208,13 @@ CGameConsole::CInstance::CInstance(int Type)
m_IsCommand = false; m_IsCommand = false;
m_Backlog.SetPopCallback([this](CBacklogEntry *pEntry) {
if(pEntry->m_LineCount != -1)
{
m_NewLineCounter -= pEntry->m_LineCount;
}
});
m_Input.SetClipboardLineCallback([this](const char *pStr) { ExecuteLine(pStr); }); m_Input.SetClipboardLineCallback([this](const char *pStr) { ExecuteLine(pStr); });
m_CurrentMatchIndex = -1; m_CurrentMatchIndex = -1;
@ -236,7 +243,7 @@ void CGameConsole::CInstance::ClearBacklog()
void CGameConsole::CInstance::UpdateBacklogTextAttributes() void CGameConsole::CInstance::UpdateBacklogTextAttributes()
{ {
// Pending backlog entries are not handled because they don't have text attributes yet. // Pending backlog entries are not handled because they don't have text attributes yet.
for(CInstance::CBacklogEntry *pEntry = m_Backlog.First(); pEntry; pEntry = m_Backlog.Next(pEntry)) for(CBacklogEntry *pEntry = m_Backlog.First(); pEntry; pEntry = m_Backlog.Next(pEntry))
{ {
UpdateEntryTextAttributes(pEntry); UpdateEntryTextAttributes(pEntry);
} }
@ -244,27 +251,29 @@ void CGameConsole::CInstance::UpdateBacklogTextAttributes()
void CGameConsole::CInstance::PumpBacklogPending() void CGameConsole::CInstance::PumpBacklogPending()
{ {
std::vector<CInstance::CBacklogEntry *> vpEntries;
{ {
// We must ensure that no log messages are printed while owning // We must ensure that no log messages are printed while owning
// m_BacklogPendingLock or this will result in a dead lock. // m_BacklogPendingLock or this will result in a dead lock.
const CLockScope LockScopePending(m_BacklogPendingLock); const CLockScope LockScopePending(m_BacklogPendingLock);
for(CInstance::CBacklogEntry *pPendingEntry = m_BacklogPending.First(); pPendingEntry; pPendingEntry = m_BacklogPending.Next(pPendingEntry)) for(CBacklogEntry *pPendingEntry = m_BacklogPending.First(); pPendingEntry; pPendingEntry = m_BacklogPending.Next(pPendingEntry))
{ {
const size_t EntrySize = sizeof(CBacklogEntry) + pPendingEntry->m_Length; const size_t EntrySize = sizeof(CBacklogEntry) + pPendingEntry->m_Length;
CBacklogEntry *pEntry = m_Backlog.Allocate(EntrySize); CBacklogEntry *pEntry = m_Backlog.Allocate(EntrySize);
mem_copy(pEntry, pPendingEntry, EntrySize); mem_copy(pEntry, pPendingEntry, EntrySize);
vpEntries.push_back(pEntry);
} }
m_BacklogPending.Init(); m_BacklogPending.Init();
} }
// Update text attributes and count number of added lines
m_pGameConsole->Ui()->MapScreen(); m_pGameConsole->Ui()->MapScreen();
for(CInstance::CBacklogEntry *pEntry : vpEntries) for(CBacklogEntry *pEntry = m_Backlog.First(); pEntry; pEntry = m_Backlog.Next(pEntry))
{ {
UpdateEntryTextAttributes(pEntry); if(pEntry->m_LineCount == -1)
m_NewLineCounter += pEntry->m_LineCount; {
UpdateEntryTextAttributes(pEntry);
m_NewLineCounter += pEntry->m_LineCount;
}
} }
} }
@ -1133,7 +1142,7 @@ void CGameConsole::OnRender()
} }
pConsole->PumpBacklogPending(); pConsole->PumpBacklogPending();
if(pConsole->m_NewLineCounter > 0) if(pConsole->m_NewLineCounter != 0)
{ {
pConsole->UpdateSearch(); pConsole->UpdateSearch();
@ -1143,6 +1152,8 @@ void CGameConsole::OnRender()
pConsole->m_BacklogCurLine += pConsole->m_NewLineCounter; pConsole->m_BacklogCurLine += pConsole->m_NewLineCounter;
pConsole->m_BacklogLastActiveLine += pConsole->m_NewLineCounter; pConsole->m_BacklogLastActiveLine += pConsole->m_NewLineCounter;
} }
if(pConsole->m_NewLineCounter < 0)
pConsole->m_NewLineCounter = 0;
} }
// render console log (current entry, status, wrap lines) // render console log (current entry, status, wrap lines)