NetPlay - Allow host to pause game for clients

This commit is contained in:
Souryo 2014-07-09 21:48:54 -04:00
parent 1ad66f714f
commit f748c51552
11 changed files with 101 additions and 46 deletions

View File

@ -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);
}
}

View File

@ -14,6 +14,7 @@
enum EmulationFlags
{
LimitFPS = 0x01,
Paused = 0x02,
};
class Console

View File

@ -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;
}
}

View File

@ -14,6 +14,8 @@ private:
private:
void SendHandshake();
void InitializeVirtualControllers();
void DisposeVirtualControllers();
protected:
void ProcessMessage(NetMessage* message);

View File

@ -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()

View File

@ -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;
}
}

View File

@ -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);
};

View File

@ -7,7 +7,8 @@ enum class ConsoleNotificationType
StateLoaded = 1,
GameReset = 2,
GamePaused = 3,
GameStopped = 4,
GameResumed = 4,
GameStopped = 5,
};
class INotificationListener

View File

@ -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);

View File

@ -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();

View File

@ -10,7 +10,6 @@ namespace NES {
enum UIFlags
{
ShowFPS = 1,
ShowPauseScreen = 2,
};
class Renderer : public IVideoDevice, public IMessageManager