From 2fb0fc2994bd7269ea73353cad657b462337d78a Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 21 Mar 2024 18:32:47 +0100 Subject: [PATCH 01/15] add orderlist export/import buttons --- src/lang/extra/english.txt | 2 ++ src/order_gui.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 26127ba51b..733db25a24 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -1681,6 +1681,8 @@ STR_ORDER_REVERSE_ORDER_LIST :Reverse order l STR_ORDER_APPEND_REVERSED_ORDER_LIST :Append reversed order list STR_ORDER_DUPLICATE_ORDER :Duplicate order STR_ORDER_CHANGE_JUMP_TARGET :Change jump target +STR_ORDER_EXPORT_ORDER_LIST :Copy order list to file +STR_ORDER_IMPORT_ORDER_LIST :Get order list from file STR_ORDER_TRY_ACQUIRE_SLOT_BUTTON :Try acquire slot STR_ORDER_RELEASE_SLOT_BUTTON :Release slot diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 8643610f84..77cd5bb91c 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -633,6 +633,8 @@ enum OrderDropDownID { static const StringID _order_manage_list_dropdown[] = { STR_ORDER_REVERSE_ORDER_LIST, STR_ORDER_APPEND_REVERSED_ORDER_LIST, + STR_ORDER_EXPORT_ORDER_LIST, + STR_ORDER_IMPORT_ORDER_LIST, INVALID_STRING_ID }; @@ -3488,6 +3490,8 @@ public: switch (index) { case 0: this->OrderClick_ReverseOrderList(0); break; case 1: this->OrderClick_ReverseOrderList(1); break; + case 2: /*TODO:Copy order list as Unified Order List Format*/break; + case 3: /*TODO:Pase order list as Unified Order List Format*/break; default: NOT_REACHED(); } break; From eaafbae8797147363c6c768ca5e7786fcbd5be3b Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 21 Mar 2024 23:12:30 +0100 Subject: [PATCH 02/15] Extended fios to display xml orferlist files. --- src/fileio_type.h | 5 ++ src/fios.cpp | 54 ++++++++++++++++ src/fios_gui.cpp | 144 ++++++++++++++++++++++++++++++++++++++++--- src/lang/english.txt | 4 +- src/order_gui.cpp | 5 +- 5 files changed, 201 insertions(+), 11 deletions(-) diff --git a/src/fileio_type.h b/src/fileio_type.h index c871c1c14b..26b0ab2948 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -18,6 +18,7 @@ enum AbstractFileType { FT_SAVEGAME, ///< old or new savegame FT_SCENARIO, ///< old or new scenario FT_HEIGHTMAP, ///< heightmap file + FT_ORDERLIST, ///< orderlist file FT_INVALID = 7, ///< Invalid or unknown file type. FT_NUMBITS = 3, ///< Number of bits required for storing a #AbstractFileType value. @@ -34,6 +35,9 @@ enum DetailedFileType { DFT_HEIGHTMAP_BMP, ///< BMP file. DFT_HEIGHTMAP_PNG, ///< PNG file. + /* Orderlist files */ + DFT_ORDERLIST, ///< XML file. + /* fios 'files' */ DFT_FIOS_DRIVE, ///< A drive (letter) entry. DFT_FIOS_PARENT, ///< A parent directory entry. @@ -76,6 +80,7 @@ enum FiosType { FIOS_TYPE_OLD_SCENARIO = MAKE_FIOS_TYPE(FT_SCENARIO, DFT_OLD_GAME_FILE), FIOS_TYPE_PNG = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_PNG), FIOS_TYPE_BMP = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_BMP), + FIOS_TYPE_ORDERLIST = MAKE_FIOS_TYPE(FT_ORDERLIST, DFT_ORDERLIST), FIOS_TYPE_INVALID = MAKE_FIOS_TYPE(FT_INVALID, DFT_INVALID), }; diff --git a/src/fios.cpp b/src/fios.cpp index d34f6070a0..28a1a92f5a 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -33,6 +33,9 @@ #include "safeguards.h" +/*For some reason I need to pre-declare this function specifically, otherwise the whole thing just won't compile*/ +void FiosGetOrderlistList(SaveLoadOperation fop, bool show_dirs, FileList &file_list); + /* Variables to display file lists */ static std::string *_fios_path = nullptr; SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; @@ -91,6 +94,10 @@ void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperati FiosGetHeightmapList(fop, show_dirs, *this); break; + case FT_ORDERLIST: + FiosGetOrderlistList(fop, show_dirs, *this); + break; + default: NOT_REACHED(); } @@ -185,6 +192,7 @@ bool FiosBrowseTo(const FiosItem *item) case FIOS_TYPE_OLDFILE: case FIOS_TYPE_SCENARIO: case FIOS_TYPE_OLD_SCENARIO: + case FIOS_TYPE_ORDERLIST: case FIOS_TYPE_PNG: case FIOS_TYPE_BMP: return false; @@ -499,6 +507,52 @@ void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_l FiosGetFileList(fop, show_dirs, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list); } +/** + * Callback for FiosGetOrderlistList. It tells if a file is a orederlist or not. + * @param fop Purpose of collecting the list. + * @param file Name of the file to check. + * @param ext A pointer to the extension identifier inside file + * @param title Buffer if a callback wants to lookup the title of the file; nullptr to skip the lookup + * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == nullptr + * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame + * @see FiosGetFileList + * @see FiosGetOrderlistList + */ +FiosType FiosGetOrderlistListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) +{ + /* Show orderlist files + * .XML orderlist files + */ + + /* Don't crash if we supply no extension */ + if (ext == nullptr) ext = ""; + + if (StrEqualsIgnoreCase(ext, ".xml")) { + GetFileTitle(file, title, last, SAVE_DIR); + return FIOS_TYPE_ORDERLIST; + } + + return FIOS_TYPE_INVALID; +} + +/** + * Get a list of orderlists. + * @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 FiosGetOrderlistList(SaveLoadOperation fop, bool show_dirs, FileList &file_list) +{ + static std::optional fios_save_path; + + if (!fios_save_path) fios_save_path = FioFindDirectory(SAVE_DIR); + + _fios_path = &(*fios_save_path); + + FiosGetFileList(fop, show_dirs, &FiosGetOrderlistListCallback, NO_DIRECTORY, file_list); +} + /** * Callback for FiosGetFileList. It tells if a file is a scenario or not. * @param fop Purpose of collecting the list. diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index e4b4318372..75b75acca2 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -234,6 +234,99 @@ static constexpr NWidgetPart _nested_save_dialog_widgets[] = { EndContainer(), }; +/** Save Orderlist */ +static constexpr NWidgetPart _nested_save_orderlist_dialog_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + EndContainer(), + /* Current directory and free space */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + /* Left side : filter box and available files */ + NWidget(NWID_VERTICAL), + /* Filter box with label */ + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 1), + NWidget(NWID_HORIZONTAL), SetPadding(WidgetDimensions::unscaled.framerect.top, 0, WidgetDimensions::unscaled.framerect.bottom, 0), + SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetFill(0, 1), SetDataTip(STR_SAVELOAD_FILTER_TITLE , STR_NULL), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), + SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + EndContainer(), + /* Sort buttons */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON), + EndContainer(), + /* Files */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND), + NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetPadding(2, 2, 2, 2), + SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(), + EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_SAVE_OSK_TITLE), SetPadding(2, 2, 2, 2), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP), + EndContainer(), + /* Save/delete buttons */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +/** Load Orderlist */ +static constexpr NWidgetPart _nested_load_orderlist_dialog_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + EndContainer(), + /* Current directory and free space */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(), + + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + /* Left side : filter box and available files */ + NWidget(NWID_VERTICAL), + /* Filter box with label */ + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 1), + NWidget(NWID_HORIZONTAL), SetPadding(WidgetDimensions::unscaled.framerect.top, 0, WidgetDimensions::unscaled.framerect.bottom, 0), + SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetFill(0, 1), SetDataTip(STR_SAVELOAD_FILTER_TITLE , STR_NULL), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), + SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + EndContainer(), + /* Sort buttons */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON), + EndContainer(), + /* Files */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND), + NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 2, 2, 2), + SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(), + EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + EndContainer(), + EndContainer(), +}; + /** Text colours of #DetailedFileType fios entries in the window. */ static const TextColour _fios_colours[] = { TC_LIGHT_BROWN, // DFT_OLD_GAME_FILE @@ -325,6 +418,7 @@ public: case FT_SCENARIO: case FT_HEIGHTMAP: + case FT_ORDERLIST: this->filename_editbox.text.Assign("UNNAMED"); break; @@ -355,6 +449,10 @@ public: caption_string = (this->fop == SLO_SAVE) ? STR_SAVELOAD_SAVE_HEIGHTMAP : STR_SAVELOAD_LOAD_HEIGHTMAP; break; + case FT_ORDERLIST: + caption_string = (this->fop == SLO_SAVE) ? STR_SAVELOAD_SAVE_ORDERLIST : STR_SAVELOAD_LOAD_ORDERLIST; + break; + default: NOT_REACHED(); } @@ -672,6 +770,8 @@ public: break; case WID_SL_DRIVES_DIRECTORIES_LIST: { // Click the listbox + printf("test"); + auto it = this->vscroll->GetScrolledItemFromWidget(this->display_list, pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top); if (it == this->display_list.end()) return; @@ -685,13 +785,18 @@ public: } if (click_count == 1) { + if (this->selected != file) { + this->selected = file; _load_check_data.Clear(); - if (GetDetailedFileType(file->type) == DFT_GAME_FILE) { - /* Other detailed file types cannot be checked before. */ - SaveOrLoad(file->name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); + auto type = GetDetailedFileType(file->type); + + switch (type) { + case DFT_GAME_FILE: SaveOrLoad(file->name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); break; + case DFT_ORDERLIST: break; + default: break; } this->InvalidateData(SLIWD_SELECTION_CHANGES); @@ -704,7 +809,7 @@ public: } else if (!_load_check_data.HasErrors()) { this->selected = file; if (this->fop == SLO_LOAD) { - if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) { + if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO || this->abstract_filetype == FT_ORDERLIST) { this->OnClick(pt, WID_SL_LOAD_BUTTON, 1); } else { assert(this->abstract_filetype == FT_HEIGHTMAP); @@ -911,9 +1016,8 @@ public: !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GLC_ALL_GOOD); break; } - - default: - NOT_REACHED(); + + default: break; } break; @@ -948,6 +1052,14 @@ static WindowDesc _load_heightmap_dialog_desc(__FILE__, __LINE__, std::begin(_nested_load_heightmap_dialog_widgets), std::end(_nested_load_heightmap_dialog_widgets) ); +/** Load orderlist*/ +static WindowDesc _load_orderlist_dialog_desc(__FILE__, __LINE__, + WDP_CENTER, "load_orderlist", 257, 320, + WC_SAVELOAD, WC_NONE, + 0, + std::begin(_nested_load_orderlist_dialog_widgets), std::end(_nested_load_orderlist_dialog_widgets) +); + /** Save game/scenario */ static WindowDesc _save_dialog_desc(__FILE__, __LINE__, WDP_CENTER, "save_game", 500, 294, @@ -956,6 +1068,14 @@ static WindowDesc _save_dialog_desc(__FILE__, __LINE__, std::begin(_nested_save_dialog_widgets), std::end(_nested_save_dialog_widgets) ); +/** Load orderlist*/ +static WindowDesc _save_orderlist_dialog_desc(__FILE__, __LINE__, + WDP_CENTER, "save_orderlist", 257, 320, + WC_SAVELOAD, WC_NONE, + 0, + std::begin(_nested_save_orderlist_dialog_widgets), std::end(_nested_save_orderlist_dialog_widgets) +); + /** * Launch save/load dialog in the given mode. * @param abstract_filetype Kind of file to handle. @@ -966,7 +1086,15 @@ void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fo CloseWindowById(WC_SAVELOAD, 0); WindowDesc *sld; - if (fop == SLO_SAVE) { + if (abstract_filetype == FT_ORDERLIST){ + + if (fop == SLO_SAVE) { + sld = &_save_orderlist_dialog_desc; + } else if (fop == SLO_LOAD) { + sld = &_load_orderlist_dialog_desc; + } + + } else if (fop == SLO_SAVE) { sld = &_save_dialog_desc; } else { /* Dialogue for loading a file. */ diff --git a/src/lang/english.txt b/src/lang/english.txt index 529743ab61..3c6cd68de6 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3257,8 +3257,10 @@ STR_SAVELOAD_SAVE_CAPTION :{WHITE}Save Gam STR_SAVELOAD_LOAD_CAPTION :{WHITE}Load Game STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Save Scenario STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Load Scenario -STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Load Heightmap STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Save Heightmap +STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Load Heightmap +STR_SAVELOAD_SAVE_ORDERLIST :{WHITE}Save Orderlist +STR_SAVELOAD_LOAD_ORDERLIST :{WHITE}Load Orderlist STR_SAVELOAD_HOME_BUTTON :{BLACK}Click here to jump to the current default save/load directory STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} free STR_SAVELOAD_LIST_TOOLTIP :{BLACK}List of drives, directories and saved-game files diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 77cd5bb91c..db6aff6828 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -35,6 +35,7 @@ #include "tracerestrict.h" #include "scope.h" #include "core/backup_type.hpp" +#include "fios.h" #include "widgets/order_widget.h" @@ -3490,8 +3491,8 @@ public: switch (index) { case 0: this->OrderClick_ReverseOrderList(0); break; case 1: this->OrderClick_ReverseOrderList(1); break; - case 2: /*TODO:Copy order list as Unified Order List Format*/break; - case 3: /*TODO:Pase order list as Unified Order List Format*/break; + case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE); break; + case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD); break; default: NOT_REACHED(); } break; From aa0b871674d29be43db3afb5890264eb782ed7d0 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 21 Mar 2024 23:23:26 +0100 Subject: [PATCH 03/15] Reverted wrong change --- src/fios_gui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 75b75acca2..1e539750ac 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -793,10 +793,10 @@ public: auto type = GetDetailedFileType(file->type); - switch (type) { - case DFT_GAME_FILE: SaveOrLoad(file->name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); break; - case DFT_ORDERLIST: break; - default: break; + if(GetDetailedFileType(file->type) == DFT_GAME_FILE) { + + SaveOrLoad(file->name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); + } this->InvalidateData(SLIWD_SELECTION_CHANGES); From 4508fbd4061334394927aae4c46b8a9bfafbf521 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Fri, 22 Mar 2024 18:01:40 +0100 Subject: [PATCH 04/15] Fixes wrong pre-declaration location --- src/fios.cpp | 3 --- src/fios.h | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fios.cpp b/src/fios.cpp index 28a1a92f5a..4e116d79ce 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -33,9 +33,6 @@ #include "safeguards.h" -/*For some reason I need to pre-declare this function specifically, otherwise the whole thing just won't compile*/ -void FiosGetOrderlistList(SaveLoadOperation fop, bool show_dirs, FileList &file_list); - /* Variables to display file lists */ static std::string *_fios_path = nullptr; SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; diff --git a/src/fios.h b/src/fios.h index 026593b787..cb48672b60 100644 --- a/src/fios.h +++ b/src/fios.h @@ -56,6 +56,7 @@ void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fo 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); +void FiosGetOrderlistList(SaveLoadOperation fop, bool show_dirs, FileList &file_list); bool FiosBrowseTo(const FiosItem *item); @@ -68,6 +69,7 @@ std::string FiosMakeSavegameName(const char *name); FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); +FiosType FiosGetOrderlistListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); void ScanScenarios(); const char *FindScenario(const ContentInfo *ci, bool md5sum); From 547d9ffe192916674fd4da60a6ba0dc4b21f5f2c Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Sat, 23 Mar 2024 14:06:18 +0100 Subject: [PATCH 05/15] styling fixes --- src/fios_gui.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 1e539750ac..ce5c3e5728 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -275,11 +275,10 @@ static constexpr NWidgetPart _nested_save_orderlist_dialog_widgets[] = { NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_SAVE_OSK_TITLE), SetPadding(2, 2, 2, 2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP), EndContainer(), - /* Save/delete buttons */ - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), - EndContainer(), + + /* Save button*/ + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + EndContainer(), EndContainer(), }; @@ -465,9 +464,9 @@ public: this->querystrings[WID_SL_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; - /* pause is only used in single-player, non-editor mode, non-menu mode. It + /* pause is only used in single-player, non-editor mode, non-menu mode, when not operationg on orderlists. It * will be unpaused in the WE_DESTROY event handler. */ - if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) { + if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR && this->abstract_filetype != FT_ORDERLIST) { DoCommandP(0, PM_PAUSED_SAVELOAD, 1, CMD_PAUSE); } SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); @@ -747,6 +746,11 @@ public: if (this->abstract_filetype == FT_HEIGHTMAP) { this->Close(); ShowHeightmapLoad(); + }else if (this->abstract_filetype == FT_ORDERLIST) { + + this->Close(); + FILE *dataFile = fopen(this->selected->name, "r"); + } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; ClearErrorMessages(); From bedc33c46e308bac76d4c84f81c7ea8b7d71441b Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Sat, 23 Mar 2024 19:37:42 +0100 Subject: [PATCH 06/15] Renamed orderlist import/export options --- src/lang/extra/english.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 733db25a24..4c59a1a7bb 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -1681,8 +1681,8 @@ STR_ORDER_REVERSE_ORDER_LIST :Reverse order l STR_ORDER_APPEND_REVERSED_ORDER_LIST :Append reversed order list STR_ORDER_DUPLICATE_ORDER :Duplicate order STR_ORDER_CHANGE_JUMP_TARGET :Change jump target -STR_ORDER_EXPORT_ORDER_LIST :Copy order list to file -STR_ORDER_IMPORT_ORDER_LIST :Get order list from file +STR_ORDER_EXPORT_ORDER_LIST :Export orderlist +STR_ORDER_IMPORT_ORDER_LIST :Import orderlist STR_ORDER_TRY_ACQUIRE_SLOT_BUTTON :Try acquire slot STR_ORDER_RELEASE_SLOT_BUTTON :Release slot From 366f1b622ad59ebea2a2afabeb81d40eb1d79940 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Sun, 24 Mar 2024 21:43:07 +0100 Subject: [PATCH 07/15] Full orderlist exporting implementation and partial importing implementation. --- src/order_base.h | 21 ++++++++ src/order_cmd.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++- src/order_gui.cpp | 73 +++++++++++++++++++++++++- 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/src/order_base.h b/src/order_base.h index 640b2edf7a..c317b33d05 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -233,6 +233,10 @@ public: void MakeChangeCounter(); void MakeLabel(OrderLabelSubType subtype); + std::string ToJSONString() const; + static Order FromJSONString(std::string); + + /** * Is this a 'goto' order with a real destination? * @return True if the type is either #OT_GOTO_WAYPOINT, #OT_GOTO_DEPOT or #OT_GOTO_STATION. @@ -780,6 +784,7 @@ public: inline std::vector &GetScheduledDispatchMutable() { return this->scheduled_dispatch; } void SetScheduledDispatch(std::vector dispatch_list); + void AddScheduledDispatch(uint32_t offset); void RemoveScheduledDispatch(uint32_t offset); void AdjustScheduledDispatch(int32_t adjust); @@ -856,6 +861,19 @@ public: */ inline int32_t GetScheduledDispatchDelay() const { return this->scheduled_dispatch_max_delay; } + /** + * Get the scheduled dispatch flags + * @return flags + */ + inline int8_t GetScheduledDispatchFlags() const {return this->scheduled_dispatch_flags; } + + /** + * Set the scheduled disaptch flags + * @param flags + */ + inline void SetScheduledDispatchFlags(int8_t flags) { this->scheduled_dispatch_flags = flags; } + + inline void BorrowSchedule(DispatchSchedule &other) { this->CopyBasicFields(other); @@ -959,6 +977,9 @@ public: void DeleteOrderAt(int index); void MoveOrder(int from, int to); + std::string ToJSONString(); + static OrderList FromJSONString(std::string); + /** * Is this a shared order list? * @return whether this order list is shared among multiple vehicles diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 05ea4836c9..31c692c26c 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -40,11 +40,12 @@ #include "tracerestrict.h" #include "train.h" #include "date_func.h" +#include "3rdparty/nlohmann/json.hpp" #include "table/strings.h" #include "3rdparty/robin_hood/robin_hood.h" - +#include <3rdparty/nlohmann/json.hpp> #include "safeguards.h" /* DestinationID must be at least as large as every these below, because it can @@ -269,6 +270,41 @@ void Order::MakeLabel(OrderLabelSubType subtype) this->flags = subtype; } +std::string Order::ToJSONString() const +{ + std::string out; + nlohmann::json json; + json["packed-data"] = this->Pack(); + + json["destination-id"] = this->GetDestination(); + + if(this->extra.get() != nullptr){ + auto& extraJson = json["extra"]; + + extraJson["cargo-type-flags"] = this->extra.get()->cargo_type_flags; + extraJson["colour"] = this->extra.get()->colour; + extraJson["dispatch-index"] = this->extra.get()->dispatch_index; + extraJson["xdata"] = this->extra.get()->xdata; + extraJson["xdata2"] = this->extra.get()->xdata2; + extraJson["xflags"] = this->extra.get()->xflags; + } + + json["refit-cargo"] = this->GetRefitCargo(); + json["wait-time"] = this->GetWaitTime(); + json["travel-time"] = this->GetTravelTime(); + json["max-speed"] = this->GetMaxSpeed(); + + out = json.dump(); + return out; +} + +Order Order::FromJSONString(std::string) +{ + + Order newOrder; + return newOrder; +} + /** * Make this depot/station order also a refit order. * @param cargo the cargo type to change to. @@ -824,6 +860,97 @@ void OrderList::MoveOrder(int from, int to) this->ReindexOrderList(); } +std::string OrderList::ToJSONString() +{ + + nlohmann::json json; + auto& SD_data = this->GetScheduledDispatchScheduleSet(); + + auto& headJson = json["head"]; + for (unsigned int i = 0; auto &SD : SD_data) { + + auto &SDJson = headJson["scheduled-dispatch"][i++]; + + for (unsigned int i = 0; auto &SD_slot : SD.GetScheduledDispatch()) { + auto& slotsJson = SDJson["slots"][i++]; + slotsJson["offset"] = SD_slot.offset; + slotsJson["flags"] = SD_slot.flags; + } + + SDJson["name"] = SD.ScheduleName(); + SDJson["start-tick"] = SD.GetScheduledDispatchStartTick().value; + SDJson["duration"] = SD.GetScheduledDispatchDuration(); + SDJson["max-delay"] = SD.GetScheduledDispatchDelay(); + SDJson["flags"] = SD.GetScheduledDispatchFlags(); + + } + + const Order* o = this->GetFirstOrder(); + + if (o != nullptr) { + int i = 0; + do { + json["orders"][i++] = nlohmann::json::parse(o->ToJSONString()); + } while ((o = this->GetNext(o)) != this->GetFirstOrder()); + } + + std::cout << json.dump(); + return json.dump(); + +} + +OrderList OrderList::FromJSONString(std::string json_str) +{ + OrderList list; + nlohmann::json json = nlohmann::json::parse(json_str); + + if (json.contains("head")){ + auto &headJson = json.at("head"); + if (headJson.contains("scheduled-dispatch")) { + auto &SDJson = headJson.at("scheduled-dispatch"); + if (SDJson.is_array()) { + for (nlohmann::json::iterator it = SDJson.begin(); it != SDJson.end(); ++it) { + if (it.value().contains("slots")) { + + auto &slotsJson = it.value().at("slots");; + DispatchSchedule dispatchSchedule; + + if (slotsJson.is_array()) { + for (nlohmann::json::iterator it = slotsJson.begin(); it != slotsJson.end(); ++it) { + + DispatchSlot newDispatchSlot; + + newDispatchSlot.offset = it.value().at("offset").template get(); + newDispatchSlot.flags = it.value().at("flags").template get(); + + dispatchSchedule.GetScheduledDispatchMutable().push_back(newDispatchSlot); + + } + } + + dispatchSchedule.ScheduleName() = it.value().at("name").template get(); + dispatchSchedule.SetScheduledDispatchStartTick(it.value().at("start-tick").template get()); + dispatchSchedule.SetScheduledDispatchDuration(it.value().at("duration").template get()); + dispatchSchedule.SetScheduledDispatchDelay(it.value().at("max-delay").template get()); + dispatchSchedule.SetScheduledDispatchFlags(it.value().at("flags").template get()); + + list.dispatch_schedules.push_back(dispatchSchedule); + + } + } + } + } + + } + + if (json.contains("orders")) { + + /*Where do orders get allocated?*/ + } + + return list; +} + /** * Removes the vehicle from the shared order list. * @note This is supposed to be called when the vehicle is still in the chain diff --git a/src/order_gui.cpp b/src/order_gui.cpp index db6aff6828..a06643a8b3 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -3491,8 +3491,77 @@ public: switch (index) { case 0: this->OrderClick_ReverseOrderList(0); break; case 1: this->OrderClick_ReverseOrderList(1); break; - case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE); break; - case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD); break; + case 2: this->vehicle->orders->ToJSONString(); break; + case 3: this->vehicle->orders->FromJSONString(R"( + { + "head": { + "scheduled-dispatch": [ + { + "duration": 106560, + "flags": 0, + "max-delay": 0, + "name": "alfredo", + "slots": [ + { + "flags": 0, + "offset": 4514 + }, + { + "flags": 0, + "offset": 90280 + } + ], + "start-tick": 16729920 + } + ] + }, + "orders": [ + { + "destination-id": 0, + "max-speed": 65535, + "packed-data": 578, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 0, + "max-speed": 65535, + "packed-data": 578, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 0, + "max-speed": 65535, + "packed-data": 578, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 0, + "max-speed": 65535, + "packed-data": 578, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 0, + "max-speed": 65535, + "packed-data": 578, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + } + ] + } + )"); break; + + //case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE); break; + //case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD); break; default: NOT_REACHED(); } break; From 04721ba625800aa2f2342bb0ab1a4884f0bcdbe9 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Mon, 25 Mar 2024 22:09:18 +0100 Subject: [PATCH 08/15] basic order data importing + json files displayed instead of xml + display station names in output json --- src/fios.cpp | 4 +- src/order_base.h | 5 +- src/order_cmd.cpp | 67 ++++++++++++++++----- src/order_gui.cpp | 148 +++++++++++++++++++++++++--------------------- 4 files changed, 135 insertions(+), 89 deletions(-) diff --git a/src/fios.cpp b/src/fios.cpp index 4e116d79ce..beee4c4fe3 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -518,13 +518,13 @@ void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_l FiosType FiosGetOrderlistListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show orderlist files - * .XML orderlist files + * .json orderlist files */ /* Don't crash if we supply no extension */ if (ext == nullptr) ext = ""; - if (StrEqualsIgnoreCase(ext, ".xml")) { + if (StrEqualsIgnoreCase(ext, ".json")) { GetFileTitle(file, title, last, SAVE_DIR); return FIOS_TYPE_ORDERLIST; } diff --git a/src/order_base.h b/src/order_base.h index c317b33d05..e554bf752b 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -234,8 +234,7 @@ public: void MakeLabel(OrderLabelSubType subtype); std::string ToJSONString() const; - static Order FromJSONString(std::string); - + static void FromJSONString(const Vehicle * vehicle,std::string jsonSTR); /** * Is this a 'goto' order with a real destination? @@ -978,7 +977,7 @@ public: void MoveOrder(int from, int to); std::string ToJSONString(); - static OrderList FromJSONString(std::string); + static void FromJSONString(const Vehicle* v,std::string str); /** * Is this a shared order list? diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 31c692c26c..2f1004421f 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -277,6 +277,9 @@ std::string Order::ToJSONString() const json["packed-data"] = this->Pack(); json["destination-id"] = this->GetDestination(); + Station * station = Station::GetIfValid(this->GetDestination()); + if(station != nullptr) + json["destination-name"] = station->cached_name; if(this->extra.get() != nullptr){ auto& extraJson = json["extra"]; @@ -298,11 +301,29 @@ std::string Order::ToJSONString() const return out; } -Order Order::FromJSONString(std::string) +void Order::FromJSONString(const Vehicle * v,std::string jsonSTR) { + + /* + this->type = (OrderType)GB(packed, 0, 8); //done + this->flags = GB(packed, 8, 16); // done + this->dest = GB(packed, 24, 16); // done + this->extra = nullptr; //masive pain ?????? + this->next = nullptr; + this->refit_cargo = CARGO_NO_REFIT; + this->occupancy = 0; + this->wait_time = 0; + this->travel_time = 0; + this->max_speed = UINT16_MAX; + */ + //hell + nlohmann::json json = nlohmann::json::parse(jsonSTR); + + uint64_t order_pack = json.at("packed-data").get(); + uint64_t extra = json.at("packed-data").get(); + + DoCommandPEx(v->tile, v->index, 0, order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); - Order newOrder; - return newOrder; } /** @@ -893,21 +914,41 @@ std::string OrderList::ToJSONString() json["orders"][i++] = nlohmann::json::parse(o->ToJSONString()); } while ((o = this->GetNext(o)) != this->GetFirstOrder()); } - - std::cout << json.dump(); + + std::cout << std::setw(4)<< json.dump() << "\n"; return json.dump(); } -OrderList OrderList::FromJSONString(std::string json_str) +void OrderList::FromJSONString(const Vehicle * v,std::string json_str) { - OrderList list; nlohmann::json json = nlohmann::json::parse(json_str); - if (json.contains("head")){ - auto &headJson = json.at("head"); + //plan... painful plan + CMD_DELETE_ORDER; //for all existing orders + CMD_INSERT_ORDER; //for each order new + + CMD_SCHEDULED_DISPATCH_ADD_NEW_SCHEDULE; + CMD_SCHEDULED_DISPATCH_ADD; + CMD_SCHEDULED_DISPATCH_RENAME_SCHEDULE; + + if (json.contains("orders")) { + auto &ordersJson = json["orders"]; + if (ordersJson.is_array()) { + for (nlohmann::json::iterator it = ordersJson.begin(); it != ordersJson.end(); ++it) { + auto &orderJson = it.value(); + Order::FromJSONString(v,orderJson.dump()); + + + } + + } + } + + if (json.contains("orders") && json.contains("head")){ + auto &headJson = json["head"]; if (headJson.contains("scheduled-dispatch")) { - auto &SDJson = headJson.at("scheduled-dispatch"); + auto &SDJson = headJson["scheduled-dispatch"]; if (SDJson.is_array()) { for (nlohmann::json::iterator it = SDJson.begin(); it != SDJson.end(); ++it) { if (it.value().contains("slots")) { @@ -934,8 +975,6 @@ OrderList OrderList::FromJSONString(std::string json_str) dispatchSchedule.SetScheduledDispatchDelay(it.value().at("max-delay").template get()); dispatchSchedule.SetScheduledDispatchFlags(it.value().at("flags").template get()); - list.dispatch_schedules.push_back(dispatchSchedule); - } } } @@ -943,12 +982,8 @@ OrderList OrderList::FromJSONString(std::string json_str) } - if (json.contains("orders")) { - /*Where do orders get allocated?*/ - } - return list; } /** diff --git a/src/order_gui.cpp b/src/order_gui.cpp index a06643a8b3..a0ac9c36bb 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -1631,7 +1631,7 @@ private: bool InsertNewOrder(uint64_t order_pack) { - return DoCommandPEx(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); + return DoCommandPEx(this->vehicle->tile, this->vehicle->index, 0, order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); } bool ModifyOrder(VehicleOrderID sel_ord, uint32_t p2, bool error_msg = true, const char *text = nullptr) @@ -3492,73 +3492,85 @@ public: case 0: this->OrderClick_ReverseOrderList(0); break; case 1: this->OrderClick_ReverseOrderList(1); break; case 2: this->vehicle->orders->ToJSONString(); break; - case 3: this->vehicle->orders->FromJSONString(R"( - { - "head": { - "scheduled-dispatch": [ - { - "duration": 106560, - "flags": 0, - "max-delay": 0, - "name": "alfredo", - "slots": [ - { - "flags": 0, - "offset": 4514 - }, - { - "flags": 0, - "offset": 90280 - } - ], - "start-tick": 16729920 - } - ] - }, - "orders": [ - { - "destination-id": 0, - "max-speed": 65535, - "packed-data": 578, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 0, - "max-speed": 65535, - "packed-data": 578, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 0, - "max-speed": 65535, - "packed-data": 578, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 0, - "max-speed": 65535, - "packed-data": 578, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 0, - "max-speed": 65535, - "packed-data": 578, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - } - ] - } - )"); break; + case 3: this->vehicle->orders->FromJSONString(this->vehicle, R"({ + "head": { + "scheduled-dispatch": [ + { + "duration": 106560, + "flags": 0, + "max-delay": 0, + "name": "alfredo", + "slots": [ + { + "flags": 0, + "offset": 4514 + }, + { + "flags": 0, + "offset": 90280 + } + ], + "start-tick": 16729920 + } + ] + }, + "orders": [ + { + "destination-id": 2, + "destination-name": "Grateley Halt", + "max-speed": 65535, + "packed-data": 33554513, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 3, + "destination-name": "Grateley Exchange", + "max-speed": 65535, + "packed-data": 50331729, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 4, + "destination-name": "Grateley Annexe", + "max-speed": 65535, + "packed-data": 67108945, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 3, + "destination-name": "Grateley Exchange", + "max-speed": 65535, + "packed-data": 50331729, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 2, + "destination-name": "Grateley Halt", + "max-speed": 65535, + "packed-data": 33554513, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + }, + { + "destination-id": 1, + "destination-name": "Grateley Transfer", + "max-speed": 65535, + "packed-data": 16777297, + "refit-cargo": 254, + "travel-time": 0, + "wait-time": 0 + } + ] +})"); break; //case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE); break; //case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD); break; From 3f678ade0337fab3d6252119e83949b255b4e04d Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 28 Mar 2024 17:15:39 +0100 Subject: [PATCH 09/15] GUI fixed and order import completed --- src/fios.cpp | 5 ++ src/fios.h | 5 +- src/fios_gui.cpp | 34 +++++++-- src/lang/english.txt | 5 ++ src/order_base.h | 2 +- src/order_cmd.cpp | 122 ++++++++++++++++++++++---------- src/order_gui.cpp | 86 +--------------------- src/script/api/script_types.hpp | 2 +- 8 files changed, 134 insertions(+), 127 deletions(-) diff --git a/src/fios.cpp b/src/fios.cpp index beee4c4fe3..2eb2d7244e 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -229,6 +229,11 @@ static std::string FiosMakeFilename(const std::string *path, const char *name, c * @param last Last element of buffer \a buf. * @return The completed filename. */ + +std::string FiosMakeOrderListName(const char *name) +{ + return FiosMakeFilename(_fios_path, name, ".json"); +} std::string FiosMakeSavegameName(const char *name) { const char *extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav"; diff --git a/src/fios.h b/src/fios.h index cb48672b60..00e91225ec 100644 --- a/src/fios.h +++ b/src/fios.h @@ -15,6 +15,7 @@ #include "newgrf_config.h" #include "network/core/tcp_content_type.h" #include +#include /** Special values for save-load window for the data parameter of #InvalidateWindowData. */ @@ -51,7 +52,7 @@ DECLARE_ENUM_AS_BIT_SET(SortingBits) /* Variables to display file lists */ extern SortingBits _savegame_sort_order; -void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop); +void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop,const Vehicle * veh = nullptr); void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_list); void FiosGetScenarioList(SaveLoadOperation fop, bool show_dirs, FileList &file_list); @@ -65,6 +66,8 @@ std::optional FiosGetDiskFreeSpace(const std::string &path); bool FiosDelete(const char *name); std::string FiosMakeHeightmapName(const char *name); std::string FiosMakeSavegameName(const char *name); +std::string FiosMakeOrderListName(const char *name); + FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index ce5c3e5728..f30f237746 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -29,6 +29,10 @@ #include "gamelog.h" #include "stringfilter_type.h" #include "gamelog.h" +#include "vehicle_base.h" +#include +#include +#include #include "widgets/fios_widget.h" @@ -370,6 +374,7 @@ struct SaveLoadWindow : public Window { private: static const uint EDITBOX_MAX_SIZE = 50; + const Vehicle* veh; QueryString filename_editbox; ///< Filename editbox. AbstractFileType abstract_filetype; /// Type of file to select. SaveLoadOperation fop; ///< File operation to perform. @@ -403,11 +408,13 @@ public: this->filename_editbox.text.Assign(GenerateDefaultSaveName()); } - SaveLoadWindow(WindowDesc *desc, AbstractFileType abstract_filetype, SaveLoadOperation fop) + SaveLoadWindow(WindowDesc *desc, AbstractFileType abstract_filetype, SaveLoadOperation fop,const Vehicle * veh = nullptr) : Window(desc), filename_editbox(64), abstract_filetype(abstract_filetype), fop(fop), filter_editbox(EDITBOX_MAX_SIZE) { assert(this->fop == SLO_SAVE || this->fop == SLO_LOAD); + this->veh = veh; + /* For saving, construct an initial file name. */ if (this->fop == SLO_SAVE) { switch (this->abstract_filetype) { @@ -748,9 +755,14 @@ public: ShowHeightmapLoad(); }else if (this->abstract_filetype == FT_ORDERLIST) { + std::ifstream t(this->selected->name); + std::stringstream buffer; + buffer << t.rdbuf(); + + veh->orders->FromJSONString(veh, buffer.str()); + this->Close(); - FILE *dataFile = fopen(this->selected->name, "r"); - + } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; ClearErrorMessages(); @@ -846,6 +858,18 @@ public: case WID_SL_SAVE_GAME: // Save game /* Note, this is also called via the OSK; and we need to lower the button. */ this->HandleButtonClick(WID_SL_SAVE_GAME); + + if (this->abstract_filetype == FT_ORDERLIST) { + + std::string fileName = FiosMakeOrderListName(this->filename_editbox.text.buf); + std::ofstream output; + output.open(fileName); + output << this->veh->orders->ToJSONString(); + output.close(); + + this->Close(); + } + break; } } @@ -1085,7 +1109,7 @@ static WindowDesc _save_orderlist_dialog_desc(__FILE__, __LINE__, * @param abstract_filetype Kind of file to handle. * @param fop File operation to perform (load or save). */ -void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop) +void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop,const Vehicle * veh) { CloseWindowById(WC_SAVELOAD, 0); @@ -1105,5 +1129,5 @@ void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fo sld = (abstract_filetype == FT_HEIGHTMAP) ? &_load_heightmap_dialog_desc : &_load_dialog_desc; } - new SaveLoadWindow(sld, abstract_filetype, fop); + new SaveLoadWindow(sld, abstract_filetype, fop, veh); } diff --git a/src/lang/english.txt b/src/lang/english.txt index 3c6cd68de6..65a11f095a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5856,3 +5856,8 @@ STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) + +#json messages + +STR_ERROR_ORDERLIST_MALFORMED_JSON :{WHITE}Input JSON was malformed +STR_ERROR_JON :{WHITE}JSON error diff --git a/src/order_base.h b/src/order_base.h index e554bf752b..a811d29147 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -234,7 +234,7 @@ public: void MakeLabel(OrderLabelSubType subtype); std::string ToJSONString() const; - static void FromJSONString(const Vehicle * vehicle,std::string jsonSTR); + static Order FromJSONString(std::string jsonSTR); /** * Is this a 'goto' order with a real destination? diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 2f1004421f..f3c7f60516 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -26,6 +26,7 @@ #include "core/container_func.hpp" #include "core/pool_func.hpp" #include "core/random_func.hpp" +#include "core/serialisation.hpp" #include "aircraft.h" #include "roadveh.h" #include "station_base.h" @@ -41,12 +42,14 @@ #include "train.h" #include "date_func.h" #include "3rdparty/nlohmann/json.hpp" +#include "command_aux.h" #include "table/strings.h" #include "3rdparty/robin_hood/robin_hood.h" #include <3rdparty/nlohmann/json.hpp> #include "safeguards.h" +#include /* DestinationID must be at least as large as every these below, because it can * be any of them @@ -301,29 +304,67 @@ std::string Order::ToJSONString() const return out; } -void Order::FromJSONString(const Vehicle * v,std::string jsonSTR) +Order Order::FromJSONString(std::string jsonSTR) { - - /* - this->type = (OrderType)GB(packed, 0, 8); //done - this->flags = GB(packed, 8, 16); // done - this->dest = GB(packed, 24, 16); // done - this->extra = nullptr; //masive pain ?????? - this->next = nullptr; - this->refit_cargo = CARGO_NO_REFIT; - this->occupancy = 0; - this->wait_time = 0; - this->travel_time = 0; - this->max_speed = UINT16_MAX; - */ - //hell nlohmann::json json = nlohmann::json::parse(jsonSTR); - uint64_t order_pack = json.at("packed-data").get(); - uint64_t extra = json.at("packed-data").get(); + if (!json.contains("packed-data") && json["packed_data"].is_number_integer()) { + + Order errOrder; + + errOrder.MakeLabel(OLST_TEXT); + errOrder.SetColour(COLOUR_RED); + errOrder.SetLabelText("JSON_ERR: JSON does not contain mandatory 'packed-data' field for this order"); + + return errOrder; + } - DoCommandPEx(v->tile, v->index, 0, order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); + Order new_order = Order(json.at("packed-data").get()); + if (json.contains("destination-id") && json["destination-id"].is_number_integer()) + json["destination-id"].get_to(new_order.dest); + + + + if (json.contains("extra") && json["extra"].is_object()) { + auto &extraJson = json["extra"]; + + new_order.AllocExtraInfo(); + + if (extraJson.contains("cargo-type-flags") && extraJson["cargo-type-flags"].is_array()) + for (int i = 0; i < 64; i++) + extraJson["cargo-type-flags"][i].get_to(new_order.extra->cargo_type_flags[i]); + + if (extraJson.contains("colour")) + extraJson["colour"].get_to(new_order.extra->colour); + + if (extraJson.contains("dispatch-index")) + extraJson["dispatch-index"].get_to(new_order.extra->dispatch_index); + + if (extraJson.contains("xdata")) + extraJson["xdata"].get_to(new_order.extra->xdata); + + if (extraJson.contains("xdata2")) + extraJson["xdata2"].get_to(new_order.extra->xdata2); + + if (extraJson.contains("xflags")) + extraJson["xflags"].get_to(new_order.extra->xflags); + + } + + if (json.contains("refit-cargo")) + json["refit-cargo"].get_to(new_order.refit_cargo); + + if (json.contains("wait-time")) + json["wait-time"].get_to(new_order.wait_time); + + if (json.contains("travel-time")) + json["travel-time"].get_to(new_order.travel_time); + + if (json.contains("max-speed")) + json["max-speed"].get_to(new_order.max_speed); + + return new_order; } /** @@ -915,33 +956,39 @@ std::string OrderList::ToJSONString() } while ((o = this->GetNext(o)) != this->GetFirstOrder()); } - std::cout << std::setw(4)<< json.dump() << "\n"; return json.dump(); } void OrderList::FromJSONString(const Vehicle * v,std::string json_str) { - nlohmann::json json = nlohmann::json::parse(json_str); - //plan... painful plan - CMD_DELETE_ORDER; //for all existing orders - CMD_INSERT_ORDER; //for each order new + Order errOrder; + + errOrder.MakeLabel(OLST_TEXT); + errOrder.SetColour(COLOUR_RED); + + nlohmann::json json; + try { + json = nlohmann::json::parse(json_str); + } catch(nlohmann::json::parse_error e){ + + ShowErrorMessage(STR_ERROR_JON, STR_ERROR_ORDERLIST_MALFORMED_JSON,WL_ERROR); + return; + } - CMD_SCHEDULED_DISPATCH_ADD_NEW_SCHEDULE; - CMD_SCHEDULED_DISPATCH_ADD; - CMD_SCHEDULED_DISPATCH_RENAME_SCHEDULE; + //delete all orders before setting the new orders + DoCommandP(v->tile, v->index, v->GetNumOrders(), CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER)); if (json.contains("orders")) { auto &ordersJson = json["orders"]; if (ordersJson.is_array()) { for (nlohmann::json::iterator it = ordersJson.begin(); it != ordersJson.end(); ++it) { auto &orderJson = it.value(); - Order::FromJSONString(v,orderJson.dump()); - - + Order new_order = Order::FromJSONString(orderJson.dump()); + OrderID new_orderID = v->GetNumOrders(); + DoCommandPEx(v->tile, v->index, new_orderID, 0, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, orderJson.dump().c_str(), nullptr, 0); } - } } @@ -1179,16 +1226,19 @@ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int * - p2 = (bit 0 - 15) - the selected order (if any). If the last order is given, * the order will be inserted before that one * @param p3 packed order to insert - * @param text unused + * @param orderJson is an optional field for an Order object encoded as JSON * @return the cost of this operation or an error */ -CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, uint64_t p3, const char *text, const CommandAuxiliaryBase *aux_data) +CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, uint64_t p3, const char *orderJson, const CommandAuxiliaryBase *aux_data) { - VehicleID veh = GB(p1, 0, 20); - VehicleOrderID sel_ord = GB(p2, 0, 16); - Order new_order(p3); + Order new_order = (orderJson != nullptr) ? Order::FromJSONString(orderJson) : Order(p3); - return CmdInsertOrderIntl(flags, Vehicle::GetIfValid(veh), sel_ord, new_order, false); + VehicleOrderID sel_ord = GB(p2, 0, 16); + VehicleID veh = GB(p1, 0, 20); + + CommandCost ret = CmdInsertOrderIntl(flags, Vehicle::GetIfValid(veh), sel_ord, new_order, false); + + return ret; } /** diff --git a/src/order_gui.cpp b/src/order_gui.cpp index a0ac9c36bb..220c4ec3fb 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -1548,6 +1548,7 @@ private: }; int selected_order; + VehicleID vehicle_id; VehicleOrderID order_over; ///< Order over which another order is dragged, \c INVALID_VEH_ORDER_ID if none. OrderPlaceObjectState goto_type; Scrollbar *vscroll; @@ -3491,89 +3492,8 @@ public: switch (index) { case 0: this->OrderClick_ReverseOrderList(0); break; case 1: this->OrderClick_ReverseOrderList(1); break; - case 2: this->vehicle->orders->ToJSONString(); break; - case 3: this->vehicle->orders->FromJSONString(this->vehicle, R"({ - "head": { - "scheduled-dispatch": [ - { - "duration": 106560, - "flags": 0, - "max-delay": 0, - "name": "alfredo", - "slots": [ - { - "flags": 0, - "offset": 4514 - }, - { - "flags": 0, - "offset": 90280 - } - ], - "start-tick": 16729920 - } - ] - }, - "orders": [ - { - "destination-id": 2, - "destination-name": "Grateley Halt", - "max-speed": 65535, - "packed-data": 33554513, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 3, - "destination-name": "Grateley Exchange", - "max-speed": 65535, - "packed-data": 50331729, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 4, - "destination-name": "Grateley Annexe", - "max-speed": 65535, - "packed-data": 67108945, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 3, - "destination-name": "Grateley Exchange", - "max-speed": 65535, - "packed-data": 50331729, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 2, - "destination-name": "Grateley Halt", - "max-speed": 65535, - "packed-data": 33554513, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - }, - { - "destination-id": 1, - "destination-name": "Grateley Transfer", - "max-speed": 65535, - "packed-data": 16777297, - "refit-cargo": 254, - "travel-time": 0, - "wait-time": 0 - } - ] -})"); break; - - //case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE); break; - //case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD); break; + case 2: ShowSaveLoadDialog(FT_ORDERLIST, SLO_SAVE, this->GetVehicle()); break; + case 3: ShowSaveLoadDialog(FT_ORDERLIST, SLO_LOAD, this->GetVehicle()); break; default: NOT_REACHED(); } break; diff --git a/src/script/api/script_types.hpp b/src/script/api/script_types.hpp index 86e13b7cb8..f0a5b8f4c6 100644 --- a/src/script/api/script_types.hpp +++ b/src/script/api/script_types.hpp @@ -86,7 +86,7 @@ /* Define all types here, so we don't have to include the whole _type.h maze */ typedef uint BridgeType; ///< Internal name, not of any use for you. -typedef byte CargoID; ///< The ID of a cargo. +typedef uint8_t CargoID; ///< The ID of a cargo. class CommandCost; ///< The cost of a command. typedef uint16_t EngineID; ///< The ID of an engine. typedef uint16_t GoalID; ///< The ID of a goal. From 26fff27e506828d24365c4049d4bb5920b65f048 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 28 Mar 2024 20:50:19 +0100 Subject: [PATCH 10/15] full import working --- src/order_base.h | 4 +++ src/order_cmd.cpp | 47 ++----------------------- src/schdispatch_cmd.cpp | 77 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 51 deletions(-) diff --git a/src/order_base.h b/src/order_base.h index a811d29147..79c5e96e1f 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -886,12 +886,16 @@ public: inline std::string &ScheduleName() { return this->name; } inline const std::string &ScheduleName() const { return this->name; } + + static DispatchSchedule FromJSONString(std::string jsonString); + std::string ToJSONString(); }; /** * Shared order list linking together the linked list of orders and the list * of vehicles sharing this order list. */ + struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { private: friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index f3c7f60516..4d3509e863 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -931,19 +931,7 @@ std::string OrderList::ToJSONString() auto& headJson = json["head"]; for (unsigned int i = 0; auto &SD : SD_data) { - auto &SDJson = headJson["scheduled-dispatch"][i++]; - - for (unsigned int i = 0; auto &SD_slot : SD.GetScheduledDispatch()) { - auto& slotsJson = SDJson["slots"][i++]; - slotsJson["offset"] = SD_slot.offset; - slotsJson["flags"] = SD_slot.flags; - } - - SDJson["name"] = SD.ScheduleName(); - SDJson["start-tick"] = SD.GetScheduledDispatchStartTick().value; - SDJson["duration"] = SD.GetScheduledDispatchDuration(); - SDJson["max-delay"] = SD.GetScheduledDispatchDelay(); - SDJson["flags"] = SD.GetScheduledDispatchFlags(); + headJson["scheduled-dispatch"][i++] = nlohmann::json::parse(SD.ToJSONString()); } @@ -985,52 +973,23 @@ void OrderList::FromJSONString(const Vehicle * v,std::string json_str) if (ordersJson.is_array()) { for (nlohmann::json::iterator it = ordersJson.begin(); it != ordersJson.end(); ++it) { auto &orderJson = it.value(); - Order new_order = Order::FromJSONString(orderJson.dump()); OrderID new_orderID = v->GetNumOrders(); DoCommandPEx(v->tile, v->index, new_orderID, 0, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, orderJson.dump().c_str(), nullptr, 0); } } } - if (json.contains("orders") && json.contains("head")){ + if (json.contains("head")){ auto &headJson = json["head"]; if (headJson.contains("scheduled-dispatch")) { auto &SDJson = headJson["scheduled-dispatch"]; if (SDJson.is_array()) { for (nlohmann::json::iterator it = SDJson.begin(); it != SDJson.end(); ++it) { - if (it.value().contains("slots")) { - - auto &slotsJson = it.value().at("slots");; - DispatchSchedule dispatchSchedule; - - if (slotsJson.is_array()) { - for (nlohmann::json::iterator it = slotsJson.begin(); it != slotsJson.end(); ++it) { - - DispatchSlot newDispatchSlot; - - newDispatchSlot.offset = it.value().at("offset").template get(); - newDispatchSlot.flags = it.value().at("flags").template get(); - - dispatchSchedule.GetScheduledDispatchMutable().push_back(newDispatchSlot); - - } - } - - dispatchSchedule.ScheduleName() = it.value().at("name").template get(); - dispatchSchedule.SetScheduledDispatchStartTick(it.value().at("start-tick").template get()); - dispatchSchedule.SetScheduledDispatchDuration(it.value().at("duration").template get()); - dispatchSchedule.SetScheduledDispatchDelay(it.value().at("max-delay").template get()); - dispatchSchedule.SetScheduledDispatchFlags(it.value().at("flags").template get()); - - } + DoCommandPEx(0, v->index, 0, 0, CMD_SCHEDULED_DISPATCH_ADD_NEW_SCHEDULE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE), nullptr, it.value().dump().c_str() , 0); } } } - } - - - } /** diff --git a/src/schdispatch_cmd.cpp b/src/schdispatch_cmd.cpp index da5a88907e..8dd82c99f1 100644 --- a/src/schdispatch_cmd.cpp +++ b/src/schdispatch_cmd.cpp @@ -20,6 +20,7 @@ #include "settings_type.h" #include "schdispatch.h" #include "vehicle_gui.h" +#include <3rdparty/nlohmann/json.hpp> #include @@ -357,15 +358,15 @@ CommandCost CmdScheduledDispatchClear(TileIndex tile, DoCommandFlag flags, uint3 * @param p1 Vehicle index * @param p2 Duration, in scaled tick * @param p3 Start tick - * @param text unused + * @param text optional JSON string * @return the cost of this operation or an error */ -CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, uint64_t p3, const char *text, const CommandAuxiliaryBase *aux_data) +CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, uint64_t p3, const char *scheduleJson, const CommandAuxiliaryBase *aux_data) { VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == nullptr || !v->IsPrimaryVehicle() || p2 == 0) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -376,10 +377,19 @@ CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag fla if (flags & DC_EXEC) { v->orders->GetScheduledDispatchScheduleSet().emplace_back(); DispatchSchedule &ds = v->orders->GetScheduledDispatchScheduleSet().back(); - ds.SetScheduledDispatchDuration(p2); - ds.SetScheduledDispatchStartTick((StateTicks)p3); - ds.UpdateScheduledDispatch(nullptr); - SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH); + if (scheduleJson == nullptr) { + if (p2 == 0) return CMD_ERROR; + ds.SetScheduledDispatchDuration(p2); + ds.SetScheduledDispatchStartTick((StateTicks)p3); + ds.UpdateScheduledDispatch(nullptr); + SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH); + } else { + + DispatchSchedule new_ds = DispatchSchedule::FromJSONString(scheduleJson); + ds.BorrowSchedule(new_ds); + + } + } return CommandCost(); @@ -801,3 +811,56 @@ void DispatchSchedule::UpdateScheduledDispatch(const Vehicle *v) SetTimetableWindowsDirty(v, STWDF_SCHEDULED_DISPATCH); } } + +DispatchSchedule DispatchSchedule::FromJSONString(std::string jsonString) +{ + nlohmann::json json = nlohmann::json::parse(jsonString); + + DispatchSchedule new_schedule; + + if (json.contains("slots")) { + + auto &slotsJson = json.at("slots"); + + if (slotsJson.is_array()) { + for (nlohmann::json::iterator it = slotsJson.begin(); it != slotsJson.end(); ++it) { + + DispatchSlot newDispatchSlot; + + newDispatchSlot.offset = it.value().at("offset").template get(); + newDispatchSlot.flags = it.value().at("flags").template get(); + + new_schedule.GetScheduledDispatchMutable().push_back(newDispatchSlot); + + } + } + } + + new_schedule.ScheduleName() = json.at("name").get(); + new_schedule.SetScheduledDispatchStartTick(json.at("start-tick").get()); + new_schedule.SetScheduledDispatchDuration(json.at("duration").get()); + new_schedule.SetScheduledDispatchDelay(json.at("max-delay").get()); + new_schedule.SetScheduledDispatchFlags(json.at("flags").get()); + + return new_schedule; +} + +std::string DispatchSchedule::ToJSONString() +{ + + nlohmann::json json; + + for (unsigned int i = 0; auto & SD_slot : this->GetScheduledDispatch()) { + auto &slotsJson = json["slots"][i++]; + slotsJson["offset"] = SD_slot.offset; + slotsJson["flags"] = SD_slot.flags; + } + + json["name"] = this->ScheduleName(); + json["start-tick"] = this->GetScheduledDispatchStartTick().value; + json["duration"] = this->GetScheduledDispatchDuration(); + json["max-delay"] = this->GetScheduledDispatchDelay(); + json["flags"] = this->GetScheduledDispatchFlags(); + + return json.dump(); +} From 4ee6381a1f0c4d219becb89ddc1c01af6714df77 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 28 Mar 2024 21:51:34 +0100 Subject: [PATCH 11/15] FIOS fixes --- src/fileio.cpp | 3 ++- src/fileio_type.h | 3 ++- src/fios.cpp | 22 ++++++++++++++++++---- src/fios.h | 2 +- src/fios_gui.cpp | 11 +++++++++-- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index d9396f8ef1..c4e98eacca 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -43,6 +43,7 @@ static const char * const _subdirs[] = { "save" PATHSEP "autosave" PATHSEP, "scenario" PATHSEP, "scenario" PATHSEP "heightmap" PATHSEP, + "orderlist" PATHSEP, "gm" PATHSEP, "data" PATHSEP, "baseset" PATHSEP, @@ -1094,7 +1095,7 @@ void DeterminePaths(const char *exe, bool only_local_path) DEBUG(misc, 1, "%s found as personal directory", _personal_dir.c_str()); static const Subdirectory default_subdirs[] = { - SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR, SOCIAL_INTEGRATION_DIR + SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, ORDERLIST_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR, SOCIAL_INTEGRATION_DIR }; for (uint i = 0; i < lengthof(default_subdirs); i++) { diff --git a/src/fileio_type.h b/src/fileio_type.h index 26b0ab2948..8c0a1ba475 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -36,7 +36,7 @@ enum DetailedFileType { DFT_HEIGHTMAP_PNG, ///< PNG file. /* Orderlist files */ - DFT_ORDERLIST, ///< XML file. + DFT_ORDERLIST, ///< JSON file. /* fios 'files' */ DFT_FIOS_DRIVE, ///< A drive (letter) entry. @@ -116,6 +116,7 @@ enum Subdirectory { AUTOSAVE_DIR, ///< Subdirectory of save for autosaves SCENARIO_DIR, ///< Base directory for all scenarios HEIGHTMAP_DIR, ///< Subdirectory of scenario for heightmaps + ORDERLIST_DIR, ///< Subdirectort for all orderlists OLD_GM_DIR, ///< Old subdirectory for the music OLD_DATA_DIR, ///< Old subdirectory for the data. BASESET_DIR, ///< Subdirectory for all base data (base sets, intro game) diff --git a/src/fios.cpp b/src/fios.cpp index 2eb2d7244e..ec7c58b142 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -259,9 +259,23 @@ std::string FiosMakeHeightmapName(const char *name) * @param name Filename to delete. * @return Whether the file deletion was successful. */ -bool FiosDelete(const char *name) +bool FiosDelete(const char *name,AbstractFileType ft) { - std::string filename = FiosMakeSavegameName(name); + std::string filename; + + switch (ft) { + case FT_SAVEGAME: + case FT_SCENARIO: + filename = FiosMakeSavegameName(name); + break; + case FT_ORDERLIST: + filename = FiosMakeOrderListName(name); + break; + default: + NOT_REACHED(); + break; + } + return unlink(filename.c_str()) == 0; } @@ -530,7 +544,7 @@ FiosType FiosGetOrderlistListCallback(SaveLoadOperation fop, const std::string & if (ext == nullptr) ext = ""; if (StrEqualsIgnoreCase(ext, ".json")) { - GetFileTitle(file, title, last, SAVE_DIR); + GetFileTitle(file, title, last, ORDERLIST_DIR); return FIOS_TYPE_ORDERLIST; } @@ -548,7 +562,7 @@ void FiosGetOrderlistList(SaveLoadOperation fop, bool show_dirs, FileList &file_ { static std::optional fios_save_path; - if (!fios_save_path) fios_save_path = FioFindDirectory(SAVE_DIR); + if (!fios_save_path) fios_save_path = FioFindDirectory(ORDERLIST_DIR); _fios_path = &(*fios_save_path); diff --git a/src/fios.h b/src/fios.h index 00e91225ec..6a092b7093 100644 --- a/src/fios.h +++ b/src/fios.h @@ -63,7 +63,7 @@ bool FiosBrowseTo(const FiosItem *item); std::string FiosGetCurrentPath(); std::optional FiosGetDiskFreeSpace(const std::string &path); -bool FiosDelete(const char *name); +bool FiosDelete(const char *name, AbstractFileType file_type); std::string FiosMakeHeightmapName(const char *name); std::string FiosMakeSavegameName(const char *name); std::string FiosMakeOrderListName(const char *name); diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index f30f237746..08eeb49e9d 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -281,7 +281,10 @@ static constexpr NWidgetPart _nested_save_orderlist_dialog_widgets[] = { EndContainer(), /* Save button*/ - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), + EndContainer(), EndContainer(), EndContainer(), @@ -497,6 +500,10 @@ public: o_dir.name = FioFindDirectory(HEIGHTMAP_DIR); break; + case FT_ORDERLIST: + o_dir.name = FioFindDirectory(ORDERLIST_DIR); + break; + default: o_dir.name = _personal_dir; } @@ -909,7 +916,7 @@ public: if (this->fop != SLO_SAVE) return; if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked - if (!FiosDelete(this->filename_editbox.text.buf)) { + if (!FiosDelete(this->filename_editbox.text.buf, this->abstract_filetype)) { ShowErrorMessage(STR_ERROR_UNABLE_TO_DELETE_FILE, INVALID_STRING_ID, WL_ERROR); } else { this->InvalidateData(SLIWD_RESCAN_FILES); From 23b1a97bf391327ce954b3afccb4c2209fda8385 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Thu, 28 Mar 2024 22:39:24 +0100 Subject: [PATCH 12/15] fix compiler errors on non-windows systems --- src/fios_gui.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 08eeb49e9d..9454952c80 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -31,6 +31,7 @@ #include "gamelog.h" #include "vehicle_base.h" #include +#include #include #include @@ -754,7 +755,7 @@ public: case WID_SL_LOAD_BUTTON: { if (this->selected == nullptr || _load_check_data.HasErrors()) break; - + _file_to_saveload.Set(*this->selected); if (this->abstract_filetype == FT_HEIGHTMAP) { @@ -762,13 +763,17 @@ public: ShowHeightmapLoad(); }else if (this->abstract_filetype == FT_ORDERLIST) { - std::ifstream t(this->selected->name); - std::stringstream buffer; - buffer << t.rdbuf(); + FILE * file = FioFOpenFile(this->selected->name, "r", NO_DIRECTORY); + + if (file != nullptr) { + std::ifstream t(file); + std::stringstream buffer; + buffer << t.rdbuf(); - veh->orders->FromJSONString(veh, buffer.str()); + veh->orders->FromJSONString(veh, buffer.str()); - this->Close(); + this->Close(); + } } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; From 192a3b4e70aa7068a429349a581df8c6e0a21c0d Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Fri, 29 Mar 2024 16:32:26 +0100 Subject: [PATCH 13/15] Fix: order insertion oversight --- src/order_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 220c4ec3fb..2ad9597b27 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -1632,7 +1632,7 @@ private: bool InsertNewOrder(uint64_t order_pack) { - return DoCommandPEx(this->vehicle->tile, this->vehicle->index, 0, order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); + return DoCommandPEx(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), order_pack, CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER), nullptr, nullptr, 0); } bool ModifyOrder(VehicleOrderID sel_ord, uint32_t p2, bool error_msg = true, const char *text = nullptr) From 0019e84188f4711c6cddec7882d8e5c49b6ea440 Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Sun, 14 Apr 2024 16:32:27 +0200 Subject: [PATCH 14/15] adds version control to orderlist exporting --- src/order_base.h | 2 +- src/order_cmd.cpp | 7 ++++++- src/order_type.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/order_base.h b/src/order_base.h index 79c5e96e1f..cd6b56c078 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -1049,7 +1049,7 @@ public: void DebugCheckSanity() const; #endif bool CheckOrderListIndexing() const; - + inline std::vector &GetScheduledDispatchScheduleSet() { return this->dispatch_schedules; } inline const std::vector &GetScheduledDispatchScheduleSet() const { return this->dispatch_schedules; } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 4d3509e863..5c0067b7df 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -43,6 +43,7 @@ #include "date_func.h" #include "3rdparty/nlohmann/json.hpp" #include "command_aux.h" +#include "rev.h" #include "table/strings.h" @@ -925,9 +926,13 @@ void OrderList::MoveOrder(int from, int to) std::string OrderList::ToJSONString() { + nlohmann::json json; - auto& SD_data = this->GetScheduledDispatchScheduleSet(); + json["version"] = ORDERLIST_JSON_OUTPUT_VERSION; + json["source"] = std::string(_openttd_revision); + + auto& SD_data = this->GetScheduledDispatchScheduleSet(); auto& headJson = json["head"]; for (unsigned int i = 0; auto &SD : SD_data) { diff --git a/src/order_type.h b/src/order_type.h index 8d2d36ebed..ee988a161c 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -313,6 +313,8 @@ enum CloneOptions { CO_UNSHARE = 2 }; +const uint8_t ORDERLIST_JSON_OUTPUT_VERSION = 1; + struct Order; struct OrderList; From 4350521b7cd6a3b5a079fc6f124622568f18e6ea Mon Sep 17 00:00:00 2001 From: lucaFiorini Date: Sun, 14 Apr 2024 16:33:57 +0200 Subject: [PATCH 15/15] adds check on whether orderlist is initialised on export --- src/order_cmd.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 5c0067b7df..cb390eba97 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -932,6 +932,11 @@ std::string OrderList::ToJSONString() json["version"] = ORDERLIST_JSON_OUTPUT_VERSION; json["source"] = std::string(_openttd_revision); + if (this == nullptr) { //order list not intiailised, return an empty result + json["error"] = "Orderlist was not initialised"; + return json.dump(); + }; + auto& SD_data = this->GetScheduledDispatchScheduleSet(); auto& headJson = json["head"]; for (unsigned int i = 0; auto &SD : SD_data) {