mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-23 17:19:39 +00:00
NetPlay - Allow host to pause game for clients
This commit is contained in:
parent
1ad66f714f
commit
f748c51552
@ -237,6 +237,16 @@ void Console::Run()
|
||||
Console::RunningLock.Acquire();
|
||||
}
|
||||
|
||||
if(CheckFlag(EmulationFlags::Paused)) {
|
||||
Console::SendNotification(ConsoleNotificationType::GamePaused);
|
||||
Console::RunningLock.Release();
|
||||
while(CheckFlag(EmulationFlags::Paused)) {
|
||||
//Sleep until emulation is resumed
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
}
|
||||
Console::RunningLock.Acquire();
|
||||
Console::SendNotification(ConsoleNotificationType::GameResumed);
|
||||
}
|
||||
clockTimer.Reset();
|
||||
|
||||
if(_stop) {
|
||||
@ -263,7 +273,8 @@ void Console::SaveState(wstring filename)
|
||||
Console::Pause();
|
||||
Console::SaveState(file);
|
||||
Console::Resume();
|
||||
file.close();
|
||||
file.close();
|
||||
Console::DisplayMessage(L"State saved.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,7 +287,7 @@ bool Console::LoadState(wstring filename)
|
||||
Console::LoadState(file);
|
||||
Console::Resume();
|
||||
file.close();
|
||||
|
||||
Console::DisplayMessage(L"State loaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -293,8 +304,6 @@ void Console::SaveState(ostream &saveStream)
|
||||
Instance->_mapper->SaveSnapshot(&saveStream);
|
||||
Instance->_apu->SaveSnapshot(&saveStream);
|
||||
Instance->_controlManager->SaveSnapshot(&saveStream);
|
||||
|
||||
Console::DisplayMessage(L"State saved.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +317,6 @@ void Console::LoadState(istream &loadStream)
|
||||
Instance->_apu->LoadSnapshot(&loadStream);
|
||||
Instance->_controlManager->LoadSnapshot(&loadStream);
|
||||
|
||||
Console::DisplayMessage(L"State loaded.");
|
||||
Console::SendNotification(ConsoleNotificationType::StateLoaded);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
enum EmulationFlags
|
||||
{
|
||||
LimitFPS = 0x01,
|
||||
Paused = 0x02,
|
||||
};
|
||||
|
||||
class Console
|
||||
|
@ -31,6 +31,18 @@ void GameClientConnection::SendHandshake()
|
||||
SendNetMessage(HandShakeMessage());
|
||||
}
|
||||
|
||||
void GameClientConnection::InitializeVirtualControllers()
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
_virtualControllers.push_back(unique_ptr<VirtualController>(new VirtualController(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void GameClientConnection::DisposeVirtualControllers()
|
||||
{
|
||||
_virtualControllers.clear();
|
||||
}
|
||||
|
||||
void GameClientConnection::ProcessMessage(NetMessage* message)
|
||||
{
|
||||
uint8_t port;
|
||||
@ -40,17 +52,15 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
|
||||
switch(message->Type) {
|
||||
case MessageType::SaveState:
|
||||
if(_gameLoaded) {
|
||||
_virtualControllers.clear();
|
||||
DisposeVirtualControllers();
|
||||
|
||||
Console::Pause();
|
||||
|
||||
((SaveStateMessage*)message)->LoadState();
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
_virtualControllers.push_back(unique_ptr<VirtualController>(new VirtualController(i)));
|
||||
}
|
||||
|
||||
Console::Resume();
|
||||
|
||||
InitializeVirtualControllers();
|
||||
}
|
||||
break;
|
||||
case MessageType::MovieData:
|
||||
@ -67,8 +77,16 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
|
||||
_controllerPort = gameInfo->ControllerPort;
|
||||
Console::DisplayMessage(wstring(L"Connected as player ") + std::to_wstring(_controllerPort + 1));
|
||||
}
|
||||
_virtualControllers.clear();
|
||||
|
||||
DisposeVirtualControllers();
|
||||
|
||||
_gameLoaded = gameInfo->AttemptLoadGame();
|
||||
if(gameInfo->Paused) {
|
||||
Console::SetFlags(EmulationFlags::Paused);
|
||||
} else {
|
||||
Console::ClearFlags(EmulationFlags::Paused);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ private:
|
||||
|
||||
private:
|
||||
void SendHandshake();
|
||||
void InitializeVirtualControllers();
|
||||
void DisposeVirtualControllers();
|
||||
|
||||
protected:
|
||||
void ProcessMessage(NetMessage* message);
|
||||
|
@ -10,7 +10,7 @@ class GameInformationMessage : public NetMessage
|
||||
protected:
|
||||
virtual uint32_t GetMessageLength()
|
||||
{
|
||||
return sizeof(ROMFilename) + sizeof(CRC32Hash) + sizeof(ControllerPort);
|
||||
return sizeof(ROMFilename) + sizeof(CRC32Hash) + sizeof(ControllerPort) + sizeof(Paused);
|
||||
}
|
||||
|
||||
virtual void ProtectedSend(Socket &socket)
|
||||
@ -18,26 +18,30 @@ protected:
|
||||
socket.BufferedSend((char*)&ROMFilename, sizeof(ROMFilename));
|
||||
socket.BufferedSend((char*)&CRC32Hash, sizeof(CRC32Hash));
|
||||
socket.BufferedSend((char*)&ControllerPort, sizeof(ControllerPort));
|
||||
socket.BufferedSend((char*)&Paused, sizeof(Paused));
|
||||
}
|
||||
|
||||
public:
|
||||
wchar_t ROMFilename[255];
|
||||
uint32_t CRC32Hash;
|
||||
uint8_t ControllerPort;
|
||||
bool Paused;
|
||||
|
||||
GameInformationMessage(char *readBuffer) : NetMessage(MessageType::GameInformation)
|
||||
{
|
||||
memcpy((char*)ROMFilename, readBuffer, sizeof(ROMFilename));
|
||||
memcpy((char*)&CRC32Hash, readBuffer + sizeof(ROMFilename), sizeof(CRC32Hash));
|
||||
ControllerPort = readBuffer[sizeof(ROMFilename) + sizeof(CRC32Hash)];
|
||||
Paused = readBuffer[sizeof(ROMFilename) + sizeof(CRC32Hash) + sizeof(ControllerPort)] == 1;
|
||||
}
|
||||
|
||||
GameInformationMessage(wstring filepath, uint8_t port) : NetMessage(MessageType::GameInformation)
|
||||
GameInformationMessage(wstring filepath, uint8_t port, bool paused) : NetMessage(MessageType::GameInformation)
|
||||
{
|
||||
memset(ROMFilename, 0, sizeof(ROMFilename));
|
||||
wcscpy_s(ROMFilename, FolderUtilities::GetFilename(filepath, true).c_str());
|
||||
CRC32Hash = CRC32::GetCRC(filepath);
|
||||
ControllerPort = port;
|
||||
Paused = paused;
|
||||
}
|
||||
|
||||
bool AttemptLoadGame()
|
||||
|
@ -38,6 +38,8 @@ GameServerConnection::GameServerConnection(shared_ptr<Socket> socket, int contro
|
||||
Console::DisplayMessage(L"Player " + std::to_wstring(_controllerPort+1) + L" connected.");
|
||||
|
||||
ControlManager::BackupControlDevices();
|
||||
|
||||
Console::RegisterNotificationListener(this);
|
||||
}
|
||||
|
||||
GameServerConnection::~GameServerConnection()
|
||||
@ -45,6 +47,8 @@ GameServerConnection::~GameServerConnection()
|
||||
Console::DisplayMessage(L"Player " + std::to_wstring(_controllerPort+1) + L" disconnected.");
|
||||
|
||||
ControlManager::RestoreControlDevices();
|
||||
|
||||
Console::UnregisterNotificationListener(this);
|
||||
}
|
||||
|
||||
void GameServerConnection::SendGameState()
|
||||
@ -66,7 +70,7 @@ void GameServerConnection::SendGameState()
|
||||
|
||||
void GameServerConnection::SendGameInformation()
|
||||
{
|
||||
SendNetMessage(GameInformationMessage(Console::GetROMPath(), _controllerPort));
|
||||
SendNetMessage(GameInformationMessage(Console::GetROMPath(), _controllerPort, Console::CheckFlag(EmulationFlags::Paused)));
|
||||
}
|
||||
|
||||
void GameServerConnection::SendMovieData(uint8_t state, uint8_t port)
|
||||
@ -91,3 +95,16 @@ ButtonState GameServerConnection::GetButtonState()
|
||||
state.FromByte(stateData);
|
||||
return state;
|
||||
}
|
||||
|
||||
void GameServerConnection::ProcessNotification(ConsoleNotificationType type)
|
||||
{
|
||||
switch(type) {
|
||||
case ConsoleNotificationType::GamePaused:
|
||||
SendGameInformation();
|
||||
break;
|
||||
case ConsoleNotificationType::GameResumed:
|
||||
SendGameInformation();
|
||||
SendGameState();
|
||||
break;
|
||||
}
|
||||
}
|
@ -3,8 +3,9 @@
|
||||
#include "GameConnection.h"
|
||||
#include "IControlDevice.h"
|
||||
#include "IGameBroadcaster.h"
|
||||
#include "INotificationListener.h"
|
||||
|
||||
class GameServerConnection : public GameConnection, public IControlDevice
|
||||
class GameServerConnection : public GameConnection, public IControlDevice, public INotificationListener
|
||||
{
|
||||
private:
|
||||
int _controllerPort;
|
||||
@ -24,4 +25,6 @@ public:
|
||||
void SendMovieData(uint8_t state, uint8_t port);
|
||||
|
||||
ButtonState GetButtonState();
|
||||
|
||||
virtual void ProcessNotification(ConsoleNotificationType type);
|
||||
};
|
||||
|
@ -7,7 +7,8 @@ enum class ConsoleNotificationType
|
||||
StateLoaded = 1,
|
||||
GameReset = 2,
|
||||
GamePaused = 3,
|
||||
GameStopped = 4,
|
||||
GameResumed = 4,
|
||||
GameStopped = 5,
|
||||
};
|
||||
|
||||
class INotificationListener
|
||||
|
@ -317,18 +317,24 @@ namespace NES
|
||||
|
||||
void MainWindow::ProcessNotification(ConsoleNotificationType type)
|
||||
{
|
||||
if(type == ConsoleNotificationType::GameLoaded) {
|
||||
if(_console.get() != Console::GetInstance()) {
|
||||
_console.reset(Console::GetInstance());
|
||||
}
|
||||
switch(type) {
|
||||
case ConsoleNotificationType::GameLoaded:
|
||||
if(_console.get() != Console::GetInstance()) {
|
||||
_console.reset(Console::GetInstance());
|
||||
}
|
||||
|
||||
StartEmuThread();
|
||||
StartEmuThread();
|
||||
break;
|
||||
|
||||
case ConsoleNotificationType::GamePaused:
|
||||
_soundManager->Reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::UpdateMenu()
|
||||
{
|
||||
bool running = (bool)_emuThread;
|
||||
bool running = (bool)_emuThread && !Console::CheckFlag(EmulationFlags::Paused);
|
||||
bool romLoaded = (bool)_console;
|
||||
bool clientConnected = GameClient::Connected();
|
||||
bool serverStarted = GameServer::Started();
|
||||
@ -371,7 +377,8 @@ namespace NES
|
||||
wstring currentROMName = FolderUtilities::GetFilename(_console->GetROMPath(), false);
|
||||
SetWindowText(_hWnd, (wstring(_windowName) + L": " + currentROMName).c_str());
|
||||
|
||||
_renderer->ClearFlags(UIFlags::ShowPauseScreen);
|
||||
Console::ClearFlags(EmulationFlags::Paused);
|
||||
|
||||
if(IsMenuChecked(ID_OPTIONS_SHOWFPS)) {
|
||||
_renderer->SetFlags(UIFlags::ShowFPS);
|
||||
}
|
||||
@ -392,22 +399,17 @@ namespace NES
|
||||
|
||||
void MainWindow::Stop(bool powerOff)
|
||||
{
|
||||
_renderer->ClearFlags(UIFlags::ShowFPS | UIFlags::ShowPauseScreen);
|
||||
if(powerOff && _emuThread) {
|
||||
_soundManager->Reset();
|
||||
|
||||
_soundManager->Reset();
|
||||
if(_console) {
|
||||
_console->Stop();
|
||||
}
|
||||
if(_emuThread) {
|
||||
_emuThread->join();
|
||||
|
||||
if(powerOff) {
|
||||
_console.reset();
|
||||
} else {
|
||||
_renderer->SetFlags(UIFlags::ShowPauseScreen);
|
||||
if(_console) {
|
||||
_console->Stop();
|
||||
}
|
||||
|
||||
_emuThread->join();
|
||||
_console.reset();
|
||||
_emuThread.reset();
|
||||
} else {
|
||||
Console::SetFlags(EmulationFlags::Paused);
|
||||
}
|
||||
}
|
||||
|
||||
@ -583,7 +585,7 @@ namespace NES
|
||||
break;
|
||||
|
||||
case ID_NES_RESUME:
|
||||
mainWindow->Start();
|
||||
Console::ClearFlags(EmulationFlags::Paused);
|
||||
break;
|
||||
case ID_NES_PAUSE:
|
||||
mainWindow->Stop(false);
|
||||
|
@ -368,7 +368,7 @@ namespace NES
|
||||
|
||||
void Renderer::Render()
|
||||
{
|
||||
if(_frameChanged || CheckFlag(UIFlags::ShowPauseScreen) || !_displayMessages.empty()) {
|
||||
if(_frameChanged || Console::CheckFlag(EmulationFlags::Paused) || !_displayMessages.empty()) {
|
||||
_frameChanged = false;
|
||||
// Clear the back buffer
|
||||
_pDeviceContext->ClearRenderTargetView(_pRenderTargetView, Colors::Black);
|
||||
@ -384,14 +384,14 @@ namespace NES
|
||||
|
||||
_spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, _samplerState);
|
||||
|
||||
if(CheckFlag(UIFlags::ShowPauseScreen)) {
|
||||
if(Console::CheckFlag(EmulationFlags::Paused)) {
|
||||
DrawPauseScreen();
|
||||
}
|
||||
|
||||
//Draw FPS counter
|
||||
if(CheckFlag(UIFlags::ShowFPS)) {
|
||||
wstring fpsString = wstring(L"FPS: ") + std::to_wstring(Console::GetFPS());
|
||||
DrawOutlinedString(fpsString, 256 * 4 - 149, 13, Colors::AntiqueWhite, 1.0f);
|
||||
} else {
|
||||
//Draw FPS counter
|
||||
if(CheckFlag(UIFlags::ShowFPS)) {
|
||||
wstring fpsString = wstring(L"FPS: ") + std::to_wstring(Console::GetFPS());
|
||||
DrawOutlinedString(fpsString, 256 * 4 - 149, 13, Colors::AntiqueWhite, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
RemoveOldMessages();
|
||||
|
@ -10,7 +10,6 @@ namespace NES {
|
||||
enum UIFlags
|
||||
{
|
||||
ShowFPS = 1,
|
||||
ShowPauseScreen = 2,
|
||||
};
|
||||
|
||||
class Renderer : public IVideoDevice, public IMessageManager
|
||||
|
Loading…
Reference in New Issue
Block a user