5793: Allow demo/map command line arguments to be relative paths, allow using `play` in command line r=def- a=Robyt3

Closes #5645.

## Checklist

- [X] Tested the change ingame
- [ ] 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
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] 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:
bors[bot] 2022-08-30 21:10:29 +00:00 committed by GitHub
commit 487d85bdf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 18 deletions

View file

@ -3198,7 +3198,9 @@ void CClient::Run()
// handle pending demo play // handle pending demo play
if(m_aCmdPlayDemo[0]) if(m_aCmdPlayDemo[0])
{ {
const char *pError = DemoPlayer_Play(m_aCmdPlayDemo, IStorage::TYPE_ABSOLUTE); const char *pError = DemoPlayer_Play(m_aCmdPlayDemo, IStorage::TYPE_ALL);
if(pError && !fs_is_relative_path(m_aCmdPlayDemo))
pError = DemoPlayer_Play(m_aCmdPlayDemo, IStorage::TYPE_ABSOLUTE);
if(pError) if(pError)
dbg_msg("demo_player", "playing passed demo file '%s' failed: %s", m_aCmdPlayDemo, pError); dbg_msg("demo_player", "playing passed demo file '%s' failed: %s", m_aCmdPlayDemo, pError);
m_aCmdPlayDemo[0] = 0; m_aCmdPlayDemo[0] = 0;
@ -3207,7 +3209,9 @@ void CClient::Run()
// handle pending map edits // handle pending map edits
if(m_aCmdEditMap[0]) if(m_aCmdEditMap[0])
{ {
int Result = m_pEditor->Load(m_aCmdEditMap, IStorage::TYPE_ABSOLUTE); int Result = m_pEditor->Load(m_aCmdEditMap, IStorage::TYPE_ALL);
if(!Result && !fs_is_relative_path(m_aCmdEditMap))
m_pEditor->Load(m_aCmdEditMap, IStorage::TYPE_ABSOLUTE);
if(Result) if(Result)
g_Config.m_ClEditor = true; g_Config.m_ClEditor = true;
else else
@ -3502,7 +3506,7 @@ bool CClient::CtrlShiftKey(int Key, bool &Last)
void CClient::Con_Connect(IConsole::IResult *pResult, void *pUserData) void CClient::Con_Connect(IConsole::IResult *pResult, void *pUserData)
{ {
CClient *pSelf = (CClient *)pUserData; CClient *pSelf = (CClient *)pUserData;
str_copy(pSelf->m_aCmdConnect, pResult->GetString(0)); pSelf->HandleConnectLink(pResult->GetString(0));
} }
void CClient::Con_Disconnect(IConsole::IResult *pResult, void *pUserData) void CClient::Con_Disconnect(IConsole::IResult *pResult, void *pUserData)
@ -3975,9 +3979,7 @@ const char *CClient::DemoPlayer_Render(const char *pFilename, int StorageType, c
void CClient::Con_Play(IConsole::IResult *pResult, void *pUserData) void CClient::Con_Play(IConsole::IResult *pResult, void *pUserData)
{ {
CClient *pSelf = (CClient *)pUserData; CClient *pSelf = (CClient *)pUserData;
const char *pError = pSelf->DemoPlayer_Play(pResult->GetString(0), IStorage::TYPE_ALL); pSelf->HandleDemoPath(pResult->GetString(0));
if(pError)
pSelf->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_player", pError);
} }
void CClient::Con_DemoPlay(IConsole::IResult *pResult, void *pUserData) void CClient::Con_DemoPlay(IConsole::IResult *pResult, void *pUserData)
@ -4531,7 +4533,10 @@ void CClient::HandleConnectAddress(const NETADDR *pAddr)
void CClient::HandleConnectLink(const char *pLink) void CClient::HandleConnectLink(const char *pLink)
{ {
if(str_startswith(pLink, CONNECTLINK))
str_copy(m_aCmdConnect, pLink + sizeof(CONNECTLINK) - 1); str_copy(m_aCmdConnect, pLink + sizeof(CONNECTLINK) - 1);
else
str_copy(m_aCmdConnect, pLink);
} }
void CClient::HandleDemoPath(const char *pPath) void CClient::HandleDemoPath(const char *pPath)
@ -4544,6 +4549,27 @@ void CClient::HandleMapPath(const char *pPath)
str_copy(m_aCmdEditMap, pPath); str_copy(m_aCmdEditMap, pPath);
} }
static bool UnknownArgumentCallback(const char *pCommand, void *pUser)
{
CClient *pClient = static_cast<CClient *>(pUser);
if(str_startswith(pCommand, CONNECTLINK))
{
pClient->HandleConnectLink(pCommand);
return true;
}
else if(str_endswith(pCommand, ".demo"))
{
pClient->HandleDemoPath(pCommand);
return true;
}
else if(str_endswith(pCommand, ".map"))
{
pClient->HandleMapPath(pCommand);
return true;
}
return false;
}
/* /*
Server Time Server Time
Client Mirror Time Client Mirror Time
@ -4729,14 +4755,9 @@ int main(int argc, const char **argv)
g_Config.m_ClConfigVersion = 1; g_Config.m_ClConfigVersion = 1;
// parse the command line arguments // parse the command line arguments
if(argc == 2 && str_startswith(argv[1], CONNECTLINK)) pConsole->SetUnknownCommandCallback(UnknownArgumentCallback, pClient);
pClient->HandleConnectLink(argv[1]);
else if(argc == 2 && str_endswith(argv[1], ".demo"))
pClient->HandleDemoPath(argv[1]);
else if(argc == 2 && str_endswith(argv[1], ".map"))
pClient->HandleMapPath(argv[1]);
else if(argc > 1)
pConsole->ParseArguments(argc - 1, (const char **)&argv[1]); pConsole->ParseArguments(argc - 1, (const char **)&argv[1]);
pConsole->SetUnknownCommandCallback(IConsole::EmptyUnknownCommandCallback, nullptr);
if(pSteam->GetConnectAddress()) if(pSteam->GetConnectAddress())
{ {

View file

@ -85,8 +85,10 @@ public:
typedef void (*FPossibleCallback)(int Index, const char *pCmd, void *pUser); typedef void (*FPossibleCallback)(int Index, const char *pCmd, void *pUser);
typedef void (*FCommandCallback)(IResult *pResult, void *pUserData); typedef void (*FCommandCallback)(IResult *pResult, void *pUserData);
typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData); typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData);
typedef bool (*FUnknownCommandCallback)(const char *pCommand, void *pUser); // returns true if the callback has handled the argument
static void EmptyPossibleCommandCallback(int Index, const char *pCmd, void *pUser) {} static void EmptyPossibleCommandCallback(int Index, const char *pCmd, void *pUser) {}
static bool EmptyUnknownCommandCallback(const char *pCommand, void *pUser) { return false; }
virtual void Init() = 0; virtual void Init() = 0;
virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0; virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0;
@ -110,6 +112,7 @@ public:
virtual char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr) = 0; virtual char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr) = 0;
virtual void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor) = 0;
virtual void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) = 0; virtual void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) = 0;
virtual void SetUnknownCommandCallback(FUnknownCommandCallback pfnCallback, void *pUser) = 0;
virtual void InitChecksum(CChecksumData *pData) const = 0; virtual void InitChecksum(CChecksumData *pData) const = 0;
virtual void SetAccessLevel(int AccessLevel) = 0; virtual void SetAccessLevel(int AccessLevel) = 0;

View file

@ -342,6 +342,12 @@ void CConsole::SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCa
m_pTeeHistorianCommandUserdata = pUser; m_pTeeHistorianCommandUserdata = pUser;
} }
void CConsole::SetUnknownCommandCallback(FUnknownCommandCallback pfnCallback, void *pUser)
{
m_pfnUnknownCommandCallback = pfnCallback;
m_pUnknownCommandUserdata = pUser;
}
void CConsole::InitChecksum(CChecksumData *pData) const void CConsole::InitChecksum(CChecksumData *pData) const
{ {
pData->m_NumCommands = 0; pData->m_NumCommands = 0;
@ -541,11 +547,14 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
} }
} }
else if(Stroke) else if(Stroke)
{
if(!m_pfnUnknownCommandCallback(Result.m_pCommand, m_pUnknownCommandUserdata))
{ {
char aBuf[256]; char aBuf[256];
str_format(aBuf, sizeof(aBuf), "No such command: %s.", Result.m_pCommand); str_format(aBuf, sizeof(aBuf), "No such command: %s.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf); Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
} }
}
pStr = pNextPart; pStr = pNextPart;
} }

View file

@ -68,6 +68,9 @@ class CConsole : public IConsole
FTeeHistorianCommandCallback m_pfnTeeHistorianCommandCallback; FTeeHistorianCommandCallback m_pfnTeeHistorianCommandCallback;
void *m_pTeeHistorianCommandUserdata; void *m_pTeeHistorianCommandUserdata;
FUnknownCommandCallback m_pfnUnknownCommandCallback = EmptyUnknownCommandCallback;
void *m_pUnknownCommandUserdata = nullptr;
enum enum
{ {
CONSOLE_MAX_STR_LENGTH = 8192, CONSOLE_MAX_STR_LENGTH = 8192,
@ -214,6 +217,7 @@ public:
char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr) override; char *Format(char *pBuf, int Size, const char *pFrom, const char *pStr) override;
void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor) override; void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = gs_ConsoleDefaultColor) override;
void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) override; void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) override;
void SetUnknownCommandCallback(FUnknownCommandCallback pfnCallback, void *pUser) override;
void InitChecksum(CChecksumData *pData) const override; void InitChecksum(CChecksumData *pData) const override;
void SetAccessLevel(int AccessLevel) override { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_USER)); } void SetAccessLevel(int AccessLevel) override { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_USER)); }