mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-23 06:57:23 +00:00
Client platform version can be retrieved live with /ids and is also recorded in the playerdetail module.
234 lines
5.9 KiB
C++
234 lines
5.9 KiB
C++
#include "server/player.h"
|
|
#include "base/tick.h"
|
|
|
|
namespace wi {
|
|
|
|
// lag time period to be declared laggy player
|
|
#define kctLagGrace 200
|
|
|
|
// to become non-laggy, the player must be not laggy for this period
|
|
#define kctLagRedemption 0
|
|
|
|
// if still laggy after this period, recommend kill
|
|
#define kctLagKill 3000
|
|
|
|
Player::Player() {
|
|
Init(0);
|
|
}
|
|
|
|
void Player::Init(Pid pid) {
|
|
anonymous_ = false;
|
|
havestats_ = false;
|
|
cur_ = 0;
|
|
wf_ = 0;
|
|
pid_ = pid;
|
|
side_ = ksideNeutral;
|
|
endpoint_ = NULL;
|
|
lag_ = knLagNone;
|
|
nLagState_ = knLagNone;
|
|
tLagStart_ = 0;
|
|
tLastLag_ = 0;
|
|
updates_ = -1;
|
|
strncpyz(name_, "Unfulfilled", sizeof(name_));
|
|
memset(alatr_, 0, sizeof(alatr_));
|
|
memset(&ws_, 0, sizeof(ws_));
|
|
memset(did_, 0, sizeof(did_));
|
|
memset(platform_, 0, sizeof(platform_));
|
|
}
|
|
|
|
void Player::SetEndpoint(Endpoint *endpoint) {
|
|
endpoint_ = endpoint;
|
|
if (endpoint == NULL) {
|
|
return;
|
|
}
|
|
strncpyz(name_, endpoint->name(), sizeof(name_));
|
|
anonymous_ = endpoint->anonymous();
|
|
address_ = endpoint->xpump().socket()->GetRemoteAddress();
|
|
strncpyz(did_, endpoint->did(), sizeof(did_));
|
|
strncpyz(platform_, endpoint->platform(), sizeof(platform_));
|
|
lag_ = knLagNone;
|
|
nLagState_ = knLagNone;
|
|
tLagStart_ = 0;
|
|
tLastLag_ = 0;
|
|
}
|
|
|
|
int Player::GetLagTimeout() {
|
|
// Return seconds until this player gets to the kill state
|
|
|
|
long64 ctElapsed = base::GetTickCount() - tLagStart_;
|
|
if (ctElapsed > kctLagKill) {
|
|
return 0;
|
|
}
|
|
return (int)((kctLagKill - ctElapsed + 50) / 100);
|
|
}
|
|
|
|
void Player::SetLagState(int nLagState) {
|
|
nLagState_ = nLagState;
|
|
tLastLag_ = base::GetTickCount();
|
|
tLagStart_ = tLastLag_;
|
|
}
|
|
|
|
int Player::UpdateLagState(long cUpdates) {
|
|
if (wf_ & kfPlrDisconnectBroadcasted) {
|
|
SetLagState(knLagNone);
|
|
return knLagNone;
|
|
}
|
|
|
|
if (updates_ < cUpdates) {
|
|
// Player is behind
|
|
|
|
switch (nLagState_) {
|
|
case knLagNone:
|
|
// Remember that pplr is lagging and when this started
|
|
|
|
tLagStart_ = base::GetTickCount();
|
|
nLagState_ = knLagGrace;
|
|
break;
|
|
|
|
case knLagGrace:
|
|
// This state is effectively a grace period. If the player remains
|
|
// laggy through this period, it becomes guilty of lag
|
|
|
|
if (base::GetTickCount() - tLagStart_ >= kctLagGrace) {
|
|
nLagState_ = knLagGuilty;
|
|
tLastLag_ = base::GetTickCount();
|
|
}
|
|
break;
|
|
|
|
case knLagGuilty:
|
|
case knLagKill:
|
|
// This player has lagged long enough to be guilty as charged. Now
|
|
// the player needs to be *not* laggy over a fixed period to get
|
|
// out of this state
|
|
|
|
tLastLag_ = base::GetTickCount();
|
|
if (base::GetTickCount() - tLagStart_ >= kctLagKill) {
|
|
nLagState_ = knLagKill;
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
// Player is not behind
|
|
|
|
switch (nLagState_) {
|
|
case knLagNone:
|
|
// All is ok
|
|
|
|
break;
|
|
|
|
case knLagGrace:
|
|
// This player has "caught up" during the grace period. Assume
|
|
// there is no lag now.
|
|
|
|
nLagState_ = knLagNone;
|
|
break;
|
|
|
|
case knLagGuilty:
|
|
case knLagKill:
|
|
// Guilty of lag and yet the player has caught up. If the player
|
|
// can keep this state it will be declared not laggy
|
|
|
|
if (base::GetTickCount() - tLastLag_ >= kctLagRedemption) {
|
|
nLagState_ = knLagNone;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nLagState_;
|
|
}
|
|
|
|
void Player::AddLatencyRecord(LatencyRecord *platr) {
|
|
memmove(&alatr_[1], &alatr_[0], sizeof(alatr_) - sizeof(alatr_[0]));
|
|
alatr_[0] = *platr;
|
|
clatr_++;
|
|
if (clatr_ > ARRAYSIZE(alatr_)) {
|
|
clatr_ = ARRAYSIZE(alatr_);
|
|
}
|
|
updates_ = platr->cUpdatesBlock;
|
|
}
|
|
|
|
int Player::GetLatencyRecordCount() {
|
|
return clatr_;
|
|
}
|
|
|
|
const LatencyRecord *Player::GetLatencyRecord(int i) {
|
|
if (i < 0 || i >= clatr_) {
|
|
return NULL;
|
|
}
|
|
return &alatr_[i];
|
|
}
|
|
|
|
void Player::SaveWinStats(const WinStats& ws, bool lock) {
|
|
// Ignore if already locked
|
|
if (ws_.ff & kfwsLocked) {
|
|
return;
|
|
}
|
|
|
|
// Otherwise keep as most recent. Filter out flags from these win stats,
|
|
// since these came from the client. Flags will be added in later, when
|
|
// these results get posted.
|
|
ws_ = ws;
|
|
ws_.ff &= (kfwsWinner | kfwsLoser);
|
|
if (lock) {
|
|
ws_.ff |= kfwsLocked;
|
|
}
|
|
havestats_ = true;
|
|
}
|
|
|
|
void Player::GetPlayerStats(PlayerStats *ps) {
|
|
// Players can be human or computer. Humans can be in a game, and leave
|
|
// before the game ends. Losers are given a chance to dispute winners.
|
|
// Clients may or may not have sent win stats.
|
|
|
|
memset(ps, 0, sizeof(*ps));
|
|
strncpyz(ps->name, name_, sizeof(ps->name));
|
|
ps->pid = pid_;
|
|
address_.IPAsString(ps->ip, sizeof(ps->ip));
|
|
strncpyz(ps->did, did_, sizeof(ps->did));
|
|
strncpyz(ps->platform, platform_, sizeof(ps->platform));
|
|
|
|
// If this player was never used, then there are no stats for it
|
|
if (!(wf_ & kfPlrInUse)) {
|
|
return;
|
|
}
|
|
|
|
// Return stats that exist, if any
|
|
if (havestats_) {
|
|
ps->ws = ws_;
|
|
ps->ws.ff |= kfwsReceivedStats;
|
|
}
|
|
|
|
// Humans can join, and then leave. When they leave, the player turns
|
|
// into a computer, with kfPlrComputer set. kfPlrHumanJoined means this
|
|
// player started out human (even if the player didn't stay till the end
|
|
// of the game).
|
|
if (wf_ & kfPlrHumanJoined) {
|
|
ps->ws.ff |= kfwsHuman;
|
|
} else {
|
|
ps->ws.ff |= kfwsComputer;
|
|
}
|
|
|
|
// Remember if the player is anonymous.
|
|
if (anonymous_) {
|
|
ps->ws.ff |= kfwsAnonymous;
|
|
}
|
|
|
|
#if 0
|
|
// not implemented
|
|
// Winner/Loser is already encoded in WinStats.
|
|
// If this player challenged the winner, note it
|
|
if (wf_ & kfPlrChallengeWinner) {
|
|
ps->ws.ff |= kfwsWinChallenger;
|
|
}
|
|
#endif
|
|
|
|
// If this player was removed at game start, remember that since the
|
|
// stats are invalid.
|
|
if (wf_ & kfPlrRemovedAtGameStart) {
|
|
ps->ws.ff |= kfwsRemovedAtGameStart;
|
|
}
|
|
}
|
|
|
|
} // namespace wi
|