Skip to content

Commit

Permalink
Merge ddnet#6752
Browse files Browse the repository at this point in the history
6752: Ensure `ListDirectory/Info` entries are unique, support selecting storage location in demo browser and editor file browser r=def- a=Robyt3

Description in commits below. Screenshots/video:

- Storage location selection for demos:
![screenshot_2023-06-18_17-25-23](https://github.com/ddnet/ddnet/assets/23437060/bcc94977-50ba-494b-894d-7bd8fea7f91e)

- Storage location selection for maps:
![screenshot_2023-06-18_17-25-33](https://github.com/ddnet/ddnet/assets/23437060/2b8b7822-b4b9-409f-86eb-e44f5c072541)

- Link to "themes" folder:
![screenshot_2023-06-18_17-26-02](https://github.com/ddnet/ddnet/assets/23437060/eba661a6-0bee-4977-ab95-35e400b5b291)

- Video showing navigation between storages (`temp` is the save directory and `temp2`, `temp3` and `data` are other storages)

https://github.com/ddnet/ddnet/assets/23437060/5736d212-3848-44c2-aa81-7f2da9b98008

Closes ddnet#5496.

## 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
- [ ] 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 <[email protected]>
  • Loading branch information
bors[bot] and Robyt3 authored Jul 3, 2023
2 parents 0007671 + f19d102 commit 06fe736
Show file tree
Hide file tree
Showing 8 changed files with 362 additions and 139 deletions.
52 changes: 49 additions & 3 deletions src/engine/shared/storage.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* (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. */
#include "linereader.h"
#include <base/math.h>
#include <base/system.h>

#include <engine/client/updater.h>
#include <engine/shared/linereader.h>
#include <engine/storage.h>

#include <unordered_set>

#ifdef CONF_PLATFORM_HAIKU
#include <cstdlib>
#endif
Expand Down Expand Up @@ -309,14 +312,38 @@ class CStorage : public IStorage
m_aBinarydir[0] = '\0';
}

int NumPaths() const override
{
return m_NumPaths;
}

struct SListDirectoryInfoUniqueCallbackData
{
FS_LISTDIR_CALLBACK_FILEINFO m_pfnDelegate;
void *m_pDelegateUser;
std::unordered_set<std::string> m_Seen;
};

static int ListDirectoryInfoUniqueCallback(const CFsFileInfo *pInfo, int IsDir, int Type, void *pUser)
{
SListDirectoryInfoUniqueCallbackData *pData = static_cast<SListDirectoryInfoUniqueCallbackData *>(pUser);
auto [_, InsertionTookPlace] = pData->m_Seen.emplace(pInfo->m_pName);
if(InsertionTookPlace)
return pData->m_pfnDelegate(pInfo, IsDir, Type, pData->m_pDelegateUser);
return 0;
}

void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_CALLBACK_FILEINFO pfnCallback, void *pUser) override
{
char aBuffer[IO_MAX_PATH_LENGTH];
if(Type == TYPE_ALL)
{
SListDirectoryInfoUniqueCallbackData Data;
Data.m_pfnDelegate = pfnCallback;
Data.m_pDelegateUser = pUser;
// list all available directories
for(int i = TYPE_SAVE; i < m_NumPaths; ++i)
fs_listdir_fileinfo(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
fs_listdir_fileinfo(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), ListDirectoryInfoUniqueCallback, i, &Data);
}
else if(Type >= TYPE_SAVE && Type < m_NumPaths)
{
Expand All @@ -329,14 +356,33 @@ class CStorage : public IStorage
}
}

struct SListDirectoryUniqueCallbackData
{
FS_LISTDIR_CALLBACK m_pfnDelegate;
void *m_pDelegateUser;
std::unordered_set<std::string> m_Seen;
};

static int ListDirectoryUniqueCallback(const char *pName, int IsDir, int Type, void *pUser)
{
SListDirectoryUniqueCallbackData *pData = static_cast<SListDirectoryUniqueCallbackData *>(pUser);
auto [_, InsertionTookPlace] = pData->m_Seen.emplace(pName);
if(InsertionTookPlace)
return pData->m_pfnDelegate(pName, IsDir, Type, pData->m_pDelegateUser);
return 0;
}

void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) override
{
char aBuffer[IO_MAX_PATH_LENGTH];
if(Type == TYPE_ALL)
{
SListDirectoryUniqueCallbackData Data;
Data.m_pfnDelegate = pfnCallback;
Data.m_pDelegateUser = pUser;
// list all available directories
for(int i = TYPE_SAVE; i < m_NumPaths; ++i)
fs_listdir(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
fs_listdir(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), ListDirectoryUniqueCallback, i, &Data);
}
else if(Type >= TYPE_SAVE && Type < m_NumPaths)
{
Expand Down
2 changes: 2 additions & 0 deletions src/engine/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class IStorage : public IInterface
STORAGETYPE_CLIENT,
};

virtual int NumPaths() const = 0;

virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0;
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_CALLBACK_FILEINFO pfnCallback, void *pUser) = 0;
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = nullptr, int BufferSize = 0) = 0;
Expand Down
7 changes: 4 additions & 3 deletions src/game/client/components/menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ CMenus::CMenus()
m_ShowStart = true;

str_copy(m_aCurrentDemoFolder, "demos");
m_DemolistStorageType = IStorage::TYPE_ALL;

m_DemoPlayerState = DEMOPLAYER_NONE;
m_Dummy = false;
Expand Down Expand Up @@ -1530,9 +1531,9 @@ int CMenus::Render()
}
else if(Storage()->RenameFile(aBufOld, aBufNew, m_vDemos[m_DemolistSelectedIndex].m_StorageType))
{
str_copy(g_Config.m_UiDemoSelected, m_DemoRenameInput.GetString());
if(str_endswith(g_Config.m_UiDemoSelected, ".demo"))
g_Config.m_UiDemoSelected[str_length(g_Config.m_UiDemoSelected) - str_length(".demo")] = '\0';
str_copy(m_aCurrentDemoSelectionName, m_DemoRenameInput.GetString());
if(str_endswith(m_aCurrentDemoSelectionName, ".demo"))
m_aCurrentDemoSelectionName[str_length(m_aCurrentDemoSelectionName) - str_length(".demo")] = '\0';
DemolistPopulate();
DemolistOnUpdate(false);
}
Expand Down
3 changes: 3 additions & 0 deletions src/game/client/components/menus.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ class CMenus : public CComponent
char m_aFilename[IO_MAX_PATH_LENGTH];
char m_aName[IO_MAX_PATH_LENGTH];
bool m_IsDir;
bool m_IsLink;
int m_StorageType;
time_t m_Date;

Expand Down Expand Up @@ -318,13 +319,15 @@ class CMenus : public CComponent
};

char m_aCurrentDemoFolder[IO_MAX_PATH_LENGTH];
char m_aCurrentDemoSelectionName[IO_MAX_PATH_LENGTH];
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoRenameInput;
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoSliceInput;
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoRenderInput;
int m_DemolistSelectedIndex;
bool m_DemolistSelectedIsDir;
bool m_DemolistSelectedReveal = false;
int m_DemolistStorageType;
bool m_DemolistMultipleStorages = false;
int m_Speed = 4;

std::chrono::nanoseconds m_DemoPopulateStartTime{0};
Expand Down
Loading

0 comments on commit 06fe736

Please sign in to comment.