mirror of
https://github.com/libretro/Mesen.git
synced 2024-12-17 22:36:35 +00:00
224 lines
6.0 KiB
C++
224 lines
6.0 KiB
C++
#include "stdafx.h"
|
|
#include "GameClientConnection.h"
|
|
#include "HandShakeMessage.h"
|
|
#include "InputDataMessage.h"
|
|
#include "MovieDataMessage.h"
|
|
#include "GameInformationMessage.h"
|
|
#include "SaveStateMessage.h"
|
|
#include "Console.h"
|
|
#include "EmulationSettings.h"
|
|
#include "ControlManager.h"
|
|
#include "ClientConnectionData.h"
|
|
#include "StandardController.h"
|
|
#include "SelectControllerMessage.h"
|
|
#include "PlayerListMessage.h"
|
|
#include "ForceDisconnectMessage.h"
|
|
|
|
GameClientConnection::GameClientConnection(shared_ptr<Socket> socket, shared_ptr<ClientConnectionData> connectionData) : GameConnection(socket, connectionData)
|
|
{
|
|
MessageManager::RegisterNotificationListener(this);
|
|
MessageManager::DisplayMessage("NetPlay", "ConnectedToServer");
|
|
SendHandshake();
|
|
}
|
|
|
|
GameClientConnection::~GameClientConnection()
|
|
{
|
|
_shutdown = true;
|
|
DisableControllers();
|
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer);
|
|
MessageManager::DisplayMessage("NetPlay", "ConnectionLost");
|
|
MessageManager::UnregisterNotificationListener(this);
|
|
}
|
|
|
|
void GameClientConnection::SendHandshake()
|
|
{
|
|
HandShakeMessage message(_connectionData->PlayerName, _connectionData->AvatarData, _connectionData->AvatarSize, _connectionData->Spectator);
|
|
SendNetMessage(message);
|
|
}
|
|
|
|
void GameClientConnection::SendControllerSelection(uint8_t port)
|
|
{
|
|
SelectControllerMessage message(port);
|
|
SendNetMessage(message);
|
|
}
|
|
|
|
void GameClientConnection::ClearInputData()
|
|
{
|
|
for(int i = 0; i < 4; i++) {
|
|
_inputSize[i] = 0;
|
|
_inputData[i].clear();
|
|
}
|
|
}
|
|
|
|
void GameClientConnection::ProcessMessage(NetMessage* message)
|
|
{
|
|
GameInformationMessage* gameInfo;
|
|
|
|
switch(message->GetType()) {
|
|
case MessageType::SaveState:
|
|
if(_gameLoaded) {
|
|
DisableControllers();
|
|
Console::Pause();
|
|
ClearInputData();
|
|
((SaveStateMessage*)message)->LoadState();
|
|
_enableControllers = true;
|
|
switch(EmulationSettings::GetControllerType(_controllerPort)) {
|
|
case ControllerType::StandardController: _controlDevice.reset(new StandardController(0)); break;
|
|
|
|
case ControllerType::Zapper:
|
|
case ControllerType::ArkanoidController:
|
|
_controlDevice = ControlManager::GetControlDevice(_controllerPort);
|
|
break;
|
|
}
|
|
Console::Resume();
|
|
}
|
|
break;
|
|
|
|
case MessageType::MovieData:
|
|
if(_gameLoaded) {
|
|
PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), ((MovieDataMessage*)message)->GetInputState());
|
|
}
|
|
break;
|
|
|
|
case MessageType::ForceDisconnect:
|
|
MessageManager::DisplayMessage("NetPlay", ((ForceDisconnectMessage*)message)->GetMessage());
|
|
break;
|
|
|
|
case MessageType::PlayerList:
|
|
_playerList = ((PlayerListMessage*)message)->GetPlayerList();
|
|
break;
|
|
|
|
case MessageType::GameInformation:
|
|
DisableControllers();
|
|
Console::Pause();
|
|
gameInfo = (GameInformationMessage*)message;
|
|
if(gameInfo->GetPort() != _controllerPort) {
|
|
_controllerPort = gameInfo->GetPort();
|
|
|
|
if(_controllerPort == GameConnection::SpectatorPort) {
|
|
MessageManager::DisplayMessage("NetPlay", "ConnectedAsSpectator");
|
|
} else {
|
|
MessageManager::DisplayMessage("NetPlay", "ConnectedAsPlayer", std::to_string(_controllerPort + 1));
|
|
}
|
|
}
|
|
|
|
ClearInputData();
|
|
|
|
_gameLoaded = gameInfo->AttemptLoadGame();
|
|
if(gameInfo->IsPaused()) {
|
|
EmulationSettings::SetFlags(EmulationFlags::Paused);
|
|
} else {
|
|
EmulationSettings::ClearFlags(EmulationFlags::Paused);
|
|
}
|
|
Console::Resume();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void GameClientConnection::PushControllerState(uint8_t port, uint8_t state)
|
|
{
|
|
LockHandler lock = _writeLock.AcquireSafe();
|
|
_inputData[port].push_back(state);
|
|
_inputSize[port]++;
|
|
|
|
if(_inputData[port].size() >= _minimumQueueSize) {
|
|
_waitForInput[port].Signal();
|
|
}
|
|
}
|
|
|
|
void GameClientConnection::DisableControllers()
|
|
{
|
|
//Used to prevent deadlocks when client is trying to fill its buffer while the host changes the current game/settings/etc. (i.e situations where we need to call Console::Pause())
|
|
ClearInputData();
|
|
_enableControllers = false;
|
|
for(int i = 0; i < 4; i++) {
|
|
_waitForInput[i].Signal();
|
|
}
|
|
}
|
|
|
|
uint8_t GameClientConnection::GetControllerState(uint8_t port)
|
|
{
|
|
if(_enableControllers) {
|
|
while(_inputSize[port] == 0) {
|
|
_waitForInput[port].Wait();
|
|
|
|
if(port == 0 && _minimumQueueSize < 10) {
|
|
//Increase buffer size - reduces freezes at the cost of additional lag
|
|
_minimumQueueSize++;
|
|
}
|
|
|
|
if(_shutdown || !_enableControllers) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
LockHandler lock = _writeLock.AcquireSafe();
|
|
uint8_t state = _inputData[port].front();
|
|
_inputData[port].pop_front();
|
|
_inputSize[port]--;
|
|
|
|
if(_inputData[port].size() > _minimumQueueSize) {
|
|
//Too much data, catch up
|
|
EmulationSettings::SetEmulationSpeed(0);
|
|
} else {
|
|
EmulationSettings::SetEmulationSpeed(100);
|
|
}
|
|
return state;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void GameClientConnection::ProcessNotification(ConsoleNotificationType type, void* parameter)
|
|
{
|
|
if(type == ConsoleNotificationType::ConfigChanged) {
|
|
switch(EmulationSettings::GetControllerType(_controllerPort)) {
|
|
case ControllerType::StandardController: _newControlDevice.reset(new StandardController(0)); break;
|
|
case ControllerType::Zapper: _newControlDevice = ControlManager::GetControlDevice(_controllerPort); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameClientConnection::SendInput()
|
|
{
|
|
if(_gameLoaded) {
|
|
if(_newControlDevice) {
|
|
_controlDevice = _newControlDevice;
|
|
_newControlDevice.reset();
|
|
}
|
|
|
|
uint32_t inputState = 0;
|
|
if(_controlDevice) {
|
|
inputState = _controlDevice->GetNetPlayState();
|
|
}
|
|
|
|
if(_lastInputSent != inputState) {
|
|
InputDataMessage message(inputState);
|
|
SendNetMessage(message);
|
|
_lastInputSent = inputState;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameClientConnection::SelectController(uint8_t port)
|
|
{
|
|
SendControllerSelection(port);
|
|
}
|
|
|
|
uint8_t GameClientConnection::GetAvailableControllers()
|
|
{
|
|
uint8_t availablePorts = 0x0F;
|
|
for(PlayerInfo &playerInfo : _playerList) {
|
|
if(playerInfo.ControllerPort < 4) {
|
|
availablePorts &= ~(1 << playerInfo.ControllerPort);
|
|
}
|
|
}
|
|
return availablePorts;
|
|
}
|
|
|
|
uint8_t GameClientConnection::GetControllerPort()
|
|
{
|
|
return _controllerPort;
|
|
} |