You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

424 lines
12 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
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, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnNetCli/pnNetCli.h
*
***/
#ifndef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETCLI_PNNETCLI_H
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETCLI_PNNETCLI_H
/*****************************************************************************
*
*
How to create a message sender/receiver:
1. Define message ids
enum {
kMsgMoveObject,
kMsgPlayerJoin,
kMsgPing,
kMsgPingReply,
// etc.
};
2. Define packed message structures
#include <PshPack1.h>
struct MoveObject {
dword messageId;
dword objectId;
float newPos[3];
};
struct PlayerJoin {
dword messageId;
dword playerId;
wchar name[kPlayerNameMaxLength];
byte data[kPlayerDataMaxLength];
dword vaultDataLen;
byte vaultData[1]; // vaultData[vaultDataLen], actually
// no more fields after variable-length data
};
struct Ping {
dword messageId;
dword pingTimeMs;
};
struct PingReply {
dword messageId;
dword pingTimeMs;
}
#include <PopPack.h>
3. Define message fields
static const NetMsgField kFieldObjectId = NET_MSG_FIELD_DWORD();
static const NetMsgField kFieldPlayerId = NET_MSG_FIELD_DWORD();
static const NetMsgField kFieldObjectPos = NET_MSG_FIELD_FLOAT_ARRAY(3);
static const NetMsgField kFieldPlayerName = NET_MSG_FIELD_STRING(kPlayerNameMaxLength);
static const NetMsgField kFieldPlayerData = NET_MSG_FIELD_PTR(kPlayerDataMaxLength);
static const NetMsgField kFieldVaultDataLen = NET_MSG_FIELD_VAR_COUNT(kVaultDataMaxLength);
static const NetMsgField kFieldVaultData = NET_MSG_FIELD_VAR_PTR();
static const NetMsgField kFieldPingTimeMs = NET_MSG_FIELD_DWORD();
4. Build field and message description blocks
// MoveObject
static const NetMsgField s_moveObjectFields[] = {
kFieldObjectId,
kFieldObjectPos,
};
static const NetMsg s_msgMoveObject = NET_MSG(kMsgMoveObject, s_msgMoveObjectFields);
// PlayerJoin
static const NetMsgField s_playerJoinFields[] = {
kFieldPlayerId,
kFieldPlayerName,
kFieldPlayerData,
kFieldVaultDataLen,
kFieldVaultData,
};
static const NetMsg s_playerJoin = NET_MSG(kMsgPlayerJoin, s_msgPlayerJoin);
5. Register message description blocks
// for server:
static const NetMsgInitSend s_srvSend[] = {
{ s_moveObject },
{ s_playerJoin },
{ s_ping },
};
static const NetMsgInitRecv s_srvRecv[] = {
{ s_pingReply, RecvMsgPingReply },
};
s_srvConn = NetMsgProtocolRegister(
kNetProtocolCliToGame,
true,
s_srvSend, arrsize(s_srvSend),
s_srvRecv, arrsize(s_srvRecv)
);
// for client:
static const NetMsgInitSend s_cliSend[] = {
{ s_pingReply },
};
static const NetMsgInitRecv s_cliRecv[] = {
{ s_moveObject, RecvMsgMoveObject },
{ s_playerJoin, RecvMsgPlayerJoin },
{ s_ping, RecvMsgPing },
};
s_cliConn = NetMsgProtocolRegister(
kNetProtocolCliToGame,
false,
s_cliSend, arrsize(s_cliSend),
s_cliRecv, arrsize(s_cliRecv)
);
5. Send messages
static void SendMoveObject (NetCli client, const Object * obj) {
const unsigned_ptr msgMoveObject[] = {
kMsgMoveObject,
obj->id,
3, (unsigned_ptr) &obj->pos,
};
NetCliSend(client, msgMoveObject, arrsize(msgMoveObject));
}
static void SendPlayerJoin (NetCli client, const Player * player) {
const unsigned_ptr msgPlayerJoin[] = {
kMsgPlayerJoin,
player->name,
player->data,
player->vault->Count(),
player->vault->Ptr()
};
NetCliSend(client, msgPlayerJoin, arrsize(msgPlayerJoin));
};
static void SendPing (NetCli player) {
const unsigned_ptr msgPing[] = {
kMsgPing,
TimeGetMs(),
};
NetCliSend(player, msgPing, arrsize(msgPing));
}
6. Receive messages
bool RecvMsgPing (const byte msg[], NetCli * from, void * param) {
Player * player = (Player *) param;
const Ping * ping = (const Ping *) msg;
const unsigned_ptr msgPingReply[] = {
kMsgPingReply,
ping->pingTimeMs,
};
MsgConnSend(from, msgPingReply, arrsize(msgPingReply));
}
*
***/
/*****************************************************************************
*
* Constants
*
***/
/*****************************************************************************
*
* Field definition types
*
***/
enum ENetMsgFieldType {
// Compressable fields
kNetMsgFieldInteger,
kNetMsgFieldReal,
kNetMsgFieldString, // variable length unicode string
kNetMsgFieldData, // data with length <= sizeof(dword)
kNetMsgFieldPtr, // pointer to fixed length data
kNetMsgFieldVarPtr, // pointer to variable length data
// Non-compressible fields (images, sounds, encrypted data, etc)
kNetMsgFieldRawData, // data with length <= sizeof(dword)
kNetMsgFieldRawPtr, // pointer to fixed length data
kNetMsgFieldRawVarPtr, // pointer to variable length data
kNetMsgFieldVarCount, // count for kNetMsgFieldVarPtr and kNetMsgFieldRawVarPtr
kNumNetMsgFieldTypes
};
struct NetMsgField {
ENetMsgFieldType type; // element type
unsigned count; // max number of elements
unsigned size; // element size
};
struct NetMsg {
const char * name;
unsigned messageId;
const NetMsgField * fields;
unsigned count;
};
// Opaque types
struct NetCli;
struct NetCliQueue;
/*****************************************************************************
*
* Msg and field definition macros
*
***/
#define NET_MSG(msgId, msgFields) { #msgId, msgId, msgFields, arrsize(msgFields) }
#define NET_MSG_FIELD(type, count, size) { type, count, size }
#define NET_MSG_FIELD_BYTE() NET_MSG_FIELD(kNetMsgFieldInteger, 0, sizeof(byte))
#define NET_MSG_FIELD_WORD() NET_MSG_FIELD(kNetMsgFieldInteger, 0, sizeof(word))
#define NET_MSG_FIELD_DWORD() NET_MSG_FIELD(kNetMsgFieldInteger, 0, sizeof(dword))
#define NET_MSG_FIELD_QWORD() NET_MSG_FIELD(kNetMsgFieldInteger, 0, sizeof(qword))
#define NET_MSG_FIELD_FLOAT() NET_MSG_FIELD(kNetMsgFieldReal, 0, sizeof(float))
#define NET_MSG_FIELD_DOUBLE() NET_MSG_FIELD(kNetMsgFieldReal, 0, sizeof(double))
#define NET_MSG_FIELD_BYTE_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldInteger, maxCount, sizeof(byte))
#define NET_MSG_FIELD_WORD_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldInteger, maxCount, sizeof(word))
#define NET_MSG_FIELD_DWORD_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldInteger, maxCount, sizeof(dword))
#define NET_MSG_FIELD_QWORD_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldInteger, maxCount, sizeof(qword))
#define NET_MSG_FIELD_FLOAT_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldReal, maxCount, sizeof(float))
#define NET_MSG_FIELD_DOUBLE_ARRAY(maxCount) NET_MSG_FIELD(kNetMsgFieldReal, maxCount, sizeof(double))
#define NET_MSG_FIELD_STRING(maxLength) NET_MSG_FIELD(kNetMsgFieldString, maxLength, sizeof(wchar))
#define NET_MSG_FIELD_DATA(maxBytes) NET_MSG_FIELD(kNetMsgFieldData, maxBytes, 1)
#define NET_MSG_FIELD_PTR(maxBytes) NET_MSG_FIELD(kNetMsgFieldPtr, maxBytes, 1)
#define NET_MSG_FIELD_RAW_DATA(maxBytes) NET_MSG_FIELD(kNetMsgFieldRawData, maxBytes, 1)
#define NET_MSG_FIELD_RAW_PTR(maxBytes) NET_MSG_FIELD(kNetMsgFieldRawPtr, maxBytes, 1)
#define NET_MSG_FIELD_VAR_PTR() NET_MSG_FIELD(kNetMsgFieldVarPtr, 0, 0)
#define NET_MSG_FIELD_RAW_VAR_PTR() NET_MSG_FIELD(kNetMsgFieldRawVarPtr, 0, 0)
#define NET_MSG_FIELD_VAR_COUNT(elemSize, maxCount) NET_MSG_FIELD(kNetMsgFieldVarCount, maxCount, elemSize)
/*****************************************************************************
*
* Message channels
*
***/
struct NetMsgInitSend {
NetMsg msg;
};
struct NetMsgInitRecv {
NetMsg msg;
bool (* recv)(const byte msg[], unsigned bytes, void * param);
};
void NetMsgProtocolRegister (
unsigned protocol, // from pnNetBase/pnNbProtocol.h
bool server,
const NetMsgInitSend sendMsgs[], // messages this program can send
unsigned sendMsgCount,
const NetMsgInitRecv recvMsgs[], // messages this program can receive
unsigned recvMsgCount,
// Diffie-Hellman keys
unsigned dh_g,
const BigNum & dh_xa, // client: dh_x server: dh_a
const BigNum & dh_n
);
void NetMsgProtocolDestroy (
unsigned protocol,
bool server
);
/*****************************************************************************
*
* NetCliQueue
*
***/
NetCliQueue * NetCliQueueCreate (
unsigned flushTimeMs
);
void NetCliQueueDestroy (
NetCliQueue * queue
);
void NetCliQueueFlush (
NetCliQueue * queue
);
float NetCliQueueQueryFlush (
NetCliQueue * queue
);
/*****************************************************************************
*
* NetCli
*
***/
typedef bool (* FNetCliEncrypt) (
ENetError error,
void * encryptParam
);
NetCli * NetCliConnectAccept (
AsyncSocket sock,
unsigned protocol,
bool unbuffered,
FNetCliEncrypt encryptFcn,
unsigned seedBytes, // optional
const byte seedData[], // optional
void * encryptParam // optional
);
#ifdef SERVER
NetCli * NetCliListenAccept (
AsyncSocket sock,
unsigned protocol,
bool unbuffered,
FNetCliEncrypt encryptFcn,
unsigned seedBytes, // optional
const byte seedData[], // optional
void * encryptParam // optional
);
#endif
#ifdef SERVER
void NetCliListenReject (
AsyncSocket sock,
ENetError error
);
#endif
void NetCliClearSocket (
NetCli * cli
);
void NetCliSetQueue (
NetCli * cli,
NetCliQueue * queue
);
void NetCliDisconnect (
NetCli * cli,
bool hardClose
);
void NetCliDelete (
NetCli * cli,
bool deleteSocket
);
void NetCliFlush (
NetCli * cli
);
void NetCliSend (
NetCli * cli,
const unsigned_ptr msg[],
unsigned count
);
bool NetCliDispatch (
NetCli * cli,
const byte buffer[],
unsigned bytes,
void * param
);
#endif // PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETCLI_PNNETCLI_H