本文为作者原创,如需转载请标注出处。 http://blog.csdn.net/eclipse_c
在游戏中有各种各样的排行榜需求,比如按照战斗力来进行排行,如果战力相同,那么就比较玩家等级,等等。
下面介绍一种排行榜的设计,排名依据有多个字段,如:等级>战力>声望
简单说下需求:
宗门分为正派邪派,女宗。其中女宗也分正邪,只是多出来的一个字段来标识女性角色。
正派/邪派排名依据
宗门等级>宗主战力>宗门声望
女宗排名依据
宗主魅力>宗门等级>宗门声望
(宗主魅力通过其他玩法获得)
新秀排名依据
成立时间(越晚越靠前)
宗门等级,1~25左右
战力用一个int32来存储
宗门声望也差不多可以用一个int32来存储。
对于正邪排行榜,可以使用一个压缩的long型来作为排行的key值,对应一个treeMap,另外存储一个hashMap,其中的key为宗门id,
value为一个压缩的long。这样就形成了两个map,一一映射的关系。可以通过宗门id来查找这个宗门是否存在排行榜总,当玩家的战力宗门等级等相关值发生变化时。
查找原有的值,然后对这个值进行修改。
对于这个64位的long型的key值,可以采用将其拆分成3个部分,宗门等级占7位,后面32位用来存战力,然后剩下的32-7位来存宗门声望。
private static final int CLAN_RANK_TYPE_GOOD_RANK = 1; // 宗门排行4种类型
private static final int CLAN_RANK_TYPE_EVIL_RANK = 2;
private static final int CLAN_RANK_TYPE_WOMAN_RANK = 3;
private static final int CLAN_RANK_TYPE_NEW_RANK = 4;
private static final int CLAN_RANK_GLOBAL_SIZE = 200;
private static final int CLAN_RANK_LOCAL_SIZE = 50;
//接口函数 handleClanGetBaseRankReq
public synchronized List<SBean.ClanRankBaseInfo> getGlobalClanRank(int type)
{
return this.clanRank.getGlobalClanRank(type);
}
public synchronized List<SBean.ClanRankBaseInfo> getLocalClanRank(int gsid, int type)
{
return this.clanRank.getLocalClanRank(type, gsid);
}
public synchronized void addNewClanToRank(int clanId, int level, int prestiage, int value, String name, String ownerName)
{
this.clanRank.addNewRankMap(new SBean.ClanRankBaseInfo(clanId, level, prestiage, value, name, ownerName));
}
//宗门排行榜修改规则:当宗主战力、魅力值、宗门等级发生变化、声望发生变化时,修改排行榜的值。
public synchronized void modefyClanRank(int gsid, int roleID, int fightPower, int charm)
{
long grid = GameData.getGlobalRoleID(gsid, roleID);
Set<Integer> clanIds = mapr2c.get(grid);
if(clanIds == null || clanIds.size() != 1)
{
return;
}
int clanIdOrError = getClanId(grid);
execClanVisitor(clanIdOrError, clan -> {
if(clan == null || clan.owner != GameData.getGlobalRoleID(gsid, roleID))
{
return;
}
int clanType = clan.type;
String clanName = clan.name;
String ownerName = clan.ownerName;
int clanLevel = clan.level;
int clanPrestiage = clan.prestige;
if(charm != Clan.CLAN_DEFAULT_RANK_CHARM && charm > 0)
{
this.clanRank.onClanRankChange(gsid, clanType, clanIdOrError, clanName, ownerName, clanLevel, fightPower, clanPrestiage, charm);
}
else{
this.clanRank.onClanRankChange(gsid, clanType, clanIdOrError, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
}
});
}
// 通过clanId 来更新宗门排行榜中的宗门信息(在宗门等级声望变化时调用此函数)
public synchronized void modifyClanRankById(int clanId)
{
execClanVisitor(clanId, clan -> {
if(clan == null)
{
return;
}
long value = 0;
SBean.ClanRankBaseInfo info = null;
int charm = 0;
int fightPower = 0;
if(this.clanRank.gRank.containsKey(clanId))
{
value = this.clanRank.gRank.get(clanId);
info = this.clanRank.gGoodRank.get(value);
fightPower = getFightPowerByRankKey(value);
}
if(this.clanRank.eRank.containsKey(clanId))
{
value = this.clanRank.eRank.get(clanId);
info = this.clanRank.gEvilRank.get(value);
fightPower = getFightPowerByRankKey(value);
}
if(this.clanRank.wRank.containsKey(clanId))
{
value = this.clanRank.wRank.get(clanId);
info = this.clanRank.gWomanRank.get(value);
charm = getCharmByRankKey(value);
}
if(value == 0 || info == null)
return ;
int clanType = clan.type;
String clanName = clan.name;
String ownerName = clan.ownerName;
int clanLevel = clan.level;
int clanPrestiage = clan.prestige;
int gsid = clan.getOwnerServerId();
if(charm != Clan.CLAN_DEFAULT_RANK_CHARM && charm > 0)
{
this.clanRank.onClanRankChange(gsid, clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage, charm);
}
else{
this.clanRank.onClanRankChange(gsid, clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
}
});
}
//功能函数
private long getCheckPrestiage(long pre, int n)
{
if(pre > Integer.MAX_VALUE >> n)
{
return getCheckPrestiage(pre >> 1, n );
}
return pre;
}
private long getRankKeyByPAIBIE(int clanLevel, int fightPower, int clanPrestiage)
{
//宗门等级>宗主战力>宗门声望 2^7=128 2^32 2^25 组合成一个long型
long result = 0;
long level = (long)clanLevel;
long power = (long)fightPower;
long pre = getCheckPrestiage((long)clanPrestiage, 7);
result |= level<<(25+32);
result |= power<<25;
result |= pre;
return result;
}
private int getFightPowerByRankKey(long value)
{
return (int)((value>>25) & 0xffffffffL);
}
private long getRankKeyByMEILI(int charm, int clanLevel, int clanPrestiage)
{
//clanPrestiage > 2^25(33554432) 时会导致返回的result有问题。不过符合问题的情况出现的可能性极小
long result = 0;
long cha = (long)charm;
long lev = (long)clanLevel;
long pre = getCheckPrestiage((long)clanPrestiage, 7);
result |= cha<<32;
result |= lev<<(32-7);
result |= pre;
return result;
}
private int getCharmByRankKey(long value)
{
return (int)((value>>32) & 0xffffffffL);
}
private long getNextRankKey(long value, Map<Long, SBean.ClanRankBaseInfo> Rank)
{
if(Rank.containsKey(value))
return getNextRankKey(value - 1, Rank);
return value;
}
/**
* @date 2016.6.15
* @problem: 当创建2个相同的角色时候,并创建相同类型的宗门,会导致二者对应的排行key值相同,在Rank这个map中只会保存一份
* @solve: 解决冲突的方法:如果找到了两个相同的key,那么表示这两个排名并列,那么找到它-1的key是否存在,如果不存在则作为key值,否则继续-1找
* @analysis: 由于最后一位减一操作,会导致排行榜排名出现问题,但是出问题的情况仅仅是在最后一个参数(声望),即前面2个参数都相同时才会出现这个问题。
*/
private void changeRankMap(int clanId, SBean.ClanRankBaseInfo info, long newRank, Map<Integer, Long>rank, Map<Long, SBean.ClanRankBaseInfo> Rank , boolean isLocal)
{
int size = isLocal ? CLAN_RANK_LOCAL_SIZE : CLAN_RANK_GLOBAL_SIZE;
if(Rank.size() < size)
{
if(rank.containsKey(clanId))
{
long oldRank = rank.get(clanId);
if(Rank.containsKey(oldRank))
{
rank.remove(clanId);
Rank.remove(oldRank);
long realRank = getNextRankKey(newRank, Rank);
rank.put(clanId, realRank);
Rank.put(realRank, info);
}
}
else{
long realRank = getNextRankKey(newRank, Rank);
rank.put(clanId, realRank);
Rank.put(realRank, info);
}
}
else{ // the map size equal the CLAN_RANK_LOCAL_SIZE
if(rank.containsKey(clanId))
{
long oldRank = rank.get(clanId);
if(Rank.containsKey(oldRank))
{
rank.remove(clanId);
Rank.remove(oldRank);
long realRank = getNextRankKey(newRank, Rank);
rank.put(clanId, realRank);
Rank.put(realRank, info);
}
}
else{
int tempKey = 0;
long tempValue = Long.MAX_VALUE;
for( Integer t : rank.keySet())
{
if( rank.get(t) < tempValue )
{
tempKey = t;
tempValue = rank.get(t);
}
}
if( newRank > tempValue)
{
rank.remove(tempKey);
Rank.remove(tempValue);
long realRank = getNextRankKey(newRank, Rank);
rank.put(clanId, realRank);
Rank.put(realRank, info);
}
}
}
}
//相同gs下宗门排行(只在ClanRank类内实例化)
public class LocalClanRank
{
public LocalClanRank()
{
this.goodRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.evilRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.womanRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.gRank = new HashMap<Integer, Long>();
this.eRank = new HashMap<Integer, Long>();
this.wRank = new HashMap<Integer, Long>();
}
public List<SBean.ClanRankBaseInfo> getLocalClanRank(int type)
{
if(type == CLAN_RANK_TYPE_GOOD_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(goodRank.values());
if(type == CLAN_RANK_TYPE_EVIL_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(evilRank.values());
if(type == CLAN_RANK_TYPE_WOMAN_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(womanRank.values());
return GameData.emptyList();
}
//刷新女宗排名
public void onLocalClanRankChange(int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage, int charm)
{
SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
if(clanType == Clan.CLAN_TYPE_N)
{
long newRank = getRankKeyByMEILI(charm, clanLevel, clanPrestiage);
changeRankMap(clanId, info, newRank, wRank, womanRank, true);
}
}
//刷新排行榜,当有宗门等级/宗主战力发/宗门声望发生变化,调用这个函数。
public void onLocalClanRankChange(int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage)
{
//updateRoleFightPower() 这个函数是战力发生变化时候调用的。
SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
if(clanType == Clan.CLAN_TYPE_Z)
{
long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
changeRankMap(clanId, info, newRank, gRank, goodRank, true);
}
if(clanType == Clan.CLAN_TYPE_X)
{
long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
changeRankMap(clanId, info, newRank, eRank, evilRank, true);
}
}
public void removeClanFromRankList(int clanId)
{
if(gRank.containsKey(clanId))
{
goodRank.remove(gRank.get(clanId));
gRank.remove(clanId);
}
if(eRank.containsKey(clanId))
{
evilRank.remove(eRank.get(clanId));
eRank.remove(clanId);
}
if(wRank.containsKey(clanId))
{
womanRank.remove(wRank.get(clanId));
wRank.remove(clanId);
}
}
private HashMap<Integer, Long> gRank; // key is clanId.两个map一一映射
private HashMap<Integer, Long> eRank;
private HashMap<Integer, Long> wRank;
private TreeMap<Long, SBean.ClanRankBaseInfo> goodRank; // 正派、邪派、女宗、新秀排行
private TreeMap<Long, SBean.ClanRankBaseInfo> evilRank;
private TreeMap<Long, SBean.ClanRankBaseInfo> womanRank;
}
//该宗门服务器中的所有宗门排行(宗门排行榜只需要实例化一个这个类的对象即可)
public class ClanRank
{
public ClanRank()
{
this.gGoodRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.gEvilRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.gWomanRank = new TreeMap<Long,SBean.ClanRankBaseInfo>(new Comparator<Long>(){
public int compare(Long a, Long b)
{
return b.compareTo(a);
}
});
this.gNewRank = new LinkedList<SBean.ClanRankBaseInfo>();
this.localServerRank = new HashMap<Integer, LocalClanRank>();
this.gRank = new HashMap<Integer, Long>();
this.eRank = new HashMap<Integer, Long>();
this.wRank = new HashMap<Integer, Long>();
}
public List<SBean.ClanRankBaseInfo> getGlobalClanRank(int type)
{
if(type == CLAN_RANK_TYPE_GOOD_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(gGoodRank.values());
if(type == CLAN_RANK_TYPE_EVIL_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(gEvilRank.values());
if(type == CLAN_RANK_TYPE_WOMAN_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(gWomanRank.values());
if(type == CLAN_RANK_TYPE_NEW_RANK)
return new ArrayList<SBean.ClanRankBaseInfo>(gNewRank);
return GameData.emptyList();
}
public List<SBean.ClanRankBaseInfo> getLocalClanRank(int type, int gsId)
{
if(!localServerRank.containsKey(gsId))
return GameData.emptyList();
return localServerRank.get(gsId).getLocalClanRank(type);
}
public void addNewRankMap(SBean.ClanRankBaseInfo info)
{
if(gNewRank.size() >= CLAN_RANK_GLOBAL_SIZE)
{
gNewRank.removeLast();
}else
{
gNewRank.addFirst(info);
}
}
//刷新女宗排名
public void onClanRankChange(int gsid, int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage, int charm)
{
SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
if(clanType == Clan.CLAN_TYPE_N)
{
long newRank = getRankKeyByMEILI(charm, clanLevel, clanPrestiage);
changeRankMap(clanId, info, newRank, wRank, gWomanRank, false);
//修改本服排行的女宗
if( ! localServerRank.containsKey(gsid))
{
localServerRank.put(gsid, new LocalClanRank());
}
localServerRank.get(gsid).onLocalClanRankChange(clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
}
}
//刷新正邪宗门排名
public void onClanRankChange(int gsid, int clanType, int clanId, String clanName, String ownerName, int clanLevel, int fightPower, int clanPrestiage)
{
SBean.ClanRankBaseInfo info = new SBean.ClanRankBaseInfo(clanId, clanLevel, clanPrestiage, fightPower, clanName, ownerName);
if(clanType == Clan.CLAN_TYPE_Z)
{
long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
changeRankMap(clanId, info, newRank, gRank, gGoodRank, false);
}
if(clanType == Clan.CLAN_TYPE_X)
{
long newRank = getRankKeyByPAIBIE(clanLevel, fightPower, clanPrestiage);
changeRankMap(clanId, info, newRank, eRank, gEvilRank, false);
}
//增加本服排行
if( ! localServerRank.containsKey(gsid))
{
localServerRank.put(gsid, new LocalClanRank());
}
localServerRank.get(gsid).onLocalClanRankChange(clanType, clanId, clanName, ownerName, clanLevel, fightPower, clanPrestiage);
}
public void removeClanFromRankList(int clanId, int gsid)
{
if(gRank.containsKey(clanId))
{
gGoodRank.remove(gRank.get(clanId));
gRank.remove(clanId);
}
if(eRank.containsKey(clanId))
{
gEvilRank.remove(eRank.get(clanId));
eRank.remove(clanId);
}
if(wRank.containsKey(clanId))
{
gWomanRank.remove(wRank.get(clanId));
wRank.remove(clanId);
}
// 移除各个gs内的排名
if( ! localServerRank.containsKey(gsid))
return ;
localServerRank.get(gsid).removeClanFromRankList(clanId);
}
private HashMap<Integer, Long> gRank; // key is clanId.两个map一一映射
private HashMap<Integer, Long> eRank;
private HashMap<Integer, Long> wRank;
private TreeMap<Long, SBean.ClanRankBaseInfo> gGoodRank; // 全区正派、邪派、女宗、新秀排行
private TreeMap<Long, SBean.ClanRankBaseInfo> gEvilRank;
private TreeMap<Long, SBean.ClanRankBaseInfo> gWomanRank;
private LinkedList<SBean.ClanRankBaseInfo> gNewRank;
private HashMap<Integer, LocalClanRank> localServerRank; // gs服务器ID,对应的表
}