Files
mir_server/server/LogicServer/base/Ranking.h

604 lines
15 KiB
C
Raw Normal View History

2025-01-09 17:45:40 +08:00
#pragma once
/********************************************
*
* 使
*
*********************************************/
class CRankingMgr;
class CRanking;
#define RANKING_ITEM_CHECUSUM 0xFFEECC11
#define RANKING_CHECUSUM 0xFFEECC00
/// 排行榜项,每项表示一个用户的分值,每个排行榜由多个排行榜项组成
class CRankingItem
{
friend class CRanking;
public:
CRankingItem(CRanking *pRank)
{
nColCount = 0;
sCd = NULL;
nId = 0;
nPoint = 0;
nMaxCol = 0;
pParent =pRank;
nParam = 0;
nParam1 = 0;
nChecuSum = RANKING_ITEM_CHECUSUM;
}
/// 设置父亲的节点的指针,用于查找位置
VOID SetParent(CRanking *pRank)
{
if(pParent != NULL) return;
pParent = pRank;
}
/// 是否是合法的
bool IsValid() {return nChecuSum ==RANKING_ITEM_CHECUSUM;}
#define CHECK_RANK_ITEM_VALID() \
if(nChecuSum !=RANKING_ITEM_CHECUSUM) {\
OutputMsg(rmError,"%s,%d,ranking error",__FUNCTION__,__LINE__);\
for(int i=0; i< nColCount;i ++)\
{\
if(sCd[i])\
{\
OutputMsg(rmError,"column %d:%s",i,sCd[i]);\
}\
}\
return; }
#define CHECK_RANK_ITEM_VALID_RETSTR() \
if( nChecuSum != RANKING_ITEM_CHECUSUM) {OutputMsg(rmError, "%s,%d,ranking get index[%d] str ret error", __FUNCTION__, __LINE__, nIndex);\
return "-"; }
void Destroy()
{
CHECK_RANK_ITEM_VALID()
if (sCd)
{
for (int i = 0; i < nColCount; i++)
{
if(sCd[i])
{
CRankingMgr::m_pAllocator->FreeBuffer(sCd[i]);
sCd[i]=NULL;
}
}
CRankingMgr::m_pAllocator->FreeBuffer(sCd);
nColCount = 0;
sCd = NULL;
nId = 0;
nPoint = 0;
nMaxCol = 0;
}
}
virtual ~CRankingItem()
{
Destroy();
nChecuSum =0;
pParent =NULL;
}
/// 设置列数
void SetColCount(INT_PTR nCount)
{
CHECK_RANK_ITEM_VALID()
if (nCount > nMaxCol)
{
INT_PTR nSize = sizeof(char*)*nCount;
char** ss = (char**)CRankingMgr::m_pAllocator->AllocBuffer(nSize);
ZeroMemory(ss,nSize);
if (sCd)
{
memcpy(ss,sCd,sizeof(char*)*nMaxCol);
CRankingMgr::m_pAllocator->FreeBuffer(sCd);
}
sCd = ss;
nMaxCol = (BYTE)nCount;
}
nColCount = (BYTE)nCount;
}
void SetSub(INT_PTR nIndex, LPCSTR sData);
void SetSub(INT_PTR nIndex, unsigned int nValue);
/// 在指定的列前增加一列.-1表示在最后插入.bUnique列名是否唯一,true则唯一
void AddColumn(LPCSTR sData,INT_PTR nIndex=-1, bool bUnique=false);
/// 设置列的标题
void SetColumnTitle(LPCSTR sData, INT_PTR nIndex);
/// 删除某列的数据
void RemoveColumn(INT_PTR nIndex);
void SetId(unsigned int id);
inline unsigned int GetId() { return nId;}
inline int GetPoint() { return nPoint;}
inline int GetParam() { return nParam;}
inline int GetParam1() { return nParam1;}
void SetPoint(int point);
void SetParam(int param);
void SetParam1(int param);
/// 获取这个节点在管理器里的索引
int GetIndex();
//inline void SetIndex(int index) {CHECK_RANK_ITEM_VALID() nIndex = index;}
inline int GetColCount() { return nColCount;}
/// 获取某列的数据
inline LPCSTR GetSubData(INT_PTR nIndex)
{
CHECK_RANK_ITEM_VALID_RETSTR()
if (sCd && nIndex >=0 && nIndex < nColCount)
{
return sCd[nIndex]?sCd[nIndex]:"-";
}else
{
return "-";
}
}
private:
unsigned int nId; ///< 唯一值可以是角色id或者帮派id等
int nPoint; ///< 分数,排行榜根据这个排序
int nParam; //额外参数
int nParam1; //额外参数1
char** sCd; ///< 每列的数据内容,每列都是字符串类型,主要用于显示
BYTE nColCount; ///< 列的数目
BYTE nMaxCol; ///< 最大列
//int nIndex; ///< 自身在排行榜的位置,0是第一位
CRanking * pParent; ///< 获得其指针
int nChecuSum; ///< 校验码
DECLARE_OBJECT_COUNTER(CRankingItem)
};
/// 排行榜类
class CRanking:
public CBaseScriptExportObject
{
public:
struct tagIndex
{
public:
int id;
CRankingItem* pItem;
};
/// 排行可见类型
enum RankVisibleType
{
enVisible_All, ///< 世界所有玩家
enVisible_SameCamp, ///< 同阵营玩家
enVisible_SameGuild, ///< 同公会玩家
enVisible_SameTeam, ///< 同队伍
};
/// 排行可见参数
struct RankVisibleParam
{
union
{
int nCampId; ///< 阵营Id
unsigned int nGuildId; ///< 公会id
int nTeamId; ///< 队伍Id
}data;
};
public:
CRanking():m_Title(this){}
CRanking(LPCSTR sName,INT_PTR nMax,bool boDisp, INT_PTR nMaxBroadCount = 0);
virtual ~CRanking();
#define CHECK_RANK_VALID() \
if(m_nCheckSum != RANKING_CHECUSUM) { OutputMsg(rmError,"rank=%s,%s,%d,CRanking is error !!!",m_szFile,__FUNCTION__,__LINE__);\
return; }
const static int s_nDur = 120 * 60 * 1000; ///< 存盘120分钟只存1次
public:
//继承基类释放资源如果引用计数器没到0不能释放内存
//virtual int release();
virtual void destroy();
/*
* Comments:m_szName
* @Return bool:true
*/
bool Load(LPCSTR sFile = nullptr);
/// 排行榜是否合法
bool IsValid()
{
if(m_nCheckSum != RANKING_CHECUSUM)
{
//OutputMsg(rmError,"rank=%s,name=%s,CRanking is error !",m_szFile,m_szName);
return false;
}
return true;
}
/*
* Comments:
* Param LPCSTR sTitle:
* Param INT_PTR nIndex:,-1
* @Return bool:
*/
void AddColumn(LPCSTR sTitle, INT_PTR nIndex, bool bUnique=false);
/// 获取一个子节点的位置
inline int GetNodeIndex(CRankingItem * pItem)
{
for(int i=0;i <m_ItemList.count(); i++)
{
if(m_ItemList[i] == pItem) return i;
}
return -10000;
}
//检车玩家id 是否在当前排行中
bool CheckActorIdInRank(unsigned int nActorId);
//通过条件获取玩家id
unsigned int GetActorIdBySexJob(LPCSTR nCondition);
/*
* Comments:
* Param LPCSTR sTitle:
* Param INT_PTR nIndex:
* @Return void:
*/
void SetColumnTitle(LPCSTR sTitle, INT_PTR nIndex);
/*
* Comments:
* Param INT_PTR nIndex:
* @Return void:
*/
void RemoveColumn(INT_PTR nIndex);
/*
* Comments:
* Param LPCSTR sFile:
* Param bool forceSave:true
* @Return void:
*/
void Save(LPCSTR sFile = nullptr,bool forceSave =false );
void ForceSave(LPCSTR sFile = nullptr);
/*
* Comments:
* @Return void:
*/
void clear();
//获取列的数量
inline INT_PTR ColumnCount() { return m_Title.GetColCount(); }
/*
* Comments:
* Param INT_PTR nId:id值
* Param INT_PTR nPoints:
* Param bool bRankFlag:true
* @Return CRankingItem*:NULL,id
*/
CRankingItem* AddItem(UINT_PTR nId,INT_PTR nPoints = 0,bool bRankFlag = true);
/*
* Comments:id增加分值
* Param INT_PTR nId:id
* Param INT_PTR nPoint:
* @Return CRankingItem*:NULL表示成功
*/
CRankingItem* Update(INT_PTR nId, INT_PTR nPoint);
/*
* Comments:id的分值
* Param INT_PTR nId:id
* Param INT_PTR nPoint:
* @Return CRankingItem*:NULL表示成功
*/
CRankingItem* Set(INT_PTR nId, INT_PTR nPoint);
//获取列表
inline CVector<CRankingItem*>& GetList(){return m_ItemList;}
//获取当前排行榜的行数
inline int GetItemCount() {return (int)m_ItemList.count();}
/*
* Comments:id
* Param INT_PTR nId:
* @Return void:
*/
void RemoveId(INT_PTR nId);
////设置上榜的最多人数,要重新排序
//void SetRankMax(INT_PTR nCount);
/*
* Comments:
* Param INT_PTR nIndex:
* @Return CRankingItem*:NULL
*/
CRankingItem* GetItem(INT_PTR nIndex);
/*
* Comments:,
* Param CRankingItem * pItem:
* @Return INT_PTR:
*/
//INT_PTR UpdateUpPos(CRankingItem* pItem);
/*
* Comments:,
* Param CRankingItem * pItem:
* @Return INT_PTR:
*/
//INT_PTR UpdateDownPos(CRankingItem* pItem);
/*
* Comments:id在排行榜中的位置0
* Param INT_PTR nId:
* @Return INT_PTR:
*/
INT_PTR GetIndexFromId(UINT_PTR nId);
/*
* Comments:id获取指针和索引
* Param INT_PTR nId:ID
* Param INT_PTR & idIndex:
* @Return CRankingItem*:
*/
CRankingItem* GetPtrFromId(INT_PTR nId,INT_PTR& idIndex);
/*
* Comments:id获取指针
* Param INT_PTR nId:ID
* @Return CRankingItem*:
*/
CRankingItem* GetPtrFromId(UINT_PTR nId);
//在榜外找个最大的,上榜
//CRankingItem* FindMaxItem();
inline LPCSTR GetName(){return m_szName;}
inline int GetMax() {
return m_nMaxBroadCount > 0 ? m_nMaxBroadCount: m_RankMax;
}
inline int GetColCount() { return m_Title.GetColCount();}
/*
* Comments:
* Param INT_PTR nIndex:
* Param bool disp:
* @Return void:
*/
void SetColDisplay(INT_PTR nIndex, bool disp);
/*
* Comments:
* Param INT_PTR nIndex:
* @Return bool:true
*/
bool isColDisplay(INT_PTR nIndex);
//是否发到客户端显示
inline bool IsDisplay(CActor *pActor) {
bool bVisible = true;
switch (m_rankVisibleType)
{
case enVisible_All:
bVisible = true;
break;
case enVisible_SameCamp:
{
bVisible =true;
break;
}
break;
// 这些暂时还没实现! 以后需要的时候,按照上面的方式实现下就行了!
case enVisible_SameGuild:
case enVisible_SameTeam:
break;
}
return m_Display && bVisible;
}
//设置在客户端显示的名称
inline void SetDisplayName(LPCSTR sName)
{
if (sName)
{
_asncpytA(m_szCnName,sName);
}
else
{
m_szCnName[0] = 0;
}
}
//获取在客户端显示的名称
inline LPCSTR GetDisplayName() { return m_szCnName; }
//获取标题
inline CRankingItem& GetTitle() { return m_Title; }
inline LPCSTR GetIdTitle() { return m_idTitle;}
inline void SetIdTitle(LPCSTR sName)
{
if (sName)
{
_asncpytA(m_idTitle,sName);
}
else
{
m_idTitle[0] = 0;
}
}
inline LPCSTR GetPointTitle() { return m_pointTitle; }
inline void SetPointTitle(LPCSTR sName)
{
if (sName)
{
_asncpytA(m_pointTitle,sName);
}
else
{
m_pointTitle[0] = 0;
}
}
inline void SetRankVisibleInfo(RankVisibleType vt, RankVisibleParam param)
{
m_rankVisibleType = vt;
m_rankVisibleParam = param;
}
//是否有数据改变
inline bool IsModify() { return m_boModify; }
//设置是否改变的标记
inline void SetModify( bool flag=true) {m_boModify =flag;}
inline void SetEmptySave(bool flag=false) { m_bRmptySave = flag;}
//更新索引中的id
//void UpdateTagId(int nOldId,int nNewId);
/*
* Comments:!!!!!
* Param INT_PTR nPos1:1
* Param INT_PTR nPos2:2
* @Return bool:truefalse
*/
bool SwapItem(INT_PTR nPos1,INT_PTR nPos2 );
//将1个项插队
bool JumpQueue(CRankingItem *pItem,INT_PTR nNewPos);
//设置属性排行榜配置数据 nRankPropIndex:属性配置表对应的配置索引 从0开始
void SetRankPropConfig(int nRankPropIndex);
/*
* Comments:
* Param CRankingItem * pItem:
* Param INT_PTR nIndex:
* Param bool bClear:
* @Return void:
*/
void UpdateRankProp(CRankingItem *pItem,INT_PTR nIndex, bool bClear=false);
//把属性与排行榜关联起来
void AtachRankProp(LPCSTR sName);
//把属性与排行榜去掉关联
void DetachhRankProp(LPCSTR sName);
/*
* Comments:
* Param int nPoint:
* @Return INT_PTR:
*/
INT_PTR GetInsertPos(int nPoint);
//是否排序好了默认的是按正常的降序排列的特殊时候不需要排序的这里要做1个标记
inline bool isRanked()
{
return m_isRanked;
}
//设置是否被排序好了
inline void SetRanked(bool flag)
{
m_isRanked = flag;
}
//获取文件的名字
char * GetFileName()
{
return m_szFile;
}
void SetSaveFlag(bool flag)
{
m_canSave = flag;
}
void PushToPack(CActor* pActor, int nNum, CDataPacket* pDataPack);
void PushRankToPack(int nNum, CDataPacket* pDataPack);
void PushEspecialRankToPack(int nNum, CDataPacket* pDataPack);
private:
//保存每项数据到文件中
void SaveItem( CRankingItem* pItem, CStringBuff &buff );
//把新id插入到索引中
//void InsertId( tagIndex &IndexItem );
private:
char m_szName[32]; //排行榜的名字,脚本通过这个名字访问排行榜,同时也是用这个名字作为文件保存
char m_szCnName[32]; //排行榜的中文名,主要显示在客户端的
char m_idTitle[32]; //id的标题文字
char m_pointTitle[32]; //分值的标题文字
CRankingItem m_Title; //这个项用来表示标题
CVector<CRankingItem*> m_ItemList; //保存所有的列表
int m_columnCount; //列的个数
//CVector<tagIndex> m_index; //索引表根据id排序查找时根据二分查找
int m_RankMax; //上榜的最多人数
int m_nMaxBroadCount; //广播给客户端次数
BYTE m_ColDisplay[255]; //表示第几列是否显示在客户端0表示显示默认是0非0表示不显示
bool m_Display; //表示是否显示
bool m_isRanked; //是否被排序好的
RankVisibleParam m_rankVisibleParam; // 排行榜可见类型相关的参数。例如阵营相关的排行这里存放可见排行的阵营ID
RankVisibleType m_rankVisibleType; // 排行榜可见类型
static const TCHAR* const m_sClassName; ///< 不知道有啥用
bool m_boModify; //是否修改过数据
char m_szFile[256]; //保存的文件
bool m_bRmptySave; //当排行榜数据为空时,是否保存排行榜文件
//排行榜属性添加
int m_nRankPropIndex; //属性排行榜配置索引
int m_nRankPropMax; //最大属性排行榜排行名额
int m_nRankPropValue; //属性榜最少值限制
unsigned int m_nCheckSum; //校验和
TICKCOUNT m_saveTick; //上次存盘的时间
bool m_canSave; // 是否存盘的标识
public:
void SendCrossServerToPack(int nNum, CDataPacket& pack);
};