/*==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 . 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 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 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