Skip to content

Commit

Permalink
Add caged manager
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Aug 30, 2023
1 parent 0337b11 commit 908a8c3
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 139 deletions.
4 changes: 1 addition & 3 deletions cmd/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/os"
"github.com/giongto35/cloud-game/v3/pkg/worker"
"github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro"
"github.com/giongto35/cloud-game/v3/pkg/worker/thread"
)

Expand All @@ -25,8 +24,7 @@ func run() {
}

done := os.ExpectTermination()
app := libretro.Cage(conf.Emulator, log)
w, err := worker.New(&app, conf, log)
w, err := worker.New(conf, log)
if err != nil {
log.Error().Err(err).Msgf("init fail")
return
Expand Down
59 changes: 59 additions & 0 deletions pkg/worker/caged/caged.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
package caged

import (
"errors"
"reflect"

"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro"
)

type App interface {
AudioSampleRate() int
Init() error
ViewportSize() (int, int)
Start()
Close()
}

type Manager struct {
list map[string]App
log *logger.Logger
}

func NewManager(log *logger.Logger) *Manager {
return &Manager{log: log, list: make(map[string]App)}
}

func (m *Manager) Get(name string) App { return m.list[name] }

func (m *Manager) Load(name string, conf any) error {
if name == "libretro" {
app, err := m.loadLibretro(conf)
if err != nil {
return err
}
m.list[name] = app
}
return nil
}

func (m *Manager) loadLibretro(conf any) (*libretro.Caged, error) {
s := reflect.ValueOf(conf)

e := s.FieldByName("Emulator")
if !e.IsValid() {
return nil, errors.New("no emulator conf")
}
r := s.FieldByName("Recording")
if !r.IsValid() {
return nil, errors.New("no recording conf")
}

c := libretro.CagedConf{
Emulator: e.Interface().(config.Emulator),
Recording: r.Interface().(config.Recording),
}

app := libretro.Cage(c, m.log)
if err := app.Init(); err != nil {
return nil, err
}
return &app, nil
}
74 changes: 56 additions & 18 deletions pkg/worker/caged/libretro/caged.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,77 @@ package libretro

import (
"github.com/giongto35/cloud-game/v3/pkg/config"
"github.com/giongto35/cloud-game/v3/pkg/games"
"github.com/giongto35/cloud-game/v3/pkg/logger"
"github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro/manager"
"github.com/rs/zerolog/log"
"github.com/giongto35/cloud-game/v3/pkg/worker/cloud"
)

type Caged struct {
conf config.Emulator
Emulator
conf CagedConf
log *logger.Logger
w, h int
}

func Cage(conf config.Emulator, log *logger.Logger) Caged { return Caged{conf, log} }
type CagedConf struct {
Emulator config.Emulator
Recording config.Recording
}

func (c *Caged) Name() string { return "libretro" }

func Cage(conf CagedConf, log *logger.Logger) Caged {
return Caged{conf: conf, log: log}
}

func (c *Caged) Init() error {
if err := manager.CheckCores(c.conf, c.log); err != nil {
log.Warn().Err(err).Msgf("a Libretro cores sync fail")
if err := manager.CheckCores(c.conf.Emulator, c.log); err != nil {
c.log.Warn().Err(err).Msgf("a Libretro cores sync fail")
}
return nil
}

func (c *Caged) Start() {
nano, err := NewFrontend(c.conf, c.log)
func (c *Caged) PreLoad(uid string, saveClose bool, storage cloud.Storage, rec bool, recUser string, recGame string) {
nan, err := NewFrontend(c.conf.Emulator, c.log)
if err != nil {
log.Fatal().Err(err).Send()
c.log.Fatal().Err(err).Send()
}
_ = nano
//room.emulator = nano
//room.emulator.SetMainSaveName(id)
//room.emulator.LoadMetadata(game.System)
//err = room.emulator.LoadGame(game.FullPath(conf.Worker.Library.BasePath))
//if err != nil {
// log.Fatal().Err(err).Msgf("couldn't load the game %v", game)
//}
//w, h := room.emulator.ViewportSize()
//room.emulator.SetViewport(w, h, conf.Emulator.Scale)
nan.SaveOnClose = saveClose
nan.SetMainSaveName(uid)

var nano Emulator = nan

if c.conf.Recording.Enabled {
nan.DisableCanvasPool = true
nano = WithRecording(nano, rec, recUser, recGame, c.conf.Recording, c.log)
}

if storage != nil {
wc, err := WithCloud(nano, uid, storage)
if err != nil {
c.log.Error().Err(err).Msgf("couldn't init %v", wc.HashPath())
} else {
c.log.Info().Msgf("cloud state %v has been initialized", wc.HashPath())
nano = wc
}
}

c.Emulator = nano
}

func (c *Caged) Load(game games.GameMetadata, path string) error {
c.Emulator.LoadCore(game.System)
if err := c.Emulator.LoadGame(game.FullPath(path)); err != nil {
return err
}
w, h := c.ViewportCalc()
c.SetViewport(w, h, c.conf.Emulator.Scale)

return nil
}

func (c *Caged) AudioSampleRate() int { return c.Emulator.AudioSampleRate() }
func (c *Caged) ViewportSize() (int, int) { return c.Emulator.ViewportSize() }
func (c *Caged) Start() { go c.Emulator.Start() }
func (c *Caged) Close() { c.Emulator.Close() }
19 changes: 12 additions & 7 deletions pkg/worker/caged/libretro/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,19 @@ type Emulator interface {
SetVideo(func(*GameFrame))
Audio() func(*GameAudio)
Video() func(*GameFrame)
LoadMetadata(name string)
LoadCore(name string)
LoadGame(path string) error
FPS() int
AudioSampleRate() int
Init() error
IsPortrait() bool
// Start is called after LoadGame
Start()
// SetViewport sets viewport size
SetViewport(width int, height int, scale int)
// ViewportSize calculates the viewport size with the aspect ratio and scale
ViewportSize() (nw int, nh int)
// ViewportCalc calculates the viewport size with the aspect ratio and scale
ViewportCalc() (nw int, nh int)
ViewportSize() (w, h int)
RestoreGameState() error
// SetMainSaveName sets distinct name for saves naming
SetMainSaveName(name string)
Expand Down Expand Up @@ -170,7 +172,7 @@ func NewFrontend(conf config.Emulator, log *logger.Logger) (*Frontend, error) {
return f, nil
}

func (f *Frontend) LoadMetadata(emu string) {
func (f *Frontend) LoadCore(emu string) {
conf := f.conf.GetLibretroCoreConfig(emu)
meta := nanoarch.Metadata{
AutoGlContext: conf.AutoGlContext,
Expand Down Expand Up @@ -294,11 +296,13 @@ func (f *Frontend) HashPath() string { return f.storage.GetSavePath
func (f *Frontend) HasSave() bool { return os.Exists(f.HashPath()) }
func (f *Frontend) SRAMPath() string { return f.storage.GetSRAMPath() }
func (f *Frontend) AudioSampleRate() int { return f.nano.AudioSampleRate() }
func (f *Frontend) Init() error { return nil }
func (f *Frontend) Input(player int, data []byte) { f.input.setInput(player, data) }
func (f *Frontend) LoadGame(path string) error { return f.nano.LoadGame(path) }
func (f *Frontend) RestoreGameState() error { return f.Load() }
func (f *Frontend) IsPortrait() bool { return f.nano.IsPortrait() }
func (f *Frontend) SaveGameState() error { return f.Save() }
func (f *Frontend) Scale(factor int) { w, h := f.ViewportSize(); f.SetViewport(w, h, factor) }
func (f *Frontend) SetAudio(ff func(*GameAudio)) { f.onAudio = ff }
func (f *Frontend) SetMainSaveName(name string) { f.storage.SetMainSaveName(name) }
func (f *Frontend) SetViewport(width int, height int, scale int) {
Expand All @@ -316,10 +320,11 @@ func (f *Frontend) SetVideo(ff func(*GameFrame)) { f.onVideo = ff }
func (f *Frontend) SetLibretroLogger(log *logger.Logger) { f.nano.SetLogger(log) }

// Tick runs one emulation frame.
func (f *Frontend) Tick() { f.mu.Lock(); f.nano.Run(); f.mu.Unlock() }
func (f *Frontend) ToggleMultitap() { f.nano.ToggleMultitap() }
func (f *Frontend) Tick() { f.mu.Lock(); f.nano.Run(); f.mu.Unlock() }
func (f *Frontend) ToggleMultitap() { f.nano.ToggleMultitap() }
func (f *Frontend) ViewportSize() (int, int) { return f.vw, f.vh }

func (f *Frontend) ViewportSize() (nw int, nh int) {
func (f *Frontend) ViewportCalc() (nw int, nh int) {
w, h := f.FrameSize()
f.log.Debug().Msgf("Viewport source size: %dx%d", w, h)

Expand Down
10 changes: 5 additions & 5 deletions pkg/worker/caged/libretro/recording.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ type RecordingFrontend struct {
rec *recorder.Recording
}

func WithRecording(fe Emulator, rec bool, user string, game string, conf config.WorkerConfig, log *logger.Logger) *RecordingFrontend {
func WithRecording(fe Emulator, rec bool, user string, game string, conf config.Recording, log *logger.Logger) *RecordingFrontend {
rr := &RecordingFrontend{Emulator: fe, rec: recorder.NewRecording(
recorder.Meta{UserName: user},
log,
recorder.Options{
Dir: conf.Recording.Folder,
Dir: conf.Folder,
Game: game,
ImageCompressionLevel: conf.Recording.CompressLevel,
Name: conf.Recording.Name,
Zip: conf.Recording.Zip,
ImageCompressionLevel: conf.CompressLevel,
Name: conf.Name,
Zip: conf.Zip,
Vsync: true,
})}
rr.ToggleRecording(rec, user)
Expand Down
49 changes: 19 additions & 30 deletions pkg/worker/coordinatorhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func buildConnQuery(id com.Uid, conf config.Worker, address string) (string, err
})
}

func emulator(wtf any) *libretro.Caged { return wtf.(*libretro.Caged) }
func recorder(wtf any) *libretro.RecordingFrontend { return wtf.(*libretro.RecordingFrontend) }

func (c *coordinator) HandleWebrtcInit(rq api.WebrtcInitRequest[com.Uid], w *Worker, connApi *webrtc.ApiFactory) api.Out {
peer := webrtc.New(c.log, connApi)
localSDP, err := peer.NewCall(w.conf.Encoder.Video.Codec, "opus", func(data any) {
Expand Down Expand Up @@ -85,40 +88,25 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke
uid = games.GenerateRoomID(rq.Game.Name)
}

fe, err := libretro.NewFrontend(w.conf.Emulator, w.log)
if err != nil {
c.log.Error().Err(err).Msgf("couldn't init the app [%v]", rq.Id)
// start the emulator
caged := emulator(w.mana.Get("libretro"))
caged.PreLoad(uid, true, w.storage, rq.Record, rq.RecordUser, rq.Game.Name)
game := games.GameMetadata(rq.Game)
if err := caged.Load(game, w.conf.Worker.Library.BasePath); err != nil {
c.log.Error().Err(err).Msgf("couldn't load the game %v", game)
// !to destroy caged
return api.EmptyPacket
}
fe.SaveOnClose = true

if w.conf.Recording.Enabled {
fe.DisableCanvasPool = true
}

var nano libretro.Emulator = fe

if w.conf.Recording.Enabled {
nano = libretro.WithRecording(nano, rq.Record, rq.RecordUser, rq.Game.Name, w.conf, w.log)
}

if w.storage != nil {
wc, err := libretro.WithCloud(nano, uid, w.storage)
if err != nil {
w.log.Error().Err(err).Msgf("couldn't init %v", wc.HashPath())
} else {
w.log.Info().Msgf("cloud state %v has been initialized", wc.HashPath())
nano = wc
}
}

r := NewRoom(uid, games.GameMetadata(rq.Game), nano, w.conf, w.log)
// make the room
r := NewRoom(uid, caged, w.conf, w.log.Extend(w.log.With().Str("room", uid[:5])))
r.HandleClose = func(room *Room) {
w.router.SetRoom(nil)
c.CloseRoom(room.id)
w.log.Debug().Msgf("Closed room %v", room.id)
}
room = r
c.log.Info().Str("room", room.Id()).Str("game", game.Name).Msg("New room")

user.SetIndex(rq.PlayerIndex)
w.router.SetRoom(room)
Expand All @@ -132,7 +120,8 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest[com.Uid], w *Worke
}

if room.OnUserConnect(user) {
room.OnUserInput(user)
c.log.Debug().Msg("Start session input poll")
user.Peer().OnMessage = func(data []byte) { emulator(room.App()).Input(user.Index(), data) }
}

c.RegisterRoom(room.Id())
Expand Down Expand Up @@ -160,7 +149,7 @@ func (c *coordinator) HandleSaveGame(rq api.SaveGameRequest[com.Uid], w *Worker)
if room == nil {
return api.ErrPacket
}
if err := room.App().SaveGameState(); err != nil {
if err := emulator(room.App()).SaveGameState(); err != nil {
c.log.Error().Err(err).Msg("cannot save game state")
return api.ErrPacket
}
Expand All @@ -172,7 +161,7 @@ func (c *coordinator) HandleLoadGame(rq api.LoadGameRequest[com.Uid], w *Worker)
if room == nil {
return api.ErrPacket
}
if err := room.App().RestoreGameState(); err != nil {
if err := emulator(room.App()).RestoreGameState(); err != nil {
c.log.Error().Err(err).Msg("cannot load game state")
return api.ErrPacket
}
Expand All @@ -194,7 +183,7 @@ func (c *coordinator) HandleToggleMultitap(rq api.ToggleMultitapRequest[com.Uid]
if room == nil {
return api.ErrPacket
}
room.App().ToggleMultitap()
emulator(room.App()).ToggleMultitap()
return api.OkPacket
}

Expand All @@ -206,7 +195,7 @@ func (c *coordinator) HandleRecordGame(rq api.RecordGameRequest[com.Uid], w *Wor
if room == nil {
return api.ErrPacket
}
room.App().(*libretro.RecordingFrontend).ToggleRecording(rq.Active, rq.User)
recorder(room.App()).ToggleRecording(rq.Active, rq.User)
return api.OkPacket
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/worker/recorder/recorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestName(t *testing.T) {
Game: fmt.Sprintf("test_game_%v", rand.Int()),
ImageCompressionLevel: 0,
Name: "test",
Zip: true,
Zip: false,
})
recorder.Set(true, "test_user")

Expand Down
Loading

0 comments on commit 908a8c3

Please sign in to comment.