hostile-takeover/mpshared/netmessage.cpp
Scott Ludwig 3618d1a6b2 Fix 32/64 bit MP message structure packing issues
- 32 bit and 64 bit should work the same way now (need to test).
  The server compiles 32 bit at the moment.
- 8 bytes from the NetMessage header were removed, and the protocol
  version was bumped.
2016-01-01 14:26:25 -08:00

445 lines
13 KiB
C++

#include "inc/basictypes.h"
#include "inc/rip.h"
#include "mpshared/netmessage.h"
#include "mpshared/mpht.h"
#include "base/bytebuffer.h"
#include "base/format.h"
namespace wi {
int gatGameSpeeds[15] = {
64, 48, 32, 24, 16, 12, 10, 8, 7, 6, 5, 4, 3, 2, 1
};
#ifndef __CPU_68K
#define SwapWord(x) ((((x)&0xFF)<<8) | (((x)&0xFF00)>>8))
#define SwapDword(x) ((((x)&0xFF)<<24) | (((x)&0xFF00)<<8) | (((x)&0xFF0000)>>8) | (((x)&0xFF000000)>>24))
void MessageByteOrderSwap(word cmsgs, Message *pmsg, bool fNative)
{
for (; cmsgs != 0; cmsgs--, pmsg++) {
word mid = pmsg->mid;
if (!fNative) {
mid = base::ByteBuffer::HostToNetWord(pmsg->mid);
}
pmsg->mid = SwapWord(pmsg->mid);
pmsg->smidSender = SwapWord(pmsg->smidSender);
pmsg->smidReceiver = SwapWord(pmsg->smidReceiver);
pmsg->tDelivery = SwapDword(pmsg->tDelivery);
switch (mid) {
case kmidHit:
case kmidNearbyAllyHit:
case kmidDelete:
case kmidEnemyNearby:
case kmidPowerLowHigh:
case kmidMoveWaitingNearby:
case kmidBeingUpgraded:
case kmidUpgradeComplete:
case kmidAnimationComplete:
case kmidBuildComplete:
case kmidFireComplete:
case kmidSpawnSmoke:
case kmidGalaxiteDelivery:
case kmidMoveAction:
case kmidAttackAction:
case kmidGuardAction:
case kmidGuardVicinityAction:
case kmidGuardAreaAction:
case kmidHuntEnemiesAction:
case kmidFire:
case kmidHeal:
case kmidPlaySfx:
// These are only sent. If they arrive here, it's a mistake
Assert(false, "Message %d is classified as sent only", pmsg->mid);
break;
default:
// Message unknown, not classified yet
Assert(false, "Message %d unknown, not classified yet", pmsg->mid);
break;
// Posted
case kmidMineCommand:
pmsg->MineCommand.gidTarget = SwapWord(pmsg->MineCommand.gidTarget);
pmsg->MineCommand.wptTarget.wx = SwapWord(pmsg->MineCommand.wptTarget.wx);
pmsg->MineCommand.wptTarget.wy = SwapWord(pmsg->MineCommand.wptTarget.wy);
break;
case kmidAttackCommand:
pmsg->AttackCommand.gidTarget = SwapWord(pmsg->AttackCommand.gidTarget);
pmsg->AttackCommand.wptTarget.wx = SwapWord(pmsg->AttackCommand.wptTarget.wx);
pmsg->AttackCommand.wptTarget.wy = SwapWord(pmsg->AttackCommand.wptTarget.wy);
pmsg->AttackCommand.wptTargetCenter.wx = SwapWord(pmsg->AttackCommand.wptTargetCenter.wx);
pmsg->AttackCommand.wptTargetCenter.wy = SwapWord(pmsg->AttackCommand.wptTargetCenter.wy);
pmsg->AttackCommand.tcTargetRadius = SwapWord(pmsg->AttackCommand.tcTargetRadius);
pmsg->AttackCommand.wcMoveDistPerUpdate = SwapWord(pmsg->AttackCommand.wcMoveDistPerUpdate);
break;
case kmidMoveCommand:
pmsg->MoveCommand.gidTarget = SwapWord(pmsg->MoveCommand.gidTarget);
pmsg->MoveCommand.wptTarget.wx = SwapWord(pmsg->MoveCommand.wptTarget.wx);
pmsg->MoveCommand.wptTarget.wy = SwapWord(pmsg->MoveCommand.wptTarget.wy);
pmsg->MoveCommand.wptTargetCenter.wx = SwapWord(pmsg->MoveCommand.wptTargetCenter.wx);
pmsg->MoveCommand.wptTargetCenter.wy = SwapWord(pmsg->MoveCommand.wptTargetCenter.wy);
pmsg->MoveCommand.tcTargetRadius = SwapWord(pmsg->MoveCommand.tcTargetRadius);
pmsg->MoveCommand.wcMoveDistPerUpdate = SwapWord(pmsg->MoveCommand.wcMoveDistPerUpdate);
break;
case kmidBuildOtherCommand:
pmsg->BuildOtherCommand.ut = SwapWord(pmsg->BuildOtherCommand.ut);
pmsg->BuildOtherCommand.wpt.wx = SwapWord(pmsg->BuildOtherCommand.wpt.wx);
pmsg->BuildOtherCommand.wpt.wy = SwapWord(pmsg->BuildOtherCommand.wpt.wy);
break;
case kmidAbortBuildOtherCommand:
pmsg->AbortBuildOtherCommand.ut = SwapWord(pmsg->AbortBuildOtherCommand.ut);
break;
case kmidUpgradeCommand:
pmsg->UpgradeCommand.wfUpgrade = SwapWord(pmsg->UpgradeCommand.wfUpgrade);
break;
case kmidDeliverCommand:
pmsg->DeliverCommand.gidTarget = SwapWord(pmsg->DeliverCommand.gidTarget);
break;
case kmidTransformCommand:
case kmidSelfDestructCommand:
case kmidRepairCommand:
case kmidAbortUpgradeCommand:
// No parameters
break;
case kmidPlayerDisconnect:
pmsg->PlayerDisconnect.pid = SwapWord(pmsg->PlayerDisconnect.pid);
pmsg->PlayerDisconnect.nReason =
SwapWord(pmsg->PlayerDisconnect.nReason);
break;
}
}
}
void SwapGameParams(GameParams *prams)
{
prams->packid.id = SwapDword(prams->packid.id);
prams->dwVersionSimulation = SwapDword(prams->dwVersionSimulation);
prams->tGameSpeed = SwapDword(prams->tGameSpeed);
}
void NetMessageByteOrderSwap(NetMessage *pnm, bool fNative)
{
// Swap endian order
word nmid;
if (fNative) {
nmid = pnm->nmid;
} else {
nmid = SwapWord(pnm->nmid);
}
pnm->nmid = SwapWord(pnm->nmid);
pnm->cb = SwapWord(pnm->cb);
switch (nmid) {
case knmidCsPlayerJoin:
case knmidCsClientReady:
case knmidScCantAcceptMoreConnections:
case knmidScServerInfo:
case knmidCsConnect:
case knmidCsRequestBeginGame:
case knmidScBeginGameFail:
case knmidCsLagAcknowledge:
case knmidCsChallengeWin:
// Nothing to do for these
break;
case knmidCsWinStats:
{
WinStatsNetMessage *pwsnm = (WinStatsNetMessage *)pnm;
pwsnm->ws.cCreditsAcquired = SwapDword(pwsnm->ws.cCreditsAcquired);
pwsnm->ws.cCreditsConsumed = SwapDword(pwsnm->ws.cCreditsConsumed);
pwsnm->ws.sidm = SwapWord(pwsnm->ws.sidm);
pwsnm->ws.sidmAllies = SwapWord(pwsnm->ws.sidmAllies);
pwsnm->ws.cEnemyMobileUnitsKilled =
SwapWord(pwsnm->ws.cEnemyMobileUnitsKilled);
pwsnm->ws.cEnemyStructuresKilled =
SwapWord(pwsnm->ws.cEnemyStructuresKilled);
pwsnm->ws.cMobileUnitsLost = SwapWord(pwsnm->ws.cMobileUnitsLost);
pwsnm->ws.cStructuresLost = SwapWord(pwsnm->ws.cStructuresLost);
pwsnm->ws.ff = SwapWord(pwsnm->ws.ff);
for (int i = 0; i < ARRAYSIZE(pwsnm->ws.acut); i++) {
pwsnm->ws.acut[i] = SwapWord(pwsnm->ws.acut[i]);
}
for (int i = 0; i < ARRAYSIZE(pwsnm->ws.acutBuilt); i++) {
pwsnm->ws.acutBuilt[i] = SwapWord(pwsnm->ws.acutBuilt[i]);
}
}
break;
case knmidScCheckWin:
{
CheckWinNetMessage *pcwnm = (CheckWinNetMessage *)pnm;
pcwnm->pid = SwapWord(pcwnm->pid);
}
break;
case knmidScGameParams:
{
GameParamsNetMessage *pgpnm = (GameParamsNetMessage *)pnm;
SwapGameParams(&pgpnm->rams);
}
break;
case knmidScBeginGame:
{
BeginGameNetMessage *pbgnm = (BeginGameNetMessage *)pnm;
pbgnm->ulRandomSeed = SwapDword(pbgnm->ulRandomSeed);
}
break;
case knmidScPlayersUpdate:
{
PlayersUpdateNetMessage *punm = (PlayersUpdateNetMessage *)pnm;
int cplrr = fNative ? punm->cplrr : SwapWord(punm->cplrr);
punm->cplrr = SwapWord(punm->cplrr);
for (int iplrr = 0; iplrr < cplrr; iplrr++) {
PlayerRecord *pplrr = &punm->aplrr[iplrr];
pplrr->pid = SwapWord(pplrr->pid);
pplrr->side = SwapWord(pplrr->side);
pplrr->wf = SwapWord(pplrr->wf);
}
}
break;
case knmidCsClientCommands:
{
ClientCommandsNetMessage *pccnm = (ClientCommandsNetMessage *)pnm;
MessageByteOrderSwap(fNative ? pccnm->cmsgCommands : SwapWord(pccnm->cmsgCommands), pccnm->amsgCommands, fNative);
pccnm->cmsgCommands = SwapWord(pccnm->cmsgCommands);
}
break;
case knmidScUpdate:
{
UpdateNetMessage *punm = (UpdateNetMessage *)pnm;
MessageByteOrderSwap(fNative ? punm->cmsgCommands : SwapWord(punm->cmsgCommands), punm->amsgCommands, fNative);
punm->cmsgCommands = SwapWord(punm->cmsgCommands);
punm->cUpdatesBlock = SwapDword(punm->cUpdatesBlock);
punm->cUpdatesSync = SwapDword(punm->cUpdatesSync);
}
break;
case knmidCsUpdateResult:
{
UpdateResultNetMessage *purnm = (UpdateResultNetMessage *)pnm;
purnm->ur.cUpdatesBlock = SwapDword(purnm->ur.cUpdatesBlock);
purnm->ur.hash = SwapDword(purnm->ur.hash);
purnm->ur.cmsLatency = SwapDword(purnm->ur.cmsLatency);
}
break;
case knmidScLagNotify:
{
LagNotifyNetMessage *plnnm = (LagNotifyNetMessage *)pnm;
plnnm->pidLagging = SwapWord(plnnm->pidLagging);
plnnm->cSeconds = SwapWord(plnnm->cSeconds);
}
break;
case knmidScPlayerDisconnect:
{
PlayerDisconnectNetMessage *ppdnm = (PlayerDisconnectNetMessage *)pnm;
ppdnm->pid = SwapWord(ppdnm->pid);
ppdnm->nReason = SwapWord(ppdnm->nReason);
}
break;
case knmidCsKillLaggingPlayer:
{
KillLaggingPlayerNetMessage *pklpnm =
(KillLaggingPlayerNetMessage *)pnm;
pklpnm->pid = SwapWord(pklpnm->pid);
pklpnm->fYes = SwapWord(pklpnm->fYes);
}
break;
case knmidCsPlayerResign:
{
PlayerResignNetMessage *pprnm = (PlayerResignNetMessage *)pnm;
pprnm->pid = SwapWord(pprnm->pid);
}
break;
case knmidScSyncError:
{
SyncErrorNetMessage *psenm = (SyncErrorNetMessage *)pnm;
for (int i = 0; i < kcPlayersMax; i++) {
psenm->aur[i].cUpdatesBlock =
SwapDword(psenm->aur[i].cUpdatesBlock);
psenm->aur[i].hash = SwapDword(psenm->aur[i].hash);
psenm->aur[i].cmsLatency =
SwapDword(psenm->aur[i].cmsLatency);
}
psenm->urLastStraw.cUpdatesBlock =
SwapDword(psenm->urLastStraw.cUpdatesBlock);
psenm->urLastStraw.hash = SwapDword(psenm->urLastStraw.hash);
psenm->urLastStraw.cmsLatency =
SwapDword(psenm->urLastStraw.cmsLatency);
}
break;
default:
Assert("Unhandled knmid! (%d)", nmid);
break;
}
}
#endif // ifndef __CPU_68K
bool FindZero(const char *psz, int cb)
{
for (const char *pszT = psz; pszT < &psz[cb]; pszT++) {
if (*pszT == 0) {
return true;
}
}
return false;
}
bool ValidateGameParams(const GameParams& params)
{
bool fFound = false;
for (int i = 0; i < ARRAYSIZE(gatGameSpeeds); i++) {
if (params.tGameSpeed == gatGameSpeeds[i]) {
fFound = true;
break;
}
}
if (!fFound) {
return false;
}
if (!FindZero(params.szLvlFilename, sizeof(params.szLvlFilename))) {
return false;
}
return true;
}
#ifdef RELEASE_LOGGING
const char *GameParamsToString(const GameParams& params) {
char szHash[33];
strncpyz(szHash, base::Format::ToHex(params.packid.hash,
sizeof(params.packid.hash)), sizeof(szHash));
return base::Format::ToString(
"id=%d hash=%s dwVersionSimulation=%d tGameSpeed=%ld szLvlFilename=\"%s\'",
params.packid.id, szHash, params.dwVersionSimulation,
params.tGameSpeed, params.szLvlFilename);
}
#endif
#ifdef RELEASE_LOGGING
void LogGameParams(const GameParams& params) {
RLOG() << GameParamsToString(params);
}
#endif
#ifdef DEBUG_LOGGING
const char *PszFromNetMessage(NetMessage *pnm)
{
static char s_szT[256];
switch (pnm->nmid) {
case knmidScCantAcceptMoreConnections:
return "ScCantAcceptMoreConnections";
case knmidScServerInfo:
((ServerInfoNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsClientCommands:
((ClientCommandsNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScUpdate:
((UpdateNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScGameParams:
((GameParamsNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScBeginGame:
((BeginGameNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsClientReady:
return "CsClientReady";
case knmidCsPlayerJoin:
((PlayerJoinNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScPlayersUpdate:
((PlayersUpdateNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsUpdateResult:
((UpdateResultNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsPlayerResign:
((PlayerResignNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsRequestBeginGame:
return "CsRequestBeginGame";
case knmidScBeginGameFail:
return "ScBeginGameFail";
case knmidScPlayerDisconnect:
((PlayerDisconnectNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsKillLaggingPlayer:
((KillLaggingPlayerNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScLagNotify:
((LagNotifyNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsLagAcknowledge:
((LagAcknowledgeNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScSyncError:
return "ScSyncError";
case knmidCsWinStats:
((WinStatsNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidScCheckWin:
((CheckWinNetMessage *)pnm)->ToString(s_szT, sizeof(s_szT));
break;
case knmidCsChallengeWin:
return "CsChallengeWin";
default:
sprintf(s_szT, "NetMessage(nmid: %d)", pnm->nmid);
break;
}
return s_szT;
}
#endif
} // namespace wi