2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2011-08-31 11:56:04 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
#include <base/logger.h>
|
2011-08-31 11:56:04 +00:00
|
|
|
|
2022-02-14 23:22:52 +00:00
|
|
|
#include <climits>
|
|
|
|
#include <cmath>
|
2022-02-14 23:32:04 +00:00
|
|
|
#include <limits>
|
2008-08-30 21:09:13 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/generated/client_data.h>
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-14 17:19:13 +00:00
|
|
|
#include <base/system.h>
|
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
#include <engine/console.h>
|
|
|
|
#include <engine/graphics.h>
|
|
|
|
#include <engine/keys.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/shared/config.h>
|
2020-09-22 16:02:03 +00:00
|
|
|
#include <engine/shared/ringbuffer.h>
|
2010-06-20 12:12:59 +00:00
|
|
|
#include <engine/storage.h>
|
2020-09-22 16:02:03 +00:00
|
|
|
#include <engine/textrender.h>
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/ui.h>
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2022-05-29 16:33:38 +00:00
|
|
|
#include <game/localization.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/version.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
#include <game/client/lineinput.h>
|
|
|
|
#include <game/client/render.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2021-07-12 09:29:59 +00:00
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
|
2021-09-12 17:32:00 +00:00
|
|
|
#include <base/math.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "console.h"
|
2008-01-30 13:15:58 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
class CConsoleLogger : public ILogger
|
|
|
|
{
|
|
|
|
CGameConsole *m_pConsole;
|
|
|
|
std::mutex m_ConsoleMutex;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CConsoleLogger(CGameConsole *pConsole) :
|
|
|
|
m_pConsole(pConsole)
|
|
|
|
{
|
|
|
|
dbg_assert(pConsole != nullptr, "console pointer must not be null");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Log(const CLogMessage *pMessage) override;
|
|
|
|
void OnConsoleDeletion();
|
|
|
|
};
|
|
|
|
|
|
|
|
void CConsoleLogger::Log(const CLogMessage *pMessage)
|
|
|
|
{
|
|
|
|
// TODO: Fix thread-unsafety of accessing `g_Config.m_ConsoleOutputLevel`
|
|
|
|
if(pMessage->m_Level > IConsole::ToLogLevel(g_Config.m_ConsoleOutputLevel))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ColorRGBA Color = gs_ConsoleDefaultColor;
|
|
|
|
if(pMessage->m_HaveColor)
|
|
|
|
{
|
|
|
|
Color.r = pMessage->m_Color.r / 255.0;
|
|
|
|
Color.g = pMessage->m_Color.g / 255.0;
|
|
|
|
Color.b = pMessage->m_Color.b / 255.0;
|
|
|
|
}
|
|
|
|
std::unique_lock<std::mutex> Guard(m_ConsoleMutex);
|
|
|
|
if(m_pConsole)
|
|
|
|
{
|
|
|
|
m_pConsole->m_LocalConsole.PrintLine(pMessage->m_aLine, pMessage->m_LineLength, Color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CConsoleLogger::OnConsoleDeletion()
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Guard(m_ConsoleMutex);
|
|
|
|
m_pConsole = nullptr;
|
|
|
|
}
|
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
// TODO: support "tune_zone", which has tuning as second argument
|
|
|
|
static const char *gs_apTuningCommands[] = {"tune ", "tune_reset ", "toggle_tune "};
|
|
|
|
static bool IsTuningCommandPrefix(const char *pStr)
|
|
|
|
{
|
|
|
|
return std::any_of(std::begin(gs_apTuningCommands), std::end(gs_apTuningCommands), [pStr](auto *pCmd) { return str_startswith_nocase(pStr, pCmd); });
|
|
|
|
}
|
|
|
|
|
2010-06-05 11:38:08 +00:00
|
|
|
CGameConsole::CInstance::CInstance(int Type)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pHistoryEntry = 0x0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Type = Type;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-11-17 12:01:46 +00:00
|
|
|
if(Type == CGameConsole::CONSOLETYPE_LOCAL)
|
2022-08-09 14:41:00 +00:00
|
|
|
{
|
|
|
|
m_pName = "local_console";
|
2010-05-29 07:25:38 +00:00
|
|
|
m_CompletionFlagmask = CFGFLAG_CLIENT;
|
2022-08-09 14:41:00 +00:00
|
|
|
}
|
2009-01-24 12:16:02 +00:00
|
|
|
else
|
2022-08-09 14:41:00 +00:00
|
|
|
{
|
|
|
|
m_pName = "remote_console";
|
2010-05-29 07:25:38 +00:00
|
|
|
m_CompletionFlagmask = CFGFLAG_SERVER;
|
2022-08-09 14:41:00 +00:00
|
|
|
}
|
2009-01-24 12:16:02 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_aCompletionBuffer[0] = 0;
|
|
|
|
m_CompletionChosen = -1;
|
2022-08-09 16:03:04 +00:00
|
|
|
m_aCompletionBufferArgument[0] = 0;
|
|
|
|
m_CompletionChosenArgument = -1;
|
2022-08-09 15:40:16 +00:00
|
|
|
Reset();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2017-03-02 15:16:50 +00:00
|
|
|
m_aUser[0] = '\0';
|
2017-03-06 12:49:08 +00:00
|
|
|
m_UserGot = false;
|
2017-07-24 19:43:55 +00:00
|
|
|
m_UsernameReq = false;
|
2017-03-02 15:16:50 +00:00
|
|
|
|
2011-07-14 20:07:21 +00:00
|
|
|
m_IsCommand = false;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-06-05 11:38:08 +00:00
|
|
|
void CGameConsole::CInstance::Init(CGameConsole *pGameConsole)
|
|
|
|
{
|
|
|
|
m_pGameConsole = pGameConsole;
|
2018-11-18 06:25:15 +00:00
|
|
|
}
|
2010-06-05 11:38:08 +00:00
|
|
|
|
2010-06-19 18:51:54 +00:00
|
|
|
void CGameConsole::CInstance::ClearBacklog()
|
|
|
|
{
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.lock();
|
2010-06-19 18:51:54 +00:00
|
|
|
m_Backlog.Init();
|
2022-04-01 16:32:51 +00:00
|
|
|
m_BacklogCurPage = 0;
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.unlock();
|
2010-06-19 18:51:54 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 21:36:41 +00:00
|
|
|
void CGameConsole::CInstance::ClearBacklogYOffsets()
|
|
|
|
{
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.lock();
|
2022-01-14 21:36:41 +00:00
|
|
|
auto *pEntry = m_Backlog.First();
|
|
|
|
while(pEntry)
|
|
|
|
{
|
|
|
|
pEntry->m_YOffset = -1.0f;
|
|
|
|
pEntry = m_Backlog.Next(pEntry);
|
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.unlock();
|
2022-01-14 21:36:41 +00:00
|
|
|
}
|
|
|
|
|
2010-10-10 22:30:56 +00:00
|
|
|
void CGameConsole::CInstance::ClearHistory()
|
|
|
|
{
|
|
|
|
m_History.Init();
|
|
|
|
m_pHistoryEntry = 0;
|
|
|
|
}
|
|
|
|
|
2022-08-09 15:40:16 +00:00
|
|
|
void CGameConsole::CInstance::Reset()
|
|
|
|
{
|
|
|
|
m_CompletionRenderOffset = 0.0f;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::CInstance::ExecuteLine(const char *pLine)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
if(m_Type == CGameConsole::CONSOLETYPE_LOCAL)
|
2011-08-13 00:11:06 +00:00
|
|
|
m_pGameConsole->m_pConsole->ExecuteLine(pLine);
|
2008-08-27 15:48:50 +00:00
|
|
|
else
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_pGameConsole->Client()->RconAuthed())
|
|
|
|
m_pGameConsole->Client()->Rcon(pLine);
|
2008-03-01 14:36:36 +00:00
|
|
|
else
|
2017-03-02 15:16:50 +00:00
|
|
|
{
|
2017-07-24 19:43:55 +00:00
|
|
|
if(!m_UserGot && m_UsernameReq)
|
2017-03-06 12:49:08 +00:00
|
|
|
{
|
|
|
|
m_UserGot = true;
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aUser, pLine);
|
2017-03-06 12:49:08 +00:00
|
|
|
}
|
2017-03-02 15:16:50 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pGameConsole->Client()->RconAuth(m_aUser, pLine);
|
2017-03-06 12:49:08 +00:00
|
|
|
m_UserGot = false;
|
2017-03-02 15:16:50 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 15:26:57 +00:00
|
|
|
void CGameConsole::CInstance::PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameConsole::CInstance *pInstance = (CGameConsole::CInstance *)pUser;
|
2022-08-09 15:26:57 +00:00
|
|
|
if(pInstance->m_CompletionChosen == Index)
|
2010-05-29 07:25:38 +00:00
|
|
|
pInstance->m_Input.Set(pStr);
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-11 17:30:29 +00:00
|
|
|
static void StrCopyUntilSpace(char *pDest, size_t DestSize, const char *pSrc)
|
|
|
|
{
|
|
|
|
const char *pSpace = str_find(pSrc, " ");
|
|
|
|
str_copy(pDest, pSrc, minimum<size_t>(pSpace ? pSpace - pSrc + 1 : 1, DestSize));
|
|
|
|
}
|
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
void CGameConsole::CInstance::PossibleArgumentsCompleteCallback(int Index, const char *pStr, void *pUser)
|
|
|
|
{
|
|
|
|
CGameConsole::CInstance *pInstance = (CGameConsole::CInstance *)pUser;
|
|
|
|
if(pInstance->m_CompletionChosenArgument == Index)
|
|
|
|
{
|
|
|
|
// get command
|
|
|
|
char aBuf[512];
|
2022-08-11 17:30:29 +00:00
|
|
|
StrCopyUntilSpace(aBuf, sizeof(aBuf), pInstance->GetString());
|
|
|
|
str_append(aBuf, " ", sizeof(aBuf));
|
2022-08-09 16:03:04 +00:00
|
|
|
|
|
|
|
// append argument
|
|
|
|
str_append(aBuf, pStr, sizeof(aBuf));
|
|
|
|
pInstance->m_Input.Set(aBuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
bool Handled = false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-12-18 11:23:20 +00:00
|
|
|
if(m_pGameConsole->Input()->ModifierIsPressed()) // jump to spaces and special ASCII characters
|
2019-06-01 14:24:22 +00:00
|
|
|
{
|
|
|
|
int SearchDirection = 0;
|
2021-09-27 13:46:44 +00:00
|
|
|
if(m_pGameConsole->Input()->KeyPress(KEY_LEFT) || m_pGameConsole->Input()->KeyPress(KEY_BACKSPACE))
|
2019-06-01 14:24:22 +00:00
|
|
|
SearchDirection = -1;
|
|
|
|
else if(m_pGameConsole->Input()->KeyPress(KEY_RIGHT) || m_pGameConsole->Input()->KeyPress(KEY_DELETE))
|
|
|
|
SearchDirection = 1;
|
|
|
|
|
|
|
|
if(SearchDirection != 0)
|
|
|
|
{
|
|
|
|
int OldOffset = m_Input.GetCursorOffset();
|
|
|
|
|
|
|
|
int FoundAt = SearchDirection > 0 ? m_Input.GetLength() - 1 : 0;
|
|
|
|
for(int i = m_Input.GetCursorOffset() + SearchDirection; SearchDirection > 0 ? i < m_Input.GetLength() - 1 : i > 0; i += SearchDirection)
|
|
|
|
{
|
|
|
|
int Next = i + SearchDirection;
|
2020-09-22 16:02:03 +00:00
|
|
|
if((m_Input.GetString()[Next] == ' ') ||
|
2019-06-01 14:24:22 +00:00
|
|
|
(m_Input.GetString()[Next] >= 32 && m_Input.GetString()[Next] <= 47) ||
|
|
|
|
(m_Input.GetString()[Next] >= 58 && m_Input.GetString()[Next] <= 64) ||
|
|
|
|
(m_Input.GetString()[Next] >= 91 && m_Input.GetString()[Next] <= 96))
|
|
|
|
{
|
|
|
|
FoundAt = i;
|
|
|
|
if(SearchDirection < 0)
|
|
|
|
FoundAt++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 13:46:44 +00:00
|
|
|
if(m_pGameConsole->Input()->KeyPress(KEY_BACKSPACE))
|
|
|
|
{
|
|
|
|
if(m_Input.GetCursorOffset() != 0)
|
|
|
|
{
|
|
|
|
char aText[512];
|
|
|
|
str_copy(aText, m_Input.GetString(), FoundAt + 1);
|
|
|
|
|
|
|
|
if(m_Input.GetCursorOffset() != str_length(m_Input.GetString()))
|
|
|
|
str_append(aText, m_Input.GetString() + m_Input.GetCursorOffset(), str_length(m_Input.GetString()));
|
|
|
|
|
|
|
|
m_Input.Set(aText);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-01 14:24:22 +00:00
|
|
|
if(m_pGameConsole->Input()->KeyPress(KEY_DELETE))
|
|
|
|
{
|
|
|
|
if(m_Input.GetCursorOffset() != m_Input.GetLength())
|
|
|
|
{
|
|
|
|
char aText[512];
|
|
|
|
aText[0] = '\0';
|
|
|
|
|
|
|
|
str_copy(aText, m_Input.GetString(), m_Input.GetCursorOffset() + 1);
|
|
|
|
|
|
|
|
if(FoundAt != m_Input.GetLength())
|
|
|
|
str_append(aText, m_Input.GetString() + FoundAt, sizeof(aText));
|
|
|
|
|
|
|
|
m_Input.Set(aText);
|
|
|
|
FoundAt = OldOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_Input.SetCursorOffset(FoundAt);
|
|
|
|
}
|
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_V))
|
2015-08-25 12:24:46 +00:00
|
|
|
{
|
2022-06-30 22:36:32 +00:00
|
|
|
const char *pText = m_pGameConsole->Input()->GetClipboardText();
|
|
|
|
if(pText)
|
2015-08-25 12:24:46 +00:00
|
|
|
{
|
2021-09-13 09:47:47 +00:00
|
|
|
char aLine[256];
|
2019-04-09 10:11:29 +00:00
|
|
|
int i, Begin = 0;
|
2022-06-30 22:36:32 +00:00
|
|
|
for(i = 0; i < str_length(pText); i++)
|
2015-08-25 12:24:46 +00:00
|
|
|
{
|
2022-06-30 22:36:32 +00:00
|
|
|
if(pText[i] == '\n')
|
2015-08-25 12:24:46 +00:00
|
|
|
{
|
2019-04-09 10:11:29 +00:00
|
|
|
if(i == Begin)
|
2015-08-26 14:40:59 +00:00
|
|
|
{
|
2019-04-09 10:11:29 +00:00
|
|
|
Begin++;
|
|
|
|
continue;
|
2015-08-26 14:40:59 +00:00
|
|
|
}
|
2021-09-13 09:47:47 +00:00
|
|
|
int max = minimum(i - Begin + 1, (int)sizeof(aLine));
|
2022-06-30 22:36:32 +00:00
|
|
|
str_copy(aLine, pText + Begin, max);
|
2020-09-22 16:02:03 +00:00
|
|
|
Begin = i + 1;
|
2021-09-13 09:47:47 +00:00
|
|
|
ExecuteLine(aLine);
|
2015-08-25 12:24:46 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-13 09:47:47 +00:00
|
|
|
int max = minimum(i - Begin + 1, (int)sizeof(aLine));
|
2022-06-30 22:36:32 +00:00
|
|
|
str_copy(aLine, pText + Begin, max);
|
2021-11-24 23:03:35 +00:00
|
|
|
m_Input.Append(aLine);
|
2015-08-25 12:24:46 +00:00
|
|
|
}
|
2019-04-09 10:11:29 +00:00
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
else if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_C))
|
2019-04-09 10:11:29 +00:00
|
|
|
{
|
|
|
|
m_pGameConsole->Input()->SetClipboardText(m_Input.GetString());
|
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
else if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_A))
|
2019-04-09 10:11:29 +00:00
|
|
|
{
|
|
|
|
m_Input.SetCursorOffset(0);
|
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
else if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_E))
|
2019-04-09 10:11:29 +00:00
|
|
|
{
|
|
|
|
m_Input.SetCursorOffset(m_Input.GetLength());
|
2015-08-25 12:24:46 +00:00
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
else if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_U))
|
2019-06-01 15:11:35 +00:00
|
|
|
{
|
2021-11-24 22:44:11 +00:00
|
|
|
m_Input.SetRange("", 0, m_Input.GetCursorOffset());
|
2019-06-01 15:11:35 +00:00
|
|
|
}
|
2021-12-18 11:23:20 +00:00
|
|
|
else if(m_pGameConsole->Input()->ModifierIsPressed() && m_pGameConsole->Input()->KeyPress(KEY_K))
|
2019-06-18 17:58:59 +00:00
|
|
|
{
|
2021-11-24 22:44:11 +00:00
|
|
|
m_Input.SetRange("", m_Input.GetCursorOffset(), m_Input.GetLength());
|
2019-06-18 17:58:59 +00:00
|
|
|
}
|
2015-08-25 12:24:46 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Event.m_Flags & IInput::FLAG_PRESS)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Event.m_Key == KEY_RETURN || Event.m_Key == KEY_KP_ENTER)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2017-07-24 19:43:55 +00:00
|
|
|
if(m_Input.GetString()[0] || (m_UsernameReq && !m_pGameConsole->Client()->RconAuthed() && !m_UserGot))
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
if(m_Type == CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed())
|
2010-10-09 18:05:52 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
char *pEntry = m_History.Allocate(m_Input.GetLength() + 1);
|
2022-06-24 23:19:32 +00:00
|
|
|
str_copy(pEntry, m_Input.GetString(), m_Input.GetLength() + 1);
|
2010-10-09 18:05:52 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
ExecuteLine(m_Input.GetString());
|
|
|
|
m_Input.Clear();
|
|
|
|
m_pHistoryEntry = 0x0;
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Handled = true;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2020-09-22 16:02:03 +00:00
|
|
|
else if(Event.m_Key == KEY_UP)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_pHistoryEntry)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
char *pTest = m_History.Prev(m_pHistoryEntry);
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(pTest)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pHistoryEntry = pTest;
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pHistoryEntry = m_History.Last();
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_pHistoryEntry)
|
2011-06-09 21:40:35 +00:00
|
|
|
m_Input.Set(m_pHistoryEntry);
|
2010-05-29 07:25:38 +00:00
|
|
|
Handled = true;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2020-09-22 16:02:03 +00:00
|
|
|
else if(Event.m_Key == KEY_DOWN)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_pHistoryEntry)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pHistoryEntry = m_History.Next(m_pHistoryEntry);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_pHistoryEntry)
|
2011-06-09 21:40:35 +00:00
|
|
|
m_Input.Set(m_pHistoryEntry);
|
2008-08-27 15:48:50 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Input.Clear();
|
|
|
|
Handled = true;
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Event.m_Key == KEY_TAB)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2022-08-09 16:03:04 +00:00
|
|
|
const int Direction = m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_LSHIFT) || m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_RSHIFT) ? -1 : 1;
|
|
|
|
|
|
|
|
// command completion
|
2010-11-17 12:01:46 +00:00
|
|
|
if(m_Type == CGameConsole::CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed())
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2022-08-09 15:40:16 +00:00
|
|
|
const bool UseTempCommands = m_Type == CGameConsole::CONSOLETYPE_REMOTE && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands();
|
|
|
|
const int CompletionEnumerationCount = m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, UseTempCommands);
|
|
|
|
if(CompletionEnumerationCount)
|
|
|
|
{
|
|
|
|
if(m_CompletionChosen == -1 && Direction < 0)
|
|
|
|
m_CompletionChosen = 0;
|
|
|
|
m_CompletionChosen = (m_CompletionChosen + Direction + CompletionEnumerationCount) % CompletionEnumerationCount;
|
|
|
|
m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, UseTempCommands, PossibleCommandsCompleteCallback, this);
|
|
|
|
}
|
|
|
|
else if(m_CompletionChosen != -1)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2022-08-09 15:40:16 +00:00
|
|
|
m_CompletionChosen = -1;
|
|
|
|
Reset();
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
2022-08-09 16:03:04 +00:00
|
|
|
|
|
|
|
// argument completion (tuning, ...)
|
|
|
|
if(m_Type == CGameConsole::CONSOLETYPE_REMOTE && m_pGameConsole->Client()->RconAuthed())
|
|
|
|
{
|
|
|
|
const bool TuningCompletion = IsTuningCommandPrefix(GetString());
|
|
|
|
if(TuningCompletion)
|
|
|
|
{
|
|
|
|
int CompletionEnumerationCount = m_pGameConsole->m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(m_aCompletionBufferArgument);
|
|
|
|
if(CompletionEnumerationCount)
|
|
|
|
{
|
|
|
|
if(m_CompletionChosenArgument == -1 && Direction < 0)
|
|
|
|
m_CompletionChosenArgument = 0;
|
|
|
|
m_CompletionChosenArgument = (m_CompletionChosenArgument + Direction + CompletionEnumerationCount) % CompletionEnumerationCount;
|
|
|
|
m_pGameConsole->m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(m_aCompletionBufferArgument, PossibleArgumentsCompleteCallback, this);
|
|
|
|
}
|
|
|
|
else if(m_CompletionChosenArgument != -1)
|
|
|
|
{
|
|
|
|
m_CompletionChosenArgument = -1;
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Event.m_Key == KEY_PAGEUP)
|
|
|
|
{
|
2022-04-01 16:32:51 +00:00
|
|
|
++m_BacklogCurPage;
|
2021-09-12 17:32:00 +00:00
|
|
|
m_pGameConsole->m_HasSelection = false;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
else if(Event.m_Key == KEY_PAGEDOWN)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2021-09-12 17:32:00 +00:00
|
|
|
m_pGameConsole->m_HasSelection = false;
|
2022-04-01 16:32:51 +00:00
|
|
|
--m_BacklogCurPage;
|
|
|
|
if(m_BacklogCurPage < 0)
|
|
|
|
m_BacklogCurPage = 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2019-04-07 21:28:30 +00:00
|
|
|
// in order not to conflict with CLineInput's handling of Home/End only
|
|
|
|
// react to it when the input is empty
|
|
|
|
else if(Event.m_Key == KEY_HOME && m_Input.GetString()[0] == '\0')
|
2017-07-04 20:06:51 +00:00
|
|
|
{
|
2022-04-01 16:32:51 +00:00
|
|
|
m_BacklogCurPage = INT_MAX;
|
2021-09-12 17:32:00 +00:00
|
|
|
m_pGameConsole->m_HasSelection = false;
|
2017-07-04 20:06:51 +00:00
|
|
|
}
|
2019-04-07 21:28:30 +00:00
|
|
|
else if(Event.m_Key == KEY_END && m_Input.GetString()[0] == '\0')
|
2017-07-04 20:06:51 +00:00
|
|
|
{
|
2022-04-01 16:32:51 +00:00
|
|
|
m_BacklogCurPage = 0;
|
2021-09-12 17:32:00 +00:00
|
|
|
m_pGameConsole->m_HasSelection = false;
|
2017-07-04 20:06:51 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!Handled)
|
|
|
|
m_Input.ProcessInput(Event);
|
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Event.m_Flags & (IInput::FLAG_PRESS | IInput::FLAG_TEXT))
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2022-08-09 15:40:16 +00:00
|
|
|
if(Event.m_Key != KEY_TAB && Event.m_Key != KEY_LSHIFT && Event.m_Key != KEY_RSHIFT)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
m_CompletionChosen = -1;
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aCompletionBuffer, m_Input.GetString());
|
2022-08-09 15:40:16 +00:00
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
for(const auto *pCmd : gs_apTuningCommands)
|
|
|
|
{
|
|
|
|
if(str_startswith_nocase(m_Input.GetString(), pCmd))
|
|
|
|
{
|
|
|
|
m_CompletionChosenArgument = -1;
|
|
|
|
str_copy(m_aCompletionBufferArgument, &m_Input.GetString()[str_length(pCmd)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-09 15:40:16 +00:00
|
|
|
Reset();
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
2009-01-24 13:12:04 +00:00
|
|
|
|
|
|
|
// find the current command
|
|
|
|
{
|
2022-08-11 17:30:29 +00:00
|
|
|
char aBuf[sizeof(m_aCommandName)];
|
|
|
|
StrCopyUntilSpace(aBuf, sizeof(aBuf), GetString());
|
2011-07-14 20:07:21 +00:00
|
|
|
const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask,
|
|
|
|
m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands());
|
|
|
|
if(pCommand)
|
|
|
|
{
|
|
|
|
m_IsCommand = true;
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(m_aCommandName, pCommand->m_pName);
|
|
|
|
str_copy(m_aCommandHelp, pCommand->m_pHelp);
|
|
|
|
str_copy(m_aCommandParams, pCommand->m_pParams);
|
2011-07-14 20:07:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
m_IsCommand = false;
|
2009-01-24 13:12:04 +00:00
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
void CGameConsole::CInstance::PrintLine(const char *pLine, int Len, ColorRGBA PrintColor)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Len > 255)
|
2010-05-29 07:25:38 +00:00
|
|
|
Len = 255;
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.lock();
|
2020-09-22 16:02:03 +00:00
|
|
|
CBacklogEntry *pEntry = m_Backlog.Allocate(sizeof(CBacklogEntry) + Len);
|
2010-10-16 08:32:56 +00:00
|
|
|
pEntry->m_YOffset = -1.0f;
|
2021-03-08 00:08:38 +00:00
|
|
|
pEntry->m_PrintColor = PrintColor;
|
2022-06-24 23:19:40 +00:00
|
|
|
str_copy(pEntry->m_aText, pLine, Len + 1);
|
2021-09-12 17:32:00 +00:00
|
|
|
if(m_pGameConsole->m_ConsoleType == m_Type)
|
|
|
|
m_pGameConsole->m_NewLineCounter++;
|
2022-04-22 23:04:48 +00:00
|
|
|
m_BacklogLock.unlock();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
CGameConsole::CGameConsole() :
|
|
|
|
m_LocalConsole(CONSOLETYPE_LOCAL), m_RemoteConsole(CONSOLETYPE_REMOTE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
m_ConsoleType = CONSOLETYPE_LOCAL;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleState = CONSOLE_CLOSED;
|
|
|
|
m_StateChangeEnd = 0.0f;
|
|
|
|
m_StateChangeDuration = 0.1f;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
CGameConsole::~CGameConsole()
|
|
|
|
{
|
2022-05-26 11:02:07 +00:00
|
|
|
if(m_pConsoleLogger)
|
|
|
|
m_pConsoleLogger->OnConsoleDeletion();
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
float CGameConsole::TimeNow()
|
2008-01-30 13:15:58 +00:00
|
|
|
{
|
2022-08-09 15:42:23 +00:00
|
|
|
static int64_t s_TimeStart = time_get();
|
2020-09-22 16:02:03 +00:00
|
|
|
return float(time_get() - s_TimeStart) / float(time_freq());
|
2008-01-30 13:15:58 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameConsole::CInstance *CGameConsole::CurrentConsole()
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
if(m_ConsoleType == CONSOLETYPE_REMOTE)
|
|
|
|
return &m_RemoteConsole;
|
|
|
|
return &m_LocalConsole;
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::OnReset()
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2022-08-09 15:40:16 +00:00
|
|
|
m_RemoteConsole.Reset();
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// only defined for 0<=t<=1
|
2010-05-29 07:25:38 +00:00
|
|
|
static float ConsoleScaleFunc(float t)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
//return t;
|
2020-09-22 16:02:03 +00:00
|
|
|
return sinf(acosf(1.0f - t));
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-01-18 15:55:03 +00:00
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
struct CCompletionOptionRenderInfo
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameConsole *m_pSelf;
|
|
|
|
CTextCursor m_Cursor;
|
|
|
|
const char *m_pCurrentCmd;
|
|
|
|
int m_WantedCompletion;
|
|
|
|
int m_EnumCount;
|
2010-06-19 11:48:01 +00:00
|
|
|
float m_Offset;
|
|
|
|
float m_Width;
|
2009-01-24 12:16:02 +00:00
|
|
|
};
|
|
|
|
|
2022-08-09 15:26:57 +00:00
|
|
|
void CGameConsole::PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2022-08-09 16:03:04 +00:00
|
|
|
CCompletionOptionRenderInfo *pInfo = static_cast<CCompletionOptionRenderInfo *>(pUser);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pInfo->m_EnumCount == pInfo->m_WantedCompletion)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2020-07-15 19:10:13 +00:00
|
|
|
float tw = pInfo->m_pSelf->TextRender()->TextWidth(pInfo->m_Cursor.m_pFont, pInfo->m_Cursor.m_FontSize, pStr, -1, -1.0f);
|
2022-07-09 15:07:28 +00:00
|
|
|
pInfo->m_pSelf->RenderTools()->DrawRect(pInfo->m_Cursor.m_X - 2.5f, pInfo->m_Cursor.m_Y - 4.f / 2.f, tw + 5.f, pInfo->m_Cursor.m_FontSize + 4.f, ColorRGBA(229.0f / 255.0f, 185.0f / 255.0f, 4.0f / 255.0f, 0.85f), CUI::CORNER_ALL, pInfo->m_Cursor.m_FontSize / 3.f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-06-19 11:48:01 +00:00
|
|
|
// scroll when out of sight
|
|
|
|
if(pInfo->m_Cursor.m_X < 3.0f)
|
|
|
|
pInfo->m_Offset = 0.0f;
|
2020-09-22 16:02:03 +00:00
|
|
|
else if(pInfo->m_Cursor.m_X + tw > pInfo->m_Width)
|
|
|
|
pInfo->m_Offset -= pInfo->m_Width / 2;
|
2010-06-19 11:48:01 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextColor(0.05f, 0.05f, 0.05f, 1);
|
2010-05-29 07:25:38 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextEx(&pInfo->m_Cursor, pStr, -1);
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
const char *pMatchStart = str_find_nocase(pStr, pInfo->m_pCurrentCmd);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pMatchStart)
|
2009-01-24 12:16:02 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextColor(0.5f, 0.5f, 0.5f, 1);
|
|
|
|
pInfo->m_pSelf->TextRender()->TextEx(&pInfo->m_Cursor, pStr, pMatchStart - pStr);
|
|
|
|
pInfo->m_pSelf->TextRender()->TextColor(229.0f / 255.0f, 185.0f / 255.0f, 4.0f / 255.0f, 1);
|
2010-05-29 07:25:38 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextEx(&pInfo->m_Cursor, pMatchStart, str_length(pInfo->m_pCurrentCmd));
|
2020-09-22 16:02:03 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextColor(0.5f, 0.5f, 0.5f, 1);
|
|
|
|
pInfo->m_pSelf->TextRender()->TextEx(&pInfo->m_Cursor, pMatchStart + str_length(pInfo->m_pCurrentCmd), -1);
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1);
|
2010-05-29 07:25:38 +00:00
|
|
|
pInfo->m_pSelf->TextRender()->TextEx(&pInfo->m_Cursor, pStr, -1);
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
pInfo->m_EnumCount++;
|
|
|
|
pInfo->m_Cursor.m_X += 7.0f;
|
2009-01-24 12:16:02 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::OnRender()
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2011-04-13 18:37:12 +00:00
|
|
|
CUIRect Screen = *UI()->Screen();
|
2020-09-22 16:02:03 +00:00
|
|
|
float ConsoleMaxHeight = Screen.h * 3 / 5.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
float ConsoleHeight;
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
float Progress = (TimeNow() - (m_StateChangeEnd - m_StateChangeDuration)) / m_StateChangeDuration;
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Progress >= 1.0f)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_CLOSING)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleState = CONSOLE_CLOSED;
|
2020-09-22 16:02:03 +00:00
|
|
|
else if(m_ConsoleState == CONSOLE_OPENING)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleState = CONSOLE_OPEN;
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Progress = 1.0f;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2009-05-31 09:44:20 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_OPEN && g_Config.m_ClEditor)
|
2011-04-13 18:37:12 +00:00
|
|
|
Toggle(CONSOLETYPE_LOCAL);
|
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_CLOSED)
|
2008-08-27 15:48:50 +00:00
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_OPEN)
|
2010-05-29 07:25:38 +00:00
|
|
|
Input()->MouseModeAbsolute();
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
float ConsoleHeightScale;
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_OPENING)
|
2010-05-29 07:25:38 +00:00
|
|
|
ConsoleHeightScale = ConsoleScaleFunc(Progress);
|
2020-09-22 16:02:03 +00:00
|
|
|
else if(m_ConsoleState == CONSOLE_CLOSING)
|
|
|
|
ConsoleHeightScale = ConsoleScaleFunc(1.0f - Progress);
|
2008-08-27 15:48:50 +00:00
|
|
|
else //if (console_state == CONSOLE_OPEN)
|
2010-05-29 07:25:38 +00:00
|
|
|
ConsoleHeightScale = ConsoleScaleFunc(1.0f);
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
ConsoleHeight = ConsoleHeightScale * ConsoleMaxHeight;
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2021-09-22 19:48:55 +00:00
|
|
|
UI()->MapScreen();
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do console shadow
|
2012-08-12 10:41:50 +00:00
|
|
|
Graphics()->TextureClear();
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsBegin();
|
2010-05-29 07:25:38 +00:00
|
|
|
IGraphics::CColorVertex Array[4] = {
|
2020-09-22 16:02:03 +00:00
|
|
|
IGraphics::CColorVertex(0, 0, 0, 0, 0.5f),
|
|
|
|
IGraphics::CColorVertex(1, 0, 0, 0, 0.5f),
|
|
|
|
IGraphics::CColorVertex(2, 0, 0, 0, 0.0f),
|
|
|
|
IGraphics::CColorVertex(3, 0, 0, 0, 0.0f)};
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->SetColorVertex(Array, 4);
|
|
|
|
IGraphics::CQuadItem QuadItem(0, ConsoleHeight, Screen.w, 10.0f);
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsEnd();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do background
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CONSOLE_BG].m_Id);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsBegin();
|
2020-09-22 16:02:03 +00:00
|
|
|
Graphics()->SetColor(0.2f, 0.2f, 0.2f, 0.9f);
|
2011-04-13 18:37:12 +00:00
|
|
|
if(m_ConsoleType == CONSOLETYPE_REMOTE)
|
2020-09-22 16:02:03 +00:00
|
|
|
Graphics()->SetColor(0.4f, 0.2f, 0.2f, 0.9f);
|
|
|
|
Graphics()->QuadsSetSubset(0, -ConsoleHeight * 0.075f, Screen.w * 0.075f * 0.5f, 0);
|
2010-05-29 07:25:38 +00:00
|
|
|
QuadItem = IGraphics::CQuadItem(0, 0, Screen.w, ConsoleHeight);
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsEnd();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do small bar shadow
|
2012-08-12 10:41:50 +00:00
|
|
|
Graphics()->TextureClear();
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsBegin();
|
2020-09-22 16:02:03 +00:00
|
|
|
Array[0] = IGraphics::CColorVertex(0, 0, 0, 0, 0.0f);
|
|
|
|
Array[1] = IGraphics::CColorVertex(1, 0, 0, 0, 0.0f);
|
|
|
|
Array[2] = IGraphics::CColorVertex(2, 0, 0, 0, 0.25f);
|
|
|
|
Array[3] = IGraphics::CColorVertex(3, 0, 0, 0, 0.25f);
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->SetColorVertex(Array, 4);
|
2020-09-22 16:02:03 +00:00
|
|
|
QuadItem = IGraphics::CQuadItem(0, ConsoleHeight - 20, Screen.w, 10);
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsEnd();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do the lower bar
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CONSOLE_BAR].m_Id);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.9f);
|
2020-09-22 16:02:03 +00:00
|
|
|
Graphics()->QuadsSetSubset(0, 0.1f, Screen.w * 0.015f, 1 - 0.1f);
|
|
|
|
QuadItem = IGraphics::CQuadItem(0, ConsoleHeight - 10.0f, Screen.w, 10.0f);
|
2010-05-29 07:25:38 +00:00
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
2011-04-13 18:37:12 +00:00
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
|
|
|
ConsoleHeight -= 22.0f;
|
|
|
|
|
|
|
|
CInstance *pConsole = CurrentConsole();
|
2008-03-29 15:00:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
float FontSize = 10.0f;
|
2020-09-22 16:02:03 +00:00
|
|
|
float RowHeight = FontSize * 1.25f;
|
2008-08-27 15:48:50 +00:00
|
|
|
float x = 3;
|
2011-03-15 08:15:46 +00:00
|
|
|
float y = ConsoleHeight - RowHeight - 5.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
const float InitialX = x;
|
|
|
|
const float InitialY = y;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2011-04-13 18:37:12 +00:00
|
|
|
// render prompt
|
2011-03-15 08:15:46 +00:00
|
|
|
CTextCursor Cursor;
|
|
|
|
TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
|
2010-05-29 07:25:38 +00:00
|
|
|
const char *pPrompt = "> ";
|
2010-11-17 12:01:46 +00:00
|
|
|
if(m_ConsoleType == CONSOLETYPE_REMOTE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2017-03-28 00:12:22 +00:00
|
|
|
if(Client()->State() == IClient::STATE_LOADING || Client()->State() == IClient::STATE_ONLINE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Client()->RconAuthed())
|
|
|
|
pPrompt = "rcon> ";
|
2008-08-27 15:48:50 +00:00
|
|
|
else
|
2017-03-02 15:16:50 +00:00
|
|
|
{
|
2017-07-24 19:43:55 +00:00
|
|
|
if(pConsole->m_UsernameReq)
|
2017-03-02 15:16:50 +00:00
|
|
|
{
|
2017-03-06 12:49:08 +00:00
|
|
|
if(!pConsole->m_UserGot)
|
2017-03-02 15:16:50 +00:00
|
|
|
pPrompt = "Enter Username> ";
|
|
|
|
else
|
|
|
|
pPrompt = "Enter Password> ";
|
|
|
|
}
|
|
|
|
else
|
2017-03-06 19:11:23 +00:00
|
|
|
pPrompt = "Enter Password> ";
|
2017-03-02 15:16:50 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
pPrompt = "NOT CONNECTED> ";
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
TextRender()->TextEx(&Cursor, pPrompt, -1);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-15 08:15:46 +00:00
|
|
|
x = Cursor.m_X;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2016-08-15 05:16:06 +00:00
|
|
|
//console text editing
|
|
|
|
bool Editing = false;
|
|
|
|
int EditingCursor = Input()->GetEditingCursor();
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Input()->GetIMEState())
|
2016-08-15 05:16:06 +00:00
|
|
|
{
|
2020-10-25 15:48:12 +00:00
|
|
|
if(str_length(Input()->GetIMEEditingText()))
|
2016-08-15 05:16:06 +00:00
|
|
|
{
|
2020-10-25 15:48:12 +00:00
|
|
|
pConsole->m_Input.Editing(Input()->GetIMEEditingText(), EditingCursor);
|
2016-08-15 05:16:06 +00:00
|
|
|
Editing = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
//hide rcon password
|
2014-03-30 20:58:59 +00:00
|
|
|
char aInputString[512];
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(aInputString, pConsole->m_Input.GetString(Editing));
|
2017-07-24 19:43:55 +00:00
|
|
|
if(m_ConsoleType == CONSOLETYPE_REMOTE && Client()->State() == IClient::STATE_ONLINE && !Client()->RconAuthed() && (pConsole->m_UserGot || !pConsole->m_UsernameReq))
|
2009-01-24 13:12:04 +00:00
|
|
|
{
|
2016-08-15 05:16:06 +00:00
|
|
|
for(int i = 0; i < pConsole->m_Input.GetLength(Editing); ++i)
|
2010-05-29 07:25:38 +00:00
|
|
|
aInputString[i] = '*';
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2012-04-20 22:23:48 +00:00
|
|
|
// render console input (wrap line)
|
|
|
|
TextRender()->SetCursor(&Cursor, x, y, FontSize, 0);
|
|
|
|
Cursor.m_LineWidth = Screen.w - 10.0f - x;
|
2016-08-15 05:16:06 +00:00
|
|
|
TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset(Editing));
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->TextEx(&Cursor, aInputString + pConsole->m_Input.GetCursorOffset(Editing), -1);
|
2012-04-20 22:23:48 +00:00
|
|
|
int Lines = Cursor.m_LineCount;
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2021-10-25 17:28:38 +00:00
|
|
|
int InputExtraLineCount = Lines - 1;
|
|
|
|
y -= InputExtraLineCount * FontSize;
|
2012-04-20 22:23:48 +00:00
|
|
|
TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
|
|
|
|
Cursor.m_LineWidth = Screen.w - 10.0f - x;
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2021-10-25 17:28:38 +00:00
|
|
|
if(m_LastInputLineCount != InputExtraLineCount)
|
|
|
|
{
|
|
|
|
m_HasSelection = false;
|
|
|
|
m_MouseIsPress = false;
|
|
|
|
m_LastInputLineCount = InputExtraLineCount;
|
|
|
|
}
|
|
|
|
|
2016-08-15 05:16:06 +00:00
|
|
|
TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset(Editing));
|
2010-05-29 07:25:38 +00:00
|
|
|
CTextCursor Marker = Cursor;
|
2012-04-20 22:23:48 +00:00
|
|
|
Marker.m_LineWidth = -1;
|
2010-05-29 07:25:38 +00:00
|
|
|
TextRender()->TextEx(&Marker, "|", -1);
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->TextEx(&Cursor, aInputString + pConsole->m_Input.GetCursorOffset(Editing), -1);
|
2020-09-22 16:01:13 +00:00
|
|
|
Input()->SetEditingPosition(Marker.m_X, Marker.m_Y + Marker.m_FontSize);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// render possible commands
|
2022-08-09 16:03:04 +00:00
|
|
|
if((m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed()) && pConsole->m_Input.GetString()[0])
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2022-08-09 16:03:04 +00:00
|
|
|
CCompletionOptionRenderInfo Info;
|
|
|
|
Info.m_pSelf = this;
|
|
|
|
Info.m_WantedCompletion = pConsole->m_CompletionChosen;
|
|
|
|
Info.m_EnumCount = 0;
|
|
|
|
Info.m_Offset = pConsole->m_CompletionRenderOffset;
|
|
|
|
Info.m_Width = Screen.w;
|
|
|
|
Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer;
|
|
|
|
TextRender()->SetCursor(&Info.m_Cursor, InitialX + Info.m_Offset, InitialY + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
|
|
|
Info.m_Cursor.m_LineWidth = std::numeric_limits<float>::max();
|
|
|
|
m_pConsole->PossibleCommands(Info.m_pCurrentCmd, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info);
|
|
|
|
pConsole->m_CompletionRenderOffset = Info.m_Offset;
|
|
|
|
|
|
|
|
if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
|
2009-01-24 13:12:04 +00:00
|
|
|
{
|
2022-08-09 16:03:04 +00:00
|
|
|
const bool TuningCompletion = IsTuningCommandPrefix(Info.m_pCurrentCmd);
|
|
|
|
if(TuningCompletion)
|
|
|
|
{
|
|
|
|
Info.m_WantedCompletion = pConsole->m_CompletionChosenArgument;
|
|
|
|
Info.m_EnumCount = 0;
|
|
|
|
Info.m_pCurrentCmd = pConsole->m_aCompletionBufferArgument;
|
|
|
|
m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(Info.m_pCurrentCmd, PossibleCommandsRenderCallback, &Info);
|
|
|
|
pConsole->m_CompletionRenderOffset = Info.m_Offset;
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2022-08-09 16:03:04 +00:00
|
|
|
if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
|
2009-01-24 13:12:04 +00:00
|
|
|
{
|
2022-08-09 16:03:04 +00:00
|
|
|
char aBuf[512];
|
|
|
|
str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp);
|
|
|
|
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
|
|
|
|
TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1);
|
|
|
|
str_format(aBuf, sizeof(aBuf), "Usage: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams);
|
|
|
|
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
|
2009-01-24 13:12:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-20 12:37:11 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
pConsole->m_BacklogLock.lock();
|
|
|
|
|
2022-04-01 16:32:51 +00:00
|
|
|
// render log (current page, wrap lines)
|
2010-10-16 08:32:56 +00:00
|
|
|
CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.Last();
|
|
|
|
float OffsetY = 0.0f;
|
|
|
|
float LineOffset = 1.0f;
|
2014-12-20 12:37:11 +00:00
|
|
|
|
2021-09-12 17:32:00 +00:00
|
|
|
bool WantsSelectionCopy = false;
|
2021-12-18 11:23:20 +00:00
|
|
|
if(Input()->ModifierIsPressed() && Input()->KeyPress(KEY_C))
|
2021-09-12 17:32:00 +00:00
|
|
|
WantsSelectionCopy = true;
|
|
|
|
std::string SelectionString;
|
|
|
|
|
2021-10-25 17:28:38 +00:00
|
|
|
// check if mouse is pressed
|
|
|
|
if(!m_MouseIsPress && Input()->NativeMousePressed(1))
|
|
|
|
{
|
|
|
|
m_MouseIsPress = true;
|
|
|
|
Input()->NativeMousePos(&m_MousePressX, &m_MousePressY);
|
|
|
|
m_MousePressX = (m_MousePressX / (float)Graphics()->WindowWidth()) * Screen.w;
|
|
|
|
m_MousePressY = (m_MousePressY / (float)Graphics()->WindowHeight()) * Screen.h;
|
|
|
|
}
|
|
|
|
if(m_MouseIsPress)
|
|
|
|
{
|
|
|
|
Input()->NativeMousePos(&m_MouseCurX, &m_MouseCurY);
|
|
|
|
m_MouseCurX = (m_MouseCurX / (float)Graphics()->WindowWidth()) * Screen.w;
|
|
|
|
m_MouseCurY = (m_MouseCurY / (float)Graphics()->WindowHeight()) * Screen.h;
|
|
|
|
}
|
|
|
|
if(m_MouseIsPress && !Input()->NativeMousePressed(1))
|
|
|
|
{
|
|
|
|
m_MouseIsPress = false;
|
|
|
|
}
|
|
|
|
|
2022-04-29 15:51:10 +00:00
|
|
|
static int s_LastActivePage = pConsole->m_BacklogCurPage;
|
|
|
|
int TotalPages = 1;
|
2022-08-09 21:42:20 +00:00
|
|
|
for(int Page = 0; Page <= maximum(s_LastActivePage, pConsole->m_BacklogCurPage); ++Page, OffsetY = 0.0f)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-03-15 08:15:46 +00:00
|
|
|
while(pEntry)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2021-03-08 00:08:38 +00:00
|
|
|
TextRender()->TextColor(pEntry->m_PrintColor);
|
2014-12-20 12:37:11 +00:00
|
|
|
|
2010-10-16 08:32:56 +00:00
|
|
|
// get y offset (calculate it if we haven't yet)
|
|
|
|
if(pEntry->m_YOffset < 0.0f)
|
|
|
|
{
|
|
|
|
TextRender()->SetCursor(&Cursor, 0.0f, 0.0f, FontSize, 0);
|
2020-09-22 16:02:03 +00:00
|
|
|
Cursor.m_LineWidth = Screen.w - 10;
|
2010-10-16 08:32:56 +00:00
|
|
|
TextRender()->TextEx(&Cursor, pEntry->m_aText, -1);
|
2021-09-12 17:32:00 +00:00
|
|
|
pEntry->m_YOffset = Cursor.m_Y + Cursor.m_AlignedFontSize + LineOffset;
|
2010-10-16 08:32:56 +00:00
|
|
|
}
|
|
|
|
OffsetY += pEntry->m_YOffset;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2021-10-25 17:28:38 +00:00
|
|
|
if((m_HasSelection || m_MouseIsPress) && m_NewLineCounter > 0)
|
2021-09-12 17:32:00 +00:00
|
|
|
{
|
2021-10-25 17:28:38 +00:00
|
|
|
float MouseExtraOff = pEntry->m_YOffset;
|
|
|
|
m_MousePressY -= MouseExtraOff;
|
|
|
|
if(!m_MouseIsPress)
|
|
|
|
m_MouseCurY -= MouseExtraOff;
|
2021-09-12 17:32:00 +00:00
|
|
|
}
|
|
|
|
|
2021-10-25 17:28:38 +00:00
|
|
|
// next page when lines reach the top
|
|
|
|
if(y - OffsetY <= RowHeight)
|
|
|
|
break;
|
|
|
|
|
2022-04-01 16:32:51 +00:00
|
|
|
// just render output from current backlog page (render bottom up)
|
2022-04-29 15:51:10 +00:00
|
|
|
if(Page == s_LastActivePage)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->SetCursor(&Cursor, 0.0f, y - OffsetY, FontSize, TEXTFLAG_RENDER);
|
|
|
|
Cursor.m_LineWidth = Screen.w - 10.0f;
|
2021-09-12 17:32:00 +00:00
|
|
|
Cursor.m_CalculateSelectionMode = (m_MouseIsPress || (m_CurSelStart != m_CurSelEnd) || m_HasSelection) ? TEXT_CURSOR_SELECTION_MODE_CALCULATE : TEXT_CURSOR_SELECTION_MODE_NONE;
|
|
|
|
Cursor.m_PressMouseX = m_MousePressX;
|
|
|
|
Cursor.m_PressMouseY = m_MousePressY;
|
|
|
|
Cursor.m_ReleaseMouseX = m_MouseCurX;
|
|
|
|
Cursor.m_ReleaseMouseY = m_MouseCurY;
|
2010-10-16 08:32:56 +00:00
|
|
|
TextRender()->TextEx(&Cursor, pEntry->m_aText, -1);
|
2021-09-12 17:32:00 +00:00
|
|
|
if(Cursor.m_CalculateSelectionMode == TEXT_CURSOR_SELECTION_MODE_CALCULATE)
|
|
|
|
{
|
|
|
|
m_CurSelStart = minimum(Cursor.m_SelectionStart, Cursor.m_SelectionEnd);
|
|
|
|
m_CurSelEnd = maximum(Cursor.m_SelectionStart, Cursor.m_SelectionEnd);
|
|
|
|
}
|
|
|
|
if(m_CurSelStart != m_CurSelEnd)
|
|
|
|
{
|
|
|
|
if(WantsSelectionCopy)
|
|
|
|
{
|
|
|
|
bool HasNewLine = false;
|
|
|
|
if(!SelectionString.empty())
|
|
|
|
HasNewLine = true;
|
|
|
|
int OffUTF8Start = 0;
|
|
|
|
int OffUTF8End = 0;
|
|
|
|
if(TextRender()->SelectionToUTF8OffSets(pEntry->m_aText, m_CurSelStart, m_CurSelEnd, OffUTF8Start, OffUTF8End))
|
|
|
|
{
|
|
|
|
SelectionString.insert(0, (std::string(&pEntry->m_aText[OffUTF8Start], OffUTF8End - OffUTF8Start) + (HasNewLine ? "\n" : "")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_HasSelection = true;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
pEntry = pConsole->m_Backlog.Prev(pEntry);
|
2015-01-27 00:13:27 +00:00
|
|
|
|
|
|
|
// reset color
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->TextColor(1, 1, 1, 1);
|
2021-09-12 17:32:00 +00:00
|
|
|
if(m_NewLineCounter > 0)
|
|
|
|
--m_NewLineCounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(WantsSelectionCopy && !SelectionString.empty())
|
|
|
|
{
|
|
|
|
Input()->SetClipboardText(SelectionString.c_str());
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2022-04-29 15:51:10 +00:00
|
|
|
if(!pEntry)
|
2010-05-29 07:25:38 +00:00
|
|
|
break;
|
2022-04-29 15:51:10 +00:00
|
|
|
TotalPages++;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2022-04-29 15:51:10 +00:00
|
|
|
pConsole->m_BacklogCurPage = clamp(pConsole->m_BacklogCurPage, 0, TotalPages - 1);
|
|
|
|
s_LastActivePage = pConsole->m_BacklogCurPage;
|
2011-03-15 08:15:46 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
pConsole->m_BacklogLock.unlock();
|
|
|
|
|
2011-03-15 08:15:46 +00:00
|
|
|
// render page
|
|
|
|
char aBuf[128];
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->TextColor(1, 1, 1, 1);
|
2022-04-01 16:32:51 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("-Page %d-"), pConsole->m_BacklogCurPage + 1);
|
2020-07-15 19:42:48 +00:00
|
|
|
TextRender()->Text(0, 10.0f, FontSize / 2.f, FontSize, aBuf, -1.0f);
|
2011-03-15 08:15:46 +00:00
|
|
|
|
|
|
|
// render version
|
2022-07-09 16:14:56 +00:00
|
|
|
str_copy(aBuf, "v" GAME_VERSION " on " CONF_PLATFORM_STRING " " CONF_ARCH_STRING);
|
2020-07-15 19:10:13 +00:00
|
|
|
float Width = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
|
2020-09-22 16:02:03 +00:00
|
|
|
TextRender()->Text(0, Screen.w - Width - 10.0f, FontSize / 2.f, FontSize, aBuf, -1.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
}
|
2008-03-23 09:22:15 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::OnMessage(int MsgType, void *pRawMsg)
|
2008-03-01 20:03:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
bool CGameConsole::OnInput(IInput::CEvent Event)
|
2008-03-01 20:03:04 +00:00
|
|
|
{
|
2016-05-22 19:23:33 +00:00
|
|
|
// accept input when opening, but not at first frame to discard the input that caused the console to open
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState != CONSOLE_OPEN && (m_ConsoleState != CONSOLE_OPENING || m_StateChangeEnd == TimeNow() + m_StateChangeDuration))
|
2008-08-27 16:23:15 +00:00
|
|
|
return false;
|
2015-08-24 20:46:28 +00:00
|
|
|
if((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24))
|
2008-08-27 16:23:15 +00:00
|
|
|
return false;
|
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(Event.m_Key == KEY_ESCAPE && (Event.m_Flags & IInput::FLAG_PRESS))
|
2010-05-29 07:25:38 +00:00
|
|
|
Toggle(m_ConsoleType);
|
2008-08-27 16:23:15 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
CurrentConsole()->OnInput(Event);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 16:23:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::Toggle(int Type)
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_ConsoleType != Type && (m_ConsoleState == CONSOLE_OPEN || m_ConsoleState == CONSOLE_OPENING))
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
|
|
|
// don't toggle console, just switch what console to use
|
|
|
|
}
|
|
|
|
else
|
2011-04-13 18:37:12 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_CLOSED || m_ConsoleState == CONSOLE_OPEN)
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
m_StateChangeEnd = TimeNow() + m_StateChangeDuration;
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-22 16:02:03 +00:00
|
|
|
float Progress = m_StateChangeEnd - TimeNow();
|
|
|
|
float ReversedProgress = m_StateChangeDuration - Progress;
|
2008-08-27 16:23:15 +00:00
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
m_StateChangeEnd = TimeNow() + ReversedProgress;
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-09-22 16:02:03 +00:00
|
|
|
if(m_ConsoleState == CONSOLE_CLOSED || m_ConsoleState == CONSOLE_CLOSING)
|
2008-10-20 18:12:15 +00:00
|
|
|
{
|
2022-05-27 16:14:31 +00:00
|
|
|
UI()->SetEnabled(false);
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleState = CONSOLE_OPENING;
|
2016-08-15 05:16:06 +00:00
|
|
|
|
|
|
|
Input()->SetIMEState(true);
|
2008-10-20 18:12:15 +00:00
|
|
|
}
|
2008-08-27 16:23:15 +00:00
|
|
|
else
|
2008-10-20 18:12:15 +00:00
|
|
|
{
|
2021-10-23 11:48:21 +00:00
|
|
|
Input()->MouseModeRelative();
|
2022-05-27 16:14:31 +00:00
|
|
|
UI()->SetEnabled(true);
|
2010-09-12 10:43:03 +00:00
|
|
|
m_pClient->OnRelease();
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleState = CONSOLE_CLOSING;
|
2016-08-15 05:16:06 +00:00
|
|
|
|
|
|
|
Input()->SetIMEState(false);
|
2008-10-20 18:12:15 +00:00
|
|
|
}
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
2021-09-12 17:32:00 +00:00
|
|
|
if(m_ConsoleType != Type)
|
|
|
|
m_HasSelection = false;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ConsoleType = Type;
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
|
2010-06-20 12:12:59 +00:00
|
|
|
void CGameConsole::Dump(int Type)
|
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
CInstance *pConsole = Type == CONSOLETYPE_REMOTE ? &m_RemoteConsole : &m_LocalConsole;
|
2022-08-09 14:41:00 +00:00
|
|
|
char aBuf[IO_MAX_PATH_LENGTH + 64];
|
2021-09-13 08:06:34 +00:00
|
|
|
char aFilename[IO_MAX_PATH_LENGTH];
|
2022-08-09 14:41:00 +00:00
|
|
|
str_timestamp(aBuf, sizeof(aBuf));
|
|
|
|
str_format(aFilename, sizeof(aFilename), "dumps/%s_dump_%s.txt", pConsole->m_pName, aBuf);
|
|
|
|
IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
|
|
|
if(File)
|
2010-06-20 12:12:59 +00:00
|
|
|
{
|
2022-04-22 23:04:48 +00:00
|
|
|
pConsole->m_BacklogLock.lock();
|
2010-12-07 23:32:50 +00:00
|
|
|
for(CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.First(); pEntry; pEntry = pConsole->m_Backlog.Next(pEntry))
|
|
|
|
{
|
2022-08-09 14:41:00 +00:00
|
|
|
io_write(File, pEntry->m_aText, str_length(pEntry->m_aText));
|
|
|
|
io_write_newline(File);
|
2010-06-20 12:12:59 +00:00
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
pConsole->m_BacklogLock.unlock();
|
2022-08-09 14:41:00 +00:00
|
|
|
io_close(File);
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s contents were written to '%s'", pConsole->m_pName, aFilename);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str_format(aBuf, sizeof(aBuf), "Failed to open '%s'", aFilename);
|
2010-06-20 12:12:59 +00:00
|
|
|
}
|
2022-08-09 14:41:00 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
|
2010-06-20 12:12:59 +00:00
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData)
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
((CGameConsole *)pUserData)->Toggle(CONSOLETYPE_LOCAL);
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData)
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
((CGameConsole *)pUserData)->Toggle(CONSOLETYPE_REMOTE);
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConClearLocalConsole(IConsole::IResult *pResult, void *pUserData)
|
2010-06-19 18:51:54 +00:00
|
|
|
{
|
|
|
|
((CGameConsole *)pUserData)->m_LocalConsole.ClearBacklog();
|
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData)
|
2010-06-19 18:51:54 +00:00
|
|
|
{
|
|
|
|
((CGameConsole *)pUserData)->m_RemoteConsole.ClearBacklog();
|
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData)
|
2010-06-20 12:12:59 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
((CGameConsole *)pUserData)->Dump(CONSOLETYPE_LOCAL);
|
2010-06-20 12:12:59 +00:00
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameConsole::ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData)
|
2010-06-20 12:12:59 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
((CGameConsole *)pUserData)->Dump(CONSOLETYPE_REMOTE);
|
2010-06-20 12:12:59 +00:00
|
|
|
}
|
|
|
|
|
2018-06-03 09:48:08 +00:00
|
|
|
void CGameConsole::ConConsolePageUp(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
CInstance *pConsole = ((CGameConsole *)pUserData)->CurrentConsole();
|
2022-04-01 16:32:51 +00:00
|
|
|
pConsole->m_BacklogCurPage++;
|
2018-06-03 09:48:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGameConsole::ConConsolePageDown(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
CInstance *pConsole = ((CGameConsole *)pUserData)->CurrentConsole();
|
2022-04-01 16:32:51 +00:00
|
|
|
--pConsole->m_BacklogCurPage;
|
|
|
|
if(pConsole->m_BacklogCurPage < 0)
|
|
|
|
pConsole->m_BacklogCurPage = 0;
|
2018-06-03 09:48:08 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 19:43:55 +00:00
|
|
|
void CGameConsole::RequireUsername(bool UsernameReq)
|
|
|
|
{
|
2017-10-16 18:08:39 +00:00
|
|
|
if((m_RemoteConsole.m_UsernameReq = UsernameReq))
|
|
|
|
{
|
|
|
|
m_RemoteConsole.m_aUser[0] = '\0';
|
|
|
|
m_RemoteConsole.m_UserGot = false;
|
|
|
|
}
|
2017-07-24 19:43:55 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::PrintLine(int Type, const char *pLine)
|
2008-08-30 08:01:29 +00:00
|
|
|
{
|
2010-11-17 12:01:46 +00:00
|
|
|
if(Type == CONSOLETYPE_LOCAL)
|
2022-04-22 23:04:48 +00:00
|
|
|
m_LocalConsole.PrintLine(pLine, str_length(pLine), ColorRGBA{1, 1, 1, 1});
|
2010-11-17 12:01:46 +00:00
|
|
|
else if(Type == CONSOLETYPE_REMOTE)
|
2022-04-22 23:04:48 +00:00
|
|
|
m_RemoteConsole.PrintLine(pLine, str_length(pLine), ColorRGBA{1, 1, 1, 1});
|
2008-08-30 08:01:29 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameConsole::OnConsoleInit()
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
2010-06-05 11:38:08 +00:00
|
|
|
// init console instances
|
|
|
|
m_LocalConsole.Init(this);
|
|
|
|
m_RemoteConsole.Init(this);
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pConsole = Kernel()->RequestInterface<IConsole>();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
Console()->Register("toggle_local_console", "", CFGFLAG_CLIENT, ConToggleLocalConsole, this, "Toggle local console");
|
|
|
|
Console()->Register("toggle_remote_console", "", CFGFLAG_CLIENT, ConToggleRemoteConsole, this, "Toggle remote console");
|
2010-06-19 18:51:54 +00:00
|
|
|
Console()->Register("clear_local_console", "", CFGFLAG_CLIENT, ConClearLocalConsole, this, "Clear local console");
|
|
|
|
Console()->Register("clear_remote_console", "", CFGFLAG_CLIENT, ConClearRemoteConsole, this, "Clear remote console");
|
2022-08-09 14:41:00 +00:00
|
|
|
Console()->Register("dump_local_console", "", CFGFLAG_CLIENT, ConDumpLocalConsole, this, "Write local console contents to a text file");
|
|
|
|
Console()->Register("dump_remote_console", "", CFGFLAG_CLIENT, ConDumpRemoteConsole, this, "Write remote console contents to a text file");
|
2011-07-30 11:40:01 +00:00
|
|
|
|
2018-06-03 09:48:08 +00:00
|
|
|
Console()->Register("console_page_up", "", CFGFLAG_CLIENT, ConConsolePageUp, this, "Previous page in console");
|
|
|
|
Console()->Register("console_page_down", "", CFGFLAG_CLIENT, ConConsolePageDown, this, "Next page in console");
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 21:36:41 +00:00
|
|
|
void CGameConsole::OnInit()
|
|
|
|
{
|
2022-04-22 23:04:48 +00:00
|
|
|
m_pConsoleLogger = new CConsoleLogger(this);
|
|
|
|
Engine()->SetAdditionalLogger(std::unique_ptr<ILogger>(m_pConsoleLogger));
|
2022-01-14 21:36:41 +00:00
|
|
|
// add resize event
|
|
|
|
Graphics()->AddWindowResizeListener([this](void *) {
|
|
|
|
m_LocalConsole.ClearBacklogYOffsets();
|
|
|
|
m_RemoteConsole.ClearBacklogYOffsets();
|
|
|
|
m_HasSelection = false;
|
|
|
|
},
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
2010-10-10 22:30:56 +00:00
|
|
|
void CGameConsole::OnStateChange(int NewState, int OldState)
|
2008-03-29 15:00:04 +00:00
|
|
|
{
|
2017-03-23 06:16:03 +00:00
|
|
|
if(OldState == IClient::STATE_ONLINE && NewState < IClient::STATE_LOADING)
|
2017-03-28 00:12:22 +00:00
|
|
|
{
|
2017-03-23 06:16:03 +00:00
|
|
|
m_RemoteConsole.m_UserGot = false;
|
2017-10-16 18:01:33 +00:00
|
|
|
m_RemoteConsole.m_aUser[0] = '\0';
|
2017-03-28 00:12:22 +00:00
|
|
|
m_RemoteConsole.m_Input.Clear();
|
2017-07-24 19:43:55 +00:00
|
|
|
m_RemoteConsole.m_UsernameReq = false;
|
2017-03-28 00:12:22 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|