From f49b24bf5fe91aaa7d01cf4f8cf02dc4b681b00e Mon Sep 17 00:00:00 2001 From: Sergey Stepanov Date: Wed, 21 Aug 2024 18:45:53 +0300 Subject: [PATCH] Add the `uniqueSaveDir` option This option allows for the safe use of distinct filesystem snapshots of games with some cores (e.g., DosBox). Keep in mind that with this option enabled, game changes won't be saved (the unique save folder will be deleted on exit) until you explicitly call the save (or share) function. Thus, you will need files like dosbox.conf along with the games to use some default behaviors with each new game session. --- .github/workflows/cd/cloudretro.io/config.yaml | 4 ++-- pkg/config/config.yaml | 2 ++ pkg/config/emulator.go | 1 + pkg/os/os.go | 4 ++++ pkg/worker/caged/libretro/frontend.go | 13 +++++++++++++ pkg/worker/caged/libretro/nanoarch/nanoarch.go | 16 ++++++++++++++++ pkg/worker/caged/libretro/storage.go | 2 ++ 7 files changed, 40 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd/cloudretro.io/config.yaml b/.github/workflows/cd/cloudretro.io/config.yaml index 180a570eb..ac29d6361 100644 --- a/.github/workflows/cd/cloudretro.io/config.yaml +++ b/.github/workflows/cd/cloudretro.io/config.yaml @@ -29,12 +29,12 @@ emulator: logLevel: 1 cores: list: + dos: + uniqueSaveDir: true mame: options: "fbneo-diagnostic-input": "Hold Start" nes: scale: 2 - pcsx: - altRepo: true snes: scale: 2 diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index 2bab6fc25..62d7f8cd3 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -209,6 +209,8 @@ emulator: # - skip_hw_context_destroy -- don't destroy OpenGL context during Libretro core deinit. # May help with crashes, for example, with PPSSPP. # - skip_same_thread_save -- skip thread lock save (used with PPSSPP). + # - uniqueSaveDir (bool) -- needed only for cores (like DosBox) that persist their state into one shared file. + # This will allow for concurrent reading and saving of current states. list: gba: lib: mgba_libretro diff --git a/pkg/config/emulator.go b/pkg/config/emulator.go index 2a25f7409..4db9b825e 100644 --- a/pkg/config/emulator.go +++ b/pkg/config/emulator.go @@ -55,6 +55,7 @@ type LibretroCoreConfig struct { Options4rom map[string]map[string]string // <(^_^)> Roms []string Scale float64 + UniqueSaveDir bool UsesLibCo bool VFR bool Width int diff --git a/pkg/os/os.go b/pkg/os/os.go index 142ffcc1c..c3ab27181 100644 --- a/pkg/os/os.go +++ b/pkg/os/os.go @@ -84,3 +84,7 @@ func StatSize(path string) (int64, error) { } return fi.Size(), nil } + +func RemoveAll(path string) error { + return os.RemoveAll(path) +} diff --git a/pkg/worker/caged/libretro/frontend.go b/pkg/worker/caged/libretro/frontend.go index a8465488c..60792d70e 100644 --- a/pkg/worker/caged/libretro/frontend.go +++ b/pkg/worker/caged/libretro/frontend.go @@ -66,6 +66,7 @@ type Frontend struct { DisableCanvasPool bool SaveOnClose bool + UniqueSaveDir bool } type Device byte @@ -153,6 +154,11 @@ func (f *Frontend) LoadCore(emu string) { KbMouseSupport: conf.KbMouseSupport, } f.mu.Lock() + if conf.UniqueSaveDir { + f.UniqueSaveDir = true + f.nano.SetSaveDirSuffix(f.storage.MainPath()) + f.log.Debug().Msgf("Using unique dir for saves: %v", f.storage.MainPath()) + } scale := 1.0 if conf.Scale > 1 { scale = conf.Scale @@ -336,6 +342,13 @@ func (f *Frontend) Close() { f.mui.Lock() f.nano.Close() + + if f.UniqueSaveDir && !f.HasSave() { + if err := f.nano.DeleteSaveDir(); err != nil { + f.log.Error().Msgf("couldn't delete save dir: %v", err) + } + } + f.mui.Unlock() f.log.Debug().Msgf("frontend closed") } diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.go b/pkg/worker/caged/libretro/nanoarch/nanoarch.go index f334c64eb..16eec60f9 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.go +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.go @@ -157,6 +157,22 @@ func (n *Nanoarch) WaitReady() { <-n.reserved } func (n *Nanoarch) Close() { n.Stopped.Store(true); n.reserved <- struct{}{} } func (n *Nanoarch) SetLogger(log *logger.Logger) { n.log = log } func (n *Nanoarch) SetVideoDebounce(t time.Duration) { n.limiter = NewLimit(t) } +func (n *Nanoarch) SetSaveDirSuffix(sx string) { + if n.cSaveDirectory != nil { + C.free(unsafe.Pointer(n.cSaveDirectory)) + } + dir := C.GoString(n.cSaveDirectory) + "/" + sx + _ = os.CheckCreateDir(dir) + n.cSaveDirectory = C.CString(dir) +} +func (n *Nanoarch) DeleteSaveDir() error { + if n.cSaveDirectory == nil { + return nil + } + + dir := C.GoString(n.cSaveDirectory) + return os.RemoveAll(dir) +} func (n *Nanoarch) CoreLoad(meta Metadata) { var err error diff --git a/pkg/worker/caged/libretro/storage.go b/pkg/worker/caged/libretro/storage.go index fc1a5a76c..fc58faaf6 100644 --- a/pkg/worker/caged/libretro/storage.go +++ b/pkg/worker/caged/libretro/storage.go @@ -10,6 +10,7 @@ import ( type ( Storage interface { + MainPath() string GetSavePath() string GetSRAMPath() string SetMainSaveName(name string) @@ -32,6 +33,7 @@ type ( } ) +func (s *StateStorage) MainPath() string { return s.MainSave } func (s *StateStorage) SetMainSaveName(name string) { s.MainSave = name } func (s *StateStorage) SetNonBlocking(v bool) { s.NonBlock = v } func (s *StateStorage) GetSavePath() string { return filepath.Join(s.Path, s.MainSave+".dat") }