From a845bbf55d021702f1d404cc5725ea103a9fc563 Mon Sep 17 00:00:00 2001 From: Jonas Volman Date: Sat, 10 Oct 2026 01:37:01 -0700 Subject: [PATCH] List the Custom Edition map folders through a handle of their own custom_edition_maps_look_for listed custom_maps and the install's maps folder with find_files_start and find_files_next, which keep their place in one global (find_files_globals). As the game starts, the menus' thread for the file system's checks (filesystem_initialization_thread_proc in ui_widget.c) makes the default gametypes' folders with directory_create_or_delete_contents, which deletes a folder's files with the same two functions. A map list looked for meanwhile takes that listing's place, and the thread then deletes the files of the folder being listed: the player's Custom Edition maps. The menus take no input until that thread is done, so it takes a start that asks for the maps at once. Seen with debug.menu_open set to the Select Map screen (main_menu/multiplayer_type_select/mp_map_select/mp_map_select_screen) on a Windows build of c9e4f13f, with six files in custom_maps: one was left. Each folder is now listed with FindFirstFileA and FindNextFileA on a handle of the function's own. The same start, twice, left the six files and listed the three maps among them. Not run on Linux or Android. Co-Authored-By: Claude Opus 5.5 --- port/linux/game/custom_edition_maps.c | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/port/linux/game/custom_edition_maps.c b/port/linux/game/custom_edition_maps.c index 803ca35f..e40f0013 100644 --- a/port/linux/game/custom_edition_maps.c +++ b/port/linux/game/custom_edition_maps.c @@ -44,6 +44,8 @@ Each map can have, beside it in its folder: #include #include +#include +#include /* ---------- constants */ @@ -388,10 +390,6 @@ static void custom_edition_maps_look_for( void) { struct custom_edition_maps_globals *globals = &custom_edition_maps_globals; - struct file_reference directory; - struct file_reference file; - char name[MAXIMUM_FILENAME_LENGTH + 1]; - char extension[MAXIMUM_FILENAME_LENGTH + 1]; char const *folders[] = { CUSTOM_EDITION_MAP_DIRECTORY, CUSTOM_EDITION_INSTALL_MAP_DIRECTORY }; short folder_index; @@ -405,17 +403,41 @@ static void custom_edition_maps_look_for( /* the game's custom_maps first, so its copy wins */ for (folder_index = 0; folder_index < NUMBEROF(folders); folder_index++) { + char pattern[MAXIMUM_FILENAME_LENGTH + 1]; + WIN32_FIND_DATAA data; + HANDLE find; + /* (the install's only when there is one) */ if (folder_index && !custom_edition_install_present()) continue; - file_reference_create_from_path(&directory, folders[folder_index], TRUE); - find_files_start(0, &directory); - while (find_files_next(&file, NULL)) + /* A folder is listed through a handle of its own, never with + find_files_start and find_files_next: those keep their place in one + global, and as the game starts a thread of the menus' deletes the + files of folders with them (perform_filesystem_initialization in + ui_widget.c, directory_create_or_delete_contents). A listing here at + the same time takes that one's place, and the thread then deletes + the files of this folder: the maps. */ + csprintf(pattern, "%s*.*", folders[folder_index]); + find = FindFirstFileA(pattern, &data); + if (find == INVALID_HANDLE_VALUE) + continue; + do { - file_reference_get_name(&file, FLAG(_name_filename_bit), name); - file_reference_get_name(&file, FLAG(_name_extension_bit), extension); - custom_edition_map_add(folders[folder_index], name, extension); - } + char name[sizeof(data.cFileName) + 1]; + char *extension; + + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + csmemcpy(name, data.cFileName, sizeof(data.cFileName)); + name[sizeof(data.cFileName)] = 0; + extension = strrchr(name, '.'); + if (extension) + { + *extension++ = 0; + custom_edition_map_add(folders[folder_index], name, extension); + } + } while (FindNextFileA(find, &data)); + CloseHandle(find); } qsort(globals->maps, globals->map_count, sizeof(globals->maps[0]), custom_edition_map_compare); qsort(globals->campaigns, globals->campaign_count, sizeof(globals->campaigns[0]), custom_edition_map_compare);