hostile-takeover/mpshared/netmessage.h
2016-01-03 23:19:26 -08:00

565 lines
14 KiB
C++

#ifndef __NETMESSAGE_H__
#define __NETMESSAGE_H__
#include "inc/basictypes.h"
#include "inc/rip.h"
#include "mpshared/mpht.h"
#include "mpshared/misc.h"
#include "mpshared/side.h"
#include "base/format.h"
#include "base/log.h"
#include "base/misc.h"
#include <stdio.h>
#include <string.h>
//---------------------------------------------------------------------------
// Network and multiplayer stuff
// NOTE: be sure to update PszFromNetMessage in Comm.cpp if you change/add/remove NetMessageIds
namespace wi {
class NetMessage;
#ifdef DEBUG_LOGGING
const char *PszFromNetMessage(NetMessage *pnm);
#endif
#ifdef RELEASE_LOGGING
void LogGameParams(const GameParams& params);
const char *GameParamsToString(const GameParams& params);
#endif
const int kcbGameName = 80;
typedef word NetMessageId; // nmid
const NetMessageId knmidScCantAcceptMoreConnections = 1;
const NetMessageId knmidScServerInfo = 2;
const NetMessageId knmidCsClientCommands = 3;
const NetMessageId knmidScUpdate = 4;
const NetMessageId knmidScGameParams = 5;
const NetMessageId knmidScBeginGame = 6;
const NetMessageId knmidCsClientReady = 7;
const NetMessageId knmidCsPlayerJoin = 8;
const NetMessageId knmidScPlayersUpdate = 9;
const NetMessageId knmidCsUpdateResult = 10;
//const NetMessageId knmidGameHostFound = 11;
const NetMessageId knmidCsConnect = 12;
const NetMessageId knmidScLagNotify = 13;
const NetMessageId knmidScPlayerDisconnect = 14;
const NetMessageId knmidCsPlayerResign = 15;
const NetMessageId knmidCsRequestBeginGame = 16;
const NetMessageId knmidScBeginGameFail = 17;
const NetMessageId knmidCsKillLaggingPlayer = 18;
const NetMessageId knmidScSyncError = 19;
const NetMessageId knmidCsLagAcknowledge = 20;
const NetMessageId knmidCsWinStats = 21;
const NetMessageId knmidScCheckWin = 22;
const NetMessageId knmidCsChallengeWin = 23;
const NetMessageId knmidMax = 24;
#pragma pack(push, 2)
class NetMessage // nm
{
public:
NetMessage() {}
NetMessage(NetMessageId nmid);
word cb; // size of whole message, including these fields
NetMessageId nmid;
// After this is dword aligned
};
inline NetMessage::NetMessage(NetMessageId nmid)
{
this->nmid = nmid;
this->cb = sizeof(NetMessage);
//this->pnmNext = NULL;
CompileAssert((sizeof(this) % 4) == 0);
}
class ServerInfoNetMessage : public NetMessage {
public:
ServerInfoNetMessage();
ServerInfoNetMessage(char *pszGameName);
char m_szGameName[kcbGameName];
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScServerInfo(gameName: \"%s\")", m_szGameName);
}
#endif
};
inline ServerInfoNetMessage::ServerInfoNetMessage()
{
nmid = knmidScServerInfo;
cb = sizeof(ServerInfoNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
inline ServerInfoNetMessage::ServerInfoNetMessage(char *pszGameName)
{
nmid = knmidScServerInfo;
cb = sizeof(ServerInfoNetMessage);
strncpyz(m_szGameName, pszGameName, sizeof(m_szGameName));
CompileAssert((sizeof(this) % 4) == 0);
}
class ConnectNetMessage : public NetMessage {
public:
ConnectNetMessage();
#ifdef LOGGING
void ToString(char *psz, int cb) {
strncpyz(psz, "CsConnect", cb);
}
#endif
};
inline ConnectNetMessage::ConnectNetMessage()
{
nmid = knmidCsConnect;
cb = sizeof(ConnectNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class BeginGameNetMessage : public NetMessage {
public:
BeginGameNetMessage();
unsigned int ulRandomSeed;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScBeginGame(seed: %u)", ulRandomSeed);
}
#endif
};
inline BeginGameNetMessage::BeginGameNetMessage()
{
nmid = knmidScBeginGame;
cb = sizeof(BeginGameNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class ClientCommandsNetMessage : public NetMessage {
public:
ClientCommandsNetMessage();
word cmsgCommands;
word wDummy; // for aligning the Messages on 68K
Message amsgCommands[1];
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "CsClientCommands(cmsg: %d)", cmsgCommands);
for (int i = 0; i < cmsgCommands; i++) {
int cch = (int)strlen(psz);
if ((cb - (cch + 1)) <= 0)
break;
snprintf(&psz[cch], cb - cch, ", %d", amsgCommands[i].mid);
}
}
#endif
};
inline ClientCommandsNetMessage::ClientCommandsNetMessage()
{
Assert((sizeof(this) % 4) == 0);
}
class UpdateNetMessage : public NetMessage {
public:
UpdateNetMessage();
int cUpdatesBlock;
int cUpdatesSync;
word cmsgCommands;
word wDummy; // for aligning the Messages on 68K
Message amsgCommands[1];
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScUpdate(cmsg: %d, cUpdatesBlock: %d, cUpdatesSync: %d)",
cmsgCommands, cUpdatesBlock, cUpdatesSync);
}
#endif
};
inline UpdateNetMessage::UpdateNetMessage()
{
Assert((sizeof(this) % 4) == 0);
}
class GameParamsNetMessage : public NetMessage {
public:
GameParamsNetMessage();
GameParams rams;
#ifdef LOGGING
void ToString(char *psz, int cb) {
strncpyz(psz, GameParamsToString(rams), cb);
}
#endif
};
inline GameParamsNetMessage::GameParamsNetMessage()
{
nmid = knmidScGameParams;
cb = sizeof(GameParamsNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class PlayerJoinNetMessage : public NetMessage {
public:
PlayerJoinNetMessage();
char szPlayerName[kcbPlayerName];
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "CsPlayerJoin(%s)", szPlayerName);
}
#endif
};
inline PlayerJoinNetMessage::PlayerJoinNetMessage()
{
nmid = knmidCsPlayerJoin;
cb = sizeof(PlayerJoinNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
const byte kfPlrrReady = 0x01;
const byte kfPlrrLocal = 0x02;
const byte kfPlrrComputer = 0x04;
const byte kfPlrrComputerOvermind = 0x08;
const byte kfPlrrUnfulfilled = 0x10;
const byte kfPlrrCreator = 0x20;
struct PlayerRecord // plrr
{
Pid pid; // 4
Side side; // 2
word wf; // 2
char szName[kcbPlayerName]; // 32
};
class PlayersUpdateNetMessage : public NetMessage {
public:
PlayersUpdateNetMessage();
word cplrr;
word wDummy; // for alignment
PlayerRecord aplrr[1];
#ifdef LOGGING
void ToString(char *psz, int cb) {
int cHuman = 0;
for (int i = 0; i < cplrr; i++) {
if ((aplrr[i].wf & (kfPlrrComputer | kfPlrrUnfulfilled)) == 0) {
cHuman++;
}
}
snprintf(psz, cb, "ScPlayersUpdate(cplrr human: %d)", cHuman);
}
#endif
};
inline PlayersUpdateNetMessage::PlayersUpdateNetMessage()
{
CompileAssert((sizeof(this) % 4) == 0);
}
class UpdateResultNetMessage : public NetMessage { // urnm
public:
UpdateResultNetMessage();
UpdateResult ur;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb,
"CsUpdateResult(cUpdatesBlock: %d, hash %08x, cmsLatency: %d)",
ur.cUpdatesBlock, ur.hash, ur.cmsLatency);
}
#endif
};
inline UpdateResultNetMessage::UpdateResultNetMessage()
{
nmid = knmidCsUpdateResult;
cb = sizeof(UpdateResultNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
struct GameHost { // gh
GameHost *pghNext;
NetAddress nad;
unsigned int msLastContact;
unsigned int id;
char szGameName[kcbGameName];
};
class LagNotifyNetMessage : public NetMessage { // lnnm
public:
LagNotifyNetMessage();
Pid pidLagging;
word cSeconds;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScLagNotify(pidLagging: %d)", pidLagging);
}
#endif
};
inline LagNotifyNetMessage::LagNotifyNetMessage()
{
nmid = knmidScLagNotify;
cb = sizeof(LagNotifyNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class LagAcknowledgeNetMessage : public NetMessage { // lanm
public:
LagAcknowledgeNetMessage();
Pid pidLagging;
word cSeconds;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScLagAcknowledge(pidLagging: %d)", pidLagging);
}
#endif
};
inline LagAcknowledgeNetMessage::LagAcknowledgeNetMessage()
{
nmid = knmidCsLagAcknowledge;
cb = sizeof(LagAcknowledgeNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
#define kfwsReceivedStats 0x0001
#define kfwsWinner 0x0002
#define kfwsLoser 0x0004
#define kfwsWinChallenger 0x0008
#define kfwsComputer 0x0010
#define kfwsHuman 0x0020
#define kfwsAnonymous 0x0040
#define kfwsLocked 0x0080
#define kfwsRemovedAtGameStart 0x0100
#define kfwsMask 0x1ff
struct WinStats {
word sidm;
word sidmAllies;
word cEnemyMobileUnitsKilled;
word cEnemyStructuresKilled;
word cMobileUnitsLost;
word cStructuresLost;
word ff;
word acut[kutMax];
word acutBuilt[kutMax];
word dummy; // to ensure alignment on all platforms
dword cCreditsAcquired;
dword cCreditsConsumed;
};
class WinStatsNetMessage : public NetMessage { // wnm
public:
WinStatsNetMessage();
Pid pid;
word filler;
byte hash[16];
WinStats ws;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "WinStatsNetMessage("
"sidm: %08x, sidmAllies: %08x, "
"cCreditsAcquired: %u, cCreditsConsumed: %u, "
"cEnemyMobileUnitsKilled: %d, cEnemyStructuresKilled: %d, "
"cMobileUnitsLost: %d, cStructuresLost: %d, ff: %08x)",
ws.sidm, ws.sidmAllies,
ws.cCreditsAcquired, ws.cCreditsConsumed,
ws.cEnemyMobileUnitsKilled, ws.cEnemyStructuresKilled,
ws.cMobileUnitsLost, ws.cStructuresLost, ws.ff);
}
#endif
};
inline WinStatsNetMessage::WinStatsNetMessage()
{
memset(this, 0, sizeof(*this));
nmid = knmidCsWinStats;
cb = sizeof(WinStatsNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class CheckWinNetMessage : public NetMessage { // cwnm
public:
CheckWinNetMessage();
Pid pid;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScCheckWin(pid: %d)", pid);
}
#endif
};
inline CheckWinNetMessage::CheckWinNetMessage()
{
nmid = knmidScCheckWin;
cb = sizeof(CheckWinNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class ChallengeWinNetMessage : public NetMessage { // cwnm
public:
ChallengeWinNetMessage();
#ifdef LOGGING
void ToString(char *psz, int cb) {
strncpyz(psz, "CsChallengeWin", cb);
}
#endif
};
inline ChallengeWinNetMessage::ChallengeWinNetMessage()
{
nmid = knmidCsChallengeWin;
cb = sizeof(ChallengeWinNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
#define knDisconnectReasonResign 0
#define knDisconnectReasonKilled 1
#define knDisconnectReasonAbnormal 2
#define knDisconnectReasonNotResponding 3
#define knDisconnectReasonLeftGame 4
STARTLABEL(DisconnectReasons)
LABEL(knDisconnectReasonResign)
LABEL(knDisconnectReasonKilled)
LABEL(knDisconnectReasonAbnormal)
LABEL(knDisconnectReasonNotResponding)
LABEL(knDisconnectReasonLeftGame)
ENDLABEL(DisconnectReasons)
class KillLaggingPlayerNetMessage : public NetMessage {
public:
KillLaggingPlayerNetMessage();
Pid pid;
word fYes;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "CsKillLaggingPlayer(pid: %d, fYes: %d)",
pid, fYes);
}
#endif
};
inline KillLaggingPlayerNetMessage::KillLaggingPlayerNetMessage()
{
nmid = knmidCsKillLaggingPlayer;
cb = sizeof(KillLaggingPlayerNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class SyncErrorNetMessage : public NetMessage {
public:
SyncErrorNetMessage();
UpdateResult urLastStraw;
UpdateResult aur[kcPlayersMax];
#ifdef LOGGING
void ToString(char *psz, int cb) {
CompileAssert(kcPlayersMax == 5);
const char *pszT = base::Format::ToString("ScSyncErrorNetMessage "
"pid 0: cUpdatesBlock=%d, hash=%08x "
"pid 1: cUpdatesBlock=%d, hash=%08x "
"pid 2: cUpdatesBlock=%d, hash=%08x "
"pid 3: cUpdatesBlock=%d, hash=%08x "
"pid 4: cUpdatesBlock=%d, hash=%08x "
"urLastStraw: cUpdatesBlock=%d, hash=%08x",
aur[0].cUpdatesBlock, aur[0].hash,
aur[1].cUpdatesBlock, aur[1].hash,
aur[2].cUpdatesBlock, aur[2].hash,
aur[3].cUpdatesBlock, aur[3].hash,
aur[4].cUpdatesBlock, aur[4].hash,
urLastStraw.cUpdatesBlock, urLastStraw.hash);
strncpyz(psz, pszT, cb);
}
#endif
};
inline SyncErrorNetMessage::SyncErrorNetMessage()
{
nmid = knmidScSyncError;
cb = sizeof(*this);
CompileAssert((sizeof(this) % 4) == 0);
}
class PlayerDisconnectNetMessage : public NetMessage { // pdnm
public:
PlayerDisconnectNetMessage();
Pid pid;
word nReason;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "ScPlayerDisconnect(pid: %d, nReason: %s)",
pid, DisconnectReasons.Find(nReason));
}
#endif
};
inline PlayerDisconnectNetMessage::PlayerDisconnectNetMessage()
{
nmid = knmidScPlayerDisconnect;
cb = sizeof(PlayerDisconnectNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
class PlayerResignNetMessage : public NetMessage { // prnm
public:
PlayerResignNetMessage();
Pid pid;
#ifdef LOGGING
void ToString(char *psz, int cb) {
snprintf(psz, cb, "CsPlayerResign(pid: %d)", pid);
}
#endif
};
inline PlayerResignNetMessage::PlayerResignNetMessage()
{
nmid = knmidCsPlayerResign;
cb = sizeof(PlayerResignNetMessage);
CompileAssert((sizeof(this) % 4) == 0);
}
#pragma pack(pop)
#ifdef __CPU_68K // 68K byte order == our chosen network byte order
#define NetMessageByteOrderSwap(a, b)
#define MessageByteOrderSwap(a, b, c)
#define SwapGameParams(a)
#else
void NetMessageByteOrderSwap(NetMessage *pnm, bool fNative);
void MessageByteOrderSwap(word cmsgs, Message *pmsg, bool fNative);
void SwapGameParams(GameParams *prams);
#endif
bool ValidateGameParams(const GameParams& params);
extern int gatGameSpeeds[15];
} // namespace wi
#endif // __NETMESSAGE_H__