Skip to content

Commit

Permalink
fix #4856: make player ids static in demos
Browse files Browse the repository at this point in the history
(for that the demo needs to save the amount of total players in the demo)
  • Loading branch information
jK committed Jul 2, 2015
1 parent 15e4daf commit 7d0351a
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 113 deletions.
152 changes: 43 additions & 109 deletions rts/Net/GameServer.cpp
Expand Up @@ -233,8 +233,11 @@ void CGameServer::Initialize()
players.reserve(MAX_PLAYERS); // no reallocation please
teams.resize(teamStartData.size());

for (int i = 0; i < playerStartData.size(); ++i)
players.push_back(GameParticipant());
players.resize(playerStartData.size());
if (demoReader != NULL) {
const size_t demoPlayers = demoReader->GetFileHeader().numPlayers;
players.resize(std::max(demoPlayers, playerStartData.size()));
}

for (size_t a = 0; a < aiStartData.size(); ++a) {
const unsigned char skirmishAIId = ReserveNextAvailableSkirmishAIId();
Expand All @@ -248,8 +251,6 @@ void CGameServer::Initialize()

std::copy(playerStartData.begin(), playerStartData.end(), players.begin());
std::copy(teamStartData.begin(), teamStartData.end(), teams.begin());

UpdatePlayerNumberMap();
}

for (unsigned int n = 0; n < (sizeof(SERVER_COMMANDS) / sizeof(std::string)); n++) {
Expand Down Expand Up @@ -465,37 +466,6 @@ std::string CGameServer::GetPlayerNames(const std::vector<int>& indices) const
}


void CGameServer::UpdatePlayerNumberMap() {
unsigned char player = 0;
for (int i = 0; i < 256; ++i, ++player) {
if (i < players.size() && !players[i].isFromDemo)
++player;
playerNumberMap[i] = (i < MAX_PLAYERS) ? player : i; // ignore SERVER_PLAYER, ChatMessage::TO_XXX etc
}
}


bool CGameServer::AdjustPlayerNumber(netcode::RawPacket* buf, int pos, int val) {
if (buf->length <= pos) {
Message(str(format("Warning: Discarding short packet in demo: ID %d, LEN %d") %buf->data[0] %buf->length));
return false;
}
// spectators watching the demo will offset the demo spectators, compensate for this
if (val < 0) {
unsigned char player = playerNumberMap[buf->data[pos]];
if (player >= players.size() && player < MAX_PLAYERS) { // ignore SERVER_PLAYER, ChatMessage::TO_XXX etc
Message(str(format("Warning: Discarding packet with invalid player number in demo: ID %d, LEN %d") %buf->data[0] %buf->length));
return false;
}
buf->data[pos] = player;
}
else {
buf->data[pos] = val;
}
return true;
}


bool CGameServer::SendDemoData(int targetFrameNum)
{
bool ret = false;
Expand Down Expand Up @@ -533,57 +503,7 @@ bool CGameServer::SendDemoData(int targetFrameNum)
break;
}

case NETMSG_AI_STATE_CHANGED: /* many of these messages are not likely to be sent by a spec, but there are cheats */
case NETMSG_ALLIANCE:
case NETMSG_DC_UPDATE:
case NETMSG_DIRECT_CONTROL:
case NETMSG_PATH_CHECKSUM:
case NETMSG_PAUSE: /* this is a synced message and must not be excluded */
case NETMSG_PLAYERINFO:
case NETMSG_PLAYERLEFT:
case NETMSG_PLAYERSTAT:
case NETMSG_SETSHARE:
case NETMSG_SHARE:
case NETMSG_STARTPOS:
case NETMSG_TEAM: {
// TODO: more messages may need adjusted player numbers, or maybe there is a better solution
if (!AdjustPlayerNumber(buf, 1))
continue;
Broadcast(rpkt);
break;
}

case NETMSG_AI_CREATED:
case NETMSG_MAPDRAW:
case NETMSG_PLAYERNAME: {
if (!AdjustPlayerNumber(buf, 2))
continue;
Broadcast(rpkt);
break;
}

case NETMSG_CHAT: {
if (!AdjustPlayerNumber(buf, 2) || !AdjustPlayerNumber(buf, 3))
continue;
Broadcast(rpkt);
break;
}

case NETMSG_AICOMMAND:
case NETMSG_AISHARE:
case NETMSG_COMMAND:
case NETMSG_LUAMSG:
case NETMSG_SELECT:
case NETMSG_SYSTEMMSG: {
if (!AdjustPlayerNumber(buf ,3))
continue;
Broadcast(rpkt);
break;
}

case NETMSG_CREATE_NEWPLAYER: {
if (!AdjustPlayerNumber(buf, 3, players.size()))
continue;
try {
netcode::UnpackPacket pckt(rpkt, 3);
unsigned char spectator, team, playerNum;
Expand All @@ -592,7 +512,7 @@ bool CGameServer::SendDemoData(int targetFrameNum)
pckt >> spectator;
pckt >> team;
pckt >> name;
AddAdditionalUser(name, "", true,(bool)spectator,(int)team); // even though this is a demo, keep the players vector properly updated
AddAdditionalUser(name, "", true, (bool)spectator, (int)team, playerNum); // even though this is a demo, keep the players vector properly updated
} catch (const netcode::UnpackPacketException& ex) {
Message(str(format("Warning: Discarding invalid new player packet in demo: %s") %ex.what()));
continue;
Expand All @@ -610,8 +530,6 @@ bool CGameServer::SendDemoData(int targetFrameNum)
break;
}
case NETMSG_CCOMMAND: {
if (!AdjustPlayerNumber(buf ,3))
continue;
try {
CommandMessage msg(rpkt);
const Action& action = msg.GetAction();
Expand Down Expand Up @@ -856,14 +774,21 @@ void CGameServer::Update()
}
else {
for (size_t a = 0; a < players.size(); ++a) {
if (!players[a].isFromDemo) {
if (players[a].myState == GameParticipant::CONNECTED) { // send pathing status
if (players[a].isFromDemo)
continue;

switch (players[a].myState) {
case GameParticipant::CONNECTED: {
// send pathing status
if (players[a].cpuUsage > 0)
Broadcast(CBaseNetProtocol::Get().SendPlayerInfo(a, players[a].cpuUsage, PATHING_FLAG));
}
else {
} break;
case GameParticipant::INGAME:
case GameParticipant::DISCONNECTED: {
Broadcast(CBaseNetProtocol::Get().SendPlayerInfo(a, 0, 0)); // reset status
}
} break;
case GameParticipant::UNCONNECTED:
default: break;
}
}
}
Expand Down Expand Up @@ -2615,20 +2540,26 @@ bool CGameServer::CheckPlayersPassword(const int playerNum, const std::string& p
}


void CGameServer::AddAdditionalUser(const std::string& name, const std::string& passwd, bool fromDemo, bool spectator, int team)
void CGameServer::AddAdditionalUser(const std::string& name, const std::string& passwd, bool fromDemo, bool spectator, int team, int playerNum)
{
GameParticipant buf;
buf.isFromDemo = fromDemo;
buf.name = name;
buf.spectator = spectator;
buf.team = team;
buf.isMidgameJoin = true;
if (playerNum < 0)
playerNum = players.size();
if (playerNum >= players.size())
players.resize(playerNum + 1);

GameParticipant& p = players[playerNum];
assert(p.myState == GameParticipant::UNCONNECTED); // we only add _new_ players here, we don't handle reconnects here!
p.name = name;
p.spectator = spectator;
p.team = team;
p.isMidgameJoin = true;
p.isFromDemo = fromDemo;
if (!passwd.empty())
buf.SetValue("password", passwd);
players.push_back(buf);
UpdatePlayerNumberMap();
p.SetValue("password", passwd);

// inform all the players of the newcomer
if (!fromDemo)
Broadcast(CBaseNetProtocol::Get().SendCreateNewPlayer(players.size() -1, buf.spectator, buf.team, buf.name)); // inform all the players of the newcomer
Broadcast(CBaseNetProtocol::Get().SendCreateNewPlayer(playerNum, p.spectator, p.team, p.name));
}


Expand All @@ -2637,14 +2568,15 @@ unsigned CGameServer::BindConnection(std::string name, const std::string& passwd
Message(str(format("%s attempt from %s") %(reconnect ? "Reconnection" : "Connection") %name));
Message(str(format(" -> Version: %s") %version));
Message(str(format(" -> Address: %s") %link->GetFullAddress()), false);
size_t newPlayerNumber = players.size();

if (link->CanReconnect())
canReconnect = true;

std::string errmsg = "";
bool terminate = false;

size_t newPlayerNumber = players.size();

// find the player in the current list
for (size_t i = 0; i < players.size(); ++i) {
const GameParticipant& p = players[i];
Expand Down Expand Up @@ -2734,11 +2666,13 @@ unsigned CGameServer::BindConnection(std::string name, const std::string& passwd
newPlayer.SendData(CBaseNetProtocol::Get().SendSetPlayerNum((unsigned char)newPlayerNumber));

// after gamedata and playerNum, the player can start loading
for (std::list< std::vector<boost::shared_ptr<const netcode::RawPacket> > >::const_iterator lit = packetCache.begin(); lit != packetCache.end(); ++lit)
for (std::vector<boost::shared_ptr<const netcode::RawPacket> >::const_iterator vit = lit->begin(); vit != lit->end(); ++vit)
newPlayer.SendData(*vit); // throw at him all stuff he missed until now
// throw at him all stuff he missed until now
for (auto& pv: packetCache)
for (boost::shared_ptr<const netcode::RawPacket>& p: pv)
newPlayer.SendData(p);

if (demoReader == NULL || myGameSetup->demoName.empty()) { // gamesetup from demo?
if (demoReader == NULL || myGameSetup->demoName.empty()) {
// player wants to play -> join team
if (!newPlayer.spectator) {
unsigned newPlayerTeam = newPlayer.team;
if (!teams[newPlayerTeam].IsActive()) { // create new team
Expand Down
5 changes: 1 addition & 4 deletions rts/Net/GameServer.h
Expand Up @@ -175,9 +175,6 @@ class CGameServer

void AddToPacketCache(boost::shared_ptr<const netcode::RawPacket>& pckt);

bool AdjustPlayerNumber(netcode::RawPacket* buf, int pos, int val = -1);
void UpdatePlayerNumberMap();

float GetDemoTime() const;

private:
Expand Down Expand Up @@ -254,7 +251,7 @@ class CGameServer
void InternalSpeedChange(float newSpeed);
void UserSpeedChange(float newSpeed, int player);

void AddAdditionalUser( const std::string& name, const std::string& passwd, bool fromDemo = false, bool spectator = true, int team = 0);
void AddAdditionalUser( const std::string& name, const std::string& passwd, bool fromDemo = false, bool spectator = true, int team = 0, int playerNum = -1);
unsigned char ReserveNextAvailableSkirmishAIId();
void FreeSkirmishAIId(const unsigned char skirmishAIId);

Expand Down
4 changes: 4 additions & 0 deletions rts/Net/NetCommands.cpp
Expand Up @@ -1282,6 +1282,10 @@ void CGame::ClientReadNet()
eventHandler.TeamChanged(player.team);
}

CDemoRecorder* record = clientNet->GetDemoRecorder();
if (record != NULL) {
record->AddNewPlayer(player.name, playerNum);
}
AddTraffic(-1, packetCode, dataLength);
} catch (const netcode::UnpackPacketException& ex) {
LOG_L(L_ERROR, "[Game::%s] invalid NETMSG_CREATE_NEWPLAYER: %s", __FUNCTION__, ex.what());
Expand Down
9 changes: 9 additions & 0 deletions rts/System/LoadSave/DemoRecorder.cpp
Expand Up @@ -137,6 +137,15 @@ void CDemoRecorder::InitializeStats(int numPlayers, int numTeams)
teamStats.resize(numTeams);
}


void CDemoRecorder::AddNewPlayer(const std::string& name, int playerNum)
{
if (playerNum >= playerStats.size()) {
playerStats.resize(playerNum + 1);
}
}


/** @brief Set (overwrite) the CPlayer::Statistics for player playerNum */
void CDemoRecorder::SetPlayerStats(int playerNum, const PlayerStatistics& stats)
{
Expand Down
1 change: 1 addition & 0 deletions rts/System/LoadSave/DemoRecorder.h
Expand Up @@ -33,6 +33,7 @@ class CDemoRecorder : public CDemo
void SetGameID(const unsigned char* buf);
void SetTime(int gameTime, int wallclockTime);

void AddNewPlayer(const std::string& name, int playerNum);
void InitializeStats(int numPlayers, int numTeams);
void SetPlayerStats(int playerNum, const PlayerStatistics& stats);
void SetTeamStats(int teamNum, const std::list< TeamStatistics >& stats);
Expand Down

0 comments on commit 7d0351a

Please sign in to comment.