mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 02:34:42 +00:00
Add new saveStateFs config param
Used when you need a copy of FS for new game sessions (i.e. DOSBox uniqueSaveDir=true).
This commit is contained in:
parent
71f5de3bf9
commit
1831e44eef
6 changed files with 91 additions and 17 deletions
|
|
@ -28,6 +28,8 @@ library:
|
|||
ignored:
|
||||
- neogeo
|
||||
- pgm
|
||||
# DOSBox filesystem state
|
||||
- .pure
|
||||
# an explicit list of supported file extensions
|
||||
# which overrides Libretro emulator ROMs configs
|
||||
supported:
|
||||
|
|
@ -216,6 +218,8 @@ emulator:
|
|||
# - 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.
|
||||
# - saveStateFs (string) -- the name of the file that will be initially copied into the save folder.
|
||||
# All * symbols will be replaced to the name of the ROM.
|
||||
list:
|
||||
gba:
|
||||
lib: mgba_libretro
|
||||
|
|
@ -281,6 +285,7 @@ emulator:
|
|||
folder: dos
|
||||
kbMouseSupport: true
|
||||
nonBlockingSave: true
|
||||
saveStateFs: "*.pure.zip"
|
||||
hid:
|
||||
0: [ 257, 513 ]
|
||||
1: [ 257, 513 ]
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ type LibretroCoreConfig struct {
|
|||
Options map[string]string
|
||||
Options4rom map[string]map[string]string // <(^_^)>
|
||||
Roms []string
|
||||
SaveStateFs string
|
||||
Scale float64
|
||||
UniqueSaveDir bool
|
||||
UsesLibCo bool
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ type libConf struct {
|
|||
aliasFile string
|
||||
path string
|
||||
supported map[string]struct{}
|
||||
ignored map[string]struct{}
|
||||
ignored []string
|
||||
verbose bool
|
||||
watchMode bool
|
||||
sessionPath string
|
||||
|
|
@ -98,7 +98,7 @@ func NewLib(conf config.Library, emu WithEmulatorInfo, log *logger.Logger) GameL
|
|||
aliasFile: conf.AliasFile,
|
||||
path: dir,
|
||||
supported: toMap(conf.Supported),
|
||||
ignored: toMap(conf.Ignored),
|
||||
ignored: conf.Ignored,
|
||||
verbose: conf.Verbose,
|
||||
watchMode: conf.WatchMode,
|
||||
sessionPath: emu.SessionStoragePath(),
|
||||
|
|
@ -207,22 +207,36 @@ func (lib *library) Scan() {
|
|||
return err
|
||||
}
|
||||
|
||||
if info != nil && !info.IsDir() && lib.isExtAllowed(path) {
|
||||
meta := getMetadata(path, dir)
|
||||
if info == nil || info.IsDir() || !lib.isExtAllowed(path) {
|
||||
return nil
|
||||
}
|
||||
|
||||
meta.System = lib.emuConf.GetEmulator(meta.Type, meta.Path)
|
||||
meta := metadata(path, dir)
|
||||
meta.System = lib.emuConf.GetEmulator(meta.Type, meta.Path)
|
||||
|
||||
if aliases != nil {
|
||||
k, ok := aliases[meta.Name]
|
||||
if ok {
|
||||
meta.Alias = k
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := lib.config.ignored[meta.Name]; !ok {
|
||||
games = append(games, meta)
|
||||
if aliases != nil {
|
||||
if k, ok := aliases[meta.Name]; ok {
|
||||
meta.Alias = k
|
||||
}
|
||||
}
|
||||
|
||||
ignored := false
|
||||
for _, k := range lib.config.ignored {
|
||||
if meta.Name == k {
|
||||
ignored = true
|
||||
break
|
||||
}
|
||||
|
||||
if len(k) > 0 && k[0] == '.' && strings.Contains(meta.Name, k) {
|
||||
ignored = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !ignored {
|
||||
games = append(games, meta)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
@ -322,8 +336,8 @@ func (lib *library) isExtAllowed(path string) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
// getMetadata returns game info from a path
|
||||
func getMetadata(path string, basePath string) GameMetadata {
|
||||
// metadata returns game info from a path
|
||||
func metadata(path string, basePath string) GameMetadata {
|
||||
name := filepath.Base(path)
|
||||
ext := filepath.Ext(name)
|
||||
relPath, _ := filepath.Rel(basePath, path)
|
||||
|
|
|
|||
12
pkg/os/os.go
12
pkg/os/os.go
|
|
@ -51,6 +51,18 @@ func GetUserHome() (string, error) {
|
|||
return me.HomeDir, nil
|
||||
}
|
||||
|
||||
func CopyFile(from string, to string) error {
|
||||
bytesRead, err := os.ReadFile(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(to, bytesRead, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteFile(name string, data []byte, perm os.FileMode) error {
|
||||
return os.WriteFile(name, data, perm)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
|
@ -67,6 +68,7 @@ type Frontend struct {
|
|||
DisableCanvasPool bool
|
||||
SaveOnClose bool
|
||||
UniqueSaveDir bool
|
||||
SaveStateFs string
|
||||
}
|
||||
|
||||
type Device byte
|
||||
|
|
@ -154,6 +156,7 @@ func (f *Frontend) LoadCore(emu string) {
|
|||
KbMouseSupport: conf.KbMouseSupport,
|
||||
}
|
||||
f.mu.Lock()
|
||||
f.SaveStateFs = conf.SaveStateFs
|
||||
if conf.UniqueSaveDir {
|
||||
f.UniqueSaveDir = true
|
||||
f.nano.SetSaveDirSuffix(f.storage.MainPath())
|
||||
|
|
@ -287,6 +290,13 @@ func (f *Frontend) Start() {
|
|||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) LoadGame(path string) error {
|
||||
if f.UniqueSaveDir {
|
||||
f.copyFsMaybe(path)
|
||||
}
|
||||
return f.nano.LoadGame(path)
|
||||
}
|
||||
|
||||
func (f *Frontend) AspectRatio() float32 { return f.nano.AspectRatio() }
|
||||
func (f *Frontend) AudioSampleRate() int { return f.nano.AudioSampleRate() }
|
||||
func (f *Frontend) FPS() int { return f.nano.VideoFramerate() }
|
||||
|
|
@ -296,7 +306,6 @@ func (f *Frontend) HasSave() bool { return os.Exists(f.HashPath(
|
|||
func (f *Frontend) HashPath() string { return f.storage.GetSavePath() }
|
||||
func (f *Frontend) IsPortrait() bool { return f.nano.IsPortrait() }
|
||||
func (f *Frontend) KbMouseSupport() bool { return f.nano.KbMouseSupport() }
|
||||
func (f *Frontend) LoadGame(path string) error { return f.nano.LoadGame(path) }
|
||||
func (f *Frontend) PixFormat() uint32 { return f.nano.Video.PixFmt.C }
|
||||
func (f *Frontend) RestoreGameState() error { return f.Load() }
|
||||
func (f *Frontend) Rotation() uint { return f.nano.Rot }
|
||||
|
|
@ -349,6 +358,9 @@ func (f *Frontend) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
f.UniqueSaveDir = false
|
||||
f.SaveStateFs = ""
|
||||
|
||||
f.mui.Unlock()
|
||||
f.log.Debug().Msgf("frontend closed")
|
||||
}
|
||||
|
|
@ -420,3 +432,32 @@ func (f *Frontend) autosave(periodSec int) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) copyFsMaybe(path string) {
|
||||
if f.SaveStateFs == "" {
|
||||
return
|
||||
}
|
||||
|
||||
fileName := f.SaveStateFs
|
||||
hasPlaceholder := strings.HasPrefix(f.SaveStateFs, "*")
|
||||
if hasPlaceholder {
|
||||
game := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
|
||||
fileName = strings.Replace(f.SaveStateFs, "*", game, 1)
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(f.nano.SaveDir(), fileName)
|
||||
|
||||
if os.Exists(fullPath) {
|
||||
return
|
||||
}
|
||||
|
||||
storePath := filepath.Dir(path)
|
||||
fsPath := filepath.Join(storePath, fileName)
|
||||
if os.Exists(fsPath) {
|
||||
if err := os.CopyFile(fsPath, fullPath); err != nil {
|
||||
f.log.Error().Err(err).Msgf("fs copy fail")
|
||||
} else {
|
||||
f.log.Debug().Msgf("copied fs %v to %v", fsPath, fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ 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) SaveDir() string { return C.GoString(n.cSaveDirectory) }
|
||||
func (n *Nanoarch) SetSaveDirSuffix(sx string) {
|
||||
dir := C.GoString(n.cSaveDirectory) + "/" + sx
|
||||
err := os.CheckCreateDir(dir)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue