Browse Source

Validate remote players in multiplayer games

pull/4930/head
staphen 4 years ago committed by Anders Jenbo
parent
commit
b98497d464
  1. 52
      Source/multi.cpp

52
Source/multi.cpp

@ -26,6 +26,7 @@
#include "utils/endian.hpp"
#include "utils/language.h"
#include "utils/stdcompat/cstddef.hpp"
#include "utils/stdcompat/string_view.hpp"
namespace devilution {
@ -56,6 +57,7 @@ bool PublicGame;
BYTE gbDeltaSender;
bool sgbNetInited;
uint32_t player_state[MAX_PLRS];
Uint32 playerInfoTimers[MAX_PLRS];
/**
* Contains the set of supported event types supported by the multiplayer
@ -133,6 +135,47 @@ void NetReceivePlayerData(TPkt *pkt)
pkt->hdr.bdex = myPlayer._pBaseDex;
}
bool IsNetPlayerValid(const Player &player)
{
return player._pLevel >= 1
&& player._pLevel <= MAXCHARLEVEL
&& static_cast<uint8_t>(player._pClass) < enum_size<HeroClass>::value
&& player.plrlevel < NUMLEVELS
&& player.pDifficulty <= DIFF_LAST
&& InDungeonBounds(player.position.tile)
&& !string_view(player._pName).empty();
}
void CheckPlayerInfoTimeouts()
{
for (int i = 0; i < MAX_PLRS; i++) {
if (i == MyPlayerId) {
continue;
}
Uint32 &timerStart = playerInfoTimers[i];
bool isPlayerConnected = (player_state[i] & PS_CONNECTED) != 0;
bool isPlayerValid = isPlayerConnected && IsNetPlayerValid(Players[i]);
if (isPlayerConnected && !isPlayerValid && timerStart == 0) {
timerStart = SDL_GetTicks();
}
if (!isPlayerConnected || isPlayerValid) {
timerStart = 0;
}
if (timerStart == 0) {
continue;
}
// Time the player out after 15 seconds
// if we do not receive valid player info
if (SDL_GetTicks() - timerStart >= 15000) {
SNetDropPlayer(i, LEAVE_DROP);
timerStart = 0;
}
}
}
void SendPacket(int playerId, const byte *packet, size_t size)
{
TPkt pkt;
@ -574,6 +617,14 @@ void multi_process_network_packets()
if (pkt->wLen != dwMsgSize)
continue;
auto &player = Players[dwID];
if (!IsNetPlayerValid(player)) {
_cmd_id cmd = *(const _cmd_id *)(pkt + 1);
if (IsNoneOf(cmd, CMD_SEND_PLRINFO, CMD_ACK_PLRINFO)) {
// Distrust all messages until
// player info is received
continue;
}
}
Point syncPosition = { pkt->px, pkt->py };
player.position.last = syncPosition;
if (dwID != MyPlayerId) {
@ -616,6 +667,7 @@ void multi_process_network_packets()
}
if (SErrGetLastError() != STORM_ERROR_NO_MESSAGES_WAITING)
nthread_terminate_game("SNetReceiveMsg");
CheckPlayerInfoTimeouts();
}
void multi_send_zero_packet(int pnum, _cmd_id bCmd, const byte *data, size_t size)

Loading…
Cancel
Save