Some refactoring of network code.

This commit is contained in:
joris 2013-03-19 18:49:50 +01:00
parent 0a6e1760d5
commit 94f20ffea4
7 changed files with 610 additions and 435 deletions

View file

@ -49,9 +49,6 @@ class ButtonStyle;
extern void DrawUIButton(ButtonStyle *style, unsigned flags,
int x, int y, const std::string &text);
/// Compare Local State <-> Server's state, force Update when changes
extern void NetClientCheckLocalState();
/// Pre menu setup
extern void PreMenuSetup();

View file

@ -76,20 +76,14 @@ public:
void Clear();
static size_t Size() { return 4 + 2 + 2 + NetPlayerNameSize; }
void SetName(const char *name);
uint32_t Host; /// Host address
uint16_t Port; /// Port on host
uint16_t PlyNr; /// Player number
char PlyName[NetPlayerNameSize]; /// Name of player
};
/**
** Connect state information of network systems active in current game.
*/
typedef struct _network_state_ {
unsigned char State; /// Menu: ConnectState
unsigned short MsgCnt; /// Menu: Counter for state msg of same type (detect unreachable)
// Fill in here...
} NetworkState;
/**
** Multiplayer game setup menu state
@ -99,27 +93,34 @@ class CServerSetup
public:
unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 * PlayerMax + 4 * PlayerMax + 4 * PlayerMax + 4 * PlayerMax; }
static size_t Size() { return 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 * PlayerMax + 1 * PlayerMax + 1 * PlayerMax + 4 * PlayerMax; }
void Clear() {
ResourcesOption = UnitsOption = FogOfWar = RevealMap = TilesetSelection =
GameTypeOption = Difficulty = MapRichness = 0;
ResourcesOption = 0;
UnitsOption = 0;
FogOfWar = 0;
RevealMap = 0;
TilesetSelection = 0;
GameTypeOption = 0;
Difficulty = 0;
MapRichness = 0;
memset(CompOpt, 0, sizeof(CompOpt));
memset(Ready, 0, sizeof(Ready));
memset(Race, 0, sizeof(Race));
memset(LastFrame, 0, sizeof(LastFrame));
}
uint32_t ResourcesOption; /// Resources option
uint32_t UnitsOption; /// Unit # option
uint32_t FogOfWar; /// Fog of war option
uint32_t RevealMap; /// Reveal all the map
uint32_t TilesetSelection; /// Tileset select option
uint32_t GameTypeOption; /// Game type option
uint32_t Difficulty; /// Difficulty option
uint32_t MapRichness; /// Map richness option
uint32_t CompOpt[PlayerMax]; /// Free slot option selection {"Available", "Computer", "Closed" }
uint32_t Ready[PlayerMax]; /// Client ready state
uint32_t Race[PlayerMax]; /// Client race selection
uint32_t LastFrame[PlayerMax]; /// Last message received
uint8_t ResourcesOption; /// Resources option
uint8_t UnitsOption; /// Unit # option
uint8_t FogOfWar; /// Fog of war option
uint8_t RevealMap; /// Reveal all the map
uint8_t TilesetSelection; /// Tileset select option
uint8_t GameTypeOption; /// Game type option
uint8_t Difficulty; /// Difficulty option
uint8_t MapRichness; /// Map richness option
uint8_t CompOpt[PlayerMax]; /// Free slot option selection {"Available", "Computer", "Closed" }
uint8_t Ready[PlayerMax]; /// Client ready state
uint8_t Race[PlayerMax]; /// Client race selection
uint32_t LastFrame[PlayerMax]; /// Last message received
// Fill in here...
};
@ -132,24 +133,25 @@ public:
class CInitMessage
{
public:
CInitMessage();
unsigned char *Serialize() const;
void Deserialize(const unsigned char *p);
static size_t Size() { return 1 + 1 + 4 + 4 + 4 + 4 + 4 + 4 + 1 + 256 + CNetworkHost::Size() * PlayerMax + CServerSetup::Size(); }
static size_t Size() { return 1 + 1 + 1 + 1 + 4 + 4 + 4 + 4 + 4 + 4 + std::max(256u, std::max(CNetworkHost::Size() * PlayerMax, CServerSetup::Size())); }
uint8_t Type; /// Init message type
uint8_t SubType; /// Init message subtype
int32_t Stratagus; /// Stratagus engine version
int32_t Version; /// Network protocol version
uint32_t ConfUID; /// Engine configuration UID (Checksum) FIXME: not available yet
uint32_t MapUID; /// UID of map to play. FIXME: add MAP name, path, etc
int32_t Lag; /// Lag time
int32_t Updates; /// Update frequency
uint8_t HostsCount; /// Number of hosts
uint8_t Type; /// Init message type
uint8_t SubType; /// Init message subtype
uint8_t HostsCount; /// Number of hosts
uint8_t padding; /// padding for alignment
int32_t Stratagus; /// Stratagus engine version
int32_t Version; /// Network protocol version
uint32_t MapUID; /// UID of map to play. FIXME: add MAP name, path, etc
int32_t Lag; /// Lag time
int32_t Updates; /// Update frequency
union {
CNetworkHost Hosts[PlayerMax]; /// Participant information
char MapPath[256];
CServerSetup State; /// Server Setup State information
CServerSetup State; /// Server Setup State information
} u;
};
@ -219,7 +221,6 @@ extern int HostsCount; /// Number of hosts.
extern CNetworkHost Hosts[PlayerMax]; /// Host, port, and number of all players.
extern int NetConnectRunning; /// Network menu: Setup mode active
extern NetworkState NetStates[PlayerMax]; /// Network menu: Server: Client Host states
extern unsigned char NetLocalState; /// Network menu: Local Server/Client connect state
extern int NetLocalHostsSlot; /// Network menu: Slot # in Hosts array of local client
extern int NetLocalPlayerNumber; /// Player number of local client
@ -231,6 +232,7 @@ extern CServerSetup LocalSetupState; /// Network menu: Multiplayer Client
-- Functions
----------------------------------------------------------------------------*/
extern int FindHostIndexBy(unsigned long ip, int port);
extern void NetworkServerStartGame(); /// Server user has finally hit the start game button
extern void NetworkGamePrepareGameSettings();
extern void NetworkConnectSetupGame(); /// Assign Player slot, evaluate Setup state..
@ -240,7 +242,7 @@ extern void NetworkExitClientConnect(); /// Terminate network connect state
extern void NetworkInitServerConnect(int openslots); /// Setup network connect state machine for the server
extern void NetworkExitServerConnect(); /// Terminate network connect state machine for the server
extern int NetworkParseSetupEvent(const unsigned char *buf, int size, unsigned long host, int port); /// Parse a network connect event
extern int NetworkSetupServerAddress(const std::string &serveraddr); /// Menu: Setup the server IP
extern int NetworkSetupServerAddress(const std::string &serveraddr, int port); /// Menu: Setup the server IP
extern void NetworkProcessClientRequest(); /// Menu Loop: Send out client request messages
extern void NetworkProcessServerRequest(); /// Menu Loop: Send out server request messages
extern void NetworkServerResyncClients(); /// Menu Loop: Server: Mark clients state to send stateinfo message

File diff suppressed because it is too large Load diff

View file

@ -543,7 +543,7 @@ void InitNetwork1()
const unsigned long myHost = NetResolveHost(buf);
const int myPort = port;
DebugPrint("My host:port %d.%d.%d.%d:%d\n" _C_
NIPQUAD(ntohl(myHost)) _C_ ntohs(myPort));
NIPQUAD(ntohl(myHost)) _C_ myPort);
}
#endif
@ -864,11 +864,8 @@ void NetworkEvent()
unsigned char buf[1024];
unsigned long host;
int port;
int i;
if ((i = NetRecvUDP(NetworkFildes, &buf, sizeof(buf), &host, &port)) < 0) {
//
// Server or client gone?
//
int len = NetRecvUDP(NetworkFildes, &buf, sizeof(buf), &host, &port);
if (len < 0) {
DebugPrint("Server/Client gone?\n");
// just hope for an automatic recover right now..
NetworkInSync = 0;
@ -881,31 +878,25 @@ void NetworkEvent()
// Setup messages
if (NetConnectRunning) {
if (NetworkParseSetupEvent(buf, i, host, port)) {
if (NetworkParseSetupEvent(buf, len, host, port)) {
return;
}
}
CNetworkPacket packet;
int commands = packet.Deserialize(buf, i);
int commands = packet.Deserialize(buf, len);
if (commands < 0) {
DebugPrint("Bad packet read\n");
return;
}
for (i = 0; i < HostsCount; ++i) {
if (Hosts[i].Host == host && Hosts[i].Port == port
&& !PlayerQuit[Hosts[i].PlyNr]) {
break;
}
}
if (i == HostsCount) {
const int index = FindHostIndexBy(host, port);
if (index == -1 || PlayerQuit[Hosts[index].PlyNr]) {
DebugPrint("Not a host in play: %d.%d.%d.%d:%d\n" _C_
NIPQUAD(ntohl(host)) _C_ ntohs(port));
return;
}
const int player = Hosts[i].PlyNr;
const int player = Hosts[index].PlyNr;
// In a normal packet there is a least sync, selection may not have that
if (packet.Header.Type[0] == MessageSelection || commands == 0) {
@ -914,13 +905,13 @@ void NetworkEvent()
}
// Parse the packet commands.
for (i = 0; i < commands; ++i) {
const CNetworkCommand *nc = &packet.Command[i];
for (int i = 0; i != commands; ++i) {
const CNetworkCommand &nc = packet.Command[i];
bool validCommand = false;
// Handle some messages.
if (packet.Header.Type[i] == MessageQuit) {
int playerNum = ntohs(nc->X);
int playerNum = ntohs(nc.X);
if (playerNum >= 0 && playerNum < NumPlayers) {
PlayerQuit[playerNum] = 1;
@ -996,7 +987,7 @@ void NetworkEvent()
case MessageCommandDismiss:
// Fall through!
default: {
const unsigned int slot = ntohs(nc->Unit);
const unsigned int slot = ntohs(nc.Unit);
const CUnit *unit = slot < UnitManager.GetUsedSlotCount() ? &UnitManager.GetSlotUnit(slot) : NULL;
if (unit && (unit->Player->Index == player
@ -1012,7 +1003,7 @@ void NetworkEvent()
if (validCommand) {
NetworkIn[packet.Header.Cycle][player][i].Time = n;
NetworkIn[packet.Header.Cycle][player][i].Type = packet.Header.Type[i];
NetworkIn[packet.Header.Cycle][player][i].Data = *nc;
NetworkIn[packet.Header.Cycle][player][i].Data = nc;
} 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()
@ -1020,7 +1011,7 @@ void NetworkEvent()
}
}
for (; i < MaxNetworkCommands; ++i) {
for (int i = commands; i != MaxNetworkCommands; ++i) {
NetworkIn[packet.Header.Cycle][player][i].Time = 0;
}
@ -1067,11 +1058,12 @@ void NetworkChatMessage(const std::string &msg)
if (IsNetworkGame()) {
const char *cp = msg.c_str();
size_t n = msg.size();
while (n >= sizeof(char) * 7) {
CNetworkChat *ncm = NULL;
while (n >= sizeof(ncm->Text)) {
CNetworkCommandQueue *ncq = AllocNCQ();
MsgCommandsIn.push_back(ncq);
ncq->Type = MessageChat;
CNetworkChat *ncm = (CNetworkChat *)(&ncq->Data);
ncm = (CNetworkChat *)(&ncq->Data);
ncm->Player = ThisPlayer->Index;
memcpy(ncm->Text, cp, sizeof(ncm->Text));
cp += sizeof(ncm->Text);
@ -1080,7 +1072,7 @@ void NetworkChatMessage(const std::string &msg)
CNetworkCommandQueue *ncq = AllocNCQ();
MsgCommandsIn.push_back(ncq);
ncq->Type = MessageChatTerm;
CNetworkChat *ncm = (CNetworkChat *)(&ncq->Data);
ncm = (CNetworkChat *)(&ncq->Data);
ncm->Player = ThisPlayer->Index;
memcpy(ncm->Text, cp, n + 1); // see >= above :)
}
@ -1107,7 +1099,7 @@ static void ParseNetworkCommand_Chat(const CNetworkCommandQueue &ncq)
const CNetworkChat &ncm = reinterpret_cast<const CNetworkChat &>(ncq.Data);
int ply = ncm.Player;
if (NetMsgBufLen[ply] + sizeof(char) * 7 < 128) {
if (NetMsgBufLen[ply] + sizeof(ncm.Text) < 128) {
memcpy(NetMsgBuf[ply] + NetMsgBufLen[ply], ncm.Text, sizeof(ncm.Text));
}
NetMsgBufLen[ply] += sizeof(ncm.Text);

View file

@ -5,7 +5,7 @@ void ExitNetwork1(void);
bool IsNetworkGame();
int NetworkSetupServerAddress(const std::string serveraddr);
int NetworkSetupServerAddress(const std::string serveraddr, int port = 0);
void NetworkInitClientConnect(void);
void NetworkInitServerConnect(int openslots);
void NetworkServerStartGame(void);
@ -16,16 +16,16 @@ void NetworkServerResyncClients(void);
void NetworkDetachFromServer(void);
class CServerSetup {
unsigned int ResourcesOption;
unsigned int UnitsOption;
unsigned int FogOfWar;
unsigned int RevealMap;
unsigned int GameTypeOption;
unsigned int Difficulty;
unsigned int MapRichness;
unsigned CompOpt[PlayerMax];
unsigned Ready[PlayerMax];
unsigned Race[PlayerMax];
unsigned char ResourcesOption;
unsigned char UnitsOption;
unsigned char FogOfWar;
unsigned char RevealMap;
unsigned char GameTypeOption;
unsigned char Difficulty;
unsigned char MapRichness;
unsigned short CompOpt[PlayerMax]; // cannot use char since tolua interpret variable as string else.
unsigned short Ready[PlayerMax]; // cannot use char since tolua interpret variable as string else.
unsigned short Race[PlayerMax]; // cannot use char since tolua interpret variable as string else.
unsigned long LastFrame[PlayerMax];
};
extern CServerSetup LocalSetupState;

View file

@ -0,0 +1,115 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name test_net_lowlevel.cpp - The test file for net_lowlevel.cpp. */
//
// (c) Copyright 2013 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
#include <UnitTest++.h>
#include "stratagus.h"
#include "netconnect.h"
void FillCustomValue(CNetworkHost *obj)
{
obj->Host = 0x12345678;
obj->Port = 0x9ABC;
for (int i = 0; i != sizeof(CNetworkHost::PlyName); ++i) {
obj->PlyName[i] = i + 1;
}
obj->PlyNr = 0xDEF0;
}
void FillCustomValue(CServerSetup *obj)
{
obj->ResourcesOption = 42;
obj->UnitsOption = 44;
obj->FogOfWar = 46;
obj->RevealMap = 48;
obj->TilesetSelection = 50;
obj->GameTypeOption = 52;
obj->Difficulty = 54;
obj->MapRichness = 56;
for (int i = 0; i != PlayerMax; ++i) {
obj->CompOpt[i] = i + 1;
}
for (int i = 0; i != PlayerMax; ++i) {
obj->Ready[i] = i + 11;
}
for (int i = 0; i != PlayerMax; ++i) {
obj->Race[i] = i + 21;
}
for (int i = 0; i != PlayerMax; ++i) {
obj->LastFrame[i] = 0x22334455 + i * 0x01020304;
}
}
void FillCustomValue(CInitMessage *obj)
{
obj->Type = 0x22;
obj->SubType = ICMHello;
obj->HostsCount = 0x04;
obj->padding = 0x33;
obj->Stratagus = 0x12345678;
obj->Version = 0x90ABCDEF;
obj->MapUID = 0x09BADCFE;
obj->Lag = 0x13245768;
obj->Updates = 0x9A0BCEDF;
// it is the biggest data size.
for (int i = 0; i != PlayerMax; ++i) {
FillCustomValue(&obj->u.Hosts[i]);
}
}
template <typename T>
bool CheckSerialization()
{
T obj1;
FillCustomValue(&obj1);
const unsigned char *buffer = obj1.Serialize();
T obj2;
obj2.Deserialize(buffer);
bool res = memcmp(&obj1, &obj2, sizeof(T)) == 0;
delete [] buffer;
return res;
}
TEST(CNetworkHost)
{
CHECK(CheckSerialization<CNetworkHost>());
}
TEST(CServerSetup)
{
CHECK(CheckSerialization<CServerSetup>());
}
TEST(CInitMessage)
{
CHECK(CheckSerialization<CInitMessage>());
}

View file

@ -0,0 +1,115 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name test_net_lowlevel.cpp - The test file for net_lowlevel.cpp. */
//
// (c) Copyright 2013 by Joris Dauphin
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
#include <UnitTest++.h>
#include "stratagus.h"
#include "network.h"
void FillCustomValue(CNetworkCommand *obj)
{
obj->Dest = 0x1234;
obj->Unit = 0x5678;
obj->X = 0x9ABC;
obj->Y = 0xDEF0;
}
void FillCustomValue(CNetworkExtendedCommand *obj)
{
obj->ExtendedType = 11;
obj->Arg1 = 22;
obj->Arg2 = 0x1234;
obj->Arg3 = 0x5678;
obj->Arg4 = 0x9ABC;
}
void FillCustomValue(CNetworkChat *obj)
{
obj->Player = 42;
for (int i = 0; i != sizeof(obj->Text); ++i) {
obj->Text[i] = 1 + i;
}
}
void FillCustomValue(CNetworkSelection *obj)
{
for (int i = 0; i != 4; ++i) {
obj->Unit[i] = 0x1234 * i;
}
}
void FillCustomValue(CNetworkPacketHeader *obj)
{
obj->Cycle = 42;
for (int i = 0; i != MaxNetworkCommands; ++i) {
obj->Type[i] = 0x05 + i * 0x12;
}
}
// CNetworkPacket
template <typename T>
bool CheckSerialization()
{
T obj1;
FillCustomValue(&obj1);
unsigned char *buffer = new unsigned char [T::Size()];
obj1.Serialize(buffer);
T obj2;
obj2.Deserialize(buffer);
bool res = memcmp(&obj1, &obj2, sizeof(T)) == 0;
delete [] buffer;
return res;
}
TEST(CNetworkCommand)
{
CHECK(CheckSerialization<CNetworkCommand>());
}
TEST(CNetworkExtendedCommand)
{
CHECK(CheckSerialization<CNetworkExtendedCommand>());
}
TEST(CNetworkChat)
{
CHECK(CheckSerialization<CNetworkChat>());
}
#if 0
TEST(CNetworkSelection)
{
CHECK(CheckSerialization<CNetworkSelection>());
}
#endif
TEST(CNetworkPacketHeader)
{
CHECK(CheckSerialization<CNetworkPacketHeader>());
}