From be45604354632e345edb5213cee4381ef8c6c67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 24 Oct 2022 19:48:44 +0200 Subject: [PATCH 1/6] Fix demo file not being closed after showing error message When entering the name of an existing demo file into the Slice demo dialog and pressing the Ok button twice, the file handle that's used for checking for the demo file's existence is not closed, hence the cut demo file cannot be deleted until the client is closed. --- src/game/client/components/menus_demo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index c629e20f4..63afa1231 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -179,6 +179,8 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) } else { + if(DemoFile) + io_close(DemoFile); m_DemoPlayerState = DEMOPLAYER_NONE; Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); DemolistPopulate(); From 3c1cd89ae698b2a3c6f3f02c74e08f21e5ed7dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 24 Oct 2022 19:53:42 +0200 Subject: [PATCH 2/6] Append file extension before checking for identical cut demo filename The file extension needs to be appended to the cut demo name before checking whether the name matches the currently playing file, otherwise the "Please use a different name" error message is not shown and instead the "File already exists" question is shown. --- src/game/client/components/menus_demo.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 63afa1231..5a6dd251c 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -160,12 +160,13 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) static CButtonContainer s_ButtonOk; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER)) { + if(!str_endswith(m_aCurrentDemoFile, ".demo")) + str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); + if(str_comp(m_vDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0) str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name")); else { - if(!str_endswith(m_aCurrentDemoFile, ".demo")) - str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); char aPath[IO_MAX_PATH_LENGTH]; str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); From 997af452d043abcf91a76eefe4660bec9492da91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 24 Oct 2022 20:14:04 +0200 Subject: [PATCH 3/6] Fix crash when cutting a demo opened from command line When playing a demo without opening the demo menu first, i.e. from command line argument or with `play` command from the main menu, clicking the demo slice button crashes the game, as the code tries to use the filename of the currently selected demo while there is no demo selected, i.e. `m_DemolistSelectedIndex == -1`. Also, when using the play command after opening the demo menu, the initial filename selected for cutting was incorrectly set to the currently selected demo. This is fixed by getting the name of the current demo file from the demo player instead, when cutting a demo. Though the cut demo will be saved to the last demo folder selected (or the demos directory) instead of being saved to the same directory as the original demo. --- src/game/client/components/menus_demo.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 5a6dd251c..27dbeda9e 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -160,14 +160,17 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) static CButtonContainer s_ButtonOk; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER)) { + char aDemoName[IO_MAX_PATH_LENGTH]; + DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); + str_append(aDemoName, ".demo", sizeof(aDemoName)); + if(!str_endswith(m_aCurrentDemoFile, ".demo")) str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); - if(str_comp(m_vDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0) + if(str_comp(aDemoName, m_aCurrentDemoFile) == 0) str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name")); else { - char aPath[IO_MAX_PATH_LENGTH]; str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); @@ -512,7 +515,8 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) static CButtonContainer s_SliceSaveButton; if(DoButton_FontIcon(&s_SliceSaveButton, "\xEF\x80\xBD", 0, &Button, IGraphics::CORNER_ALL)) { - str_copy(m_aCurrentDemoFile, m_vDemos[m_DemolistSelectedIndex].m_aFilename); + DemoPlayer()->GetDemoName(m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile)); + str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); m_aDemoPlayerPopupHint[0] = '\0'; m_DemoPlayerState = DEMOPLAYER_SLICE_SAVE; } From 326a0a576df9111a8942ad065fab1a4c5df88243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 24 Oct 2022 20:15:49 +0200 Subject: [PATCH 4/6] Fix slicing a demo opened with absolute path not working Slicing a demo opened from command line with an absolute path did not work, as the game only tried to load the source demo from storage instead of using the given absolute path. --- src/engine/shared/demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 959e7d062..64fb57813 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -1143,7 +1143,7 @@ void CDemoEditor::Slice(const char *pDemo, const char *pDst, int StartTick, int m_SliceTo = EndTick; m_Stop = false; - if(m_pDemoPlayer->Load(m_pStorage, m_pConsole, pDemo, IStorage::TYPE_ALL) == -1) + if(m_pDemoPlayer->Load(m_pStorage, m_pConsole, pDemo, fs_is_relative_path(pDemo) ? IStorage::TYPE_ALL : IStorage::TYPE_ABSOLUTE) == -1) return; const CMapInfo *pMapInfo = m_pDemoPlayer->GetMapInfo(); From b4860288384844a7c9c7b2633367947ffdbc7384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 16 Oct 2022 21:28:31 +0200 Subject: [PATCH 5/6] Remove dead code The `PopupMessage` was never shown, as the next line activates `POPUP_REPLACE_VIDEO` which immediates overrides the message popup. --- src/game/client/components/menus.cpp | 2 -- src/game/client/components/menus.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 80ace42ce..801c56a43 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -2067,14 +2067,12 @@ int CMenus::Render() str_copy(m_aCurrentDemoFile, aBufNew); if(Storage()->FindFile(m_aCurrentDemoFile, "videos", IStorage::TYPE_ALL, aWholePath, sizeof(aWholePath))) { - PopupMessage(Localize("Error"), Localize("Destination file already exist"), Localize("Ok")); m_Popup = POPUP_REPLACE_VIDEO; } else { const char *pError = Client()->DemoPlayer_Render(aBufOld, m_vDemos[m_DemolistSelectedIndex].m_StorageType, m_aCurrentDemoFile, m_Speed); m_Speed = 4; - //Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "demo_render_path", aWholePath); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); } diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index d73e5f41f..76bea3986 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -444,7 +444,6 @@ protected: std::chrono::nanoseconds m_DemoPopulateStartTime{0}; void DemolistOnUpdate(bool Reset); - //void DemolistPopulate(); static int DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser); // friends From 6ef3adaa23dd116ee8686f9796bf5cc3b67763ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 24 Oct 2022 20:17:11 +0200 Subject: [PATCH 6/6] Fix long demo names being truncated in popups and UI Use `IO_MAX_PATH_LENGTH` for all demo filenames and paths, so long demo names and demo names containing many unicode characters are not so easily truncated in the cut, rename and render dialogs. Use combination of `str_endswith` and `str_append` to append file extensions, instead of using `str_comp_nocase` and `str_format`. Thereby only support creating demos and video files with lower case file extension, as only demo files with lower case file extension are shown in the client anyway. --- src/game/client/components/menus.cpp | 25 ++++++++--------------- src/game/client/components/menus.h | 6 +++--- src/game/client/components/menus_demo.cpp | 15 +++++++------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 801c56a43..e04da1ed8 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1995,14 +1995,12 @@ int CMenus::Render() // rename demo if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { - char aBufOld[512]; + char aBufOld[IO_MAX_PATH_LENGTH]; str_format(aBufOld, sizeof(aBufOld), "%s/%s", m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename); - int Length = str_length(m_aCurrentDemoFile); - char aBufNew[512]; - if(Length <= 4 || m_aCurrentDemoFile[Length - 5] != '.' || str_comp_nocase(m_aCurrentDemoFile + Length - 4, "demo")) - str_format(aBufNew, sizeof(aBufNew), "%s/%s.demo", m_aCurrentDemoFolder, m_aCurrentDemoFile); - else - str_format(aBufNew, sizeof(aBufNew), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); + char aBufNew[IO_MAX_PATH_LENGTH]; + str_format(aBufNew, sizeof(aBufNew), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); + if(!str_endswith(aBufNew, ".demo")) + str_append(aBufNew, ".demo", sizeof(aBufNew)); if(Storage()->RenameFile(aBufOld, aBufNew, m_vDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); @@ -2054,17 +2052,12 @@ int CMenus::Render() // name video if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { - char aBufOld[512]; + char aBufOld[IO_MAX_PATH_LENGTH]; str_format(aBufOld, sizeof(aBufOld), "%s/%s", m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename); - int Length = str_length(m_aCurrentDemoFile); - char aBufNew[512]; - if(Length <= 3 || m_aCurrentDemoFile[Length - 4] != '.' || str_comp_nocase(m_aCurrentDemoFile + Length - 3, "mp4")) - str_format(aBufNew, sizeof(aBufNew), "%s.mp4", m_aCurrentDemoFile); - else - str_format(aBufNew, sizeof(aBufNew), "%s", m_aCurrentDemoFile); - char aWholePath[1024]; + if(!str_endswith(m_aCurrentDemoFile, ".mp4")) + str_append(m_aCurrentDemoFile, ".mp4", sizeof(m_aCurrentDemoFile)); + char aWholePath[IO_MAX_PATH_LENGTH]; // store new video filename to origin buffer - str_copy(m_aCurrentDemoFile, aBufNew); if(Storage()->FindFile(m_aCurrentDemoFile, "videos", IStorage::TYPE_ALL, aWholePath, sizeof(aWholePath))) { m_Popup = POPUP_REPLACE_VIDEO; diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 76bea3986..1e5764909 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -374,7 +374,7 @@ protected: struct CDemoItem { char m_aFilename[IO_MAX_PATH_LENGTH]; - char m_aName[128]; + char m_aName[IO_MAX_PATH_LENGTH]; bool m_IsDir; int m_StorageType; time_t m_Date; @@ -434,8 +434,8 @@ protected: } }; - char m_aCurrentDemoFolder[256]; - char m_aCurrentDemoFile[64]; + char m_aCurrentDemoFolder[IO_MAX_PATH_LENGTH]; + char m_aCurrentDemoFile[IO_MAX_PATH_LENGTH]; int m_DemolistSelectedIndex; bool m_DemolistSelectedIsDir; int m_DemolistStorageType; diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 27dbeda9e..cc690e113 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -542,9 +542,9 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_KeyboardShortcutsButton, &Button, Localize("Toggle keyboard shortcuts")); // demo name - char aDemoName[64] = {0}; + char aDemoName[IO_MAX_PATH_LENGTH]; DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); - char aBuf[128]; + char aBuf[IO_MAX_PATH_LENGTH + 128]; str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y + (NameBar.h - (Button.h * 0.5f)) / 2.f, Button.h * 0.5f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END); @@ -824,7 +824,7 @@ int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int Stora } else { - str_truncate(Item.m_aName, sizeof(Item.m_aName), pInfo->m_pName, str_length(pInfo->m_pName) - 5); + str_truncate(Item.m_aName, sizeof(Item.m_aName), pInfo->m_pName, str_length(pInfo->m_pName) - str_length(".demo")); Item.m_InfosLoaded = false; Item.m_Date = pInfo->m_TimeModified; } @@ -887,7 +887,7 @@ bool CMenus::FetchHeader(CDemoItem &Item) { if(!Item.m_InfosLoaded) { - char aBuffer[512]; + char aBuffer[IO_MAX_PATH_LENGTH]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item.m_aFilename); Item.m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item.m_StorageType, &Item.m_Info, &Item.m_TimelineMarkers, &Item.m_MapInfo); Item.m_InfosLoaded = true; @@ -1302,9 +1302,8 @@ void CMenus::RenderDemoList(CUIRect MainView) fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { - char aTemp[256]; - str_copy(aTemp, m_aCurrentDemoFolder); - str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_vDemos[m_DemolistSelectedIndex].m_aFilename); + str_append(m_aCurrentDemoFolder, "/", sizeof(m_aCurrentDemoFolder)); + str_append(m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFolder)); m_DemolistStorageType = m_vDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); @@ -1312,7 +1311,7 @@ void CMenus::RenderDemoList(CUIRect MainView) } else // file { - char aBuf[512]; + char aBuf[IO_MAX_PATH_LENGTH]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_vDemos[m_DemolistSelectedIndex].m_StorageType); if(pError)