mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #5724
5724: Show console completion options for tunings, extend and rename commands according to upstream r=def- a=Robyt3 - Rename commands that list things according to upstream so they are consistent and improve command descriptions: - `dump_binds` -> `binds` - `tune_dump` -> `tunes` - `bans` (already named fittingly) - `dump_(local|remote)_console` (named correctly, `dump` should be used when writing to a file) - Add success/error messages to `dump_(local|remote)_console` and improve description. - Print error when using incorrect tuning names like `tune xyz 123`. - Extend `tune_reset` so a single tuning value can be reset to default. For example `tune_reset player_collision` will reset just the `player_collision` tuning, whereas `tune_reset` will reset all to defaults like before. - Get the actual tuning value after setting it, as the value that was applied may differ due to overflow or rounding errors. - Extend `tune` so the current value of a given tuning variable is printed if no new value is given, so it works like commands in the console. For example `tune player_collision` will print the current value of the variable, whereas `tune player_collision 0` will change the value like before. - Show completion options for tune params in console. Closes #5711. - Currently supports `tune`, `tune_reset` and `toggle_tune`. - For `tune_zone` the tune name is the second argument, so this is more difficult to handle. - Screenshot: ![screenshot](https://user-images.githubusercontent.com/23437060/184015369-05853414-e45e-474d-a29a-90b82cf94159.png) ## Checklist - [X] Tested the change ingame - [X] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [X] Considered possible null pointers and out of bounds array indexing - [X] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
commit
f10edfa589
|
@ -82,14 +82,16 @@ public:
|
|||
|
||||
typedef void (*FTeeHistorianCommandCallback)(int ClientID, int FlagMask, const char *pCmd, IResult *pResult, void *pUser);
|
||||
typedef void (*FPrintCallback)(const char *pStr, void *pUser, ColorRGBA PrintColor);
|
||||
typedef void (*FPossibleCallback)(const char *pCmd, void *pUser);
|
||||
typedef void (*FPossibleCallback)(int Index, const char *pCmd, void *pUser);
|
||||
typedef void (*FCommandCallback)(IResult *pResult, void *pUserData);
|
||||
typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData);
|
||||
|
||||
static void EmptyPossibleCommandCallback(int Index, const char *pCmd, void *pUser) {}
|
||||
|
||||
virtual void Init() = 0;
|
||||
virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0;
|
||||
virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) = 0;
|
||||
virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0;
|
||||
virtual int PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback = EmptyPossibleCommandCallback, void *pUser = nullptr) = 0;
|
||||
virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0;
|
||||
|
||||
virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0;
|
||||
|
|
|
@ -551,16 +551,21 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
|
|||
}
|
||||
}
|
||||
|
||||
void CConsole::PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser)
|
||||
int CConsole::PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser)
|
||||
{
|
||||
int Index = 0;
|
||||
for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
|
||||
{
|
||||
if(pCommand->m_Flags & FlagMask && pCommand->m_Temp == Temp)
|
||||
{
|
||||
if(str_find_nocase(pCommand->m_pName, pStr))
|
||||
pfnCallback(pCommand->m_pName, pUser);
|
||||
{
|
||||
pfnCallback(Index, pCommand->m_pName, pUser);
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Index;
|
||||
}
|
||||
|
||||
CConsole::CCommand *CConsole::FindCommand(const char *pName, int FlagMask)
|
||||
|
|
|
@ -196,7 +196,7 @@ public:
|
|||
void Init() override;
|
||||
const CCommandInfo *FirstCommandInfo(int AccessLevel, int FlagMask) const override;
|
||||
const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) override;
|
||||
void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) override;
|
||||
int PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) override;
|
||||
|
||||
void ParseArguments(int NumArgs, const char **ppArguments) override;
|
||||
void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) override;
|
||||
|
|
|
@ -254,7 +254,7 @@ void CBinds::OnConsoleInit()
|
|||
pConfigManager->RegisterCallback(ConfigSaveCallback, this);
|
||||
|
||||
Console()->Register("bind", "s[key] r[command]", CFGFLAG_CLIENT, ConBind, this, "Bind key to execute the command");
|
||||
Console()->Register("dump_binds", "?s[key]", CFGFLAG_CLIENT, ConDumpBinds, this, "Print command executed by this keybindind or all binds");
|
||||
Console()->Register("binds", "?s[key]", CFGFLAG_CLIENT, ConBinds, this, "Print command executed by this keybinding or all binds");
|
||||
Console()->Register("unbind", "s[key]", CFGFLAG_CLIENT, ConUnbind, this, "Unbind key");
|
||||
Console()->Register("unbindall", "", CFGFLAG_CLIENT, ConUnbindAll, this, "Unbind all keys");
|
||||
|
||||
|
@ -280,7 +280,7 @@ void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData)
|
|||
pBinds->Bind(KeyID, pResult->GetString(1), false, Modifier);
|
||||
}
|
||||
|
||||
void CBinds::ConDumpBinds(IConsole::IResult *pResult, void *pUserData)
|
||||
void CBinds::ConBinds(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CBinds *pBinds = (CBinds *)pUserData;
|
||||
if(pResult->NumArguments() == 1)
|
||||
|
|
|
@ -15,7 +15,7 @@ class CBinds : public CComponent
|
|||
int GetKeyID(const char *pKeyName);
|
||||
|
||||
static void ConBind(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConDumpBinds(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConBinds(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConUnbind(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConUnbindAll(IConsole::IResult *pResult, void *pUserData);
|
||||
class IConsole *GetConsole() const { return Console(); }
|
||||
|
|
|
@ -76,6 +76,13 @@ void CConsoleLogger::OnConsoleDeletion()
|
|||
m_pConsole = nullptr;
|
||||
}
|
||||
|
||||
// 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); });
|
||||
}
|
||||
|
||||
CGameConsole::CInstance::CInstance(int Type)
|
||||
{
|
||||
m_pHistoryEntry = 0x0;
|
||||
|
@ -83,15 +90,21 @@ CGameConsole::CInstance::CInstance(int Type)
|
|||
m_Type = Type;
|
||||
|
||||
if(Type == CGameConsole::CONSOLETYPE_LOCAL)
|
||||
{
|
||||
m_pName = "local_console";
|
||||
m_CompletionFlagmask = CFGFLAG_CLIENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pName = "remote_console";
|
||||
m_CompletionFlagmask = CFGFLAG_SERVER;
|
||||
}
|
||||
|
||||
m_aCompletionBuffer[0] = 0;
|
||||
m_CompletionUsed = false;
|
||||
m_CompletionChosen = -1;
|
||||
m_CompletionRenderOffset = 0.0f;
|
||||
m_ReverseTAB = false;
|
||||
m_aCompletionBufferArgument[0] = 0;
|
||||
m_CompletionChosenArgument = -1;
|
||||
Reset();
|
||||
|
||||
m_aUser[0] = '\0';
|
||||
m_UserGot = false;
|
||||
|
@ -131,6 +144,11 @@ void CGameConsole::CInstance::ClearHistory()
|
|||
m_pHistoryEntry = 0;
|
||||
}
|
||||
|
||||
void CGameConsole::CInstance::Reset()
|
||||
{
|
||||
m_CompletionRenderOffset = 0.0f;
|
||||
}
|
||||
|
||||
void CGameConsole::CInstance::ExecuteLine(const char *pLine)
|
||||
{
|
||||
if(m_Type == CGameConsole::CONSOLETYPE_LOCAL)
|
||||
|
@ -155,12 +173,33 @@ void CGameConsole::CInstance::ExecuteLine(const char *pLine)
|
|||
}
|
||||
}
|
||||
|
||||
void CGameConsole::CInstance::PossibleCommandsCompleteCallback(const char *pStr, void *pUser)
|
||||
void CGameConsole::CInstance::PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser)
|
||||
{
|
||||
CGameConsole::CInstance *pInstance = (CGameConsole::CInstance *)pUser;
|
||||
if(pInstance->m_CompletionChosen == pInstance->m_CompletionEnumerationCount)
|
||||
if(pInstance->m_CompletionChosen == Index)
|
||||
pInstance->m_Input.Set(pStr);
|
||||
pInstance->m_CompletionEnumerationCount++;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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];
|
||||
StrCopyUntilSpace(aBuf, sizeof(aBuf), pInstance->GetString());
|
||||
str_append(aBuf, " ", sizeof(aBuf));
|
||||
|
||||
// append argument
|
||||
str_append(aBuf, pStr, sizeof(aBuf));
|
||||
pInstance->m_Input.Set(aBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
|
||||
|
@ -323,23 +362,46 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
|
|||
}
|
||||
else if(Event.m_Key == KEY_TAB)
|
||||
{
|
||||
const int Direction = m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_LSHIFT) || m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_RSHIFT) ? -1 : 1;
|
||||
|
||||
// command completion
|
||||
if(m_Type == CGameConsole::CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed())
|
||||
{
|
||||
if(m_ReverseTAB && m_CompletionUsed)
|
||||
m_CompletionChosen--;
|
||||
else if(!m_ReverseTAB)
|
||||
m_CompletionChosen++;
|
||||
m_CompletionEnumerationCount = 0;
|
||||
m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this);
|
||||
|
||||
m_CompletionUsed = true;
|
||||
|
||||
// handle wrapping
|
||||
if(m_CompletionEnumerationCount && (m_CompletionChosen >= m_CompletionEnumerationCount || m_CompletionChosen < 0))
|
||||
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)
|
||||
{
|
||||
m_CompletionChosen = (m_CompletionChosen + m_CompletionEnumerationCount) % m_CompletionEnumerationCount;
|
||||
m_CompletionEnumerationCount = 0;
|
||||
m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this);
|
||||
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)
|
||||
{
|
||||
m_CompletionChosen = -1;
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,16 +429,6 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
|
|||
m_BacklogCurPage = 0;
|
||||
m_pGameConsole->m_HasSelection = false;
|
||||
}
|
||||
else if(Event.m_Key == KEY_LSHIFT)
|
||||
{
|
||||
m_ReverseTAB = true;
|
||||
Handled = true;
|
||||
}
|
||||
}
|
||||
if(Event.m_Flags & IInput::FLAG_RELEASE && Event.m_Key == KEY_LSHIFT)
|
||||
{
|
||||
m_ReverseTAB = false;
|
||||
Handled = true;
|
||||
}
|
||||
|
||||
if(!Handled)
|
||||
|
@ -384,23 +436,27 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
|
|||
|
||||
if(Event.m_Flags & (IInput::FLAG_PRESS | IInput::FLAG_TEXT))
|
||||
{
|
||||
if((Event.m_Key != KEY_TAB) && (Event.m_Key != KEY_LSHIFT))
|
||||
if(Event.m_Key != KEY_TAB && Event.m_Key != KEY_LSHIFT && Event.m_Key != KEY_RSHIFT)
|
||||
{
|
||||
m_CompletionUsed = false;
|
||||
m_CompletionChosen = -1;
|
||||
str_copy(m_aCompletionBuffer, m_Input.GetString());
|
||||
m_CompletionRenderOffset = 0.0f;
|
||||
|
||||
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)]);
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
// find the current command
|
||||
{
|
||||
char aBuf[64] = {0};
|
||||
const char *pSrc = GetString();
|
||||
int i = 0;
|
||||
for(; i < (int)sizeof(aBuf) - 1 && *pSrc && *pSrc != ' '; i++, pSrc++)
|
||||
aBuf[i] = *pSrc;
|
||||
aBuf[i] = 0;
|
||||
|
||||
char aBuf[sizeof(m_aCommandName)];
|
||||
StrCopyUntilSpace(aBuf, sizeof(aBuf), GetString());
|
||||
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)
|
||||
|
@ -461,6 +517,7 @@ CGameConsole::CInstance *CGameConsole::CurrentConsole()
|
|||
|
||||
void CGameConsole::OnReset()
|
||||
{
|
||||
m_RemoteConsole.Reset();
|
||||
}
|
||||
|
||||
// only defined for 0<=t<=1
|
||||
|
@ -470,7 +527,7 @@ static float ConsoleScaleFunc(float t)
|
|||
return sinf(acosf(1.0f - t));
|
||||
}
|
||||
|
||||
struct CRenderInfo
|
||||
struct CCompletionOptionRenderInfo
|
||||
{
|
||||
CGameConsole *m_pSelf;
|
||||
CTextCursor m_Cursor;
|
||||
|
@ -481,9 +538,9 @@ struct CRenderInfo
|
|||
float m_Width;
|
||||
};
|
||||
|
||||
void CGameConsole::PossibleCommandsRenderCallback(const char *pStr, void *pUser)
|
||||
void CGameConsole::PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser)
|
||||
{
|
||||
CRenderInfo *pInfo = static_cast<CRenderInfo *>(pUser);
|
||||
CCompletionOptionRenderInfo *pInfo = static_cast<CCompletionOptionRenderInfo *>(pUser);
|
||||
|
||||
if(pInfo->m_EnumCount == pInfo->m_WantedCompletion)
|
||||
{
|
||||
|
@ -618,15 +675,8 @@ void CGameConsole::OnRender()
|
|||
float x = 3;
|
||||
float y = ConsoleHeight - RowHeight - 5.0f;
|
||||
|
||||
CRenderInfo Info;
|
||||
Info.m_pSelf = this;
|
||||
Info.m_WantedCompletion = pConsole->m_CompletionUsed ? pConsole->m_CompletionChosen : -1;
|
||||
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, x + Info.m_Offset, y + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||
Info.m_Cursor.m_LineWidth = std::numeric_limits<float>::max();
|
||||
const float InitialX = x;
|
||||
const float InitialY = y;
|
||||
|
||||
// render prompt
|
||||
CTextCursor Cursor;
|
||||
|
@ -706,16 +756,33 @@ void CGameConsole::OnRender()
|
|||
Input()->SetEditingPosition(Marker.m_X, Marker.m_Y + Marker.m_FontSize);
|
||||
|
||||
// render possible commands
|
||||
if(m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed())
|
||||
if((m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed()) && pConsole->m_Input.GetString()[0])
|
||||
{
|
||||
if(pConsole->m_Input.GetString()[0] != 0)
|
||||
{
|
||||
m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info);
|
||||
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)
|
||||
if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
|
||||
{
|
||||
if(pConsole->m_IsCommand)
|
||||
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;
|
||||
}
|
||||
|
||||
if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp);
|
||||
|
@ -726,7 +793,6 @@ void CGameConsole::OnRender()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pConsole->m_BacklogLock.lock();
|
||||
|
||||
|
@ -922,23 +988,28 @@ void CGameConsole::Toggle(int Type)
|
|||
void CGameConsole::Dump(int Type)
|
||||
{
|
||||
CInstance *pConsole = Type == CONSOLETYPE_REMOTE ? &m_RemoteConsole : &m_LocalConsole;
|
||||
char aBuf[IO_MAX_PATH_LENGTH + 64];
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
char aDate[20];
|
||||
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
str_format(aFilename, sizeof(aFilename), "dumps/%s_dump_%s.txt", Type == CONSOLETYPE_REMOTE ? "remote_console" : "local_console", aDate);
|
||||
IOHANDLE io = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||
if(io)
|
||||
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)
|
||||
{
|
||||
pConsole->m_BacklogLock.lock();
|
||||
for(CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.First(); pEntry; pEntry = pConsole->m_Backlog.Next(pEntry))
|
||||
{
|
||||
io_write(io, pEntry->m_aText, str_length(pEntry->m_aText));
|
||||
io_write_newline(io);
|
||||
io_write(File, pEntry->m_aText, str_length(pEntry->m_aText));
|
||||
io_write_newline(File);
|
||||
}
|
||||
pConsole->m_BacklogLock.unlock();
|
||||
io_close(io);
|
||||
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);
|
||||
}
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
|
||||
}
|
||||
|
||||
void CGameConsole::ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData)
|
||||
|
@ -1014,8 +1085,8 @@ void CGameConsole::OnConsoleInit()
|
|||
Console()->Register("toggle_remote_console", "", CFGFLAG_CLIENT, ConToggleRemoteConsole, this, "Toggle remote console");
|
||||
Console()->Register("clear_local_console", "", CFGFLAG_CLIENT, ConClearLocalConsole, this, "Clear local console");
|
||||
Console()->Register("clear_remote_console", "", CFGFLAG_CLIENT, ConClearRemoteConsole, this, "Clear remote console");
|
||||
Console()->Register("dump_local_console", "", CFGFLAG_CLIENT, ConDumpLocalConsole, this, "Dump local console");
|
||||
Console()->Register("dump_remote_console", "", CFGFLAG_CLIENT, ConDumpRemoteConsole, this, "Dump remote console");
|
||||
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");
|
||||
|
||||
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");
|
||||
|
|
|
@ -38,18 +38,18 @@ class CGameConsole : public CComponent
|
|||
char *m_pHistoryEntry;
|
||||
|
||||
CLineInput m_Input;
|
||||
const char *m_pName;
|
||||
int m_Type;
|
||||
int m_CompletionEnumerationCount;
|
||||
int m_BacklogCurPage;
|
||||
|
||||
CGameConsole *m_pGameConsole;
|
||||
|
||||
char m_aCompletionBuffer[128];
|
||||
bool m_CompletionUsed;
|
||||
int m_CompletionChosen;
|
||||
char m_aCompletionBufferArgument[128];
|
||||
int m_CompletionChosenArgument;
|
||||
int m_CompletionFlagmask;
|
||||
float m_CompletionRenderOffset;
|
||||
bool m_ReverseTAB;
|
||||
|
||||
char m_aUser[32];
|
||||
bool m_UserGot;
|
||||
|
@ -66,6 +66,7 @@ class CGameConsole : public CComponent
|
|||
void ClearBacklog();
|
||||
void ClearBacklogYOffsets();
|
||||
void ClearHistory();
|
||||
void Reset();
|
||||
|
||||
void ExecuteLine(const char *pLine);
|
||||
|
||||
|
@ -73,7 +74,8 @@ class CGameConsole : public CComponent
|
|||
void PrintLine(const char *pLine, int Len, ColorRGBA PrintColor);
|
||||
|
||||
const char *GetString() const { return m_Input.GetString(); }
|
||||
static void PossibleCommandsCompleteCallback(const char *pStr, void *pUser);
|
||||
static void PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser);
|
||||
static void PossibleArgumentsCompleteCallback(int Index, const char *pStr, void *pUser);
|
||||
};
|
||||
|
||||
class IConsole *m_pConsole;
|
||||
|
@ -105,7 +107,7 @@ class CGameConsole : public CComponent
|
|||
void Toggle(int Type);
|
||||
void Dump(int Type);
|
||||
|
||||
static void PossibleCommandsRenderCallback(const char *pStr, void *pUser);
|
||||
static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser);
|
||||
static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConClearLocalConsole(IConsole::IResult *pResult, void *pUserData);
|
||||
|
|
|
@ -119,7 +119,7 @@ void CDebugHud::RenderTuning()
|
|||
TextRender()->Text(0x0, x - w, y + Count * 6, 5, aBuf, -1.0f);
|
||||
|
||||
x += 5.0f;
|
||||
TextRender()->Text(0x0, x, y + Count * 6, 5, CTuningParams::ms_apNames[i], -1.0f);
|
||||
TextRender()->Text(0x0, x, y + Count * 6, 5, CTuningParams::Name(i), -1.0f);
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
|
|
@ -163,9 +163,9 @@ void CGameClient::OnConsoleInit()
|
|||
Console()->Register("kill", "", CFGFLAG_CLIENT, ConKill, this, "Kill yourself to restart");
|
||||
|
||||
// register server dummy commands for tab completion
|
||||
Console()->Register("tune", "s[tuning] i[value]", CFGFLAG_SERVER, 0, 0, "Tune variable to value");
|
||||
Console()->Register("tune_reset", "", CFGFLAG_SERVER, 0, 0, "Reset tuning");
|
||||
Console()->Register("tune_dump", "", CFGFLAG_SERVER, 0, 0, "Dump tuning");
|
||||
Console()->Register("tune", "s[tuning] ?i[value]", CFGFLAG_SERVER, 0, 0, "Tune variable to value or show current value");
|
||||
Console()->Register("tune_reset", "?s[tuning]", CFGFLAG_SERVER, 0, 0, "Reset all or one tuning variable to default");
|
||||
Console()->Register("tunes", "", CFGFLAG_SERVER, 0, 0, "List all tuning variables and their values");
|
||||
Console()->Register("change_map", "?r[map]", CFGFLAG_SERVER, 0, 0, "Change map");
|
||||
Console()->Register("restart", "?i[seconds]", CFGFLAG_SERVER, 0, 0, "Restart in x seconds");
|
||||
Console()->Register("broadcast", "r[message]", CFGFLAG_SERVER, 0, 0, "Broadcast message");
|
||||
|
|
|
@ -34,7 +34,7 @@ bool CTuningParams::Get(int Index, float *pValue) const
|
|||
bool CTuningParams::Set(const char *pName, float Value)
|
||||
{
|
||||
for(int i = 0; i < Num(); i++)
|
||||
if(str_comp_nocase(pName, ms_apNames[i]) == 0)
|
||||
if(str_comp_nocase(pName, Name(i)) == 0)
|
||||
return Set(i, Value);
|
||||
return false;
|
||||
}
|
||||
|
@ -42,12 +42,26 @@ bool CTuningParams::Set(const char *pName, float Value)
|
|||
bool CTuningParams::Get(const char *pName, float *pValue) const
|
||||
{
|
||||
for(int i = 0; i < Num(); i++)
|
||||
if(str_comp_nocase(pName, ms_apNames[i]) == 0)
|
||||
if(str_comp_nocase(pName, Name(i)) == 0)
|
||||
return Get(i, pValue);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int CTuningParams::PossibleTunings(const char *pStr, IConsole::FPossibleCallback pfnCallback, void *pUser)
|
||||
{
|
||||
int Index = 0;
|
||||
for(int i = 0; i < Num(); i++)
|
||||
{
|
||||
if(str_find_nocase(Name(i), pStr))
|
||||
{
|
||||
pfnCallback(Index, Name(i), pUser);
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
return Index;
|
||||
}
|
||||
|
||||
float VelocityRamp(float Value, float Start, float Range, float Curvature)
|
||||
{
|
||||
if(Value < Start)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <engine/console.h>
|
||||
#include <engine/shared/protocol.h>
|
||||
#include <game/generated/protocol.h>
|
||||
|
||||
|
@ -40,6 +41,8 @@ public:
|
|||
|
||||
class CTuningParams
|
||||
{
|
||||
static const char *ms_apNames[];
|
||||
|
||||
public:
|
||||
CTuningParams()
|
||||
{
|
||||
|
@ -49,8 +52,6 @@ public:
|
|||
#undef MACRO_TUNING_PARAM
|
||||
}
|
||||
|
||||
static const char *ms_apNames[];
|
||||
|
||||
#define MACRO_TUNING_PARAM(Name, ScriptName, Value, Description) CTuneParam m_##Name;
|
||||
#include "tuning.h"
|
||||
#undef MACRO_TUNING_PARAM
|
||||
|
@ -63,6 +64,8 @@ public:
|
|||
bool Set(const char *pName, float Value);
|
||||
bool Get(int Index, float *pValue) const;
|
||||
bool Get(const char *pName, float *pValue) const;
|
||||
static const char *Name(int Index) { return ms_apNames[Index]; }
|
||||
int PossibleTunings(const char *pStr, IConsole::FPossibleCallback pfnCallback = IConsole::EmptyPossibleCommandCallback, void *pUser = nullptr);
|
||||
};
|
||||
|
||||
inline void StrToInts(int *pInts, int Num, const char *pStr)
|
||||
|
|
|
@ -2550,17 +2550,34 @@ void CGameContext::ConTuneParam(IConsole::IResult *pResult, void *pUserData)
|
|||
{
|
||||
CGameContext *pSelf = (CGameContext *)pUserData;
|
||||
const char *pParamName = pResult->GetString(0);
|
||||
float NewValue = pResult->GetFloat(1);
|
||||
|
||||
if(pSelf->Tuning()->Set(pParamName, NewValue))
|
||||
{
|
||||
char aBuf[256];
|
||||
if(pResult->NumArguments() == 2)
|
||||
{
|
||||
float NewValue = pResult->GetFloat(1);
|
||||
if(pSelf->Tuning()->Set(pParamName, NewValue) && pSelf->Tuning()->Get(pParamName, &NewValue))
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s changed to %.2f", pParamName, NewValue);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
pSelf->SendTuningParams(-1);
|
||||
}
|
||||
else
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "No such tuning parameter");
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "No such tuning parameter: %s", pParamName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float Value;
|
||||
if(pSelf->Tuning()->Get(pParamName, &Value))
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s %.2f", pParamName, Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "No such tuning parameter: %s", pParamName);
|
||||
}
|
||||
}
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
}
|
||||
|
||||
void CGameContext::ConToggleTuneParam(IConsole::IResult *pResult, void *pUserData)
|
||||
|
@ -2569,17 +2586,19 @@ void CGameContext::ConToggleTuneParam(IConsole::IResult *pResult, void *pUserDat
|
|||
const char *pParamName = pResult->GetString(0);
|
||||
float OldValue;
|
||||
|
||||
char aBuf[256];
|
||||
if(!pSelf->Tuning()->Get(pParamName, &OldValue))
|
||||
{
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "No such tuning parameter");
|
||||
str_format(aBuf, sizeof(aBuf), "No such tuning parameter: %s", pParamName);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
float NewValue = fabs(OldValue - pResult->GetFloat(1)) < 0.0001f ? pResult->GetFloat(2) : pResult->GetFloat(1);
|
||||
|
||||
pSelf->Tuning()->Set(pParamName, NewValue);
|
||||
pSelf->Tuning()->Get(pParamName, &NewValue);
|
||||
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "%s changed to %.2f", pParamName, NewValue);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
pSelf->SendTuningParams(-1);
|
||||
|
@ -2588,11 +2607,31 @@ void CGameContext::ConToggleTuneParam(IConsole::IResult *pResult, void *pUserDat
|
|||
void CGameContext::ConTuneReset(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CGameContext *pSelf = (CGameContext *)pUserData;
|
||||
if(pResult->NumArguments())
|
||||
{
|
||||
const char *pParamName = pResult->GetString(0);
|
||||
float DefaultValue = 0.0f;
|
||||
char aBuf[256];
|
||||
CTuningParams TuningParams;
|
||||
if(TuningParams.Get(pParamName, &DefaultValue) && pSelf->Tuning()->Set(pParamName, DefaultValue) && pSelf->Tuning()->Get(pParamName, &DefaultValue))
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s reset to %.2f", pParamName, DefaultValue);
|
||||
pSelf->SendTuningParams(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "No such tuning parameter: %s", pParamName);
|
||||
}
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
pSelf->ResetTuning();
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "Tuning reset");
|
||||
}
|
||||
}
|
||||
|
||||
void CGameContext::ConTuneDump(IConsole::IResult *pResult, void *pUserData)
|
||||
void CGameContext::ConTunes(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CGameContext *pSelf = (CGameContext *)pUserData;
|
||||
char aBuf[256];
|
||||
|
@ -2600,7 +2639,7 @@ void CGameContext::ConTuneDump(IConsole::IResult *pResult, void *pUserData)
|
|||
{
|
||||
float Value;
|
||||
pSelf->Tuning()->Get(i, &Value);
|
||||
str_format(aBuf, sizeof(aBuf), "%s %.2f", pSelf->Tuning()->ms_apNames[i], Value);
|
||||
str_format(aBuf, sizeof(aBuf), "%s %.2f", CTuningParams::Name(i), Value);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
}
|
||||
}
|
||||
|
@ -2613,16 +2652,18 @@ void CGameContext::ConTuneZone(IConsole::IResult *pResult, void *pUserData)
|
|||
float NewValue = pResult->GetFloat(2);
|
||||
|
||||
if(List >= 0 && List < NUM_TUNEZONES)
|
||||
{
|
||||
if(pSelf->TuningList()[List].Set(pParamName, NewValue))
|
||||
{
|
||||
char aBuf[256];
|
||||
if(pSelf->TuningList()[List].Set(pParamName, NewValue) && pSelf->TuningList()[List].Get(pParamName, &NewValue))
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s in zone %d changed to %.2f", pParamName, List, NewValue);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
pSelf->SendTuningParams(-1, List);
|
||||
}
|
||||
else
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", "No such tuning parameter");
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "No such tuning parameter: %s", pParamName);
|
||||
}
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2637,7 +2678,7 @@ void CGameContext::ConTuneDumpZone(IConsole::IResult *pResult, void *pUserData)
|
|||
{
|
||||
float Value;
|
||||
pSelf->TuningList()[List].Get(i, &Value);
|
||||
str_format(aBuf, sizeof(aBuf), "zone %d: %s %.2f", List, pSelf->TuningList()[List].ms_apNames[i], Value);
|
||||
str_format(aBuf, sizeof(aBuf), "zone %d: %s %.2f", List, CTuningParams::Name(i), Value);
|
||||
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tuning", aBuf);
|
||||
}
|
||||
}
|
||||
|
@ -3140,10 +3181,10 @@ void CGameContext::OnConsoleInit()
|
|||
m_pEngine = Kernel()->RequestInterface<IEngine>();
|
||||
m_pStorage = Kernel()->RequestInterface<IStorage>();
|
||||
|
||||
Console()->Register("tune", "s[tuning] i[value]", CFGFLAG_SERVER | CFGFLAG_GAME, ConTuneParam, this, "Tune variable to value");
|
||||
Console()->Register("tune", "s[tuning] ?i[value]", CFGFLAG_SERVER | CFGFLAG_GAME, ConTuneParam, this, "Tune variable to value or show current value");
|
||||
Console()->Register("toggle_tune", "s[tuning] i[value 1] i[value 2]", CFGFLAG_SERVER | CFGFLAG_GAME, ConToggleTuneParam, this, "Toggle tune variable");
|
||||
Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "Reset tuning");
|
||||
Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "Dump tuning");
|
||||
Console()->Register("tune_reset", "?s[tuning]", CFGFLAG_SERVER, ConTuneReset, this, "Reset all or one tuning variable to default");
|
||||
Console()->Register("tunes", "", CFGFLAG_SERVER, ConTunes, this, "List all tuning variables and their values");
|
||||
Console()->Register("tune_zone", "i[zone] s[tuning] i[value]", CFGFLAG_SERVER | CFGFLAG_GAME, ConTuneZone, this, "Tune in zone a variable to value");
|
||||
Console()->Register("tune_zone_dump", "i[zone]", CFGFLAG_SERVER, ConTuneDumpZone, this, "Dump zone tuning in zone x");
|
||||
Console()->Register("tune_zone_reset", "?i[zone]", CFGFLAG_SERVER, ConTuneResetZone, this, "reset zone tuning in zone x or in all zones");
|
||||
|
|
|
@ -90,7 +90,7 @@ class CGameContext : public IGameServer
|
|||
static void ConTuneParam(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConToggleTuneParam(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTuneReset(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTuneDump(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTunes(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTuneZone(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTuneDumpZone(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTuneResetZone(IConsole::IResult *pResult, void *pUserData);
|
||||
|
|
Loading…
Reference in a new issue