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.
This commit is contained in:
Sergey Stepanov 2024-08-21 18:45:53 +03:00 committed by sergystepanov
parent ddb16f899f
commit 7da993a4c7
7 changed files with 40 additions and 2 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -84,3 +84,7 @@ func StatSize(path string) (int64, error) {
}
return fi.Size(), nil
}
func RemoveAll(path string) error {
return os.RemoveAll(path)
}

View file

@ -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")
}

View file

@ -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

View file

@ -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") }