diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 20dd7542..1fbcb7e6 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -370,6 +370,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index f0a30f19..5fa0d3fa 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -545,6 +545,9 @@
NetPlay\Messages
+
+ NetPlay\Messages
+
diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp
index 7bebd9f5..50f8f1ce 100644
--- a/Core/EmulationSettings.cpp
+++ b/Core/EmulationSettings.cpp
@@ -17,6 +17,10 @@ uint32_t EmulationSettings::PpuPaletteArgb[64] = {
0xFFB5EBF2, 0xFFB8B8B8, 0xFF000000, 0xFF000000,
};
+uint16_t EmulationSettings::_versionMajor = 0;
+uint8_t EmulationSettings::_versionMinor = 1;
+uint8_t EmulationSettings::_versionRevision = 0;
+
uint32_t EmulationSettings::_flags = 0;
uint32_t EmulationSettings::_audioLatency = 20000;
diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h
index 1ca1703c..8b8b4766 100644
--- a/Core/EmulationSettings.h
+++ b/Core/EmulationSettings.h
@@ -143,6 +143,11 @@ struct KeyMappingSet
class EmulationSettings
{
private:
+ //Version 0.1.0
+ static uint16_t _versionMajor;
+ static uint8_t _versionMinor;
+ static uint8_t _versionRevision;
+
static uint32_t PpuPaletteArgb[64];
static uint32_t _flags;
@@ -170,12 +175,12 @@ private:
public:
static uint32_t GetMesenVersion()
{
- //Version 0.1.0
- uint16_t major = 0;
- uint8_t minor = 1;
- uint8_t revision = 0;
+ return (_versionMajor << 16) | (_versionMinor << 8) | _versionRevision;
+ }
- return (major << 16) | (minor << 8) | revision;
+ static string GetMesenVersionString()
+ {
+ return std::to_string(_versionMajor) + "." + std::to_string(_versionMinor) + "." + std::to_string(_versionRevision);
}
static void SetFlags(EmulationFlags flags)
diff --git a/Core/ForceDisconnectMessage.h b/Core/ForceDisconnectMessage.h
new file mode 100644
index 00000000..894bd16a
--- /dev/null
+++ b/Core/ForceDisconnectMessage.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "stdafx.h"
+#include "MessageManager.h"
+#include "NetMessage.h"
+#include "Console.h"
+#include "RomLoader.h"
+#include "../Utilities/FolderUtilities.h"
+
+class ForceDisconnectMessage : public NetMessage
+{
+private:
+ char* _disconnectMessage = nullptr;
+ uint32_t _messageLength = 0;
+
+protected:
+ virtual void ProtectedStreamState()
+ {
+ StreamArray((void**)&_disconnectMessage, _messageLength);
+ }
+
+public:
+ ForceDisconnectMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
+
+ ForceDisconnectMessage(string message) : NetMessage(MessageType::ForceDisconnect)
+ {
+ CopyString(&_disconnectMessage, _messageLength, message);
+ }
+
+ string GetMessage()
+ {
+ return _disconnectMessage;
+ }
+};
\ No newline at end of file
diff --git a/Core/GameClientConnection.cpp b/Core/GameClientConnection.cpp
index c52aa140..0bda8677 100644
--- a/Core/GameClientConnection.cpp
+++ b/Core/GameClientConnection.cpp
@@ -12,6 +12,7 @@
#include "StandardController.h"
#include "SelectControllerMessage.h"
#include "PlayerListMessage.h"
+#include "ForceDisconnectMessage.h"
GameClientConnection::GameClientConnection(shared_ptr socket, shared_ptr connectionData) : GameConnection(socket, connectionData)
{
@@ -76,6 +77,10 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
}
break;
+ case MessageType::ForceDisconnect:
+ MessageManager::DisplayMessage("Net Play", ((ForceDisconnectMessage*)message)->GetMessage());
+ break;
+
case MessageType::PlayerList:
_playerList = ((PlayerListMessage*)message)->GetPlayerList();
break;
diff --git a/Core/GameConnection.cpp b/Core/GameConnection.cpp
index 1cab2c29..910b3c33 100644
--- a/Core/GameConnection.cpp
+++ b/Core/GameConnection.cpp
@@ -8,6 +8,7 @@
#include "PlayerListMessage.h"
#include "SelectControllerMessage.h"
#include "ClientConnectionData.h"
+#include "ForceDisconnectMessage.h"
GameConnection::GameConnection(shared_ptr socket, shared_ptr connectionData)
{
@@ -58,6 +59,7 @@ NetMessage* GameConnection::ReadMessage()
case MessageType::GameInformation: return new GameInformationMessage(_messageBuffer, messageLength);
case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength);
case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength);
+ case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength);
}
}
return nullptr;
@@ -70,6 +72,11 @@ void GameConnection::SendNetMessage(NetMessage &message)
_socketLock.Release();
}
+void GameConnection::Disconnect()
+{
+ _socket->Close();
+}
+
bool GameConnection::ConnectionError()
{
return _socket->ConnectionError();
diff --git a/Core/GameConnection.h b/Core/GameConnection.h
index ba233014..ad7e94a3 100644
--- a/Core/GameConnection.h
+++ b/Core/GameConnection.h
@@ -31,6 +31,9 @@ private:
virtual void ProcessMessage(NetMessage* message) = 0;
+protected:
+ void Disconnect();
+
public:
static const uint8_t SpectatorPort = 0xFF;
GameConnection(shared_ptr socket, shared_ptr connectionData);
diff --git a/Core/GameServerConnection.cpp b/Core/GameServerConnection.cpp
index 847a9a37..bd97030d 100644
--- a/Core/GameServerConnection.cpp
+++ b/Core/GameServerConnection.cpp
@@ -14,6 +14,7 @@
#include "SelectControllerMessage.h"
#include "PlayerListMessage.h"
#include "GameServer.h"
+#include "ForceDisconnectMessage.h"
GameServerConnection* GameServerConnection::_netPlayDevices[4] = { nullptr,nullptr,nullptr,nullptr };
@@ -28,8 +29,6 @@ GameServerConnection::~GameServerConnection()
{
if(_connectionData) {
MessageManager::DisplayToast("Net Play", _connectionData->PlayerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected.", _connectionData->AvatarData, _connectionData->AvatarSize);
- } else {
- MessageManager::DisplayMessage("Net Play", "Player " + std::to_string(_controllerPort + 1) + " disconnected.");
}
UnregisterNetPlayDevice(this);
@@ -54,6 +53,13 @@ void GameServerConnection::SendMovieData(uint8_t state, uint8_t port)
}
}
+void GameServerConnection::SendForceDisconnectMessage(string disconnectMessage)
+{
+ ForceDisconnectMessage message(disconnectMessage);
+ SendNetMessage(message);
+ Disconnect();
+}
+
void GameServerConnection::PushState(uint32_t state)
{
if(_inputData.size() == 0 || state != _inputData.back()) {
@@ -96,6 +102,9 @@ void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message)
RegisterNetPlayDevice(this, _controllerPort);
GameServer::SendPlayerList();
Console::Resume();
+ } else {
+ SendForceDisconnectMessage("Server is using a different version of Mesen (" + EmulationSettings::GetMesenVersionString() + ") - you have been disconnected.");
+ MessageManager::DisplayMessage("Net Play", message->GetPlayerName() + " is not running the same version of Mesen and has been disconnected");
}
}
diff --git a/Core/GameServerConnection.h b/Core/GameServerConnection.h
index 9e0521d9..efeffc4c 100644
--- a/Core/GameServerConnection.h
+++ b/Core/GameServerConnection.h
@@ -20,6 +20,8 @@ private:
void SendGameInformation();
void SelectControllerPort(uint8_t port);
+ void SendForceDisconnectMessage(string disconnectMessage);
+
void ProcessHandshakeResponse(HandShakeMessage* message);
static void RegisterNetPlayDevice(GameServerConnection* connection, uint8_t port);
diff --git a/Core/HandShakeMessage.h b/Core/HandShakeMessage.h
index f55e4665..f01e62c0 100644
--- a/Core/HandShakeMessage.h
+++ b/Core/HandShakeMessage.h
@@ -1,11 +1,13 @@
#pragma once
#include "stdafx.h"
#include "NetMessage.h"
+#include "EmulationSettings.h"
class HandShakeMessage : public NetMessage
{
private:
const static int CurrentVersion = 1;
+ uint32_t _mesenVersion = 0;
uint32_t _protocolVersion = CurrentVersion;
char* _playerName = nullptr;
uint32_t _playerNameLength = 0;
@@ -16,6 +18,7 @@ private:
protected:
virtual void ProtectedStreamState()
{
+ Stream(_mesenVersion);
Stream(_protocolVersion);
StreamArray((void**)&_playerName, _playerNameLength);
StreamArray(&_avatarData, _avatarSize);
@@ -26,13 +29,14 @@ public:
HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
HandShakeMessage(string playerName, uint8_t* avatarData, uint32_t avatarSize, bool spectator) : NetMessage(MessageType::HandShake)
{
- _protocolVersion = 1;
+ _mesenVersion = EmulationSettings::GetMesenVersion();
+ _protocolVersion = HandShakeMessage::CurrentVersion;
CopyString(&_playerName, _playerNameLength, playerName);
_avatarSize = avatarSize;
_avatarData = avatarData;
_spectator = spectator;
}
-
+
string GetPlayerName()
{
return string(_playerName);
@@ -50,7 +54,7 @@ public:
bool IsValid()
{
- return _protocolVersion == CurrentVersion;
+ return _protocolVersion == CurrentVersion && _mesenVersion == EmulationSettings::GetMesenVersion();
}
bool IsSpectator()
diff --git a/Core/MessageType.h b/Core/MessageType.h
index 99d03822..901e244e 100644
--- a/Core/MessageType.h
+++ b/Core/MessageType.h
@@ -10,4 +10,5 @@ enum class MessageType : uint8_t
GameInformation = 4,
PlayerList = 5,
SelectController = 6,
+ ForceDisconnect = 7
};
\ No newline at end of file