Add: list_[scenario|heightmap] and load_[scenario|height] console commands (#11867)

This commit is contained in:
Patric Stout 2024-01-23 14:01:25 +01:00 committed by GitHub
parent 76499b96fb
commit a1487ce620
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 134 additions and 37 deletions

View File

@ -56,9 +56,8 @@ static uint _script_current_depth; ///< Depth of scripts running (used to abort
/** File list storage for the console, for caching the last 'ls' command. */
class ConsoleFileList : public FileList {
public:
ConsoleFileList() : FileList()
ConsoleFileList(AbstractFileType abstract_filetype, bool show_dirs) : FileList(), abstract_filetype(abstract_filetype), show_dirs(show_dirs)
{
this->file_list_valid = false;
}
/** Declare the file storage cache as being invalid, also clears all stored files. */
@ -75,15 +74,19 @@ public:
void ValidateFileList(bool force_reload = false)
{
if (force_reload || !this->file_list_valid) {
this->BuildFileList(FT_SAVEGAME, SLO_LOAD);
this->BuildFileList(this->abstract_filetype, SLO_LOAD, this->show_dirs);
this->file_list_valid = true;
}
}
bool file_list_valid; ///< If set, the file list is valid.
AbstractFileType abstract_filetype; ///< The abstract file type to list.
bool show_dirs; ///< Whether to show directories in the file list.
bool file_list_valid = false; ///< If set, the file list is valid.
};
static ConsoleFileList _console_file_list; ///< File storage cache for the console.
static ConsoleFileList _console_file_list_savegame{FT_SAVEGAME, true}; ///< File storage cache for savegames.
static ConsoleFileList _console_file_list_scenario{FT_SCENARIO, false}; ///< File storage cache for scenarios.
static ConsoleFileList _console_file_list_heightmap{FT_HEIGHTMAP, false}; ///< File storage cache for heightmaps.
/* console command defines */
#define DEF_CONSOLE_CMD(function) static bool function([[maybe_unused]] byte argc, [[maybe_unused]] char *argv[])
@ -424,8 +427,8 @@ DEF_CONSOLE_CMD(ConLoad)
if (argc != 2) return false;
const char *file = argv[1];
_console_file_list.ValidateFileList();
const FiosItem *item = _console_file_list.FindItem(file);
_console_file_list_savegame.ValidateFileList();
const FiosItem *item = _console_file_list_savegame.FindItem(file);
if (item != nullptr) {
if (GetAbstractFileType(item->type) == FT_SAVEGAME) {
_switch_mode = SM_LOAD_GAME;
@ -440,6 +443,57 @@ DEF_CONSOLE_CMD(ConLoad)
return true;
}
DEF_CONSOLE_CMD(ConLoadScenario)
{
if (argc == 0) {
IConsolePrint(CC_HELP, "Load a scenario by name or index. Usage: 'load_scenario <file | number>'.");
return true;
}
if (argc != 2) return false;
const char *file = argv[1];
_console_file_list_scenario.ValidateFileList();
const FiosItem *item = _console_file_list_scenario.FindItem(file);
if (item != nullptr) {
if (GetAbstractFileType(item->type) == FT_SCENARIO) {
_switch_mode = SM_LOAD_GAME;
_file_to_saveload.Set(*item);
} else {
IConsolePrint(CC_ERROR, "'{}' is not a scenario.", file);
}
} else {
IConsolePrint(CC_ERROR, "'{}' cannot be found.", file);
}
return true;
}
DEF_CONSOLE_CMD(ConLoadHeightmap)
{
if (argc == 0) {
IConsolePrint(CC_HELP, "Load a heightmap by name or index. Usage: 'load_heightmap <file | number>'.");
return true;
}
if (argc != 2) return false;
const char *file = argv[1];
_console_file_list_heightmap.ValidateFileList();
const FiosItem *item = _console_file_list_heightmap.FindItem(file);
if (item != nullptr) {
if (GetAbstractFileType(item->type) == FT_HEIGHTMAP) {
_switch_mode = SM_START_HEIGHTMAP;
_file_to_saveload.Set(*item);
} else {
IConsolePrint(CC_ERROR, "'{}' is not a heightmap.", file);
}
} else {
IConsolePrint(CC_ERROR, "'{}' cannot be found.", file);
}
return true;
}
DEF_CONSOLE_CMD(ConRemove)
{
@ -451,8 +505,8 @@ DEF_CONSOLE_CMD(ConRemove)
if (argc != 2) return false;
const char *file = argv[1];
_console_file_list.ValidateFileList();
const FiosItem *item = _console_file_list.FindItem(file);
_console_file_list_savegame.ValidateFileList();
const FiosItem *item = _console_file_list_savegame.FindItem(file);
if (item != nullptr) {
if (unlink(item->name.c_str()) != 0) {
IConsolePrint(CC_ERROR, "Failed to delete '{}'.", item->name);
@ -461,7 +515,7 @@ DEF_CONSOLE_CMD(ConRemove)
IConsolePrint(CC_ERROR, "'{}' could not be found.", file);
}
_console_file_list.InvalidateFileList();
_console_file_list_savegame.InvalidateFileList();
return true;
}
@ -474,9 +528,41 @@ DEF_CONSOLE_CMD(ConListFiles)
return true;
}
_console_file_list.ValidateFileList(true);
for (uint i = 0; i < _console_file_list.size(); i++) {
IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list[i].title);
_console_file_list_savegame.ValidateFileList(true);
for (uint i = 0; i < _console_file_list_savegame.size(); i++) {
IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_savegame[i].title);
}
return true;
}
/* List all the scenarios */
DEF_CONSOLE_CMD(ConListScenarios)
{
if (argc == 0) {
IConsolePrint(CC_HELP, "List all loadable scenarios. Usage: 'list_scenarios'.");
return true;
}
_console_file_list_scenario.ValidateFileList(true);
for (uint i = 0; i < _console_file_list_scenario.size(); i++) {
IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_scenario[i].title);
}
return true;
}
/* List all the heightmaps */
DEF_CONSOLE_CMD(ConListHeightmaps)
{
if (argc == 0) {
IConsolePrint(CC_HELP, "List all loadable heightmaps. Usage: 'list_heightmaps'.");
return true;
}
_console_file_list_heightmap.ValidateFileList(true);
for (uint i = 0; i < _console_file_list_heightmap.size(); i++) {
IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_heightmap[i].title);
}
return true;
@ -493,8 +579,8 @@ DEF_CONSOLE_CMD(ConChangeDirectory)
if (argc != 2) return false;
const char *file = argv[1];
_console_file_list.ValidateFileList(true);
const FiosItem *item = _console_file_list.FindItem(file);
_console_file_list_savegame.ValidateFileList(true);
const FiosItem *item = _console_file_list_savegame.FindItem(file);
if (item != nullptr) {
switch (item->type) {
case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
@ -506,7 +592,7 @@ DEF_CONSOLE_CMD(ConChangeDirectory)
IConsolePrint(CC_ERROR, "{}: No such file or directory.", file);
}
_console_file_list.InvalidateFileList();
_console_file_list_savegame.InvalidateFileList();
return true;
}
@ -518,8 +604,8 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
}
/* XXX - Workaround for broken file handling */
_console_file_list.ValidateFileList(true);
_console_file_list.InvalidateFileList();
_console_file_list_savegame.ValidateFileList(true);
_console_file_list_savegame.InvalidateFileList();
IConsolePrint(CC_DEFAULT, FiosGetCurrentPath());
return true;
@ -2531,10 +2617,16 @@ void IConsoleStdLibRegister()
IConsole::CmdRegister("scrollto", ConScrollToTile);
IConsole::CmdRegister("alias", ConAlias);
IConsole::CmdRegister("load", ConLoad);
IConsole::CmdRegister("load_save", ConLoad);
IConsole::CmdRegister("load_scenario", ConLoadScenario);
IConsole::CmdRegister("load_heightmap", ConLoadHeightmap);
IConsole::CmdRegister("rm", ConRemove);
IConsole::CmdRegister("save", ConSave);
IConsole::CmdRegister("saveconfig", ConSaveConfig);
IConsole::CmdRegister("ls", ConListFiles);
IConsole::CmdRegister("list_saves", ConListFiles);
IConsole::CmdRegister("list_scenarios", ConListScenarios);
IConsole::CmdRegister("list_heightmaps", ConListHeightmaps);
IConsole::CmdRegister("cd", ConChangeDirectory);
IConsole::CmdRegister("pwd", ConPrintWorkingDirectory);
IConsole::CmdRegister("clear", ConClearBuffer);

View File

@ -65,8 +65,9 @@ bool FiosItem::operator< (const FiosItem &other) const
* Construct a file list with the given kind of files, for the stated purpose.
* @param abstract_filetype Kind of files to collect.
* @param fop Purpose of the collection, either #SLO_LOAD or #SLO_SAVE.
* @param show_dirs Whether to show directories.
*/
void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop)
void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop, bool show_dirs)
{
this->clear();
@ -76,15 +77,15 @@ void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperati
break;
case FT_SAVEGAME:
FiosGetSavegameList(fop, *this);
FiosGetSavegameList(fop, show_dirs, *this);
break;
case FT_SCENARIO:
FiosGetScenarioList(fop, *this);
FiosGetScenarioList(fop, show_dirs, *this);
break;
case FT_HEIGHTMAP:
FiosGetHeightmapList(fop, *this);
FiosGetHeightmapList(fop, show_dirs, *this);
break;
default:
@ -337,11 +338,12 @@ bool FiosFileScanner::AddFile(const std::string &filename, size_t, const std::st
/**
* Fill the list of the files in a directory, according to some arbitrary rule.
* @param fop Purpose of collecting the list.
* @param show_dirs Whether to list directories.
* @param callback_proc The function that is called where you need to do the filtering.
* @param subdir The directory from where to start (global) searching.
* @param file_list Destination of the found files.
*/
static void FiosGetFileList(SaveLoadOperation fop, FiosGetTypeAndNameProc *callback_proc, Subdirectory subdir, FileList &file_list)
static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAndNameProc *callback_proc, Subdirectory subdir, FileList &file_list)
{
struct stat sb;
struct dirent *dirent;
@ -354,7 +356,7 @@ static void FiosGetFileList(SaveLoadOperation fop, FiosGetTypeAndNameProc *callb
assert(_fios_path != nullptr);
/* A parent directory link exists if we are not in the root directory */
if (!FiosIsRoot(*_fios_path)) {
if (show_dirs && !FiosIsRoot(*_fios_path)) {
fios = &file_list.emplace_back();
fios->type = FIOS_TYPE_PARENT;
fios->mtime = 0;
@ -364,7 +366,7 @@ static void FiosGetFileList(SaveLoadOperation fop, FiosGetTypeAndNameProc *callb
}
/* Show subdirectories */
if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) {
if (show_dirs && (dir = ttd_opendir(_fios_path->c_str())) != nullptr) {
while ((dirent = readdir(dir)) != nullptr) {
std::string d_name = FS2OTTD(dirent->d_name);
@ -384,7 +386,7 @@ static void FiosGetFileList(SaveLoadOperation fop, FiosGetTypeAndNameProc *callb
}
/* Sort the subdirs always by name, ascending, remember user-sorting order */
{
if (show_dirs) {
SortingBits order = _savegame_sort_order;
_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
std::sort(file_list.begin(), file_list.end());
@ -464,10 +466,11 @@ std::tuple<FiosType, std::string> FiosGetSavegameListCallback(SaveLoadOperation
/**
* Get a list of savegames.
* @param fop Purpose of collecting the list.
* @param show_dirs Whether to show directories.
* @param file_list Destination of the found files.
* @see FiosGetFileList
*/
void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list)
void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
{
static std::optional<std::string> fios_save_path;
@ -475,7 +478,7 @@ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list)
_fios_path = &(*fios_save_path);
FiosGetFileList(fop, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list);
FiosGetFileList(fop, show_dirs, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list);
}
/**
@ -510,10 +513,11 @@ std::tuple<FiosType, std::string> FiosGetScenarioListCallback(SaveLoadOperation
/**
* Get a list of scenarios.
* @param fop Purpose of collecting the list.
* @param show_dirs Whether to show directories.
* @param file_list Destination of the found files.
* @see FiosGetFileList
*/
void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list)
void FiosGetScenarioList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
{
static std::optional<std::string> fios_scn_path;
@ -524,7 +528,7 @@ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list)
std::string base_path = FioFindDirectory(SCENARIO_DIR);
Subdirectory subdir = (fop == SLO_LOAD && base_path == *_fios_path) ? SCENARIO_DIR : NO_DIRECTORY;
FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list);
FiosGetFileList(fop, show_dirs, &FiosGetScenarioListCallback, subdir, file_list);
}
std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation, const std::string &file, const std::string_view ext)
@ -570,9 +574,10 @@ std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation
/**
* Get a list of heightmaps.
* @param fop Purpose of collecting the list.
* @param show_dirs Whether to show directories.
* @param file_list Destination of the found files.
*/
void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list)
void FiosGetHeightmapList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
{
static std::optional<std::string> fios_hmap_path;
@ -582,7 +587,7 @@ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list)
std::string base_path = FioFindDirectory(HEIGHTMAP_DIR);
Subdirectory subdir = base_path == *_fios_path ? HEIGHTMAP_DIR : NO_DIRECTORY;
FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list);
FiosGetFileList(fop, show_dirs, &FiosGetHeightmapListCallback, subdir, file_list);
}
/**

View File

@ -87,7 +87,7 @@ struct FiosItem {
/** List of file information. */
class FileList : public std::vector<FiosItem> {
public:
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop);
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop, bool show_dirs);
const FiosItem *FindItem(const std::string_view file);
};
@ -104,9 +104,9 @@ extern SortingBits _savegame_sort_order;
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop);
void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list);
void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list);
void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list);
void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_list);
void FiosGetScenarioList(SaveLoadOperation fop, bool show_dirs, FileList &file_list);
void FiosGetHeightmapList(SaveLoadOperation fop, bool show_dirs, FileList &file_list);
bool FiosBrowseTo(const FiosItem *item);

View File

@ -829,7 +829,7 @@ public:
if (!gui_scope) break;
_fios_path_changed = true;
this->fios_items.BuildFileList(this->abstract_filetype, this->fop);
this->fios_items.BuildFileList(this->abstract_filetype, this->fop, true);
this->selected = nullptr;
_load_check_data.Clear();