Rework InGame network messages.
Remove 'adjust' parameter of ChangeTeamSelectedUnits (always called with 0)
This commit is contained in:
parent
39dec1df00
commit
a42cfaecab
7 changed files with 462 additions and 365 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
//@}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue