From 954bb23bb8d1f743281a8589d7b01307694a2aa7 Mon Sep 17 00:00:00 2001 From: Sergey Stepanov Date: Tue, 3 Dec 2024 00:38:15 +0300 Subject: [PATCH] Add Reset with 0 key --- pkg/api/api.go | 3 +++ pkg/api/worker.go | 6 +++++- pkg/coordinator/user.go | 6 ++++++ pkg/coordinator/userhandlers.go | 7 +++++++ pkg/coordinator/workerapi.go | 4 ++++ pkg/worker/caged/libretro/frontend.go | 2 ++ pkg/worker/caged/libretro/nanoarch/nanoarch.c | 4 ++++ pkg/worker/caged/libretro/nanoarch/nanoarch.go | 6 ++++++ pkg/worker/caged/libretro/nanoarch/nanoarch.h | 1 + pkg/worker/coordinator.go | 6 ++++++ pkg/worker/coordinatorhandlers.go | 8 ++++++++ web/js/api.js | 2 ++ web/js/app.js | 3 +++ web/js/input/keyboard.js | 3 ++- web/js/input/keys.js | 1 + 15 files changed, 60 insertions(+), 2 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 3c33e1e72..2deeb44a9 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -81,6 +81,7 @@ const ( RecordGame PT = 110 GetWorkerList PT = 111 ErrNoFreeSlots PT = 112 + ResetGame PT = 113 RegisterRoom PT = 201 CloseRoom PT = 202 IceCandidate = WebrtcIce @@ -120,6 +121,8 @@ func (p PT) String() string { return "GetWorkerList" case ErrNoFreeSlots: return "NoFreeSlots" + case ResetGame: + return "ResetGame" case RegisterRoom: return "RegisterRoom" case CloseRoom: diff --git a/pkg/api/worker.go b/pkg/api/worker.go index 5031afab6..189daf66b 100644 --- a/pkg/api/worker.go +++ b/pkg/api/worker.go @@ -12,7 +12,11 @@ type ( LoadGameRequest[T Id] struct { StatefulRoom[T] } - LoadGameResponse string + LoadGameResponse string + ResetGameRequest[T Id] struct { + StatefulRoom[T] + } + ResetGameResponse string SaveGameRequest[T Id] struct { StatefulRoom[T] } diff --git a/pkg/coordinator/user.go b/pkg/coordinator/user.go index 471561716..a6865d75f 100644 --- a/pkg/coordinator/user.go +++ b/pkg/coordinator/user.go @@ -83,6 +83,12 @@ func (u *User) HandleRequests(info HasServerInfo, conf config.CoordinatorConfig) return api.ErrMalformed } u.HandleChangePlayer(*rq) + case api.ResetGame: + rq := api.Unwrap[api.ResetGameRequest[com.Uid]](payload) + if rq == nil { + return api.ErrMalformed + } + u.HandleResetGame(*rq) case api.RecordGame: if !conf.Recording.Enabled { return api.ErrForbidden diff --git a/pkg/coordinator/userhandlers.go b/pkg/coordinator/userhandlers.go index 61c3f494e..811ce3329 100644 --- a/pkg/coordinator/userhandlers.go +++ b/pkg/coordinator/userhandlers.go @@ -50,6 +50,13 @@ func (u *User) HandleQuitGame(rq api.GameQuitRequest[com.Uid]) { } } +func (u *User) HandleResetGame(rq api.ResetGameRequest[com.Uid]) { + if rq.Room.Rid != u.w.RoomId { + return + } + u.w.ResetGame(u.Id()) +} + func (u *User) HandleSaveGame() error { resp, err := u.w.SaveGame(u.Id()) if err != nil { diff --git a/pkg/coordinator/workerapi.go b/pkg/coordinator/workerapi.go index 05ead1d98..7a1ccf51d 100644 --- a/pkg/coordinator/workerapi.go +++ b/pkg/coordinator/workerapi.go @@ -48,6 +48,10 @@ func (w *Worker) ChangePlayer(id com.Uid, index int) (*api.ChangePlayerResponse, w.Send(api.ChangePlayer, api.ChangePlayerRequest[com.Uid]{StatefulRoom: StateRoom(id, w.RoomId), Index: index})) } +func (w *Worker) ResetGame(id com.Uid) { + w.Notify(api.ResetGame, api.ResetGameRequest[com.Uid]{StatefulRoom: StateRoom(id, w.RoomId)}) +} + func (w *Worker) RecordGame(id com.Uid, rec bool, recUser string) (*api.RecordGameResponse, error) { return api.UnwrapChecked[api.RecordGameResponse]( w.Send(api.RecordGame, api.RecordGameRequest[com.Uid]{StatefulRoom: StateRoom(id, w.RoomId), Active: rec, User: recUser})) diff --git a/pkg/worker/caged/libretro/frontend.go b/pkg/worker/caged/libretro/frontend.go index 057d7e217..341038a47 100644 --- a/pkg/worker/caged/libretro/frontend.go +++ b/pkg/worker/caged/libretro/frontend.go @@ -47,6 +47,7 @@ type Emulator interface { Input(player int, device byte, data []byte) // Scale returns set video scale factor Scale() float64 + Reset() } type Frontend struct { @@ -307,6 +308,7 @@ 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) PixFormat() uint32 { return f.nano.Video.PixFmt.C } +func (f *Frontend) Reset() { f.mu.Lock(); defer f.mu.Unlock(); f.nano.Reset() } func (f *Frontend) RestoreGameState() error { return f.Load() } func (f *Frontend) Rotation() uint { return f.nano.Rot } func (f *Frontend) SRAMPath() string { return f.storage.GetSRAMPath() } diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.c b/pkg/worker/caged/libretro/nanoarch/nanoarch.c index 4c46963bc..2bbd18836 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.c +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.c @@ -90,6 +90,10 @@ void bridge_retro_unload_game(void *f) { ((void (*)(void)) f)(); } +void bridge_retro_reset(void *f) { + ((void (*)(void)) f)(); +} + void bridge_retro_run(void *f) { ((void (*)(void)) f)(); } diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.go b/pkg/worker/caged/libretro/nanoarch/nanoarch.go index 4db0dcea9..9d8447a05 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.go +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.go @@ -230,6 +230,7 @@ func (n *Nanoarch) CoreLoad(meta Metadata) { retroSetInputState = loadFunction(coreLib, "retro_set_input_state") retroSetAudioSample = loadFunction(coreLib, "retro_set_audio_sample") retroSetAudioSampleBatch = loadFunction(coreLib, "retro_set_audio_sample_batch") + retroReset = loadFunction(coreLib, "retro_reset") retroRun = loadFunction(coreLib, "retro_run") retroLoadGame = loadFunction(coreLib, "retro_load_game") retroUnloadGame = loadFunction(coreLib, "retro_unload_game") @@ -396,6 +397,10 @@ func (n *Nanoarch) Shutdown() { C.free(unsafe.Pointer(n.cSystemDirectory)) } +func (n *Nanoarch) Reset() { + C.bridge_retro_reset(retroReset) +} + func (n *Nanoarch) Run() { if n.LibCo { C.same_thread(retroRun) @@ -595,6 +600,7 @@ var ( coreLib unsafe.Pointer retroInit unsafe.Pointer retroLoadGame unsafe.Pointer + retroReset unsafe.Pointer retroRun unsafe.Pointer retroSetAudioSample unsafe.Pointer retroSetAudioSampleBatch unsafe.Pointer diff --git a/pkg/worker/caged/libretro/nanoarch/nanoarch.h b/pkg/worker/caged/libretro/nanoarch/nanoarch.h index 661036434..c1e09462f 100644 --- a/pkg/worker/caged/libretro/nanoarch/nanoarch.h +++ b/pkg/worker/caged/libretro/nanoarch/nanoarch.h @@ -15,6 +15,7 @@ void bridge_retro_deinit(void *f); void bridge_retro_get_system_av_info(void *f, struct retro_system_av_info *si); void bridge_retro_get_system_info(void *f, struct retro_system_info *si); void bridge_retro_init(void *f); +void bridge_retro_reset(void *f); void bridge_retro_run(void *f); void bridge_retro_set_audio_sample(void *f, void *callback); void bridge_retro_set_audio_sample_batch(void *f, void *callback); diff --git a/pkg/worker/coordinator.go b/pkg/worker/coordinator.go index 1dd4c7ef0..079635773 100644 --- a/pkg/worker/coordinator.go +++ b/pkg/worker/coordinator.go @@ -126,6 +126,12 @@ func (c *coordinator) HandleRequests(w *Worker) chan struct{} { } else { out = c.HandleChangePlayer(*dat, w) } + case api.ResetGame: + dat := api.Unwrap[api.ResetGameRequest[com.Uid]](x.Payload) + if dat == nil { + return api.ErrMalformed + } + c.HandleResetGame(*dat, w) case api.RecordGame: if dat := api.Unwrap[api.RecordGameRequest[com.Uid]](x.Payload); dat == nil { err, out = api.ErrMalformed, api.EmptyPacket diff --git a/pkg/worker/coordinatorhandlers.go b/pkg/worker/coordinatorhandlers.go index db0b5ad01..97cb27849 100644 --- a/pkg/worker/coordinatorhandlers.go +++ b/pkg/worker/coordinatorhandlers.go @@ -234,6 +234,14 @@ func (c *coordinator) HandleQuitGame(rq api.GameQuitRequest[com.Uid], w *Worker) } } +func (c *coordinator) HandleResetGame(rq api.ResetGameRequest[com.Uid], w *Worker) api.Out { + if r := w.router.FindRoom(rq.Rid); r != nil { + room.WithEmulator(r.App()).Reset() + return api.OkPacket + } + return api.ErrPacket +} + func (c *coordinator) HandleSaveGame(rq api.SaveGameRequest[com.Uid], w *Worker) api.Out { r := w.router.FindRoom(rq.Rid) if r == nil { diff --git a/web/js/api.js b/web/js/api.js index 736328ee4..906342b08 100644 --- a/web/js/api.js +++ b/web/js/api.js @@ -15,6 +15,7 @@ const endpoints = { GAME_RECORDING: 110, GET_WORKER_LIST: 111, GAME_ERROR_NO_FREE_SLOTS: 112, + GAME_RESET: 113, APP_VIDEO_CHANGE: 150, } @@ -319,6 +320,7 @@ export const api = { } }, load: () => packet(endpoints.GAME_LOAD), + reset: (roomId) => packet(endpoints.GAME_RESET, {room_id: roomId}), save: () => packet(endpoints.GAME_SAVE), setPlayerIndex: (i) => packet(endpoints.GAME_SET_PLAYER_INDEX, i), start: (game, roomId, record, recordUser, player) => packet(endpoints.GAME_START, { diff --git a/web/js/app.js b/web/js/app.js index ad5bb6c6c..01327be33 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -437,6 +437,9 @@ const app = { room.reset(); window.location = window.location.pathname; break; + case KEY.RESET: + api.game.reset(room.id) + break; case KEY.STATS: stats.toggle(); break; diff --git a/web/js/input/keyboard.js b/web/js/input/keyboard.js index b29b61bf2..4c26e9dbf 100644 --- a/web/js/input/keyboard.js +++ b/web/js/input/keyboard.js @@ -45,7 +45,8 @@ const defaultMap = Object.freeze({ KeyH: KEY.HELP, Backslash: KEY.STATS, Digit9: KEY.SETTINGS, - KeyT: KEY.DTOGGLE + KeyT: KEY.DTOGGLE, + Digit0: KEY.RESET, }); let keyMap = {}; diff --git a/web/js/input/keys.js b/web/js/input/keys.js index 6f94c2ff4..4406823e2 100644 --- a/web/js/input/keys.js +++ b/web/js/input/keys.js @@ -29,4 +29,5 @@ export const KEY = { L3: 'l3', R3: 'r3', REC: 'rec', + RESET: 'reset', }