diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea61d912b..9d8d1eb295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1408,6 +1408,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Debugger/WebSocket/CPUCoreSubscriber.h Core/Debugger/WebSocket/GameBroadcaster.cpp Core/Debugger/WebSocket/GameBroadcaster.h + Core/Debugger/WebSocket/GameSubscriber.cpp + Core/Debugger/WebSocket/GameSubscriber.h Core/Debugger/WebSocket/LogBroadcaster.cpp Core/Debugger/WebSocket/LogBroadcaster.h Core/Debugger/WebSocket/SteppingBroadcaster.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index c102fd2cb7..4e8826e6e1 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -187,6 +187,7 @@ + @@ -539,6 +540,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 3a8a72a82e..e0d5840131 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -713,6 +713,9 @@ Debugger\WebSocket + + Debugger\WebSocket + @@ -1313,6 +1316,9 @@ Debugger\WebSocket + + Debugger\WebSocket + diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index d42fdbd3a2..2f5aafa403 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -44,6 +44,7 @@ #include "Core/Debugger/WebSocket/SteppingBroadcaster.h" #include "Core/Debugger/WebSocket/CPUCoreSubscriber.h" +#include "Core/Debugger/WebSocket/GameSubscriber.h" typedef void *(*SubscriberInit)(DebuggerEventHandlerMap &map); typedef void (*Subscribershutdown)(void *p); @@ -54,6 +55,7 @@ struct SubscriberInfo { static const std::vector subscribers({ { &WebSocketCPUCoreInit, nullptr }, + { &WebSocketGameInit, nullptr }, }); // To handle webserver restart, keep track of how many running. diff --git a/Core/Debugger/WebSocket/GameBroadcaster.cpp b/Core/Debugger/WebSocket/GameBroadcaster.cpp index 37a9e2c919..4c53522a98 100644 --- a/Core/Debugger/WebSocket/GameBroadcaster.cpp +++ b/Core/Debugger/WebSocket/GameBroadcaster.cpp @@ -17,22 +17,78 @@ #include "Core/Debugger/WebSocket/GameBroadcaster.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/ELF/ParamSFO.h" #include "Core/System.h" +struct GameStatusEvent { + const char *ev; + + operator std::string() { + JsonWriter j; + j.begin(); + j.writeString("event", ev); + if (PSP_IsInited()) { + j.pushDict("game"); + j.writeString("id", g_paramSFO.GetDiscID()); + j.writeString("version", g_paramSFO.GetValueString("DISC_VERSION")); + j.writeString("title", g_paramSFO.GetValueString("TITLE")); + j.pop(); + } else { + j.writeRaw("game", "null"); + } + j.end(); + return j.str(); + } +}; + +// Game started (game.start) +// +// Sent unexpectedly with these properties: +// - game: null or an object with properties: +// - id: string disc ID (such as ULUS12345.) +// - version: string disc version. +// - title: string game title. + +// Game quit / ended (game.quit) +// +// Sent unexpectedly with these properties: +// - game: null + +// Game paused (game.pause) +// +// Note: this is not the same as stepping. This means the user went to the pause menu. +// +// Sent unexpectedly with these properties: +// - game: null or an object with properties: +// - id: string disc ID (such as ULUS12345.) +// - version: string disc version. +// - title: string game title. + +// Game resumed (game.pause) +// +// Note: this is not the same as stepping. This means the user resumed from the pause menu. +// +// Sent unexpectedly with these properties: +// - game: null or an object with properties: +// - id: string disc ID (such as ULUS12345.) +// - version: string disc version. +// - title: string game title. void GameBroadcaster::Broadcast(net::WebSocketServer *ws) { - // TODO: This is ugly. Implement proper information instead. - // TODO: Should probably include info about which game, etc. + // TODO: This is ugly. Callbacks instead? GlobalUIState state = GetUIState(); if (prevState_ != state) { if (state == UISTATE_PAUSEMENU) { - ws->Send(R"({"event":"game.pause"})"); + ws->Send(GameStatusEvent{"game.pause"}); + prevState_ = state; } else if (state == UISTATE_INGAME && prevState_ == UISTATE_PAUSEMENU) { - ws->Send(R"({"event":"game.resume"})"); - } else if (state == UISTATE_INGAME) { - ws->Send(R"({"event":"game.start"})"); - } else if (state == UISTATE_MENU) { - ws->Send(R"({"event":"game.quit"})"); + ws->Send(GameStatusEvent{"game.resume"}); + prevState_ = state; + } else if (state == UISTATE_INGAME && PSP_IsInited()) { + ws->Send(GameStatusEvent{"game.start"}); + prevState_ = state; + } else if (state == UISTATE_MENU && !PSP_IsInited() && !PSP_IsQuitting()) { + ws->Send(GameStatusEvent{"game.quit"}); + prevState_ = state; } - prevState_ = state; } } diff --git a/Core/Debugger/WebSocket/GameSubscriber.cpp b/Core/Debugger/WebSocket/GameSubscriber.cpp new file mode 100644 index 0000000000..2e91505ac2 --- /dev/null +++ b/Core/Debugger/WebSocket/GameSubscriber.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2018- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Core/Debugger/WebSocket/GameSubscriber.h" +#include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/ELF/ParamSFO.h" +#include "Core/System.h" + +void *WebSocketGameInit(DebuggerEventHandlerMap &map) { + map["game.status"] = &WebSocketGameStatus; + + return nullptr; +} + +// Check game status (game.status) +// +// No parameters. +// +// Response (same event name): +// - game: null or an object with properties: +// - id: string disc ID (such as ULUS12345.) +// - version: string disc version. +// - title: string game title. +// - paused: boolean, true when gameplay is paused (not the same as stepping.) +void WebSocketGameStatus(DebuggerRequest &req) { + JsonWriter &json = req.Respond(); + if (PSP_IsInited()) { + json.pushDict("game"); + json.writeString("id", g_paramSFO.GetDiscID()); + json.writeString("version", g_paramSFO.GetValueString("DISC_VERSION")); + json.writeString("title", g_paramSFO.GetValueString("TITLE")); + json.pop(); + } else { + json.writeRaw("game", "null"); + } + json.writeBool("paused", GetUIState() == UISTATE_PAUSEMENU); +} diff --git a/Core/Debugger/WebSocket/GameSubscriber.h b/Core/Debugger/WebSocket/GameSubscriber.h new file mode 100644 index 0000000000..4236b54885 --- /dev/null +++ b/Core/Debugger/WebSocket/GameSubscriber.h @@ -0,0 +1,24 @@ +// Copyright (c) 2018- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Core/Debugger/WebSocket/WebSocketUtils.h" + +void *WebSocketGameInit(DebuggerEventHandlerMap &map); + +void WebSocketGameStatus(DebuggerRequest &req); diff --git a/Core/System.cpp b/Core/System.cpp index 6355c66dd3..b59a365872 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -385,6 +385,10 @@ bool PSP_IsInited() { return pspIsInited && !pspIsQuitting; } +bool PSP_IsQuitting() { + return pspIsQuitting; +} + void PSP_Shutdown() { // Do nothing if we never inited. if (!pspIsInited && !pspIsIniting && !pspIsQuitting) { diff --git a/Core/System.h b/Core/System.h index 32182c3bc2..f25974970e 100644 --- a/Core/System.h +++ b/Core/System.h @@ -66,6 +66,7 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string); bool PSP_InitUpdate(std::string *error_string); bool PSP_IsIniting(); bool PSP_IsInited(); +bool PSP_IsQuitting(); void PSP_Shutdown(); void PSP_BeginHostFrame(); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index b5b8dda1d2..9e32c054a7 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -303,6 +303,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/Debugger/WebSocket.cpp \ $(SRC)/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \ + $(SRC)/Core/Debugger/WebSocket/GameSubscriber.cpp \ $(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \ $(SRC)/Core/Debugger/WebSocket/WebSocketUtils.cpp \