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 \