Rework InGame network messages.

Remove 'adjust' parameter of ChangeTeamSelectedUnits (always called with 0)
This commit is contained in:
joris 2013-04-10 19:39:52 +02:00
parent 39dec1df00
commit a42cfaecab
7 changed files with 462 additions and 365 deletions

View file

@ -927,7 +927,7 @@ void CommandQuit(int player)
CommandSharedVision(player, 0, i);
// Remove Selection from Quit Player
std::vector<CUnit *> empty;
ChangeTeamSelectedUnits(Players[player], empty, 0);
ChangeTeamSelectedUnits(Players[player], empty);
}
}

View file

@ -32,6 +32,7 @@
//@{
#include <stdint.h>
#include <vector>
/*----------------------------------------------------------------------------
-- Declarations
@ -279,11 +280,9 @@ enum _message_type_ {
MessageSync, /// Heart beat
MessageSelection, /// Update a Selection from Team Player
MessageQuit, /// Quit game
MessageQuitAck, /// Quit reply - UNUSED YET - Protocol Version 2 - Reserved for menus
MessageResend, /// Resend message
MessageChat, /// Chat message
MessageChatTerm, /// Chat message termination - Protocol Version 2
MessageCommandStop, /// Unit command stop
MessageCommandStand, /// Unit command stand ground
@ -332,16 +331,10 @@ public:
CNetworkCommand() : Unit(0), X(0), Y(0), Dest(0) {}
void Clear() { this->Unit = this->X = this->Y = this->Dest = 0; }
void Serialize(unsigned char *p) const;
void Deserialize(const unsigned char *p);
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
static size_t Size() { return 2 + 2 + 2 + 2; }
bool operator == (const CNetworkCommand &rhs) const
{
return Unit == rhs.Unit && X == rhs.X && Y == rhs.Y && Dest == rhs.Dest;
}
bool operator != (const CNetworkCommand &rhs) const { return !(*this == rhs); }
public:
uint16_t Unit; /// Command for unit
uint16_t X; /// Map position X
@ -357,8 +350,8 @@ class CNetworkExtendedCommand
public:
CNetworkExtendedCommand() : ExtendedType(0), Arg1(0), Arg2(0), Arg3(0), Arg4(0) {}
void Serialize(unsigned char *p) const;
void Deserialize(const unsigned char *p);
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
static size_t Size() { return 1 + 1 + 2 + 2 + 2; }
uint8_t ExtendedType; /// Extended network command type
@ -374,17 +367,43 @@ public:
class CNetworkChat
{
public:
CNetworkChat() {
Player = 0;
memset(Text, 0, sizeof(Text));
}
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
size_t Size() const;
void Serialize(unsigned char *p) const ;
void Deserialize(const unsigned char *p);
static size_t Size() { return 1 + 7; }
public:
std::string Text; /// Message bytes
};
uint8_t Player; /// Sending player
char Text[7]; /// Message bytes
/**
** Network sync message.
*/
class CNetworkCommandSync
{
public:
CNetworkCommandSync() : syncSeed(0), syncHash(0) {}
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
static size_t Size() { return 4 + 4; };
public:
uint32_t syncSeed;
uint32_t syncHash;
};
/**
** Network quit message.
*/
class CNetworkCommandQuit
{
public:
CNetworkCommandQuit() : player(0) {}
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
static size_t Size() { return 2; };
public:
uint16_t player;
};
/**
@ -393,15 +412,15 @@ public:
class CNetworkSelection
{
public:
CNetworkSelection() {
memset(Unit, 0, sizeof(Unit));
}
CNetworkSelection() : player(0) {}
void Serialize(unsigned char *p) const;
void Deserialize(const unsigned char *p);
static size_t Size() { return 2 * 4; }
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
size_t Size() const;
uint16_t Unit[4]; /// Selection Units
public:
uint16_t player;
std::vector<uint16_t> Units; /// Selection Units
};
/**
@ -417,8 +436,8 @@ public:
memset(Type, 0, sizeof(Type));
}
void Serialize(unsigned char *p) const;
void Deserialize(const unsigned char *p);
unsigned int Serialize(unsigned char *buf) const;
unsigned int Deserialize(const unsigned char *buf);
static size_t Size() { return 1 + 1 * MaxNetworkCommands; }
uint8_t Type[MaxNetworkCommands]; /// Commands in packet
@ -433,14 +452,12 @@ public:
class CNetworkPacket
{
public:
void Serialize(unsigned char *buf, int numcommands) const;
int Deserialize(const unsigned char *p, unsigned int len);
static size_t Size(int numcommands) {
return CNetworkPacketHeader::Size() + numcommands * CNetworkCommand::Size();
}
unsigned int Serialize(unsigned char *buf, int numcommands) const;
void Deserialize(const unsigned char *buf, unsigned int len, int *numcommands);
size_t Size(int numcommands) const;
CNetworkPacketHeader Header; /// Packet Header Info
CNetworkCommand Command[MaxNetworkCommands];
std::vector<unsigned char> Command[MaxNetworkCommands];
};
//@}

View file

@ -635,7 +635,7 @@ extern void RestoreSelection();
/// Clear current selection
extern void UnSelectAll();
/// Changed TeamUnit Selection
extern void ChangeTeamSelectedUnits(CPlayer &player, const std::vector<CUnit *> &units, int adjust);
extern void ChangeTeamSelectedUnits(CPlayer &player, const std::vector<CUnit *> &units);
/// Add a unit to selection
extern int SelectUnit(CUnit &unit);
/// Select one unit as selection

View file

@ -42,42 +42,42 @@
#include "network.h"
#include "version.h"
int serialize32(unsigned char *buf, uint32_t data)
unsigned int serialize32(unsigned char *buf, uint32_t data)
{
if (buf) {
*reinterpret_cast<uint32_t *>(buf) = htonl(data);
}
return sizeof(data);
}
int serialize32(unsigned char *buf, int32_t data)
unsigned int serialize32(unsigned char *buf, int32_t data)
{
if (buf) {
*reinterpret_cast<int32_t *>(buf) = htonl(data);
}
return sizeof(data);
}
int serialize16(unsigned char *buf, uint16_t data)
unsigned int serialize16(unsigned char *buf, uint16_t data)
{
if (buf) {
*reinterpret_cast<uint16_t *>(buf) = htons(data);
}
return sizeof(data);
}
int serialize16(unsigned char *buf, int16_t data)
unsigned int serialize16(unsigned char *buf, int16_t data)
{
if (buf) {
*reinterpret_cast<int16_t *>(buf) = htons(data);
}
return sizeof(data);
}
int serialize8(unsigned char *buf, uint8_t data)
unsigned int serialize8(unsigned char *buf, uint8_t data)
{
if (buf) {
*buf = data;
}
return sizeof(data);
}
int serialize8(unsigned char *buf, int8_t data)
unsigned int serialize8(unsigned char *buf, int8_t data)
{
if (buf) {
*buf = data;
@ -85,50 +85,93 @@ int serialize8(unsigned char *buf, int8_t data)
return sizeof(data);
}
template <int N>
int serialize(unsigned char *buf, const char(&data)[N])
unsigned int serialize(unsigned char *buf, const char(&data)[N])
{
if (buf) {
memcpy(buf, data, N);
}
return N;
}
unsigned int serialize(unsigned char *buf, const std::string &s)
{
if (buf) {
buf += serialize16(buf, uint16_t(s.size()));
memcpy(buf, s.c_str(), s.size());
buf += s.size();
if ((s.size() & 0x03) != 0) {
memset(buf, 0, s.size() & 0x03);
}
}
return 2 + ((s.size() + 3) & ~0x03); // round up to multiple of 4 for alignment.
}
unsigned int serialize(unsigned char *buf, const std::vector<unsigned char> &data)
{
if (buf) {
if (data.empty()) {
return serialize16(buf, uint16_t(data.size()));
}
buf += serialize16(buf, uint16_t(data.size()));
memcpy(buf, &data[0], data.size());
buf += data.size();
if ((data.size() & 0x03) != 0) {
memset(buf, 0, data.size() & 0x03);
}
}
return 2 + ((data.size() + 3) & ~0x03); // round up to multiple of 4 for alignment.
}
int deserialize32(const unsigned char *buf, uint32_t *data)
unsigned int deserialize32(const unsigned char *buf, uint32_t *data)
{
*data = ntohl(*reinterpret_cast<const uint32_t *>(buf));
return sizeof(*data);
}
int deserialize32(const unsigned char *buf, int32_t *data)
unsigned int deserialize32(const unsigned char *buf, int32_t *data)
{
*data = ntohl(*reinterpret_cast<const int32_t *>(buf));
return sizeof(*data);
}
int deserialize16(const unsigned char *buf, uint16_t *data)
unsigned int deserialize16(const unsigned char *buf, uint16_t *data)
{
*data = ntohs(*reinterpret_cast<const uint16_t *>(buf));
return sizeof(*data);
}
int deserialize16(const unsigned char *buf, int16_t *data)
unsigned int deserialize16(const unsigned char *buf, int16_t *data)
{
*data = ntohs(*reinterpret_cast<const int16_t *>(buf));
return sizeof(*data);
}
int deserialize8(const unsigned char *buf, uint8_t *data)
unsigned int deserialize8(const unsigned char *buf, uint8_t *data)
{
*data = *buf;
return sizeof(*data);
}
int deserialize8(const unsigned char *buf, int8_t *data)
unsigned int deserialize8(const unsigned char *buf, int8_t *data)
{
*data = *buf;
return sizeof(*data);
}
template <int N>
int deserialize(const unsigned char *buf, char(&data)[N])
unsigned int deserialize(const unsigned char *buf, char(&data)[N])
{
memcpy(data, buf, N);
return N;
}
unsigned int deserialize(const unsigned char *buf, std::string &s)
{
uint16_t size;
buf += deserialize16(buf, &size);
s = std::string(reinterpret_cast<const char *>(buf), size);
return 2 + ((s.size() + 3) & ~0x03); // round up to multiple of 4 for alignment.
}
unsigned int deserialize(const unsigned char *buf, std::vector<unsigned char> &data)
{
uint16_t size;
buf += deserialize16(buf, &size);
data.assign(buf, buf + size);
return 2 + ((data.size() + 3) & ~0x03); // round up to multiple of 4 for alignment.
}
//
// CNetworkHost
@ -511,153 +554,212 @@ void CInitMessage_Resync::Deserialize(const unsigned char *p)
// CNetworkCommand
//
void CNetworkCommand::Serialize(unsigned char *p) const
unsigned int CNetworkCommand::Serialize(unsigned char *buf) const
{
*(uint16_t *)p = this->Unit;
p += 2;
*(uint16_t *)p = this->X;
p += 2;
*(uint16_t *)p = this->Y;
p += 2;
*(uint16_t *)p = this->Dest;
p += 2;
unsigned char *p = buf;
p += serialize16(p, this->Unit);
p += serialize16(p, this->X);
p += serialize16(p, this->Y);
p += serialize16(p, this->Dest);
return p - buf;
}
void CNetworkCommand::Deserialize(const unsigned char *p)
unsigned int CNetworkCommand::Deserialize(const unsigned char *buf)
{
this->Unit = *(uint16_t *)p;
p += 2;
this->X = *(uint16_t *)p;
p += 2;
this->Y = *(uint16_t *)p;
p += 2;
this->Dest = *(uint16_t *)p;
p += 2;
const unsigned char *p = buf;
p += deserialize16(p, &this->Unit);
p += deserialize16(p, &this->X);
p += deserialize16(p, &this->Y);
p += deserialize16(p, &this->Dest);
return p - buf;
}
//
// CNetworkExtendedCommand
//
void CNetworkExtendedCommand::Serialize(unsigned char *p) const
unsigned int CNetworkExtendedCommand::Serialize(unsigned char *buf) const
{
*p++ = this->ExtendedType;
*p++ = this->Arg1;
*(uint16_t *)p = this->Arg2;
p += 2;
*(uint16_t *)p = this->Arg3;
p += 2;
*(uint16_t *)p = this->Arg4;
p += 2;
unsigned char *p = buf;
p += serialize8(p, this->ExtendedType);
p += serialize8(p, this->Arg1);
p += serialize16(p, this->Arg2);
p += serialize16(p, this->Arg3);
p += serialize16(p, this->Arg4);
return p - buf;
}
void CNetworkExtendedCommand::Deserialize(const unsigned char *p)
unsigned int CNetworkExtendedCommand::Deserialize(const unsigned char *buf)
{
this->ExtendedType = *p++;
this->Arg1 = *p++;
this->Arg2 = *(uint16_t *)p;
p += 2;
this->Arg3 = *(uint16_t *)p;
p += 2;
this->Arg4 = *(uint16_t *)p;
p += 2;
const unsigned char *p = buf;
p += deserialize8(p, &this->ExtendedType);
p += deserialize8(p, &this->Arg1);
p += deserialize16(p, &this->Arg2);
p += deserialize16(p, &this->Arg3);
p += deserialize16(p, &this->Arg4);
return p - buf;
}
//
// CNetworkChat
//
void CNetworkChat::Serialize(unsigned char *p) const
unsigned int CNetworkChat::Serialize(unsigned char *buf) const
{
*p++ = this->Player;
memcpy(p, this->Text, 7);
p += 7;
unsigned char *p = buf;
p += serialize(p, this->Text);
return p - buf;
}
void CNetworkChat::Deserialize(const unsigned char *p)
unsigned int CNetworkChat::Deserialize(const unsigned char *buf)
{
this->Player = *p++;
memcpy(this->Text, p, 7);
p += 7;
const unsigned char *p = buf;
p += deserialize(p, this->Text);
return p - buf;
}
unsigned int CNetworkChat::Size() const
{
unsigned int size = 0;
size += serialize(NULL, this->Text);
return size;
}
//
// CNetworkCommandSync
//
unsigned int CNetworkCommandSync::Serialize(unsigned char *buf) const
{
unsigned char *p = buf;
p += serialize32(p, this->syncSeed);
p += serialize32(p, this->syncHash);
return p - buf;
}
unsigned int CNetworkCommandSync::Deserialize(const unsigned char *buf)
{
const unsigned char *p = buf;
p += deserialize32(p, &this->syncSeed);
p += deserialize32(p, &this->syncHash);
return p - buf;
}
//
// CNetworkCommandQuit
//
unsigned int CNetworkCommandQuit::Serialize(unsigned char *buf) const
{
unsigned char *p = buf;
p += serialize16(p, this->player);
return p - buf;
}
unsigned int CNetworkCommandQuit::Deserialize(const unsigned char *buf)
{
const unsigned char *p = buf;
p += deserialize16(p, &this->player);
return p - buf;
}
//
// CNetworkSelection
//
unsigned int CNetworkSelection::Serialize(unsigned char *buf) const
{
unsigned char *p = buf;
p += serialize16(p, this->player);
p += serialize16(p, uint16_t(this->Units.size()));
for (size_t i = 0; i != this->Units.size(); ++i) {
p += serialize16(p, Units[i]);
}
return p - buf;
}
unsigned int CNetworkSelection::Deserialize(const unsigned char *buf)
{
const unsigned char *p = buf;
uint16_t size;
p += deserialize16(p, &this->player);
p += deserialize16(p, &size);
this->Units.resize(size);
for (size_t i = 0; i != this->Units.size(); ++i) {
p += deserialize16(p, &Units[i]);
}
return p - buf;
}
size_t CNetworkSelection::Size() const
{
return 2 + 2 + 2 * Units.size();
}
//
// CNetworkPacketHeader
//
void CNetworkPacketHeader::Serialize(unsigned char *p) const
unsigned int CNetworkPacketHeader::Serialize(unsigned char *p) const
{
for (int i = 0; i < MaxNetworkCommands; ++i) {
*p++ = this->Type[i];
if (p != NULL) {
for (int i = 0; i != MaxNetworkCommands; ++i) {
p += serialize8(p, this->Type[i]);
}
*p++ = this->Cycle;
p += serialize8(p, this->Cycle);
}
return MaxNetworkCommands + 1;
}
void CNetworkPacketHeader::Deserialize(const unsigned char *p)
unsigned int CNetworkPacketHeader::Deserialize(const unsigned char *buf)
{
for (int i = 0; i < MaxNetworkCommands; ++i) {
this->Type[i] = *p++;
}
this->Cycle = *p++;
}
const unsigned char *p = buf;
for (int i = 0; i != MaxNetworkCommands; ++i) {
p += deserialize8(p, &this->Type[i]);
}
p += deserialize8(p, &this->Cycle);
return p - buf;
}
//
// CNetworkPacket
//
void CNetworkPacket::Serialize(unsigned char *buf, int numcommands) const
unsigned CNetworkPacket::Serialize(unsigned char *buf, int numcommands) const
{
unsigned char *p = buf;
this->Header.Serialize(p);
p += CNetworkPacketHeader::Size();
for (int i = 0; i < numcommands; ++i) {
if (this->Header.Type[i] == MessageExtendedCommand) {
((CNetworkExtendedCommand *)&this->Command[i])->Serialize(p);
} else if (this->Header.Type[i] == MessageChat) {
((CNetworkChat *)&this->Command[i])->Serialize(p);
} else {
this->Command[i].Serialize(p);
}
p += CNetworkCommand::Size();
p += this->Header.Serialize(p);
for (int i = 0; i != numcommands; ++i) {
p += serialize(p, this->Command[i]);
}
return p - buf;
}
int CNetworkPacket::Deserialize(const unsigned char *p, unsigned int len)
void CNetworkPacket::Deserialize(const unsigned char *p, unsigned int len, int *commandCount)
{
// check min and max size
if (len < CNetworkPacket::Size(1)
|| len > CNetworkPacket::Size(MaxNetworkCommands)) {
return -1;
}
// can't have partial commands
len -= CNetworkPacketHeader::Size();
if ((len / CNetworkCommand::Size()) * CNetworkCommand::Size() != len) {
return -1;
}
this->Header.Deserialize(p);
p += CNetworkPacketHeader::Size();
len -= CNetworkPacketHeader::Size();
int commands = len / CNetworkCommand::Size();
for (int i = 0; i < commands; ++i) {
if (this->Header.Type[i] == MessageExtendedCommand) {
((CNetworkExtendedCommand *)&this->Command[i])->Deserialize(p);
} else if (this->Header.Type[i] == MessageChat) {
((CNetworkChat *)&this->Command[i])->Deserialize(p);
} else {
this->Command[i].Deserialize(p);
for (*commandCount = 0; len != 0; ++*commandCount) {
const unsigned int r = deserialize(p, this->Command[*commandCount]);
p += r;
len -= r;
}
p += CNetworkCommand::Size();
}
return commands;
}
size_t CNetworkPacket::Size(int numcommands) const {
size_t size = 0;
size += this->Header.Serialize(NULL);
for (int i = 0; i != numcommands; ++i) {
size += serialize(NULL, this->Command[i]);
}
return size;
}
//@}

View file

@ -113,7 +113,7 @@
** IP Header 20 bytes
** UDP Header 8 bytes
**
** With 9 bytes per command and N(=9) commands there are 20+8+1+9*N(=120) bytes
** With ~9 bytes per command and up to N(=9) commands there are 20+8+1+9*N(=120) bytes
** per packet. Sending it to 7 other players, gives 840 bytes per update.
** This means we could do 6 updates (each 166ms) per second (6*840=5040 bytes/s).
**
@ -125,14 +125,11 @@
** if Type is one of the InitConfigMessage
** @li [Header Data:SubType - 1 byte]
** @li [Data - depend of subtype (may be 0 byte)]
** if Type is Chat
** [..]
** if Type is Selection
** [..]
** else
** @li [Header Data:Types - N-1 bytes] (for N commands)
** @li [Header Data:Cycle - 1 byte]
** @li [Data:Commands - 8 bytes * N]
** @li [Data:Commands - Sum of Xi bytes for the N Commands]
**
**
** @subsection internals Putting it together
**
@ -251,7 +248,7 @@ class CNetworkCommandQueue
{
public:
CNetworkCommandQueue() : Time(0), Type(0) {}
void Clear() { this->Time = this->Type = 0; Data.Clear(); }
void Clear() { this->Time = this->Type = 0; Data.clear(); }
bool operator == (const CNetworkCommandQueue &rhs) const
{
@ -261,17 +258,7 @@ public:
public:
unsigned long Time; /// time to execute
unsigned char Type; /// Command Type
CNetworkCommand Data; /// command content
};
/**
** Network Selection Info
*/
struct NetworkSelectionHeader {
unsigned char Type[MaxNetworkCommands]; /// Command
unsigned NumberSent : 6; /// New Number Selected
unsigned Add : 1; /// Adding to Selection
unsigned Remove : 1; /// Removing from Selection
std::vector<unsigned char> Data; /// command content (network format)
};
//----------------------------------------------------------------------------
@ -301,8 +288,6 @@ CUDPSocket NetworkFildes; /// Network file descriptor
static unsigned long NetworkLastFrame[PlayerMax]; /// Last frame received packet
static const int NetworkTimeout = 45; /// Number of seconds until player times out
static char NetMsgBuf[PlayerMax][128]; /// Chat message buffers
static int NetMsgBufLen[PlayerMax]; /// Stored chat message length
static unsigned long NetworkDelay; /// Delay counter for recover.
static int NetworkSyncSeeds[256]; /// Network sync seeds.
static int NetworkSyncHashs[256]; /// Network sync hashs.
@ -335,13 +320,14 @@ static int PlayerQuit[PlayerMax]; /// Player quit
*/
static void NetworkBroadcast(const CNetworkPacket &packet, int numcommands)
{
unsigned char *buf = new unsigned char[CNetworkPacket::Size(numcommands)];
const unsigned int size = packet.Size(numcommands);
unsigned char *buf = new unsigned char[size];
packet.Serialize(buf, numcommands);
// Send to all clients.
for (int i = 0; i < HostsCount; ++i) {
const CHost host(Hosts[i].Host, Hosts[i].Port);
NetworkFildes.Send(host, buf, CNetworkPacket::Size(numcommands));
NetworkFildes.Send(host, buf, size);
}
delete[] buf;
}
@ -393,10 +379,6 @@ void InitNetwork1()
NetInit(); // machine dependent setup
for (int i = 0; i < PlayerMax; ++i) {
NetMsgBufLen[i] = 0;
}
// Our communication port
int port = CNetworkParameter::Instance.localPort;
for (int i = 0; i < 10; ++i) {
@ -475,13 +457,25 @@ void InitNetwork2()
CNetworkParameter::Instance.NetworkUpdates _C_
CNetworkParameter::Instance.NetworkLag _C_ HostsCount);
// Prepare first time without syncs.
memset(NetworkIn, 0, sizeof(NetworkIn));
for (int i = 0; i != 256; ++i) {
for (int p = 0; p != PlayerMax; ++p) {
for (int j = 0; j != MaxNetworkCommands; ++j) {
NetworkIn[i][p][j].Clear();
}
}
}
CNetworkCommandSync nc;
//nc.syncHash = SyncHash;
//nc.syncSeed = SyncRandSeed;
for (int i = 0; i <= CNetworkParameter::Instance.NetworkLag; ++i) {
for (int n = 0; n < HostsCount; ++n) {
CNetworkCommandQueue (&ncqs)[MaxNetworkCommands] = NetworkIn[i][Hosts[n].PlyNr];
ncqs[0].Time = i * CNetworkParameter::Instance.NetworkUpdates;
ncqs[0].Type = MessageSync;
ncqs[0].Data.resize(nc.Size());
nc.Serialize(&ncqs[0].Data[0]);
ncqs[1].Time = i * CNetworkParameter::Instance.NetworkUpdates;
ncqs[1].Type = MessageNone;
}
@ -521,17 +515,20 @@ void NetworkSendCommand(int command, const CUnit &unit, int x, int y,
if (status) {
ncq.Type |= 0x80;
}
ncq.Data.Unit = htons(UnitNumber(unit));
ncq.Data.X = htons(x);
ncq.Data.Y = htons(y);
CNetworkCommand nc;
nc.Unit = UnitNumber(unit);
nc.X = x;
nc.Y = y;
Assert(!dest || !type); // Both together isn't allowed
if (dest) {
ncq.Data.Dest = htons(UnitNumber(*dest));
nc.Dest = UnitNumber(*dest);
} else if (type) {
ncq.Data.Dest = htons(type->Slot);
nc.Dest = type->Slot;
} else {
ncq.Data.Dest = htons(0xFFFF); // -1
nc.Dest = 0xFFFF; // -1
}
ncq.Data.resize(nc.Size());
nc.Serialize(&ncq.Data[0]);
// Check for duplicate command in queue
if (std::find(CommandsIn.begin(), CommandsIn.end(), ncq) != CommandsIn.end()) {
return;
@ -557,17 +554,18 @@ void NetworkSendExtendedCommand(int command, int arg1, int arg2, int arg3,
CNetworkCommandQueue ncq;
ncq.Time = GameCycle;
CNetworkExtendedCommand *nec = reinterpret_cast<CNetworkExtendedCommand *>(&ncq.Data);
ncq.Type = MessageExtendedCommand;
if (status) {
ncq.Type |= 0x80;
}
nec->ExtendedType = command;
nec->Arg1 = arg1;
nec->Arg2 = htons(arg2);
nec->Arg3 = htons(arg3);
nec->Arg4 = htons(arg4);
CNetworkExtendedCommand nec;
nec.ExtendedType = command;
nec.Arg1 = arg1;
nec.Arg2 = arg2;
nec.Arg3 = arg3;
nec.Arg4 = arg4;
ncq.Data.resize(nec.Size());
nec.Serialize(&ncq.Data[0]);
CommandsIn.push_back(ncq);
}
@ -579,86 +577,53 @@ void NetworkSendExtendedCommand(int command, int arg1, int arg2, int arg3,
*/
void NetworkSendSelection(CUnit **units, int count)
{
int teammates[PlayerMax];
// Check if we have any teammates to send to
int numteammates = 0;
bool hasteammates = false;
for (int i = 0; i < HostsCount; ++i) {
if (Players[Hosts[i].PlyNr].Team == ThisPlayer->Team) {
teammates[numteammates++] = i;
hasteammates = true;
break;
}
}
if (!numteammates) {
if (!hasteammates) {
return;
}
// Build and send packets to cover all units.
CNetworkPacket packet;
int unitcount = 0;
while (unitcount < count) {
NetworkSelectionHeader &header = (NetworkSelectionHeader &) packet.Header;
if (unitcount == 0) {
header.Add = 0;
} else {
header.Add = 1;
}
header.Remove = 0;
CNetworkSelection ns;
int nosent = 0;
int i;
for (i = 0; i < MaxNetworkCommands && unitcount < count; ++i) {
header.Type[i] = MessageSelection;
CNetworkSelection &selection = (CNetworkSelection &)packet.Command[i];
for (int ref = 0; ref < 4 && unitcount < count; ++ref, ++unitcount) {
selection.Unit[ref] = htons(UnitNumber(*units[unitcount]));
++nosent;
for (int i = 0; i != count; ++i) {
ns.Units.push_back(UnitNumber(*units[i]));
}
}
if (unitcount >= count) {
// This is the last command
header.NumberSent = nosent;
} else {
header.NumberSent = MaxNetworkCommands * 4;
}
for (; i < MaxNetworkCommands; ++i) {
packet.Header.Type[i] = MessageNone;
}
// Send the Constructed packet to team members
const int numcommands = (nosent + 3) / 4;
unsigned char *buf = new unsigned char [CNetworkPacket::Size(numcommands)];
packet.Serialize(buf, numcommands);
const int len = CNetworkPacketHeader::Size() + CNetworkSelection::Size() * numcommands;
CNetworkCommandQueue ncq;
ncq.Time = GameCycle;
ncq.Type = MessageSelection;
for (int i = 0; i < numteammates; ++i) {
const CHost host(Hosts[teammates[i]].Host, Hosts[teammates[i]].Port);
NetworkFildes.Send(host, buf, len);
}
delete [] buf;
}
ncq.Data.resize(ns.Size());
ns.Serialize(&ncq.Data[0]);
CommandsIn.push_back(ncq);
}
/**
** Process Received Unit Selection
**
** @param packet Network Packet to Process
** @param player Player number
** @param ncq Network Packet to Process
*/
static void NetworkProcessSelection(const CNetworkPacket &packet, int player)
static void ParseNetworkCommand_Selection(const CNetworkCommandQueue &ncq)
{
const NetworkSelectionHeader &header = reinterpret_cast<const NetworkSelectionHeader &>(packet.Header);
const size_t count = header.NumberSent;
const int adjust = (header.Add << 1) | header.Remove;
Assert((ncq.Type & 0x7F) == MessageSelection);
CNetworkSelection ns;
ns.Deserialize(&ncq.Data[0]);
if (Players[ns.player].Team != ThisPlayer->Team) {
return;
}
std::vector<CUnit *> units;
for (int i = 0; header.Type[i] == MessageSelection; ++i) {
const CNetworkSelection &selection = reinterpret_cast<const CNetworkSelection &>(packet.Command[i]);
for (int j = 0; j < 4 && units.size() < count; ++j) {
units.push_back(&UnitManager.GetSlotUnit(ntohs(selection.Unit[j])));
for (size_t i = 0; i != ns.Units.size(); ++i) {
units.push_back(&UnitManager.GetSlotUnit(ns.Units[i]));
}
}
Assert(count == units.size());
ChangeTeamSelectedUnits(Players[player], units, adjust);
ChangeTeamSelectedUnits(Players[ns.player], units);
}
/**
@ -732,7 +697,7 @@ static void ParseResendCommand(const CNetworkPacket &packet)
}
}
static bool IsAValidCommand(const CNetworkPacket &packet, int index, const CNetworkCommand &nc)
static bool IsAValidCommand(const CNetworkPacket &packet, int index)
{
const int player = Hosts[index].PlyNr;
@ -741,15 +706,17 @@ static bool IsAValidCommand(const CNetworkPacket &packet, int index, const CNetw
return true;
case MessageSync: // Sync does not matter
return true;
case MessageSelection:
return true;
case MessageQuit:
case MessageQuitAck:
case MessageResend:
case MessageChat:
case MessageChatTerm:
// FIXME: ensure it's from the right player
return true;
case MessageCommandDismiss: {
const unsigned int slot = ntohs(nc.Unit);
CNetworkCommand nc;
nc.Deserialize(&packet.Command[index][0]);
const unsigned int slot = nc.Unit;
const CUnit *unit = slot < UnitManager.GetUsedSlotCount() ? &UnitManager.GetSlotUnit(slot) : NULL;
if (unit && unit->Type->ClicksToExplode) {
@ -758,7 +725,9 @@ static bool IsAValidCommand(const CNetworkPacket &packet, int index, const CNetw
}
// Fall through!
default: {
const unsigned int slot = ntohs(nc.Unit);
CNetworkCommand nc;
nc.Deserialize(&packet.Command[index][0]);
const unsigned int slot = nc.Unit;
const CUnit *unit = slot < UnitManager.GetUsedSlotCount() ? &UnitManager.GetSlotUnit(slot) : NULL;
if (unit && (unit->Player->Index == player
@ -772,7 +741,7 @@ static bool IsAValidCommand(const CNetworkPacket &packet, int index, const CNetw
// FIXME: not all values in nc have been validated
}
static void NetworkParseInGameEvent(unsigned char *buf, int len, const CHost &host)
static void NetworkParseInGameEvent(const unsigned char *buf, int len, const CHost &host)
{
const int index = FindHostIndexBy(host);
if (index == -1 || PlayerQuit[Hosts[index].PlyNr]) {
@ -785,23 +754,19 @@ static void NetworkParseInGameEvent(unsigned char *buf, int len, const CHost &ho
const int player = Hosts[index].PlyNr;
CNetworkPacket packet;
int commands = packet.Deserialize(buf, len);
int commands;
packet.Deserialize(buf, len, &commands);
if (commands < 0) {
DebugPrint("Bad packet read\n");
return;
}
// In a normal packet there is a least sync, selection may not have that
if (packet.Header.Type[0] == MessageSelection || commands == 0) {
NetworkProcessSelection(packet, player);
return;
}
// Parse the packet commands.
for (int i = 0; i != commands; ++i) {
const CNetworkCommand &nc = packet.Command[i];
// Handle some messages.
if (packet.Header.Type[i] == MessageQuit) {
const int playerNum = ntohs(nc.X);
CNetworkCommandQuit nc;
nc.Deserialize(&packet.Command[i][0]);
const int playerNum = nc.player;
if (playerNum >= 0 && playerNum < NumPlayers) {
PlayerQuit[playerNum] = 1;
@ -814,7 +779,7 @@ static void NetworkParseInGameEvent(unsigned char *buf, int len, const CHost &ho
// Receive statistic
NetworkLastFrame[player] = FrameCounter;
bool validCommand = IsAValidCommand(packet, i, nc);
bool validCommand = IsAValidCommand(packet, i);
// Place in network in
if (validCommand) {
// Destination cycle (time to execute).
@ -825,7 +790,7 @@ static void NetworkParseInGameEvent(unsigned char *buf, int len, const CHost &ho
const unsigned long gameNetCycle = n / CNetworkParameter::Instance.NetworkUpdates;
NetworkIn[gameNetCycle & 0xFF][player][i].Time = n;
NetworkIn[gameNetCycle & 0xFF][player][i].Type = packet.Header.Type[i];
NetworkIn[gameNetCycle & 0xFF][player][i].Data = nc;
NetworkIn[gameNetCycle & 0xFF][player][i].Data = packet.Command[i];
} else {
SetMessage(_("%s sent bad command"), Players[player].Name.c_str());
DebugPrint("%s sent bad command: 0x%x\n" _C_ Players[player].Name.c_str()
@ -872,12 +837,17 @@ void NetworkEvent()
#ifdef DEBUG
++NetworkReceivedPackets;
#endif
// Setup messages
if (NetConnectRunning) {
if (NetworkParseSetupEvent(buf, len, host)) {
return;
}
}
const unsigned char msgtype = buf[0];
if (msgtype == MessageInit_FromClient || msgtype == MessageInit_FromServer) {
return;
}
NetworkParseInGameEvent(buf, len, host);
}
@ -894,11 +864,15 @@ void NetworkQuit()
const int gameNetCycle = GameCycle / NetworkUpdates;
const int n = gameNetCycle + 1 + NetworkLag;
CNetworkCommandQueue (&ncqs)[MaxNetworkCommands] = NetworkIn[n & 0xFF][ThisPlayer->Index];
CNetworkCommandQuit nc;
nc.player = ThisPlayer->Index;
ncqs[0].Type = MessageQuit;
ncqs[0].Time = n * CNetworkParameter::Instance.NetworkUpdates;
ncqs[0].Data.X = ThisPlayer->Index;
ncqs[0].Data.resize(nc.Size());
nc.Serialize(&ncqs[0].Data[0]);
for (int i = 1; i < MaxNetworkCommands; ++i) {
ncqs[i].Type = MessageNone;
ncqs[i].Data.clear();
}
NetworkSendPacket(ncqs);
}
@ -913,33 +887,24 @@ void NetworkChatMessage(const std::string &msg)
if (!IsNetworkGame()) {
return;
}
const char *cp = msg.c_str();
size_t n = msg.size();
CNetworkChat *ncm = NULL;
while (n >= sizeof(ncm->Text)) {
CNetworkChat nc;
nc.Text = msg;
CNetworkCommandQueue ncq;
ncq.Type = MessageChat;
ncm = reinterpret_cast<CNetworkChat *>(&ncq.Data);
ncm->Player = ThisPlayer->Index;
memcpy(ncm->Text, cp, sizeof(ncm->Text));
cp += sizeof(ncm->Text);
n -= sizeof(ncm->Text);
MsgCommandsIn.push_back(ncq);
}
CNetworkCommandQueue ncq;
ncq.Type = MessageChatTerm;
ncm = reinterpret_cast<CNetworkChat *>(&ncq.Data);
ncm->Player = ThisPlayer->Index;
memcpy(ncm->Text, cp, n + 1); // see >= above :)
ncq.Data.resize(nc.Size());
nc.Serialize(&ncq.Data[0]);
MsgCommandsIn.push_back(ncq);
}
static void ParseNetworkCommand_Sync(const CNetworkCommandQueue &ncq)
{
Assert((ncq.Type & 0x7F) == MessageSync);
CNetworkCommandSync nc;
nc.Deserialize(&ncq.Data[0]);
const unsigned long gameNetCycle = GameCycle / CNetworkParameter::Instance.NetworkUpdates;
const int syncSeed = (ntohs(ncq.Data.X) << 16) | ntohs(ncq.Data.Y);
const int syncHash = ntohs(ncq.Data.Unit);
const int syncSeed = nc.syncSeed;
const int syncHash = nc.syncHash;
if (syncSeed != NetworkSyncSeeds[gameNetCycle & 0xFF]
|| syncHash != NetworkSyncHashs[gameNetCycle & 0xFF]) {
@ -952,20 +917,14 @@ static void ParseNetworkCommand_Sync(const CNetworkCommandQueue &ncq)
static void ParseNetworkCommand_Chat(const CNetworkCommandQueue &ncq)
{
const CNetworkChat &ncm = reinterpret_cast<const CNetworkChat &>(ncq.Data);
const int ply = ncm.Player;
Assert((ncq.Type & 0x7F) == MessageChat);
if (NetMsgBufLen[ply] + sizeof(ncm.Text) < 128) {
memcpy(NetMsgBuf[ply] + NetMsgBufLen[ply], ncm.Text, sizeof(ncm.Text));
}
NetMsgBufLen[ply] += sizeof(ncm.Text);
if (ncq.Type == MessageChatTerm) {
NetMsgBuf[ply][127] = '\0';
SetMessage("%s", NetMsgBuf[ply]);
CNetworkChat nc;
nc.Deserialize(&ncq.Data[0]);
SetMessage("%s", nc.Text.c_str());
PlayGameSound(GameSounds.ChatMessage.Sound, MaxSampleVolume);
CommandLog("chat", NoUnitP, FlushCommands, -1, -1, NoUnitP, NetMsgBuf[ply], -1);
NetMsgBufLen[ply] = 0;
}
CommandLog("chat", NoUnitP, FlushCommands, -1, -1, NoUnitP, nc.Text.c_str(), -1);
}
/**
@ -977,31 +936,36 @@ static void ParseNetworkCommand(const CNetworkCommandQueue &ncq)
{
switch (ncq.Type & 0x7F) {
case MessageSync: ParseNetworkCommand_Sync(ncq); break;
case MessageSelection: ParseNetworkCommand_Selection(ncq); break;
case MessageChat: ParseNetworkCommand_Chat(ncq); break;
case MessageChat: // Follow
case MessageChatTerm: ParseNetworkCommand_Chat(ncq); break;
case MessageQuit:
NetworkRemovePlayer(ncq.Data.X);
CommandLog("quit", NoUnitP, FlushCommands, ncq.Data.X, -1, NoUnitP, NULL, -1);
CommandQuit(ncq.Data.X);
case MessageQuit: {
CNetworkCommandQuit nc;
nc.Deserialize(&ncq.Data[0]);
NetworkRemovePlayer(nc.player);
CommandLog("quit", NoUnitP, FlushCommands, nc.player, -1, NoUnitP, NULL, -1);
CommandQuit(nc.player);
break;
}
case MessageExtendedCommand: {
const CNetworkExtendedCommand *nec = (CNetworkExtendedCommand *)(&ncq.Data);
ParseExtendedCommand(nec->ExtendedType, (ncq.Type & 0x80) >> 7,
nec->Arg1, ntohs(nec->Arg2), ntohs(nec->Arg3), ntohs(nec->Arg4));
CNetworkExtendedCommand nec;
nec.Deserialize(&ncq.Data[0]);
ParseExtendedCommand(nec.ExtendedType, (ncq.Type & 0x80) >> 7,
nec.Arg1, nec.Arg2, nec.Arg3, nec.Arg4);
}
break;
case MessageNone:
// Nothing to Do, This Message Should Never be Executed
Assert(0);
break;
default:
ParseCommand(ncq.Type, ntohs(ncq.Data.Unit),
ntohs(ncq.Data.X), ntohs(ncq.Data.Y), ntohs(ncq.Data.Dest));
default: {
CNetworkCommand nc;
nc.Deserialize(&ncq.Data[0]);
ParseCommand(ncq.Type, nc.Unit, nc.X, nc.Y, nc.Dest);
break;
}
}
}
/**
** Network send commands.
@ -1013,10 +977,12 @@ static void NetworkSendCommands(unsigned long gameNetCycle)
CNetworkCommandQueue (&ncq)[MaxNetworkCommands] = NetworkIn[gameNetCycle & 0xFF][ThisPlayer->Index];
ncq[0].Clear();
if (CommandsIn.empty() && MsgCommandsIn.empty()) {
CNetworkCommandSync nc;
ncq[0].Type = MessageSync;
ncq[0].Data.Unit = htons(SyncHash & 0xFFFF);
ncq[0].Data.X = htons(SyncRandSeed >> 16);
ncq[0].Data.Y = htons(SyncRandSeed & 0xFFFF);
nc.syncHash = SyncHash;
nc.syncSeed = SyncRandSeed;
ncq[0].Data.resize(nc.Size());
nc.Serialize(&ncq[0].Data[0]);
ncq[0].Time = gameNetCycle * CNetworkParameter::Instance.NetworkUpdates;
numcommands = 1;
} else {
@ -1024,11 +990,13 @@ static void NetworkSendCommands(unsigned long gameNetCycle)
const CNetworkCommandQueue &incommand = CommandsIn.front();
#ifdef DEBUG
if (incommand.Type != MessageExtendedCommand) {
const CUnit &unit = UnitManager.GetSlotUnit(ntohs(incommand.Data.Unit));
CNetworkCommand nc;
nc.Deserialize(&incommand.Data[0]);
const CUnit &unit = UnitManager.GetSlotUnit(nc.Unit);
// FIXME: we can send destoyed units over network :(
if (unit.Destroyed) {
DebugPrint("Sending destroyed unit %d over network!!!!!!\n" _C_
ntohs(incommand.Data.Unit));
DebugPrint("Sending destroyed unit %d over network!!!!!!\n" _C_ nc.Unit);
}
}
#endif
@ -1051,7 +1019,7 @@ static void NetworkSendCommands(unsigned long gameNetCycle)
NetworkSendPacket(ncq);
NetworkSyncSeeds[gameNetCycle & 0xFF] = SyncRandSeed;
NetworkSyncHashs[gameNetCycle & 0xFF] = SyncHash & 0xFFFF; // FIXME: 32bit later
NetworkSyncHashs[gameNetCycle & 0xFF] = SyncHash;
}
/**
@ -1154,12 +1122,13 @@ void NetworkRecover()
}
if (secs >= NetworkTimeout) {
const unsigned int nextGameNetCycle = GameCycle / CNetworkParameter::Instance.NetworkUpdates + 1;
CNetworkCommand nc;
nc.X = playerIndex;
CNetworkCommandQuit nc;
nc.player = playerIndex;
CNetworkCommandQueue *ncq = &NetworkIn[nextGameNetCycle & 0xFF][playerIndex][0];
ncq->Time = nextGameNetCycle * CNetworkParameter::Instance.NetworkUpdates;
ncq->Type = MessageQuit;
ncq->Data = nc;
ncq->Data.resize(nc.Size());
nc.Serialize(&ncq->Data[0]);
PlayerQuit[playerIndex] = 1;
SetMessage("%s", _("Timed out"));

View file

@ -186,20 +186,16 @@ static void ChangeSelectedUnits(CUnit **units, int count)
**
** @param player The Player who is selecting the units
** @param units The Units to add/remove
** @param adjust 0 = reset, 1 = remove units, 2 = add units
*/
void ChangeTeamSelectedUnits(CPlayer &player, const std::vector<CUnit *> &units, int adjust)
void ChangeTeamSelectedUnits(CPlayer &player, const std::vector<CUnit *> &units)
{
switch (adjust) {
case 0:
// UnSelectAllTeam(player);
while (TeamNumSelected[player.Index]) {
CUnit *unit = TeamSelected[player.Index][--TeamNumSelected[player.Index]];
unit->TeamSelected &= ~(1 << player.Index);
TeamSelected[player.Index][TeamNumSelected[player.Index]] = NULL; // FIXME: only needed for old code
}
// FALL THROUGH
case 2:
// Add to selection
for (size_t i = 0; i != units.size(); ++i) {
CUnit &unit = *units[i];
Assert(!unit.Removed);
@ -209,21 +205,6 @@ void ChangeTeamSelectedUnits(CPlayer &player, const std::vector<CUnit *> &units,
}
}
Assert(TeamNumSelected[player.Index] <= MaxSelectable);
break;
case 1:
for (int n = 0; n < TeamNumSelected[player.Index]; ++n) {
for (size_t i = 0; i != units.size(); ++i) {
if (units[i] == TeamSelected[player.Index][n]) {
TeamSelected[player.Index][n] =
TeamSelected[player.Index][TeamNumSelected[player.Index]--];
}
}
}
Assert(TeamNumSelected[player.Index] >= 0);
break;
default:
Assert(0);
}
}
/**

View file

@ -52,16 +52,21 @@ void FillCustomValue(CNetworkExtendedCommand *obj)
void FillCustomValue(CNetworkChat *obj)
{
obj->Player = 42;
for (int i = 0; i != sizeof(obj->Text); ++i) {
obj->Text[i] = 1 + i;
obj->Text = "abcdefghijklmnopqrstuvwxyz";
}
void FillCustomValue(CNetworkCommandSync *obj)
{
obj->syncSeed = 0x01234567;
obj->syncHash = 0x89ABCDEF;
}
void FillCustomValue(CNetworkCommandQuit *obj)
{
obj->player = 0x0123;
}
void FillCustomValue(CNetworkSelection *obj)
{
for (int i = 0; i != 4; ++i) {
obj->Unit[i] = 0x1234 * i;
for (int i = 0; i != 10; ++i) {
obj->Units.push_back(0x0123 * i);
}
}
@ -73,7 +78,22 @@ void FillCustomValue(CNetworkPacketHeader *obj)
}
}
// CNetworkPacket
template <typename T>
bool Comp(const T &lhs, const T &rhs)
{
return memcmp(&lhs, &rhs, sizeof(T)) == 0;
}
bool Comp(const CNetworkChat &lhs, const CNetworkChat &rhs)
{
return lhs.Text == rhs.Text;
}
bool Comp(const CNetworkSelection &lhs, const CNetworkSelection &rhs)
{
return lhs.Units == rhs.Units;
}
template <typename T>
bool CheckSerialization()
@ -81,12 +101,12 @@ bool CheckSerialization()
T obj1;
FillCustomValue(&obj1);
unsigned char *buffer = new unsigned char [T::Size()];
unsigned char *buffer = new unsigned char [obj1.Size()];
obj1.Serialize(buffer);
T obj2;
obj2.Deserialize(buffer);
bool res = memcmp(&obj1, &obj2, sizeof(T)) == 0;
bool res = Comp(obj1, obj2);
delete [] buffer;
return res;
}
@ -103,13 +123,21 @@ TEST(CNetworkChat)
{
CHECK(CheckSerialization<CNetworkChat>());
}
#if 0
TEST(CNetworkCommandSync)
{
CHECK(CheckSerialization<CNetworkCommandSync>());
}
TEST(CNetworkCommandQuit)
{
CHECK(CheckSerialization<CNetworkCommandQuit>());
}
TEST(CNetworkSelection)
{
CHECK(CheckSerialization<CNetworkSelection>());
}
#endif
TEST(CNetworkPacketHeader)
{
CHECK(CheckSerialization<CNetworkPacketHeader>());
}
//TEST(CNetworkPacket)