diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp
index ebf2ba5140..3142a6e4d2 100644
--- a/Client/mods/deathmatch/logic/CPacketHandler.cpp
+++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp
@@ -572,6 +572,10 @@ void CPacketHandler::Packet_ServerDisconnected(NetBitStreamInterface& bitStream)
strReason = _("Disconnected: Serial verification failed");
strErrorCode = _E("CD44");
break;
+ case ePlayerDisconnectType::SERIAL_DUPLICATE:
+ strReason = _("Disconnected: Serial already in use");
+ strErrorCode = _E("CD50");
+ break;
case ePlayerDisconnectType::CONNECTION_DESYNC:
strReason = _("Disconnected: Connection desync %s");
strErrorCode = _E("CD45");
diff --git a/Client/mods/deathmatch/logic/CPacketHandler.h b/Client/mods/deathmatch/logic/CPacketHandler.h
index ca0f6f3d69..9a50b24615 100644
--- a/Client/mods/deathmatch/logic/CPacketHandler.h
+++ b/Client/mods/deathmatch/logic/CPacketHandler.h
@@ -42,7 +42,8 @@ class CPacketHandler
BAN,
KICK,
CUSTOM,
- SHUTDOWN
+ SHUTDOWN,
+ SERIAL_DUPLICATE
};
struct SEntityDependantStuff
diff --git a/Server/mods/deathmatch/editor.conf b/Server/mods/deathmatch/editor.conf
index 3b2b75fa80..1355e673ee 100644
--- a/Server/mods/deathmatch/editor.conf
+++ b/Server/mods/deathmatch/editor.conf
@@ -268,6 +268,12 @@
Values: 0 - Off, 1 - Enabled. Default - 1 -->
1
+
+ 1
+
diff --git a/Server/mods/deathmatch/local.conf b/Server/mods/deathmatch/local.conf
index 039e155d81..d30a608781 100644
--- a/Server/mods/deathmatch/local.conf
+++ b/Server/mods/deathmatch/local.conf
@@ -274,6 +274,12 @@
Values: 0 - Off, 1 - Enabled. Default - 0 -->
0
+
+ 1
+
diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp
index 9543e1e447..a72885c929 100644
--- a/Server/mods/deathmatch/logic/CGame.cpp
+++ b/Server/mods/deathmatch/logic/CGame.cpp
@@ -1798,6 +1798,21 @@ void CGame::Packet_PlayerJoinData(CPlayerJoinDataPacket& Packet)
return;
}
+ // Check if another player is using the same serial
+ if (m_pMainConfig->IsCheckDuplicateSerialsEnabled() && m_pPlayerManager->GetBySerial(strSerial))
+ {
+ // Tell the console
+ CLogger::LogPrintf("CONNECT: %s failed to connect (Serial already in use) (%s)\n", szNick, strIPAndSerial.c_str());
+
+ // Tell the player the problem
+ if (pPlayer->CanBitStream(eBitStreamVersion::CheckDuplicateSerials))
+ DisconnectPlayer(this, *pPlayer, CPlayerDisconnectedPacket::SERIAL_DUPLICATE);
+ else
+ DisconnectPlayer(this, *pPlayer, CPlayerDisconnectedPacket::KICK);
+
+ return;
+ }
+
// Check the nick is valid
if (!CheckNickProvided(szNick))
{
diff --git a/Server/mods/deathmatch/logic/CMainConfig.cpp b/Server/mods/deathmatch/logic/CMainConfig.cpp
index bece65e885..49c73419ca 100644
--- a/Server/mods/deathmatch/logic/CMainConfig.cpp
+++ b/Server/mods/deathmatch/logic/CMainConfig.cpp
@@ -80,6 +80,7 @@ CMainConfig::CMainConfig(CConsole* pConsole) : CXMLConfig(NULL)
m_iBackupAmount = 5;
m_bSyncMapElementData = true;
m_elementDataWhitelisted = false;
+ m_checkDuplicateSerials = true;
}
bool CMainConfig::Load()
@@ -528,6 +529,7 @@ bool CMainConfig::Load()
}
GetBoolean(m_pRootNode, "elementdata_whitelisted", m_elementDataWhitelisted);
+ GetBoolean(m_pRootNode, "check_duplicate_serials", m_checkDuplicateSerials);
ApplyNetOptions();
diff --git a/Server/mods/deathmatch/logic/CMainConfig.h b/Server/mods/deathmatch/logic/CMainConfig.h
index 9758ae2dbf..05df0e2f32 100644
--- a/Server/mods/deathmatch/logic/CMainConfig.h
+++ b/Server/mods/deathmatch/logic/CMainConfig.h
@@ -127,6 +127,7 @@ class CMainConfig : public CXMLConfig
bool IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; }
bool IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; }
bool IsElementDataWhitelisted() const { return m_elementDataWhitelisted; }
+ bool IsCheckDuplicateSerialsEnabled() const noexcept { return m_checkDuplicateSerials; }
bool IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; }
SString GetSetting(const SString& configSetting);
@@ -230,5 +231,6 @@ class CMainConfig : public CXMLConfig
int m_iPlayerTriggeredEventIntervalMs;
int m_iMaxPlayerTriggeredEventsPerInterval;
bool m_elementDataWhitelisted;
+ bool m_checkDuplicateSerials;
int m_checkResourceClientFiles;
};
diff --git a/Server/mods/deathmatch/logic/CPlayerManager.cpp b/Server/mods/deathmatch/logic/CPlayerManager.cpp
index abdf923df7..227d3677f2 100644
--- a/Server/mods/deathmatch/logic/CPlayerManager.cpp
+++ b/Server/mods/deathmatch/logic/CPlayerManager.cpp
@@ -138,6 +138,17 @@ CPlayer* CPlayerManager::Get(const char* szNick, bool bCaseSensitive)
return NULL;
}
+CPlayer* CPlayerManager::GetBySerial(const std::string_view serial) const noexcept
+{
+ for (const auto& player : m_Players)
+ {
+ if (player->GetSerial() == serial)
+ return player;
+ }
+
+ return nullptr;
+}
+
void CPlayerManager::DeleteAll()
{
// Delete all the items in the list
diff --git a/Server/mods/deathmatch/logic/CPlayerManager.h b/Server/mods/deathmatch/logic/CPlayerManager.h
index bd503380f4..0380c4bce4 100644
--- a/Server/mods/deathmatch/logic/CPlayerManager.h
+++ b/Server/mods/deathmatch/logic/CPlayerManager.h
@@ -40,6 +40,7 @@ class CPlayerManager
CPlayer* Get(const NetServerPlayerID& PlayerSocket);
CPlayer* Get(const char* szNick, bool bCaseSensitive = false);
+ CPlayer* GetBySerial(const std::string_view serial) const noexcept;
std::list::const_iterator IterBegin() { return m_Players.begin(); };
std::list::const_iterator IterEnd() { return m_Players.end(); };
diff --git a/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h b/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h
index 82fdfbd1b0..541f9b191c 100644
--- a/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h
+++ b/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h
@@ -39,7 +39,8 @@ class CPlayerDisconnectedPacket final : public CPacket
BAN,
KICK,
CUSTOM,
- SHUTDOWN
+ SHUTDOWN,
+ SERIAL_DUPLICATE
};
CPlayerDisconnectedPacket(const char* szReason);
diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf
index 11ef497fa7..726199d548 100644
--- a/Server/mods/deathmatch/mtaserver.conf
+++ b/Server/mods/deathmatch/mtaserver.conf
@@ -274,6 +274,12 @@
Values: 0 - Off, 1 - Enabled. Default - 0 -->
0
+
+ 1
+
0
+
+ 1
+