声明:本文参考了langresser发布的blog“跨平台的游戏客户端Socket封装”
Socket处理是异步非阻塞的,所以可以放心的放到主线程处理消息,并且在原作者的基本上进行了系列优化,考虑了客户端可能建立多个SOCKET,因此加入了Manager概念,与cocos2d-x进行了融合。
本文基于cocos2d-x3.0+VS2012
文件目录结构截图:
文件源码:
TCPSocket.h
#ifndef __CC_TCPSOCKET_H__
#define __CC_TCPSOCKET_H__ #include "cocos2d.h"
#include "ExtensionMacros.h"
#include "WorldPacket.h"
#ifdef WIN32
#include <windows.h>
#include <WinSock.h>
#pragma comment( lib, "ws2_32.lib" )
#else
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1 #endif NS_CC_EXT_BEGIN
#ifndef CHECKF
#define CHECKF(x) \
do \
{ \
if (!(x)) { \
log_msg("CHECKF", #x, __FILE__, __LINE__); \
return ; \
} \
} while ()
#endif #define _MAX_MSGSIZE 16 * 1024 // 暂定一个消息最大为16k
#define BLOCKSECONDS 30 // INIT函数阻塞时间
#define INBUFSIZE (64*1024) //? 具体尺寸根据剖面报告调整 接收数据的缓存
#define OUTBUFSIZE (8*1024) //? 具体尺寸根据剖面报告调整。 发送数据的缓存,当不超过8K时,FLUSH只需要SEND一次 class CC_DLL TCPSocket
{
public:
TCPSocket(void);
bool Create(const char* pszServerIP, int nServerPort, int tagid, int nBlockSec = BLOCKSECONDS, bool bKeepAlive = false);
bool SendMsg(void* pBuf, int nSize);
bool ReceiveMsg(void* pBuf, int& nSize);
bool Flush(void);
bool Check(void);
void Destroy(void);
SOCKET GetSocket(void) const { return m_sockClient; } int getTagID(){ return m_tag; }
private:
bool recvFromSock(void); // 从网络中读取尽可能多的数据
bool hasError(); // 是否发生错误,注意,异步模式未完成非错误
void closeSocket(); SOCKET m_sockClient; // 发送数据缓冲
char m_bufOutput[OUTBUFSIZE]; //? 可优化为指针数组
int m_nOutbufLen; // 环形缓冲区
char m_bufInput[INBUFSIZE];
int m_nInbufLen;
int m_nInbufStart; // INBUF使用循环式队列,该变量为队列起点,0 - (SIZE-1)
int m_tag;
}; typedef std::function<bool(int,int,WorldPacket&)> ProAllFunc; // 接收所有协议,自行处理,@socket标识,@协议头,@数据包,返回是否分发
typedef std::function<void(int,WorldPacket&)> ProFunc; // 接收单个协议,@socket标识,@数据包
typedef std::function<void(int)> sckFunc; // 连接成功/断开事件 #define SCT_CALLBACK_1(func, _Object) std::bind(&func,_Object, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
#define SCT_CALLBACK_2(func, _Object) std::bind(&func,_Object, std::placeholders::_1, std::placeholders::_2)
#define SCT_CALLBACK_3(func, _Object) std::bind(&func,_Object, std::placeholders::_1)
// 创建SOCKET管理器
#define CREATE_TCPSOCKETMGR(pNode) pNode->addChild(new TCPSocketManager(), 0) class CC_DLL TCPSocketManager :
public Node
{
public:
TCPSocketManager()
{
assert(!mSingleton);
this->mSingleton = this;
// 开启update
scheduleUpdate();
};
~TCPSocketManager(){};
// 创建socket并添加到管理器
TCPSocket *createSocket(const char* pszServerIP, // IP地址
int nServerPort, // 端口
int _tag, // 标识ID
int nBlockSec = BLOCKSECONDS, // 阻塞时间ms
bool bKeepAlive = false);
// 注册协议包
void register_process(const uint16 &entry, ProFunc callback);
// 注册接收所有协议
void register_all_process(ProAllFunc callback){ _pProcess = callback; }
// 注册socket连接成功事件
void register_connect(sckFunc callback){ _pOnConnect = callback; }
// 注册socket断线事件
void register_disconnect(sckFunc callback){ _OnDisconnect = callback; } // 单独添加socket到管理器
bool addSocket(TCPSocket *pSocket);
// 删除socket
bool removeSocket(int _tag);
// 断开socket
void disconnect(int _tag);
// 获取socket
TCPSocket *GetSocket(int _tag);
// 发送消息
bool SendPacket(int _tag, WorldPacket *packet); void update(float delta); static TCPSocketManager &getSingleton(){ assert(mSingleton); return *mSingleton;} private:
ProAllFunc _pProcess;
sckFunc _pOnConnect;
sckFunc _OnDisconnect;
std::list<TCPSocket*> m_lstSocket;
std::map<uint16, ProFunc> _mapProcess;
static TCPSocketManager * mSingleton;
}; #define sSocketMgr TCPSocketManager::getSingleton()
NS_CC_EXT_END #endif //__CC_TCPSOCKET_H__
TCPSocket.cpp
#include "TCPSocket.h"
#include "support/zip_support/unzip.h" NS_CC_EXT_BEGIN
TCPSocket::TCPSocket()
{
// 初始化
memset(m_bufOutput, , sizeof(m_bufOutput));
memset(m_bufInput, , sizeof(m_bufInput));
} void TCPSocket::closeSocket()
{
#ifdef WIN32
closesocket(m_sockClient);
WSACleanup();
#else
close(m_sockClient);
#endif
} bool TCPSocket::Create(const char* pszServerIP, int nServerPort, int tagid, int nBlockSec, bool bKeepAlive /*= FALSE*/)
{
// 检查参数
if(pszServerIP == || strlen(pszServerIP) > ) {
return false;
} #ifdef WIN32
WSADATA wsaData;
WORD version = MAKEWORD(, );
int ret = WSAStartup(version, &wsaData);//win sock start up
if (ret != ) {
return false;
}
#endif // 创建主套接字
m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_sockClient == INVALID_SOCKET) {
closeSocket();
return false;
} // 设置SOCKET为KEEPALIVE
if(bKeepAlive)
{
int optval=;
if(setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char *) &optval, sizeof(optval)))
{
closeSocket();
return false;
}
} #ifdef WIN32
DWORD nMode = ;
int nRes = ioctlsocket(m_sockClient, FIONBIO, &nMode);
if (nRes == SOCKET_ERROR) {
closeSocket();
return false;
}
#else
// 设置为非阻塞方式
fcntl(m_sockClient, F_SETFL, O_NONBLOCK);
#endif unsigned long serveraddr = inet_addr(pszServerIP);
if(serveraddr == INADDR_NONE) // 检查IP地址格式错误
{
closeSocket();
return false;
} sockaddr_in addr_in;
memset((void *)&addr_in, , sizeof(addr_in));
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(nServerPort);
addr_in.sin_addr.s_addr = serveraddr; if(connect(m_sockClient, (sockaddr *)&addr_in, sizeof(addr_in)) == SOCKET_ERROR) {
if (hasError()) {
closeSocket();
return false;
}
else // WSAWOLDBLOCK
{
timeval timeout;
timeout.tv_sec = nBlockSec;
timeout.tv_usec = ;
fd_set writeset, exceptset;
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
FD_SET(m_sockClient, &writeset);
FD_SET(m_sockClient, &exceptset); int ret = select(FD_SETSIZE, NULL, &writeset, &exceptset, &timeout);
if (ret == || ret < ) {
closeSocket();
return false;
} else // ret > 0
{
ret = FD_ISSET(m_sockClient, &exceptset);
if(ret) // or (!FD_ISSET(m_sockClient, &writeset)
{
closeSocket();
return false;
}
}
}
} m_nInbufLen = ;
m_nInbufStart = ;
m_nOutbufLen = ; struct linger so_linger;
so_linger.l_onoff = ;
so_linger.l_linger = ;
setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));
m_tag = tagid;
return true;
} bool TCPSocket::SendMsg(void* pBuf, int nSize)
{
if(pBuf == || nSize <= ) {
return false;
} if (m_sockClient == INVALID_SOCKET) {
return false;
} // 检查通讯消息包长度
int packsize = ;
packsize = nSize; // 检测BUF溢出
if(m_nOutbufLen + nSize > OUTBUFSIZE) {
// 立即发送OUTBUF中的数据,以清空OUTBUF。
Flush();
if(m_nOutbufLen + nSize > OUTBUFSIZE) {
// 出错了
Destroy();
return false;
}
}
// 数据添加到BUF尾
memcpy(m_bufOutput + m_nOutbufLen, pBuf, nSize);
m_nOutbufLen += nSize;
return true;
} bool TCPSocket::ReceiveMsg(void* pBuf, int& nSize)
{
//检查参数
if(pBuf == NULL || nSize <= ) {
return false;
} if (m_sockClient == INVALID_SOCKET) {
return false;
} // 检查是否有一个消息(小于2则无法获取到消息长度)
if(m_nInbufLen < ) {
// 如果没有请求成功 或者 如果没有数据则直接返回
if(!recvFromSock() || m_nInbufLen < ) { // 这个m_nInbufLen更新了
return false;
}
} // 计算要拷贝的消息的大小(一个消息,大小为整个消息的第一个16字节),因为环形缓冲区,所以要分开计算
int packsize = (unsigned char)m_bufInput[m_nInbufStart+] +
(unsigned char)m_bufInput[(m_nInbufStart + ) % INBUFSIZE] * ; // 注意字节序,高位+低位 // 检测消息包尺寸错误 暂定最大16k
if (packsize <= || packsize > _MAX_MSGSIZE) {
m_nInbufLen = ; // 直接清空INBUF
m_nInbufStart = ;
return false;
} // 检查消息是否完整(如果将要拷贝的消息大于此时缓冲区数据长度,需要再次请求接收剩余数据)
if (packsize > m_nInbufLen) {
// 如果没有请求成功 或者 依然无法获取到完整的数据包 则返回,直到取得完整包
if (!recvFromSock() || packsize > m_nInbufLen) { // 这个m_nInbufLen已更新
return false;
}
} // 复制出一个消息
if(m_nInbufStart + packsize > INBUFSIZE) {
// 如果一个消息有回卷(被拆成两份在环形缓冲区的头尾)
// 先拷贝环形缓冲区末尾的数据
int copylen = INBUFSIZE - m_nInbufStart;
memcpy(pBuf, m_bufInput + m_nInbufStart, copylen); // 再拷贝环形缓冲区头部的剩余部分
memcpy((unsigned char *)pBuf + copylen, m_bufInput, packsize - copylen);
nSize = packsize;
} else {
// 消息没有回卷,可以一次拷贝出去
memcpy(pBuf, m_bufInput + m_nInbufStart, packsize);
nSize = packsize;
} // 重新计算环形缓冲区头部位置
m_nInbufStart = (m_nInbufStart + packsize) % INBUFSIZE;
m_nInbufLen -= packsize;
return true;
} bool TCPSocket::hasError()
{
#ifdef WIN32
int err = WSAGetLastError();
if(err != WSAEWOULDBLOCK) {
#else
int err = errno;
if(err != EINPROGRESS && err != EAGAIN) {
#endif
return true;
} return false;
} // 从网络中读取尽可能多的数据,实际向服务器请求数据的地方
bool TCPSocket::recvFromSock(void)
{
if (m_nInbufLen >= INBUFSIZE || m_sockClient == INVALID_SOCKET) {
return false;
} // 接收第一段数据
int savelen, savepos; // 数据要保存的长度和位置
if(m_nInbufStart + m_nInbufLen < INBUFSIZE) { // INBUF中的剩余空间有回绕
savelen = INBUFSIZE - (m_nInbufStart + m_nInbufLen); // 后部空间长度,最大接收数据的长度
} else {
savelen = INBUFSIZE - m_nInbufLen;
} // 缓冲区数据的末尾
savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;
//CHECKF(savepos + savelen <= INBUFSIZE);
int inlen = recv(m_sockClient, m_bufInput + savepos, savelen, );
if(inlen > ) {
// 有接收到数据
m_nInbufLen += inlen; if (m_nInbufLen > INBUFSIZE) {
return false;
} // 接收第二段数据(一次接收没有完成,接收第二段数据)
if(inlen == savelen && m_nInbufLen < INBUFSIZE) {
int savelen = INBUFSIZE - m_nInbufLen;
int savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;
//CHECKF(savepos + savelen <= INBUFSIZE);
inlen = recv(m_sockClient, m_bufInput + savepos, savelen, );
if(inlen > ) {
m_nInbufLen += inlen;
if (m_nInbufLen > INBUFSIZE) {
return false;
}
} else if(inlen == ) {
Destroy();
return false;
} else {
// 连接已断开或者错误(包括阻塞)
if (hasError()) {
Destroy();
return false;
}
}
}
} else if(inlen == ) {
Destroy();
return false;
} else {
// 连接已断开或者错误(包括阻塞)
if (hasError()) {
Destroy();
return false;
}
} return true;
} bool TCPSocket::Flush(void) //? 如果 OUTBUF > SENDBUF 则需要多次SEND()
{
if (m_sockClient == INVALID_SOCKET) {
return false;
} if(m_nOutbufLen <= ) {
return true;
} // 发送一段数据
int outsize;
outsize = send(m_sockClient, m_bufOutput, m_nOutbufLen, );
if(outsize > ) {
// 删除已发送的部分
if(m_nOutbufLen - outsize > ) {
memcpy(m_bufOutput, m_bufOutput + outsize, m_nOutbufLen - outsize);
} m_nOutbufLen -= outsize; if (m_nOutbufLen < ) {
return false;
}
} else {
if (hasError()) {
Destroy();
return false;
}
} return true;
} bool TCPSocket::Check(void)
{
// 检查状态
if (m_sockClient == INVALID_SOCKET) {
return false;
} char buf[];
int ret = recv(m_sockClient, buf, , MSG_PEEK);
if(ret == ) {
Destroy();
return false;
} else if(ret < ) {
if (hasError()) {
Destroy();
return false;
} else { // 阻塞
return true;
}
} else { // 有数据
return true;
} return true;
} void TCPSocket::Destroy(void)
{
// 关闭
struct linger so_linger;
so_linger.l_onoff = ;
so_linger.l_linger = ;
int ret = setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger)); closeSocket(); m_sockClient = INVALID_SOCKET;
m_nInbufLen = ;
m_nInbufStart = ;
m_nOutbufLen = ; memset(m_bufOutput, , sizeof(m_bufOutput));
memset(m_bufInput, , sizeof(m_bufInput));
} TCPSocketManager *TCPSocketManager::mSingleton = ;
TCPSocket *TCPSocketManager::createSocket(const char* pszServerIP, // IP地址
int nServerPort, // 端口
int _tag, // 标识ID
int nBlockSec, // 阻塞时间ms
bool bKeepAlive)
{
TCPSocket *pSocket = new TCPSocket();
if (pSocket->Create(pszServerIP, nServerPort, _tag, nBlockSec, bKeepAlive))
{
assert(addSocket(pSocket));
if (_pOnConnect){
_pOnConnect(_tag);
}
return pSocket;
} delete pSocket;
return NULL;
} bool TCPSocketManager::addSocket(TCPSocket *pSocket)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
if ((*iter)->GetSocket() == pSocket->GetSocket())
return false;
}
m_lstSocket.push_back(pSocket);
return true;
} // 删除socket
bool TCPSocketManager::removeSocket(int _tag)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
if ((*iter)->getTagID() == _tag)
{
(*iter)->Destroy();
m_lstSocket.erase(iter);
return true;
}
}
return false;
} TCPSocket *TCPSocketManager::GetSocket(int _tag)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
if ((*iter)->getTagID() == _tag)
{
return *iter;
}
}
return NULL;
} void TCPSocketManager::update(float delta)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
TCPSocket *pSocket = *iter;
int _tag = pSocket->getTagID();
if (!pSocket->Check())
{// 掉线了
_OnDisconnect(_tag);
m_lstSocket.erase(iter);
break;
} while (true)
{
char buffer[_MAX_MSGSIZE] = {};
int nSize = sizeof(buffer);
char *pbufMsg = buffer;
if (!pSocket->ReceiveMsg(pbufMsg, nSize))
break;
WorldPacket packet;
uint16 _cmd, _length;
packet.Write((uint8*)pbufMsg, nSize);
packet >> _cmd >> _length;
if (_cmd & 0x8000)
{
Byte uncompr[] = {};
uLong uncomprLen;
_cmd &= 0x7fff;
uncompress(uncompr, &uncomprLen, packet.contents()+, packet.size()-);
} if (_pProcess == || _pProcess(pSocket->getTagID(), _cmd, packet))
{// 分发数据
std::map<uint16, ProFunc>::iterator mapi = _mapProcess.find(_cmd);
if (mapi == _mapProcess.end())
continue;
mapi->second(pSocket->getTagID(), packet);
}
}
}
} void TCPSocketManager::register_process(const uint16 &entry, ProFunc callback)
{
_mapProcess[entry] = callback;
} bool TCPSocketManager::SendPacket(int _tag, WorldPacket *packet)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
if ((*iter)->getTagID() == _tag)
{
(*iter)->SendMsg((void *)packet->contents(), packet->size());
return (*iter)->Flush();
}
} return false;
} void TCPSocketManager::disconnect(int _tag)
{
std::list<TCPSocket*>::iterator iter, enditer = m_lstSocket.end();
for (iter = m_lstSocket.begin(); iter != enditer; ++ iter)
{
if ((*iter)->getTagID() == _tag)
{
(*iter)->Destroy();
if (_OnDisconnect){
_OnDisconnect(_tag);
}
break;
}
}
} NS_CC_EXT_END
ByteBuffer.h (读写数据包)
/****************************************************************************
*
* ByteBuffer Class
*
*/ #ifndef _BYTEBUFFER_H
#define _BYTEBUFFER_H #include "Common.h"
//#include "Vector3.h" class ByteBuffer
{
#define DEFAULT_SIZE 0x1000
#define DEFAULT_INCREASE_SIZE 200
uint8 * m_buffer;
size_t m_readPos;
size_t m_writePos;
uint32 m_buffersize; public:
/** Creates a bytebuffer with the default size
*/
ByteBuffer()
{
m_buffer =;
m_readPos = m_writePos = ;
m_buffersize = ;
reserve(DEFAULT_SIZE);
} /** Creates a bytebuffer with the specified size
*/
ByteBuffer(size_t res)
{
m_buffer =;
m_readPos = m_writePos = ;
m_buffersize = ;
reserve(res);
} /** Frees the allocated buffer
*/
~ByteBuffer()
{
free(m_buffer);
} /** Allocates/reallocates buffer with specified size.
*/
void reserve(size_t res)
{
if(m_buffer)
m_buffer = (uint8*)realloc(m_buffer, res);
else
m_buffer = (uint8*)malloc(res); m_buffersize = res;
} /** Resets read/write indexes
*/
inline void clear()
{
m_readPos = m_writePos = ;
} /** Sets write position
*/
inline void resize(size_t size)
{
m_writePos = size;
} /** Returns the buffer pointer
*/
inline const uint8 * contents()
{
return m_buffer;
} /** Gets the buffer size.
*/
uint32 GetBufferSize() { return m_writePos; } /** Reads sizeof(T) bytes from the buffer
* @return the bytes read
*/
template<typename T>
T Read()
{
if(m_readPos + sizeof(T) > m_writePos)
return (T);
T ret = *(T*)&m_buffer[m_readPos];
m_readPos += sizeof(T);
return ret;
} void skip(size_t len)
{
if(m_readPos + len > m_writePos)
len = (m_writePos - m_readPos);
m_readPos += len;
} /** Reads x bytes from the buffer
*/
void read(uint8 * buffer, size_t len)
{
if(m_readPos + len > m_writePos)
len = (m_writePos - m_readPos); memcpy(buffer, &m_buffer[m_readPos], len);
m_readPos += len;
} /** Writes sizeof(T) bytes to the buffer, while checking for overflows.
* @param T data The data to be written
*/
template<typename T>
void Write(const T & data)
{
size_t new_size = m_writePos + sizeof(T);
if(new_size > m_buffersize)
{
new_size = (new_size / DEFAULT_INCREASE_SIZE + ) * DEFAULT_INCREASE_SIZE;
reserve(new_size);
} *(T*)&m_buffer[m_writePos] = data;
m_writePos += sizeof(T);
} /** writes x bytes to the buffer, while checking for overflows
* @param ptr the data to be written
* @param size byte count
*/
void Write(const uint8 * data, size_t size)
{
size_t new_size = m_writePos + size;
if(new_size > m_buffersize)
{
new_size = (new_size / DEFAULT_INCREASE_SIZE + ) * DEFAULT_INCREASE_SIZE;
reserve(new_size);
} memcpy(&m_buffer[m_writePos], data, size);
m_writePos += size;
} /** Ensures the buffer is big enough to fit the specified number of bytes.
* @param bytes number of bytes to fit
*/
inline void EnsureBufferSize(uint32 Bytes)
{
size_t new_size = m_writePos + Bytes;
if(new_size > m_buffersize)
{
new_size = (new_size / DEFAULT_INCREASE_SIZE + ) * DEFAULT_INCREASE_SIZE;
reserve(new_size);
} } /** These are the default read/write operators.
*/
#define DEFINE_BUFFER_READ_OPERATOR(type) void operator >> (type& dest) { dest = Read<type>(); }
#define DEFINE_BUFFER_WRITE_OPERATOR(type) void operator << (const type src) { Write<type>(src); } /** Fast read/write operators without using the templated read/write functions.
*/
#define DEFINE_FAST_READ_OPERATOR(type, size) ByteBuffer& operator >> (type& dest) { if(m_readPos + size > m_writePos) { dest = (type)0; return *this; } else { dest = *(type*)&m_buffer[m_readPos]; m_readPos += size; return *this; } }
#define DEFINE_FAST_WRITE_OPERATOR(type, size) ByteBuffer& operator << (const type src) { if(m_writePos + size > m_buffersize) { reserve(m_buffersize + DEFAULT_INCREASE_SIZE); } *(type*)&m_buffer[m_writePos] = src; m_writePos += size; return *this; } /** Integer/float r/w operators
*/
DEFINE_FAST_READ_OPERATOR(uint64, );
DEFINE_FAST_READ_OPERATOR(uint32, );
DEFINE_FAST_READ_OPERATOR(uint16, );
DEFINE_FAST_READ_OPERATOR(uint8, );
DEFINE_FAST_READ_OPERATOR(int64, );
DEFINE_FAST_READ_OPERATOR(int32, );
DEFINE_FAST_READ_OPERATOR(int16, );
DEFINE_FAST_READ_OPERATOR(int8, );
DEFINE_FAST_READ_OPERATOR(float, );
DEFINE_FAST_READ_OPERATOR(double, ); DEFINE_FAST_WRITE_OPERATOR(uint64, );
DEFINE_FAST_WRITE_OPERATOR(uint32, );
DEFINE_FAST_WRITE_OPERATOR(uint16, );
DEFINE_FAST_WRITE_OPERATOR(uint8, );
DEFINE_FAST_WRITE_OPERATOR(int64, );
DEFINE_FAST_WRITE_OPERATOR(int32, );
DEFINE_FAST_WRITE_OPERATOR(int16, );
DEFINE_FAST_WRITE_OPERATOR(int8, );
DEFINE_FAST_WRITE_OPERATOR(float, );
DEFINE_FAST_WRITE_OPERATOR(double, ); /** boolean (1-byte) read/write operators
*/
DEFINE_FAST_WRITE_OPERATOR(bool, );
ByteBuffer& operator >> (bool & dst) { dst = (Read<char>() > ? true : false); return *this; } /** string (null-terminated) operators
*/
ByteBuffer& operator << (const std::string & value) { EnsureBufferSize(value.length() + ); memcpy(&m_buffer[m_writePos], value.c_str(), value.length()+); m_writePos += (value.length() + ); return *this; }
ByteBuffer& operator >> (std::string & dest)
{
dest.clear();
char c;
for(;;)
{
c = Read<char>();
if(c == ) break;
dest += c;
}
return *this;
} /** Gets the write position
* @return buffer size
*/
inline size_t size() { return m_writePos; } /** read/write position setting/getting
*/
inline size_t rpos() { return m_readPos; }
inline size_t wpos() { return m_writePos; }
inline void rpos(size_t p) { assert(p <= m_writePos); m_readPos = p; }
inline void wpos(size_t p) { assert(p <= m_buffersize); m_writePos = p; } template<typename T> size_t writeVector(std::vector<T> &v)
{
for (typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); i++) {
Write<T>(*i);
}
return v.size(); }
template<typename T> size_t readVector(size_t vsize, std::vector<T> &v)
{ v.clear();
while(vsize--) {
T t = Read<T>();
v.push_back(t);
}
return v.size();
} template<typename T> size_t writeList(std::list<T> &v)
{
for (typename std::list<T>::const_iterator i = v.begin(); i != v.end(); i++) {
Write<T>(*i);
}
return v.size(); }
template<typename T> size_t readList(size_t vsize, std::list<T> &v)
{ v.clear();
while(vsize--) {
T t = Read<T>();
v.push_back(t);
}
return v.size();
} template <typename K, typename V> size_t writeMap(const std::map<K, V> &m)
{
for (typename std::map<K, V>::const_iterator i = m.begin(); i != m.end(); i++) {
Write<K>(i->first);
Write<V>(i->second);
}
return m.size();
} template <typename K, typename V> size_t readMap(size_t msize, std::map<K, V> &m)
{
m.clear();
while(msize--) {
K k = Read<K>();
V v = Read<V>();
m.insert(make_pair(k, v));
}
return m.size();
} }; ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// template <typename T> ByteBuffer &operator<<(ByteBuffer &b, const std::vector<T> & v)
{
b << (uint32)v.size();
for (typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); i++) {
b << *i;
}
return b;
} template <typename T> ByteBuffer &operator>>(ByteBuffer &b, std::vector<T> &v)
{
uint32 vsize;
b >> vsize;
v.clear();
while(vsize--) {
T t;
b >> t;
v.push_back(t);
}
return b;
} template <typename T> ByteBuffer &operator<<(ByteBuffer &b, const std::list<T> & v)
{
b << (uint32)v.size();
for (typename std::list<T>::const_iterator i = v.begin(); i != v.end(); i++) {
b << *i;
}
return b;
} template <typename T> ByteBuffer &operator>>(ByteBuffer &b, std::list<T> &v)
{
uint32 vsize;
b >> vsize;
v.clear();
while(vsize--) {
T t;
b >> t;
v.push_back(t);
}
return b;
} template <typename K, typename V> ByteBuffer &operator<<(ByteBuffer &b, const std::map<K, V> &m)
{
b << (uint32)m.size();
for (typename std::map<K, V>::const_iterator i = m.begin(); i != m.end(); i++) {
b << i->first << i->second;
}
return b;
} template <typename K, typename V> ByteBuffer &operator>>(ByteBuffer &b, std::map<K, V> &m)
{
uint32 msize;
b >> msize;
m.clear();
while(msize--) {
K k;
V v;
b >> k >> v;
m.insert(make_pair(k, v));
}
return b;
} #endif
WorldPacket.h (读写扩展类,协议前2字节表示协议包,其次2字节表示数据大小)
#ifndef WGSERVER_WORLDPACKET_H
#define WGSERVER_WORLDPACKET_H #include "ByteBuffer.h" class WorldPacket : public ByteBuffer
{
public:
__inline WorldPacket() : ByteBuffer(), m_opcode() { }
__inline WorldPacket(uint16 opcode, size_t res) : ByteBuffer(res), m_opcode(opcode) {}
__inline WorldPacket(size_t res) : ByteBuffer(res), m_opcode() { }
__inline WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode) {} //! Clear packet and set opcode all in one mighty blow
__inline void Initialize(uint16 opcode )
{
clear();
m_opcode = opcode;
} __inline uint16 GetOpcode() const { return m_opcode; }
__inline void SetOpcode(const uint16 & opcode) { m_opcode = opcode; }
__inline void SetLength(const uint16 & len) {
uint16 * plen = (uint16 * ) &(contents()[]);
*plen = len;
} __inline std::string getString()
{
//std::string buff =
return (const char*)contents();
} template<typename T>
void SetOffset(const uint16 & offset, const T value ) {
T * pval = (T *) &(contents()[offset]);
*pval = value;
} public:
/**
* @创建时间 2011-08-31
* @创建人 *勇
* @函数作用 向数据包追加字符串
* @参数
* @packet 数据封包指针
* @str 追加的字符串
*/
template<typename T> void AppendPacketString(std::string str)
{
T ilen = (T)str.size();
*this << ilen;
if (ilen > )
Write((const uint8 *) str.c_str(), ilen);
}
/**
* @创建时间 2011-08-31
* @创建人 *勇
* @函数作用 获取字符串
* @参数
* @packet 数据封包
* @返回 是否成功
*/
template<typename T> bool GetPacketString(std::string &str)
{
T ilen;
*this >> ilen;
if (ilen == )
return true;
uint8 buf[ilen+];
uint16 plen = size();
if (plen < ilen)
return false;
read(buf, ilen);
buf[ilen] = ;
str = (char*)buf;
return true;
} protected:
uint16 m_opcode;
}; /*
template<uint32 Size>
class SERVER_DECL StackWorldPacket : public StackBuffer<Size>
{
uint16 m_opcode;
public:
__inline StackWorldPacket(uint16 opcode) : StackBuffer<Size>(), m_opcode(opcode) { } //! Clear packet and set opcode all in one mighty blow
__inline void Initialize(uint16 opcode )
{
StackBuffer<Size>::Clear();
m_opcode = opcode;
} uint16 GetOpcode() { return m_opcode; }
__inline void SetOpcode(uint16 opcode) { m_opcode = opcode; }
};
*/ #endif
Common.h (bytebuffer.h所需的一些定义,该文件来自“魔兽世界服务端”源码,cocos2d-x自身有个CCommon.h文件,如果把两个文件合并的话,在linux下编译会发生冲突,冲突较多,本人也没有做区分,因此建议独立出来)
#ifndef WGSERVER_COMMON_H
#define WGSERVER_COMMON_H #ifdef WIN32
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_DEPRECATE 1
#define _CRT_SECURE_COPP_OVERLOAD_STANDARD_NAMES 1
#pragma warning(disable:4251) // dll-interface bullshit
#endif enum TimeVariables
{
TIME_SECOND = ,
TIME_MINUTE = TIME_SECOND * ,
TIME_HOUR = TIME_MINUTE * ,
TIME_DAY = TIME_HOUR * ,
TIME_MONTH = TIME_DAY * ,
TIME_YEAR = TIME_MONTH *
}; enum MsTimeVariables
{
MSTIME_SECOND = ,
MSTIME_MINUTE = MSTIME_SECOND * ,
MSTIME_HOUR = MSTIME_MINUTE * ,
MSTIME_DAY = MSTIME_HOUR *
}; #ifdef WIN32
#define WGSERVER_INLINE __forceinline
#else
#define WGSERVER_INLINE inline
#endif #ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* Define this if you're using a big-endian machine */
#ifdef USING_BIG_ENDIAN
#include <machine/byte_order.h>
#define bswap_16(x) NXSwapShort(x)
#define bswap_32(x) NXSwapInt(x)
#define bswap_64(x) NXSwapLongLong(x)
#endif #include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <math.h>
#include <errno.h>
//#include <sys/syscall.h> #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
# define WIN32_LEAN_AND_MEAN
//# define _WIN32_WINNT 0x0500
# define NOMINMAX
# include <windows.h>
#else
# include <string.h>
# define MAX_PATH
#endif #ifdef min
#undef min
#endif #ifdef max
#undef max
#endif #ifdef CONFIG_USE_SELECT
#undef FD_SETSIZE
#define FD_SETSIZE 2048
#endif #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <netdb.h>
#endif // current platform and compiler
#define PLATFORM_WIN32 0
#define PLATFORM_UNIX 1
#define PLATFORM_APPLE 2 #define UNIX_FLAVOUR_LINUX 1
#define UNIX_FLAVOUR_BSD 2
#define UNIX_FLAVOUR_OTHER 3
#define UNIX_FLAVOUR_OSX 4 #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
# define PLATFORM PLATFORM_WIN32
#elif defined( __APPLE_CC__ )
# define PLATFORM PLATFORM_APPLE
#else
# define PLATFORM PLATFORM_UNIX
#endif #define COMPILER_MICROSOFT 0
#define COMPILER_GNU 1
#define COMPILER_BORLAND 2 #ifdef _MSC_VER
# define COMPILER COMPILER_MICROSOFT
#elif defined( __BORLANDC__ )
# define COMPILER COMPILER_BORLAND
#elif defined( __GNUC__ )
# define COMPILER COMPILER_GNU
#else
# pragma error "FATAL ERROR: Unknown compiler."
#endif #if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
#ifdef HAVE_DARWIN
#define PLATFORM_TEXT "MacOSX"
#define UNIX_FLAVOUR UNIX_FLAVOUR_OSX
#else
#ifdef USE_KQUEUE
#define PLATFORM_TEXT "FreeBSD"
#define UNIX_FLAVOUR UNIX_FLAVOUR_BSD
#else
#define PLATFORM_TEXT "Linux"
#define UNIX_FLAVOUR UNIX_FLAVOUR_LINUX
#endif
#endif
#endif #if PLATFORM == PLATFORM_WIN32
#define PLATFORM_TEXT "Win32"
#endif #ifdef _DEBUG
#define CONFIG "Debug"
#else
#define CONFIG "Release"
#endif #ifdef USING_BIG_ENDIAN
#define ARCH "PPC"
#else
#ifdef X64
#define ARCH "X64"
#else
#define ARCH "X86"
#endif
#endif /*#if COMPILER == COMPILER_MICROSOFT
# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data
# pragma warning( disable : 4311 ) // 'type cast': pointer truncation from HMODULE to uint32
# pragma warning( disable : 4786 ) // identifier was truncated to '255' characters in the debug information
# pragma warning( disable : 4146 )
# pragma warning( disable : 4800 )
#endif*/ #if PLATFORM == PLATFORM_WIN32
#define STRCASECMP stricmp
#else
#define STRCASECMP strcasecmp
#endif #if PLATFORM == PLATFORM_WIN32
#define ASYNC_NET
#endif #ifdef USE_EPOLL
#define CONFIG_USE_EPOLL
#endif
#ifdef USE_KQUEUE
#define CONFIG_USE_KQUEUE
#endif
#ifdef USE_SELECT
#define CONFIG_USE_SELECT
#endif
#ifdef USE_POLL
#define CONFIG_USE_POLL
#endif #ifdef min
#undef min
#endif #ifdef max
#undef max
#endif #include <cstdlib>
#include <set>
#include <list>
#include <string>
#include <map>
#include <queue>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
//#include <iostream> #if defined ( __GNUC__ )
# define LIKELY( _x ) \
__builtin_expect( ( _x ), )
# define UNLIKELY( _x ) \
__builtin_expect( ( _x ), )
#else
# define LIKELY( _x ) \
_x
# define UNLIKELY( _x ) \
_x
#endif #if defined (__GNUC__)
# define GCC_VERSION (__GNUC__ * \
+ __GNUC_MINOR__ * \
+ __GNUC_PATCHLEVEL__)
#endif #ifndef WIN32
#ifndef X64
# if defined (__GNUC__)
# if GCC_VERSION >=
# ifdef HAVE_DARWIN
# define __fastcall
# else
# define __fastcall __attribute__((__fastcall__))
# endif
# else
# define __fastcall __attribute__((__regparm__()))
# endif
# else
# define __fastcall __attribute__((__fastcall__))
# endif
#else
#define __fastcall
#endif
#endif #ifdef HAVE_STDCXX_0X
#include <unordered_map>
#include <unordered_set>
#elif COMPILER == COMPILER_GNU && __GNUC__ >= 3
#include <ext/hash_map>
#include <ext/hash_set>
#else
#include <hash_map>
#include <hash_set>
#endif #ifdef _STLPORT_VERSION
#define HM_NAMESPACE std
using std::hash_map;
using std::hash_set;
#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1300
#define HM_NAMESPACE stdext
using stdext::hash_map;
using stdext::hash_set;
#define ENABLE_SHITTY_STL_HACKS 1 /*
# if GNUC_COMP_VER >= 430
# define HashMap ::std::tr1::unordered_map
# define HashSet ::std::tr1::unordered_set
# else
# define HashMap ::__gnu_cxx::hash_map
# define HashSet ::__gnu_cxx::hash_set
# endif
*/ #define HashMap ::__gnu_cxx::hash_map
#define HashSet ::__gnu_cxx::hash_set // hacky stuff for vc++
#define snprintf _snprintf
#define vsnprintf _vsnprintf
//#define strlen lstrlen #ifdef WIN32
//typedef char TCHAR;
#define __T(x) x
#endif // cebernic added it
#define __utf8(x) _StringToUTF8(x)
#define __ansi(x) _StringToANSI(x)
#define __isutf8(x) _IsStringUTF8(x) #elif COMPILER == COMPILER_INTEL
#define HM_NAMESPACE std
using std::hash_map;
using std::hash_set;
#elif defined(HAVE_STDCXX_0X)
#define HM_NAMESPACE std
#define hash_map unordered_map
#define hash_set unordered_set
using std::unordered_map;
using std::unordered_set;
#elif COMPILER == COMPILER_GNU && __GNUC__ >= 3
#define HM_NAMESPACE __gnu_cxx
using __gnu_cxx::hash_map;
using __gnu_cxx::hash_set; namespace __gnu_cxx
{
template<> struct hash<unsigned long long>
{
size_t operator()(const unsigned long long &__x) const { return (size_t)__x; }
};
template<typename T> struct hash<T *>
{
size_t operator()(T * const &__x) const { return (size_t)__x; }
}; }; #else
#define HM_NAMESPACE std
using std::hash_map;
#endif /* Use correct types for x64 platforms, too */
#if COMPILER != COMPILER_GNU
typedef signed __int64 int64;
typedef signed __int32 int32;
typedef signed __int16 int16;
typedef signed __int8 int8; typedef unsigned __int64 uint64;
typedef unsigned __int32 uint32;
typedef unsigned __int16 uint16;
typedef unsigned __int8 uint8;
typedef float Real;
#else typedef int64_t int64;
typedef int32_t int32;
typedef int16_t int16;
typedef int8_t int8;
typedef uint64_t uint64;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
typedef uint32_t DWORD;
typedef float Real; #endif /* these can be optimized into assembly */
#ifdef USING_BIG_ENDIAN WGSERVER_INLINE static void swap16(uint16* p) { *p = bswap_16((uint16_t)*p); }
WGSERVER_INLINE static void swap32(uint32* p) { *p = bswap_32((uint32_t)*p); }
WGSERVER_INLINE static void swap64(uint64* p) { *p = bswap_64((uint64_t)*p);; } WGSERVER_INLINE static float swapfloat(float p)
{
union { float asfloat; uint8 asbytes[]; } u1, u2;
u1.asfloat = p;
/* swap! */
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[]; return u2.asfloat;
} WGSERVER_INLINE static double swapdouble(double p)
{
union { double asfloat; uint8 asbytes[]; } u1, u2;
u1.asfloat = p;
/* swap! */
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[]; return u2.asfloat;
} WGSERVER_INLINE static void swapfloat(float * p)
{
union { float asfloat; uint8 asbytes[]; } u1, u2;
u1.asfloat = *p;
/* swap! */
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
*p = u2.asfloat;
} WGSERVER_INLINE static void swapdouble(double * p)
{
union { double asfloat; uint8 asbytes[]; } u1, u2;
u1.asfloat = *p;
/* swap! */
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
u2.asbytes[] = u1.asbytes[];
*p = u2.asfloat;
} WGSERVER_INLINE static uint16 swap16(uint16 p) { return bswap_16((uint16_t)p); }
WGSERVER_INLINE static uint32 swap32(uint32 p) { return bswap_32((uint32_t)p); }
WGSERVER_INLINE static uint64 swap64(uint64 p) { return bswap_64((uint64_t)p); } WGSERVER_INLINE static void swap16(int16* p) { *p = bswap_16((uint16_t)*p); }
WGSERVER_INLINE static void swap32(int32* p) { *p = bswap_32((uint32_t)*p); }
WGSERVER_INLINE static void swap64(int64* p) { *p = bswap_64((uint64_t)*p); } WGSERVER_INLINE static int16 swap16(int16 p) { return bswap_16((uint16_t)p); }
WGSERVER_INLINE static int32 swap32(int32 p) { return bswap_32((uint32_t)p); }
WGSERVER_INLINE static int64 swap64(int64 p) { return bswap_64((uint64_t)p); } #endif
/*
Scripting system exports/imports
*/ #ifdef WIN32
#ifndef SCRIPTLIB
#define SERVER_DECL __declspec(dllexport)
#define SCRIPT_DECL __declspec(dllimport)
#else
#define SERVER_DECL __declspec(dllimport)
#define SCRIPT_DECL __declspec(dllexport)
#endif
#else
#define SERVER_DECL
#define SCRIPT_DECL
#endif // Include all threading files
#include <assert.h>
//#include "Threading/Threading.h" //#include "MersenneTwister.h" #if COMPILER == COMPILER_MICROSOFT #define I64FMT "%016I64X"
#define I64FMTD "%I64u"
#define SI64FMTD "%I64d"
#define snprintf _snprintf
#define atoll __atoi64 #else #define stricmp strcasecmp
#define strnicmp strncasecmp
#define I64FMT "%016llX"
#define I64FMTD "%llu"
#define SI64FMTD "%lld" #endif #ifndef WIN32
#ifdef USING_BIG_ENDIAN
//#define GUID_HIPART(x) (*((uint32*)&(x)))
//#define GUID_LOPART(x) (*(((uint32*)&(x))+1))
#define GUID_LOPART(x) ( ( x >> 32 ) )
#define GUID_HIPART(x) ( ( x & 0x00000000ffffffff ) )
#else
#define GUID_HIPART(x) ( ( x >> 32 ) )
#define GUID_LOPART(x) ( ( x & 0x00000000ffffffff ) )
#endif
#else
#define GUID_HIPART(x) (*(((uint32*)&(x))+1))
#define GUID_LOPART(x) (*((uint32*)&(x)))
#endif #define atol(a) strtoul( a, NULL, 10) #define STRINGIZE(a) #a // fix buggy MSVC's for variable scoping to be reliable =S
#define for if(true) for #if COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1400
#pragma float_control(push)
#pragma float_control(precise, on)
#endif // fast int abs
static inline int int32abs( const int value )
{
return (value ^ (value >> )) - (value >> );
} // fast int abs and recast to unsigned
static inline uint32 int32abs2uint32( const int value )
{
return (uint32)(value ^ (value >> )) - (value >> );
} /// Fastest Method of float2int32
static inline int float2int32(const float value)
{
#if !defined(X64) && COMPILER == COMPILER_MICROSOFT && !defined(USING_BIG_ENDIAN)
int i;
__asm {
fld value
frndint
fistp i
}
return i;
#else
union { int asInt[]; double asDouble; } n;
n.asDouble = value + 6755399441055744.0; #if USING_BIG_ENDIAN
return n.asInt [];
#else
return n.asInt [];
#endif
#endif
} /// Fastest Method of long2int32
static inline int long2int32(const double value)
{
#if !defined(X64) && COMPILER == COMPILER_MICROSOFT && !defined(USING_BIG_ENDIAN)
int i;
__asm {
fld value
frndint
fistp i
}
return i;
#else
union { int asInt[]; double asDouble; } n;
n.asDouble = value + 6755399441055744.0; #if USING_BIG_ENDIAN
return n.asInt [];
#else
return n.asInt [];
#endif
#endif
} #if COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1400
#pragma float_control(pop)
#endif #ifndef WIN32
#include <sys/timeb.h>
#endif extern uint32 system_start_time_t; WGSERVER_INLINE uint32 now()
{
#ifdef WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return ((tv.tv_sec - system_start_time_t) * ) + (tv.tv_usec / );
#endif
} #ifndef WIN32
#define FALSE 0
#define TRUE 1
#endif #ifndef WIN32
#define Sleep(ms) usleep(1000*ms)
#endif /*#ifdef WIN32
#ifndef __SHOW_STUPID_WARNINGS__
#pragma warning(disable:4018)
#pragma warning(disable:4244)
#pragma warning(disable:4305)
#pragma warning(disable:4748)
#pragma warning(disable:4800)
#pragma warning(disable:4996)
#pragma warning(disable:4251)
#endif
#endif #undef INTEL_COMPILER
#ifdef INTEL_COMPILER
#pragma warning(disable:279)
#pragma warning(disable:1744)
#pragma warning(disable:1740)
#endif*/ //#include "Util.h"
struct WayPoint
{
WayPoint()
{
o = 0.0f;
}
uint32 id;
float x;
float y;
float z;
float o;
uint32 waittime; //ms
uint32 flags;
bool forwardemoteoneshot;
uint32 forwardemoteid;
bool backwardemoteoneshot;
uint32 backwardemoteid;
uint32 forwardskinid;
uint32 backwardskinid; }; struct spawn_timed_emotes
{
uint8 type; //1 standstate, 2 emotestate, 3 emoteoneshot
uint32 value; //get yar list elsewhere
char *msg; //maybe we wish to say smething while changing emote state
uint8 msg_type; //yell ? say ?
uint8 msg_lang; //yell ? say ?
uint32 expire_after; //going to nex faze in
};
typedef std::list<spawn_timed_emotes*> TimedEmoteList; WGSERVER_INLINE void reverse_array(uint8 * pointer, size_t count)
{
size_t x;
uint8 * temp = (uint8*)malloc(count);
memcpy(temp, pointer, count);
for(x = ; x < count; ++x)
pointer[x] = temp[count-x-];
free(temp);
} typedef std::vector<WayPoint*> WayPointMap; int32 GetTimePeriodFromString(const char * str);
std::string ConvertTimeStampToString(uint32 timestamp);
std::string ConvertTimeStampToDataTime(uint32 timestamp); uint32 DecimalToMask(uint32 dec); WGSERVER_INLINE void wgs_TOLOWER(std::string& str)
{
for(size_t i = ; i < str.length(); ++i)
str[i] = (char)tolower(str[i]);
} WGSERVER_INLINE void wgs_TOUPPER(std::string& str)
{
for(size_t i = ; i < str.length(); ++i)
str[i] = (char)toupper(str[i]);
} // returns true if the ip hits the mask, otherwise false
inline static bool ParseCIDRBan(unsigned int IP, unsigned int Mask, unsigned int MaskBits)
{
// CIDR bans are a compacted form of IP / Submask
// So 192.168.1.0/255.255.255.0 would be 192.168.1.0/24
// IP's in the 192.168l.1.x range would be hit, others not.
unsigned char * source_ip = (unsigned char*)&IP;
unsigned char * mask = (unsigned char*)&Mask;
int full_bytes = MaskBits / ;
int leftover_bits = MaskBits % ;
//int byte; // sanity checks for the data first
if( MaskBits > )
return false; // this is the table for comparing leftover bits
static const unsigned char leftover_bits_compare[] = {
0x00, //
0x80, //
0xC0, //
0xE0, //
0xF0, //
0xF8, //
0xFC, //
0xFE, //
0xFF, // 11111111 - This one isn't used
}; // if we have any full bytes, compare them with memcpy
if( full_bytes > )
{
if( memcmp( source_ip, mask, full_bytes ) != )
return false;
} // compare the left over bits
if( leftover_bits > )
{
if( ( source_ip[full_bytes] & leftover_bits_compare[leftover_bits] ) !=
( mask[full_bytes] & leftover_bits_compare[leftover_bits] ) )
{
// one of the bits does not match
return false;
}
} // all of the bits match that were testable
return true;
} inline static unsigned int MakeIP(const char * str)
{
unsigned int bytes[];
unsigned int res;
if( sscanf(str, "%u.%u.%u.%u", &bytes[], &bytes[], &bytes[], &bytes[]) != )
return ; res = bytes[] | (bytes[] << ) | (bytes[] << ) | (bytes[] << );
return res;
} inline static unsigned int GetANetwork(unsigned int ip)
{
return (ip & 0x000000FF);
} inline static unsigned int GetBNetwork(unsigned int ip)
{
return (ip & 0x0000FFFF);
} inline static unsigned int GetCNetwork(unsigned int ip)
{
return (ip & 0x00FFFFFF);
} //get current thread id
#define getThreadId() syscall(__NR_gettid) // warning, by enabling this define you are aware that you are only delaying the inevitable
// some crashes are not recorable and those will stack up in time and lead to a full crash
// enabling this define will make windows servers shut down only the map instance in where the crash ocured
// during this forced shutdown players are not saved to avoid saving corrupted data
// there might be a lot of cases where each saved crash will lead to memory leaks or unhandled cases
// crashreports are still created and do use them to report the actaul problem that casued the crash
// fixing the problem that causes the crash is the proper way to fix things
//#define FORCED_SERVER_KEEPALIVE #endif
另外,
在extensions/cocos-ext.h文件内加入
#include "network/TCPSocket.h"
在extensions/Android.mk文件内加入,使其在linux下能够编译到
network/TCPSocket.cpp \
使用例子,代码片段:
///////////////////////////////////////////////
// 创建SOCKET管理器
CREATE_TCPSOCKETMGR(this);
// 创建并添加SOCKET,参数:服务器IP,端口,自定义的SOCKET_ID标识
sSocketMgr.createSocket("192.168.0.183", , );
// 注册协议,参数:包头,回调函数
sSocketMgr.register_process(0x10, SCT_CALLBACK_2(HelloWorld::login, this));
// 注册消息截获事件,注册此事件后可以截获收到的所有消息,若回调函数返回true则本次事件会继续分发注册过的协议,返回false则不分发
sSocketMgr.register_all_process(SCT_CALLBACK_1(HelloWorld::process, this));
// 定义协议包
WorldPacket packet;
packet.clear();
// 设置协议头
packet.SetOpcode(0x0010);
packet << uint16(0x0010)
<< uint16()// 协议长度
<< uint32()
<< uint32();
// 加入字符串数据(uint8表示字符串长度所占字节,此处为1字节)
packet.AppendPacketString<uint8>(std::string("aaa:88889083:d5956683c17d7e284d33ee295b277b52"));
// 设置协议长度
packet.SetLength(packet.size());
// 发送数据
sSocketMgr.SendPacket(, &packet);
///////////////////////////////////////////////
回调函数例子:
// 注册单个协议回调函数(样例),参数:SOCKET_ID标识,数据包
void process_login(int _tag, WorldPacket & packet);
// 注册单个协议回调函数(样例),参数:SOCKET_ID标识,协议头,数据包
bool process_all(int _tag, int _cmd, WorldPacket & packet);
// 断线事件
void onDisconnect(int _tag);
取数据例子:
WorldPacket packet ;
// 取整形数据
uint16 opcode;
uint16 len;
uint32 serial;
float fl;
packet >> opcode;
packet >> len;
packet >> serial;
packet >> fl;
// 取字符串
String oldPwd, newPwd;
packet.GetPacketString<uint8>(&packet, oldPwd);
packet.GetPacketString<uint8>(&packet, newPwd);
写得比较草,如果看不懂的,好的建议和意见可以给我留言。
如果有不同的,好的思路也可以提出来,一起探讨。。