From 3a7dbbfaaaab71dff08040970d5c2f6f56c3fb34 Mon Sep 17 00:00:00 2001 From: mz Date: Sat, 19 Sep 2026 10:27:45 +0200 Subject: [PATCH 1/2] -saves cmd for saves directory specification added --- common/commandline.cpp | 25 +++++++++++++++++++++++++ common/commandline.h | 2 ++ common/mainwindow.cpp | 3 +++ common/ui/gamemenu.cpp | 35 ++++++++++++++++++++++++----------- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/common/commandline.cpp b/common/commandline.cpp index d3acfabe0..6a94d28e5 100644 --- a/common/commandline.cpp +++ b/common/commandline.cpp @@ -64,6 +64,17 @@ CommandLine::CommandLine(int argc, const char** argv) { if(i &name, Tempest::Dir::FileType type) const; + std::u16string savesPath; bool isDevMode() const { return devmode; } bool isValidationMode() const { return isDebug; } @@ -48,6 +49,7 @@ class CommandLine { bool doForceG2NR() const { return forceG2NR; } bool aaPreset() const { return aaPresetId; } std::string_view defaultSave() const { return saveDef; } + std::u16string saveFilePath(std::string_view fname) const; std::string wrldDef; diff --git a/common/mainwindow.cpp b/common/mainwindow.cpp index 59664c6b7..37f7d9f9a 100644 --- a/common/mainwindow.cpp +++ b/common/mainwindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "ui/dialogmenu.h" #include "ui/menuroot.h" @@ -23,6 +24,7 @@ #include "utils/gthfont.h" #include "utils/dbgpainter.h" + #include "commandline.h" #include "gothic.h" @@ -1058,6 +1060,7 @@ void MainWindow::loadGame(std::string_view slot) { Gothic::inst().setBenchmarkMode(Benchmark::None); Gothic::inst().startLoad("LOADING.TGA",[slot=std::string(slot)](std::unique_ptr&& game){ game = nullptr; // clear world-memory now + Tempest::RFile file(slot); Serialize s(file); std::unique_ptr w(new GameSession(s)); diff --git a/common/ui/gamemenu.cpp b/common/ui/gamemenu.cpp index 61798b47b..e688ee8a6 100644 --- a/common/ui/gamemenu.cpp +++ b/common/ui/gamemenu.cpp @@ -20,6 +20,7 @@ #include "gothic.h" #include "resources.h" #include "build.h" +#include "commandline.h" using namespace Tempest; @@ -919,8 +920,11 @@ void GameMenu::execSaveGame(const GameMenu::Item& item) { return; string_frm fname("save_slot_",int(id),".sav"); - Gothic::inst().save(fname,item.handle->text[0]); - } + const std::u16string path16 = CommandLine::inst().saveFilePath(fname.c_str()); + + std::string path8 = Tempest::TextCodec::toUtf8(path16); + Gothic::inst().save(path8, item.handle->text[0]); +} bool GameMenu::execLoadGame(const GameMenu::Item &item) { const size_t id = saveSlotId(item); @@ -928,11 +932,14 @@ bool GameMenu::execLoadGame(const GameMenu::Item &item) { return false; string_frm fname("save_slot_",int(id),".sav"); - if(!FileUtil::exists(TextCodec::toUtf16(fname.c_str()))) + const std::u16string path16 = CommandLine::inst().saveFilePath(fname.c_str()); + + if(!FileUtil::exists(path16)) return false; - Gothic::inst().load(fname); + + Gothic::inst().load(Tempest::TextCodec::toUtf8(path16)); return true; - } +} void GameMenu::execCommands(std::string str, bool isClick, KeyCodec::Action hint) { if(str.find("EFFECTS ")==0) { @@ -993,15 +1000,19 @@ void GameMenu::updateSavTitle(GameMenu::Item& sel) { char fname[64]={}; std::snprintf(fname,sizeof(fname)-1,"save_slot_%d.sav",int(id)); - if(!FileUtil::exists(TextCodec::toUtf16(fname))) { + const std::u16string path16 = CommandLine::inst().saveFilePath(fname); + + if(!FileUtil::exists(path16)) { sel.handle->text[0] = "---"; return; } SaveGameHeader hdr; try { - RFile fin(fname); - Serialize reader(fin); + std::string path8 = Tempest::TextCodec::toUtf8(path16); + RFile fin(path8); + Serialize reader(fin); + reader.setEntry("header"); reader.read(hdr); if(id!=0 || sel.handle->text[0].empty()) @@ -1025,7 +1036,7 @@ void GameMenu::updateSavTitle(GameMenu::Item& sel) { catch(std::runtime_error&) { return; } - } +} void GameMenu::updateSavThumb(GameMenu::Item &sel) { if(sel.handle->on_sel_action_s[0]!="SAVEGAME_LOAD" && @@ -1058,7 +1069,9 @@ bool GameMenu::implUpdateSavThumb(GameMenu::Item& sel) { char fname[64]={}; std::snprintf(fname,sizeof(fname)-1,"save_slot_%d.sav",int(id)); - if(!FileUtil::exists(TextCodec::toUtf16(fname))) + const std::u16string path16 = CommandLine::inst().saveFilePath(fname); + + if(!FileUtil::exists(path16)) return false; const SaveGameHeader& hdr = sel.savHdr; @@ -1079,7 +1092,7 @@ bool GameMenu::implUpdateSavThumb(GameMenu::Item& sel) { std::snprintf(form,sizeof(form),"%dh %dmin",int(mins/60),int(mins%60)); set("MENUITEM_LOADSAVE_PLAYTIME_VALUE", form); return true; - } +} size_t GameMenu::saveSlotId(const GameMenu::Item &sel) { const char* prefix[2] = {"MENUITEM_LOAD_SLOT", "MENUITEM_SAVE_SLOT"}; From 436651ffa5533bce994850a7392bc6f9240c1df3 Mon Sep 17 00:00:00 2001 From: mz Date: Sun, 20 Sep 2026 08:47:49 +0200 Subject: [PATCH 2/2] creating saves dir if this is not existing --- common/commandline.cpp | 4 ++++ common/utils/fileutil.cpp | 36 ++++++++++++++++++++++++++++++++++++ common/utils/fileutil.h | 2 ++ 3 files changed, 42 insertions(+) diff --git a/common/commandline.cpp b/common/commandline.cpp index 6a94d28e5..571674723 100644 --- a/common/commandline.cpp +++ b/common/commandline.cpp @@ -71,8 +71,12 @@ CommandLine::CommandLine(int argc, const char** argv) { for(auto& c : savesPath) if(c == u'\\') c = u'/'; + if(!savesPath.empty() && savesPath.back() != u'/') savesPath.push_back(u'/'); + + if(!FileUtil::mkpath(savesPath)) + Log::e("unable to create save directory: \"", TextCodec::toUtf8(savesPath), "\""); } } else if(arg=="-devmode") { diff --git a/common/utils/fileutil.cpp b/common/utils/fileutil.cpp index d309cfa41..eafec856c 100644 --- a/common/utils/fileutil.cpp +++ b/common/utils/fileutil.cpp @@ -8,6 +8,7 @@ #include #else #include +#include #endif using namespace Tempest; @@ -22,6 +23,41 @@ bool FileUtil::exists(const std::u16string &path) { #endif } +static bool mkdirOne(const std::u16string& path) { +#ifdef __WINDOWS__ + if(CreateDirectoryW(reinterpret_cast(path.c_str()), nullptr)) + return true; + return GetLastError()==ERROR_ALREADY_EXISTS; +#else + std::string p = Tempest::TextCodec::toUtf8(path); + if(::mkdir(p.c_str(), 0755)==0) + return true; + return errno==EEXIST; +#endif + } + +bool FileUtil::mkpath(const std::u16string& path) { + std::u16string cur; + for(size_t i=0; i &name, Tempest::Dir::FileType type); }