Files
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

604 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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:成功返回true否则返回false
*/
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);
};