This commit is contained in:
aixianling
2025-01-09 17:45:40 +08:00
commit 5c9f1dae4a
3482 changed files with 1146531 additions and 0 deletions

View File

@@ -0,0 +1,270 @@
#include "StdAfx.h"
using namespace TRANSMIT;
#include "../base/Container.hpp"
bool CTransmitMgr::ReqTransmitTo(CActor *pActor, const char *pSceneName, const int nPosX, const int nPosY)
{
if (!pActor)
return false;
// 0、判断此玩家是否在等待传送阶段发送了传送请求还没收到应答如果是返回false否则继续下面处理
// 1、找到目标逻辑服务器如果没连接上返回false否则继续下面处理
// 2、调用对应的连接对象分配数据包DataPacket并且先写入本服务器的ServerIndex以及是否是公共服务器标记1Byte
// 3、将要传送到的目标场景和位置写入到DataPacket以便目标服务器检测是否可传入
// 4、将数据包发送给目标服务器
// 5、将此玩家加入到等待传送列表记录当前时间用于超时。
// 当前角色所在的逻辑服务器ServerIndex
int nServerIdx = GetLogicServer()->GetServerIndex();
unsigned int nActorId = pActor->GetId();
// 角色原始服务器的ServerIndex
int nRawServerIdx = GetActorRawServerIndex(pActor);
char szData[256];
CDataPacket packet(szData, sizeof(szData));
packet.setLength(0);
packet << (WORD)L2L_ReqTransmit << nServerIdx << nActorId;
SendMessage(packet.getMemoryPtr(), packet.getPosition(), nRawServerIdx);
return true;
}
void CTransmitMgr::OnRecvReqTransmitTo(CDataPacketReader &reader)
{
unsigned int nSrcServerIdx = 0, nActorId = 0;
reader >> nSrcServerIdx >> nActorId; // TODO 场景名称、坐标XY
char szData[256];
CDataPacket packet(szData, sizeof(szData));
packet.setLength(0);
packet << (WORD)L2L_ReqTransmitAck << (bool)true << nSrcServerIdx << nActorId;
SendMessage(packet.getMemoryPtr(), packet.getPosition(), nSrcServerIdx);
}
void CTransmitMgr::OnRecvReqTransmitToAck(CDataPacketReader &reader)
{
unsigned int nServerIdx = 0, nActorId = 0;
reader >> nServerIdx >> nActorId;
// TODO 对于公共服务器应该根据角色ID和ServerID一起来唯一确定一个CActor对象
CActor *pActor = GetGlobalLogicEngine()->GetEntityMgr()->GetEntityPtrByActorID(nActorId);
StartTransmitTo(pActor);
}
void CTransmitMgr::StartTransmitTo(CActor *pActor)
{
int nServerIdx = GetLogicServer()->GetServerIndex();
unsigned int nActorId = 0;
char szData[128];
CDataPacket packet(szData, sizeof(szData));
packet << (WORD)L2L_StartTransmit << nServerIdx << nActorId;
SendMessage(packet.getMemoryPtr(), packet.getPosition(), GetActorRawServerIndex(pActor));
// TODO.调用Actor的TransmitTo函数开始传送
EndTransmitTo(pActor);
}
void CTransmitMgr::OnRecvStartTransmitTo(CDataPacketReader &reader)
{
unsigned int nServerIdx = 0, nActorId = 0;
reader >> nServerIdx >> nActorId; // 场景名称、坐标XY
if (nServerIdx < 0 || nServerIdx >= SERVER_INDEX_MAX)
{
OutputMsg(rmError, _T("%s error occur: invalid serverindex=%d"), __FUNCTION__, nServerIdx);
return;
}
if (nServerIdx == GetLogicServer()->GetServerIndex())
{
OutputMsg(rmError, _T("%s error occur: transmit from same server!!!"), __FUNCTION__);
return;
}
// TODO.设置角色的会话状态、创建角色缓存数据对象
CServerActorInfo &serverActorInfo = m_ServerActorInfo[nServerIdx];
serverActorInfo.AddActorCache(nActorId); // 到目前为止,还没有缓存任何角色传送数据!
}
bool CTransmitMgr::ExistActorTransSessionData(int nServerIdx, unsigned int nActorId)
{
if (nServerIdx < 0 || nServerIdx > SERVER_INDEX_MAX)
{
OutputMsg(rmError, _T("%s invalid serverindex:%d"), __FUNCTION__, nServerIdx);
return false;
}
TRANSMIT::CServerActorInfo &serverActorInfo = m_ServerActorInfo[nServerIdx];
return serverActorInfo.GetActorCache(nActorId) != NULL ? true : false;
}
bool CTransmitMgr::ExistAccountTransSessionData(int nServerIdx, unsigned int nAccount)
{
if (nServerIdx < 0 || nServerIdx > SERVER_INDEX_MAX)
{
OutputMsg(rmError, _T("%s invalid serverindex:%d"), __FUNCTION__, nServerIdx);
return false;
}
TRANSMIT::CServerActorInfo &serverActorInfo = m_ServerActorInfo[nServerIdx];
return serverActorInfo.GetActorCacheByAccountId(nAccount) != NULL ? true : false;
}
void CTransmitMgr::OnLogicServerDisconnected(int nServerIdx)
{
CLogicServer *pLogicServer = GetLogicServer();
if (pLogicServer->IsCommonServer())
{
((CCSTransmitMgr *)this)->KillActorByServerIdx(nServerIdx);
}
else
{
// 将那些传送到公共服务器的玩家会话关闭。
((CNSTransmitMgr *)this)->CloseTransedActorSession();
}
}
void CTransmitMgr::EndTransmitTo(CActor *pActor)
{
int nServerIdx = GetLogicServer()->GetServerIndex();
unsigned int nActorId = 0;
char szData[128];
CDataPacket packet(szData, sizeof(szData));
packet << (WORD)L2L_EndTransmit << nServerIdx << nActorId;
SendMessage(packet.getMemoryPtr(), packet.getPosition(), GetActorRawServerIndex(pActor));
}
void CTransmitMgr::OnRecvEndTransmitTo(CDataPacketReader &reader)
{
unsigned int nServerIdx = 0, nActorId = 0;
reader >> nServerIdx >> nActorId;
if (nServerIdx < 0 || nServerIdx >= SERVER_INDEX_MAX)
return;
CServerActorInfo &serverActorInfo = m_ServerActorInfo[nServerIdx];
CActorTransmitCache *pCache = serverActorInfo.GetActorCache(nActorId);
if (pCache)
{
pCache->SetAllDataReady(true);
}
}
void CTransmitMgr::SendMessage(void *pData, SIZE_T size, int nServerIdx)
{
CLogicServer *pLogicServer = GetLogicServer();
if (pLogicServer->IsCommonServer())
{
//CCommonServer *pServer = pLogicServer->GetCommonServer();
//pServer->SendData(nServerIdx, pData, size);
}
else
{
CCommonClient *pClient = pLogicServer->GetCommonClient();
// 这里消息号是站位用pData里头已经有消息号
CDataPacket &packet = pClient->allocProtoPacket(0);
packet.adjustOffset(0-sizeof(jxSrvDef::INTERSRVCMD)); // 将Offset回退到消息ID的位置
packet.writeBuf(pData, size);
pClient->flushProtoPacket(packet);
}
}
void CTransmitMgr::TransmitFrom(INT_PTR nCmd, CDataPacketReader &reader)
{
// 处理传送打包的角色数据
}
int CTransmitMgr::GetActorRawServerIndex(CActor *pActor)
{
CLogicServer *pLogicServer = GetLogicServer();
int nServerIdx = pLogicServer->GetServerIndex();
if (GetLogicServer()->IsCommonServer())
nServerIdx = pActor->GetRawServerIndex();
return nServerIdx;
}
void CTransmitMgr::OnRecvMessage(int nDir, int nMsgId, CDataPacketReader &reader)
{
switch (nMsgId)
{
case L2L_ReqTransmit:
OnRecvReqTransmitTo(reader);
break;
case L2L_ReqTransmitAck:
OnRecvReqTransmitToAck(reader);
break;
case L2L_StartTransmit:
OnRecvStartTransmitTo(reader);
break;
case L2L_EndTransmit:
OnRecvEndTransmitTo(reader);
break;
default:
OutputMsg(rmError, _T("%s Recv unknown message:%d"), __FUNCTION__, nMsgId);
break;
}
}
void CCSTransmitMgr::KillActorByServerIdx(int nServerIdx)
{
if (nServerIdx < 0 || nServerIdx >= SERVER_INDEX_MAX)
{
OutputMsg(rmError, _T("%s invalid serveridx:%d"), __FUNCTION__, nServerIdx);
return;
}
TRANSMIT::CServerActorInfo &serverActorInfo = m_ServerActorInfo[nServerIdx];
serverActorInfo.CloseAllActor();
}
void CNSTransmitMgr::CloseTransedActorSession()
{
INT_PTR count = m_transedActorList.count();
if (count > 0)
{
CLogicSSClient *pSSClient = GetLogicServer()->GetSessionClient();
CMiniDateTime nCurrentTime;
nCurrentTime.tv = GetGlobalLogicEngine()->getMiniDateTime();
for (INT_PTR i = 0; i < count; i++)
{
TRANSMIT::CTransedActorRecord &record = m_transedActorList[i];
pSSClient->PostCloseSession(record.m_nAccountId, 0);
}
}
}
void CTransmitMgr::RunOne(TICKCOUNT nCurrTick)
{
for (INT_PTR i = 0; i < SERVER_INDEX_MAX; i++)
{
TRANSMIT::CServerActorInfo &ServerActorInfo = this->m_ServerActorInfo[i];
ServerActorInfo.RunOne(nCurrTick);
}
}
namespace TRANSMIT
{
void CServerActorInfo::CloseAllActor()
{
if (m_actorDBData.size() > 0)
{
CEntityManager *pEntityMgr = GetGlobalLogicEngine()->GetEntityMgr();
std::map<int, CActorTransmitCache*>::iterator iter = m_actorDBData.begin();
std::map<int, CActorTransmitCache*>::iterator iter_end = m_actorDBData.end();
for (; iter != iter_end; ++iter)
{
unsigned int nActorId = iter->first;
CActor *pActor = pEntityMgr->GetEntityPtrByActorID(nActorId);
if (pActor)
pActor->CloseActor(lwiCloseTransmitAllUser, false);
}
}
}
void CServerActorInfo::RunOne(TICKCOUNT nCurrTick)
{
std::map<int, CActorTransmitCache*>::iterator iter = m_actorDBData.begin();
std::map<int, CActorTransmitCache*>::iterator iter_end = m_actorDBData.end();
for (; iter != iter_end; ++iter)
{
CActorTransmitCache *pCache = iter->second;
}
}
}

View File

@@ -0,0 +1,405 @@
#ifndef TRANSMIT_MGR_H_
#define TRANSMIT_MGR_H_
/*
传送管理器。用于管理玩家从一个服务器传送到另外一个服务器的操作。包括玩家发起传送的数据打包、
传送到目的地的数据解包、公共服务器发给普通服务器的数据定时存盘数据处理等等
源逻辑服务器: 目标服务器
发送请求传送消息角色Id、场景名称、坐标
接收到请求传送消息,检测场景是否可进入
如果可以传送,给出可以进入的应答消息。
发送开始传送消息带上角色Id
为此用户设置会话状态,并且创建此角色的缓存数据对象。
打包并发送角色基本数据和子系统数据 接收到用户数据,先缓存起来。如果客户端连接上
就创建角色,并且初始化角色数据。如果客户端超时还
没有连接上,就关闭用户会话,删除角色缓存数据对象
*/
// 角色传送缓存数据。传送目的方接收到数据先缓存起来
namespace TRANSMIT
{
class CActorTransmitCacheData
{
public:
CActorTransmitCacheData() : m_nDataType(-1), m_packet(0){}
CActorTransmitCacheData(int nType, CDataPacket *packet){
m_nDataType = nType;
m_packet = packet;
}
int GetDataType() const { return m_nDataType; }
private:
int m_nDataType; // 角色数据类型
CDataPacket *m_packet; // 数据包
};
class CActorTransmitCache
{
public:
enum
{
TRANSMIT_TIMEOUT = 2 * 60 * 1000, // 传送超时
};
CActorTransmitCache()
{
m_nAccountId = 0;
m_bAllDataReady = false;
}
unsigned int GetAccountId() const
{
return m_nAccountId;
}
void SetAccountId(unsigned int nAccountId)
{
m_nAccountId = nAccountId;
}
unsigned int GetStartTransTime() const
{
return m_nStartTransTime;
}
void SetStartTransTime(unsigned int nTime)
{
m_nStartTransTime = nTime;
}
/*
* Comments: 缓存角色传送数据
* Param int nType: 数据类型。例如技能数据、背包物品数据等等
* Param CDataPacket * packet: 数据包内容
* @Return void:
* @Remark:
*/
void CacheData(int nType, CDataPacket *packet)
{
CActorTransmitCacheData *pCacheData = GetCacheData(nType);
if (pCacheData)
{
// TODO 覆盖
}
else
{
// 添加一个新的
CActorTransmitCacheData cacheData(nType, packet);
m_cache.add(cacheData);
}
}
/*
* Comments: 获取指定类型的数据
* Param const int nType:
* @Return CActorTransmitCacheData*:
* @Remark:
*/
CActorTransmitCacheData* GetCacheData(const int nType)
{
for (INT_PTR i = 0; i < m_cache.count(); i++)
{
if (nType == m_cache[i].GetDataType())
return &m_cache[i];
}
return NULL;
}
/*
* Comments: 设置全部数据缓存完毕标记
* Param bool flag:
* @Return void:
* @Remark:
*/
void SetAllDataReady(bool flag)
{
m_bAllDataReady = flag;
}
private:
unsigned int m_nAccountId; // 该角色的登录账号ID
unsigned int m_nStartTransTime; // 开始传送时间
bool m_bAllDataReady; // 所有的传送数据都缓存OK
CVector<CActorTransmitCacheData> m_cache;
};
// 同一个服务器内的所有角色数据
class CServerActorInfo
{
public:
/*
* Comments: 获取指定角色ID的Cache数据对象
* Param int nActorId:
* @Return CActorTransmitCache*:
* @Remark:
*/
CActorTransmitCache* GetActorCache(unsigned int nActorId)
{
std::map<int, CActorTransmitCache*>::iterator iter = m_actorDBData.find(nActorId);
if (iter != m_actorDBData.end())
return iter->second;
return NULL;
}
CActorTransmitCache* GetActorCacheByAccountId(unsigned int nAccountId)
{
std::map<int, CActorTransmitCache*>::iterator iter = m_actorDBData.begin();
std::map<int, CActorTransmitCache*>::iterator iter_end = m_actorDBData.end();
for (; iter != iter_end; ++iter)
{
if (iter->second->GetAccountId() == nAccountId)
return iter->second;
}
return NULL;
}
/*
* Comments: 添加一个角色Cache数据
* Param int nActorId:
* @Return CActorTransmitCache*: 返回此角色的CaChe对象指针
* @Remark:
*/
CActorTransmitCache* AddActorCache(unsigned int nActorId)
{
CActorTransmitCache *pCache = GetActorCache(nActorId);
if (pCache != NULL)
return pCache;
pCache = new CActorTransmitCache();
m_actorDBData[nActorId] = pCache;
return pCache;
}
/*
* Comments: 删除一个角色Cache数据
* Param int nActorId:
* @Return void:
* @Remark:
*/
void RemoveActorCache(unsigned int nActorId)
{
std::map<int, CActorTransmitCache*>::iterator iter = m_actorDBData.find(nActorId);
if (iter != m_actorDBData.end())
{
delete iter->second;
m_actorDBData.erase(iter);
}
}
/*
* Comments: 踢出所有的玩家
* @Return void:
* @Remark:
*/
void CloseAllActor();
/*
* Comments: 例行更新角色传送缓存对象
* Param TICKCOUNT nCurrTick:
* @Return void:
* @Remark:
*/
void RunOne(TICKCOUNT nCurrTick);
private:
std::map<int, CActorTransmitCache*> m_actorDBData; // 角色Id --> 传送缓存数据
};
// 记录角色传送到公共服务器的一些信息
struct CTransedActorRecord
{
unsigned int m_nAccountId; // 账号ID
unsigned int m_nActorId; // 角色ID
unsigned int m_nLoginTime; // 角色登录普通逻辑服务器的时间
};
}
class CTransmitMgr
{
public:
enum
{
SERVER_INDEX_MAX = 1024, // 最大的ServerIndex
};
CTransmitMgr(){}
~CTransmitMgr(){}
/*
* Comments: 请求将玩家传送到远程逻辑服务器
* Param CActor * pActor: 角色指针
* Param const char * pSceneName: 场景名称
* Param const int nPosX: 场景坐标X
* Param const int nPosY: 场景坐标Y
* @Return bool:
* @Remark: 此函数发送消息给远程逻辑服务器检测玩家是否可以传送到目标服务器的指定场景
*/
bool ReqTransmitTo(CActor *pActor, const char *pSceneName, const int nPosX, const int nPosY);
/*
* Comments: 从远程逻辑服务器传送到本服务器
* Param INT_PTR nCmd: 消息ID
* Param CDataPacketReader & reader: 消息数据
* @Return void:
* @Remark: 调用此函数接收处理角色传送各个模块的数据这里接收到数据处理类似于角色登录从DB中加载数据处理
*/
void TransmitFrom(INT_PTR nCmd, CDataPacketReader &reader);
/*
* Comments: 是否存在指定服务器的指定角色的传送会话信息
* Param int nServerIdx: 角色传送前的ServerIndex
* Param int nActorId: 角色ID
* @Return bool: 存在角色传送会话信息返回true否则返回false
* @Remark: 收到源服务器的开始传送消息后就为此角色建立传送会话数据结构,并且设置超时。在超时时间内角色连接到本逻辑服务器不需要
查询DB和Session会话状态直接创建角色。
*/
bool ExistActorTransSessionData(int nServerIdx, unsigned int nActorId);
/*
* Comments: 判断是否存在指定账号的传送会话信息
* Param int nServerIdx: 角色传送前的ServerIndex
* Param int nAccount:
* @Return bool:
* @Remark:
*/
bool ExistAccountTransSessionData(int nServerIdx, unsigned int nAccount);
/*
* Comments: 与连接的对端逻辑服务器断开时调用此函数。
* Param int nServerIdx:
* @Return void:
* @Remark:对于普通逻辑服务器而言,在断开与公共服务器的连接时,如果有玩家已经传送到公共服务器,需要通知
SessionServer断开此玩家的会话对于公共服务器而言如果与某个普通逻辑服务器断开那么需要将
所有此逻辑服务器的玩家踢下线。
*/
void OnLogicServerDisconnected(int nServerIdx);
/*
* Comments: 接收逻辑服务器之间的传送相关消息
* Param int nDir: 标记消息方向0表示是普通逻辑服务器到公共逻辑服务器反之为1
* Param int nMsgId: 消息Id
* Param CDataPacketReader & reader:
* @Return void:
* @Remark:
*/
void OnRecvMessage(int nDir, int nMsgId, CDataPacketReader &reader);
/*
* Comments: 传送管理器例行处理
* Param TICKCOUNT nCurrTick:
* @Return void:
* @Remark:
*/
void RunOne(TICKCOUNT nCurrTick);
protected:
/*
* Comments: 开始传送。
* Param CActor * pActor:
* @Return void:
* @Remark: 发开始传送消息给远程服务器用于标记传送的开始。消息携带角色Id、ServerIndex等信息。
目标服务器收到此消息后就创建此角色传送数据缓存对象,并且为此角色设置会话状态,等待客户端连接。
*/
void StartTransmitTo(CActor *pActor);
/*
* Comments: 源服务器发送给目标服务器的传送完毕通知
* Param CActor * pActor:
* @Return void:
* @Remark:
*/
void EndTransmitTo(CActor *pActor);
/*
* Comments: 接收到请求传送消息。
* Param CDataPacketReader & reader:
* @Return void:
* @Remark: 检测目标场景是否可以传送进入,并且把结果通知给连接逻辑服务器
*/
void OnRecvReqTransmitTo(CDataPacketReader &reader);
/*
* Comments: 接收到请求传送ACK
* Param CDataPacketReader & reader:
* @Return void:
* @Remark:
*/
void OnRecvReqTransmitToAck(CDataPacketReader &reader);
/*
* Comments: 接收到玩家开始传送消息。
* Param CDataPacketReader & reader:
* @Return void:
* @Remark: 为此玩家创建角色数据缓存对象设置角色session状态等等
*/
void OnRecvStartTransmitTo(CDataPacketReader &reader);
/*
* Comments: 接收到传送结束消息
* Param CDataPacketReader & reader:
* @Return void:
* @Remark: 目标服务器收到此消息就开始角色数据的初始化
*/
void OnRecvEndTransmitTo(CDataPacketReader &reader);
/*
* Comments: 发送消息给连接的逻辑服务器
* Param void * pData:
* Param SIZE_T size:
* Param int nServerIdx: 目标逻辑服务器的ServerIndex。对于公共服务器有意义。
* @Return void:
* @Remark:
*/
void SendMessage(void *pData, SIZE_T size, int nServerIdx);
/*
* Comments: 获取角色所在的原生服务器ServerIndex
* Param CActor * pActor:
* @Return int:
* @Remark:
*/
int GetActorRawServerIndex(CActor *pActor);
protected:
// 最多支持1024个服务器。用于缓存传送到本服务器的玩家的打包数据
TRANSMIT::CServerActorInfo m_ServerActorInfo[SERVER_INDEX_MAX];
// 对于普通逻辑服务器还需要记录传送到公共服务器的玩家的信息包括账号ID、角色ID、玩家上线时间用于
// 定时数据存盘的检测以及与公共服务器断开连接时关闭此部分玩家会话用
};
// 普通逻辑服务器传送管理器
class CNSTransmitMgr : public CTransmitMgr
{
public:
/*
* Comments: 被普通逻辑服务器调用,用于将当前传送到公共服务器的玩家会话关闭。
* @Return void:
* @Remark:
*/
void CloseTransedActorSession();
private:
CVector<TRANSMIT::CTransedActorRecord> m_transedActorList; // 已经传送到公共服务器的玩家列表
};
// 公共服务器的传送管理器
class CCSTransmitMgr : public CTransmitMgr
{
public:
/*
* Comments: 被公共逻辑服务器调用,用于将来自指定逻辑服务器的玩家踢下线
* Param int nServerIdx:
* @Return void:
* @Remark:
*/
void KillActorByServerIdx(int nServerIdx);
};
#endif