From b3c6d36f5ae851f09a3c2e73494ff19956b06fb0 Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期五, 11 四月 2025 16:56:14 +0800 Subject: [PATCH] 10367 【越南】【英语】【BT】【砍树】仙盟攻城战-服务端(跨服仙盟支持;后台查询区服仙盟支持;活动时间流程支持;攻城战主活动功能完整流程:公示、分组、战备、战斗、榜单、竞猜、领奖等;) --- ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyGCZ.py | 2902 ++++++++++++++++++ ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py | 30 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py | 161 + ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py | 251 + ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py | 1824 +++++++++++ ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py | 251 + ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py | 1824 +++++++++++ ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py | 4 ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py | 92 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActFamilyGCZ.py | 525 +++ ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py | 32 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py | 1 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py | 150 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py | 5 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_GetFamilyByServerID.py | 83 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py | 21 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini | 11 ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py | 16 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py | 45 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py | 21 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py | 11 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py | 13 ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py | 7 ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py | 4 ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py | 12 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py | 3 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py | 29 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py | 406 ++ ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py | 9 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py | 5 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini | 20 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CreateFamily.py | 146 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/FamilyGCZ.py | 75 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py | 41 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FamilyGCZ.py | 47 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py | 4 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameRecData.py | 35 PySysDB/PySysDBG.h | 64 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py | 16 39 files changed, 9,077 insertions(+), 119 deletions(-) diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h index 6f49190..a1339f2 100644 --- a/PySysDB/PySysDBG.h +++ b/PySysDB/PySysDBG.h @@ -792,6 +792,70 @@ dict ScoreAwardEx; //达标积分额外奖励 {积分:[[物品ID,个数,是否拍品], ...], ...} }; + +//活动时间流程表 + +struct tagActTimeFlow +{ + DWORD _FlowID; + BYTE StartDay; //开始天 + BYTE StartHour; //开始时 + BYTE StartMinute; //开始分 + BYTE EndDay; //结束天 + BYTE EndHour; //结束时 + BYTE EndMinute; //结束分 + WORD StateValue; //状态值 +}; + +//活动榜单奖励模版表 + +struct tagActBillboardAwardTemp +{ + DWORD _TemplateID; //模板编号 + BYTE Rank; //名次 + DWORD NeedValue; //上榜所需值 + dict ValueAwardEx; //达标值额外奖励 {值:[[物品ID,个数,是否拍品], ...], ...} + list AwardItemList; //奖励物品列表[[物品ID,个数,是否拍品], ...] + list LeaderAwardItemList; //仙盟榜盟主奖励物品信息列表[[物品ID,个数,是否拍品], ...] + list EliteAwardItemList; //仙盟榜精英奖励物品信息列表[[物品ID,个数,是否拍品], ...] +}; + +//活动竞猜表 + +struct tagActGuess +{ + DWORD _TemplateID; //模板编号 + DWORD AwardID; //奖励ID + list RightRankList; //猜对名次列表 + list AwardItemList; //对应奖励列表 [[物品ID,个数,是否拍品], ...] +}; + +//仙盟攻城战活动表 + +struct tagCrossActFamilyGCZ +{ + DWORD _CfgID; //配置ID + char ActGroupName; //活动组名(同组活动的名字需相同) + BYTE ZoneID; //组内分组编号 + list ServerIDRangeList; //活动的服务器ID范围列表 [[serverIDA, serverIDB], ...] + char StartDate; //开启日期 + char EndDate; //结束日期 + BYTE JoinFamilyCnt; //参与仙盟数 + WORD ActFlowID; //活动流程ID,对应H.活动时间流程表 + WORD GuessTemplateID; //竞猜奖励模版,对应H.活动竞猜表 + WORD PersonalTemplateID; //个人伤害排行奖励模版,对应H.活动榜单奖励模版表 + WORD FamilyTemplateID; //仙盟积分排行奖励模版,对应H.活动榜单奖励模版表 +}; + +//仙盟攻城战大本营等级表 + +struct tagCrossActFamilyGCZCampLV +{ + DWORD _CampLV; //大本营等级 + DWORD LVUPNeedExp; //升下一级所需经验 + DWORD AddHPPer; //生命累计总加成百分比 +}; + //仙匣秘境活动时间表 struct tagActXianXiaMJ diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini index 6e9965f..2f79136 100644 --- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini +++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini @@ -566,6 +566,17 @@ PacketSubCMD_1=0x07 PacketCallFunc_1=OnVoiceChat +[CrossFamilyGCZ] +ScriptName = GameWorldLogic\CrossFamilyGCZ.py +Writer = hxp +Releaser = hxp +RegType = 0 +RegisterPackCount = 1 + +PacketCMD_1=0xC0 +PacketSubCMD_1=0x26 +PacketCallFunc_1=OnFamilyGCZQuery + [GameWorship] ScriptName = GameWorldLogic\GameWorship.py Writer = hxp diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py index 2b69f4f..390086e 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py @@ -381,6 +381,7 @@ Def_WorldKey_CrossPKZoneSeasonState = "CrossPKZoneSeasonState_%s" #跨服PK赛区赛季状态,跨服服务器控制,参数(zoneID)0-未开启,1-开启中,2-已结束 Def_WorldKey_CrossPKBillboardSyncTick = "CrossPKBillboardSyncTick_%s_%s" #跨服PK本赛季排行榜同步tick,参数(zoneID, seasonID) Def_WorldKey_CrossSetPlayerAttrTick = "CrossSetPlayerAttrTick" #同步设置跨服玩家属性值tick +Def_WorldKey_SyncFamilyAllToCross = "SyncFamilyAllToCross" #本次启动是否已经同步过所有仙盟到跨服服务器 #--------------------------------------------------------------------- #个人时间间隔 TYPE_Player_Tick_Requestkey = 0 # 玩家请求处理间隔 diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py index 2163321..dec4787 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py @@ -5089,6 +5089,70 @@ #------------------------------------------------------ +# C0 26 仙盟攻城战查询 #tagCGFamilyGCZQuery + +class tagCGFamilyGCZQuery(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("QueryType", c_ubyte), #查询类型:1-成员捐献值;2-进入城池场景;3-退出城池场景;4-进入城池;5-退出城池;6-战报;7-分组仙盟成员伤害; + ("BatType", c_ubyte), #指定战场类型,需要发送的查询类型: 2、4 + ("GroupNum", c_ubyte), #指定分组编号,需要发送的查询类型: 2、4 + ("FamilyID", c_int), #指定仙盟ID或城池ID,查自己盟的可不发,需要发的类型:2、4、6、7 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC0 + self.SubCmd = 0x26 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC0 + self.SubCmd = 0x26 + self.QueryType = 0 + self.BatType = 0 + self.GroupNum = 0 + self.FamilyID = 0 + return + + def GetLength(self): + return sizeof(tagCGFamilyGCZQuery) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 26 仙盟攻城战查询 //tagCGFamilyGCZQuery: + Cmd:%s, + SubCmd:%s, + QueryType:%d, + BatType:%d, + GroupNum:%d, + FamilyID:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.QueryType, + self.BatType, + self.GroupNum, + self.FamilyID + ) + return DumpString + + +m_NAtagCGFamilyGCZQuery=tagCGFamilyGCZQuery() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGFamilyGCZQuery.Cmd,m_NAtagCGFamilyGCZQuery.SubCmd))] = m_NAtagCGFamilyGCZQuery + + +#------------------------------------------------------ # C0 03 强制退出跨服状态 #tagCGForceQuitCrossState class tagCGForceQuitCrossState(Structure): @@ -5245,8 +5309,8 @@ ("Cmd", c_ubyte), ("SubCmd", c_ubyte), ("Type", c_ubyte), #榜单类型 - ("GroupValue1", c_ubyte), # 分组值1 - ("GroupValue2", c_ubyte), # 分组值2,与分组值1组合归为同组榜单数据 + ("GroupValue1", c_int), # 分组值1 + ("GroupValue2", c_int), # 分组值2,与分组值1组合归为同组榜单数据 ("StartIndex", c_int), #查看的起始名次索引, 默认0 ("WatchCnt", c_ubyte), #查看条数,默认20,最大不超过100 ("WatchID", c_int), #查看指定ID名次前后,如玩家ID、家族ID等 @@ -23599,6 +23663,189 @@ #------------------------------------------------------ +# C1 25 仙盟攻城战攻击 #tagCMFamilyGCZAtk + +class tagCMFamilyGCZAtk(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("AtkType", c_ubyte), #攻击类型: 1-普通单攻;2-技能单攻;3-技能群攻; + ("TagCityID", c_int), #目标城池ID,一般是仙盟ID或者特殊城池ID如修罗城城池,普攻单攻需指定目标,群攻技能发0 + ("TagGuardID", c_int), #目标守卫ID,一般是玩家ID或者特殊守卫ID如修罗城守卫,普攻单攻需指定目标,技能攻击发0 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x25 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x25 + self.AtkType = 0 + self.TagCityID = 0 + self.TagGuardID = 0 + return + + def GetLength(self): + return sizeof(tagCMFamilyGCZAtk) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 25 仙盟攻城战攻击 //tagCMFamilyGCZAtk: + Cmd:%s, + SubCmd:%s, + AtkType:%d, + TagCityID:%d, + TagGuardID:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.AtkType, + self.TagCityID, + self.TagGuardID + ) + return DumpString + + +m_NAtagCMFamilyGCZAtk=tagCMFamilyGCZAtk() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZAtk.Cmd,m_NAtagCMFamilyGCZAtk.SubCmd))] = m_NAtagCMFamilyGCZAtk + + +#------------------------------------------------------ +# C1 24 仙盟攻城战捐献 #tagCMFamilyGCZContribution + +class tagCMFamilyGCZContribution(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("ContributionType", c_ubyte), #捐献类型: 0-低级;1-高级 + ("UseCount", c_int), #物品捐献时使用个数 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x24 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x24 + self.ContributionType = 0 + self.UseCount = 0 + return + + def GetLength(self): + return sizeof(tagCMFamilyGCZContribution) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 24 仙盟攻城战捐献 //tagCMFamilyGCZContribution: + Cmd:%s, + SubCmd:%s, + ContributionType:%d, + UseCount:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.ContributionType, + self.UseCount + ) + return DumpString + + +m_NAtagCMFamilyGCZContribution=tagCMFamilyGCZContribution() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZContribution.Cmd,m_NAtagCMFamilyGCZContribution.SubCmd))] = m_NAtagCMFamilyGCZContribution + + +#------------------------------------------------------ +# C1 26 仙盟攻城战竞猜 #tagCMFamilyGCZGuess + +class tagCMFamilyGCZGuess(Structure): + Head = tagHead() + SelectCnt = 0 #(BYTE SelectCnt) + SelectFamilyIDList = list() #(vector<DWORD> SelectFamilyIDList)// 竞猜选择的仙盟ID排名顺序 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC1 + self.Head.SubCmd = 0x26 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.SelectCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.SelectCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.SelectFamilyIDList.append(value) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC1 + self.Head.SubCmd = 0x26 + self.SelectCnt = 0 + self.SelectFamilyIDList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 4 * self.SelectCnt + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.SelectCnt) + for i in range(self.SelectCnt): + data = CommFunc.WriteDWORD(data, self.SelectFamilyIDList[i]) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + SelectCnt:%d, + SelectFamilyIDList:%s + '''\ + %( + self.Head.OutputString(), + self.SelectCnt, + "..." + ) + return DumpString + + +m_NAtagCMFamilyGCZGuess=tagCMFamilyGCZGuess() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZGuess.Head.Cmd,m_NAtagCMFamilyGCZGuess.Head.SubCmd))] = m_NAtagCMFamilyGCZGuess + + +#------------------------------------------------------ # C1 10 幸运云购购买 #tagCMLuckyCloudBuy class tagCMLuckyCloudBuy(Structure): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py index 9e7d65d..58ed11c 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py @@ -17027,8 +17027,8 @@ class tagGCCrossBillboardInfo(Structure): Head = tagHead() Type = 0 #(BYTE Type)//榜单类型 - GroupValue1 = 0 #(BYTE GroupValue1)// 分组值1 - GroupValue2 = 0 #(BYTE GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据 + GroupValue1 = 0 #(DWORD GroupValue1)// 分组值1 + GroupValue2 = 0 #(DWORD GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据 WatchID = 0 #(DWORD WatchID)//查看指定ID名次前后,如玩家ID、家族ID等 BillboardCount = 0 #(BYTE BillboardCount) CrossBillboardDataList = list() #(vector<tagGCCrossBillboardData> CrossBillboardDataList) @@ -17044,8 +17044,8 @@ self.Clear() _pos = self.Head.ReadData(_lpData, _pos) self.Type,_pos = CommFunc.ReadBYTE(_lpData, _pos) - self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos) - self.GroupValue2,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupValue1,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.GroupValue2,_pos = CommFunc.ReadDWORD(_lpData, _pos) self.WatchID,_pos = CommFunc.ReadDWORD(_lpData, _pos) self.BillboardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos) for i in range(self.BillboardCount): @@ -17071,8 +17071,8 @@ length = 0 length += self.Head.GetLength() length += 1 - length += 1 - length += 1 + length += 4 + length += 4 length += 4 length += 1 for i in range(self.BillboardCount): @@ -17084,8 +17084,8 @@ data = '' data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) data = CommFunc.WriteBYTE(data, self.Type) - data = CommFunc.WriteBYTE(data, self.GroupValue1) - data = CommFunc.WriteBYTE(data, self.GroupValue2) + data = CommFunc.WriteDWORD(data, self.GroupValue1) + data = CommFunc.WriteDWORD(data, self.GroupValue2) data = CommFunc.WriteDWORD(data, self.WatchID) data = CommFunc.WriteBYTE(data, self.BillboardCount) for i in range(self.BillboardCount): @@ -18518,6 +18518,1750 @@ m_NAtagGCCrossZoneInfo=tagGCCrossZoneInfo() ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossZoneInfo.Cmd,m_NAtagGCCrossZoneInfo.SubCmd))] = m_NAtagGCCrossZoneInfo + + +#------------------------------------------------------ +# C0 24 仙盟攻城战活动信息 #tagGCFamilyGCZActInfo + +class tagGCFamilyGCZActFamily(Structure): + FamilyID = 0 #(DWORD FamilyID) + Name = "" #(char Name[33])//参与仙盟名字 + LV = 0 #(BYTE LV)//仙盟等级 + ServerID = 0 #(DWORD ServerID)//仙盟所属区服ID + EmblemID = 0 #(DWORD EmblemID)//徽章ID + FightPower = 0 #(DWORD FightPower)//仙盟总战力,求余亿部分 + FightPowerEx = 0 #(DWORD FightPowerEx)//仙盟总战力,整除亿部分 + LeaderID = 0 #(DWORD LeaderID)//盟主ID + LeaderName = "" #(char LeaderName[33])//盟主名 + LeaderFace = 0 #(DWORD LeaderFace) + LeaderFacePic = 0 #(DWORD LeaderFacePic) + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.LV,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.EmblemID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderName,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.LeaderFace,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderFacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.FamilyID = 0 + self.Name = "" + self.LV = 0 + self.ServerID = 0 + self.EmblemID = 0 + self.FightPower = 0 + self.FightPowerEx = 0 + self.LeaderID = 0 + self.LeaderName = "" + self.LeaderFace = 0 + self.LeaderFacePic = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteBYTE(data, self.LV) + data = CommFunc.WriteDWORD(data, self.ServerID) + data = CommFunc.WriteDWORD(data, self.EmblemID) + data = CommFunc.WriteDWORD(data, self.FightPower) + data = CommFunc.WriteDWORD(data, self.FightPowerEx) + data = CommFunc.WriteDWORD(data, self.LeaderID) + data = CommFunc.WriteString(data, 33, self.LeaderName) + data = CommFunc.WriteDWORD(data, self.LeaderFace) + data = CommFunc.WriteDWORD(data, self.LeaderFacePic) + return data + + def OutputString(self): + DumpString = ''' + FamilyID:%d, + Name:%s, + LV:%d, + ServerID:%d, + EmblemID:%d, + FightPower:%d, + FightPowerEx:%d, + LeaderID:%d, + LeaderName:%s, + LeaderFace:%d, + LeaderFacePic:%d + '''\ + %( + self.FamilyID, + self.Name, + self.LV, + self.ServerID, + self.EmblemID, + self.FightPower, + self.FightPowerEx, + self.LeaderID, + self.LeaderName, + self.LeaderFace, + self.LeaderFacePic + ) + return DumpString + + +class tagGCFamilyGCZActInfo(Structure): + Head = tagHead() + ServerInfoLen = 0 #(BYTE ServerInfoLen) + ServerIDRangeInfo = "" #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服 + ZoneID = 0 #(BYTE ZoneID)// 活动分区ID,公示期为0 + ActID = 0 #(DWORD ActID)// 活动ID,代表某一次活动的唯一ID,前端如果有活动相关的本地记录可以通过验证此ID变更进行重置 + StartDate = "" #(char StartDate[10])// 开始日期 y-m-d + EndtDate = "" #(char EndtDate[10])// 结束日期 y-m-d + JoinFamilyCnt = 0 #(BYTE JoinFamilyCnt)// 参与仙盟数 + ActFlowID = 0 #(WORD ActFlowID)// 活动流程ID,对应H.活动时间流程表中的编号,前端根据跨服时间自行计算当前所处流程状态 + GuessTemplateID = 0 #(WORD GuessTemplateID)// 竞猜奖励模版,对应H.活动竞猜表,前端自行读表展示 + PersonalTemplateID = 0 #(WORD PersonalTemplateID)// 个人伤害排行奖励模版,对应H.活动榜单奖励模版表,前端自行读表展示 + FamilyTemplateID = 0 #(WORD FamilyTemplateID)// 仙盟积分排行奖励模版,对应H.活动榜单奖励模版表,前端自行读表展示 + StateError = 0 #(BYTE StateError)// 活动流程状态是否异常,如果不为0代表活动已异常,前端自行决定是不显示活动还是活动页面做提示 + FamilyCount = 0 #(BYTE FamilyCount) + ActFamilyList = list() #(vector<tagGCFamilyGCZActFamily> ActFamilyList)//本分区参与的仙盟名单 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x24 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen) + self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ActID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.JoinFamilyCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ActFlowID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.GuessTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.PersonalTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.FamilyTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.StateError,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.FamilyCount,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyCount): + temActFamilyList = tagGCFamilyGCZActFamily() + _pos = temActFamilyList.ReadData(_lpData, _pos) + self.ActFamilyList.append(temActFamilyList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x24 + self.ServerInfoLen = 0 + self.ServerIDRangeInfo = "" + self.ZoneID = 0 + self.ActID = 0 + self.StartDate = "" + self.EndtDate = "" + self.JoinFamilyCnt = 0 + self.ActFlowID = 0 + self.GuessTemplateID = 0 + self.PersonalTemplateID = 0 + self.FamilyTemplateID = 0 + self.StateError = 0 + self.FamilyCount = 0 + self.ActFamilyList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += len(self.ServerIDRangeInfo) + length += 1 + length += 4 + length += 10 + length += 10 + length += 1 + length += 2 + length += 2 + length += 2 + length += 2 + length += 1 + length += 1 + for i in range(self.FamilyCount): + length += self.ActFamilyList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ServerInfoLen) + data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo) + data = CommFunc.WriteBYTE(data, self.ZoneID) + data = CommFunc.WriteDWORD(data, self.ActID) + data = CommFunc.WriteString(data, 10, self.StartDate) + data = CommFunc.WriteString(data, 10, self.EndtDate) + data = CommFunc.WriteBYTE(data, self.JoinFamilyCnt) + data = CommFunc.WriteWORD(data, self.ActFlowID) + data = CommFunc.WriteWORD(data, self.GuessTemplateID) + data = CommFunc.WriteWORD(data, self.PersonalTemplateID) + data = CommFunc.WriteWORD(data, self.FamilyTemplateID) + data = CommFunc.WriteBYTE(data, self.StateError) + data = CommFunc.WriteBYTE(data, self.FamilyCount) + for i in range(self.FamilyCount): + data = CommFunc.WriteString(data, self.ActFamilyList[i].GetLength(), self.ActFamilyList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ServerInfoLen:%d, + ServerIDRangeInfo:%s, + ZoneID:%d, + ActID:%d, + StartDate:%s, + EndtDate:%s, + JoinFamilyCnt:%d, + ActFlowID:%d, + GuessTemplateID:%d, + PersonalTemplateID:%d, + FamilyTemplateID:%d, + StateError:%d, + FamilyCount:%d, + ActFamilyList:%s + '''\ + %( + self.Head.OutputString(), + self.ServerInfoLen, + self.ServerIDRangeInfo, + self.ZoneID, + self.ActID, + self.StartDate, + self.EndtDate, + self.JoinFamilyCnt, + self.ActFlowID, + self.GuessTemplateID, + self.PersonalTemplateID, + self.FamilyTemplateID, + self.StateError, + self.FamilyCount, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZActInfo=tagGCFamilyGCZActInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZActInfo.Head.Cmd,m_NAtagGCFamilyGCZActInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZActInfo + + +#------------------------------------------------------ +# C0 29 仙盟攻城战城池战斗信息 #tagGCFamilyGCZBatCityInfo + +class tagGCFamilyGCZBatCityInfo(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("CityID", c_int), #城池ID + ("CityLV", c_ubyte), #城池等级 + ("FamilyID", c_int), #所属仙盟ID,可能为0 + ("GuardID", c_int), #当前防守成员ID,为0时表示没有防守成员了,城池已被击毁 + ("HP", c_int), #防守成员剩余生命,求余亿部分,剩余生命为0时代表该防守成员被击败 + ("HPEx", c_int), #防守成员剩余生命,整除亿部分 + ("HPMax", c_int), #防守成员最大生命,求余亿部分 + ("HPMaxEx", c_int), #防守成员最大生命,整除亿部分 + ("AtkPlayerID", c_int), #发起攻击的玩家ID,可能为0,判断是否自己的ID进行相应的攻击表现 + ("AtkRet", c_ubyte), #攻击结果,仅在攻击玩家ID不为0时有效,0--成功;1-目标已被击杀;2-城池已被摧毁;3-其他 + ("KillCnt", c_ubyte), #本次攻击击杀防守人员数 + ("HurtValue", c_int), #伤害飘血,求余亿部分 + ("HurtValueEx", c_int), #伤害飘血,整除亿部分 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC0 + self.SubCmd = 0x29 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC0 + self.SubCmd = 0x29 + self.CityID = 0 + self.CityLV = 0 + self.FamilyID = 0 + self.GuardID = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.AtkPlayerID = 0 + self.AtkRet = 0 + self.KillCnt = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatCityInfo) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 29 仙盟攻城战城池战斗信息 //tagGCFamilyGCZBatCityInfo: + Cmd:%s, + SubCmd:%s, + CityID:%d, + CityLV:%d, + FamilyID:%d, + GuardID:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + AtkPlayerID:%d, + AtkRet:%d, + KillCnt:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.CityID, + self.CityLV, + self.FamilyID, + self.GuardID, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.AtkPlayerID, + self.AtkRet, + self.KillCnt, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +m_NAtagGCFamilyGCZBatCityInfo=tagGCFamilyGCZBatCityInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatCityInfo.Cmd,m_NAtagGCFamilyGCZBatCityInfo.SubCmd))] = m_NAtagGCFamilyGCZBatCityInfo + + +#------------------------------------------------------ +# C0 25 仙盟攻城战轮次分组信息 #tagGCFamilyGCZBatGroupInfo + +class tagGCFamilyGCZBatGroup(Structure): + GroupNum = 0 #(BYTE GroupNum)// 分组编号,从1开始,对应A + FamilyIDCnt = 0 #(BYTE FamilyIDCnt) + FamilyIDList = list() #(vector<DWORD> FamilyIDList)// 仙盟ID列表,前端可以通过判断参与的仙盟ID是否在某个分组里面验证有没有战场参赛资格 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.GroupNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.FamilyIDCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyIDCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.FamilyIDList.append(value) + return _pos + + def Clear(self): + self.GroupNum = 0 + self.FamilyIDCnt = 0 + self.FamilyIDList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 1 + length += 4 * self.FamilyIDCnt + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.GroupNum) + data = CommFunc.WriteBYTE(data, self.FamilyIDCnt) + for i in range(self.FamilyIDCnt): + data = CommFunc.WriteDWORD(data, self.FamilyIDList[i]) + return data + + def OutputString(self): + DumpString = ''' + GroupNum:%d, + FamilyIDCnt:%d, + FamilyIDList:%s + '''\ + %( + self.GroupNum, + self.FamilyIDCnt, + "..." + ) + return DumpString + + +class tagGCFamilyGCZBat(Structure): + BatType = 0 #(BYTE BatType)// 战场类型 1-初级;2-中级;3-高级; + GroupCnt = 0 #(BYTE GroupCnt)// 分组数 + GroupList = list() #(vector<tagGCFamilyGCZBatGroup> GroupList)// 分组列表 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.BatType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.GroupCnt): + temGroupList = tagGCFamilyGCZBatGroup() + _pos = temGroupList.ReadData(_lpData, _pos) + self.GroupList.append(temGroupList) + return _pos + + def Clear(self): + self.BatType = 0 + self.GroupCnt = 0 + self.GroupList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 1 + for i in range(self.GroupCnt): + length += self.GroupList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.BatType) + data = CommFunc.WriteBYTE(data, self.GroupCnt) + for i in range(self.GroupCnt): + data = CommFunc.WriteString(data, self.GroupList[i].GetLength(), self.GroupList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + BatType:%d, + GroupCnt:%d, + GroupList:%s + '''\ + %( + self.BatType, + self.GroupCnt, + "..." + ) + return DumpString + + +class tagGCFamilyGCZBatGroupInfo(Structure): + Head = tagHead() + RoundNum = 0 #(BYTE RoundNum)// 第x轮的分组,从1开始,没有在对应轮次战场分组里的视为没有该轮次的参赛资格 + BatTypeCnt = 0 #(BYTE BatTypeCnt)// 战场类型数 + BatList = list() #(vector<tagGCFamilyGCZBat> BatList)//战场列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x25 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.RoundNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.BatTypeCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.BatTypeCnt): + temBatList = tagGCFamilyGCZBat() + _pos = temBatList.ReadData(_lpData, _pos) + self.BatList.append(temBatList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x25 + self.RoundNum = 0 + self.BatTypeCnt = 0 + self.BatList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 1 + for i in range(self.BatTypeCnt): + length += self.BatList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.RoundNum) + data = CommFunc.WriteBYTE(data, self.BatTypeCnt) + for i in range(self.BatTypeCnt): + data = CommFunc.WriteString(data, self.BatList[i].GetLength(), self.BatList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + RoundNum:%d, + BatTypeCnt:%d, + BatList:%s + '''\ + %( + self.Head.OutputString(), + self.RoundNum, + self.BatTypeCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatGroupInfo=tagGCFamilyGCZBatGroupInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatGroupInfo.Head.Cmd,m_NAtagGCFamilyGCZBatGroupInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZBatGroupInfo + + +#------------------------------------------------------ +# C0 30 仙盟攻城战战斗战报 #tagGCFamilyGCZBatReport + +class tagGCFamilyGCZBatRepHurt(Structure): + _pack_ = 1 + _fields_ = [ + ("TagFamilyID", c_int), #目标仙盟ID + ("HurtValue", c_int), #输出伤害,求余亿部分 + ("HurtValueEx", c_int), #输出伤害,整除亿部分 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.TagFamilyID = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatRepHurt) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 30 仙盟攻城战战斗战报 //tagGCFamilyGCZBatReport: + TagFamilyID:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.TagFamilyID, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZBatReport(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)// 战报仙盟ID + DefRepCnt = 0 #(BYTE DefRepCnt) + DefRepList = list() #(vector<tagGCFamilyGCZBatRepHurt> DefRepList)// 防守战报 + AtkRepCnt = 0 #(BYTE AtkRepCnt) + AtkRepList = list() #(vector<tagGCFamilyGCZBatRepHurt> AtkRepList)// 进攻战报 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x30 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.DefRepCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.DefRepCnt): + temDefRepList = tagGCFamilyGCZBatRepHurt() + _pos = temDefRepList.ReadData(_lpData, _pos) + self.DefRepList.append(temDefRepList) + self.AtkRepCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.AtkRepCnt): + temAtkRepList = tagGCFamilyGCZBatRepHurt() + _pos = temAtkRepList.ReadData(_lpData, _pos) + self.AtkRepList.append(temAtkRepList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x30 + self.FamilyID = 0 + self.DefRepCnt = 0 + self.DefRepList = list() + self.AtkRepCnt = 0 + self.AtkRepList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + for i in range(self.DefRepCnt): + length += self.DefRepList[i].GetLength() + length += 1 + for i in range(self.AtkRepCnt): + length += self.AtkRepList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteBYTE(data, self.DefRepCnt) + for i in range(self.DefRepCnt): + data = CommFunc.WriteString(data, self.DefRepList[i].GetLength(), self.DefRepList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.AtkRepCnt) + for i in range(self.AtkRepCnt): + data = CommFunc.WriteString(data, self.AtkRepList[i].GetLength(), self.AtkRepList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + DefRepCnt:%d, + DefRepList:%s, + AtkRepCnt:%d, + AtkRepList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.DefRepCnt, + "...", + self.AtkRepCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatReport=tagGCFamilyGCZBatReport() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatReport.Head.Cmd,m_NAtagGCFamilyGCZBatReport.Head.SubCmd))] = m_NAtagGCFamilyGCZBatReport + + +#------------------------------------------------------ +# C0 28 仙盟攻城战城池场景信息 #tagGCFamilyGCZBatSceneInfo + +class tagGCFamilyGCZBatScenePlayer(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33]) + Face = 0 #(DWORD Face) + FacePic = 0 #(DWORD FacePic) + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.Face = 0 + self.FacePic = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteDWORD(data, self.Face) + data = CommFunc.WriteDWORD(data, self.FacePic) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + Face:%d, + FacePic:%d + '''\ + %( + self.PlayerID, + self.Name, + self.Face, + self.FacePic + ) + return DumpString + + +class tagGCFamilyGCZBatSceneHurt(Structure): + _pack_ = 1 + _fields_ = [ + ("CityID", c_int), #被攻击的城池ID + ("HurtValue", c_int), #伤害飘血,求余亿部分 + ("HurtValueEx", c_int), #伤害飘血,整除亿部分 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.CityID = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatSceneHurt) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 28 仙盟攻城战城池场景信息 //tagGCFamilyGCZBatSceneInfo: + CityID:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.CityID, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZBatSceneCity(Structure): + _pack_ = 1 + _fields_ = [ + ("CityID", c_int), #城池ID + ("CityLV", c_ubyte), #城池等级 + ("FamilyID", c_int), #所属仙盟ID,可能为0 + ("Rank", c_ubyte), #当前名次,从1开始 + ("HP", c_int), #剩余生命,求余亿部分,剩余生命为0时代表被摧毁 + ("HPEx", c_int), #剩余生命,整除亿部分 + ("HPMax", c_int), #最大生命,求余亿部分 + ("HPMaxEx", c_int), #最大生命,整除亿部分 + ("LastAtkedTime", c_int), #最后一次被攻击时间戳,可能为0 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.CityID = 0 + self.CityLV = 0 + self.FamilyID = 0 + self.Rank = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.LastAtkedTime = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatSceneCity) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 28 仙盟攻城战城池场景信息 //tagGCFamilyGCZBatSceneInfo: + CityID:%d, + CityLV:%d, + FamilyID:%d, + Rank:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + LastAtkedTime:%d + '''\ + %( + self.CityID, + self.CityLV, + self.FamilyID, + self.Rank, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.LastAtkedTime + ) + return DumpString + + +class tagGCFamilyGCZBatSceneInfo(Structure): + Head = tagHead() + BatType = 0 #(BYTE BatType)// 战场类型 1-初级;2-中级;3-高级; + GroupNum = 0 #(BYTE GroupNum)// 分组编号,从1开始,对应A + TopFamilyID = 0 #(DWORD TopFamilyID)// 伤害第一仙盟ID + TopLeaderID = 0 #(DWORD TopLeaderID)// 伤害第一盟主ID + TopPlayerID = 0 #(DWORD TopPlayerID)// 伤害第一玩家ID + TopPlayerFamilyID = 0 #(DWORD TopPlayerFamilyID)// 伤害第一玩家仙盟ID + AtkPlayerID = 0 #(DWORD AtkPlayerID)// 发起攻击的玩家,可能为0,仅技能攻击时通知,普攻时仅通知血量等信息 + AtkType = 0 #(BYTE AtkType)// 攻击类型,有发起攻击的玩家时有效 + KillCnt = 0 #(BYTE KillCnt)// 本次攻击累计击杀数,有发起攻击的玩家时有效 + HurtCnt = 0 #(BYTE HurtCnt) + HurtList = list() #(vector<tagGCFamilyGCZBatSceneHurt> HurtList)//本次攻击伤血信息,有发起攻击的玩家时有效 + CityCnt = 0 #(BYTE CityCnt) + CityList = list() #(vector<tagGCFamilyGCZBatSceneCity> CityList)// 城池信息,仅通知变化的城池 + PlayerCnt = 0 #(BYTE PlayerCnt) + PlayerInfoList = list() #(vector<tagGCFamilyGCZBatScenePlayer> PlayerInfoList)// 场景展示所需要用到的玩家信息,如第一玩家、使用技能玩家 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x28 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.BatType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.TopFamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopLeaderID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopPlayerFamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.AtkPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.AtkType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.KillCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.HurtCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.HurtCnt): + temHurtList = tagGCFamilyGCZBatSceneHurt() + _pos = temHurtList.ReadData(_lpData, _pos) + self.HurtList.append(temHurtList) + self.CityCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.CityCnt): + temCityList = tagGCFamilyGCZBatSceneCity() + _pos = temCityList.ReadData(_lpData, _pos) + self.CityList.append(temCityList) + self.PlayerCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.PlayerCnt): + temPlayerInfoList = tagGCFamilyGCZBatScenePlayer() + _pos = temPlayerInfoList.ReadData(_lpData, _pos) + self.PlayerInfoList.append(temPlayerInfoList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x28 + self.BatType = 0 + self.GroupNum = 0 + self.TopFamilyID = 0 + self.TopLeaderID = 0 + self.TopPlayerID = 0 + self.TopPlayerFamilyID = 0 + self.AtkPlayerID = 0 + self.AtkType = 0 + self.KillCnt = 0 + self.HurtCnt = 0 + self.HurtList = list() + self.CityCnt = 0 + self.CityList = list() + self.PlayerCnt = 0 + self.PlayerInfoList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 1 + length += 1 + length += 1 + for i in range(self.HurtCnt): + length += self.HurtList[i].GetLength() + length += 1 + for i in range(self.CityCnt): + length += self.CityList[i].GetLength() + length += 1 + for i in range(self.PlayerCnt): + length += self.PlayerInfoList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.BatType) + data = CommFunc.WriteBYTE(data, self.GroupNum) + data = CommFunc.WriteDWORD(data, self.TopFamilyID) + data = CommFunc.WriteDWORD(data, self.TopLeaderID) + data = CommFunc.WriteDWORD(data, self.TopPlayerID) + data = CommFunc.WriteDWORD(data, self.TopPlayerFamilyID) + data = CommFunc.WriteDWORD(data, self.AtkPlayerID) + data = CommFunc.WriteBYTE(data, self.AtkType) + data = CommFunc.WriteBYTE(data, self.KillCnt) + data = CommFunc.WriteBYTE(data, self.HurtCnt) + for i in range(self.HurtCnt): + data = CommFunc.WriteString(data, self.HurtList[i].GetLength(), self.HurtList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.CityCnt) + for i in range(self.CityCnt): + data = CommFunc.WriteString(data, self.CityList[i].GetLength(), self.CityList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.PlayerCnt) + for i in range(self.PlayerCnt): + data = CommFunc.WriteString(data, self.PlayerInfoList[i].GetLength(), self.PlayerInfoList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + BatType:%d, + GroupNum:%d, + TopFamilyID:%d, + TopLeaderID:%d, + TopPlayerID:%d, + TopPlayerFamilyID:%d, + AtkPlayerID:%d, + AtkType:%d, + KillCnt:%d, + HurtCnt:%d, + HurtList:%s, + CityCnt:%d, + CityList:%s, + PlayerCnt:%d, + PlayerInfoList:%s + '''\ + %( + self.Head.OutputString(), + self.BatType, + self.GroupNum, + self.TopFamilyID, + self.TopLeaderID, + self.TopPlayerID, + self.TopPlayerFamilyID, + self.AtkPlayerID, + self.AtkType, + self.KillCnt, + self.HurtCnt, + "...", + self.CityCnt, + "...", + self.PlayerCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatSceneInfo=tagGCFamilyGCZBatSceneInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatSceneInfo.Head.Cmd,m_NAtagGCFamilyGCZBatSceneInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZBatSceneInfo + + +#------------------------------------------------------ +# C0 26 仙盟攻城战大本营信息 #tagGCFamilyGCZCampInfo + +class tagGCFamilyGCZCampMem(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33])//参与玩家名字 + FamilyLV = 0 #(BYTE FamilyLV)//参与时的家族职位 + Face = 0 #(DWORD Face)//基本脸型 + FacePic = 0 #(DWORD FacePic)//头像框 + FightPower = 0 #(DWORD FightPower)//战力,求余亿部分 + FightPowerEx = 0 #(DWORD FightPowerEx)//战力,整除亿部分 + HP = 0 #(DWORD HP)//剩余生命,求余亿部分 + HPEx = 0 #(DWORD HPEx)//剩余生命,整除亿部分 + HPMax = 0 #(DWORD HPMax)//最大生命,求余亿部分 + HPMaxEx = 0 #(DWORD HPMaxEx)//最大生命,整除亿部分 + TotalHurt = 0 #(DWORD TotalHurt)//活动总伤害,求余亿部分,如果不在榜上则读该值 + TotalHurtEx = 0 #(DWORD TotalHurtEx)//活动总伤害,整除亿部分 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.FamilyLV,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HP,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMax,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMaxEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TotalHurt,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TotalHurtEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.FamilyLV = 0 + self.Face = 0 + self.FacePic = 0 + self.FightPower = 0 + self.FightPowerEx = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.TotalHurt = 0 + self.TotalHurtEx = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteBYTE(data, self.FamilyLV) + data = CommFunc.WriteDWORD(data, self.Face) + data = CommFunc.WriteDWORD(data, self.FacePic) + data = CommFunc.WriteDWORD(data, self.FightPower) + data = CommFunc.WriteDWORD(data, self.FightPowerEx) + data = CommFunc.WriteDWORD(data, self.HP) + data = CommFunc.WriteDWORD(data, self.HPEx) + data = CommFunc.WriteDWORD(data, self.HPMax) + data = CommFunc.WriteDWORD(data, self.HPMaxEx) + data = CommFunc.WriteDWORD(data, self.TotalHurt) + data = CommFunc.WriteDWORD(data, self.TotalHurtEx) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + FamilyLV:%d, + Face:%d, + FacePic:%d, + FightPower:%d, + FightPowerEx:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + TotalHurt:%d, + TotalHurtEx:%d + '''\ + %( + self.PlayerID, + self.Name, + self.FamilyLV, + self.Face, + self.FacePic, + self.FightPower, + self.FightPowerEx, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.TotalHurt, + self.TotalHurtEx + ) + return DumpString + + +class tagGCFamilyGCZCampInfo(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)//所在活动仙盟ID,可能不是玩家当前的仙盟ID,活动以该ID为准 + Score = 0 #(WORD Score)//活动总积分,如果不在榜上则读该值 + CampLV = 0 #(WORD CampLV)//大本营当前等级 + CampExp = 0 #(DWORD CampExp)//大本营当前经验 + CityLV = 0 #(WORD CityLV)//城池属性等级,开战后可能与当前大本营等级不一样 + HPBase = 0 #(DWORD HPBase)//基础生命,求余亿部分 + HPBaseEx = 0 #(DWORD HPBaseEx)//基础生命,整除亿部分 + HPMax = 0 #(DWORD HPMax)//总生命,求余亿部分 + HPMaxEx = 0 #(DWORD HPMaxEx)//总大生命,整除亿部分 + HP = 0 #(DWORD HP)//剩余生命,求余亿部分 + HPEx = 0 #(DWORD HPEx)//剩余生命,整除亿部分 + DefMemCnt = 0 #(BYTE DefMemCnt) + DefMemList = list() #(vector<tagGCFamilyGCZCampMem> DefMemList)//防守成员列表,有同步则差异更新,没有在防守成员里的视为没有参与资格 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x26 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Score,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.CampLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.CampExp,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.CityLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.HPBase,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPBaseEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMax,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMaxEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HP,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.DefMemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.DefMemCnt): + temDefMemList = tagGCFamilyGCZCampMem() + _pos = temDefMemList.ReadData(_lpData, _pos) + self.DefMemList.append(temDefMemList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x26 + self.FamilyID = 0 + self.Score = 0 + self.CampLV = 0 + self.CampExp = 0 + self.CityLV = 0 + self.HPBase = 0 + self.HPBaseEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.HP = 0 + self.HPEx = 0 + self.DefMemCnt = 0 + self.DefMemList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 2 + length += 2 + length += 4 + length += 2 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 1 + for i in range(self.DefMemCnt): + length += self.DefMemList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteWORD(data, self.Score) + data = CommFunc.WriteWORD(data, self.CampLV) + data = CommFunc.WriteDWORD(data, self.CampExp) + data = CommFunc.WriteWORD(data, self.CityLV) + data = CommFunc.WriteDWORD(data, self.HPBase) + data = CommFunc.WriteDWORD(data, self.HPBaseEx) + data = CommFunc.WriteDWORD(data, self.HPMax) + data = CommFunc.WriteDWORD(data, self.HPMaxEx) + data = CommFunc.WriteDWORD(data, self.HP) + data = CommFunc.WriteDWORD(data, self.HPEx) + data = CommFunc.WriteBYTE(data, self.DefMemCnt) + for i in range(self.DefMemCnt): + data = CommFunc.WriteString(data, self.DefMemList[i].GetLength(), self.DefMemList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + Score:%d, + CampLV:%d, + CampExp:%d, + CityLV:%d, + HPBase:%d, + HPBaseEx:%d, + HPMax:%d, + HPMaxEx:%d, + HP:%d, + HPEx:%d, + DefMemCnt:%d, + DefMemList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.Score, + self.CampLV, + self.CampExp, + self.CityLV, + self.HPBase, + self.HPBaseEx, + self.HPMax, + self.HPMaxEx, + self.HP, + self.HPEx, + self.DefMemCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZCampInfo=tagGCFamilyGCZCampInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZCampInfo.Head.Cmd,m_NAtagGCFamilyGCZCampInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZCampInfo + + +#------------------------------------------------------ +# C0 27 仙盟攻城战成员贡献值信息 #tagGCFamilyGCZContributionInfo + +class tagGCFamilyGCZContribution(Structure): + _pack_ = 1 + _fields_ = [ + ("PlayerID", c_int), + ("ContributionValue", c_int), #贡献值 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.PlayerID = 0 + self.ContributionValue = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZContribution) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 27 仙盟攻城战成员贡献值信息 //tagGCFamilyGCZContributionInfo: + PlayerID:%d, + ContributionValue:%d + '''\ + %( + self.PlayerID, + self.ContributionValue + ) + return DumpString + + +class tagGCFamilyGCZContributionInfo(Structure): + Head = tagHead() + ContriCnt = 0 #(BYTE ContriCnt) + ContriList = list() #(vector<tagGCFamilyGCZContribution> ContriList)//成员贡献值列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x27 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ContriCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.ContriCnt): + temContriList = tagGCFamilyGCZContribution() + _pos = temContriList.ReadData(_lpData, _pos) + self.ContriList.append(temContriList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x27 + self.ContriCnt = 0 + self.ContriList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + for i in range(self.ContriCnt): + length += self.ContriList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ContriCnt) + for i in range(self.ContriCnt): + data = CommFunc.WriteString(data, self.ContriList[i].GetLength(), self.ContriList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ContriCnt:%d, + ContriList:%s + '''\ + %( + self.Head.OutputString(), + self.ContriCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZContributionInfo=tagGCFamilyGCZContributionInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZContributionInfo.Head.Cmd,m_NAtagGCFamilyGCZContributionInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZContributionInfo + + +#------------------------------------------------------ +# C0 31 仙盟攻城战分组仙盟成员伤害明细 #tagGCFamilyGCZGroupFamilyMemHurtInfo + +class tagGCFamilyGCZGroupFamilyMemHurt(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33])//参与玩家名字 + HurtValue = 0 #(DWORD HurtValue)//伤害,求余亿部分 + HurtValueEx = 0 #(DWORD HurtValueEx)//伤害,整除亿部分 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.HurtValue,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HurtValueEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteDWORD(data, self.HurtValue) + data = CommFunc.WriteDWORD(data, self.HurtValueEx) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.PlayerID, + self.Name, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZGroupFamilyMemHurtInfo(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)//查看的目标仙盟ID + HurtMemCnt = 0 #(BYTE HurtMemCnt) + HurtMemList = list() #(vector<tagGCFamilyGCZGroupFamilyMemHurt> HurtMemList)//成员伤害明细列表,只算城池被摧毁前的伤害,未排序,前端自己排序 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x31 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HurtMemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.HurtMemCnt): + temHurtMemList = tagGCFamilyGCZGroupFamilyMemHurt() + _pos = temHurtMemList.ReadData(_lpData, _pos) + self.HurtMemList.append(temHurtMemList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x31 + self.FamilyID = 0 + self.HurtMemCnt = 0 + self.HurtMemList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + for i in range(self.HurtMemCnt): + length += self.HurtMemList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteBYTE(data, self.HurtMemCnt) + for i in range(self.HurtMemCnt): + data = CommFunc.WriteString(data, self.HurtMemList[i].GetLength(), self.HurtMemList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + HurtMemCnt:%d, + HurtMemList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.HurtMemCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo=tagGCFamilyGCZGroupFamilyMemHurtInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo.Head.Cmd,m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo + + +#------------------------------------------------------ +# C0 32 仙盟攻城战竞猜名单信息 #tagGCFamilyGCZGuessInfo + +class tagGCFamilyGCZGuessFamily(Structure): + _pack_ = 1 + _fields_ = [ + ("FamilyID", c_int), #备选仙盟ID + ("GuessValue", c_ushort), #竞猜热度值,玩家每次选择则加1,重复选择也算 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.FamilyID = 0 + self.GuessValue = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZGuessFamily) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 32 仙盟攻城战竞猜名单信息 //tagGCFamilyGCZGuessInfo: + FamilyID:%d, + GuessValue:%d + '''\ + %( + self.FamilyID, + self.GuessValue + ) + return DumpString + + +class tagGCFamilyGCZGuessRight(Structure): + _pack_ = 1 + _fields_ = [ + ("AwardID", c_ubyte), #奖励ID + ("RightPlayerCnt", c_ushort), #猜中玩家个数 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.AwardID = 0 + self.RightPlayerCnt = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZGuessRight) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 32 仙盟攻城战竞猜名单信息 //tagGCFamilyGCZGuessInfo: + AwardID:%d, + RightPlayerCnt:%d + '''\ + %( + self.AwardID, + self.RightPlayerCnt + ) + return DumpString + + +class tagGCFamilyGCZGuessInfo(Structure): + Head = tagHead() + PlayerID = 0 #(DWORD PlayerID)//竞猜玩家ID,有玩家修改竞猜时会附带该信息,如果是自己ID,则更新自己的竞猜选项,否则无视 + SelectCnt = 0 #(BYTE SelectCnt) + SelectFamilyIDList = list() #(vector<DWORD> SelectFamilyIDList)//竞猜玩家选择的仙盟ID顺序 + FinalCnt = 0 #(BYTE FinalCnt) + FinalFamilyIDList = list() #(vector<DWORD> FinalFamilyIDList)//最终排名顺序,仅活动排名出来后才有值 + RightCnt = 0 #(BYTE RightCnt) + RightInfoList = list() #(vector<tagGCFamilyGCZGuessRight> RightInfoList)//猜中个数明细列表 + FamilyCnt = 0 #(BYTE FamilyCnt) + GuessFamilyList = list() #(vector<tagGCFamilyGCZGuessFamily> GuessFamilyList)//备选仙盟名单列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x32 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.SelectCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.SelectCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.SelectFamilyIDList.append(value) + self.FinalCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FinalCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.FinalFamilyIDList.append(value) + self.RightCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.RightCnt): + temRightInfoList = tagGCFamilyGCZGuessRight() + _pos = temRightInfoList.ReadData(_lpData, _pos) + self.RightInfoList.append(temRightInfoList) + self.FamilyCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyCnt): + temGuessFamilyList = tagGCFamilyGCZGuessFamily() + _pos = temGuessFamilyList.ReadData(_lpData, _pos) + self.GuessFamilyList.append(temGuessFamilyList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x32 + self.PlayerID = 0 + self.SelectCnt = 0 + self.SelectFamilyIDList = list() + self.FinalCnt = 0 + self.FinalFamilyIDList = list() + self.RightCnt = 0 + self.RightInfoList = list() + self.FamilyCnt = 0 + self.GuessFamilyList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + length += 4 * self.SelectCnt + length += 1 + length += 4 * self.FinalCnt + length += 1 + for i in range(self.RightCnt): + length += self.RightInfoList[i].GetLength() + length += 1 + for i in range(self.FamilyCnt): + length += self.GuessFamilyList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteBYTE(data, self.SelectCnt) + for i in range(self.SelectCnt): + data = CommFunc.WriteDWORD(data, self.SelectFamilyIDList[i]) + data = CommFunc.WriteBYTE(data, self.FinalCnt) + for i in range(self.FinalCnt): + data = CommFunc.WriteDWORD(data, self.FinalFamilyIDList[i]) + data = CommFunc.WriteBYTE(data, self.RightCnt) + for i in range(self.RightCnt): + data = CommFunc.WriteString(data, self.RightInfoList[i].GetLength(), self.RightInfoList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.FamilyCnt) + for i in range(self.FamilyCnt): + data = CommFunc.WriteString(data, self.GuessFamilyList[i].GetLength(), self.GuessFamilyList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + PlayerID:%d, + SelectCnt:%d, + SelectFamilyIDList:%s, + FinalCnt:%d, + FinalFamilyIDList:%s, + RightCnt:%d, + RightInfoList:%s, + FamilyCnt:%d, + GuessFamilyList:%s + '''\ + %( + self.Head.OutputString(), + self.PlayerID, + self.SelectCnt, + "...", + self.FinalCnt, + "...", + self.RightCnt, + "...", + self.FamilyCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZGuessInfo=tagGCFamilyGCZGuessInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZGuessInfo.Head.Cmd,m_NAtagGCFamilyGCZGuessInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZGuessInfo #------------------------------------------------------ @@ -57675,6 +59419,70 @@ #------------------------------------------------------ +# C1 10 仙盟攻城战玩家信息 #tagMCFamilyGCZPlayerInfo + +class tagMCFamilyGCZPlayerInfo(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("ContributionCnt", c_ubyte), # 轮次低级捐献已捐献次数,轮次变更时会重置 + ("Energy", c_ubyte), # 当前可用免费体力 + ("EnergyTime", c_int), # 上次恢复免费体力时间戳,为0时不再恢复 + ("AwardState", c_int), # 活动奖励领取状态,按二进制位判断是否已领取,0-竞猜奖励;1-个人排行奖励;2-仙盟排名奖励; + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x10 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x10 + self.ContributionCnt = 0 + self.Energy = 0 + self.EnergyTime = 0 + self.AwardState = 0 + return + + def GetLength(self): + return sizeof(tagMCFamilyGCZPlayerInfo) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 10 仙盟攻城战玩家信息 //tagMCFamilyGCZPlayerInfo: + Cmd:%s, + SubCmd:%s, + ContributionCnt:%d, + Energy:%d, + EnergyTime:%d, + AwardState:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.ContributionCnt, + self.Energy, + self.EnergyTime, + self.AwardState + ) + return DumpString + + +m_NAtagMCFamilyGCZPlayerInfo=tagMCFamilyGCZPlayerInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCFamilyGCZPlayerInfo.Cmd,m_NAtagMCFamilyGCZPlayerInfo.SubCmd))] = m_NAtagMCFamilyGCZPlayerInfo + + +#------------------------------------------------------ # C1 08 幸运云购玩家信息 #tagMCLuckyCloudBuyPlayerInfo class tagMCLuckyCloudBuyPlayerInfo(Structure): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CreateFamily.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CreateFamily.py index 0d572b6..5382fb2 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CreateFamily.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CreateFamily.py @@ -18,7 +18,10 @@ import ShareDefine import PlayerFamily import GameWorldFamilyWar +import IPY_GameServer +import random +FackFamilyIDStart = 1000000000 ## 执行逻辑 # @param curPlayer 当前玩家 @@ -27,11 +30,17 @@ def OnExec(curPlayer, gmList): if not gmList: - GameWorld.DebugAnswer(curPlayer, "CreatFamily 创建假仙盟个数 可选参数(仙盟等级 是否设置联赛名次)") - GameWorld.DebugAnswer(curPlayer, "删除创建的假仙盟: CreatFamily 0") + GameWorld.DebugAnswer(curPlayer, "创建跨服假仙盟: CreatFamily c 个数 [总战力 ServerID 等级 成员数]") + GameWorld.DebugAnswer(curPlayer, "删除跨服假仙盟: CreatFamily c 0") + GameWorld.DebugAnswer(curPlayer, "创建本服假仙盟: CreatFamily 个数 [等级 设置联赛名次]") + GameWorld.DebugAnswer(curPlayer, "删除本服假仙盟: CreatFamily 0") return - creatCount = gmList[0] + value1 = gmList[0] + if value1 == "c": + return + + creatCount = value1 if creatCount <= 0: delFamilyList = [] familyManager = GameWorld.GetFamilyManager() @@ -94,4 +103,135 @@ PlayerFamily.DoFamilySort() return +def OnGetMergeParam(curPlayer): + return [] + +def OnMergeServerExec(gmList, tick): + ## 跨服执行命令 + if not gmList: + return + + value1 = gmList[0] + if value1 != "c": + return + + value2 = gmList[1] if len(gmList) > 1 else 1 # 默认1个 + if not value2: + __delMergeServerFackFamily() + return + + __createMergeServerFackFamily(gmList) + return + +def __delMergeServerFackFamily(): + + delCnt = 0 + familyManager = GameWorld.GetFamilyManager() + for i in range(familyManager.GetCount())[::-1]: + family = familyManager.GetAt(i) + if not family: + continue + if family.GetID() >= FackFamilyIDStart: + familyManager.DelFamily(family.GetID()) + delCnt += 1 + + GameWorld.DebugAnswer(None, "成功删除跨服假仙盟: %s,剩余:%s" % (delCnt, familyManager.GetCount())) + return + +def __createMergeServerFackFamily(gmList): + ## c 个数 [总战力 ServerID 等级 成员数] + + creatCount = gmList[1] if len(gmList) > 1 else 1 # 默认1个 + familyFightPower = gmList[2] if len(gmList) > 2 else 10000000 + serverID = gmList[3] if len(gmList) > 3 else random.randint(1, 200) + familyLV = gmList[4] if len(gmList) > 4 else 1 # 默认1级 + memberCnt = gmList[5] if len(gmList) > 5 else random.randint(1, 10) + + FakeFamilyName = "假仙盟".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding()) + FakeMemberName = "假成员".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding()) + + fackFamilyID = FackFamilyIDStart # 跨服假仙盟ID从10亿开始,因为子服的仙盟ID分配是从1开始 + fackFamilyIDMax = fackFamilyID + 10000 # 限制最大假盟数 + fackMemID = 1 # 假成员 1~9999 + fackMemIDMax = 9999 + fackMemIDList = [] + createOKCnt = 0 + familyManager = GameWorld.GetFamilyManager() + for _ in range(min(creatCount, 100)): + + fackFamily = familyManager.FindFamily(fackFamilyID) + while fackFamily and fackFamilyID < fackFamilyIDMax: + for m in xrange(fackFamily.GetCount()): + member = fackFamily.GetAt(m) + memID = member.GetPlayerID() + if memID and memID not in fackMemIDList: + fackMemIDList.append(memID) + fackFamilyID += 1 + fackFamily = familyManager.FindFamily(fackFamilyID) + + if fackFamily: + break + + fackFamilyName = "%s%s" % (FakeFamilyName, fackFamilyID) + fackFamily = familyManager.AddFamilyEx(fackFamilyName, fackFamilyID) + fackFamilyID += 1 + if not fackFamily: + continue + + fackFamily.SetLV(familyLV) + PlayerFamily.SetFamilyTotalFightPower(fackFamily, familyFightPower) + PlayerFamily.SetFamilyEmblemID(fackFamily, 1) + fackFamily.SetServerID(serverID) + + GameWorld.DebugLog("创建假仙盟: fackFamilyID=%s,serverID=%s,familyFightPower=%s,memberCnt=%s" + % (fackFamilyID, serverID, familyFightPower, memberCnt)) + for _ in range(memberCnt): + + while fackMemID in fackMemIDList and fackMemID < fackMemIDMax: + fackMemID += 1 + + if fackMemID in fackMemIDList: + break + fackMemName = "%s%s" % (FakeMemberName, fackMemID) + + member = fackFamily.AddMemberEx(fackMemID) + if not member: + continue + + member.SetName(fackMemName) + member.SetLV(random.randint(100, 200)) + member.SetJob(random.randint(1, 2)) + member.SetOfficialRank(random.randint(1, 20)) + + if not fackFamily.GetLeaderID(): + member.SetFamilyLV(IPY_GameServer.fmlLeader) + fackFamily.SetLeaderID(fackMemID) + fackFamily.SetLeaderName(fackMemName) + fackFamily.SetLeaderOfficialRank(member.GetOfficialRank()) + + fackMemID += 1 + + # 根据成功创建的成员平均分配总战力 + memFightPowerTotal = familyFightPower + memCnt = fackFamily.GetCount() + avgValue = memFightPowerTotal / memCnt + for m in range(memCnt): + member = fackFamily.GetAt(m) + memID = member.GetPlayerID() + fmLV = member.GetFamilyLV() + if m == memCnt - 1: + memFightPower = memFightPowerTotal + else: + memFightPower = avgValue + memCnt / 2 - m + memFightPowerTotal -= memFightPower + PlayerFamily.SetMemberFightPower(member, memFightPower) + GameWorld.DebugLog(" 仙盟成员: memID=%s,memFightPower=%s,fmLV=%s" % (memID, memFightPower, fmLV)) + + createOKCnt += 1 + familyFightPower += 10000 + + GameWorld.DebugAnswer(None, "成功创建跨服假仙盟: %s,总:%s" % (creatCount, familyManager.GetCount())) + return + + diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_GetFamilyByServerID.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_GetFamilyByServerID.py new file mode 100644 index 0000000..7aebf12 --- /dev/null +++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_GetFamilyByServerID.py @@ -0,0 +1,83 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package GM.Commands.GMT_GetFamilyByServerID +# +# @todo:查询仙盟 +# @author hxp +# @date 2025-04-09 +# @version 1.0 +# +# 详细描述: 查询仙盟 - 根据所属区服ID条件 +# +#------------------------------------------------------------------------------- +#"""Version = 2025-04-09 16:00""" +#------------------------------------------------------------------------------- + +import GMCommon +import GameWorld +import PlayerFamily +import ChPlayer + +def OnExec(orderId, gmCmdDict): + serverIDList = eval(gmCmdDict.get("serverIDList", '[]')) + queryCnt = GameWorld.ToIntDef(gmCmdDict.get("queryCnt", '0') , 100) + GameWorld.DebugLog("GMT_GetFamilyByServerID queryCnt=%s, %s, %s" % (queryCnt, serverIDList, gmCmdDict)) + + isCrossServer = GameWorld.IsCrossServer() + familyMgr = GameWorld.GetFamilyManager() + if isCrossServer: + sortFamilyIDList, totalCnt = PlayerFamily.SortCrossFamily(serverIDList, queryCnt) + else: + sortFamilyIDList = PlayerFamily.GetSortFamilyIDList() + totalCnt = len(sortFamilyIDList) + + retCnt = 0 + familyList = [] + for familyID in sortFamilyIDList: + if isCrossServer: + curFamily = familyID + familyID = curFamily.GetID() + else: + curFamily = familyMgr.FindFamily(familyID) + if not curFamily: + continue + familyList.append(GetQueryFamilyInfo(curFamily, isCrossServer)) + retCnt += 1 + if retCnt >= queryCnt: + break + + #执行成功 + retMsg = {"familyList":familyList, "totalCnt":totalCnt} + GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_Success, retMsg) + return + +def GetQueryFamilyInfo(curFamily, isCrossServer): + if curFamily == None: + return {} + + onlineCnt = 0 + memberCnt = curFamily.GetCount() + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + for index in range(memberCnt): + curMember = curFamily.GetAt(index) + playerID = curMember.GetPlayerID() + if onlineMgr.IsOnline(playerID): + onlineCnt += 1 + + familyInfo = { + 'ID':curFamily.GetID(), + 'Name':curFamily.GetName(), + 'FightPower':PlayerFamily.GetFamilyTotalFightPower(curFamily), # 总战力 + 'LeaderID':curFamily.GetLeaderID(), + 'LeaderName':curFamily.GetLeaderName(), + 'LV':curFamily.GetLV(), + 'MemberCnt':memberCnt, + 'OnLineCnt':onlineCnt, + 'ServerID':curFamily.GetServerID(), + } + + return familyInfo + + \ No newline at end of file diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py index d7ad0ea..31bad23 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py @@ -1223,6 +1223,98 @@ # 找不到的默认取最后一名 return orderDict[orderList[-1]] if isDefaultLast else defaultValue +def GetActBillboardTempAward(playerID, billID, billRank, awardTemplateID, billValue=None, fmLV=None): + '''获取玩家活动榜单领奖奖励 + @param playerID: 领奖玩家ID + @param billID: 上榜ID,不一定是玩家ID,比如仙盟ID + @param billRank: 上榜名次 + @param awardTemplateID: 活动奖励模版ID + @param billValue: 榜单上榜值,None时不处理 + @param fmLV: 活动时的仙盟成员等级,None时不处理 + ''' + playerAwardItemList = [] + if not billRank: + return playerAwardItemList + ipyDataList = IpyGameDataPY.GetIpyGameDataList("ActBillboardAwardTemp", awardTemplateID) + if not ipyDataList: + ErrLog("活动榜单奖励模版找不到模版! billID=%s,billRank=%s,awardTemplateID=%s,billValue=%s,fmLV=%s" + % (billID, billRank, awardTemplateID, billValue, fmLV), playerID) + return playerAwardItemList + + for ipyData in ipyDataList: + rank = ipyData.GetRank() + if billRank > rank: + continue + needValue = ipyData.GetNeedValue() + if needValue and billValue != None and billValue < needValue: + continue + + awardItemList = ipyData.GetAwardItemList() + leaderAwardItemList = ipyData.GetLeaderAwardItemList() + eliteAwardItemList = ipyData.GetEliteAwardItemList() + + if fmLV != None and fmLV == IPY_GameServer.fmlLeader and leaderAwardItemList: + playerAwardItemList += leaderAwardItemList + elif fmLV != None and fmLV > IPY_GameServer.fmlMember and eliteAwardItemList: + playerAwardItemList += eliteAwardItemList + else: + playerAwardItemList += awardItemList + + valueAwardEx = ipyData.GetValueAwardEx() + if valueAwardEx and billValue != None: + valueAwardExList = valueAwardEx.keys() + valueAwardExList.sort() + awardItemExList = [] + for valueEx in valueAwardExList: + if billValue < valueEx: + break + awardItemExList = valueAwardEx[valueEx] # 取最大满足条件的一档 + playerAwardItemList += awardItemExList + + return playerAwardItemList + + ErrLog("活动榜单奖励模版找不到奖励! billID=%s,billRank=%s,awardTemplateID=%s,billValue=%s,fmLV=%s" + % (billID, billRank, awardTemplateID, billValue, fmLV), playerID) + return playerAwardItemList + +def GetActGuessRightRankAwardIDDict(guessTemplateID): + ## 获取活动竞猜默认猜中名次对应奖励ID信息 + # @return: {(名次, ...):awardID, ...} 用于 StatActGuessRet 统计竞猜结果 + rightRankAwardIDDict = {} + guessIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActGuess", guessTemplateID) + if guessIpyDataList: + for ipyData in guessIpyDataList: + awardID = ipyData.GetAwardID() + rightRankList = ipyData.GetRightRankList() + rightRankAwardIDDict[tuple(rightRankList)] = awardID + return rightRankAwardIDDict + +def StatActGuessRet(playerID, playerGuessIDList, finalRankIDList, rightRankAwardIDDict, statGuessRetDict, actName=""): + '''统计活动竞猜结果 + @param playerID: 参与竞猜的玩家ID + @param playerGuessIDList: 玩家竞猜选择的ID顺序列表 + @param finalRankIDList: 活动最终排名顺序列表 + @param rightRankAwardIDDict: GetActGuessRightRankAwardIDDict 返回值 + @param statGuessRetDict: 统计结果 {awardID:[猜中的玩家ID, ...], ...} + @param actName: 活动名称,可选参数,输出日志用 + ''' + rightRankList = [] # 玩家猜中的名次列表 + for index, finalID in enumerate(finalRankIDList): + rank = index + 1 + guessID = playerGuessIDList[index] if len(playerGuessIDList) > index else 0 + if guessID == finalID: + rightRankList.append(rank) + + rightRankTuple = tuple(rightRankList) + awardID = rightRankAwardIDDict.get(rightRankTuple, 0) + if awardID not in statGuessRetDict: + statGuessRetDict[awardID] = [] + rightPlayerIDList = statGuessRetDict[awardID] + rightPlayerIDList.append(playerID) + DebugLog(" %s统计玩家竞猜结果: playerID=%s,rightRankTuple=%s,awardID=%s,%s" + % (actName, playerID, rightRankTuple, awardID, len(rightPlayerIDList))) + return + ##概率相关, 这个事件是否能够出现 # @param rate 基础几率 # @param maxRate 最大几率 diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py index 0d1c52f..7772342 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py @@ -27,6 +27,8 @@ import PlayerActGubao import PlayerActHorsePetTrain import PlayerActLianqi +import PlayerDBGSEvent +import CrossFamilyGCZ import CrossRealmMsg import PyGameData import ChConfig @@ -137,6 +139,37 @@ if zoneID != ipyZoneID: return return actInfo + +def GetCrossActInfoByZoneID(actName, zoneID): + ## 获取分区ID对应的跨服活动信息 + crossActInfoDict = GetCrossActInfoDict() + if actName not in crossActInfoDict: + return + curActInfoDict = crossActInfoDict[actName] + for actInfo in curActInfoDict.values(): + ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {}) + if not ipyDataDict: + return + ipyZoneID = ipyDataDict.get("ZoneID", 0) + if zoneID == ipyZoneID: + return actInfo + return + +def GetCrossActZoneIDList(actName): + ## 获取跨服活动当前所有分区列表 + crossActInfoDict = GetCrossActInfoDict() + if actName not in crossActInfoDict: + return [] + zoneIDList = [] + curActInfoDict = crossActInfoDict[actName] + for actInfo in curActInfoDict.values(): + ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {}) + if not ipyDataDict: + return + zoneID = ipyDataDict.get("ZoneID", 0) + if zoneID and zoneID not in zoneIDList: + zoneIDList.append(zoneID) + return zoneIDList def GetCrossActInfoDict(): if PyGameData.g_crossActInfoDict == None: @@ -530,6 +563,7 @@ actChangeList = [] actStateChangeList = [] sysnCrossActInfoDict = {} + flowStateErrorResetList = [] for actName in ShareDefine.CrossActNameList: if actName not in actTimeInfoDict or actName not in crossActInfoDict or actName not in actCfgIDInfoDict: continue @@ -549,6 +583,8 @@ cfgID = ipyData.GetCfgID() groupName = ipyData.GetActGroupName() zoneID = ipyData.GetZoneID() + actFlowID = ipyData.GetActFlowID() if hasattr(ipyData, "GetActFlowID") else 0 # 活动流程ID + actStartDataTime = None if cfgID not in crossActInfoDict[actName]: crossActInfoDict[actName][cfgID] = {} @@ -560,6 +596,7 @@ endDateTime = endList[dIndex] if startDateTime <= curDateTime < endDateTime: state = dIndex + 1 # 也是代表第几个时间段 + actStartDataTime = startDateTime break if endList: isEnd = (curDateTime >= endList[-1]) @@ -575,18 +612,11 @@ else: stateJoin = ShareDefine.ActStateJoin_Start if state else ShareDefine.ActStateJoin_None + actID = actInfoDict.get(ShareDefine.ActKey_ID, 0) + templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0) serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList) - # 全服广播提示信息 - if curDateTime in notifyDict: - if serverIDRangeList != None: - notifyKey, paramList = notifyDict[curDateTime] - country = 0 - serverGroupIDList = [] - crossNotifyList = [] - crossNotifyList.append([ShareDefine.CrossNotify_CrossAct, [country, notifyKey, paramList], serverIDRangeList]) - PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList) - dbInfo = actInfoDict.get(ShareDefine.ActKey_DBInfo, {}) + dbState = dbInfo.get(ShareDefine.ActKey_State, 0) dbStateJoin = dbInfo.get(ShareDefine.ActKey_StateJoin, 0) dbCfgID = dbInfo.get(ShareDefine.ActKey_CfgID, 0) @@ -598,8 +628,33 @@ if dbCfgID == cfgID and dbServerIDRangeList != serverIDRangeList: forceReset = True - actID = actInfoDict.get(ShareDefine.ActKey_ID, 0) - templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0) + errStateActID = 0 + if state and actFlowID: # 有活动流程ID的,实际状态按取活动流程对应状态 + errStateActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID)) + # 已经是不同活动了,强制重置异常状态标记,防止影响新活动 + if errStateActID and (errStateActID != actID or not dbState): + GameWorld.Log("按流程走的活动流程上次异常,新活动重置状态! %s,zoneID=%s,actID=%s,errStateActID=%s,dbState=%s" % (actName, zoneID, actID, errStateActID, dbState)) + PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), 0) + errStateActID = 0 + + flowStateIndex, flowState, flowStatePre = GetActTimeFlowState(actFlowID, actStartDataTime, curDateTime) + # 非第一个流程状态变更的时候,要验证流程是否正确,如果异常,则流程照走,标记异常,具体异常的处理由各活动自行处理 + if flowStateIndex > 0 and flowState != dbState and flowStatePre != dbState and not errStateActID: + GameWorld.ErrLog("按流程走的活动流程已异常! %s,zoneID=%s,actID=%s,flowStatePre=%s,dbState=%s" % (actName, zoneID, actID, flowStatePre, dbState)) + PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), actID) + errStateActID = actID + state = flowState + + # 全服广播提示信息 + if curDateTime in notifyDict and not flowState and not errStateActID: + if serverIDRangeList != None: + notifyKey, paramList = notifyDict[curDateTime] + country = 0 + serverGroupIDList = [] + crossNotifyList = [] + crossNotifyList.append([ShareDefine.CrossNotify_CrossAct, [country, notifyKey, paramList], serverIDRangeList]) + PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList) + if not isReload and dbState == state and dbStateJoin == stateJoin and dbActID == actID and not forceReset: #已经是这个状态了 continue @@ -612,6 +667,9 @@ dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID, ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList, ShareDefine.ActKey_StateJoin:stateJoin} + if errStateActID: + actInfoDict[ShareDefine.ActKey_StateError] = errStateActID + actInfoDict[ShareDefine.ActKey_DBInfo] = dbInfo #GameWorld.Log(" 活动状态同步信息: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,actInfoDict=%s" % (actName, cfgID, groupName, zoneID, actInfoDict)) if actName not in sysnCrossActInfoDict: @@ -622,6 +680,9 @@ GameWorld.Log(" 活动ID变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbActID=%s -> actID=%s,forceReset=%s,dbTemplateID=%s" % (actName, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID)) + if errStateActID: + flowStateErrorResetList.append((actName, zoneID)) + if actName == ShareDefine.CrossActName_CTGBillboard: CrossActCTGBillboard.OnActIDChange(cfgID, dbTemplateID, state) @@ -640,18 +701,21 @@ elif actName == ShareDefine.CrossActName_Lianqi: PlayerActLianqi.OnCrossActIDChange(cfgID, zoneID, ipyData, state) + elif actName == ShareDefine.CrossActName_FamilyGCZ: + CrossFamilyGCZ.OnCrossActIDChange(cfgID, zoneID, ipyData, state) + else: actChangeList.append([actName, ipyData, state, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID]) # 活动ID变更强制视为状态变更,防止维护前后状态一样,但其实活动ID已经不同的情况会导致无法触发状态变更 actIDChange = True - actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, dbTemplateID]) + actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID]) elif dbState != state: actIDChange = False GameWorld.Log(" 活动状态变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,actIDChange=%s,dbTemplateID=%s" % (actName, cfgID, groupName, zoneID, dbState, state, actIDChange, dbTemplateID)) - actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, dbTemplateID]) + actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID]) # 活动中刷新,每次都需要刷新的逻辑,包含重读配置等 if state: @@ -713,15 +777,67 @@ CrossActAllRecharge.OnActIDChange(ipyData, state) for changeInfo in actStateChangeList: - actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, dbTemplateID = changeInfo + actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID = changeInfo GameWorld.Log(" 活动状态变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,actIDChange=%s,dbTemplateID=%s" % (actName, cfgID, groupName, zoneID, dbState, state, actIDChange, dbTemplateID)) if actName == ShareDefine.CrossActName_LuckyCloudBuy: import CrossLuckyCloudBuy CrossLuckyCloudBuy.OnLuckyCloudBuyStateChange(ipyData, actIDChange, state) + elif actName == ShareDefine.CrossActName_FamilyGCZ: + CrossFamilyGCZ.OnCrossActStateChange(ipyData, actID, dbState, state) + for actName, zoneID in flowStateErrorResetList: + GameWorld.Log("活动结束重置按流程走的活动流程异常状态! %s,zoneID=%s" % (actName, zoneID)) + PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), 0) + return + +def IsActFlowStateError(actName, zoneID): + ## 流程状态是否已异常 + errStateActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID)) + if errStateActID: + GameWorld.ErrLog("活动流程状态已异常! %s,zoneID=%s,errStateActID=%s" % (actName, zoneID, errStateActID)) + return True + return False + +def GetActTimeFlowState(actFlowID, actStartDataTime, curDateTime): + ## 获取活动流程ID对应当前状态 + ipyDataList = IpyGameDataPY.GetIpyGameDataList("ActTimeFlow", actFlowID) + if not ipyDataList: + return 0 + + flowStatePre = 0 + flowState = 0 + flowStateIndex = -1 + for index, timeIpyData in enumerate(ipyDataList): + #dataID = timeIpyData.GetID() + startDay, startHour, startMinute = timeIpyData.GetStartDay(), timeIpyData.GetStartHour(), timeIpyData.GetStartMinute() + endDay, endHour, endMinute = timeIpyData.GetEndDay(), timeIpyData.GetEndHour(), timeIpyData.GetEndMinute() + + startSeconds = ((startDay - 1) * 24 + startHour) * 3600 + startMinute * 60 + endSeconds = ((endDay - 1) * 24 + endHour) * 3600 + endMinute * 60 + startDateTime = actStartDataTime + datetime.timedelta(seconds=startSeconds) + endDateTime = actStartDataTime + datetime.timedelta(seconds=endSeconds) + if curDateTime < startDateTime or curDateTime > endDateTime: + flowStatePre = timeIpyData.GetStateValue() + continue + flowState = timeIpyData.GetStateValue() + flowStateIndex = index + #notifyInfoDict = timeIpyData.GetNotifyInfo() + #if not stateError and notifyInfoDict: + # diffDateTime = curDateTime - startDateTime + # diffMinute = (diffDateTime.days * 24 * 3600 + diffDateTime.seconds) / 60 # 当前时间与开始时间相差分钟数 + # GameWorld.DebugLog(" 广播判断: curDateTime=%s,startDateTime=%s,diffDays=%s,diffSeconds=%s,diffMinute=%s" + # % (curDateTime, startDateTime, diffDateTime.days, diffDateTime.seconds, diffMinute)) + # if diffMinute in notifyInfoDict: + # notifyKey, paramList = notifyInfoDict[diffMinute] + # PlayerControl.WorldNotifyCross(serverGroupIDList, 0, notifyKey, paramList) + break + + if not flowState: + flowStatePre = 0 + return flowStateIndex, flowState, flowStatePre def Sync_CrossActInfoToClientServer(serverGroupID=0): ''' 同步跨服运营活动信息到子服务器 @@ -761,6 +877,10 @@ GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, syncActInfoDict) + # 以下需要等活动信息同步给地图后才处理 + if actName == ShareDefine.CrossActName_FamilyGCZ: + CrossFamilyGCZ.ClientServer_CrossActInfo() + # 删除非活动中的 for actName, actInfoDict in PyGameData.g_crossActInfoDict.items(): for cfgID, actInfo in actInfoDict.items(): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py index 93bbf87..d3fec6f 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py @@ -19,6 +19,7 @@ import ShareDefine import IpyGameDataPY import CrossRealmMsg +import PlayerViewCache import PyGameDataStruct import ChPyNetSendPack import DataRecordPack @@ -66,6 +67,27 @@ for key in self.__billboardDict.keys(): if key[0] == billboardType: self.__billboardDict.pop(key) + return + + def ClearBillboard(self, billboardType, groupValue1=None, groupValue2=None): + '''清除某个类型的榜单所有数据,可指定过滤groupValue,有流向记录 + @param groupValue1: 不为None时验证 groupValue1 是否相同 + @param groupValue2: 不为None时验证 groupValue2 是否相同 + 如果groupValue1 groupValue2 都传入None,相当于清空 billboardType 类型的所有榜单数据 + ''' + clearList = [] + for bType, gValue1, gValue2 in self.__billboardDict.keys(): + if bType != billboardType: + continue + if groupValue1 != None and groupValue1 != gValue1: + continue + if groupValue2 != None and groupValue2 != gValue2: + continue + key = (bType, gValue1, gValue2) + clearList.append(key) + + for bType, gValue1, gValue2 in clearList: + self.GetCrossBillboard(bType, gValue1, gValue2).ClearData() return # 保存数据 存数据库和realtimebackup @@ -450,8 +472,8 @@ #{ # tagHead Head; # BYTE Type; //榜单类型 -# BYTE GroupValue1; // 分组值1 -# BYTE GroupValue2; // 分组值2,与分组值1组合归为同组榜单数据 +# DWORD GroupValue1; // 分组值1 +# DWORD GroupValue2; // 分组值2,与分组值1组合归为同组榜单数据 # DWORD StartIndex; //查看的起始名次索引, 默认0 # BYTE WatchCnt; //查看条数,默认20,最大不超过100 # DWORD WatchID; //查看指定ID名次前后,如玩家ID、家族ID等 @@ -771,6 +793,21 @@ id2=id2, autoSort=autoSort, value3=value3, value4=value4, value5=value5) return +def UpdCrossBillboardPlayer(bType, playerID, groupValue1, cmpValue, cmpValue2=0, value1=0, value2=0, groupValue2=0, autoSort=True, **kwargs): + ## 通用的更新跨服玩家榜,GameServer直接调用 + playerInfo = PlayerViewCache.GetShotCacheDict(playerID, "AccID", "ServerID", "Face", "FacePic") + name1 = playerInfo.get("Name", "") + name2 = playerInfo.get("AccID", "") + type2 = playerInfo.get("Job", 1) + if not value1: + value1 = playerInfo.get("RealmLV", 1) + value3 = playerInfo.get("Face", 0) + value4 = playerInfo.get("FacePic", 0) + value5 = playerInfo.get("ServerID", 0) + UpdCrossBillboard(bType, groupValue1, playerID, name1, name2, type2, value1, value2, cmpValue, cmpValue2, + autoSort=autoSort, value3=value3, value4=value4, value5=value5) + return + def UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue, cmpValue2=0, cmpValue3=0, groupValue2=0, id2=0, autoSort=True, noSortAndSync=False, **kwargs): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyGCZ.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyGCZ.py new file mode 100644 index 0000000..0b61fe1 --- /dev/null +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyGCZ.py @@ -0,0 +1,2902 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package CrossFamilyGCZ +# +# @todo:仙盟攻城战 +# @author hxp +# @date 2025-04-09 +# @version 1.0 +# +# 详细描述: 仙盟攻城战 +# +#------------------------------------------------------------------------------- +#"""Version = 2025-04-09 16:00""" +#------------------------------------------------------------------------------- + +import GameWorld +import ShareDefine +import PlayerFamily +import IpyGameDataPY +import CrossRealmMsg +import CrossBillboard +import PlayerViewCache +import CrossActionControl +import PlayerCompensation +import ChPyNetSendPack +import NetPackCommon +import PyDataManager +import PlayerControl +import PyGameData +import ChConfig +import ChPlayer + +import random +import copy +import time + + +## 1-公示期;99-领奖期;轮次状态=轮次*10+轮次阶段;轮次阶段:1-分组战备;2-战斗;3-休战结算 +FamilyGCZState_Publicity = 1 # 公示期 +FamilyGCZState_Award = 99 # 结束领奖期 + +# 轮次状态信息 +FamilyGCZRoundState_Group = 1 # 分组+战备 +FamilyGCZRoundState_Fight = 2 # 战斗 +FamilyGCZRoundState_Over = 3 # 休战结算 + +# 战场类型 +BatTypeList = ( +BatType_Junior, # 初级 1 +BatType_Middle, # 中级 2 +BatType_High, # 高级 3 +) = range(1, 1 + 3) + +# 攻击类型 +( +AtkType_Normal, # 普通单攻 1 +AtkType_SkillSingle, # 技能单攻 2 +AtkType_SkillArea, # 技能群攻 3 +) = range(1, 1 + 3) + +# 攻击结果 +( +AtkRet_OK, # 成功 0 +AtkRet_TagDead, # 目标已被击杀 1 +AtkRet_TagBroken, # 城池已被摧毁 3 +AtkRet_Other, # 其他 3 +) = range(4) + +# 修罗城池ID,每个分组都允许有各自的修罗城,ID可以一样 +XiuluoCityID = 2000000000 + +# 奖励类型 +( +AwwardType_Guess, # 竞猜 +AwwardType_PlayerHurt, # 个人伤害排行 +AwwardType_FamilyScore, # 仙盟积分排行 +) = range(3) + + +class FamilyGCZFighter(object): + ## 城池战斗防守人员 - 玩家、守卫战斗类 + + def __init__(self): + self.fighterID = 0 + self.hp = 0 # 当前血量 + self.hpMax = 0 # 最大血量 + self.hpBase = 0 # 基础血量,不算加成 + self.fightPower = 0 # 战斗力 + return + + def IsDead(self): return self.hp <= 0 + + def RefreshFighterAttr(self, hpFightPowerMulti, addHPPer): + self.hpBase = self.fightPower * hpFightPowerMulti + self.hpMax = int(self.hpBase * (100 + addHPPer) / 100.0) + self.hp = self.hpMax # 只要刷属性就回满血,战斗阶段会锁住不允许刷属性 + return + +class FamilyGCZCityWall(): + ## 城池 + + def __init__(self, zoneID=0, cityID=0, cityLV=0, familyID=0): + self.zoneID = zoneID + self.batType = 0 + self.groupNum = 0 + self.cityID = cityID # 城池ID + self.cityLV = cityLV # 城池等级,一般为锁定时的大本营等级,或指定的等级,战斗属性加成由该等级决定 + self.familyID = familyID # 所属仙盟ID,可能无归属,如修罗城 + self.guardMemIDList = [] # 防守战斗人员ID列表,被击杀不变 + self.fighterIDList = [] # 防守战斗人员ID列表,按成员战力升序排,NPC守卫 + 成员,被击杀移除 + + self.guardNPCCount = 0 # 守卫NPC数,这里指的是非玩家的系统守卫 + self.guardNPC = FamilyGCZFighter() # 当前NPC守卫,目前仅修罗成有用 + + self.attrLock = 0 # 是否锁定属性 + self.hp = 0 # 当前血量,所有防守战斗人员hp 之和 + self.hpMax = 0 # 最大血量,所有防守战斗人员hp hpMax 之和 + self.hpBase = 0 # 基础血量,不算加成,所有防守战斗人员hp hpBase 之和 + self.fightPowerTotal = 0 # 总战力 + + self.atkedTime = 0 # 最后一次被攻击时间戳 + self.atkReportDict = {} # 攻击战报 {tagFamilyID:totalHurt, ...} + self.defReportDict = {} # 防守战报 {tagFamilyID:totalHurt, ...} + self.fighterHurtDict = {} # 战斗成员贡献伤害,被击毁后不会再累加 {playerID:hurtValue, ...} + self.inCityPlayerIDList = [] # 在战斗城池里的玩家ID列表 + return + + def ResetDefense(self, cityLV, guardMemIDList=None, guardNPCCount=0): + ## 城池重置防御 + self.attrLock = 0 + self.cityLV = cityLV + self.guardMemIDList = [] + self.guardNPCCount = guardNPCCount + if self.guardNPCCount: + self.guardMemIDList += range(1, 1 + self.guardNPCCount) + if guardMemIDList: + self.guardMemIDList += guardMemIDList + self.atkedTime = 0 + self.atkReportDict = {} + self.defReportDict = {} + self.fighterHurtDict = {} + self.inCityPlayerIDList = [] + self.RefreshCityAttr() + return + + def OnFightStart(self): + ## 战斗开始 - 锁定 + self.RefreshCityAttr() + self.attrLock = 1 # 刷完属性后锁住 + return + + def IsBroken(self): + ## 是否被击毁 + if self.hp <= 0 or not self.fighterIDList: + return True + return False + + def GetCurGuardID(self): + ## 当前守卫ID + if not self.fighterIDList: + return 0 + return self.fighterIDList[0] + + def NextGuard(self): + ## 换下一个守卫 + if not self.fighterIDList: + return 0 + self.fighterIDList.pop(0) + if not self.fighterIDList: + return 0 + nextGuardID = self.fighterIDList + if self.IsGuardNPC(nextGuardID): + self.guardNPC.hp = self.guardNPC.hpMax + GameWorld.DebugLog(" 切换下一个NPC守卫: %s, %s/%s" % (nextGuardID, self.guardNPC.hp, self.guardNPC.hpMax)) + else: + GameWorld.DebugLog(" 切换下一个防守人员: %s" % nextGuardID) + return nextGuardID + + def IsGuardNPC(self, fighterID): + ## 是否系统NPC守卫,加上系统NPC数验证,兼容内网假仙盟成员测试 + return self.guardNPCCount > 0 and fighterID < 10000 + + def RefreshCityAttr(self, cityLV=None): + # @return: 是否成功刷新属性,战斗锁定时无法刷属性 + if self.attrLock: + GameWorld.ErrLog("仙盟攻城战已经锁定战斗属性不能刷新! cityID=%s,familyID=%s" % (self.cityID, self.familyID)) + return + if cityLV != None: + self.cityLV = cityLV + cityID = self.cityID + cityLV = self.cityLV + addHPPer = 0 + campIpyData = IpyGameDataPY.GetIpyGameData("CrossActFamilyGCZCampLV", cityLV) + if campIpyData: + addHPPer = campIpyData.GetAddHPPer() + + hpFightPowerMulti = IpyGameDataPY.GetFuncCfg("FamilyGCZCity", 1) # 成员生命是战力的x倍 + GameWorld.DebugLog("仙盟攻城战刷新城池属性: cityID=%s,cityLV=%s,addHPPer=%s,hpFightPowerMulti=%s" % (cityID, cityLV, addHPPer, hpFightPowerMulti)) + + zone = GetFamilyGCZMgr().GetActZone(self.zoneID) + + self.hpBase = 0 + self.hpMax = 0 + self.fightPowerTotal = 0 + sortFighterIDList = [] + for fighterID in self.guardMemIDList: + if self.IsGuardNPC(fighterID): + fighter = self.guardNPC + fighter.fightPower = IpyGameDataPY.GetFuncCfg("FamilyGCZXiuluo", 1) + else: + fighter = zone.GetZoneJoinMember(fighterID) + + fighter.RefreshFighterAttr(hpFightPowerMulti, addHPPer) + + self.hpBase += fighter.hpBase + self.hpMax += fighter.hpMax + self.fightPowerTotal += fighter.fightPower + + sortFighterIDList.append([fighter.fightPower, fighterID]) + GameWorld.DebugLog(" 成员属性: cityID=%s,fighterID=%s,fightPower=%s,hpBase=%s,hpMax=%s,cityHPMax=%s" + % (cityID, fighterID, fighter.fightPower, fighter.hpBase, fighter.hpMax, self.hpMax)) + + sortFighterIDList.sort() # 按战力升序 + self.fighterIDList = [f[1] for f in sortFighterIDList] + + self.hp = self.hpMax # 只要刷属性就回满血,战斗阶段会锁住不允许刷属性 + + GameWorld.DebugLog(" 城池属性: cityID=%s,cityLV=%s,fightPowerTotal=%s,hpBase=%s,hpMax=%s" % (cityID, cityLV, self.fightPowerTotal, self.hpBase, self.hpMax)) + GameWorld.DebugLog(" 防守人员战力ID排序=%s" % sortFighterIDList) + GameWorld.DebugLog(" 防守人员ID排序顺序=%s" % self.fighterIDList) + return True + + def SetPlayerInCity(self, playerID, serverGroupID): + if playerID in self.inCityPlayerIDList: + return + self.inCityPlayerIDList.append(playerID) + Sync_FamilyGCZBatCityInfo(self.zoneID, self.batType, self.groupNum, self.cityID, toPlayerServerDict={playerID:serverGroupID}) + return + + def SetPlayerOutCity(self, playerID): + if playerID in self.inCityPlayerIDList: + self.inCityPlayerIDList.remove(playerID) + return + +class FamilyGCZMember(FamilyGCZFighter): + ## 参与的成员 + + def __init__(self, zoneID=0, familyID=0, playerID=0): + super(FamilyGCZMember, self).__init__() + self.zoneID = zoneID + self.batType = 0 + self.groupNum = 0 + self.playerID = playerID + self.familyID = familyID # 参与时的仙盟ID + self.fighterID = playerID + self.fmLV = 0 # 参与时的仙盟职位等级 + self.playerName = "" + self.job = 0 + self.realmLV = 0 + self.face = 0 + self.facePic = 0 + self.lv = 0 + self.totalHurtValue = 0 # 活动总伤害,可能无法上榜,记录用 + self.awardState = 0 # 活动发奖同步记录,与子服的玩家个人记录对应,该记录仅用于补发奖励用 + return + +class FamilyGCZFamily(): + ## 参与的仙盟 + + def __init__(self, zoneID=0, familyID=0): + self.zoneID = zoneID + self.familyID = familyID + self.batType = 0 + self.groupNum = 0 + self.campLV = 1 # 大本营等级 + self.campExp = 0 + self.score = 0 # 活动总积分 + + self.familyName = "" + self.lv = 0 + self.leaderID = 0 + self.leaderName = "" + self.emblemID = 0 + self.serverID = 0 + self.fightPowerTotal = 0 + + self.joinMemberIDList = [] # 参与的成员ID列表 [playerID, ...] + self.memAddCampExpInfo = {} # 成员贡献大本营经验信息 {playerID:addExp, ...} + self.cityWall = FamilyGCZCityWall(zoneID, familyID, self.campLV, familyID) # 每个盟自带一个城池 + return + + def OnRoundFamilyReset(self): + ## 轮次重置处理 + self.batType = 0 + self.groupNum = 0 + self.cityWall.ResetDefense(self.campLV, self.joinMemberIDList) + self.fightPowerTotal = self.cityWall.fightPowerTotal + Sync_FamilyGCZCampInfo(self.zoneID, self.familyID) + return + + def OnRoundFamilyFightStart(self): + ## 轮次开战 + self.cityWall.OnFightStart() + self.fightPowerTotal = self.cityWall.fightPowerTotal + Sync_FamilyGCZCampInfo(self.zoneID, self.familyID) + return + + def RefreshFamilyAttr(self, isNotify=True): + ## 刷新仙盟战斗属性 + isOK = self.cityWall.RefreshCityAttr(self.campLV) + self.fightPowerTotal = self.cityWall.fightPowerTotal + if isNotify: + Sync_FamilyGCZCampInfo(self.zoneID, self.familyID) + return isOK + + def AddCampExp(self, playerID, addCampExp, isNotify=True): + ## 大本营加经验 + # @return: 是否升级 + if playerID not in self.joinMemberIDList: + # 非本盟锁定成员不能加经验 + GameWorld.ErrLog("非仙盟攻城战锁定成员无法加大本营经验! familyID=%s,playerID=%s not in %s" % (self.familyID, playerID, self.joinMemberIDList)) + return + + campLV = self.campLV + campExp = self.campExp + updCampExp = min(campExp + addCampExp, ChConfig.Def_UpperLimit_DWord) + updCampLV = campLV + + # 满级了也不限制捐献,让玩家可以继续消耗多余的道具 + campIpyData = IpyGameDataPY.GetIpyGameData("CrossActFamilyGCZCampLV", campLV) + if campIpyData and campIpyData.GetLVUPNeedExp(): + lvupNeedExp = campIpyData.GetLVUPNeedExp() + if updCampExp >= lvupNeedExp and IpyGameDataPY.GetIpyGameDataNotLog("CrossActFamilyGCZCampLV", campLV + 1): + updCampExp -= lvupNeedExp + updCampLV = campLV + 1 + + self.campLV = updCampLV + self.campExp = updCampExp + self.memAddCampExpInfo[playerID] = self.memAddCampExpInfo.get(playerID, 0) + addCampExp + + GameWorld.DebugLog("增加大本营经验: familyID=%s,playerID=%s,addCampExp=%s,campLV-Exp=%s-%s,updLV-Exp=%s-%s,playerAddExpTotal=%s" + % (self.familyID, playerID, addCampExp, campLV, campExp, updCampLV, updCampExp, self.memAddCampExpInfo[playerID])) + + # 升级了 + defMemIDList = [] # 加经验默认不通知防守成员属性 + isLVUP = False + if campLV != updCampLV: + isLVUP = True + GameWorld.DebugLog("大本营升级了! familyID=%s,campLV=%s to %s" % (self.familyID, campLV, updCampLV)) + if self.RefreshFamilyAttr(False): + defMemIDList = None # 升级后成功刷成员属性后,额外附带所有防守成员信息,战斗阶段属性是锁定的 + + if isNotify: + Sync_FamilyGCZCampInfo(self.zoneID, self.familyID, defMemIDList=defMemIDList) + + return isLVUP + + def GetOLMemServerGroupIDDict(self): + ## 获取本盟在线参与成员信息 + olDict = {} + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + for playerID in self.joinMemberIDList: + serverGroupID = onlineMgr.GetOLPlayerServerGroupID(playerID) + if serverGroupID: + olDict[playerID] = serverGroupID + return olDict + +class FamilyGCZBatGroup(): + ## 战斗分组 + + def __init__(self, zoneID, batType, groupNum): + self.zoneID = zoneID + self.batType = batType + self.groupNum = groupNum + + # 城池并不一定归属于某个仙盟所以由分组自行管理 + self.cityWallDict = {} # 城池对象信息 {cityID:FamilyGCZCityWall, ...} + self.__cityIDList = [] # 城池ID列表,按添加顺序的列表 + self.__topHurtPlayerID = 0 # 本组伤害第一玩家ID + self.__topHurtPlayerValue = 0 # 本组伤害第一玩家伤害 + self.inBatScenePlayerIDList = [] # 在战斗场景中的玩家ID列表 [playerID, ...] + return + + def GetTopHurtPlayerIDValue(self): + ## 获取本组有效伤害第一玩家,仅算城池未被摧毁前的累计伤害 + if self.__topHurtPlayerID and self.__topHurtPlayerValue: + return self.__topHurtPlayerID, self.__topHurtPlayerValue + + for cityID in self.cityWallDict.keys(): + cityWall = self.GetCityWall(cityID) + if not cityWall: + continue + for playerID, hurtTotal in cityWall.fighterHurtDict.items(): + if hurtTotal > self.__topHurtPlayerValue: + self.__topHurtPlayerID = playerID + + return self.__topHurtPlayerID, self.__topHurtPlayerValue + def UpdTopHurtPlayerIDValue(self, topPlayerID, topHurtValue): + self.__topHurtPlayerID, self.__topHurtPlayerValue = topPlayerID, topHurtValue + return + + def GetCityIDList(self): + if not self.__cityIDList: + self.__cityIDList = self.cityWallDict.keys() + return self.__cityIDList + + def GetCityWall(self, cityID): + ## 获取某个城池,可能为None + cityWall = None + if cityID in self.cityWallDict: + cityWall = self.cityWallDict[cityID] + elif False: # 不可能执行,提示代码用 + cityWall = FamilyGCZCityWall() + return cityWall + + def GetGroupFamilyIDList(self): + familyIDList = [] + for cityID in self.GetCityIDList(): + city = self.GetCityWall(cityID) + if not city: + continue + familyID = city.familyID + if familyID not in familyIDList: + familyIDList.append(familyID) + return familyIDList + + def AddGroupFamily(self, familyID): + ## 将仙盟分配到该分组 + zone = GetFamilyGCZMgr().GetActZone(self.zoneID) + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + return + joinFamily.batType = self.batType + joinFamily.groupNum = self.groupNum + for playerID in joinFamily.joinMemberIDList: + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + joinMember.batType = self.batType + joinMember.groupNum = self.groupNum + + joinFamily.cityWall.batType = self.batType + joinFamily.cityWall.groupNum = self.groupNum + cityID = joinFamily.cityWall.cityID + self.cityWallDict[cityID] = joinFamily.cityWall + if cityID not in self.__cityIDList: + self.__cityIDList.append(cityID) + return joinFamily + + def CreateCityWall(self, cityID, cityLV, guardMemIDList=None, guardNPCCount=0, isAttrLock=False): + '''创建自定义城池,如修罗城 + @param cityID: 自定义城池ID + @param cityLV: 城池等级 + @param guardMemIDList: 布防玩家ID列表 + @param guardNPCCount: 布防系统NPC数量 + 城池总属性: (布防的玩家 + 布防系统NPC)属性总和 + ''' + guardNPCCount = min(guardNPCCount, 100) + newCity = FamilyGCZCityWall(self.zoneID, cityID, cityLV) + newCity.batType = self.batType + newCity.groupNum = self.groupNum + newCity.ResetDefense(cityLV, guardNPCCount=guardNPCCount) + if isAttrLock: + newCity.attrLock = 1 + self.cityWallDict[cityID] = newCity + if cityID not in self.__cityIDList: + self.__cityIDList.append(cityID) + return newCity + + def SetPlayerInScene(self, playerID, serverGroupID): + if playerID in self.inBatScenePlayerIDList: + return + self.inBatScenePlayerIDList.append(playerID) + Sync_FamilyGCZBatSceneInfo(self.zoneID, self.batType, self.groupNum, toPlayerServerDict={playerID:serverGroupID}) + return + + def SetPlayerOutScene(self, playerID): + if playerID in self.inBatScenePlayerIDList: + self.inBatScenePlayerIDList.remove(playerID) + return + +class FamilyGCZZone(): + ## 攻城战分区 + + def __init__(self, zoneID): + self.zoneID = zoneID + self.joinFamilyCnt = 0 + self.lockFamilyIDList = [] # 锁定的仙盟ID列表 + self.joinFamilyDict = {} # 参与仙盟对象信息 {familyID:FamilyGCZFamily, ...} + self.joinMemberDict = {} # 参与玩家对象信息 {playerID:FamilyGCZMember, ...} + self.roundGroupDict = {} # 当前轮次分组信息 {batType:{groupNum:FamilyGCZBatGroup, ...}, ...} + self.familyGuessDict = {} # 仙盟竞猜热度信息 {familyID:value, ...} + self.playerGuessDict = {} # 玩家竞猜记录 {playerID:[familyID, ...], ...} + + self.statGuessRetDict = None # 统计竞猜结果 {awardID:[猜中玩家ID, ...], ...} + self.guessFinalFamilyIDList = [] # 竞猜最终排名仙盟ID列表 + self.inBatScenePlayerIDDict = {} # 在战斗场景中的玩家ID {(batType, groupNum):[playerID, ...], ...} + self.inBatCityPlayerIDDict = {} # 在战斗城池中的玩家ID {(batType, groupNum, cityID):[playerID, ...], ...} + return + + def OnRoundReset(self): + ## 分区轮次重置 + self.roundGroupDict = {} + self.inBatScenePlayerIDDict = {} + self.inBatCityPlayerIDDict = {} + for familyID in self.lockFamilyIDList: + joinFamily = self.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + joinFamily.OnRoundFamilyReset() + return + + def OnRoundFightStart(self): + ## 分区轮次开始 + for familyID in self.lockFamilyIDList: + joinFamily = self.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + joinFamily.OnRoundFamilyFightStart() + return + + def AddBatGroup(self, batType, groupNum): + if batType not in self.roundGroupDict: + self.roundGroupDict[batType] = {} + groupNumDict = self.roundGroupDict[batType] + batGroup = FamilyGCZBatGroup(self.zoneID, batType, groupNum) + groupNumDict[groupNum] = batGroup + return batGroup + + def GetBatGroup(self, batType, groupNum): + ## 获取某个分组,可能为None + if batType not in self.roundGroupDict: + self.roundGroupDict[batType] = {} + groupNumDict = self.roundGroupDict[batType] + batGroup = groupNumDict.get(groupNum, None) + if batGroup == None and False: # 不可能执行,提示代码用 + batGroup = FamilyGCZBatGroup() + return batGroup + + ## 获取本分区参与的仙盟ID列表,按锁定顺序的 + def GetZoneLockFamilyIDList(self): return self.lockFamilyIDList + def GetZoneJoinFamily(self, familyID): + ## 获取本分区参与的仙盟,可能为None + joinFamily = None + if familyID in self.joinFamilyDict: + joinFamily = self.joinFamilyDict[familyID] + elif False: # 不可能执行,提示代码用 + joinFamily = FamilyGCZFamily() + return joinFamily + + def AddZoneJoinFamily(self, familyID): + ## 添加参与仙盟 + joinFamily = None + if familyID in self.joinFamilyDict: + joinFamily = self.joinFamilyDict[familyID] + else: + joinFamily = FamilyGCZFamily(self.zoneID, familyID) + self.joinFamilyDict[familyID] = joinFamily + if familyID not in self.lockFamilyIDList: + self.lockFamilyIDList.append(familyID) + GetFamilyGCZMgr().SetFamilyIDZoneID(familyID, self.zoneID) + return joinFamily + + def GetZoneJoinMember(self, playerID): + ## 获取本分区参与的玩家,可能为None + joinMember = None + if playerID in self.joinMemberDict: + joinMember = self.joinMemberDict[playerID] + elif False: # 不可能执行,提示代码用 + joinMember = FamilyGCZMember() + return joinMember + + def AddZoneJoinMember(self, playerID, familyID): + ## 添加参与成员 + joinMember = None + if playerID in self.joinMemberDict: + joinMember = self.joinMemberDict[playerID] + else: + joinMember = FamilyGCZMember(self.zoneID, familyID, playerID) + self.joinMemberDict[playerID] = joinMember + GetFamilyGCZMgr().SetPlayerIDZoneID(playerID, self.zoneID) + return joinMember + + def GetOLServerGroupIDDict(self): + ## 获取本分区在线参与成员信息 + olDict = {} + for joinFamily in self.joinFamilyDict.values(): + olDict.update(joinFamily.GetOLMemServerGroupIDDict()) + return olDict + + def SetPlayerInBatScene(self, playerID, batType=0, groupNum=0, serverGroupID=0): + ## 设置玩家在某个战斗场景,参数默认0为退出 + for bType, groupDict in self.roundGroupDict.items(): + for gNum in groupDict.keys(): + batGroup = self.GetBatGroup(bType, gNum) + if not batGroup: + continue + if batType != bType or groupNum != gNum: + batGroup.SetPlayerOutScene(playerID) + else: + batGroup.SetPlayerInScene(playerID, serverGroupID) + return + + def SetPlayerInBatCity(self, playerID, batType=0, groupNum=0, cityID=0, serverGroupID=0): + ## 设置玩家在某个战斗城池,参数默认0为退出 + for bType, groupDict in self.roundGroupDict.items(): + for gNum in groupDict.keys(): + batGroup = self.GetBatGroup(bType, gNum) + if not batGroup: + continue + for cID in batGroup.GetCityIDList(): + cityWall = batGroup.GetCityWall(cID) + if not cityWall: + continue + if batType != bType or groupNum != gNum or cityID != cID: + cityWall.SetPlayerOutCity(playerID) + else: + cityWall.SetPlayerInCity(playerID, serverGroupID) + return + +class FamilyGCZMgr(): + ## 仙盟攻城战管理 + + def __init__(self): + self.zoneDict = {} # 分区信息 {zone:FamilyGCZZone, ...} + self.familyIDZoneIDDict = {} # 仙盟ID所在分区 {familyID:zoneID, ...} + self.playerIDZoneIDDict = {} # 玩家ID所在分区 {playerID:zoneID, ...} + return + + def SetFamilyIDZoneID(self, familyID, zoneID): + self.familyIDZoneIDDict[familyID] = zoneID + return + + def SetPlayerIDZoneID(self, playerID, zoneID): + self.playerIDZoneIDDict[playerID] = zoneID + return + + def ClearGCZZone(self, zoneID): + self.zoneDict.pop(zoneID, None) + for familyID, fZoneID in self.familyIDZoneIDDict.items(): + if fZoneID == zoneID: + self.familyIDZoneIDDict.pop(familyID) + for playerID, pZoneID in self.playerIDZoneIDDict.items(): + if pZoneID == zoneID: + self.playerIDZoneIDDict.pop(playerID) + return + + def GetActZone(self, zoneID): + ## 获取分区管理 + zone = None + if zoneID in self.zoneDict: + zone = self.zoneDict[zoneID] + else: + zone = FamilyGCZZone(zoneID) + self.zoneDict[zoneID] = zone + return zone + + def GetJoinFamily(self, familyID): + ## 直接获取某个参与仙盟信息 + joinFamily = None + if familyID in self.familyIDZoneIDDict: + zoneID = self.familyIDZoneIDDict[familyID] + zone = self.GetActZone(zoneID) + joinFamily = zone.GetZoneJoinFamily(familyID) + elif False: # 不可能执行,提示代码用 + joinFamily = FamilyGCZFamily() + return joinFamily + + def GetJoinFamilyByPlayerID(self, playerID): + ## 直接获取某个参与仙盟信息 - 根据成员玩家ID + joinFamily = None + if playerID in self.playerIDZoneIDDict: + zoneID = self.playerIDZoneIDDict[playerID] + zone = self.GetActZone(zoneID) + joinMember = zone.GetZoneJoinMember(playerID) + if joinMember: + joinFamily = zone.GetZoneJoinFamily(joinMember.familyID) + elif False: # 不可能执行,提示代码用 + joinFamily = FamilyGCZFamily() + return joinFamily + + def GetJoinMember(self, playerID): + ## 直接获取某个参与玩家信息 + joinMember = None + if playerID in self.playerIDZoneIDDict: + zoneID = self.playerIDZoneIDDict[playerID] + zone = self.GetActZone(zoneID) + joinMember = zone.GetZoneJoinMember(playerID) + elif False: # 不可能执行,提示代码用 + joinMember = FamilyGCZMember() + return joinMember + +def GetFamilyGCZMgr(): + mgr = PyGameData.g_familyGCZMgr + if not mgr: + mgr = FamilyGCZMgr() + PyGameData.g_familyGCZMgr = mgr + return mgr + +def OnLoadPyData(): + + if not GameWorld.IsCrossServer(): + return + + gczMgr = GetFamilyGCZMgr() + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + + recDataDict = gameRecMgr.GetGameRecDataDict(ShareDefine.Def_GameRecType_FamilyGCZMgr) + for zoneID, zoneRecDataList in recDataDict.items(): + if not zoneRecDataList: + continue + zoneRecData = zoneRecDataList[0] # 分区管理,每个分区只要一条记录 + joinFamilyCnt = zoneRecData.GetValue1() + zoneDataDict = zoneRecData.GetUserDataDict() + + gczMgr.ClearGCZZone(zoneID) + + zone = gczMgr.GetActZone(zoneID) + zone.joinFamilyCnt = joinFamilyCnt + zone.lockFamilyIDList = zoneDataDict.get("lockFamilyIDList", []) + zone.familyGuessDict = zoneDataDict.get("familyGuessDict", {}) + zone.playerGuessDict = zoneDataDict.get("playerGuessDict", {}) + GameWorld.Log("加载分区记录! zoneID=%s,joinFamilyCnt=%s,lockCnt=%s,%s" % (zoneID, zone.joinFamilyCnt, len(zone.lockFamilyIDList), zone.lockFamilyIDList)) + + familyRecList = gameRecMgr.GetGameRecDataList(ShareDefine.Def_GameRecType_FamilyGCZJoinFamily, zoneID) + for fNum, familyRecData in enumerate(familyRecList, 1): + familyID = familyRecData.GetValue1() + batType = familyRecData.GetValue2() + groupNum = familyRecData.GetValue3() + campLV = familyRecData.GetValue4() + campExp = familyRecData.GetValue5() + score = familyRecData.GetValue6() + familyDataDict = familyRecData.GetUserDataDict() + + joinFamily = zone.AddZoneJoinFamily(familyID) + joinFamily.batType = batType + joinFamily.groupNum = groupNum + joinFamily.campLV = campLV + joinFamily.campExp = campExp + joinFamily.score = score + joinFamily.familyName = familyDataDict.get("familyName", "") + joinFamily.leaderID = familyDataDict.get("leaderID", 0) + joinFamily.leaderName = familyDataDict.get("leaderName", "") + joinFamily.lv = familyDataDict.get("lv", 0) + joinFamily.emblemID = familyDataDict.get("emblemID", 0) + joinFamily.serverID = familyDataDict.get("serverID", 0) + joinFamily.fightPowerTotal = familyDataDict.get("fightPowerTotal", 0) + joinFamily.joinMemberIDList = familyDataDict.get("joinMemberIDList", []) + joinFamily.memAddCampExpInfo = familyDataDict.get("memAddCampExpInfo", {}) + + GameWorld.Log(" 加载分区仙盟 zoneID=%s,%s,familyID=%s,campLV=%s-%s,score=%s,,memAddCampExpInfo=%s" + % (zoneID, fNum, familyID, joinFamily.campLV, joinFamily.campExp, joinFamily.score, joinFamily.memAddCampExpInfo)) + + memberRecList = gameRecMgr.GetGameRecDataList(ShareDefine.Def_GameRecType_FamilyGCZJoinMember, zoneID) + for pNum, memberRecData in enumerate(memberRecList, 1): + playerID = memberRecData.GetValue1() + familyID = memberRecData.GetValue2() + batType = memberRecData.GetValue3() + groupNum = memberRecData.GetValue4() + fmLV = memberRecData.GetValue5() + playerDataDict = memberRecData.GetUserDataDict() + + joinMember = zone.AddZoneJoinMember(playerID, familyID) + joinMember.batType = batType + joinMember.groupNum = groupNum + joinMember.fmLV = fmLV + joinMember.playerName = playerDataDict.get("playerName", "") + joinMember.job = playerDataDict.get("job", 1) + joinMember.realmLV = playerDataDict.get("realmLV", 1) + joinMember.face = playerDataDict.get("face", 0) + joinMember.facePic = playerDataDict.get("facePic", 0) + joinMember.lv = playerDataDict.get("lv", 1) + joinMember.totalHurtValue = playerDataDict.get("totalHurtValue", 0) + joinMember.awardState = playerDataDict.get("awardState", 0) + joinMember.hp = playerDataDict.get("hp", 0) + joinMember.hpMax = playerDataDict.get("hpMax", 0) + joinMember.hpBase = playerDataDict.get("hpBase", 0) + joinMember.fightPower = playerDataDict.get("fightPower", 0) + + GameWorld.Log(" 加载分区成员 zoneID=%s,familyID=%s,%s,playerID=%s,hp=%s/%s,totalHurtValue=%s" + % (zoneID, familyID, pNum, playerID, joinMember.hp, joinMember.hpMax, joinMember.totalHurtValue)) + + cityWallRecList = gameRecMgr.GetGameRecDataList(ShareDefine.Def_GameRecType_FamilyGCZCityWall, zoneID) + for cNum, cityRecData in enumerate(cityWallRecList, 1): + cityID = cityRecData.GetValue1() + batType = cityRecData.GetValue2() + groupNum = cityRecData.GetValue3() + cityLV = cityRecData.GetValue4() + familyID = cityRecData.GetValue5() + attrLock = cityRecData.GetValue6() + cityDataDict = cityRecData.GetUserDataDict() + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + batGroup = zone.AddBatGroup(batType, groupNum) + if not batGroup: + continue + if familyID: + batGroup.AddGroupFamily(familyID) + else: + batGroup.CreateCityWall(cityID, cityLV) + + city = batGroup.GetCityWall(cityID) + if not city: + continue + + city.cityLV = cityLV + city.attrLock = attrLock + city.guardMemIDList = cityDataDict.get("guardMemIDList", []) + city.fighterIDList = cityDataDict.get("fighterIDList", []) + city.guardNPCCount = cityDataDict.get("guardNPCCount", 0) + city.hp = cityDataDict.get("hp", 0) + city.hpMax = cityDataDict.get("hpMax", 0) + city.hpBase = cityDataDict.get("hpBase", 0) + city.fightPowerTotal = cityDataDict.get("fightPowerTotal", 0) + city.atkReportDict = cityDataDict.get("atkReportDict", {}) + city.fighterHurtDict = cityDataDict.get("fighterHurtDict", {}) + + GameWorld.Log(" 加载分区城池 zoneID=%s,batType=%s,batType=%s,%s,cityID=%s,familyID=%s,hp=%s/%s,fighterIDList=%s,%s" + % (zoneID, batType, groupNum, cNum, cityID, city.familyID, city.hp, city.hpMax, len(city.fighterIDList), city.fighterIDList)) + + return + +def OnSavePyData(): + if not GameWorld.IsCrossServer(): + return + + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + gameRecMgr.DelGameRecDataByType(ShareDefine.Def_GameRecType_FamilyGCZMgr) + gameRecMgr.DelGameRecDataByType(ShareDefine.Def_GameRecType_FamilyGCZJoinFamily) + gameRecMgr.DelGameRecDataByType(ShareDefine.Def_GameRecType_FamilyGCZJoinMember) + gameRecMgr.DelGameRecDataByType(ShareDefine.Def_GameRecType_FamilyGCZCityWall) + + gczMgr = GetFamilyGCZMgr() + zoneIDList = gczMgr.zoneDict.keys() + GameWorld.Log("保存仙盟攻城战分区记录! zoneIDList=%s" % zoneIDList) + for zoneID in zoneIDList: + if not zoneID: + continue + zone = gczMgr.GetActZone(zoneID) + zoneRecData = gameRecMgr.AddGameRecData(ShareDefine.Def_GameRecType_FamilyGCZMgr, zoneID) + zoneRecData.SetValue1(zone.joinFamilyCnt) + lockFamilyIDList = zone.GetZoneLockFamilyIDList() + zoneData = {"lockFamilyIDList":lockFamilyIDList, "familyGuessDict":zone.familyGuessDict, "playerGuessDict":zone.playerGuessDict} + zoneRecData.SetUserData(zoneData) + + GameWorld.Log("----- zoneID=%s,joinFamilyCnt=%s,lockFamilyIDList=%s,%s" % (zoneID, zone.joinFamilyCnt, len(lockFamilyIDList), lockFamilyIDList)) + + for batType, groupDict in zone.roundGroupDict.items(): + for groupNum in groupDict.keys(): + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + continue + cityIDList = batGroup.GetCityIDList() + for cNum, cityID in enumerate(cityIDList, 1): + city = batGroup.GetCityWall(cityID) + if not city: + continue + cityRecData = gameRecMgr.AddGameRecData(ShareDefine.Def_GameRecType_FamilyGCZCityWall, zoneID) + cityRecData.SetValue1(cityID) + cityRecData.SetValue2(city.batType) + cityRecData.SetValue3(city.groupNum) + cityRecData.SetValue4(city.cityLV) + cityRecData.SetValue5(city.familyID) + cityRecData.SetValue6(city.attrLock) + cityData = {"guardMemIDList":city.guardMemIDList, "fighterIDList":city.fighterIDList, "guardNPCCount":city.guardNPCCount, + "hp":city.hp, "hpMax":city.hpMax, "hpBase":city.hpBase, "fightPowerTotal":city.fightPowerTotal, + "atkReportDict":city.atkReportDict, "defReportDict":city.defReportDict, "fighterHurtDict":city.fighterHurtDict} + cityRecData.SetUserData(cityData) + GameWorld.Log(" 保存分区城池 zoneID=%s,batType=%s,groupNum=%s,%s,cityID=%s,familyID=%s,attrLock=%s,hp=%s/%s,fighterIDList=%s,%s" + % (zoneID, batType, groupNum, cNum, cityID, city.familyID, city.attrLock, city.hp, city.hpMax, len(city.fighterIDList), city.fighterIDList)) + + for fNum, familyID in enumerate(lockFamilyIDList, 1): + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + familyRecData = gameRecMgr.AddGameRecData(ShareDefine.Def_GameRecType_FamilyGCZJoinFamily, zoneID) + familyRecData.SetValue1(familyID) + familyRecData.SetValue2(joinFamily.batType) + familyRecData.SetValue3(joinFamily.groupNum) + familyRecData.SetValue4(joinFamily.campLV) + familyRecData.SetValue5(joinFamily.campExp) + familyRecData.SetValue6(joinFamily.score) + + familyData = {"familyName":joinFamily.familyName, "leaderID":joinFamily.leaderID, "leaderName":joinFamily.leaderName, + "lv":joinFamily.lv, "emblemID":joinFamily.emblemID, "serverID":joinFamily.serverID, "fightPowerTotal":joinFamily.fightPowerTotal, + "joinMemberIDList":joinFamily.joinMemberIDList, "memAddCampExpInfo":joinFamily.memAddCampExpInfo + } + familyRecData.SetUserData(familyData) + GameWorld.Log(" 保存分区仙盟 zoneID=%s,%s,familyID=%s,campLV=%s-%s,score=%s," % (zoneID, fNum, familyID, joinFamily.campLV, joinFamily.campExp, joinFamily.score)) + + for pNum, playerID in enumerate(joinFamily.joinMemberIDList, 1): + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + memberRecData = gameRecMgr.AddGameRecData(ShareDefine.Def_GameRecType_FamilyGCZJoinMember, zoneID) + memberRecData.SetValue1(playerID) + memberRecData.SetValue2(familyID) + memberRecData.SetValue3(joinMember.batType) + memberRecData.SetValue4(joinMember.groupNum) + memberRecData.SetValue5(joinMember.fmLV) + + memberData = {"playerName":joinMember.playerName, "job":joinMember.job, "realmLV":joinMember.realmLV, + "face":joinMember.face, "facePic":joinMember.facePic, "lv":joinMember.lv, "totalHurtValue":joinMember.totalHurtValue, + "awardState":joinMember.awardState, + "hp":joinMember.hp, "hpMax":joinMember.hpMax, "hpBase":joinMember.hpBase, "fightPower":joinMember.fightPower} + memberRecData.SetUserData(memberData) + GameWorld.Log(" 保存分区成员 zoneID=%s,familyID=%s,%s,playerID=%s,hp=%s/%s,totalHurtValue=%s" + % (zoneID, familyID, pNum, playerID, joinMember.hp, joinMember.hpMax, joinMember.totalHurtValue)) + + return + +def OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID): + ## 本服登录时跨服服务器需要处理的逻辑 + + zoneID, familyID = GetPlayerActJoinInfo(playerID) + if not zoneID: + return + + Sync_FamilyGCZActInfo(zoneID, playerID) + Sync_FamilyGCZBatGroupInfo(zoneID, {playerID:serverGroupID}) + Sync_FamilyGCZCampInfo(zoneID, familyID, {playerID:serverGroupID}) + Sync_FamilyGCZGuessInfo(zoneID, playerID, playerID) + return + +def GetRoundState(state): + ## 获取轮次、状态信息 + if state < 10 or state == FamilyGCZState_Award: + return 0, state + return state / 10, state % 10 + +def OnCrossActIDChange(cfgID, zoneID, ipyData, state): + ## 跨服活动ID变更 + DoMailReissueAward(zoneID, ipyData) + DelFamilyGCZZone(zoneID) + return + +def DelFamilyGCZZone(zoneID): + # 清空活动相关数据 + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + gameRecMgr.DelGameRecDataByTypeID(ShareDefine.Def_GameRecType_FamilyGCZMgr, zoneID) + gameRecMgr.DelGameRecDataByTypeID(ShareDefine.Def_GameRecType_FamilyGCZJoinFamily, zoneID) + gameRecMgr.DelGameRecDataByTypeID(ShareDefine.Def_GameRecType_FamilyGCZJoinMember, zoneID) + gameRecMgr.DelGameRecDataByTypeID(ShareDefine.Def_GameRecType_FamilyGCZCityWall, zoneID) + + # 清空活动相关榜单 + billboardMgr = PyDataManager.GetCrossBillboardManager() + billboardMgr.ClearBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID) + billboardMgr.ClearBillboard(ShareDefine.Def_CBT_FamilyGCZPlayerHurt, zoneID) + billboardMgr.ClearBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, zoneID) + + GetFamilyGCZMgr().ClearGCZZone(zoneID) + return + +def OnCrossActStateChange(ipyData, actID, dbState, state): + ## 跨服活动状态变更 + + zoneID = ipyData.GetZoneID() + if CrossActionControl.IsActFlowStateError(ShareDefine.CrossActName_FamilyGCZ, zoneID): + Sync_FamilyGCZActInfo(zoneID) + return + + if state == FamilyGCZState_Publicity: + Sync_FamilyGCZActInfo(zoneID) + return + + if state == FamilyGCZState_Award: + DoStartAward(zoneID) + return + + curRound, roundState = GetRoundState(state) + if curRound > 0: + # 分组 + if roundState == FamilyGCZRoundState_Group: + if curRound == 1: # 第一轮分组前锁定名单 + DoLockActFamily(actID, ipyData) + DoRoundGroup(curRound, zoneID, ipyData.GetJoinFamilyCnt()) + + # 开始战斗 + elif roundState == FamilyGCZRoundState_Fight: + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + zone.OnRoundFightStart() + + # 结算 + elif roundState == FamilyGCZRoundState_Over: + DoRoundOver(curRound, zoneID) + + else: + pass + + # 竞猜 + DoGenerateGuess(zoneID, state) + return + +def GetPlayerActJoinInfo(playerID): + '''获取玩家参与的活动信息,如果返回的有分区ID及活动ID,代表一定是活动中的 + 必须是zoneID、actID都一直才能视为同一个活动,且actState非0 + @return: [zoneID, familyID] + ''' + + zoneID, familyID = 0, 0 + defaultRet = (zoneID, familyID) + + gczMgr = GetFamilyGCZMgr() + joinMember = gczMgr.GetJoinMember(playerID) + # 有在参赛资格名单里 + if joinMember: + zoneID, familyID = joinMember.zoneID, joinMember.familyID + return zoneID, familyID + + # 注: 公示期期间也是没有在资格里的,没有参与资格的,暂时都视为普通成员 + # 没有在活动中参与资格里的,再按所在服ID判断资格: 当前所在盟服ID > 玩家所在服ID + # + # 参与资格的相关跨服活动本身具有一定的数据延迟容错空间,逻辑统一由跨服服务器处理 + # 故没有在锁定资格里的玩家可能存在以下情况 + # 1. 没有跨服查看缓存,一般为未达到跨服条件的号或已流失7天的号,可视为不参与活动 + # 2. 玩家缓存中的仙盟ID在跨服服务器还在,但子服已经解散了,一样还是用的缓存中的仙盟ID,因为活动本身具有一定的时间差容错空间,所以不影响 + cacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(playerID)) + if not cacheDict: + return defaultRet + + joinServerID = 0 + familyIDNow = cacheDict.get("FamilyID", 0) + if familyIDNow: + curFamily = GameWorld.GetFamilyManager().FindFamily(familyIDNow) + if curFamily: + familyID = familyIDNow + joinServerID = curFamily.GetServerID() + + if not joinServerID: + joinServerID = GameWorld.GetAccIDServerID(cacheDict.get("AccID", "")) + + actInfo = CrossActionControl.GetCrossActInfoByServerGroupID(ShareDefine.CrossActName_FamilyGCZ, joinServerID) + if not actInfo or not actInfo.get(ShareDefine.ActKey_State): + # 非活动中直接返回 + return defaultRet + ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo) + if ipyDataInfo: + zoneID = ipyDataInfo.get("ZoneID", 0) + return zoneID, familyID + +def OnCrossJoinFamilyMemberUpd(curFamily, updMemIDList): + ## 本活动只更新参与活动成员战力,换仙盟的成员不更新了,以最后一次更新为准 + if not curFamily: + return + + familyID = curFamily.GetID() + gczMgr = GetFamilyGCZMgr() + joinFamily = gczMgr.GetJoinFamily(familyID) + if not joinFamily: + # 非锁定的仙盟不更新,可能没有参与资格或未锁定 + return + zoneID = joinFamily.zoneID + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + # 非活动中不更新 + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + curRound, roundState = GetRoundState(state) + GameWorld.DebugLog("更新仙盟攻城战仙盟成员: familyID=%s,zoneID=%s,state=%s,curRound=%s,roundState=%s" + % (familyID, zoneID, state, curRound, roundState)) + + zone = gczMgr.GetActZone(zoneID) + for playerID in updMemIDList: + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + curMember = curFamily.FindMember(playerID) + if not curMember: + continue + joinMember.fightPower = max(joinMember.fightPower, PlayerFamily.GetMemberFightPower(curMember)) # 以较大战力为准 + GameWorld.DebugLog(" playerID=%s,joinFamilyID=%s,updFightPower=%s" % (playerID, joinMember.familyID, joinMember.fightPower)) + + return + +def DoLockActFamily(actID, ipyData): + ## 锁定参与仙盟名单 + + zoneID = ipyData.GetZoneID() + serverIDList = ipyData.GetServerIDRangeList() + joinFamilyCnt = ipyData.GetJoinFamilyCnt() + GameWorld.Log("仙盟攻城战锁定参与仙盟名单: zoneID=%s,serverIDList=%s,joinFamilyCnt=%s" % (zoneID, serverIDList, joinFamilyCnt)) + sortFamilyList = PlayerFamily.SortCrossFamily(serverIDList, joinFamilyCnt)[0] + + DelFamilyGCZZone(zoneID) + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + zone.joinFamilyCnt = joinFamilyCnt + + for num, family in enumerate(sortFamilyList, 1): + familyID = family.GetID() + serverID = family.GetServerID() + + joinFamily = zone.AddZoneJoinFamily(familyID) + familyBaseInfo = PlayerFamily.GetCrossFamilyBaseInfo(family) + joinFamily.familyName = familyBaseInfo.get("Name", "") + joinFamily.lv = familyBaseInfo.get("LV", 0) + joinFamily.leaderID = familyBaseInfo.get("LeaderID", 0) + joinFamily.leaderName = familyBaseInfo.get("LeaderName", "") + joinFamily.emblemID = familyBaseInfo.get("EmblemID", 0) + joinFamily.serverID = familyBaseInfo.get("ServerID", 0) + joinFamily.fightPowerTotal = familyBaseInfo.get("FightPower", 0) + joinFamily.campLV = 1 + fightPowerTotal = joinFamily.fightPowerTotal + + for i in range(0, family.GetCount()): + member = family.GetAt(i) + playerID = member.GetPlayerID() + if not playerID: + continue + + memBaseInfo = PlayerFamily.GetCrossFamilyMemInfo(member) + joinMember = zone.AddZoneJoinMember(playerID, familyID) + joinMember.playerName = memBaseInfo.get("Name", "") + joinMember.lv = memBaseInfo.get("LV", 0) + joinMember.job = memBaseInfo.get("Job", 0) + joinMember.realmLV = memBaseInfo.get("OfficialRank", 0) + joinMember.face = memBaseInfo.get("Face", 0) + joinMember.facePic = memBaseInfo.get("FacePic", 0) + joinMember.fightPower = memBaseInfo.get("FightPower", 0) + joinMember.fmLV = memBaseInfo.get("FamilyLV", 0) + + joinFamily.joinMemberIDList.append(playerID) + + GameWorld.Log(" %s,familyID=%s,serverID=%s,fightPowerTotal=%s,memCnt=%s,%s" + % (num, familyID, serverID, fightPowerTotal, len(joinFamily.joinMemberIDList), joinFamily.joinMemberIDList)) + + Sync_FamilyGCZActInfo(zoneID) + return + +def DoRoundGroup(curRound, zoneID, joinFamilyCnt): + ## 执行轮次分组 + + GameWorld.Log("========== 仙盟攻城战轮次分组: zoneID=%s,curRound=%s,joinFamilyCnt=%s" % (zoneID, curRound, joinFamilyCnt)) + # 参与仙盟数对应分组及晋级规则 {参与仙盟数:{轮次:{战场类型:[组数, 前x名晋级, x名开始降级], ...}, ...}, ...} + FamilyGCZGroupSet = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGroupSet", 1, {}) + if joinFamilyCnt not in FamilyGCZGroupSet: + return + roundSetDict = FamilyGCZGroupSet[joinFamilyCnt] + if curRound not in roundSetDict: + return + batTypeDict = roundSetDict[curRound] + + groupValue1 = zoneID + billboardMgr = PyDataManager.GetCrossBillboardManager() + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + + # 先处理上一轮晋级、保级、降级,需在重置前处理 + nextBatTypeFamilyInfo = {} # 下一轮战场仙盟ID分配信息 {batType:[familyID, ...], ....} + preRound = curRound - 1 + preBatTypeDict = roundSetDict.get(preRound, {}) + for batType in BatTypeList: # 按战场类型顺序遍历处理 + if batType not in zone.roundGroupDict: + continue + groupDict = zone.roundGroupDict[batType] + groupNumList = groupDict.keys() + groupNumList.sort() + preRoundSet = preBatTypeDict.get(batType, [0, 0]) + upRank = preRoundSet[1] # 前x晋级 + downRank = preRoundSet[2] if len(preRoundSet) > 2 else 0 # 大于等于x名降级,为0时不降级 + GameWorld.Log("上轮战场类型分组: preRound=%s,batType=%s,upRank=%s,downRank=%s,%s" % (preRound, batType, upRank, downRank, groupNumList)) + for groupNum in groupNumList: + groupValue2 = GetRoundHurtGroupID(batType, groupNum) + billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, groupValue1, groupValue2) + billboardObj.SortData() + upFamilyIDList, keepFamilyIDList, downFamilyIDList = [], [], [] + for bIndex in range(billboardObj.GetCount()): + billData = billboardObj.At(bIndex) + familyID = billData.ID + rank = bIndex + 1 + if rank <= upRank: + nextBatType = min(BatType_High, batType + 1) + upFamilyIDList.append(familyID) + elif downRank and rank >= downRank: + nextBatType = max(BatType_Junior, batType - 1) + downFamilyIDList.append(familyID) + # 除了升降级的就是保级 + else: + nextBatType = batType + keepFamilyIDList.append(familyID) + + if nextBatType not in nextBatTypeFamilyInfo: + nextBatTypeFamilyInfo[nextBatType] = [] + familyIDList = nextBatTypeFamilyInfo[nextBatType] + if familyID not in familyIDList: + familyIDList.append(familyID) + GameWorld.Log(" 升保降级zoneID=%s,batType=%s,groupNum=%s,up:%s,keep:%s,down:%s,%s" + % (zoneID, batType, groupNum, upFamilyIDList, keepFamilyIDList, downFamilyIDList, nextBatTypeFamilyInfo)) + + #每轮重新分组时,重置该分区下的轮次伤害相关榜单 + billboardMgr.ClearBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, groupValue1) + zone.OnRoundReset() + + for batType in BatTypeList: # 按战场类型顺序遍历处理 + if batType not in batTypeDict: + # 本轮不需要此战场类型分组 + continue + groupCnt = batTypeDict[batType][0] # 本轮该战场类型分组 + if not groupCnt: + GameWorld.Log("本轮战场不需要分组: zoneID=%s,curRound=%s,batType=%s" % (zoneID, curRound, batType)) + continue + + batFamilyIDList = [] # 该战场的仙盟ID列表 + if curRound == 1: + # 首轮分组默认取锁定名单 + batFamilyIDList = zone.GetZoneLockFamilyIDList() + GameWorld.Log("首轮战场分组直接取分区锁定仙盟名单: zoneID=%s,curRound=%s,batType=%s,%s,%s" % (zoneID, curRound, batType, len(batFamilyIDList), batFamilyIDList)) + + # 上一轮该战场类型有比赛的 + elif batType in nextBatTypeFamilyInfo: + batFamilyIDList = nextBatTypeFamilyInfo[batType] + GameWorld.Log("非首轮分组直接取上轮晋保降仙盟名单: zoneID=%s,curRound=%s,batType=%s,%s,%s" % (zoneID, curRound, batType, len(batFamilyIDList), batFamilyIDList)) + + else: + GameWorld.ErrLog("本轮分组可能没有仙盟名单: zoneID=%s,curRound=%s,batType=%s,%s,%s" % (zoneID, curRound, batType, len(batFamilyIDList), batFamilyIDList)) + + # 生成空分组,确保即使没有仙盟也有对应分组 + for groupNum in range(1, 1 + groupCnt): + zone.AddBatGroup(batType, groupNum) + + # 先按分组规则排序 + groupFamilyDict = {} + groupFamilySortList = [] + for familyID in batFamilyIDList: + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + groupFamilySortList.append(joinFamily) + groupFamilyDict[familyID] = [joinFamily.fightPowerTotal, joinFamily.score] + + # 先按总战力倒序,可扩展积分等 + groupFamilySortList.sort(key=lambda f: (f.fightPowerTotal, f.score), reverse=True) + groupFamilyIDSortList = [f.familyID for f in groupFamilySortList] + + GameWorld.Log("开始分组按排序后的顺序循环插入每组! 仙盟数:%s, %s, %s" % (len(groupFamilyIDSortList), groupFamilyIDSortList, groupFamilyDict)) + + groupNum = 0 + for familyID in groupFamilyIDSortList: + groupNum += 1 + if groupNum > groupCnt: + groupNum = 1 + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + GameWorld.ErrLog("仙盟分组时战斗分组不存在! zoneID=%s,batType=%s,groupNum=%s,familyID=%s" % (zoneID, batType, groupNum, familyID)) + continue + joinFamily = batGroup.AddGroupFamily(familyID) + if not joinFamily: + GameWorld.ErrLog("仙盟分配到战斗分组失败! zoneID=%s,batType=%s,groupNum=%s,familyID=%s" % (zoneID, batType, groupNum, familyID)) + continue + UndFamilyRoundHurtBillboard(joinFamily) + GameWorld.Log(" 仙盟ID分组: zoneID=%s,curRound=%s,batType=%s,groupNum=%s,familyID=%s,%s" % (zoneID, curRound, batType, groupNum, familyID, groupFamilyDict[familyID])) + + Sync_FamilyGCZBatGroupInfo(zoneID) + return + +def UndFamilyRoundHurtBillboard(joinFamily): + ## 更新仙盟轮次伤害榜单 + if not joinFamily: + return + dataID = joinFamily.familyID + name1 = joinFamily.familyName + id2 = joinFamily.leaderID + name2 = joinFamily.leaderName + type2, value1, value2 = 0, 0, 0 + value3 = joinFamily.emblemID + value5 = joinFamily.serverID + groupValue1 = joinFamily.zoneID + groupValue2 = GetRoundHurtGroupID(joinFamily.batType, joinFamily.groupNum) + roundTotalHurt = sum(joinFamily.cityWall.fighterHurtDict.values()) + cmpValue = roundTotalHurt / ChConfig.Def_PerPointValue + cmpValue2 = roundTotalHurt % ChConfig.Def_PerPointValue + CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, groupValue1, dataID, name1, name2, type2, value1, value2, + cmpValue, cmpValue2, groupValue2=groupValue2, id2=id2, autoSort=True, value3=value3, value5=value5) + return + +def DoRoundOver(curRound, zoneID): + ## 执行轮次结算 + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + billboardMgr = PyDataManager.GetCrossBillboardManager() + batTypeScoreInfo = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGroupSet", 2, {}) + GameWorld.Log("========== 仙盟攻城战轮次结算: zoneID=%s,curRound=%s" % (zoneID, curRound)) + for batType, groupDict in zone.roundGroupDict.items(): + rankScoreInfo = batTypeScoreInfo.get(str(batType), {}) + if not rankScoreInfo: + GameWorld.ErrLog("仙盟攻城战战场类型没有配置名次积分! batType=%s" % batType) + rankScoreDict = {int(k):v for k, v in rankScoreInfo.items()} + groupNumList = groupDict.keys() + GameWorld.Log("zoneID=%s,batType=%s,groupCnt=%s,rankScoreDict=%s" % (zoneID, batType, len(groupNumList), rankScoreDict)) + for groupNum in groupNumList: + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + continue + + groupValue2 = GetRoundHurtGroupID(batType, groupNum) + billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, zoneID, groupValue2) + billboardObj.SortData() + GameWorld.Log("zoneID=%s,batType=%s,groupNum=%s,roundHurtFamilyCnt=%s" % (zoneID, batType, groupNum, billboardObj.GetCount())) + for bIndex in range(billboardObj.GetCount()): + billData = billboardObj.At(bIndex) + familyID = billData.ID + hurtValue = billData.CmpValue + hurtValueEx = billData.CmpValue2 + hurtValueTotal = hurtValue * ChConfig.Def_PerPointValue + hurtValueEx + rank = bIndex + 1 + addScore = GameWorld.GetOrderValueByDict(rankScoreDict, rank, False, 0) + + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + joinFamily.score += addScore + GameWorld.Log(" zoneID=%s,batType=%s,groupNum=%s,rank=%s,familyID=%s,addScore=%s,updScore=%s,hurtValueTotal=%s" + % (zoneID, batType, groupNum, rank, familyID, addScore, joinFamily.score, hurtValueTotal)) + + dataID = joinFamily.familyID + name1 = joinFamily.familyName + id2 = joinFamily.leaderID + name2 = joinFamily.leaderName + type2, value1, value2 = 0, 0, 0 + value3 = joinFamily.emblemID + value5 = joinFamily.serverID + cmpValue = joinFamily.score + CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID, dataID, name1, name2, type2, value1, value2, + cmpValue, id2=id2, autoSort=False, value3=value3, value5=value5) + + # 都加完积分后统一排序 + familyScoreBillObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID) + familyScoreBillObj.SortData() + + playerHurtBillObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZPlayerHurt, zoneID) + playerHurtBillObj.SortData() + return + +def DoGenerateGuess(zoneID, state): + ## 生成竞猜数据 + if state not in IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGuess", 1): + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + + guessRankMax = IpyGameDataPY.GetFuncCfg("FamilyGCZGuess", 2) + billboardMgr = PyDataManager.GetCrossBillboardManager() + scoreBillObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID) + for index in range(guessRankMax): + billData = scoreBillObj.At(index) + familyID = billData.ID + if familyID not in zone.familyGuessDict: + zone.familyGuessDict[familyID] = 0 + GameWorld.Log("仙盟攻城战生成竞猜备选名单: zoneID=%s,index=%s,familyID=%s" % (zoneID, index, familyID)) + + Sync_FamilyGCZGuessInfo(zoneID) + return + +def DoStartAward(zoneID): + ## 开始领奖 + + # 下发竞猜统计结果 + Sync_FamilyGCZGuessInfo(zoneID) + return + +def GetRoundHurtGroupID(batType, groupNum): return batType * 100 + groupNum +def GetRoundHurtGroupIDInfo(groupValue2): + batType = groupValue2 / 100 + groupNum = groupValue2 % 100 + return batType, groupNum + +def Send_CrossServerMsg_FamilyGCZ(actMsgType, msgInfo, serverGroupIDList=None): + msgInfo["ActMsgType"] = actMsgType + CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FamilyGCZ, msgInfo, serverGroupIDList) + return + +#def GetMaxRound(joinFamilyCnt): +# ## 获取最大轮次 +# FamilyGCZGroupSet = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGroupSet", 1, {}) +# if joinFamilyCnt not in FamilyGCZGroupSet: +# return 0 +# roundSetDict = FamilyGCZGroupSet[joinFamilyCnt] +# if not roundSetDict: +# return 0 +# return max(roundSetDict) + +def ClientServerMsg_FamilyGCZ(serverGroupID, msgData): + ActMsgType = msgData["ActMsgType"] + + # 加经验 + if ActMsgType == "AddCampExp": + __clientServer_AddCampExp(msgData) + + elif ActMsgType == "Query": + # 查询类型:1-成员捐献值;2-进入城池场景;3-退出城池场景;4-进入城池;5-退出城池;6-战报;7-分组仙盟成员伤害 + # "ActMsgType":"Query", "playerID":playerID, "queryType":queryType, "batType":batType, "groupNum":groupNum, "familyID":familyID + queryType = msgData["queryType"] + playerID = msgData["playerID"] + batType = msgData["batType"] + groupNum = msgData["groupNum"] + tagFamilyID = msgData["familyID"] + gczMgr = GetFamilyGCZMgr() + joinMember = gczMgr.GetJoinMember(playerID) + if not joinMember: + return + zoneID = joinMember.zoneID + zone = gczMgr.GetActZone(zoneID) + + if queryType == 1: # 成员捐献值 + __clientServer_QueryContributionInfo(playerID, serverGroupID, msgData) + elif queryType == 2: # 进入城池场景 + zone.SetPlayerInBatScene(playerID, batType, groupNum, serverGroupID) + elif queryType == 3: # 退出城池场景 + zone.SetPlayerInBatScene(playerID) + elif queryType == 4: # 进入城池 + zone.SetPlayerInBatCity(playerID, batType, groupNum, tagFamilyID, serverGroupID) + elif queryType == 5: # 退出城池 + zone.SetPlayerInBatCity(playerID) + elif queryType == 6: # 战报 + repFamilyID = tagFamilyID if tagFamilyID else joinMember.familyID + __clientServer_QueryBatReport(playerID, serverGroupID, repFamilyID) + elif queryType == 7: # 分组仙盟成员伤害 + repFamilyID = tagFamilyID if tagFamilyID else joinMember.familyID + __clientServer_QueryGroupFamilyMemHurt(playerID, serverGroupID, zoneID, repFamilyID) + + elif ActMsgType == "GCZAtk": + __clientServer_Atk(serverGroupID, msgData) + + elif ActMsgType == "Guess": + __clientServer_Guess(serverGroupID, msgData) + + elif ActMsgType == "GetAward": + __clientServer_GetAward(serverGroupID, msgData) + + elif ActMsgType == "GMCMD": + __clientServer_GMCMD(serverGroupID, msgData) + + return + +def __clientServer_AddCampExp(msgData): + playerID = msgData["playerID"] + addCampExp = msgData["addCampExp"] + + gczMgr = GetFamilyGCZMgr() + joinMember = gczMgr.GetJoinMember(playerID) + if not joinMember: + GameWorld.ErrLog("非仙盟攻城战参赛成员无法加经验!", playerID) + return + familyID = joinMember.familyID + joinFamily = gczMgr.GetJoinFamily(familyID) + if not joinFamily: + GameWorld.ErrLog("非仙盟攻城战参赛仙盟无法加经验! familyID=%s" % familyID, playerID) + return + joinFamily.AddCampExp(playerID, addCampExp) + return + +def __clientServer_GMCMD(serverGroupID, msgData): + ''' GM命令,方便开发测试用 + ''' + playerID = msgData["playerID"] + msgList = msgData["msgList"] + + gczMgr = GetFamilyGCZMgr() + joinMember = gczMgr.GetJoinMember(playerID) + if not joinMember: + GameWorld.ErrLog("非仙盟攻城战参赛成员!", playerID) + return + zoneID = joinMember.zoneID + familyID = joinMember.familyID + zone = gczMgr.GetActZone(zoneID) + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + GameWorld.ErrLog("非仙盟攻城战参赛仙盟! familyID=%s" % familyID, playerID) + return + batType, groupNum = joinMember.batType, joinMember.groupNum + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "没有战斗分组:batType-group:%s-%s" % (batType, groupNum)) + return + + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + curRound, roundState = GetRoundState(state) + + value0 = msgList[0] + if value0 in ["a", "h", "k"]: + if not curRound or (curRound and roundState != FamilyGCZRoundState_Fight): + GameWorld.DebugAnswerCross(playerID, serverGroupID, "非战斗阶段!state=%s" % (state)) + return + + #攻击城池: FamilyGCZ a 城池ID [攻击次数 仙盟ID] + if value0 == "a": + tagCityID = msgList[1] if len(msgList) > 1 else 0 + atkCntTotal = msgList[2] if len(msgList) > 2 else 1 + atkFamilyID = msgList[3] if len(msgList) > 3 else familyID + atkMemberID = 0 + if atkFamilyID == familyID: + atkJoinFamily = joinFamily + if atkCntTotal == 1: + atkMemberID = playerID + else: + atkJoinFamily = zone.GetZoneJoinFamily(atkFamilyID) + if not atkJoinFamily: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "攻击方不存在:%s" % atkFamilyID) + return + curCityID = atkJoinFamily.cityWall.cityID + tagCity = batGroup.GetCityWall(tagCityID) + if not tagCity: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "目标城池不存在:%s" % (tagCityID)) + return + atkOK = __DoGMAtkCity(playerID, serverGroupID, zoneID, curRound, batType, groupNum, curCityID, tagCityID, atkCntTotal, 0, atkMemberID) + GameWorld.DebugAnswerCross(playerID, serverGroupID, "atkOK:%s,remainHP:%s" % (atkOK, tagCity.hp)) + + #攻击城池: FamilyGCZ a 城池ID 剩余血量 [攻击方人数 仙盟ID] + elif value0 == "h": + tagCityID = msgList[1] if len(msgList) > 1 else 0 + remainHP = msgList[2] if len(msgList) > 2 else 0 + atkCntTotal = msgList[3] if len(msgList) > 3 else 0 + atkFamilyID = msgList[4] if len(msgList) > 4 else familyID + atkMemberID = 0 + if atkFamilyID == familyID: + atkJoinFamily = joinFamily + if atkCntTotal == 1: + atkMemberID = playerID + else: + atkJoinFamily = zone.GetZoneJoinFamily(atkFamilyID) + if not atkJoinFamily: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "攻击方不存在:%s" % atkFamilyID) + return + curCityID = atkJoinFamily.cityWall.cityID + tagCity = batGroup.GetCityWall(tagCityID) + if not tagCity: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "目标城池不存在:%s" % (tagCityID)) + return + if tagCity.hp <= remainHP: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "剩余血量不能超过当前血量:%s" % (tagCity.hp)) + return + hurtValueTotal = tagCity.hp - remainHP + atkOK = __DoGMAtkCity(playerID, serverGroupID, zoneID, curRound, batType, groupNum, curCityID, tagCityID, 0, hurtValueTotal, atkMemberID) + GameWorld.DebugAnswerCross(playerID, serverGroupID, "atkOK:%s,remainHP:%s" % (atkOK, tagCity.hp)) + + #击毁城池: FamilyGCZ k [城池ID 攻击方仙盟ID] + elif value0 == "k": + tagCityID = msgList[1] if len(msgList) > 1 else 0 + atkFamilyID = msgList[2] if len(msgList) > 2 else familyID + atkJoinFamily = zone.GetZoneJoinFamily(atkFamilyID) + if not atkJoinFamily: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "攻击方不存在:%s" % atkFamilyID) + return + curCityID = atkJoinFamily.cityWall.cityID + #随机一个城池击毁 + if not tagCityID: + cityIDList = batGroup.GetCityIDList() + else: + cityIDList = [tagCityID] + tagCity = None + for cityID in cityIDList[::-1]: + city = batGroup.GetCityWall(cityID) + if not city: + continue + if city.IsBroken() or cityID in [XiuluoCityID, atkFamilyID]: + continue + tagCity = city + break + if not tagCity: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "没有可击毁的城池了!") + return + tagCityID = tagCity.cityID + hurtValueTotal = tagCity.hp + atkOK = __DoGMAtkCity(playerID, serverGroupID, zoneID, curRound, batType, groupNum, curCityID, tagCityID, 0, hurtValueTotal) + GameWorld.DebugAnswerCross(playerID, serverGroupID, "killOK:%s,目标:%s,攻击方:%s" % (atkOK, tagCityID, curCityID)) + + #输出城池: FamilyGCZ p [战场类型 分组编号] + elif value0 == "p": + bType = msgList[1] if len(msgList) > 1 else batType + gNum = msgList[2] if len(msgList) > 2 else groupNum + __GMPrintGroupCity(zoneID, bType, gNum, playerID, serverGroupID) + + #山寨竞猜: FamilyGCZ g 人数 [竞猜ID1 ID2 ID3] + elif value0 == "g": + guessCnt = msgList[1] if len(msgList) > 1 else 1 + guessFamilyIDList = msgList[2:] + __DoGMGuess(zoneID, state, guessCnt, guessFamilyIDList, playerID, serverGroupID) + + #成员捐献: FamilyGCZ x 经验 [成员数] + elif value0 == "x": + addCampExp = msgList[1] if len(msgList) > 1 else 1 + memCnt = msgList[2] if len(msgList) > 2 else 1 + if memCnt > 1: + memIDList = copy.deepcopy(joinFamily.joinMemberIDList) + random.shuffle(memIDList) + playerIDList = memIDList[:memCnt] + else: + playerIDList = [playerID] + + for memID in playerIDList: + joinFamily.AddCampExp(memID, addCampExp, False) + + Sync_FamilyGCZCampInfo(joinFamily.zoneID, joinFamily.familyID) + GameWorld.DebugAnswerCross(playerID, serverGroupID, "成员捐献:人数(%s)x%s:campLV(%s),Exp(%s)" % (len(playerIDList), addCampExp, joinFamily.campLV, joinFamily.campExp)) + + #设大本营: FamilyGCZ c 等级 [经验] + elif value0 == "c": + campLV = msgList[1] if len(msgList) > 1 else joinFamily.campLV + campExp = msgList[2] if len(msgList) > 2 else joinFamily.campExp + if campLV and not IpyGameDataPY.GetIpyGameData("CrossActFamilyGCZCampLV", campLV): + GameWorld.DebugAnswerCross(playerID, serverGroupID, "大本营没有该等级:%s" % campExp) + return + joinFamily.campLV = campLV + joinFamily.campExp = campExp + GameWorld.DebugAnswerCross(playerID, serverGroupID, "设置大本营等级:%s,Exp:%s" % (campLV, campExp)) + joinFamily.RefreshFamilyAttr() + + return + +def __GMPrintGroupCity(zoneID, batType, groupNum, playerID, serverGroupID): + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + batGroup = zone.GetBatGroup(batType, groupNum) + cityIDList = batGroup.GetCityIDList() + GameWorld.DebugAnswerCross(playerID, serverGroupID, "---分区(%s)分组类型(%s)组(%s)城池数(%s)" % (zoneID, batType, groupNum, len(cityIDList))) + for cNum, cityID in enumerate(cityIDList, 1): + city = batGroup.GetCityWall(cityID) + if not city: + continue + broken = "已击毁" if city.IsBroken() else "" + GameWorld.DebugAnswerCross(playerID, serverGroupID, "城池%02d:%s,防守人员ID:%s,人数:%s/%s" + % (cNum, cityID, city.GetCurGuardID(), len(city.fighterIDList), len(city.guardMemIDList))) + GameWorld.DebugAnswerCross(playerID, serverGroupID, " HP: %s/%s %s" % (city.hp, city.hpMax, broken)) + return + +def __DoGMAtkCity(gmPlayerID, serverGroupID, zoneID, curRound, batType, groupNum, curCityID, tagCityID, atkCntTotal=0, hurtValueTotal=0, atkMemberID=0): + '''GM攻击城池 + @param curCityID: 攻击方城池ID + @param tagCityID: 防守方城池ID + @param atkCntTotal: 大于0时指定总攻击次数 + @param hurtValueTotal: 大于0时指定总伤害 + @param atkMemberID: 发起攻击的成员ID,如果为0则所有成员平摊攻击 + ''' + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + if curCityID == tagCityID: + GameWorld.DebugAnswerCross(gmPlayerID, serverGroupID, "不能攻击自己的城池") + return + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + return + curCity = batGroup.GetCityWall(curCityID) + tagCity = batGroup.GetCityWall(tagCityID) + if not curCity: + GameWorld.DebugAnswerCross(gmPlayerID, serverGroupID, "攻击方不存在:%s" % curCityID) + return + if not tagCity: + GameWorld.DebugAnswerCross(gmPlayerID, serverGroupID, "被攻击方不存在:%s" % tagCityID) + return + curFamilyID = curCity.familyID + tagFamilyID = tagCity.familyID + curJoinFamily = zone.GetZoneJoinFamily(curFamilyID) + if not curJoinFamily: + GameWorld.DebugAnswerCross(gmPlayerID, serverGroupID, "无归属仙盟城池不能发起攻击") + return + + GameWorld.DebugLog("GM攻击城池: zoneID=%s,batType=%s,groupNum=%s,curCityID=%s,tagCityID=%s,atkCntTotal=%s,hurtValueTotal=%s,atkMemberID=%s" + % (zoneID, batType, groupNum, curCityID, tagCityID, atkCntTotal, hurtValueTotal, atkMemberID)) + + remainHurtTotal = 0 + memHurtDict = {} + atkMemIDList = [atkMemberID] if (atkMemberID and atkMemberID in curJoinFamily.joinMemberIDList) else curJoinFamily.joinMemberIDList + # 按次数输出 + if atkCntTotal: + remainAtkCnt = atkCntTotal + while remainAtkCnt > 0 and atkMemIDList: + remainAtkCnt -= 1 + atkMemID = atkMemIDList.pop(0) + atkMemIDList.append(atkMemID) + atkMember = zone.GetZoneJoinMember(atkMemID) + memHurt = atkMember.fightPower + remainHurtTotal += atkMember.fightPower + memHurtDict[atkMemID] = memHurtDict.get(atkMemID, 0) + memHurt + GameWorld.DebugLog("按总次数攻击: atkCntTotal=%s,remainHurtTotal=%s,atkMem=%s,%s" % (atkCntTotal, remainHurtTotal, len(memHurtDict), memHurtDict)) + + # 按总伤害输出 + elif hurtValueTotal: + remainHurtTotal = hurtValueTotal + while hurtValueTotal > 0 and atkMemIDList: + atkMemID = atkMemIDList.pop(0) + atkMemIDList.append(atkMemID) + atkMember = zone.GetZoneJoinMember(atkMemID) + memHurt = atkMember.fightPower + hurtValueTotal -= memHurt + memHurtDict[atkMemID] = memHurtDict.get(atkMemID, 0) + memHurt + GameWorld.DebugLog("按总伤害攻击: remainHurtTotal=%s,atkMem=%s,%s" % (remainHurtTotal, len(memHurtDict), memHurtDict)) + + killCnt = 0 + curTime = int(time.time()) + atkedGuardIDList = [] # 被攻击的人员ID列表 + # GM攻击不限制防守人员击杀上限,直到伤害用完为止 + GameWorld.DebugLog("计算GM攻击城池: tagCityID=%s,cityHP=%s/%s,remainHurtTotal=%s" % (tagCityID, tagCity.hp, tagCity.hpMax, remainHurtTotal)) + while not tagCity.IsBroken() and remainHurtTotal > 0: + fighterID = tagCity.fighterIDList[0] + if tagCity.IsGuardNPC(fighterID): + tagGuard = tagCity.guardNPC + else: + tagGuard = zone.GetZoneJoinMember(fighterID) + if not tagGuard or tagGuard.IsDead(): + tagCity.NextGuard() + continue + atkedGuardIDList.append(fighterID) + tagCity.atkedTime = curTime + + hpBef = tagGuard.hp + tagGuard.hp = max(0, hpBef - remainHurtTotal) + lostHP = hpBef - tagGuard.hp # 该防守队员实际掉血 + tagCity.hp = max(0, tagCity.hp - lostHP) # 城池同步扣血 + + # 修罗城防爆 + if tagCityID == XiuluoCityID and tagCity.hp <= 0: + tagCity.hp = 1 + tagGuard.hp = 1 + lostHP = remainHurtTotal + GameWorld.Log(" GM攻击修罗城防爆: zoneID=%s,tagCityID=%s" % (zoneID, tagCityID)) + + GameWorld.DebugLog(" tagGuardID=%s,remainHurtTotal=%s,lostHP=%s,hpBef=%s/%s,hpUpd=%s,cityHP=%s" + % (fighterID, remainHurtTotal, lostHP, hpBef, tagGuard.hpMax, tagGuard.hp, tagCity.hp)) + + remainHurtTotal -= lostHP # 剩余伤害值 + + # 战报以实际掉血计算,总量为100% + curCity.atkReportDict[tagCityID] = curCity.atkReportDict.get(tagCityID, 0) + lostHP + tagCity.defReportDict[curCityID] = tagCity.defReportDict.get(curCityID, 0) + lostHP + + if tagGuard.IsDead(): + killCnt += 1 + tagCity.NextGuard() + + GameWorld.DebugLog(" remainHurtTotal=%s,killCnt=%s,atkReportDict=%s,defReportDict=%s" + % (remainHurtTotal, killCnt, curCity.atkReportDict, tagCity.defReportDict)) + + GameWorld.DebugLog("cityHP=%s/%s,atkedGuardIDList=%s" % (tagCity.hp, tagCity.hpMax, atkedGuardIDList)) + + for memID, memHurt in memHurtDict.items(): + GameWorld.DebugLog("攻击方成员输出: memID=%s,%s" % (memID, memHurt)) + joinMember = zone.GetZoneJoinMember(memID) + if not joinMember: + continue + joinMember.totalHurtValue += memHurt + cmpValue = joinMember.totalHurtValue / ChConfig.Def_PerPointValue + cmpValue2 = joinMember.totalHurtValue % ChConfig.Def_PerPointValue + CrossBillboard.UpdCrossBillboardPlayer(ShareDefine.Def_CBT_FamilyGCZPlayerHurt, memID, zoneID, cmpValue, cmpValue2, autoSort=False) + if curCity.IsBroken(): + continue + curCity.fighterHurtDict[memID] = curCity.fighterHurtDict.get(memID, 0) + memHurt + playerRoundHurtTotal = curCity.fighterHurtDict[memID] # 只算生存伤害 + _, topHurtPlayerValue = batGroup.GetTopHurtPlayerIDValue() + if playerRoundHurtTotal > topHurtPlayerValue: + batGroup.UpdTopHurtPlayerIDValue(memID, playerRoundHurtTotal) + + if not curCity.IsBroken(): + UndFamilyRoundHurtBillboard(curJoinFamily) + + if not CheckXiuluoCity(zoneID, curRound, batType, groupNum, gmPlayerID): + Sync_FamilyGCZBatSceneInfo(zoneID, batType, groupNum) + Sync_FamilyGCZBatCityInfo(zoneID, batType, groupNum, tagCityID) + if tagFamilyID: + Sync_FamilyGCZCampInfo(zoneID, tagFamilyID, defMemIDList=atkedGuardIDList) + return True + +def __clientServer_Atk(serverGroupID, msgData): + ## 攻击 + zoneID = msgData["zoneID"] + playerID = msgData["playerID"] + atkType = msgData["atkType"] # 攻击类型: 1-普通单攻;2-技能单攻;3-技能群攻; + tagCityID = msgData["tagCityID"] # 目标城池ID,一般是仙盟ID或者特殊城池ID如修罗城城池,普攻单攻需指定目标,群攻技能发0 + tagGuardID = msgData["tagGuardID"] # 目标守卫ID,一般是玩家ID或者特殊守卫ID如修罗城守卫,普攻单攻需指定目标,技能攻击发0 + hurtMulti = msgData["hurtMulti"] + #useItemID = msgData["useItemID"] + hurtFamilyCnt = msgData["hurtFamilyCnt"] + + GameWorld.DebugLog("仙盟攻城战攻击: zoneID=%s,atkType=%s,tagCityID=%s,tagGuardID=%s,hurtMulti=%s,hurtFamilyCnt=%s" + % (zoneID, atkType, tagCityID, tagGuardID, hurtMulti, hurtFamilyCnt), playerID) + + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + curRound, roundState = GetRoundState(state) + if not curRound or (curRound and roundState != FamilyGCZRoundState_Fight): + GameWorld.ErrLog("仙盟攻城战非攻击阶段: state=%s,curRound=%s,roundState=%s" % (state, curRound, roundState), playerID) + return + + gczMgr = GetFamilyGCZMgr() + joinMember = gczMgr.GetJoinMember(playerID) + if not joinMember: + GameWorld.ErrLog("非仙盟攻城战参赛成员!", playerID) + return + if zoneID != joinMember.zoneID: + GameWorld.ErrLog("非仙盟攻城战参赛成员! zoneID=%s" % joinMember.zoneID, playerID) + return + zone = gczMgr.GetActZone(zoneID) + familyID = joinMember.familyID + batType, groupNum = joinMember.batType, joinMember.groupNum + curJoinFamily = zone.GetZoneJoinFamily(familyID) + if not curJoinFamily: + GameWorld.ErrLog("非仙盟攻城战参赛仙盟! familyID=%s" % familyID, playerID) + return + curCity = curJoinFamily.cityWall + curCityID = curCity.cityID + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + GameWorld.ErrLog("仙盟攻城战分组不存在! batType=%s,groupNum=%s" % (batType, groupNum), playerID) + return + + canAtkedCityList = [] # 可被攻击的城池列表 + # 群攻技能 + if atkType == AtkType_SkillArea: + # 群攻时强制目标为0 + tagCityID, tagGuardID = 0, 0 + for tagCID in batGroup.cityWallDict.keys(): # 遍历同组城池 + if tagCID == curCityID: + #不打自己 + continue + tagCity = batGroup.GetCityWall(tagCID) + if not tagCity or tagCity.IsBroken(): + # 已被摧毁的 + continue + canAtkedCityList.append(tagCity) + if len(canAtkedCityList) > hurtFamilyCnt: + random.shuffle(canAtkedCityList) + canAtkedCityList = canAtkedCityList[:hurtFamilyCnt] + + # 单攻技能 + elif atkType == AtkType_SkillSingle: + if not tagCityID or tagCityID == curCityID: + SendFamilyGCZAtkResult(AtkRet_Other, "TagIDError-tagCityID", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + tagCity = batGroup.GetCityWall(tagCityID) + if not tagCity: + SendFamilyGCZAtkResult(AtkRet_Other, "GroupNoTagCity", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + if tagCity.IsBroken(): + SendFamilyGCZAtkResult(AtkRet_TagBroken, "TagBroken", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + tagGuardID = 0 # 单攻技能指定城池,不指定目标 + canAtkedCityList.append(tagCity) + + # 普通单攻 + else: + if not tagCityID or not tagGuardID or tagCityID == curCityID: + SendFamilyGCZAtkResult(AtkRet_Other, "TagIDError-tagCityID-GuardID", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + tagCity = batGroup.GetCityWall(tagCityID) + if not tagCity: + SendFamilyGCZAtkResult(AtkRet_Other, "GroupNoTagCity", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + if tagCity.IsBroken(): + SendFamilyGCZAtkResult(AtkRet_TagBroken, "TagBroken", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + if tagCity.GetCurGuardID() != tagGuardID: + GameWorld.DebugLog("CurGuardID=%s,fighterIDList=%s" % (tagCity.GetCurGuardID(), tagCity.fighterIDList)) + SendFamilyGCZAtkResult(AtkRet_TagDead, "TagDead", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + canAtkedCityList.append(tagCity) + + if not canAtkedCityList: + SendFamilyGCZAtkResult(AtkRet_Other, "NoAtkedTag", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + + batFightPower = joinMember.fightPower + oneHurtTotal = totalHurtValue = batFightPower * hurtMulti # 总伤害 + if len(canAtkedCityList) > 1 : + oneHurtTotal = totalHurtValue / len(canAtkedCityList) # 所有可攻击的目标仙盟平摊伤害 + GameWorld.DebugLog("batFightPower=%s,totalHurtValue=%s,oneHurtTotal=%s" % (batFightPower, totalHurtValue, oneHurtTotal), playerID) + + curTime = int(time.time()) + oneCanAtkDefMax = IpyGameDataPY.GetFuncCfg("FamilyGCZCity", 2) # 单盟最大可攻击x个防守人员 + hurtDict = {} # 最终伤血信息 + killCntTotal = 0 # 本次攻击击杀数 + + for tagCity in canAtkedCityList: + if not tagCity or tagCity.IsBroken(): + continue + killCnt = 0 + tagCityID = tagCity.cityID + remainHurtTotal = oneHurtTotal + atkedGuardIDList = [] # 被攻击的人员ID列表 + GameWorld.DebugLog("计算攻击城池: tagCityID=%s,cityHP=%s/%s,oneHurtTotal=%s,oneCanAtkDefMax=%s,fighterIDList=%s" + % (tagCityID, tagCity.hp, tagCity.hpMax, oneHurtTotal, oneCanAtkDefMax, tagCity.fighterIDList), playerID) + while not tagCity.IsBroken() and len(atkedGuardIDList) < oneCanAtkDefMax and remainHurtTotal > 0: + fighterID = tagCity.fighterIDList[0] + if tagCity.IsGuardNPC(fighterID): + tagGuard = tagCity.guardNPC + else: + tagGuard = zone.GetZoneJoinMember(fighterID) + if not tagGuard or tagGuard.IsDead(): + tagCity.NextGuard() + continue + atkedGuardIDList.append(fighterID) + tagCity.atkedTime = curTime + + hpBef = tagGuard.hp + tagGuard.hp = max(0, hpBef - remainHurtTotal) + lostHP = hpBef - tagGuard.hp # 该防守队员实际掉血 + tagCity.hp = max(0, tagCity.hp - lostHP) # 城池同步扣血 + + # 修罗城防爆 + if tagCityID == XiuluoCityID and tagCity.hp <= 0: + tagCity.hp = 1 + tagGuard.hp = 1 + lostHP = remainHurtTotal + GameWorld.Log(" 修罗城防爆: zoneID=%s,familyID=%s" % (zoneID, familyID), playerID) + + GameWorld.DebugLog(" tagGuardID=%s,remainHurtTotal=%s,lostHP=%s,hpBef=%s/%s,hpUpd=%s,cityHPUpd=%s" + % (fighterID, remainHurtTotal, lostHP, hpBef, tagGuard.hpMax, tagGuard.hp, tagCity.hp), playerID) + + remainHurtTotal -= lostHP # 剩余伤害值 + + # 战报以实际掉血计算,总量为100% + curCity.atkReportDict[tagCityID] = curCity.atkReportDict.get(tagCityID, 0) + lostHP + tagCity.defReportDict[curCityID] = tagCity.defReportDict.get(curCityID, 0) + lostHP + + if tagGuard.IsDead(): + killCnt += 1 + killCntTotal += 1 + tagCity.NextGuard() + + GameWorld.DebugLog(" remainHurtTotal=%s,killCnt=%s,atkReportDict=%s,defReportDict=%s" + % (remainHurtTotal, killCnt, curCity.atkReportDict, tagCity.defReportDict), playerID) + + if not atkedGuardIDList: + continue + + hurtDict[tagCityID] = oneHurtTotal # 飘血按伤害 + # 通知被攻击盟成员大本营城池信息 + if tagCity.familyID: + Sync_FamilyGCZCampInfo(zoneID, tagCity.familyID, defMemIDList=atkedGuardIDList) + Sync_FamilyGCZBatCityInfo(zoneID, batType, groupNum, tagCityID, AtkRet_OK, playerID, oneHurtTotal, killCnt) + + if not hurtDict: + SendFamilyGCZAtkResult(AtkRet_Other, "NoHurt", msgData, serverGroupID, zoneID, curRound, batType, groupNum) + return + + # 更新个人活动总伤害 + joinMember.totalHurtValue += totalHurtValue + GameWorld.DebugLog(" 更新玩家活动总伤害榜值! memTotalHurt=%s" % (joinMember.totalHurtValue), playerID) + cmpValue = joinMember.totalHurtValue / ChConfig.Def_PerPointValue + cmpValue2 = joinMember.totalHurtValue % ChConfig.Def_PerPointValue + CrossBillboard.UpdCrossBillboardPlayer(ShareDefine.Def_CBT_FamilyGCZPlayerHurt, playerID, zoneID, cmpValue, cmpValue2, autoSort=False) + + # 本盟还未被摧毁,可计算轮次伤害 + if not curCity.IsBroken(): + # 本轮成员贡献伤害 + curCity.fighterHurtDict[playerID] = curCity.fighterHurtDict.get(playerID, 0) + totalHurtValue + GameWorld.DebugLog(" 更新本轮仙盟成员贡献伤害! familyID=%s,playerID=%s,addHurtValue=%s,%s" + % (familyID, playerID, totalHurtValue, curCity.fighterHurtDict), playerID) + UndFamilyRoundHurtBillboard(curJoinFamily) + + playerRoundHurtTotal = curCity.fighterHurtDict[playerID] # 只算生存伤害 + topHurtPlayerID, topHurtPlayerValue = batGroup.GetTopHurtPlayerIDValue() + if playerRoundHurtTotal > topHurtPlayerValue: + batGroup.UpdTopHurtPlayerIDValue(playerID, playerRoundHurtTotal) + GameWorld.DebugLog(" 更新为本组伤害第一玩家: playerRoundHurtTotal=%s > %s" % (playerRoundHurtTotal, topHurtPlayerValue), playerID) + else: + GameWorld.DebugLog(" 未超过本组伤害第一玩家: playerRoundHurtTotal=%s <= %s,topPlayerHurtID=%s" + % (playerRoundHurtTotal, topHurtPlayerValue, topHurtPlayerID), playerID) + else: + GameWorld.DebugLog(" 自己仙盟城池已被摧毁,不再累加本轮仙盟伤害榜值! familyID=%s" % familyID, playerID) + + SendFamilyGCZAtkResult(AtkRet_OK, "OK", msgData, serverGroupID, zoneID, curRound, batType, groupNum, hurtDict, killCntTotal) + return + +def CheckXiuluoCity(zoneID, curRound, batType, groupNum, playerID=0): + ## 检查是否刷新修罗城 + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + #maxRound = GetMaxRound(zone.joinFamilyCnt) + appearRoundList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZXiuluo", 4) + if curRound not in appearRoundList: + return + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + return + xiuluoCity = batGroup.GetCityWall(XiuluoCityID) + if xiuluoCity: + return + aliveFamilyCnt = 0 + for tagCity in batGroup.cityWallDict.values(): + if tagCity.IsBroken(): + continue + aliveFamilyCnt += 1 + if aliveFamilyCnt > 1: + return + GameWorld.Log("剩下一个仙盟未被摧毁,刷新修罗城! zoneID=%s,curRound=%s,batType=%s,groupNum=%s" % (zoneID, curRound, batType, groupNum), playerID) + xiuluoCityLV = IpyGameDataPY.GetFuncCfg("FamilyGCZXiuluo", 3) + guardNPCCount = IpyGameDataPY.GetFuncCfg("FamilyGCZXiuluo", 2) + batGroup.CreateCityWall(XiuluoCityID, xiuluoCityLV, guardNPCCount=guardNPCCount, isAttrLock=True) + Sync_FamilyGCZBatSceneInfo(zoneID, batType, groupNum) + return True + +def SendFamilyGCZAtkResult(atkRet, errMsg, msgData, serverGroupID, zoneID, curRound, batType, groupNum, hurtDict={}, killCntTotal=0): + atkPlayerID = msgData["playerID"] + atkType = msgData["atkType"] + tagCityID = msgData["tagCityID"] + + if atkPlayerID and atkRet != AtkRet_OK: + GameWorld.ErrLog("仙盟攻城战攻击失败: atkRet=%s:%s,atkType=%s,%s" % (atkRet, errMsg, atkType, msgData), atkPlayerID) + # 失败时仅通知发起攻击玩家刷新最新信息即可 + if atkType == AtkType_Normal: + Sync_FamilyGCZBatCityInfo(zoneID, batType, groupNum, tagCityID, atkRet, atkPlayerID, toPlayerServerDict={atkPlayerID:serverGroupID}) + else: + Sync_FamilyGCZBatSceneInfo(zoneID, batType, groupNum, atkPlayerID, atkType, toPlayerServerDict={atkPlayerID:serverGroupID}) + + # 有玩家攻击成功,需要同步通知在城池场景内及城池内的玩家,因为无论在哪里攻击都会触发城池内城池外双方信息的变化 + if atkPlayerID and atkRet == AtkRet_OK: + #Sync_FamilyGCZBatCityInfo 这个在攻击遍历中已通知,仅通知被攻击的城池 + Sync_FamilyGCZBatSceneInfo(zoneID, batType, groupNum, atkPlayerID, atkType, hurtDict, killCntTotal) + + msgInfo = {"atkRet":atkRet, "errMsg":errMsg, "reqMsg":msgData, "hurtDict":hurtDict, "killCntTotal":killCntTotal} + Send_CrossServerMsg_FamilyGCZ("FamilyGCZAtkResult", msgInfo, [serverGroupID]) + + CheckXiuluoCity(zoneID, curRound, batType, groupNum, atkPlayerID) + return + +def Sync_FamilyGCZBatSceneInfo(zoneID, batType, groupNum, atkPlayerID=0, atkType=0, hurtDict={}, killCntTotal=0, toPlayerServerDict=None): + ## 通知城池场景信息 + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + return + + onlinePlayerIDDict = {} + if toPlayerServerDict != None: + onlinePlayerIDDict = toPlayerServerDict + else: + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + notifyPlayerIDList = batGroup.inBatScenePlayerIDList # + [atkPlayerID] + for playerID in notifyPlayerIDList: + if not playerID or playerID in onlinePlayerIDDict: + continue + serverGroupID = onlineMgr.GetOLPlayerServerGroupID(playerID) + if serverGroupID: + onlinePlayerIDDict[playerID] = serverGroupID + GameWorld.DebugLog("Sync_FamilyGCZBatSceneInfo zoneID=%s,batType=%s,groupNum=%s,%s,%s" + % (zoneID, batType, groupNum, notifyPlayerIDList, onlinePlayerIDDict), atkPlayerID) + + if not onlinePlayerIDDict: + return + + sceneShowPlayerIDList = [] # 场景中需要展示的玩家ID列表 + topFamilyID, topLeaderID = 0, 0 + + groupValue2 = GetRoundHurtGroupID(batType, groupNum) + billboardMgr = PyDataManager.GetCrossBillboardManager() + roundHurtBillboard = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZRoundHurt, zoneID, groupValue2) + idOrderDict = roundHurtBillboard.GetIDOrderDict() + if roundHurtBillboard.GetCount(): + topFamilyBillboard = roundHurtBillboard.At(0) + topFamilyID = topFamilyBillboard.ID + topFamily = zone.GetZoneJoinFamily(topFamilyID) + if topFamily: + topLeaderID = topFamily.leaderID + if topLeaderID not in sceneShowPlayerIDList: + sceneShowPlayerIDList.append(topLeaderID) + + topPlayerID = batGroup.GetTopHurtPlayerIDValue()[0] + topPlayerFamilyID = 0 + if topPlayerID: + if topPlayerID not in sceneShowPlayerIDList: + sceneShowPlayerIDList.append(topPlayerID) + topMember = zone.GetZoneJoinMember(topPlayerID) + if topMember: + topPlayerFamilyID = topMember.familyID + + clientPack = ChPyNetSendPack.tagGCFamilyGCZBatSceneInfo() + clientPack.BatType = batType + clientPack.GroupNum = groupNum + clientPack.TopFamilyID = topFamilyID + clientPack.TopLeaderID = topLeaderID + clientPack.TopPlayerID = topPlayerID + clientPack.TopPlayerFamilyID = topPlayerFamilyID + # 场景信息只通知技能攻击 + if atkType != AtkType_Normal and hurtDict: + if atkPlayerID not in sceneShowPlayerIDList: + sceneShowPlayerIDList.append(atkPlayerID) + clientPack.AtkPlayerID = atkPlayerID + clientPack.AtkType = atkType + clientPack.KillCnt = killCntTotal + clientPack.HurtList = [] + for cityID, hurtTotal in hurtDict.items(): + hurt = ChPyNetSendPack.tagGCFamilyGCZBatSceneHurt() + hurt.CityID = cityID + hurt.HurtValue = hurtTotal % ChConfig.Def_PerPointValue + hurt.HurtValueEx = hurtTotal / ChConfig.Def_PerPointValue + clientPack.HurtList.append(hurt) + clientPack.HurtCnt = len(clientPack.HurtList) + + # 场景有变化的城池,暂时都同步,不然可能名次显示有问题 + #if hurtDict: + # syncCityIDList = hurtDict.keys() + #else: + syncCityIDList = batGroup.GetCityIDList() + clientPack.CityList = [] + for cityID in syncCityIDList: + cityWall = batGroup.GetCityWall(cityID) + if not cityWall: + continue + city = ChPyNetSendPack.tagGCFamilyGCZBatSceneCity() + city.CityID = cityID + city.CityLV = cityWall.cityLV + city.FamilyID = cityWall.familyID + city.Rank = idOrderDict.get(cityWall.familyID, 0) + city.HP = cityWall.hp % ChConfig.Def_PerPointValue + city.HPEx = cityWall.hp / ChConfig.Def_PerPointValue + city.HPMax = cityWall.hpMax % ChConfig.Def_PerPointValue + city.HPMaxEx = cityWall.hpMax / ChConfig.Def_PerPointValue + city.LastAtkedTime = cityWall.atkedTime + clientPack.CityList.append(city) + clientPack.CityCnt = len(clientPack.CityList) + + # 场景需要用到的玩家信息 + clientPack.PlayerInfoList = [] + for playerID in sceneShowPlayerIDList: + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + scenePlayer = ChPyNetSendPack.tagGCFamilyGCZBatScenePlayer() + scenePlayer.PlayerID = playerID + scenePlayer.Name = joinMember.playerName + scenePlayer.Face = joinMember.face + scenePlayer.FacePic = joinMember.facePic + clientPack.PlayerInfoList.append(scenePlayer) + clientPack.PlayerCnt = len(clientPack.PlayerInfoList) + + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + return + +def Sync_FamilyGCZBatCityInfo(zoneID, batType, groupNum, cityID, atkRet=0, atkPlayerID=0, hurtValue=0, killCnt=0, toPlayerServerDict=None): + ## 通知城池信息 + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + return + cityWall = batGroup.GetCityWall(cityID) + if not cityWall: + return + + onlinePlayerIDDict = {} + if toPlayerServerDict != None: + onlinePlayerIDDict = toPlayerServerDict + else: + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + notifyPlayerIDList = cityWall.inCityPlayerIDList # + [atkPlayerID] + for playerID in notifyPlayerIDList: + if not playerID or playerID in onlinePlayerIDDict: + continue + serverGroupID = onlineMgr.GetOLPlayerServerGroupID(playerID) + if serverGroupID: + onlinePlayerIDDict[playerID] = serverGroupID + GameWorld.DebugLog("Sync_FamilyGCZBatCityInfo zoneID=%s,batType=%s,groupNum=%s,cityID=%s,%s,%s" + % (zoneID, batType, groupNum, cityID, notifyPlayerIDList, onlinePlayerIDDict), atkPlayerID) + + if not onlinePlayerIDDict: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZBatCityInfo() + clientPack.CityID = cityID + clientPack.CityLV = cityWall.cityLV + clientPack.FamilyID = cityWall.familyID + clientPack.GuardID = cityWall.GetCurGuardID() + clientPack.HP = cityWall.hp % ChConfig.Def_PerPointValue + clientPack.HPEx = cityWall.hp / ChConfig.Def_PerPointValue + clientPack.HPMax = cityWall.hpMax % ChConfig.Def_PerPointValue + clientPack.HPMaxEx = cityWall.hpMax / ChConfig.Def_PerPointValue + clientPack.AtkPlayerID = atkPlayerID + clientPack.AtkRet = atkRet + clientPack.KillCnt = killCnt + clientPack.HurtValue = hurtValue % ChConfig.Def_PerPointValue + clientPack.HurtValueEx = hurtValue / ChConfig.Def_PerPointValue + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + return + +def __clientServer_QueryContributionInfo(playerID, serverGroupID, msgData): + ## 查询贡献值信息 + gczMgr = GetFamilyGCZMgr() + joinFamily = gczMgr.GetJoinFamilyByPlayerID(playerID) + if not joinFamily: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZContributionInfo() + clientPack.ContriList = [] + for memID, value in joinFamily.memAddCampExpInfo.items(): + contri = ChPyNetSendPack.tagGCFamilyGCZContribution() + contri.PlayerID = memID + contri.ContributionValue = value + clientPack.ContriList.append(contri) + clientPack.ContriCnt = len(clientPack.ContriList) + NetPackCommon.SendFakePackByCross({playerID:serverGroupID}, clientPack) + return + +def __clientServer_QueryBatReport(playerID, serverGroupID, repFamilyID): + ## 查询战报 + + gczMgr = GetFamilyGCZMgr() + repFamily = gczMgr.GetJoinFamily(repFamilyID) + if not repFamily: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZBatReport() + clientPack.FamilyID = repFamilyID + clientPack.DefRepList = [] + for tagFamilyID, hurtValue in repFamily.cityWall.defReportDict.items(): + defRep = ChPyNetSendPack.tagGCFamilyGCZBatRepHurt() + defRep.TagFamilyID = tagFamilyID + defRep.HurtValue = hurtValue % ChConfig.Def_PerPointValue + defRep.HurtValueEx = hurtValue / ChConfig.Def_PerPointValue + clientPack.DefRepList.append(defRep) + clientPack.DefRepCnt = len(clientPack.DefRepList) + + clientPack.AtkRepList = [] + for tagFamilyID, hurtValue in repFamily.cityWall.atkReportDict.items(): + atkRep = ChPyNetSendPack.tagGCFamilyGCZBatRepHurt() + atkRep.TagFamilyID = tagFamilyID + atkRep.HurtValue = hurtValue % ChConfig.Def_PerPointValue + atkRep.HurtValueEx = hurtValue / ChConfig.Def_PerPointValue + clientPack.AtkRepList.append(atkRep) + clientPack.AtkRepCnt = len(clientPack.AtkRepList) + + NetPackCommon.SendFakePackByCross({playerID:serverGroupID}, clientPack) + return + +def __clientServer_QueryGroupFamilyMemHurt(playerID, serverGroupID, zoneID, tagFamilyID): + ## 查询分组仙盟成员伤害信息 + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + joinFamily = zone.GetZoneJoinFamily(tagFamilyID) + if not joinFamily: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZGroupFamilyMemHurtInfo() + clientPack.FamilyID = tagFamilyID + clientPack.HurtMemList = [] + for memID, value in joinFamily.cityWall.fighterHurtDict.items(): + joinMember = zone.GetZoneJoinMember(memID) + memHurt = ChPyNetSendPack.tagGCFamilyGCZGroupFamilyMemHurt() + memHurt.PlayerID = memID + memHurt.Name = joinMember.playerName if joinMember else "" + memHurt.HurtValue = value % ChConfig.Def_PerPointValue + memHurt.HurtValueEx = value / ChConfig.Def_PerPointValue + clientPack.HurtMemList.append(memHurt) + clientPack.HurtMemCnt = len(clientPack.HurtMemList) + NetPackCommon.SendFakePackByCross({playerID:serverGroupID}, clientPack) + return + +def __clientServer_Guess(serverGroupID, msgData): + ## 竞猜 - 无参与资格的也可以竞猜 + + playerID = msgData["playerID"] + selectFamilyIDList = msgData["selectFamilyIDList"] + + zoneID = GetPlayerActJoinInfo(playerID)[0] + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + canGuessStateList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGuess", 1) + if state not in canGuessStateList: + GameWorld.ErrLog("仙盟攻城战非竞猜阶段: zoneID=%s,state=%s not in %s" % (zoneID, state, canGuessStateList), playerID) + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + guessCountMax = IpyGameDataPY.GetFuncCfg("FamilyGCZGuess", 3) + selectFamilyIDList = selectFamilyIDList[:guessCountMax] + for familyID in selectFamilyIDList: + if familyID not in zone.familyGuessDict: + GameWorld.ErrLog("仙盟攻城战该仙盟ID不可竞猜! zoneID=%s,selectFamilyIDList=%s,familyID=%s not in %s" + % (zoneID, selectFamilyIDList, familyID, zone.familyGuessDict.keys()), playerID) + return + + for familyID in selectFamilyIDList: + zone.familyGuessDict[familyID] = zone.familyGuessDict.get(familyID, 0) + 1 + + zone.playerGuessDict[playerID] = selectFamilyIDList + GameWorld.DebugLog("仙盟攻城战竞猜: %s,familyGuessDict=%s" % (selectFamilyIDList, zone.familyGuessDict), playerID) + + Sync_FamilyGCZGuessInfo(zoneID, selectPlayerID=playerID) + return + +def __DoGMGuess(zoneID, state, guessCnt, selectFamilyIDList, playerID, serverGroupID): + ## GM山寨竞猜数据 + + canGuessStateList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZGuess", 1) + if state not in canGuessStateList: + GameWorld.DebugAnswerCross(playerID, serverGroupID, "非竞猜阶段!state=%s" % (state)) + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + guessCountMax = IpyGameDataPY.GetFuncCfg("FamilyGCZGuess", 3) + selectFamilyIDList = selectFamilyIDList[:guessCountMax] + + # 没有指定竞猜,则随机 + if not selectFamilyIDList: + familyIDList = zone.familyGuessDict.keys() + random.shuffle(familyIDList) + selectFamilyIDList = familyIDList[:guessCountMax] + + for familyID in selectFamilyIDList: + zone.familyGuessDict[familyID] = zone.familyGuessDict.get(familyID, 0) + guessCnt + + maxFackID = 0 + for pID in zone.playerGuessDict.keys(): + if pID < 10000 and pID > maxFackID: + maxFackID = pID + + for pID in range(maxFackID + 1, maxFackID + 1 + guessCnt + 1): + zone.playerGuessDict[pID] = selectFamilyIDList + + GameWorld.DebugAnswerCross(playerID, serverGroupID, "新增竞猜人数:%s, 总:%s" % (guessCnt, len(zone.playerGuessDict))) + Sync_FamilyGCZGuessInfo(zoneID) + return + +def __clientServer_GetAward(serverGroupID, msgData): + ## 领奖 + playerID = msgData["playerID"] + awardType = msgData["awardType"] + + zoneID = GetPlayerActJoinInfo(playerID)[0] + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + actID = actInfo.get(ShareDefine.ActKey_ID) + state = actInfo.get(ShareDefine.ActKey_State) + if not state or state != FamilyGCZState_Award: + GameWorld.ErrLog("仙盟攻城战非领奖阶段: zoneID=%s,state=%s" % (zoneID, state), playerID) + return + + ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo) + if not ipyDataInfo: + return + + # 跨服领奖不验证领奖状态,领奖状态只标记已推送,实际领奖由子服地图玩家自行验证 + + # 竞猜 + if awardType == AwwardType_Guess: + awardTemplateID = ipyDataInfo.get("GuessTemplateID", 0) + __clientServer_GetAward_Guess(zoneID, playerID, serverGroupID, actID, state, awardType, awardTemplateID) + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + GameWorld.ErrLog("非仙盟攻城战参赛成员!", playerID) + return + zoneID = joinMember.zoneID + familyID = joinMember.familyID + fmLV = joinMember.fmLV + + billID = playerID + billboardType = 0 + awardTemplateID = 0 + billValue = None + + # 个人排行 + if awardType == AwwardType_PlayerHurt: + billID = playerID + billboardType = ShareDefine.Def_CBT_FamilyGCZPlayerHurt + awardTemplateID = ipyDataInfo.get("PersonalTemplateID", 0) + + # 仙盟排行 + elif awardType == AwwardType_FamilyScore: + billID = familyID + billboardType = ShareDefine.Def_CBT_FamilyGCZScore + awardTemplateID = ipyDataInfo.get("FamilyTemplateID", 0) + + else: + return + + if not awardTemplateID: + GameWorld.ErrLog("仙盟攻城战领奖时没有排行奖励模版! zoneID=%s,awardType=%s" % (zoneID, awardType), playerID) + return + + billboardMgr = PyDataManager.GetCrossBillboardManager() + billObj = billboardMgr.GetCrossBillboard(billboardType, zoneID) + idRankDict = billObj.GetIDOrderDict() + billRank = idRankDict.get(billID, 0) + + if not billRank: + GameWorld.ErrLog("仙盟攻城战领奖时没有上榜! zoneID=%s,awardType=%s,billboardType=%s,billID=%s" + % (zoneID, awardType, billboardType, billID), playerID) + return + + playerAwardItemList = GameWorld.GetActBillboardTempAward(playerID, billID, billRank, awardTemplateID, billValue, fmLV) + if not playerAwardItemList: + return + + GameWorld.Log("仙盟攻城战玩家请求领取奖励! zoneID=%s,awardType=%s,playerAwardItemList=%s" + % (zoneID, awardType, playerAwardItemList), playerID) + + joinMember.awardState = joinMember.awardState | pow(2, awardType) # 标记已推送 + msgInfo = {"zoneID":zoneID, "playerID":playerID, "actID":actID, "awardType":awardType, "awardValue":billRank, + "awardItemList":playerAwardItemList, "fmLV":fmLV} + Send_CrossServerMsg_FamilyGCZ("FamilyGCZAward", msgInfo, [serverGroupID]) + return + +def __clientServer_GetAward_Guess(zoneID, playerID, serverGroupID, actID, state, awardType, guessTemplateID): + ## 竞猜领奖 + playerAwardID, awardItemList = GetGuessAwardInfo(zoneID, state, guessTemplateID, playerID) + if not awardItemList: + GameWorld.ErrLog("仙盟攻城战玩家没有竞猜奖励! zoneID=%s" % (zoneID), playerID) + return + GameWorld.Log("仙盟攻城战玩家请求领取竞猜奖励! zoneID=%s,playerAwardID=%s,awardItemList=%s" + % (zoneID, playerAwardID, awardItemList), playerID) + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + joinMember = zone.GetZoneJoinMember(playerID) + if joinMember: + joinMember.awardState = joinMember.awardState | pow(2, awardType) # 标记已推送 + msgInfo = {"zoneID":zoneID, "playerID":playerID, "actID":actID, "awardType":awardType, "awardValue":playerAwardID, "awardItemList":awardItemList} + Send_CrossServerMsg_FamilyGCZ("FamilyGCZAward", msgInfo, [serverGroupID]) + return + +def GetGuessAwardInfo(zoneID, state, guessTemplateID, playerID): + ## 获取竞猜奖励 + playerAwardID = 0 + awardItemList = [] + _, statGuessRetDict = __statGuessFinal(zoneID, state, guessTemplateID) + for awardID, rightPlayerIDList in statGuessRetDict.items(): + if playerID in rightPlayerIDList: + playerAwardID = awardID + break + + if playerAwardID: + ipyData = IpyGameDataPY.GetIpyGameDataByCondition("ActGuess", {"TemplateID":guessTemplateID, "AwardID":playerAwardID}, False) + if ipyData: + awardItemList = ipyData.GetAwardItemList() + + return playerAwardID, awardItemList + +def DoMailReissueAward(zoneID, ipyData): + ## 邮件补发奖励 - 仅针对有参与资格的,无参与资格的玩家奖励暂不补发,如竞猜奖励 + + if not ipyData: + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + if not zone.joinMemberDict: + return + + GameWorld.Log("仙盟攻城战邮件补发未领取奖励: zoneID=%s" % zoneID) + + billboardMgr = PyDataManager.GetCrossBillboardManager() + for playerID in zone.joinMemberDict.keys(): + if playerID < 10000: + continue + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + familyID = joinMember.familyID + fmLV = joinMember.fmLV + + # 个人伤害名次奖励 + if not joinMember.awardState&pow(2, AwwardType_PlayerHurt): + joinMember.awardState = joinMember.awardState | pow(2, AwwardType_PlayerHurt) + billObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZPlayerHurt, zoneID) + idRankDict = billObj.GetIDOrderDict() + billRank = idRankDict.get(playerID, 0) + billValue = None + awardTemplateID = ipyData.GetPersonalTemplateID() + playerAwardItemList = GameWorld.GetActBillboardTempAward(playerID, playerID, billRank, awardTemplateID, billValue, fmLV) + if playerAwardItemList: + paramList = [billRank] + PlayerCompensation.SendMailByKey("FamilyGCZAwardHurt", [playerID], playerAwardItemList, paramList, crossMail=True) + + # 仙盟积分名次奖励 + if not joinMember.awardState&pow(2, AwwardType_FamilyScore): + joinMember.awardState = joinMember.awardState | pow(2, AwwardType_FamilyScore) + billObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID) + idRankDict = billObj.GetIDOrderDict() + billRank = idRankDict.get(familyID, 0) + billValue = None + awardTemplateID = ipyData.GetFamilyTemplateID() + playerAwardItemList = GameWorld.GetActBillboardTempAward(playerID, familyID, billRank, awardTemplateID, billValue, fmLV) + if playerAwardItemList: + paramList = [billRank] + PlayerCompensation.SendMailByKey("FamilyGCZAwardScore", [playerID], playerAwardItemList, paramList, crossMail=True) + + # 竞猜奖励 + if not joinMember.awardState&pow(2, AwwardType_Guess): + joinMember.awardState = joinMember.awardState | pow(2, AwwardType_Guess) + awardTemplateID = ipyData.GetGuessTemplateID() + _, awardItemList = GetGuessAwardInfo(zoneID, None, awardTemplateID, playerID) + if awardItemList: + paramList = [] + PlayerCompensation.SendMailByKey("FamilyGCZAwardGuess", [playerID], awardItemList, paramList, crossMail=True) + + return + +def Sync_FamilyGCZGuessInfo(zoneID, playerID=0, selectPlayerID=0): + ## 同步竞猜信息 - 需同步全服玩家,包含没有参与资格的 + # @param selectPlayerID: 同步竞猜玩家ID竞猜记录 + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo) + if not ipyDataInfo: + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + if not zone.familyGuessDict: + # 暂无竞猜名单 + return + + onlinePlayerIDDict = {} + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + if not playerID: + for playerID, serverGroupID in onlineMgr.onlinePlayerDict.items(): + pActInfo = GetPlayerActJoinInfo(playerID) + if zoneID != pActInfo[0]: + continue + onlinePlayerIDDict[playerID] = serverGroupID + else: + onlinePlayerIDDict = {playerID:onlineMgr.GetOLPlayerServerGroupID(playerID)} + + if not onlinePlayerIDDict: + return + + selectFamilyIDList = [] + if selectPlayerID: + selectFamilyIDList = zone.playerGuessDict.get(selectPlayerID, []) + + guessTemplateID = ipyDataInfo.get("GuessTemplateID", 0) + finalFamilyIDList, statGuessRetDict = __statGuessFinal(zoneID, state, guessTemplateID) + + clientPack = ChPyNetSendPack.tagGCFamilyGCZGuessInfo() + clientPack.PlayerID = selectPlayerID + clientPack.SelectFamilyIDList = selectFamilyIDList + clientPack.SelectCnt = len(clientPack.SelectFamilyIDList) + + clientPack.FinalFamilyIDList = finalFamilyIDList + clientPack.FinalCnt = len(clientPack.FinalFamilyIDList) + + clientPack.RightInfoList = [] + for awardID, rightPlayerIDList in statGuessRetDict.items(): + right = ChPyNetSendPack.tagGCFamilyGCZGuessRight() + right.AwardID = awardID + right.RightPlayerCnt = len(rightPlayerIDList) + clientPack.RightInfoList.append(right) + clientPack.RightCnt = len(clientPack.RightInfoList) + + clientPack.GuessFamilyList = [] + for familyID, guessValue in zone.familyGuessDict.items(): + familyGuess = ChPyNetSendPack.tagGCFamilyGCZGuessFamily() + familyGuess.FamilyID = familyID + familyGuess.GuessValue = guessValue + clientPack.GuessFamilyList.append(familyGuess) + clientPack.FamilyCnt = len(clientPack.GuessFamilyList) + + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + return + +def __statGuessFinal(zoneID, state, guessTemplateID): + ## 统计竞猜最终结果 + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + if zone.statGuessRetDict != None: + statGuessRetDict = zone.statGuessRetDict + finalFamilyIDList = zone.guessFinalFamilyIDList + return finalFamilyIDList, statGuessRetDict + + finalFamilyIDList = [] + statGuessRetDict = {} + if state != None and state != FamilyGCZState_Award: + return finalFamilyIDList, statGuessRetDict + + guessCountMax = IpyGameDataPY.GetFuncCfg("FamilyGCZGuess", 3) + billboardMgr = PyDataManager.GetCrossBillboardManager() + scoreBillObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyGCZScore, zoneID) + for index in range(guessCountMax): + billData = scoreBillObj.At(index) + finalFamilyIDList.append(billData.ID) + + # 统计竞猜结果 + rightRankAwardIDDict = GameWorld.GetActGuessRightRankAwardIDDict(guessTemplateID) + GameWorld.Log("仙盟攻城战统计竞猜结果: zoneID=%s,guessTemplateID=%s,finalFamilyIDList=%s,%s" % (zoneID, guessTemplateID, finalFamilyIDList, rightRankAwardIDDict)) + + statGuessRetDict = {} + for playerID, guessFamilyIDList in zone.playerGuessDict.items(): + GameWorld.StatActGuessRet(playerID, guessFamilyIDList, finalFamilyIDList, rightRankAwardIDDict, statGuessRetDict, "FamilyGCZ") + + GameWorld.Log(" zoneID=%s,statGuessRetDict=%s" % (zoneID, statGuessRetDict)) + zone.statGuessRetDict = statGuessRetDict + zone.guessFinalFamilyIDList = finalFamilyIDList + return finalFamilyIDList, statGuessRetDict + +def Sync_FamilyGCZActInfo(zoneID, playerID=0): + ## 同步活动时间信息 - 需同步全服玩家,包含没有参与资格的 + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + if not actInfo.get(ShareDefine.ActKey_State): + return + ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo) + if not ipyDataInfo: + return + + playerActInfo = {} + onlinePlayerIDDict = {} + onlineMgr = ChPlayer.GetOnlinePlayerMgr() + if not playerID: + for playerID, serverGroupID in onlineMgr.onlinePlayerDict.items(): + pActInfo = GetPlayerActJoinInfo(playerID) + if zoneID != pActInfo[0]: + continue + playerActInfo[playerID] = pActInfo + onlinePlayerIDDict[playerID] = serverGroupID + else: + playerActInfo[playerID] = GetPlayerActJoinInfo(playerID) + onlinePlayerIDDict = {playerID:onlineMgr.GetOLPlayerServerGroupID(playerID)} + + if not onlinePlayerIDDict: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZActInfo() + clientPack.Clear() + clientPack.ServerIDRangeInfo = str(actInfo.get(ShareDefine.ActKey_ServerIDRangeList, [])) + clientPack.ServerInfoLen = len(clientPack.ServerIDRangeInfo) + clientPack.ZoneID = zoneID + clientPack.ActID = actInfo.get(ShareDefine.ActKey_ID, 0) + clientPack.StartDate = ipyDataInfo.get("StartDate", "") + clientPack.EndtDate = ipyDataInfo.get("EndDate", "") + clientPack.JoinFamilyCnt = ipyDataInfo.get("JoinFamilyCnt", 0) + clientPack.ActFlowID = ipyDataInfo.get("ActFlowID", 0) + clientPack.GuessTemplateID = ipyDataInfo.get("GuessTemplateID", 0) + clientPack.PersonalTemplateID = ipyDataInfo.get("PersonalTemplateID", 0) + clientPack.FamilyTemplateID = ipyDataInfo.get("FamilyTemplateID", 0) + clientPack.StateError = actInfo.get(ShareDefine.ActKey_StateError, 0) + + clientPack.ActFamilyList = [] + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + for familyID in zone.GetZoneLockFamilyIDList(): + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + continue + + actFamily = ChPyNetSendPack.tagGCFamilyGCZActFamily() + actFamily.FamilyID = familyID + actFamily.Name = joinFamily.familyName + actFamily.LV = joinFamily.lv + actFamily.ServerID = joinFamily.serverID + actFamily.EmblemID = joinFamily.emblemID + actFamily.FightPower = joinFamily.fightPowerTotal % ChConfig.Def_PerPointValue + actFamily.FightPowerEx = joinFamily.fightPowerTotal / ChConfig.Def_PerPointValue + actFamily.LeaderID = joinFamily.leaderID + actFamily.LeaderName = joinFamily.leaderName + + leaderMem = zone.GetZoneJoinMember(actFamily.LeaderID) + if leaderMem: + actFamily.LeaderFace = leaderMem.face + actFamily.LeaderFacePic = leaderMem.facePic + + clientPack.ActFamilyList.append(actFamily) + clientPack.FamilyCount = len(clientPack.ActFamilyList) + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + + #同步场景、同步玩家攻击结果 + #下发分区活动的时候,顺便下发玩家活动信息 + msgInfo = {"zoneID":zoneID, "playerActInfo":playerActInfo} + Send_CrossServerMsg_FamilyGCZ("FamilyGCZPlayerActInfo", msgInfo, onlinePlayerIDDict.values()) + return + +def Sync_FamilyGCZBatGroupInfo(zoneID, onlinePlayerIDDict=None): + ## 同步战场类型分组信息 - 只同步有参与资格的即可 + + actInfo = CrossActionControl.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State) + if not state: + return + curRound, _ = GetRoundState(state) + if not curRound: + return + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + if onlinePlayerIDDict == None: + onlinePlayerIDDict = zone.GetOLServerGroupIDDict() + + if not onlinePlayerIDDict: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZBatGroupInfo() + clientPack.RoundNum = curRound + clientPack.BatList = [] + for batType, groupNumDict in zone.roundGroupDict.items(): + batInfo = ChPyNetSendPack.tagGCFamilyGCZBat() + batInfo.BatType = batType + batInfo.GroupList = [] + for groupNum in groupNumDict.keys(): + batGroup = zone.GetBatGroup(batType, groupNum) + if not batGroup: + continue + group = ChPyNetSendPack.tagGCFamilyGCZBatGroup() + group.GroupNum = groupNum + group.FamilyIDList = batGroup.GetGroupFamilyIDList() + group.FamilyIDCnt = len(group.FamilyIDList) + batInfo.GroupList.append(group) + batInfo.GroupCnt = len(batInfo.GroupList) + + clientPack.BatList.append(batInfo) + clientPack.BatTypeCnt = len(clientPack.BatList) + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + return + +def Sync_FamilyGCZCampInfo(zoneID, familyID, onlinePlayerIDDict=None, defMemIDList=None): + ## 同步仙盟大本营信息 - 只同步某个锁定盟的锁定成员即可 + + gczMgr = GetFamilyGCZMgr() + zone = gczMgr.GetActZone(zoneID) + joinFamily = zone.GetZoneJoinFamily(familyID) + if not joinFamily: + return + + if onlinePlayerIDDict == None: + onlinePlayerIDDict = joinFamily.GetOLMemServerGroupIDDict() + + #GameWorld.DebugLog("Sync_FamilyGCZCampInfo zoneID=%s,familyID=%s,%s,defMemIDList=%s" % (zoneID, familyID, onlinePlayerIDDict, defMemIDList)) + if not onlinePlayerIDDict: + return + + clientPack = ChPyNetSendPack.tagGCFamilyGCZCampInfo() + clientPack.Clear() + clientPack.FamilyID = familyID + clientPack.Score = joinFamily.score + clientPack.CampLV = joinFamily.campLV + clientPack.CampExp = joinFamily.campExp + clientPack.CityLV = joinFamily.cityWall.cityLV + clientPack.HPBase = joinFamily.cityWall.hpBase % ChConfig.Def_PerPointValue + clientPack.HPBaseEx = joinFamily.cityWall.hpBase / ChConfig.Def_PerPointValue + clientPack.HPMax = joinFamily.cityWall.hpMax % ChConfig.Def_PerPointValue + clientPack.HPMaxEx = joinFamily.cityWall.hpMax / ChConfig.Def_PerPointValue + clientPack.HP = joinFamily.cityWall.hp % ChConfig.Def_PerPointValue + clientPack.HPEx = joinFamily.cityWall.hp / ChConfig.Def_PerPointValue + clientPack.DefMemList = [] + for playerID in joinFamily.joinMemberIDList: + if defMemIDList != None and playerID not in defMemIDList: + continue + joinMember = zone.GetZoneJoinMember(playerID) + if not joinMember: + continue + + defMem = ChPyNetSendPack.tagGCFamilyGCZCampMem() + defMem.PlayerID = playerID + defMem.Name = joinMember.playerName + defMem.FamilyLV = joinMember.fmLV + defMem.Face = joinMember.face + defMem.FacePic = joinMember.facePic + defMem.FightPower = joinMember.fightPower % ChConfig.Def_PerPointValue + defMem.FightPowerEx = joinMember.fightPower / ChConfig.Def_PerPointValue + defMem.HP = joinMember.hp % ChConfig.Def_PerPointValue + defMem.HPEx = joinMember.hp / ChConfig.Def_PerPointValue + defMem.HPMax = joinMember.hpMax % ChConfig.Def_PerPointValue + defMem.HPMaxEx = joinMember.hpMax / ChConfig.Def_PerPointValue + defMem.TotalHurt = joinMember.totalHurtValue % ChConfig.Def_PerPointValue + defMem.TotalHurtEx = joinMember.totalHurtValue / ChConfig.Def_PerPointValue + clientPack.DefMemList.append(defMem) + + clientPack.DefMemCnt = len(clientPack.DefMemList) + NetPackCommon.SendFakePackByCross(onlinePlayerIDDict, clientPack) + return + +## ------------------------------------------------------------------------------------------------- +def OnPlayerLogin(curPlayer): + PlayerControl.DoOfflineUnprocessed(curPlayer, "FamilyGCZAtkResult", __DoOfflineFamilyGCZAtkResult) + PlayerControl.DoOfflineUnprocessed(curPlayer, "FamilyGCZAward", __DoOfflineFamilyGCZAward) + return + +def ClientServer_CrossActInfo(): + ## 子服处理 - 活动状态信息 + return + +def MapServer_FamilyGCZ(curPlayer, msgList): + mapID = curPlayer.GetRealMapID() + playerID = curPlayer.GetPlayerID() + GameWorld.DebugLog("MapServer_FamilyGCZ mapID=%s,msgList=%s" % (mapID, msgList), playerID) + if not msgList: + return + + #msgType, dataMsg = msgList + ret = None + + if ret == None: + return + return msgList + (ret if isinstance(ret, list) else [ret]) + +def MapServer_QueryPlayerResult(curPlayer, msgType, dataMsg=[]): + ret = 1 + msgInfo = str([msgType, dataMsg, ret]) + curPlayer.MapServer_QueryPlayerResult(0, 0, "FamilyGCZ", msgInfo, len(msgInfo)) + return + +#// C0 26 仙盟攻城战查询 #tagCGFamilyGCZQuery +# +#struct tagCGFamilyGCZQuery +#{ +# tagHead Head; +# BYTE QueryType; //查询类型:1-成员捐献值;2-进入城池场景;3-退出城池场景;4-进入城池;5-退出城池;6-战报;7-分组仙盟成员伤害; +# BYTE BatType; //指定战场类型,需要发送的查询类型: 2、4 +# BYTE GroupNum; //指定分组编号,需要发送的查询类型: 2、4 +# DWORD FamilyID; //指定仙盟ID或城池ID,查自己盟的可不发,需要发的类型:2、4、6、7 +#}; +def OnFamilyGCZQuery(index, clientData, tick): + curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index) + queryType = clientData.QueryType + batType = clientData.BatType + groupNum = clientData.GroupNum + familyID = clientData.FamilyID + + playerID = curPlayer.GetPlayerID() + dataMsg = {"ActMsgType":"Query", "playerID":playerID, "queryType":queryType, "batType":batType, "groupNum":groupNum, "familyID":familyID} + CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + return + +def CrossServerMsg_FamilyGCZ(dataMsg): + ## 收到跨服服务器同步的跨服运营活动状态 + + actMsgType = dataMsg["ActMsgType"] + if actMsgType == "FamilyGCZPlayerActInfo": + __clientServer_FamilyGCZPlayerActInfo(dataMsg) + + elif actMsgType == "FamilyGCZAtkResult": + atkRet = dataMsg["atkRet"] + playerID = dataMsg["reqMsg"]["playerID"] + if not PlayerControl.GetDBPlayerAccIDByID(playerID): + return + curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID) + if not curPlayer: + if atkRet != AtkRet_OK: + # 不是攻击成功的,玩家不在线可以不处理 + return + PlayerControl.AddOfflineUnprocessed(playerID, "FamilyGCZAtkResult", dataMsg) + return + MapServer_QueryPlayerResult(curPlayer, "FamilyGCZAtkResult", dataMsg) + + elif actMsgType == "FamilyGCZAward": + playerID = dataMsg["playerID"] + if not PlayerControl.GetDBPlayerAccIDByID(playerID): + return + curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID) + if not curPlayer: + PlayerControl.AddOfflineUnprocessed(playerID, "FamilyGCZAward", dataMsg) + return + MapServer_QueryPlayerResult(curPlayer, "FamilyGCZAward", dataMsg) + + return + +def __DoOfflineFamilyGCZAtkResult(curPlayer, recData, eventName, eventData): + ## 执行离线未处理的战斗结果 + MapServer_QueryPlayerResult(curPlayer, "FamilyGCZAtkResult", eventData) + return + +def __DoOfflineFamilyGCZAward(curPlayer, recData, eventName, eventData): + ## 执行离线未处理的 + MapServer_QueryPlayerResult(curPlayer, "FamilyGCZAward", eventData) + return + +def __clientServer_FamilyGCZPlayerActInfo(dataMsg): + playerActInfo = dataMsg["playerActInfo"] + + playerManager = GameWorld.GetPlayerManager() + for playerID, pActInfo in playerActInfo.items(): + if not PlayerControl.GetDBPlayerAccIDByID(playerID): + # 非本服玩家 + return + curPlayer = playerManager.FindPlayerByID(playerID) + if curPlayer: + MapServer_QueryPlayerResult(curPlayer, "FamilyGCZPlayerActInfo", pActInfo) + + return diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py index a7f3d39..451dbf4 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py @@ -18,9 +18,11 @@ import GameWorld import ShareDefine import PlayerAssist +import PlayerFamily import PlayerControl import PlayerPackData import PlayerFuncTeam +import NetPackCommon import CrossLuckyCloudBuy import IPY_GameServer import PlayerViewCache @@ -35,6 +37,7 @@ import CrossActAllRecharge import CrossChampionship import CrossBattlefield +import CrossFamilyGCZ import CrossBillboard import CrossYaomoBoss import GameWorldBoss @@ -224,6 +227,12 @@ elif msgType == ShareDefine.ClientServerMsg_LianqiScore: PlayerActLianqi.ClientServerMsg_LianqiScore(serverGroupID, msgData) + elif msgType == ShareDefine.ClientServerMsg_SyncFamilyInfo: + PlayerFamily.ClientServerMsg_SyncFamilyInfo(serverGroupID, msgData) + + elif msgType == ShareDefine.ClientServerMsg_FamilyGCZ: + CrossFamilyGCZ.ClientServerMsg_FamilyGCZ(serverGroupID, msgData) + elif msgType == ShareDefine.ClientServerMsg_CreateFuncTeam: PlayerFuncTeam.ClientServerMsg_CreateFuncTeam(serverGroupID, msgData) @@ -405,6 +414,9 @@ elif msgType == ShareDefine.CrossServerMsg_PlayerLoginout: ChPlayer.CrossServerMsg_PlayerLoginout(msgData) + elif msgType == ShareDefine.CrossServerMsg_SendFakePack: + NetPackCommon.CrossServerMsg_SendFakePack(msgData) + elif msgType == ShareDefine.CrossServerMsg_ChatCrossWorld: PlayerTalk.CrossServerMsg_ChatCrossWorld(msgData) @@ -458,6 +470,12 @@ elif msgType == ShareDefine.CrossServerMsg_FuncTeamList: PlayerFuncTeam.CrossServerMsg_FuncTeamList(msgData) + + elif msgType == ShareDefine.CrossServerMsg_FamilyDelRet: + PlayerFamily.CrossServerMsg_FamilyDelRet(msgData) + + elif msgType == ShareDefine.CrossServerMsg_FamilyGCZ: + CrossFamilyGCZ.CrossServerMsg_FamilyGCZ(msgData) elif msgType == ShareDefine.CrossServerMsg_Worship: GameWorship.CrossServerMsg_Worship(msgData) @@ -636,5 +654,12 @@ SendMsgToCrossServer(ShareDefine.ClientServerMsg_ServerInitOK, dataMsg) return - - \ No newline at end of file +def OnCrossServerStateOpen(): + '''子服收到跨服服务器通知 - 跨服服务器状态正常开放中,可能是启动、重连、或者维护后重新开放 + 这里可以处理一些子服与跨服正式建立常规逻辑通讯(注意与socket连接区分,这里指的是逻辑通讯)后的逻辑 + 注:跨服子服socket连接后,并不能正式开始逻辑消息通讯,需要等待双方都启动成功后才可以 + 即子服发送 ClientServerMsg_ServerInitOK 告知启动成功 + 然后跨服回复开启状态后才算正式建立常规逻辑通讯 + ''' + PlayerFamily.Sync_ClientFamilyAllToCrossServer() + return diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameRecData.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameRecData.py index 8690970..f1bb836 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameRecData.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameRecData.py @@ -58,7 +58,7 @@ def SetValue7(self, value7): self.dbRecData.Value7 = value7 def GetValue8(self): return self.dbRecData.Value8 def SetValue8(self, value8): self.dbRecData.Value8 = value8 - def __GetUserDataDict(self): + def GetUserDataDict(self): if self.__userDataDict == None: try: self.__userDataDict = eval(self.dbRecData.UserData) @@ -66,12 +66,12 @@ self.__userDataDict = {} return self.__userDataDict def GetUserDataByKey(self, key, defaultValue=None): - userDataDict = self.__GetUserDataDict() + userDataDict = self.GetUserDataDict() if key in userDataDict: return userDataDict[key] return defaultValue def SetUserDataByKey(self, key, value): - userDataDict = self.__GetUserDataDict() + userDataDict = self.GetUserDataDict() userDataDict[key] = value self.__userDataChange = True return @@ -112,7 +112,7 @@ return {"RecID":self.GetRecID(), "RecType":self.GetRecType(), "Time":self.GetTime(), "Value1":self.GetValue1(), "Value2":self.GetValue2(), "Value3":self.GetValue3(), "Value4":self.GetValue4(), "Value5":self.GetValue5(), "Value6":self.GetValue6(), "Value7":self.GetValue7(), "Value8":self.GetValue8(), - "UserDataDict":self.__GetUserDataDict() + "UserDataDict":self.GetUserDataDict() } def SetAttr(self, attrDict, isClear=False): if isClear: @@ -324,6 +324,33 @@ matchRecDataList.append(recData) return matchRecDataList + def GetGameRecDataMatchEx(self, recType, valueList, findone=False): + '''获取记录类型对应的匹配value值记录 + @param recType: 记录类型 + @param valueList: [value1, value2, ...] value为None时不判断该值 + @param findone: 是否只匹配一条满足的记录 + @return: recData or [recData, ...] or None + ''' + if recType not in self.recTypeDict: + return + recDataDict = self.recTypeDict[recType] + for recID in recDataDict.keys(): + matchRet = self.GetGameRecDataMatch(recType, recID, valueList, findone) + if matchRet: + return matchRet + return + + def GetGameRecDataFirst(self, recType, recID, isAddNew): + ## 获取记录类型对应的第一条记录,适用于仅需一条的记录类型 + # @param isAddNew: 没有记录时是否添加一条新记录,一般获取后需要更新数据的可以设置为True,仅判断用的建议设置为False,减少产生多余空数据 + recData = None + recDataList = self.GetGameRecDataList(recType, recID) + if recDataList: + recData = recDataList[0] + elif isAddNew: + recData = self.AddGameRecData(recType, recID) + return recData + def GetGameRecDataList(self, recType, recID): ## 获取记录类型对应记录列表 [recData, ...] if recType not in self.recTypeDict: diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py index 54f790c..4cd71d1 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py @@ -97,7 +97,6 @@ import IpyGameDataPY import PlayerFamilyParty import PlayerFamilyZhenfa -import PlayerFamilyEmblem import GameWorldFamilyWar import GameWorldArena import CrossLuckyCloudBuy @@ -396,12 +395,8 @@ AuctionHouse.OnAuctionItemMinuteProcess(tick) #福地 GameWorldMineArea.OnProcessOnMinute() - #每5分钟触发一次仙盟总战力更新 - if curMinute % 5 == 0: - PlayerFamily.UpdFamilyTotalFightPower() - PlayerFamilyRedPacket.CheckDelRedpacketData() - PlayerFamilyEmblem.CheckExpireEmblem() - + #仙盟 + PlayerFamily.OnMinuteProcess(curMinute) return def CheckServerHasPlayerLoginAfterInitOK(): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py index d5d148a..b711674 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py @@ -646,6 +646,54 @@ ("dict", "ScoreAwardEx", 0), ), + "ActTimeFlow":( + ("DWORD", "FlowID", 1), + ("BYTE", "StartDay", 0), + ("BYTE", "StartHour", 0), + ("BYTE", "StartMinute", 0), + ("BYTE", "EndDay", 0), + ("BYTE", "EndHour", 0), + ("BYTE", "EndMinute", 0), + ("WORD", "StateValue", 0), + ), + + "ActBillboardAwardTemp":( + ("DWORD", "TemplateID", 1), + ("BYTE", "Rank", 0), + ("DWORD", "NeedValue", 0), + ("dict", "ValueAwardEx", 0), + ("list", "AwardItemList", 0), + ("list", "LeaderAwardItemList", 0), + ("list", "EliteAwardItemList", 0), + ), + + "ActGuess":( + ("DWORD", "TemplateID", 1), + ("DWORD", "AwardID", 0), + ("list", "RightRankList", 0), + ("list", "AwardItemList", 0), + ), + + "CrossActFamilyGCZ":( + ("DWORD", "CfgID", 1), + ("char", "ActGroupName", 0), + ("BYTE", "ZoneID", 0), + ("list", "ServerIDRangeList", 0), + ("char", "StartDate", 0), + ("char", "EndDate", 0), + ("BYTE", "JoinFamilyCnt", 0), + ("WORD", "ActFlowID", 0), + ("WORD", "GuessTemplateID", 0), + ("WORD", "PersonalTemplateID", 0), + ("WORD", "FamilyTemplateID", 0), + ), + + "CrossActFamilyGCZCampLV":( + ("DWORD", "CampLV", 1), + ("DWORD", "LVUPNeedExp", 0), + ("DWORD", "AddHPPer", 0), + ), + "ActXianXiaMJ":( ("DWORD", "CfgID", 1), ("list", "PlatformList", 0), @@ -2141,6 +2189,79 @@ def GetNeedScore(self): return self.attrTuple[3] # 上榜所需积分 DWORD def GetScoreAwardEx(self): return self.attrTuple[4] # 达标积分额外奖励 {积分:[[物品ID,个数,是否拍品], ...], ...} dict +# 活动时间流程表 +class IPY_ActTimeFlow(): + + def __init__(self): + self.attrTuple = None + return + + def GetFlowID(self): return self.attrTuple[0] # DWORD + def GetStartDay(self): return self.attrTuple[1] # 开始天 BYTE + def GetStartHour(self): return self.attrTuple[2] # 开始时 BYTE + def GetStartMinute(self): return self.attrTuple[3] # 开始分 BYTE + def GetEndDay(self): return self.attrTuple[4] # 结束天 BYTE + def GetEndHour(self): return self.attrTuple[5] # 结束时 BYTE + def GetEndMinute(self): return self.attrTuple[6] # 结束分 BYTE + def GetStateValue(self): return self.attrTuple[7] # 状态值 WORD + +# 活动榜单奖励模版表 +class IPY_ActBillboardAwardTemp(): + + def __init__(self): + self.attrTuple = None + return + + def GetTemplateID(self): return self.attrTuple[0] # 模板编号 DWORD + def GetRank(self): return self.attrTuple[1] # 名次 BYTE + def GetNeedValue(self): return self.attrTuple[2] # 上榜所需值 DWORD + def GetValueAwardEx(self): return self.attrTuple[3] # 达标值额外奖励 {值:[[物品ID,个数,是否拍品], ...], ...} dict + def GetAwardItemList(self): return self.attrTuple[4] # 奖励物品列表[[物品ID,个数,是否拍品], ...] list + def GetLeaderAwardItemList(self): return self.attrTuple[5] # 仙盟榜盟主奖励物品信息列表[[物品ID,个数,是否拍品], ...] list + def GetEliteAwardItemList(self): return self.attrTuple[6] # 仙盟榜精英奖励物品信息列表[[物品ID,个数,是否拍品], ...] list + +# 活动竞猜表 +class IPY_ActGuess(): + + def __init__(self): + self.attrTuple = None + return + + def GetTemplateID(self): return self.attrTuple[0] # 模板编号 DWORD + def GetAwardID(self): return self.attrTuple[1] # 奖励ID DWORD + def GetRightRankList(self): return self.attrTuple[2] # 猜对名次列表 list + def GetAwardItemList(self): return self.attrTuple[3] # 对应奖励列表 [[物品ID,个数,是否拍品], ...] list + +# 仙盟攻城战活动表 +class IPY_CrossActFamilyGCZ(): + + def __init__(self): + self.attrTuple = None + return + + def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD + def GetActGroupName(self): return self.attrTuple[1] # 活动组名(同组活动的名字需相同) char + def GetZoneID(self): return self.attrTuple[2] # 组内分组编号 BYTE + def GetServerIDRangeList(self): return self.attrTuple[3] # 活动的服务器ID范围列表 [[serverIDA, serverIDB], ...] list + def GetStartDate(self): return self.attrTuple[4] # 开启日期 char + def GetEndDate(self): return self.attrTuple[5] # 结束日期 char + def GetJoinFamilyCnt(self): return self.attrTuple[6] # 参与仙盟数 BYTE + def GetActFlowID(self): return self.attrTuple[7] # 活动流程ID,对应H.活动时间流程表 WORD + def GetGuessTemplateID(self): return self.attrTuple[8] # 竞猜奖励模版,对应H.活动竞猜表 WORD + def GetPersonalTemplateID(self): return self.attrTuple[9] # 个人伤害排行奖励模版,对应H.活动榜单奖励模版表 WORD + def GetFamilyTemplateID(self): return self.attrTuple[10] # 仙盟积分排行奖励模版,对应H.活动榜单奖励模版表 WORD + +# 仙盟攻城战大本营等级表 +class IPY_CrossActFamilyGCZCampLV(): + + def __init__(self): + self.attrTuple = None + return + + def GetCampLV(self): return self.attrTuple[0] # 大本营等级 DWORD + def GetLVUPNeedExp(self): return self.attrTuple[1] # 升下一级所需经验 DWORD + def GetAddHPPer(self): return self.attrTuple[2] # 生命累计总加成百分比 DWORD + # 仙匣秘境活动时间表 class IPY_ActXianXiaMJ(): @@ -3111,6 +3232,11 @@ self.__LoadFileData("ActGubaoBillTemp", onlyCheck) self.__LoadFileData("CrossActLianqi", onlyCheck) self.__LoadFileData("ActLianqiBillTemp", onlyCheck) + self.__LoadFileData("ActTimeFlow", onlyCheck) + self.__LoadFileData("ActBillboardAwardTemp", onlyCheck) + self.__LoadFileData("ActGuess", onlyCheck) + self.__LoadFileData("CrossActFamilyGCZ", onlyCheck) + self.__LoadFileData("CrossActFamilyGCZCampLV", onlyCheck) self.__LoadFileData("ActXianXiaMJ", onlyCheck) self.__LoadFileData("CrossActXianXiaMJ", onlyCheck) self.__LoadFileData("ActXianXiaMJBillTemp", onlyCheck) @@ -3795,6 +3921,41 @@ self.CheckLoadData("ActLianqiBillTemp") return self.ipyActLianqiBillTempCache[index] + def GetActTimeFlowCount(self): + self.CheckLoadData("ActTimeFlow") + return self.ipyActTimeFlowLen + def GetActTimeFlowByIndex(self, index): + self.CheckLoadData("ActTimeFlow") + return self.ipyActTimeFlowCache[index] + + def GetActBillboardAwardTempCount(self): + self.CheckLoadData("ActBillboardAwardTemp") + return self.ipyActBillboardAwardTempLen + def GetActBillboardAwardTempByIndex(self, index): + self.CheckLoadData("ActBillboardAwardTemp") + return self.ipyActBillboardAwardTempCache[index] + + def GetActGuessCount(self): + self.CheckLoadData("ActGuess") + return self.ipyActGuessLen + def GetActGuessByIndex(self, index): + self.CheckLoadData("ActGuess") + return self.ipyActGuessCache[index] + + def GetCrossActFamilyGCZCount(self): + self.CheckLoadData("CrossActFamilyGCZ") + return self.ipyCrossActFamilyGCZLen + def GetCrossActFamilyGCZByIndex(self, index): + self.CheckLoadData("CrossActFamilyGCZ") + return self.ipyCrossActFamilyGCZCache[index] + + def GetCrossActFamilyGCZCampLVCount(self): + self.CheckLoadData("CrossActFamilyGCZCampLV") + return self.ipyCrossActFamilyGCZCampLVLen + def GetCrossActFamilyGCZCampLVByIndex(self, index): + self.CheckLoadData("CrossActFamilyGCZCampLV") + return self.ipyCrossActFamilyGCZCampLVCache[index] + def GetActXianXiaMJCount(self): self.CheckLoadData("ActXianXiaMJ") return self.ipyActXianXiaMJLen diff --git a/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py b/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py index 6ca8e2a..e354686 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py @@ -31,6 +31,8 @@ import ChMapToGamePyPack import CrossRealmMsg import PlayerControl +import ChPlayer +import ShareDefine #------------------------------------------------------------------------------- #---全局变量--- @@ -241,6 +243,34 @@ SendFakePack(curPlayer, clientPack) return +def SendFakePackByCross(onlinePlayerIDDict, clientPack): + '''由跨服服务器直接给子服在线玩家发送封包,适用于接受的玩家封包数据一致的 + @param onlinePlayerIDDict: 在线玩家GroupID字典 {playerID:groupID, ...} + 功能自行通过 onlineMgr = ChPlayer.GetOnlinePlayerMgr() 过滤 + onlineMgr.GetOLPlayerServerGroupID(playerID) 获取ServerGroupID + ''' + if not onlinePlayerIDDict: + return + innerPackData = clientPack.GetBuffer() + dataMsg = {"playerIDList":onlinePlayerIDDict.keys(), "innerPackData":innerPackData} + CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_SendFakePack, dataMsg, onlinePlayerIDDict.values()) + return + +def CrossServerMsg_SendFakePack(msgData): + ## 子服收到由跨服直接发送给玩家的封包 + playerIDList = msgData["playerIDList"] + innerPackData = msgData["innerPackData"] + + playerManager = GameWorld.GetPlayerManager() + for playerID in playerIDList: + curPlayer = playerManager.FindPlayerByID(playerID) + if curPlayer == None: + continue + if PlayerControl.GetIsTJG(curPlayer): + continue + curPlayer.Sync_GeneralPack(len(innerPackData), innerPackData) + + return #------------------------------------------------------------------------------- #---Py封包注册信息 PyPackTable = ReadPyPackTable("PyNetPack") diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py index 5232ad5..a260ded 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py @@ -81,6 +81,7 @@ import PlayerRecData import GameWorship import GameXiangong +import CrossFamilyGCZ #--------------------------------------------------------------------- #--------------------------------------------------------------------- @@ -95,6 +96,8 @@ return def IsOnline(self, playerID): return playerID in self.onlinePlayerDict + + def GetOLPlayerServerGroupID(self, playerID): return self.onlinePlayerDict.get(playerID, 0) def __SetOnline(self, playerID, serverGroupID): self.onlinePlayerDict[playerID] = serverGroupID @@ -287,6 +290,8 @@ CrossBattlefield.OnPlayerLogin(curPlayer) #跨服排位 CrossChampionship.OnPlayerLogin(curPlayer, tick) + #仙盟攻城战 + CrossFamilyGCZ.OnPlayerLogin(curPlayer) #跨服全民充值 CrossActAllRecharge.OnPlayerLogin(curPlayer) #跨服妖魔boss @@ -708,6 +713,8 @@ CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PlayerPackDataState, syncStateInfo, [serverGroupID]) GameXiangong.OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID) + #仙盟攻城战 + CrossFamilyGCZ.OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID) # 下线 else: diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py index 7dbf112..d070849 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py @@ -167,7 +167,9 @@ if curPlayer == None: continue PlayerControl.SetCrossMapID(curPlayer, 0) - + else: + CrossRealmMsg.OnCrossServerStateOpen() + GameWorld.GetGameWorld().SendCrossServerStateToLoginServer(isOpen) # 通知地图 GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossServerOpen, isOpen) diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py index 674d42a..e103424 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py @@ -195,6 +195,8 @@ Def_ActHorsePetTrainAwardC = "ActHorsePetTrainAwardC_%s" #跨服炼器结算状态,参数(zoneID) Def_ActLianqiAwardC = "ActLianqiAwardC_%s" +#活动流程状态是否已经异常 - 按流程走的活动只能按状态顺序执行,不能跳状态,否则视为活动异常,参数(actName, zoneID),存储的值为异常的活动ID +Def_ActFlowStateError = "SE%s%s" def SetInitOpenServerTime(initTime): openDatetime = GameWorld.ChangeTimeNumToDatetime(initTime) @@ -268,7 +270,7 @@ # @param value 设置value # @return 返回trig # @remarks 函数详细说明. -def SetDBGSTrig_ByKey( key , value ): +def SetDBGSTrig_ByKey( key , value): gsEventTrigManager = GameWorld.GetGameWorld().GetDBGameServerEventTrigManager() trig = gsEventTrigManager.Find( key ) diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py index d9af3a4..ff60117 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py @@ -44,6 +44,8 @@ import PlayerFamilySWRH import PlayerViewCache import GameWorldBoss +import CrossRealmMsg +import CrossFamilyGCZ import AuctionHouse import PlayerAssist import PlayerTalk @@ -61,6 +63,62 @@ ImpeachLastTime # 弹劾需要持续的时间 ) = range(3) +class FamilyMgr(): + + def __init__(self): + self.sortFamilyIDList = [] #本服仙盟排序顺序 [familyID, ...] + self.fightPowerChangeFamilyIDList = [] # 仙盟成员战力有变更的仙盟ID [familyID, ...] + + #这里仅针对增改信息,删除的另外处理,因为删除的需要确保成功删除,所以需要入库未成功删除的记录 + #而变更同步的会定时同步,每次重连服务器也会强制同步,所以不需要有成功回复 + self.syncCrossFamilyDict = {} # 需要同步跨服的仙盟 {familyID:[需要同步的成员ID, ...], ...} + return + + def OnDeleteFamilyID(self, familyID): + if familyID in self.sortFamilyIDList: + self.sortFamilyIDList.remove(familyID) # 直接从排序列表中移除, 不需要重新排序 + self.SetSyncCrossFamilyDel(familyID) # 解散仙盟 + return + + def GetFamilyIDRank(self, familyID): + if familyID not in self.sortFamilyIDList: + return len(self.sortFamilyIDList) + 1 + return self.sortFamilyIDList.index(familyID) + 1 + + def AddFamilyIDToFightPowerChangeList(self, familyID, playerID=0): + if familyID not in self.fightPowerChangeFamilyIDList: + self.fightPowerChangeFamilyIDList.append(familyID) + GameWorld.DebugLog("仙盟战力变更待处理列表: fightPowerChangeFamilyIDList=%s" % self.fightPowerChangeFamilyIDList) + self.SetSyncCrossFamilyUpd(familyID, playerID) # 仙盟战力变更、成员战力变更 + return + + def SetSyncCrossFamilyUpd(self, familyID, playerID=0, syncNow=False): + if familyID not in self.syncCrossFamilyDict: + self.syncCrossFamilyDict[familyID] = [] + if playerID: + needSyncMemIDList = self.syncCrossFamilyDict[familyID] + if playerID not in needSyncMemIDList: + needSyncMemIDList.append(playerID) + # 变更数据是否立即同步跨服,否则等待定时同步即可 + if syncNow: + Sync_ClientFamilyUpdToCrossServer() + return + + def SetSyncCrossFamilyDel(self, familyID, playerID=0): + ## 设置同步跨服服务器仙盟删除 + # @param playerID: 如果有值代表仅成员删除 + valueSetList = [playerID] + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + gameRecMgr.AddGameRecData(ShareDefine.Def_GameRecType_FamilyDelSyncCross, familyID, valueSetList) + Sync_ClientFamilyDelToCrossServer() # 删除的立马同步 + return + +def GetFamilyMgr(): + mgr = PyGameData.g_familyMgr + if not mgr: + mgr = FamilyMgr() + PyGameData.g_familyMgr = mgr + return mgr ## ------------------ 仙盟 ---------------------- ## 仙盟联赛排名 @@ -71,6 +129,7 @@ def SetFamilyTotalFightPower(curFamily, totalFightPower): curFamily.SetExtra4(totalFightPower / ChConfig.Def_PerPointValue) curFamily.SetExtra5(totalFightPower % ChConfig.Def_PerPointValue) + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID()) # 仙盟战力变更 return def GetFamilyTotalFightPowerByID(familyID): family = GameWorld.GetFamilyManager().FindFamily(familyID) @@ -79,7 +138,10 @@ return GetFamilyTotalFightPower(family) # 徽章ID def GetFamilyEmblemID(curFamily): return curFamily.GetExtra6() -def SetFamilyEmblemID(curFamily, emblemID): return curFamily.SetExtra6(emblemID) +def SetFamilyEmblemID(curFamily, emblemID): + curFamily.SetExtra6(emblemID) + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID()) # 徽章变更 + return # 公告修改次数 def GetFamilyBroadcastCnt(curFamily): return curFamily.GetExtra3() @@ -108,11 +170,17 @@ def OnGameServerInitOK(): ## 服务器启动成功处理 - DoFamilySort() + if GameWorld.IsCrossServer(): + pass + else: + DoFamilySort() return def OnMixServerInit(): ## 合服后首次启动成功处理 + + if GameWorld.IsCrossServer(): + return # 仙盟联赛重置 GameWorldFamilyWar.DoFamilyWarReset() @@ -440,7 +508,7 @@ #加入家族 familyMember = curFamily.AddMember(jionPlayer) #刷新基本信息 - RefreshFamilyMemberBaseMsg(familyMember, jionPlayer) + RefreshFamilyMemberBaseMsg(curFamily, familyMember, jionPlayer) #族长设置 if jionFamilySetLv == IPY_GameServer.fmlLeader: @@ -486,7 +554,7 @@ #仙盟拍品 AuctionHouse.Sync_FamilyAuctionItemInfo(jionPlayer, curFamily.GetID()) SetMemberFightPower(familyMember, PlayerControl.GetFightPower(jionPlayer)) - AddFamilyIDToFightPowerChangeList(curFamily.GetID()) + GetFamilyMgr().AddFamilyIDToFightPowerChangeList(curFamily.GetID(), jionPlayer.GetPlayerID()) #通知仙盟盛宴题目 PlayerFamilyParty.NotifyFamilyPartyQuestion(jionPlayer) @@ -678,7 +746,7 @@ # @remarks 通知客户端服务器家族信息 def Sync_AllFamilyInfo(curPlayer, viewPage, pageCnt=ChConfig.Def_ViewAllFamilyPageCount, sortRule=IPY_GameServer.fsrHornor): #familyCount = GameWorld.GetFamilyManager().GetCount() - familyCount = len(PyGameData.g_sortFamilyIDList) + familyCount = len(GetFamilyMgr().sortFamilyIDList) allPageCnt = GameWorld.GetIntUpper(familyCount, pageCnt) if allPageCnt != 0 and (viewPage < 0 or viewPage >= allPageCnt): @@ -716,7 +784,8 @@ return def Sync_PyAllFamilyInfo(curPlayer, allPageCnt, viewPage, startIndex, endIndex): - familyCount = len(PyGameData.g_sortFamilyIDList) + sortFamilyIDList = GetFamilyMgr().sortFamilyIDList + familyCount = len(sortFamilyIDList) if startIndex < 0 or endIndex >= familyCount: return @@ -727,7 +796,7 @@ familyViewPack.CurPage = viewPage familyViewPack.Family = [] for i in xrange(startIndex, endIndex + 1): - familyID = PyGameData.g_sortFamilyIDList[i] + familyID = sortFamilyIDList[i] family = familyMgr.FindFamily(familyID) if not family: continue @@ -785,7 +854,7 @@ familyViewPack.TotalCount = 1 #familyViewPack.CurPage = viewPage familyViewPack.Family = [] - for i, familyID in enumerate(PyGameData.g_sortFamilyIDList): + for i, familyID in enumerate(GetFamilyMgr().sortFamilyIDList): family = familyMgr.FindFamily(familyID) if not family: continue @@ -822,7 +891,7 @@ familyViewPack.TotalCount = 1 #familyViewPack.CurPage = viewPage familyViewPack.Family = [] - for i, familyID in enumerate(PyGameData.g_sortFamilyIDList): + for i, familyID in enumerate(GetFamilyMgr().sortFamilyIDList): family = familyMgr.FindFamily(familyID) if not family: continue @@ -908,6 +977,7 @@ continue curPlayer.ChatMi(notifyPlayer, 1, pack.GetMsg(), 0, PlayerTalk.GetTalkExtraValue(curPlayer)) PyDataManager.GetContactsManager().AddContactsBoth(curPlayer.GetID(), notifyPlayer.GetID()) + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID()) # 公告变更 return ## 检测目标玩家是否可以加入家族 @@ -1696,11 +1766,12 @@ PlayerFamilyAction.DelFamilyOfficerModelEquip(curFamily.GetID(), leavePlayerID) # 玩家战盟名变更处理 __OnFamilyNameChange(leavePlayerID, '') - AddFamilyIDToFightPowerChangeList(curFamily.GetID()) + GetFamilyMgr().AddFamilyIDToFightPowerChangeList(curFamily.GetID(), leavePlayerID) PlayerViewCache.OnPlayerFamilyChange(leavePlayerID, 0, "") PlayerAssist.OnPlayerLeaveFamily(curFamily.GetID(), leavePlayerID, tagPlayer) if leavePlayerID in PyGameData.g_autoViceleaderDict.get(curFamily.GetID(),[]): PyGameData.g_autoViceleaderDict[curFamily.GetID()].remove(leavePlayerID) + GetFamilyMgr().SetSyncCrossFamilyDel(curFamily.GetID(), leavePlayerID) # 成员离开、踢出 return #////////////////////////////////////////////////////////////// @@ -1845,7 +1916,7 @@ SetMemberFightPower(curMember, fightPower) GameWorld.DebugLog("仙盟成员战力变更 familyID=%s,fightPower=%s" % (familyID, fightPower), playerID) - AddFamilyIDToFightPowerChangeList(familyID) + GetFamilyMgr().AddFamilyIDToFightPowerChangeList(familyID, playerID) return ## A4 07 升级家族#tagCGFamilyLVUp @@ -1954,6 +2025,7 @@ #世界服务器家族重新排序 #GameWorld.GetFamilyManager().SortByLV() DoFamilySort() # 升级直接强排一次 + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID(), syncNow=True) # 仙盟等级变更 return True #--------------------------------------------------------------------- @@ -2002,6 +2074,8 @@ # @remarks 函数详细说明. def OnPlayerChangeMap(curPlayer, tick): #同步给玩家, 最新的家族信息(家族等级刷新) + if GameWorld.IsCrossServer(): + return curPlayer.MapServer_FamilyRefresh() return @@ -2151,7 +2225,7 @@ # @param curPlayer 真实玩家 # @return None # @remarks 刷新家族成员基本信息 -def RefreshFamilyMemberBaseMsg(curMember, curPlayer): +def RefreshFamilyMemberBaseMsg(curFamily, curMember, curPlayer): curMember.SetName(curPlayer.GetName()) curMember.SetLV(curPlayer.GetLV()) curMember.SetReincarnationLv(curPlayer.GetReincarnationLv()) @@ -2160,6 +2234,7 @@ curMember.SetOfficialRank(curPlayer.GetOfficialRank()) curMember.SetFace(curPlayer.GetFace()) curMember.SetFacePic(curPlayer.GetFacePic()) + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID(), curPlayer.GetPlayerID()) # 成员基础信息刷新,含加入仙盟刷新 return #--------------------------------------------------------------------- ## 玩家刷新 @@ -2174,9 +2249,9 @@ if curMember == None: return - RefreshFamilyMemberBaseMsg(curMember, curPlayer) - #家族长境界 family = curPlayer.GetFamily() + RefreshFamilyMemberBaseMsg(family, curMember, curPlayer) + #家族长境界 if family.GetLeaderID() == curPlayer.GetID(): family.SetLeaderOfficialRank(curPlayer.GetOfficialRank()) return @@ -2292,8 +2367,7 @@ #重新排序家族 #GameWorld.GetFamilyManager().SortByLV() - if familyID in PyGameData.g_sortFamilyIDList: - PyGameData.g_sortFamilyIDList.remove(familyID) # 直接从排序列表中移除, 不需要重新排序 + GetFamilyMgr().OnDeleteFamilyID(familyID) #家族科技删除, 改为地图直接处理, 暂屏蔽 #PlayerFamilyTech.DelFamilyTechData(familyID) @@ -2322,6 +2396,7 @@ #设置族长权限 ChangeFamilyMemberLv(familyMember, IPY_GameServer.fmlLeader) GameWorldFamilyWar.OnChangeFamilyLeader(curFamily.GetID(), familyMember.GetPlayerID()) + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamily.GetID(), syncNow=True) # 盟主变更 return #--------------------------------------------------------------------- ##更改家族成员等级. @@ -2353,6 +2428,8 @@ # 变为普通成员,删除模型装备信息 elif changeFamilyLV == IPY_GameServer.fmlMember: PlayerFamilyAction.DelFamilyOfficerModelEquip(familyMember.GetFamilyID(), familyMember.GetPlayerID()) + + GetFamilyMgr().SetSyncCrossFamilyUpd(familyMember.GetFamilyID(), familyMember.GetPlayerID(), syncNow=True) # 成员职位变更 return #--------------------------------------------------------------------- @@ -2531,6 +2608,7 @@ #通知家族刷新 curFamily.Broadcast_FamilyChange() + GetFamilyMgr().SetSyncCrossFamilyUpd(curFamilyID, syncNow=True) # 仙盟改名 playerManager = GameWorld.GetPlayerManager() #仙盟联赛 @@ -2711,6 +2789,8 @@ # @return 返回值无意义 # @remarks 家族过天 def FamilyOnDay(tick): + if GameWorld.IsCrossServer(): + return #---设置所有玩家可以再次加入家族--- GameWorld.GetPlayerManager().ClearForbiddenEnterFamily() #---扣除地图上所有家族的维护费--- @@ -2769,6 +2849,8 @@ return def FamilyOnDayEx(tick): + if GameWorld.IsCrossServer(): + return familyManager = GameWorld.GetFamilyManager() for i in range(0, familyManager.GetCount()): family = familyManager.GetAt(i) @@ -2784,7 +2866,8 @@ # @return 返回值无意义 # @remarks 家族过周 def FamilyOnWeek(tick): - + if GameWorld.IsCrossServer(): + return #---计算上周家族活跃度--- familyManager = GameWorld.GetFamilyManager() for i in range(0, familyManager.GetCount()): @@ -2816,6 +2899,8 @@ return def FamilyOnHour(): + if GameWorld.IsCrossServer(): + return familyManager = GameWorld.GetFamilyManager() for i in xrange(familyManager.GetCount()): family = familyManager.GetAt(i) @@ -2885,12 +2970,31 @@ return cmp(GetMemberJoinTime(member1), GetMemberJoinTime(member2)) return ret +def SortCrossFamily(serverIDList, top=0): + ''' 跨服仙盟排序, 排序规则: 总战力 > 等级 > ID + @param serverIDList: 仙盟所属区服ID范围列表 + @param top: 返回排序靠前x个仙盟,0则全部返回 + ''' + familyList = [] + familyManager = GameWorld.GetFamilyManager() + for i in xrange(familyManager.GetCount()): + family = familyManager.GetAt(i) + serverID = family.GetServerID() + if not GameWorld.CheckServerIDInList(serverID, serverIDList): + continue + familyList.append(family) + familyList.sort(key=lambda f: (GetFamilyTotalFightPower(f), f.GetLV(), f.GetID()), reverse=True) + totalCnt = len(familyList) + return familyList[:top] if top else familyList, totalCnt + #--------------------------------------------------------------------- ##通知地图服务器, 玩家家族属性刷新 # @param curFamily 家族实例 # @return 返回值无意义 # @remarks IPY_MFamilyRefresh def SendPack_MapServer_PlayerFamilyRefresh(curFamily): + if GameWorld.IsCrossServer(): + return #=============================================================================== # 当家族以下权限变更时要通知地图服务器 IPY_MFamilyRefresh # GetFamilyLV @@ -3534,21 +3638,30 @@ break return leaderLV -def AddFamilyIDToFightPowerChangeList(familyID): - if familyID not in PyGameData.g_fightPowerChangeFamilyIDList: - PyGameData.g_fightPowerChangeFamilyIDList.append(familyID) - GameWorld.DebugLog("仙盟战力变更待处理列表: fightPowerChangeFamilyIDList=%s" % PyGameData.g_fightPowerChangeFamilyIDList) +def OnMinuteProcess(curMinute): + if GameWorld.IsCrossServer(): + return + + #每5分钟触发一次仙盟更新 + if curMinute % 5 != 0: + return + + UpdFamilyTotalFightPower() + PlayerFamilyRedPacket.CheckDelRedpacketData() + PlayerFamilyEmblem.CheckExpireEmblem() + Sync_ClientFamilyUpdToCrossServer() return def UpdFamilyTotalFightPower(): ## 更新仙盟总战力 - if not PyGameData.g_fightPowerChangeFamilyIDList: + mgr = GetFamilyMgr() + if not mgr.fightPowerChangeFamilyIDList: #GameWorld.DebugLog("不需要更新仙盟总战力!") return - GameWorld.DebugLog("更新仙盟总战力 fightPowerChangeFamilyIDList=%s" % PyGameData.g_fightPowerChangeFamilyIDList) + GameWorld.DebugLog("更新仙盟总战力 fightPowerChangeFamilyIDList=%s" % mgr.fightPowerChangeFamilyIDList) familyManager = GameWorld.GetFamilyManager() - for familyID in PyGameData.g_fightPowerChangeFamilyIDList: + for familyID in mgr.fightPowerChangeFamilyIDList: family = familyManager.FindFamily(familyID) if not family: continue @@ -3560,19 +3673,17 @@ SetFamilyTotalFightPower(family, totalFightPower) GameWorld.DebugLog(" familyID=%s,totalFightPower=%s" % (familyID, totalFightPower)) - PyGameData.g_fightPowerChangeFamilyIDList = [] + mgr.fightPowerChangeFamilyIDList = [] DoFamilySort(False) # 此处必须为False return True -def GetSortFamilyIDList(): return PyGameData.g_sortFamilyIDList +def GetSortFamilyIDList(): return GetFamilyMgr().sortFamilyIDList def GetFamilyIDRank(familyID): '''获取仙盟的排名, 注意与联赛排名区分 每个仙盟一定有排名,但是不一定有联赛排名,联赛排名只是决定仙盟最终排名的一个比较因素 ''' - if familyID not in PyGameData.g_sortFamilyIDList: - return len(PyGameData.g_sortFamilyIDList) + 1 - return PyGameData.g_sortFamilyIDList.index(familyID) + 1 + return GetFamilyMgr().GetFamilyIDRank(familyID) def DoFamilySort(isUpdTotalFightPower=True): ''' 仙盟排序, 排序规则: 联赛评级 > 总战力 > 等级 > 创建时间 @@ -3590,12 +3701,13 @@ familyList.append(family) familyList.sort(cmp=CmpFamilySort) - PyGameData.g_sortFamilyIDList = [] + mgr = GetFamilyMgr() + mgr.sortFamilyIDList = [] for i, family in enumerate(familyList, 1): GameWorld.DebugLog(" i=%s,warRank=%s,fightPower=%s,LV=%s,CreateTime=%s,familyID=%s" % (i, GetFamilyWarRank(family), GetFamilyTotalFightPower(family), family.GetLV(), family.GetCreateTime(), family.GetID())) - PyGameData.g_sortFamilyIDList.append(family.GetID()) - GameWorld.DebugLog(" sortFamilyIDList=%s" % PyGameData.g_sortFamilyIDList) + mgr.sortFamilyIDList.append(family.GetID()) + GameWorld.DebugLog(" sortFamilyIDList=%s" % mgr.sortFamilyIDList) return def CmpFamilySort(family1, family2): @@ -3836,6 +3948,17 @@ ##-------------------------------------------------------------------------------------------------- +def CrossServerMsg_FamilyDelRet(msgData): + ## 跨服仙盟删除结果,有收到结果即代表成功 + familyID = msgData["familyID"] + playerID = msgData.get("playerID", 0) + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + if playerID: + gameRecMgr.DelGameRecDataByTypeValue(ShareDefine.Def_GameRecType_FamilyDelSyncCross, [playerID], familyID) + else: + gameRecMgr.DelGameRecDataByTypeID(ShareDefine.Def_GameRecType_FamilyDelSyncCross, familyID) + return + def GetFamilyBillboardInfo(curFamily): ## 获取仙盟榜单信息 区服ID、徽章、仙盟名、盟主名、仙盟总战力、仙盟等级 familyID = curFamily.GetID() @@ -3851,3 +3974,222 @@ return {"id":familyID, "name":name, "id2":id2, "name2":name2, "value1":value1, "value2":value2, "value3":value3, "value4":value4, "value5":value5} +def Sync_ClientFamilyUpdToCrossServer(): + ## 定时同步仙盟变更数据到跨服服务器 + + Sync_ClientFamilyDelToCrossServer() # 防止未删除成功,这里补通知 + + mgr = GetFamilyMgr() + if not mgr.syncCrossFamilyDict: + return + + familyManager = GameWorld.GetFamilyManager() + for familyID, updMemIDList in mgr.syncCrossFamilyDict.items(): + family = familyManager.FindFamily(familyID) + if not family: + continue + Send_ClientServerMsg_SyncFamilyInfo("FamilyUpd", GetSyncCrossServerFamilyInfo(family, updMemIDList)) + + mgr.syncCrossFamilyDict = {} + return + +def Sync_ClientFamilyAllToCrossServer(): + ## 同步子服所有仙盟信息到跨服 + + if GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_SyncFamilyAllToCross): + return + GameWorld.GetGameWorld().SetDict(ChConfig.Def_WorldKey_SyncFamilyAllToCross, 1) + GameWorld.Log("开始同步本服所有仙盟到跨服服务器!") + + Sync_ClientFamilyDelToCrossServer() # 防止未删除成功,这里补通知 + + familyManager = GameWorld.GetFamilyManager() + for i in xrange(familyManager.GetCount()): + family = familyManager.GetAt(i) + if not family: + continue + Send_ClientServerMsg_SyncFamilyInfo("FamilyUpd", GetSyncCrossServerFamilyInfo(family)) + return + +def Sync_ClientFamilyDelToCrossServer(): + ## 同步仙盟删除数据到跨服服务器 + gameRecMgr = PyDataManager.GetDBGameRecDataManager() + recDataDict = gameRecMgr.GetGameRecDataDict(ShareDefine.Def_GameRecType_FamilyDelSyncCross) + for familyID, recDataList in recDataDict.items(): + for recData in recDataList: + playerID = recData.GetValue1() + Send_ClientServerMsg_SyncFamilyInfo("FamilyDel", {"familyID":familyID, "playerID":playerID}) + return + +def GetCrossFamilyBaseInfo(family): + return {"ID": family.GetID(), "Name": family.GetName(), "LV":family.GetLV(), "FightPower":GetFamilyTotalFightPower(family), + "LeaderID": family.GetLeaderID(), "LeaderName": family.GetLeaderName(), "EmblemID":GetFamilyEmblemID(family), + "ServerID":family.GetServerID(), "Broadcast":family.GetBroadcast()} + +def GetCrossFamilyMemInfo(member): + return {"Name":member.GetName(), "LV":member.GetLV(), "Job":member.GetJob(), "OfficialRank":member.GetOfficialRank(), + "Face":member.GetFace(), "FacePic":member.GetFacePic(), "FamilyLV":member.GetFamilyLV(), "FightPower":GetMemberFightPower(member)} + +def GetSyncCrossServerFamilyInfo(family, memIDList=None): + ## 获取仙盟跨服所需信息 + # @param memIDList: 需要获取成员信息ID列表,不传则取所有成员 + + crossFamilyInfo = GetCrossFamilyBaseInfo(family) + + memAll = True if memIDList == None else False + memInfo = {} + for m in xrange(family.GetCount()): + member = family.GetAt(m) + memID = member.GetPlayerID() + if not memID: + continue + if memIDList and memID not in memIDList: + continue + memInfo[memID] = GetCrossFamilyMemInfo(member) + + crossFamilyInfo.update({"memInfo":memInfo, "memAll":memAll}) + return crossFamilyInfo + +def Send_ClientServerMsg_SyncFamilyInfo(syncType, syncInfo): + dataMsg = {"syncType":syncType, "syncInfo":syncInfo} + CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_SyncFamilyInfo, dataMsg) + return + +def ClientServerMsg_SyncFamilyInfo(serverGroupID, msgData): + ## 收到子服 - 仙盟信息 + + syncType = msgData["syncType"] + syncInfo = msgData["syncInfo"] + + if syncType == "FamilyUpd": + __CrossServer_FamilyUpd(syncInfo) + + elif syncType == "FamilyDel": + __CrossServer_FamilyDel(serverGroupID, syncInfo) + + return + +def __CrossServer_FamilyDel(serverGroupID, syncInfo): + ## 跨服服务器删除子服仙盟、成员 + familyID = syncInfo["familyID"] + playerID = syncInfo.get("playerID", 0) + if playerID: + curFamily = GameWorld.GetFamilyManager().FindFamily(familyID) + if curFamily: + curFamily.DeleteMember(playerID) + else: + #删除家族 + GameWorld.GetFamilyManager().DelFamily(familyID) + #删除家族行为数据 + PlayerFamilyAction.ClearFamilyAction(familyID) + + # 直接回复就是删除成功 + CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FamilyDelRet, syncInfo, [serverGroupID]) + return + +def __CrossServer_FamilyUpd(familyInfo): + ## 跨服服务器更新子服仙盟 - 这里只覆盖更新,不考虑删除的情况 + + familyID = familyInfo["ID"] + familyName = familyInfo["Name"] + curFamily = FindAndFixCrossFamilyByIDName(familyID, familyName) + if not curFamily: + GameWorld.ErrLog("跨服更新仙盟失败! 仙盟不存在或者创建失败! familyID=%s" % familyID) + return + + #curFamily.SetName(familyInfo["Name"]) # 这里不再更新名称 + curFamily.SetLV(familyInfo["LV"]) + SetFamilyTotalFightPower(curFamily, familyInfo["FightPower"]) + curFamily.SetLeaderID(familyInfo["LeaderID"]) + curFamily.SetLeaderName(familyInfo["LeaderName"]) + SetFamilyEmblemID(curFamily, familyInfo["EmblemID"]) + curFamily.SetServerID(familyInfo["ServerID"]) + curFamily.SetBroadcast(familyInfo["Broadcast"]) + + updMemIDList = [] + memAll = familyInfo.get("memAll", False) + memInfoDict = familyInfo.get("memInfo", {}) + if memInfoDict: + for m in range(curFamily.GetCount())[::-1]: + member = curFamily.GetAt(m) + memID = member.GetPlayerID() + if not memID: + continue + if memID not in memInfoDict: + if memAll: + curFamily.DeleteMember(memID) + continue + memInfo = memInfoDict.pop(memID) + __updCrossFamilyMemberInfo(curFamily, member, memInfo) + updMemIDList.append(memID) + + # 剩下的就是新增的成员 + for memID, memInfo in memInfoDict.items(): + member = curFamily.AddMemberEx(memID) + if not member: + continue + __updCrossFamilyMemberInfo(curFamily, member, memInfo) + updMemIDList.append(memID) + + # 相关活动数据更新 + CrossFamilyGCZ.OnCrossJoinFamilyMemberUpd(curFamily, updMemIDList) + return + +def FindAndFixCrossFamilyByIDName(familyID, familyName): + ## 按仙盟名及ID查找跨服仙盟,重名时系统会自动修改仙盟名 + + familyManager = GameWorld.GetFamilyManager() + curFamily = familyManager.FindFamily(familyID) + if not curFamily: + for i in range(100): + crossFamilyName = familyName if i == 0 else ("%s_%s" % (familyName, i)) + curFamily = familyManager.AddFamilyEx(crossFamilyName, familyID) + if curFamily: + GameWorld.DebugLog("跨服添加新仙盟! familyID=%s, i=%s" % (familyID, i)) + break + return curFamily + + # 验证当前名字是否还是唯一的,因为延迟同步的原因,仙盟可能改名时在本服唯一,但是在跨服不唯一 + nameFamily = familyManager.FindFamilyByName(familyName) + if not nameFamily: + GameWorld.DebugLog("新同步的名字已经不存在仙盟了,可直接替换新仙盟名! familyID=%s" % familyID) + curFamily.SetName(familyName) + return curFamily + + if nameFamily.GetID() == familyID: + #GameWorld.DebugLog("还是自己原来的仙盟名,直接返回! familyID=%s" % familyID) + return curFamily + + # 尝试修改仙盟名,如果没有唯一名,则不修改保留最后一次同步的仙盟名,至少最后一次的名字还是唯一的 + for i in range(1, 100): + fixFamilyName = "%s_%s" % (familyName, i) + family = familyManager.FindFamilyByName(fixFamilyName) + if family: + if family.GetID() == familyID: + #GameWorld.DebugLog("保留原系统修改的仙盟名! familyID=%s" % familyID) + break + # 已存在该仙盟名,且不是自己的仙盟 + continue + curFamily.SetName(fixFamilyName) + GameWorld.Log("跨服强制修改仙盟名: familyID=%s,%s,%s" % (familyID, i, fixFamilyName)) + break + + return curFamily + +def __updCrossFamilyMemberInfo(curFamily, member, memInfo): + member.SetName(memInfo.get("Name", "")) + member.SetLV(memInfo.get("LV", 1)) + member.SetJob(memInfo.get("Job", 1)) + member.SetOfficialRank(memInfo.get("OfficialRank", 1)) + member.SetFace(memInfo.get("Face", 0)) + member.SetFacePic(memInfo.get("FacePic", 0)) + SetMemberFightPower(member, memInfo.get("FightPower", 0)) + memFamilyLV = memInfo.get("FamilyLV", 0) + member.SetFamilyLV(memFamilyLV) + if memFamilyLV == IPY_GameServer.fmlLeader: + curFamily.SetLeaderID(member.GetPlayerID()) + curFamily.SetLeaderName(member.GetName()) + curFamily.SetLeaderOfficialRank(member.GetOfficialRank()) + + return + diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py index a4c6352..c892648 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py @@ -77,6 +77,7 @@ import CrossChampionship import CrossBattlefield import CrossActAllRecharge +import CrossFamilyGCZ import PlayerActGubao import PlayerActHorsePetTrain import PlayerActLianqi @@ -1052,6 +1053,16 @@ return resultName = '%s' % ret + # 仙盟攻城战 + if callName == "FamilyGCZ": + curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID) + if not curPlayer: + return + ret = CrossFamilyGCZ.MapServer_FamilyGCZ(curPlayer, eval(resultName)) + if ret == None: + return + resultName = '%s' % ret + # 仙盟珍宝阁 if callName =="FamilyZhenbaoge": curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID) diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py index dcadebf..e087772 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py @@ -132,10 +132,14 @@ PlayerPackData.DelOutofTimePackData() + onlineMgr = ChPlayer.GetOnlinePlayerMgr() pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager() playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict for playerID, viewCache in playerViewCachePyDict.items(): if IsSaveDBViewCache(viewCache): + continue + if onlineMgr.IsOnline(playerID): + #在线的先不删除 continue playerViewCachePyDict.pop(playerID) @@ -234,24 +238,28 @@ def GetSyncCrossCacheBase(curPlayer): ## 获取同步跨服基础查看缓存,主要用于个别功能需要提前先同步玩家基础缓存到跨服,因为跨服不一定有玩家缓存,需要提前同步 - playerID = curPlayer.GetPlayerID() + if isinstance(curPlayer, int): + playerID = curPlayer + curPlayer = None + else: + playerID = curPlayer.GetPlayerID() cacheDict = GetCachePropDataDict(FindViewCache(playerID)) cacheBase = { - "AccID":curPlayer.GetAccID(), - "LV":curPlayer.GetLV(), - "RealmLV":curPlayer.GetOfficialRank(), - "Job":curPlayer.GetJob(), - "VIPLV":curPlayer.GetVIPLv(), - "Name":CrossRealmPlayer.GetCrossPlayerName(curPlayer), - "Face":curPlayer.GetFace(), - "FacePic":curPlayer.GetFacePic(), - "FamilyID":curPlayer.GetFamilyID(), + "AccID":curPlayer.GetAccID() if curPlayer else cacheDict.get("AccID", ""), + "LV":curPlayer.GetLV() if curPlayer else cacheDict.get("LV", 1), + "RealmLV":curPlayer.GetOfficialRank() if curPlayer else cacheDict.get("RealmLV", 1), + "Job":curPlayer.GetJob() if curPlayer else cacheDict.get("Job", 1), + "VIPLV":curPlayer.GetVIPLv() if curPlayer else cacheDict.get("VIPLV", 0), + "Name":curPlayer.GetName() if curPlayer else cacheDict.get("Name", ""), # 此处不用跨服名称,如前端需要展示跨服名称,可通过ServerID或AccID取得ServerID展示 + "Face":curPlayer.GetFace() if curPlayer else cacheDict.get("Face", 0), + "FacePic":curPlayer.GetFacePic() if curPlayer else cacheDict.get("FacePic", 0), + "FamilyID":curPlayer.GetFamilyID() if curPlayer else cacheDict.get("FacmilyID", 0), "FamilyName":cacheDict.get("FamilyName", ""), "TitleID":cacheDict.get("TitleID", 0), - "FightPower":PlayerControl.GetFightPower(curPlayer), + "FightPower":PlayerControl.GetFightPower(curPlayer) if curPlayer else cacheDict.get("FightPower", 0), "EquipShowSwitch":cacheDict.get("EquipShowSwitch", 0), "EquipShowID":cacheDict.get("EquipShowID", []), - "ServerGroupID":PlayerControl.GetPlayerServerGroupID(curPlayer), + "ServerGroupID":PlayerControl.GetPlayerServerGroupID(curPlayer) if curPlayer else cacheDict.get("ServerGroupID", GameWorld.GetServerGroupID()), } return cacheBase diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py index 32db39d..c2e882c 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py @@ -15,6 +15,7 @@ import GameWorld import PlayerSocial import CrossBillboard +import CrossFamilyGCZ import PlayerFamilyStore import PlayerCompensation import PlayerBourse @@ -39,6 +40,10 @@ import time def GetSavePyData(): + + #存储数据前,一些功能业务数据先转化为存档数据 + CrossFamilyGCZ.OnSavePyData() + pyGameDataMgr = GetPyGameDataManager() result = pyGameDataMgr.GetSaveData() GameWorld.Log("GetSavePyData!! id = %s-%s"%(id(pyGameDataMgr), len(result))) @@ -52,7 +57,12 @@ def LoadPyGameData(gameBuffer, pos): pyGameDataMgr = GetPyGameDataManager() GameWorld.Log("LoadPyGameData!!id = %s %s"%(id(pyGameDataMgr), len(gameBuffer))) - return pyGameDataMgr.LoadGameData(gameBuffer, pos) + pos = pyGameDataMgr.LoadGameData(gameBuffer, pos) + + #加载数据后,一些功能转化为功能业务数据 + CrossFamilyGCZ.OnLoadPyData() + + return pos #协助感谢表 class PlayerAssistThanksPyManager(object): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py index 5c20298..0aef8b5 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py @@ -58,12 +58,13 @@ #请求列表 玩家的AddRequest废弃 g_playerRequests = {} -g_fightPowerChangeFamilyIDList = [] #仙盟成员战力有变更的仙盟ID [familyID, ...] -g_sortFamilyIDList = [] #仙盟排序顺序 [familyID, ...] +g_familyMgr = None # 仙盟管理 g_familyWarFightingIDList = [] # 仙盟联赛中正在战斗中的仙盟ID列表 [familyID, ...] g_familyWarFamilyIDList = [] # 仙盟联赛参赛仙盟ID列表 [familyID, ...] g_familyWarMemDict = {} # 仙盟联赛参赛人员名单 {playerID:memRecData, ...} +g_familyGCZMgr = None + #boss刷新排序列表 g_sortBOSSRefreshList = [] g_swrhJoinRecord = [] #守护人皇家族今日参加记录(已正常结算)[familyID] diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py index 809da18..d28397e 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py @@ -813,8 +813,8 @@ class tagDBCrossBillboard(Structure): _pack_ = 1 _fields_ = [ - ('GroupValue1', ctypes.c_ubyte), - ('GroupValue2', ctypes.c_ubyte), + ('GroupValue1', ctypes.c_ulong), + ('GroupValue2', ctypes.c_ulong), ('BillboardType', ctypes.c_ubyte), ('ID', ctypes.c_ulong), ('ID2', ctypes.c_ulong), @@ -870,8 +870,8 @@ if len(buf) < pos + self.getLength(): return -1 self.clear() - self.GroupValue1, pos = CommFunc.ReadBYTE(buf, pos) - self.GroupValue2, pos = CommFunc.ReadBYTE(buf, pos) + self.GroupValue1, pos = CommFunc.ReadDWORD(buf, pos) + self.GroupValue2, pos = CommFunc.ReadDWORD(buf, pos) self.BillboardType, pos = CommFunc.ReadBYTE(buf, pos) self.ID, pos = CommFunc.ReadDWORD(buf, pos) self.ID2, pos = CommFunc.ReadDWORD(buf, pos) @@ -896,8 +896,8 @@ def getBuffer(self): buf = '' - buf = CommFunc.WriteBYTE(buf, self.GroupValue1) - buf = CommFunc.WriteBYTE(buf, self.GroupValue2) + buf = CommFunc.WriteDWORD(buf, self.GroupValue1) + buf = CommFunc.WriteDWORD(buf, self.GroupValue2) buf = CommFunc.WriteBYTE(buf, self.BillboardType) buf = CommFunc.WriteDWORD(buf, self.ID) buf = CommFunc.WriteDWORD(buf, self.ID2) @@ -921,8 +921,8 @@ def getLength(self): length = 0 - length += sizeof(ctypes.c_ubyte) - length += sizeof(ctypes.c_ubyte) + length += sizeof(ctypes.c_ulong) + length += sizeof(ctypes.c_ulong) length += sizeof(ctypes.c_ubyte) length += sizeof(ctypes.c_ulong) length += sizeof(ctypes.c_ulong) diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py index 25a3322..39d2b8e 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py @@ -364,10 +364,11 @@ CrossActName_Gubao = "CrossActGubao" # 古宝养成 - 跨服 CrossActName_HorsePetTrain = "CrossActHorsePetTrain" # 骑宠养成 - 跨服 CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服 +CrossActName_FamilyGCZ = "CrossActFamilyGCZ" # 仙盟攻城战 #跨服运营活动列表 CrossActNameList = [CrossActName_CTGBillboard, CrossActName_AllRecharge, CrossActName_LuckyCloudBuy, CrossActName_BossTrial, - CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi] + CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi, CrossActName_FamilyGCZ] #需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束 CrossActLockServerGroupIDList = [CrossActName_CTGBillboard, CrossActName_AllRecharge] @@ -375,6 +376,7 @@ ActKey_ID = "ID" # 活动ID,唯一标识的ID,一般是活动开启的time值 ActKey_State = "State" # 活动状态 0-未开启, >0开启中,也代表当日的第几个时间段 ActKey_StateJoin = "StateJoin" # 活动某些功能可参与状态 0-还不可参与, >0可参与,一般可参与时该状态等于state +ActKey_StateError = "StateError" # 按流程走的活动状态是否已异常 ActKey_CfgID = "CfgID" # 活动表配置ID ActKey_ActNum = "ActNum" # 活动分组编号 ActKey_DayIndex = "DayIndex" # 当前活动天索引,0开始,代表第1天 @@ -917,7 +919,10 @@ Def_CBT_HorsePetTrainScore, # 骑宠养成积分 - 个人榜 164 Def_CBT_CrossRealmPK, # 跨服PK竞技场 165 Def_CBT_LianqiScore, # 炼器积分 - 个人榜 166 -) = range(150, 166 + 1) +Def_CBT_FamilyGCZScore, # 仙盟攻城战 - 仙盟积分总榜 167 (zoneID, 0) +Def_CBT_FamilyGCZPlayerHurt, # 仙盟攻城战 - 玩家伤害总榜 168 (zoneID, 0) +Def_CBT_FamilyGCZRoundHurt, # 仙盟攻城战 - 本轮分组仙盟伤害榜 169 (zoneID, batType*100+groupNum) +) = range(150, 169 + 1) #职业对应战力排行榜类型 JobFightPowerBillboardDict = { @@ -1435,7 +1440,12 @@ #通用信息记录类型 - 新 从 300 开始,原通用记录类型最大到255 Def_GameRecTypeList = ( Def_GameRecType_Xiangong, # 仙宫记录 300 - ) = range(300, 1 + 300) + Def_GameRecType_FamilyDelSyncCross, # 仙盟删除同步跨服状态本服记录, familyID 301 + Def_GameRecType_FamilyGCZMgr, # 仙盟攻城战公共管理信息记录, zoneID 302 + Def_GameRecType_FamilyGCZJoinFamily, # 仙盟攻城战参与仙盟信息, zoneID 303 + Def_GameRecType_FamilyGCZJoinMember, # 仙盟攻城战参与成员信息, zoneID 304 + Def_GameRecType_FamilyGCZCityWall, # 仙盟攻城战城池信息, zoneID 305 + ) = range(300, 1 + 305) #通用信息记录新 - 字典key配置,如果有配置,则可额外按对应记录Value值存储字典,方便快速取值,可配置Value编号 1~8,配空默认 Value1 Def_GameRecValueKeyDict = { Def_GameRecType_Xiangong:[1], @@ -1640,6 +1650,7 @@ CrossServerMsg_CrossServerState = "CrossServerState" # 跨服服务器状态变更 CrossServerMsg_PlayerLoginout = "PlayerLoginout" # 玩家上下线状态同步 CrossServerMsg_ExitCrossServer = "ExitCrossServer" # 退出跨服服务器 +CrossServerMsg_SendFakePack = "SendFakePack" # 给子服玩家发送封包 CrossServerMsg_Notify = "Notify" # 提示信息 CrossServerMsg_ChatCrossWorld = "ChatCrossWorld" # 跨服世界聊天 CrossServerMsg_ViewPlayerCacheRet = "ViewPlayerCacheRet"# 查看跨服玩家信息结果 @@ -1693,6 +1704,8 @@ CrossServerMsg_FuncTeamInfo = "FuncTeamInfo" # 功能队伍信息同步 CrossServerMsg_FuncTeamDel = "FuncTeamDel" # 功能队伍删除同步 CrossServerMsg_FuncTeamList = "FuncTeamList" # 功能队伍列表同步 +CrossServerMsg_FamilyDelRet = "FamilyDelRet" # 仙盟删除结果 +CrossServerMsg_FamilyGCZ = "FamilyGCZ" # 仙盟攻城战 # 子服发送跨服信息定义 ClientServerMsg_ServerInitOK = "ServerInitOK" # 子服启动成功 @@ -1742,6 +1755,8 @@ ClientServerMsg_HorsePetTrainScore = "HorsePetTrainScore" # 骑宠养成积分 ClientServerMsg_QueryXiangong = "QueryXiangong" # 查看仙宫仙名录 ClientServerMsg_LianqiScore = "LianqiScore" # 炼器积分 +ClientServerMsg_SyncFamilyInfo = "SyncFamilyInfo" # 仙盟信息同步 +ClientServerMsg_FamilyGCZ = "FamilyGCZ" # 仙盟攻城战 #跨服广播类型定义 CrossNotify_CrossAct = "CrossAct" diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini index 4296654..99d11ac 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini @@ -2012,3 +2012,23 @@ PacketCMD_4=0xB0 PacketSubCMD_4=0x35 PacketCallFunc_4=OnMineHouseKeeperFreeUse + +;仙盟攻城战 +[PlayerActFamilyGCZ] +ScriptName = Player\PlayerActFamilyGCZ.py +Writer = hxp +Releaser = hxp +RegType = 0 +RegisterPackCount = 3 + +PacketCMD_1=0xC1 +PacketSubCMD_1=0x24 +PacketCallFunc_1=OnFamilyGCZContribution + +PacketCMD_2=0xC1 +PacketSubCMD_2=0x25 +PacketCallFunc_2=OnFamilyGCZAtk + +PacketCMD_3=0xC1 +PacketSubCMD_3=0x26 +PacketCallFunc_3=OnFamilyGCZGuess diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py index 4d0d5d4..5687fe6 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py @@ -2327,6 +2327,7 @@ 1000 * 20, # 仙盟充值互助 1000 * 20, # 仙盟珍宝阁 300, # 砍树 + 1000 * 20, # 仙盟攻城战 ] TYPE_Player_Tick_Count = len(TYPE_Player_Tick_Time) @@ -2411,6 +2412,7 @@ TYPE_Player_Tick_FamilyCTGAssist, #仙盟充值互助 TYPE_Player_Tick_FamilyZhenbaoge, #仙盟珍宝阁 TYPE_Player_Tick_CutTree, #砍树 +TYPE_Player_Tick_FamilyGCZ, #仙盟攻城战 ) = range(0, TYPE_Player_Tick_Count) #--------------------------------------------------------------------- @@ -4245,6 +4247,16 @@ #购买次数礼包活动 Def_PDict_BuyCountGiftID = "BuyCountGiftID_%s" # 玩家身上的活动ID,唯一标识,取活动开始日期time,参数(活动编号) Def_PDict_BuyCountGiftAward = "BuyCountGiftAward_%s" # 礼包奖励记录,按位记录是否已领取,参数(活动编号) + +#仙盟攻城战 +Def_PDict_FamilyGCZID = "FamilyGCZID" # 玩家身上的活动ID,唯一标识,取活动开始日期time值 +Def_PDict_FamilyGCZZoneID = "FamilyGCZZoneID" # 参与的分区ID +Def_PDict_FamilyGCZFamilyID = "FamilyGCZFamilyID" # 参与的仙盟ID +Def_PDict_FamilyGCZRoundNum = "FamilyGCZRoundNum" # 记录的轮次 +Def_PDict_FamilyGCZContributionCnt = "FamilyGCZContributionCnt" # 轮次低级捐献次数 +Def_PDict_FamilyGCZEnergy = "FamilyGCZEnergy" # 进攻剩余体力 +Def_PDict_FamilyGCZEnergyTime = "FamilyGCZEnergyTime" # 上次恢复体力时间戳,为0时不再恢复 +Def_PDict_FamilyGCZAwardState = "FamilyGCZAwardState" # 活动奖励领取状态,按二进制位判断是否已领取,0-竞猜奖励;1-个人排行奖励;2-仙盟排名奖励; #------------------------------------------------------------------------------- #开服活动,Def_PDictType_OpenServerCampaign @@ -6178,7 +6190,9 @@ Def_RewardType_OpenServerDailyAward, # 开服每日奖励 76 Def_RewardType_TreasureCntAward, # 寻宝累计次数奖励 77 Def_RewardType_LunhuidianAward, # 轮回殿奖励 78 -)= range(79) +Def_RewardType_RechargeDayAward, # 累充每日奖励 79 +Def_RewardType_FamilyGCZ, # 仙盟攻城战 80 +)= range(81) #boss复活相关活动定义 BossRebornActIDList = ( diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py index 2163321..dec4787 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py @@ -5089,6 +5089,70 @@ #------------------------------------------------------ +# C0 26 仙盟攻城战查询 #tagCGFamilyGCZQuery + +class tagCGFamilyGCZQuery(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("QueryType", c_ubyte), #查询类型:1-成员捐献值;2-进入城池场景;3-退出城池场景;4-进入城池;5-退出城池;6-战报;7-分组仙盟成员伤害; + ("BatType", c_ubyte), #指定战场类型,需要发送的查询类型: 2、4 + ("GroupNum", c_ubyte), #指定分组编号,需要发送的查询类型: 2、4 + ("FamilyID", c_int), #指定仙盟ID或城池ID,查自己盟的可不发,需要发的类型:2、4、6、7 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC0 + self.SubCmd = 0x26 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC0 + self.SubCmd = 0x26 + self.QueryType = 0 + self.BatType = 0 + self.GroupNum = 0 + self.FamilyID = 0 + return + + def GetLength(self): + return sizeof(tagCGFamilyGCZQuery) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 26 仙盟攻城战查询 //tagCGFamilyGCZQuery: + Cmd:%s, + SubCmd:%s, + QueryType:%d, + BatType:%d, + GroupNum:%d, + FamilyID:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.QueryType, + self.BatType, + self.GroupNum, + self.FamilyID + ) + return DumpString + + +m_NAtagCGFamilyGCZQuery=tagCGFamilyGCZQuery() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGFamilyGCZQuery.Cmd,m_NAtagCGFamilyGCZQuery.SubCmd))] = m_NAtagCGFamilyGCZQuery + + +#------------------------------------------------------ # C0 03 强制退出跨服状态 #tagCGForceQuitCrossState class tagCGForceQuitCrossState(Structure): @@ -5245,8 +5309,8 @@ ("Cmd", c_ubyte), ("SubCmd", c_ubyte), ("Type", c_ubyte), #榜单类型 - ("GroupValue1", c_ubyte), # 分组值1 - ("GroupValue2", c_ubyte), # 分组值2,与分组值1组合归为同组榜单数据 + ("GroupValue1", c_int), # 分组值1 + ("GroupValue2", c_int), # 分组值2,与分组值1组合归为同组榜单数据 ("StartIndex", c_int), #查看的起始名次索引, 默认0 ("WatchCnt", c_ubyte), #查看条数,默认20,最大不超过100 ("WatchID", c_int), #查看指定ID名次前后,如玩家ID、家族ID等 @@ -23599,6 +23663,189 @@ #------------------------------------------------------ +# C1 25 仙盟攻城战攻击 #tagCMFamilyGCZAtk + +class tagCMFamilyGCZAtk(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("AtkType", c_ubyte), #攻击类型: 1-普通单攻;2-技能单攻;3-技能群攻; + ("TagCityID", c_int), #目标城池ID,一般是仙盟ID或者特殊城池ID如修罗城城池,普攻单攻需指定目标,群攻技能发0 + ("TagGuardID", c_int), #目标守卫ID,一般是玩家ID或者特殊守卫ID如修罗城守卫,普攻单攻需指定目标,技能攻击发0 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x25 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x25 + self.AtkType = 0 + self.TagCityID = 0 + self.TagGuardID = 0 + return + + def GetLength(self): + return sizeof(tagCMFamilyGCZAtk) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 25 仙盟攻城战攻击 //tagCMFamilyGCZAtk: + Cmd:%s, + SubCmd:%s, + AtkType:%d, + TagCityID:%d, + TagGuardID:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.AtkType, + self.TagCityID, + self.TagGuardID + ) + return DumpString + + +m_NAtagCMFamilyGCZAtk=tagCMFamilyGCZAtk() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZAtk.Cmd,m_NAtagCMFamilyGCZAtk.SubCmd))] = m_NAtagCMFamilyGCZAtk + + +#------------------------------------------------------ +# C1 24 仙盟攻城战捐献 #tagCMFamilyGCZContribution + +class tagCMFamilyGCZContribution(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("ContributionType", c_ubyte), #捐献类型: 0-低级;1-高级 + ("UseCount", c_int), #物品捐献时使用个数 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x24 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x24 + self.ContributionType = 0 + self.UseCount = 0 + return + + def GetLength(self): + return sizeof(tagCMFamilyGCZContribution) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 24 仙盟攻城战捐献 //tagCMFamilyGCZContribution: + Cmd:%s, + SubCmd:%s, + ContributionType:%d, + UseCount:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.ContributionType, + self.UseCount + ) + return DumpString + + +m_NAtagCMFamilyGCZContribution=tagCMFamilyGCZContribution() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZContribution.Cmd,m_NAtagCMFamilyGCZContribution.SubCmd))] = m_NAtagCMFamilyGCZContribution + + +#------------------------------------------------------ +# C1 26 仙盟攻城战竞猜 #tagCMFamilyGCZGuess + +class tagCMFamilyGCZGuess(Structure): + Head = tagHead() + SelectCnt = 0 #(BYTE SelectCnt) + SelectFamilyIDList = list() #(vector<DWORD> SelectFamilyIDList)// 竞猜选择的仙盟ID排名顺序 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC1 + self.Head.SubCmd = 0x26 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.SelectCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.SelectCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.SelectFamilyIDList.append(value) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC1 + self.Head.SubCmd = 0x26 + self.SelectCnt = 0 + self.SelectFamilyIDList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 4 * self.SelectCnt + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.SelectCnt) + for i in range(self.SelectCnt): + data = CommFunc.WriteDWORD(data, self.SelectFamilyIDList[i]) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + SelectCnt:%d, + SelectFamilyIDList:%s + '''\ + %( + self.Head.OutputString(), + self.SelectCnt, + "..." + ) + return DumpString + + +m_NAtagCMFamilyGCZGuess=tagCMFamilyGCZGuess() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMFamilyGCZGuess.Head.Cmd,m_NAtagCMFamilyGCZGuess.Head.SubCmd))] = m_NAtagCMFamilyGCZGuess + + +#------------------------------------------------------ # C1 10 幸运云购购买 #tagCMLuckyCloudBuy class tagCMLuckyCloudBuy(Structure): diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py index 9e7d65d..58ed11c 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py @@ -17027,8 +17027,8 @@ class tagGCCrossBillboardInfo(Structure): Head = tagHead() Type = 0 #(BYTE Type)//榜单类型 - GroupValue1 = 0 #(BYTE GroupValue1)// 分组值1 - GroupValue2 = 0 #(BYTE GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据 + GroupValue1 = 0 #(DWORD GroupValue1)// 分组值1 + GroupValue2 = 0 #(DWORD GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据 WatchID = 0 #(DWORD WatchID)//查看指定ID名次前后,如玩家ID、家族ID等 BillboardCount = 0 #(BYTE BillboardCount) CrossBillboardDataList = list() #(vector<tagGCCrossBillboardData> CrossBillboardDataList) @@ -17044,8 +17044,8 @@ self.Clear() _pos = self.Head.ReadData(_lpData, _pos) self.Type,_pos = CommFunc.ReadBYTE(_lpData, _pos) - self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos) - self.GroupValue2,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupValue1,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.GroupValue2,_pos = CommFunc.ReadDWORD(_lpData, _pos) self.WatchID,_pos = CommFunc.ReadDWORD(_lpData, _pos) self.BillboardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos) for i in range(self.BillboardCount): @@ -17071,8 +17071,8 @@ length = 0 length += self.Head.GetLength() length += 1 - length += 1 - length += 1 + length += 4 + length += 4 length += 4 length += 1 for i in range(self.BillboardCount): @@ -17084,8 +17084,8 @@ data = '' data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) data = CommFunc.WriteBYTE(data, self.Type) - data = CommFunc.WriteBYTE(data, self.GroupValue1) - data = CommFunc.WriteBYTE(data, self.GroupValue2) + data = CommFunc.WriteDWORD(data, self.GroupValue1) + data = CommFunc.WriteDWORD(data, self.GroupValue2) data = CommFunc.WriteDWORD(data, self.WatchID) data = CommFunc.WriteBYTE(data, self.BillboardCount) for i in range(self.BillboardCount): @@ -18518,6 +18518,1750 @@ m_NAtagGCCrossZoneInfo=tagGCCrossZoneInfo() ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossZoneInfo.Cmd,m_NAtagGCCrossZoneInfo.SubCmd))] = m_NAtagGCCrossZoneInfo + + +#------------------------------------------------------ +# C0 24 仙盟攻城战活动信息 #tagGCFamilyGCZActInfo + +class tagGCFamilyGCZActFamily(Structure): + FamilyID = 0 #(DWORD FamilyID) + Name = "" #(char Name[33])//参与仙盟名字 + LV = 0 #(BYTE LV)//仙盟等级 + ServerID = 0 #(DWORD ServerID)//仙盟所属区服ID + EmblemID = 0 #(DWORD EmblemID)//徽章ID + FightPower = 0 #(DWORD FightPower)//仙盟总战力,求余亿部分 + FightPowerEx = 0 #(DWORD FightPowerEx)//仙盟总战力,整除亿部分 + LeaderID = 0 #(DWORD LeaderID)//盟主ID + LeaderName = "" #(char LeaderName[33])//盟主名 + LeaderFace = 0 #(DWORD LeaderFace) + LeaderFacePic = 0 #(DWORD LeaderFacePic) + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.LV,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.EmblemID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderName,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.LeaderFace,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.LeaderFacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.FamilyID = 0 + self.Name = "" + self.LV = 0 + self.ServerID = 0 + self.EmblemID = 0 + self.FightPower = 0 + self.FightPowerEx = 0 + self.LeaderID = 0 + self.LeaderName = "" + self.LeaderFace = 0 + self.LeaderFacePic = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteBYTE(data, self.LV) + data = CommFunc.WriteDWORD(data, self.ServerID) + data = CommFunc.WriteDWORD(data, self.EmblemID) + data = CommFunc.WriteDWORD(data, self.FightPower) + data = CommFunc.WriteDWORD(data, self.FightPowerEx) + data = CommFunc.WriteDWORD(data, self.LeaderID) + data = CommFunc.WriteString(data, 33, self.LeaderName) + data = CommFunc.WriteDWORD(data, self.LeaderFace) + data = CommFunc.WriteDWORD(data, self.LeaderFacePic) + return data + + def OutputString(self): + DumpString = ''' + FamilyID:%d, + Name:%s, + LV:%d, + ServerID:%d, + EmblemID:%d, + FightPower:%d, + FightPowerEx:%d, + LeaderID:%d, + LeaderName:%s, + LeaderFace:%d, + LeaderFacePic:%d + '''\ + %( + self.FamilyID, + self.Name, + self.LV, + self.ServerID, + self.EmblemID, + self.FightPower, + self.FightPowerEx, + self.LeaderID, + self.LeaderName, + self.LeaderFace, + self.LeaderFacePic + ) + return DumpString + + +class tagGCFamilyGCZActInfo(Structure): + Head = tagHead() + ServerInfoLen = 0 #(BYTE ServerInfoLen) + ServerIDRangeInfo = "" #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服 + ZoneID = 0 #(BYTE ZoneID)// 活动分区ID,公示期为0 + ActID = 0 #(DWORD ActID)// 活动ID,代表某一次活动的唯一ID,前端如果有活动相关的本地记录可以通过验证此ID变更进行重置 + StartDate = "" #(char StartDate[10])// 开始日期 y-m-d + EndtDate = "" #(char EndtDate[10])// 结束日期 y-m-d + JoinFamilyCnt = 0 #(BYTE JoinFamilyCnt)// 参与仙盟数 + ActFlowID = 0 #(WORD ActFlowID)// 活动流程ID,对应H.活动时间流程表中的编号,前端根据跨服时间自行计算当前所处流程状态 + GuessTemplateID = 0 #(WORD GuessTemplateID)// 竞猜奖励模版,对应H.活动竞猜表,前端自行读表展示 + PersonalTemplateID = 0 #(WORD PersonalTemplateID)// 个人伤害排行奖励模版,对应H.活动榜单奖励模版表,前端自行读表展示 + FamilyTemplateID = 0 #(WORD FamilyTemplateID)// 仙盟积分排行奖励模版,对应H.活动榜单奖励模版表,前端自行读表展示 + StateError = 0 #(BYTE StateError)// 活动流程状态是否异常,如果不为0代表活动已异常,前端自行决定是不显示活动还是活动页面做提示 + FamilyCount = 0 #(BYTE FamilyCount) + ActFamilyList = list() #(vector<tagGCFamilyGCZActFamily> ActFamilyList)//本分区参与的仙盟名单 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x24 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen) + self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ActID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.JoinFamilyCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.ActFlowID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.GuessTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.PersonalTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.FamilyTemplateID,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.StateError,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.FamilyCount,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyCount): + temActFamilyList = tagGCFamilyGCZActFamily() + _pos = temActFamilyList.ReadData(_lpData, _pos) + self.ActFamilyList.append(temActFamilyList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x24 + self.ServerInfoLen = 0 + self.ServerIDRangeInfo = "" + self.ZoneID = 0 + self.ActID = 0 + self.StartDate = "" + self.EndtDate = "" + self.JoinFamilyCnt = 0 + self.ActFlowID = 0 + self.GuessTemplateID = 0 + self.PersonalTemplateID = 0 + self.FamilyTemplateID = 0 + self.StateError = 0 + self.FamilyCount = 0 + self.ActFamilyList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += len(self.ServerIDRangeInfo) + length += 1 + length += 4 + length += 10 + length += 10 + length += 1 + length += 2 + length += 2 + length += 2 + length += 2 + length += 1 + length += 1 + for i in range(self.FamilyCount): + length += self.ActFamilyList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ServerInfoLen) + data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo) + data = CommFunc.WriteBYTE(data, self.ZoneID) + data = CommFunc.WriteDWORD(data, self.ActID) + data = CommFunc.WriteString(data, 10, self.StartDate) + data = CommFunc.WriteString(data, 10, self.EndtDate) + data = CommFunc.WriteBYTE(data, self.JoinFamilyCnt) + data = CommFunc.WriteWORD(data, self.ActFlowID) + data = CommFunc.WriteWORD(data, self.GuessTemplateID) + data = CommFunc.WriteWORD(data, self.PersonalTemplateID) + data = CommFunc.WriteWORD(data, self.FamilyTemplateID) + data = CommFunc.WriteBYTE(data, self.StateError) + data = CommFunc.WriteBYTE(data, self.FamilyCount) + for i in range(self.FamilyCount): + data = CommFunc.WriteString(data, self.ActFamilyList[i].GetLength(), self.ActFamilyList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ServerInfoLen:%d, + ServerIDRangeInfo:%s, + ZoneID:%d, + ActID:%d, + StartDate:%s, + EndtDate:%s, + JoinFamilyCnt:%d, + ActFlowID:%d, + GuessTemplateID:%d, + PersonalTemplateID:%d, + FamilyTemplateID:%d, + StateError:%d, + FamilyCount:%d, + ActFamilyList:%s + '''\ + %( + self.Head.OutputString(), + self.ServerInfoLen, + self.ServerIDRangeInfo, + self.ZoneID, + self.ActID, + self.StartDate, + self.EndtDate, + self.JoinFamilyCnt, + self.ActFlowID, + self.GuessTemplateID, + self.PersonalTemplateID, + self.FamilyTemplateID, + self.StateError, + self.FamilyCount, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZActInfo=tagGCFamilyGCZActInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZActInfo.Head.Cmd,m_NAtagGCFamilyGCZActInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZActInfo + + +#------------------------------------------------------ +# C0 29 仙盟攻城战城池战斗信息 #tagGCFamilyGCZBatCityInfo + +class tagGCFamilyGCZBatCityInfo(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("CityID", c_int), #城池ID + ("CityLV", c_ubyte), #城池等级 + ("FamilyID", c_int), #所属仙盟ID,可能为0 + ("GuardID", c_int), #当前防守成员ID,为0时表示没有防守成员了,城池已被击毁 + ("HP", c_int), #防守成员剩余生命,求余亿部分,剩余生命为0时代表该防守成员被击败 + ("HPEx", c_int), #防守成员剩余生命,整除亿部分 + ("HPMax", c_int), #防守成员最大生命,求余亿部分 + ("HPMaxEx", c_int), #防守成员最大生命,整除亿部分 + ("AtkPlayerID", c_int), #发起攻击的玩家ID,可能为0,判断是否自己的ID进行相应的攻击表现 + ("AtkRet", c_ubyte), #攻击结果,仅在攻击玩家ID不为0时有效,0--成功;1-目标已被击杀;2-城池已被摧毁;3-其他 + ("KillCnt", c_ubyte), #本次攻击击杀防守人员数 + ("HurtValue", c_int), #伤害飘血,求余亿部分 + ("HurtValueEx", c_int), #伤害飘血,整除亿部分 + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC0 + self.SubCmd = 0x29 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC0 + self.SubCmd = 0x29 + self.CityID = 0 + self.CityLV = 0 + self.FamilyID = 0 + self.GuardID = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.AtkPlayerID = 0 + self.AtkRet = 0 + self.KillCnt = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatCityInfo) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 29 仙盟攻城战城池战斗信息 //tagGCFamilyGCZBatCityInfo: + Cmd:%s, + SubCmd:%s, + CityID:%d, + CityLV:%d, + FamilyID:%d, + GuardID:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + AtkPlayerID:%d, + AtkRet:%d, + KillCnt:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.CityID, + self.CityLV, + self.FamilyID, + self.GuardID, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.AtkPlayerID, + self.AtkRet, + self.KillCnt, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +m_NAtagGCFamilyGCZBatCityInfo=tagGCFamilyGCZBatCityInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatCityInfo.Cmd,m_NAtagGCFamilyGCZBatCityInfo.SubCmd))] = m_NAtagGCFamilyGCZBatCityInfo + + +#------------------------------------------------------ +# C0 25 仙盟攻城战轮次分组信息 #tagGCFamilyGCZBatGroupInfo + +class tagGCFamilyGCZBatGroup(Structure): + GroupNum = 0 #(BYTE GroupNum)// 分组编号,从1开始,对应A + FamilyIDCnt = 0 #(BYTE FamilyIDCnt) + FamilyIDList = list() #(vector<DWORD> FamilyIDList)// 仙盟ID列表,前端可以通过判断参与的仙盟ID是否在某个分组里面验证有没有战场参赛资格 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.GroupNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.FamilyIDCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyIDCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.FamilyIDList.append(value) + return _pos + + def Clear(self): + self.GroupNum = 0 + self.FamilyIDCnt = 0 + self.FamilyIDList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 1 + length += 4 * self.FamilyIDCnt + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.GroupNum) + data = CommFunc.WriteBYTE(data, self.FamilyIDCnt) + for i in range(self.FamilyIDCnt): + data = CommFunc.WriteDWORD(data, self.FamilyIDList[i]) + return data + + def OutputString(self): + DumpString = ''' + GroupNum:%d, + FamilyIDCnt:%d, + FamilyIDList:%s + '''\ + %( + self.GroupNum, + self.FamilyIDCnt, + "..." + ) + return DumpString + + +class tagGCFamilyGCZBat(Structure): + BatType = 0 #(BYTE BatType)// 战场类型 1-初级;2-中级;3-高级; + GroupCnt = 0 #(BYTE GroupCnt)// 分组数 + GroupList = list() #(vector<tagGCFamilyGCZBatGroup> GroupList)// 分组列表 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.BatType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.GroupCnt): + temGroupList = tagGCFamilyGCZBatGroup() + _pos = temGroupList.ReadData(_lpData, _pos) + self.GroupList.append(temGroupList) + return _pos + + def Clear(self): + self.BatType = 0 + self.GroupCnt = 0 + self.GroupList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 1 + for i in range(self.GroupCnt): + length += self.GroupList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.BatType) + data = CommFunc.WriteBYTE(data, self.GroupCnt) + for i in range(self.GroupCnt): + data = CommFunc.WriteString(data, self.GroupList[i].GetLength(), self.GroupList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + BatType:%d, + GroupCnt:%d, + GroupList:%s + '''\ + %( + self.BatType, + self.GroupCnt, + "..." + ) + return DumpString + + +class tagGCFamilyGCZBatGroupInfo(Structure): + Head = tagHead() + RoundNum = 0 #(BYTE RoundNum)// 第x轮的分组,从1开始,没有在对应轮次战场分组里的视为没有该轮次的参赛资格 + BatTypeCnt = 0 #(BYTE BatTypeCnt)// 战场类型数 + BatList = list() #(vector<tagGCFamilyGCZBat> BatList)//战场列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x25 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.RoundNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.BatTypeCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.BatTypeCnt): + temBatList = tagGCFamilyGCZBat() + _pos = temBatList.ReadData(_lpData, _pos) + self.BatList.append(temBatList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x25 + self.RoundNum = 0 + self.BatTypeCnt = 0 + self.BatList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 1 + for i in range(self.BatTypeCnt): + length += self.BatList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.RoundNum) + data = CommFunc.WriteBYTE(data, self.BatTypeCnt) + for i in range(self.BatTypeCnt): + data = CommFunc.WriteString(data, self.BatList[i].GetLength(), self.BatList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + RoundNum:%d, + BatTypeCnt:%d, + BatList:%s + '''\ + %( + self.Head.OutputString(), + self.RoundNum, + self.BatTypeCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatGroupInfo=tagGCFamilyGCZBatGroupInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatGroupInfo.Head.Cmd,m_NAtagGCFamilyGCZBatGroupInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZBatGroupInfo + + +#------------------------------------------------------ +# C0 30 仙盟攻城战战斗战报 #tagGCFamilyGCZBatReport + +class tagGCFamilyGCZBatRepHurt(Structure): + _pack_ = 1 + _fields_ = [ + ("TagFamilyID", c_int), #目标仙盟ID + ("HurtValue", c_int), #输出伤害,求余亿部分 + ("HurtValueEx", c_int), #输出伤害,整除亿部分 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.TagFamilyID = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatRepHurt) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 30 仙盟攻城战战斗战报 //tagGCFamilyGCZBatReport: + TagFamilyID:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.TagFamilyID, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZBatReport(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)// 战报仙盟ID + DefRepCnt = 0 #(BYTE DefRepCnt) + DefRepList = list() #(vector<tagGCFamilyGCZBatRepHurt> DefRepList)// 防守战报 + AtkRepCnt = 0 #(BYTE AtkRepCnt) + AtkRepList = list() #(vector<tagGCFamilyGCZBatRepHurt> AtkRepList)// 进攻战报 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x30 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.DefRepCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.DefRepCnt): + temDefRepList = tagGCFamilyGCZBatRepHurt() + _pos = temDefRepList.ReadData(_lpData, _pos) + self.DefRepList.append(temDefRepList) + self.AtkRepCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.AtkRepCnt): + temAtkRepList = tagGCFamilyGCZBatRepHurt() + _pos = temAtkRepList.ReadData(_lpData, _pos) + self.AtkRepList.append(temAtkRepList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x30 + self.FamilyID = 0 + self.DefRepCnt = 0 + self.DefRepList = list() + self.AtkRepCnt = 0 + self.AtkRepList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + for i in range(self.DefRepCnt): + length += self.DefRepList[i].GetLength() + length += 1 + for i in range(self.AtkRepCnt): + length += self.AtkRepList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteBYTE(data, self.DefRepCnt) + for i in range(self.DefRepCnt): + data = CommFunc.WriteString(data, self.DefRepList[i].GetLength(), self.DefRepList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.AtkRepCnt) + for i in range(self.AtkRepCnt): + data = CommFunc.WriteString(data, self.AtkRepList[i].GetLength(), self.AtkRepList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + DefRepCnt:%d, + DefRepList:%s, + AtkRepCnt:%d, + AtkRepList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.DefRepCnt, + "...", + self.AtkRepCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatReport=tagGCFamilyGCZBatReport() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatReport.Head.Cmd,m_NAtagGCFamilyGCZBatReport.Head.SubCmd))] = m_NAtagGCFamilyGCZBatReport + + +#------------------------------------------------------ +# C0 28 仙盟攻城战城池场景信息 #tagGCFamilyGCZBatSceneInfo + +class tagGCFamilyGCZBatScenePlayer(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33]) + Face = 0 #(DWORD Face) + FacePic = 0 #(DWORD FacePic) + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.Face = 0 + self.FacePic = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteDWORD(data, self.Face) + data = CommFunc.WriteDWORD(data, self.FacePic) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + Face:%d, + FacePic:%d + '''\ + %( + self.PlayerID, + self.Name, + self.Face, + self.FacePic + ) + return DumpString + + +class tagGCFamilyGCZBatSceneHurt(Structure): + _pack_ = 1 + _fields_ = [ + ("CityID", c_int), #被攻击的城池ID + ("HurtValue", c_int), #伤害飘血,求余亿部分 + ("HurtValueEx", c_int), #伤害飘血,整除亿部分 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.CityID = 0 + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatSceneHurt) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 28 仙盟攻城战城池场景信息 //tagGCFamilyGCZBatSceneInfo: + CityID:%d, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.CityID, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZBatSceneCity(Structure): + _pack_ = 1 + _fields_ = [ + ("CityID", c_int), #城池ID + ("CityLV", c_ubyte), #城池等级 + ("FamilyID", c_int), #所属仙盟ID,可能为0 + ("Rank", c_ubyte), #当前名次,从1开始 + ("HP", c_int), #剩余生命,求余亿部分,剩余生命为0时代表被摧毁 + ("HPEx", c_int), #剩余生命,整除亿部分 + ("HPMax", c_int), #最大生命,求余亿部分 + ("HPMaxEx", c_int), #最大生命,整除亿部分 + ("LastAtkedTime", c_int), #最后一次被攻击时间戳,可能为0 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.CityID = 0 + self.CityLV = 0 + self.FamilyID = 0 + self.Rank = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.LastAtkedTime = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZBatSceneCity) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 28 仙盟攻城战城池场景信息 //tagGCFamilyGCZBatSceneInfo: + CityID:%d, + CityLV:%d, + FamilyID:%d, + Rank:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + LastAtkedTime:%d + '''\ + %( + self.CityID, + self.CityLV, + self.FamilyID, + self.Rank, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.LastAtkedTime + ) + return DumpString + + +class tagGCFamilyGCZBatSceneInfo(Structure): + Head = tagHead() + BatType = 0 #(BYTE BatType)// 战场类型 1-初级;2-中级;3-高级; + GroupNum = 0 #(BYTE GroupNum)// 分组编号,从1开始,对应A + TopFamilyID = 0 #(DWORD TopFamilyID)// 伤害第一仙盟ID + TopLeaderID = 0 #(DWORD TopLeaderID)// 伤害第一盟主ID + TopPlayerID = 0 #(DWORD TopPlayerID)// 伤害第一玩家ID + TopPlayerFamilyID = 0 #(DWORD TopPlayerFamilyID)// 伤害第一玩家仙盟ID + AtkPlayerID = 0 #(DWORD AtkPlayerID)// 发起攻击的玩家,可能为0,仅技能攻击时通知,普攻时仅通知血量等信息 + AtkType = 0 #(BYTE AtkType)// 攻击类型,有发起攻击的玩家时有效 + KillCnt = 0 #(BYTE KillCnt)// 本次攻击累计击杀数,有发起攻击的玩家时有效 + HurtCnt = 0 #(BYTE HurtCnt) + HurtList = list() #(vector<tagGCFamilyGCZBatSceneHurt> HurtList)//本次攻击伤血信息,有发起攻击的玩家时有效 + CityCnt = 0 #(BYTE CityCnt) + CityList = list() #(vector<tagGCFamilyGCZBatSceneCity> CityList)// 城池信息,仅通知变化的城池 + PlayerCnt = 0 #(BYTE PlayerCnt) + PlayerInfoList = list() #(vector<tagGCFamilyGCZBatScenePlayer> PlayerInfoList)// 场景展示所需要用到的玩家信息,如第一玩家、使用技能玩家 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x28 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.BatType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.GroupNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.TopFamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopLeaderID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TopPlayerFamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.AtkPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.AtkType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.KillCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.HurtCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.HurtCnt): + temHurtList = tagGCFamilyGCZBatSceneHurt() + _pos = temHurtList.ReadData(_lpData, _pos) + self.HurtList.append(temHurtList) + self.CityCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.CityCnt): + temCityList = tagGCFamilyGCZBatSceneCity() + _pos = temCityList.ReadData(_lpData, _pos) + self.CityList.append(temCityList) + self.PlayerCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.PlayerCnt): + temPlayerInfoList = tagGCFamilyGCZBatScenePlayer() + _pos = temPlayerInfoList.ReadData(_lpData, _pos) + self.PlayerInfoList.append(temPlayerInfoList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x28 + self.BatType = 0 + self.GroupNum = 0 + self.TopFamilyID = 0 + self.TopLeaderID = 0 + self.TopPlayerID = 0 + self.TopPlayerFamilyID = 0 + self.AtkPlayerID = 0 + self.AtkType = 0 + self.KillCnt = 0 + self.HurtCnt = 0 + self.HurtList = list() + self.CityCnt = 0 + self.CityList = list() + self.PlayerCnt = 0 + self.PlayerInfoList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 1 + length += 1 + length += 1 + for i in range(self.HurtCnt): + length += self.HurtList[i].GetLength() + length += 1 + for i in range(self.CityCnt): + length += self.CityList[i].GetLength() + length += 1 + for i in range(self.PlayerCnt): + length += self.PlayerInfoList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.BatType) + data = CommFunc.WriteBYTE(data, self.GroupNum) + data = CommFunc.WriteDWORD(data, self.TopFamilyID) + data = CommFunc.WriteDWORD(data, self.TopLeaderID) + data = CommFunc.WriteDWORD(data, self.TopPlayerID) + data = CommFunc.WriteDWORD(data, self.TopPlayerFamilyID) + data = CommFunc.WriteDWORD(data, self.AtkPlayerID) + data = CommFunc.WriteBYTE(data, self.AtkType) + data = CommFunc.WriteBYTE(data, self.KillCnt) + data = CommFunc.WriteBYTE(data, self.HurtCnt) + for i in range(self.HurtCnt): + data = CommFunc.WriteString(data, self.HurtList[i].GetLength(), self.HurtList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.CityCnt) + for i in range(self.CityCnt): + data = CommFunc.WriteString(data, self.CityList[i].GetLength(), self.CityList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.PlayerCnt) + for i in range(self.PlayerCnt): + data = CommFunc.WriteString(data, self.PlayerInfoList[i].GetLength(), self.PlayerInfoList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + BatType:%d, + GroupNum:%d, + TopFamilyID:%d, + TopLeaderID:%d, + TopPlayerID:%d, + TopPlayerFamilyID:%d, + AtkPlayerID:%d, + AtkType:%d, + KillCnt:%d, + HurtCnt:%d, + HurtList:%s, + CityCnt:%d, + CityList:%s, + PlayerCnt:%d, + PlayerInfoList:%s + '''\ + %( + self.Head.OutputString(), + self.BatType, + self.GroupNum, + self.TopFamilyID, + self.TopLeaderID, + self.TopPlayerID, + self.TopPlayerFamilyID, + self.AtkPlayerID, + self.AtkType, + self.KillCnt, + self.HurtCnt, + "...", + self.CityCnt, + "...", + self.PlayerCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZBatSceneInfo=tagGCFamilyGCZBatSceneInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZBatSceneInfo.Head.Cmd,m_NAtagGCFamilyGCZBatSceneInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZBatSceneInfo + + +#------------------------------------------------------ +# C0 26 仙盟攻城战大本营信息 #tagGCFamilyGCZCampInfo + +class tagGCFamilyGCZCampMem(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33])//参与玩家名字 + FamilyLV = 0 #(BYTE FamilyLV)//参与时的家族职位 + Face = 0 #(DWORD Face)//基本脸型 + FacePic = 0 #(DWORD FacePic)//头像框 + FightPower = 0 #(DWORD FightPower)//战力,求余亿部分 + FightPowerEx = 0 #(DWORD FightPowerEx)//战力,整除亿部分 + HP = 0 #(DWORD HP)//剩余生命,求余亿部分 + HPEx = 0 #(DWORD HPEx)//剩余生命,整除亿部分 + HPMax = 0 #(DWORD HPMax)//最大生命,求余亿部分 + HPMaxEx = 0 #(DWORD HPMaxEx)//最大生命,整除亿部分 + TotalHurt = 0 #(DWORD TotalHurt)//活动总伤害,求余亿部分,如果不在榜上则读该值 + TotalHurtEx = 0 #(DWORD TotalHurtEx)//活动总伤害,整除亿部分 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.FamilyLV,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.Face,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FacePic,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HP,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMax,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMaxEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TotalHurt,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.TotalHurtEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.FamilyLV = 0 + self.Face = 0 + self.FacePic = 0 + self.FightPower = 0 + self.FightPowerEx = 0 + self.HP = 0 + self.HPEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.TotalHurt = 0 + self.TotalHurtEx = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 1 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteBYTE(data, self.FamilyLV) + data = CommFunc.WriteDWORD(data, self.Face) + data = CommFunc.WriteDWORD(data, self.FacePic) + data = CommFunc.WriteDWORD(data, self.FightPower) + data = CommFunc.WriteDWORD(data, self.FightPowerEx) + data = CommFunc.WriteDWORD(data, self.HP) + data = CommFunc.WriteDWORD(data, self.HPEx) + data = CommFunc.WriteDWORD(data, self.HPMax) + data = CommFunc.WriteDWORD(data, self.HPMaxEx) + data = CommFunc.WriteDWORD(data, self.TotalHurt) + data = CommFunc.WriteDWORD(data, self.TotalHurtEx) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + FamilyLV:%d, + Face:%d, + FacePic:%d, + FightPower:%d, + FightPowerEx:%d, + HP:%d, + HPEx:%d, + HPMax:%d, + HPMaxEx:%d, + TotalHurt:%d, + TotalHurtEx:%d + '''\ + %( + self.PlayerID, + self.Name, + self.FamilyLV, + self.Face, + self.FacePic, + self.FightPower, + self.FightPowerEx, + self.HP, + self.HPEx, + self.HPMax, + self.HPMaxEx, + self.TotalHurt, + self.TotalHurtEx + ) + return DumpString + + +class tagGCFamilyGCZCampInfo(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)//所在活动仙盟ID,可能不是玩家当前的仙盟ID,活动以该ID为准 + Score = 0 #(WORD Score)//活动总积分,如果不在榜上则读该值 + CampLV = 0 #(WORD CampLV)//大本营当前等级 + CampExp = 0 #(DWORD CampExp)//大本营当前经验 + CityLV = 0 #(WORD CityLV)//城池属性等级,开战后可能与当前大本营等级不一样 + HPBase = 0 #(DWORD HPBase)//基础生命,求余亿部分 + HPBaseEx = 0 #(DWORD HPBaseEx)//基础生命,整除亿部分 + HPMax = 0 #(DWORD HPMax)//总生命,求余亿部分 + HPMaxEx = 0 #(DWORD HPMaxEx)//总大生命,整除亿部分 + HP = 0 #(DWORD HP)//剩余生命,求余亿部分 + HPEx = 0 #(DWORD HPEx)//剩余生命,整除亿部分 + DefMemCnt = 0 #(BYTE DefMemCnt) + DefMemList = list() #(vector<tagGCFamilyGCZCampMem> DefMemList)//防守成员列表,有同步则差异更新,没有在防守成员里的视为没有参与资格 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x26 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Score,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.CampLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.CampExp,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.CityLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.HPBase,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPBaseEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMax,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPMaxEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HP,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.DefMemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.DefMemCnt): + temDefMemList = tagGCFamilyGCZCampMem() + _pos = temDefMemList.ReadData(_lpData, _pos) + self.DefMemList.append(temDefMemList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x26 + self.FamilyID = 0 + self.Score = 0 + self.CampLV = 0 + self.CampExp = 0 + self.CityLV = 0 + self.HPBase = 0 + self.HPBaseEx = 0 + self.HPMax = 0 + self.HPMaxEx = 0 + self.HP = 0 + self.HPEx = 0 + self.DefMemCnt = 0 + self.DefMemList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 2 + length += 2 + length += 4 + length += 2 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 4 + length += 1 + for i in range(self.DefMemCnt): + length += self.DefMemList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteWORD(data, self.Score) + data = CommFunc.WriteWORD(data, self.CampLV) + data = CommFunc.WriteDWORD(data, self.CampExp) + data = CommFunc.WriteWORD(data, self.CityLV) + data = CommFunc.WriteDWORD(data, self.HPBase) + data = CommFunc.WriteDWORD(data, self.HPBaseEx) + data = CommFunc.WriteDWORD(data, self.HPMax) + data = CommFunc.WriteDWORD(data, self.HPMaxEx) + data = CommFunc.WriteDWORD(data, self.HP) + data = CommFunc.WriteDWORD(data, self.HPEx) + data = CommFunc.WriteBYTE(data, self.DefMemCnt) + for i in range(self.DefMemCnt): + data = CommFunc.WriteString(data, self.DefMemList[i].GetLength(), self.DefMemList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + Score:%d, + CampLV:%d, + CampExp:%d, + CityLV:%d, + HPBase:%d, + HPBaseEx:%d, + HPMax:%d, + HPMaxEx:%d, + HP:%d, + HPEx:%d, + DefMemCnt:%d, + DefMemList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.Score, + self.CampLV, + self.CampExp, + self.CityLV, + self.HPBase, + self.HPBaseEx, + self.HPMax, + self.HPMaxEx, + self.HP, + self.HPEx, + self.DefMemCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZCampInfo=tagGCFamilyGCZCampInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZCampInfo.Head.Cmd,m_NAtagGCFamilyGCZCampInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZCampInfo + + +#------------------------------------------------------ +# C0 27 仙盟攻城战成员贡献值信息 #tagGCFamilyGCZContributionInfo + +class tagGCFamilyGCZContribution(Structure): + _pack_ = 1 + _fields_ = [ + ("PlayerID", c_int), + ("ContributionValue", c_int), #贡献值 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.PlayerID = 0 + self.ContributionValue = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZContribution) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 27 仙盟攻城战成员贡献值信息 //tagGCFamilyGCZContributionInfo: + PlayerID:%d, + ContributionValue:%d + '''\ + %( + self.PlayerID, + self.ContributionValue + ) + return DumpString + + +class tagGCFamilyGCZContributionInfo(Structure): + Head = tagHead() + ContriCnt = 0 #(BYTE ContriCnt) + ContriList = list() #(vector<tagGCFamilyGCZContribution> ContriList)//成员贡献值列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x27 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ContriCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.ContriCnt): + temContriList = tagGCFamilyGCZContribution() + _pos = temContriList.ReadData(_lpData, _pos) + self.ContriList.append(temContriList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x27 + self.ContriCnt = 0 + self.ContriList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + for i in range(self.ContriCnt): + length += self.ContriList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ContriCnt) + for i in range(self.ContriCnt): + data = CommFunc.WriteString(data, self.ContriList[i].GetLength(), self.ContriList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ContriCnt:%d, + ContriList:%s + '''\ + %( + self.Head.OutputString(), + self.ContriCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZContributionInfo=tagGCFamilyGCZContributionInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZContributionInfo.Head.Cmd,m_NAtagGCFamilyGCZContributionInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZContributionInfo + + +#------------------------------------------------------ +# C0 31 仙盟攻城战分组仙盟成员伤害明细 #tagGCFamilyGCZGroupFamilyMemHurtInfo + +class tagGCFamilyGCZGroupFamilyMemHurt(Structure): + PlayerID = 0 #(DWORD PlayerID) + Name = "" #(char Name[33])//参与玩家名字 + HurtValue = 0 #(DWORD HurtValue)//伤害,求余亿部分 + HurtValueEx = 0 #(DWORD HurtValueEx)//伤害,整除亿部分 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.Name,_pos = CommFunc.ReadString(_lpData, _pos,33) + self.HurtValue,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HurtValueEx,_pos = CommFunc.ReadDWORD(_lpData, _pos) + return _pos + + def Clear(self): + self.PlayerID = 0 + self.Name = "" + self.HurtValue = 0 + self.HurtValueEx = 0 + return + + def GetLength(self): + length = 0 + length += 4 + length += 33 + length += 4 + length += 4 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteString(data, 33, self.Name) + data = CommFunc.WriteDWORD(data, self.HurtValue) + data = CommFunc.WriteDWORD(data, self.HurtValueEx) + return data + + def OutputString(self): + DumpString = ''' + PlayerID:%d, + Name:%s, + HurtValue:%d, + HurtValueEx:%d + '''\ + %( + self.PlayerID, + self.Name, + self.HurtValue, + self.HurtValueEx + ) + return DumpString + + +class tagGCFamilyGCZGroupFamilyMemHurtInfo(Structure): + Head = tagHead() + FamilyID = 0 #(DWORD FamilyID)//查看的目标仙盟ID + HurtMemCnt = 0 #(BYTE HurtMemCnt) + HurtMemList = list() #(vector<tagGCFamilyGCZGroupFamilyMemHurt> HurtMemList)//成员伤害明细列表,只算城池被摧毁前的伤害,未排序,前端自己排序 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x31 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.FamilyID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.HurtMemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.HurtMemCnt): + temHurtMemList = tagGCFamilyGCZGroupFamilyMemHurt() + _pos = temHurtMemList.ReadData(_lpData, _pos) + self.HurtMemList.append(temHurtMemList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x31 + self.FamilyID = 0 + self.HurtMemCnt = 0 + self.HurtMemList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + for i in range(self.HurtMemCnt): + length += self.HurtMemList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.FamilyID) + data = CommFunc.WriteBYTE(data, self.HurtMemCnt) + for i in range(self.HurtMemCnt): + data = CommFunc.WriteString(data, self.HurtMemList[i].GetLength(), self.HurtMemList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + FamilyID:%d, + HurtMemCnt:%d, + HurtMemList:%s + '''\ + %( + self.Head.OutputString(), + self.FamilyID, + self.HurtMemCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo=tagGCFamilyGCZGroupFamilyMemHurtInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo.Head.Cmd,m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZGroupFamilyMemHurtInfo + + +#------------------------------------------------------ +# C0 32 仙盟攻城战竞猜名单信息 #tagGCFamilyGCZGuessInfo + +class tagGCFamilyGCZGuessFamily(Structure): + _pack_ = 1 + _fields_ = [ + ("FamilyID", c_int), #备选仙盟ID + ("GuessValue", c_ushort), #竞猜热度值,玩家每次选择则加1,重复选择也算 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.FamilyID = 0 + self.GuessValue = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZGuessFamily) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 32 仙盟攻城战竞猜名单信息 //tagGCFamilyGCZGuessInfo: + FamilyID:%d, + GuessValue:%d + '''\ + %( + self.FamilyID, + self.GuessValue + ) + return DumpString + + +class tagGCFamilyGCZGuessRight(Structure): + _pack_ = 1 + _fields_ = [ + ("AwardID", c_ubyte), #奖励ID + ("RightPlayerCnt", c_ushort), #猜中玩家个数 + ] + + def __init__(self): + self.Clear() + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.AwardID = 0 + self.RightPlayerCnt = 0 + return + + def GetLength(self): + return sizeof(tagGCFamilyGCZGuessRight) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C0 32 仙盟攻城战竞猜名单信息 //tagGCFamilyGCZGuessInfo: + AwardID:%d, + RightPlayerCnt:%d + '''\ + %( + self.AwardID, + self.RightPlayerCnt + ) + return DumpString + + +class tagGCFamilyGCZGuessInfo(Structure): + Head = tagHead() + PlayerID = 0 #(DWORD PlayerID)//竞猜玩家ID,有玩家修改竞猜时会附带该信息,如果是自己ID,则更新自己的竞猜选项,否则无视 + SelectCnt = 0 #(BYTE SelectCnt) + SelectFamilyIDList = list() #(vector<DWORD> SelectFamilyIDList)//竞猜玩家选择的仙盟ID顺序 + FinalCnt = 0 #(BYTE FinalCnt) + FinalFamilyIDList = list() #(vector<DWORD> FinalFamilyIDList)//最终排名顺序,仅活动排名出来后才有值 + RightCnt = 0 #(BYTE RightCnt) + RightInfoList = list() #(vector<tagGCFamilyGCZGuessRight> RightInfoList)//猜中个数明细列表 + FamilyCnt = 0 #(BYTE FamilyCnt) + GuessFamilyList = list() #(vector<tagGCFamilyGCZGuessFamily> GuessFamilyList)//备选仙盟名单列表 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x32 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.SelectCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.SelectCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.SelectFamilyIDList.append(value) + self.FinalCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FinalCnt): + value,_pos=CommFunc.ReadDWORD(_lpData,_pos) + self.FinalFamilyIDList.append(value) + self.RightCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.RightCnt): + temRightInfoList = tagGCFamilyGCZGuessRight() + _pos = temRightInfoList.ReadData(_lpData, _pos) + self.RightInfoList.append(temRightInfoList) + self.FamilyCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.FamilyCnt): + temGuessFamilyList = tagGCFamilyGCZGuessFamily() + _pos = temGuessFamilyList.ReadData(_lpData, _pos) + self.GuessFamilyList.append(temGuessFamilyList) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xC0 + self.Head.SubCmd = 0x32 + self.PlayerID = 0 + self.SelectCnt = 0 + self.SelectFamilyIDList = list() + self.FinalCnt = 0 + self.FinalFamilyIDList = list() + self.RightCnt = 0 + self.RightInfoList = list() + self.FamilyCnt = 0 + self.GuessFamilyList = list() + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 4 + length += 1 + length += 4 * self.SelectCnt + length += 1 + length += 4 * self.FinalCnt + length += 1 + for i in range(self.RightCnt): + length += self.RightInfoList[i].GetLength() + length += 1 + for i in range(self.FamilyCnt): + length += self.GuessFamilyList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteDWORD(data, self.PlayerID) + data = CommFunc.WriteBYTE(data, self.SelectCnt) + for i in range(self.SelectCnt): + data = CommFunc.WriteDWORD(data, self.SelectFamilyIDList[i]) + data = CommFunc.WriteBYTE(data, self.FinalCnt) + for i in range(self.FinalCnt): + data = CommFunc.WriteDWORD(data, self.FinalFamilyIDList[i]) + data = CommFunc.WriteBYTE(data, self.RightCnt) + for i in range(self.RightCnt): + data = CommFunc.WriteString(data, self.RightInfoList[i].GetLength(), self.RightInfoList[i].GetBuffer()) + data = CommFunc.WriteBYTE(data, self.FamilyCnt) + for i in range(self.FamilyCnt): + data = CommFunc.WriteString(data, self.GuessFamilyList[i].GetLength(), self.GuessFamilyList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + PlayerID:%d, + SelectCnt:%d, + SelectFamilyIDList:%s, + FinalCnt:%d, + FinalFamilyIDList:%s, + RightCnt:%d, + RightInfoList:%s, + FamilyCnt:%d, + GuessFamilyList:%s + '''\ + %( + self.Head.OutputString(), + self.PlayerID, + self.SelectCnt, + "...", + self.FinalCnt, + "...", + self.RightCnt, + "...", + self.FamilyCnt, + "..." + ) + return DumpString + + +m_NAtagGCFamilyGCZGuessInfo=tagGCFamilyGCZGuessInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCFamilyGCZGuessInfo.Head.Cmd,m_NAtagGCFamilyGCZGuessInfo.Head.SubCmd))] = m_NAtagGCFamilyGCZGuessInfo #------------------------------------------------------ @@ -57675,6 +59419,70 @@ #------------------------------------------------------ +# C1 10 仙盟攻城战玩家信息 #tagMCFamilyGCZPlayerInfo + +class tagMCFamilyGCZPlayerInfo(Structure): + _pack_ = 1 + _fields_ = [ + ("Cmd", c_ubyte), + ("SubCmd", c_ubyte), + ("ContributionCnt", c_ubyte), # 轮次低级捐献已捐献次数,轮次变更时会重置 + ("Energy", c_ubyte), # 当前可用免费体力 + ("EnergyTime", c_int), # 上次恢复免费体力时间戳,为0时不再恢复 + ("AwardState", c_int), # 活动奖励领取状态,按二进制位判断是否已领取,0-竞猜奖励;1-个人排行奖励;2-仙盟排名奖励; + ] + + def __init__(self): + self.Clear() + self.Cmd = 0xC1 + self.SubCmd = 0x10 + return + + def ReadData(self, stringData, _pos=0, _len=0): + self.Clear() + memmove(addressof(self), stringData[_pos:], self.GetLength()) + return _pos + self.GetLength() + + def Clear(self): + self.Cmd = 0xC1 + self.SubCmd = 0x10 + self.ContributionCnt = 0 + self.Energy = 0 + self.EnergyTime = 0 + self.AwardState = 0 + return + + def GetLength(self): + return sizeof(tagMCFamilyGCZPlayerInfo) + + def GetBuffer(self): + return string_at(addressof(self), self.GetLength()) + + def OutputString(self): + DumpString = '''// C1 10 仙盟攻城战玩家信息 //tagMCFamilyGCZPlayerInfo: + Cmd:%s, + SubCmd:%s, + ContributionCnt:%d, + Energy:%d, + EnergyTime:%d, + AwardState:%d + '''\ + %( + self.Cmd, + self.SubCmd, + self.ContributionCnt, + self.Energy, + self.EnergyTime, + self.AwardState + ) + return DumpString + + +m_NAtagMCFamilyGCZPlayerInfo=tagMCFamilyGCZPlayerInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCFamilyGCZPlayerInfo.Cmd,m_NAtagMCFamilyGCZPlayerInfo.SubCmd))] = m_NAtagMCFamilyGCZPlayerInfo + + +#------------------------------------------------------ # C1 08 幸运云购玩家信息 #tagMCLuckyCloudBuyPlayerInfo class tagMCLuckyCloudBuyPlayerInfo(Structure): diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/FamilyGCZ.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/FamilyGCZ.py new file mode 100644 index 0000000..fd4d6a0 --- /dev/null +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/FamilyGCZ.py @@ -0,0 +1,75 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package GM.Commands.FamilyGCZ +# +# @todo:仙盟攻城战 +# @author hxp +# @date 2025-04-09 +# @version 1.0 +# +# 详细描述: 仙盟攻城战 +# +#------------------------------------------------------------------------------- +#"""Version = 2025-04-09 16:00""" +#------------------------------------------------------------------------------- + +import ChConfig +import GameWorld +import PlayerControl +import PlayerActFamilyGCZ +import ShareDefine + +#--------------------------------------------------------------------- +#逻辑实现 + +## GM命令执行入口 +# @param curPlayer 当前玩家 +# @param msgList 参数列表 +# @return None +# @remarks 函数详细说明. +def OnExec(curPlayer, msgList): + + if not msgList: + GameWorld.DebugAnswer(curPlayer, "捐献次数: FamilyGCZ j 低级捐献次数") + GameWorld.DebugAnswer(curPlayer, "设置体力: FamilyGCZ e 体力") + GameWorld.DebugAnswer(curPlayer, "成员捐献: FamilyGCZ x 经验 [成员数]") + GameWorld.DebugAnswer(curPlayer, "设大本营: FamilyGCZ c 等级 [经验]") + GameWorld.DebugAnswer(curPlayer, "攻击城池: FamilyGCZ a 城池ID [攻击次数 仙盟ID]") + GameWorld.DebugAnswer(curPlayer, "攻击城池: FamilyGCZ h 城池ID 剩余血量 [攻击方人数 仙盟ID]") + GameWorld.DebugAnswer(curPlayer, "击毁城池: FamilyGCZ k [城池ID 攻击方仙盟ID]") + GameWorld.DebugAnswer(curPlayer, "输出城池: FamilyGCZ p [战场类型 分组编号]") + GameWorld.DebugAnswer(curPlayer, "山寨竞猜: FamilyGCZ g 人数 [竞猜ID1 ID2 ID3]") + GameWorld.DebugAnswer(curPlayer, "城池ID一般等同于仙盟ID,修罗城ID=20亿") + GameWorld.DebugAnswer(curPlayer, "攻击次数默认1自己攻击,大于1仙盟成员轮流攻击") + GameWorld.DebugAnswer(curPlayer, "剩余血量 :由指定的攻击方人数平摊输出,1个时默认自己") + GameWorld.DebugAnswer(curPlayer, "击毁城池没有指定ID时则随机击毁一个") + GameWorld.DebugAnswer(curPlayer, "攻击方仙盟ID有值可指定A盟攻击B盟") + GameWorld.DebugAnswer(curPlayer, "攻击方仙盟ID没填则A盟默认自己盟") + return + + playerID = curPlayer.GetPlayerID() + value = msgList[0] + + # 捐献次数 + if value == "j": + contriCnt = msgList[1] if len(msgList) > 1 else 0 + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZContributionCnt, contriCnt) + GameWorld.DebugAnswer(curPlayer, "设置低级捐献次数: %s" % contriCnt) + PlayerActFamilyGCZ.Sync_FamilyGCZPlayerInfo(curPlayer) + return + + # 设置体力 + if value == "e": + setEnergy = msgList[1] if len(msgList) > 1 else 0 + updEnergy = PlayerActFamilyGCZ.SetEnergy(curPlayer, setEnergy) + GameWorld.DebugAnswer(curPlayer, "设置体力: %s" % updEnergy) + return + + if value in ["x", "c", "a", "h", "k", "p", "g"]: + dataMsg = {"ActMsgType":"GMCMD", "playerID":playerID, "msgList":msgList} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + + return diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py index 1dfdf39..fd0fd8c 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py @@ -224,6 +224,47 @@ def IsEventItem(item): return (item.GetType() == ChConfig.Def_ItemType_MissionItem) +def DelPlayerItemByPacks(curPlayer, itemID, delCount, eventName="", saveDataDict={}, + packTypeList=[IPY_GameWorld.rptItem, IPY_GameWorld.rptWarehouse]): + '''扣除玩家物品,从多个背包检查,一般是用于不是立马扣除的逻辑,防止玩家快速把背包物品放入仓库导致扣除失败 + 如跨服功能,有些逻辑需要跨服验证或处理后才进行扣除 + ''' + remainDelCnt = delCount # 剩余需要扣除数量 + for packType in packTypeList: + curPack = curPlayer.GetItemManager().GetPack(packType) + for i in range(0, curPack.GetCount()): + curItem = curPack.GetAt(i) + if curItem.IsEmpty(): + continue + if curItem.GetItemTypeID() != itemID: + continue + if curItem.GetIsLocked(): + continue + + itemCount = GetItemCount(curItem) + + #身上物品比要删除的物品多 + if itemCount > remainDelCnt: + updItemCount = itemCount - remainDelCnt + SetItemCount(curItem, updItemCount) + if ItemNeedRecord(curItem): + itemNoteDict = ItemCommon.GetItemNoteDict(curItem, remainDelCnt, itemCount, updItemCount) + ItemCommon.DR_DelItem(curPlayer, packType, eventName, itemNoteDict, saveDataDict) + remainDelCnt = 0 + else: + if ItemNeedRecord(curItem): + itemNoteDict = ItemCommon.GetItemNoteDict(curItem, itemCount, itemCount, 0) + ItemCommon.DR_DelItem(curPlayer, packType, eventName, itemNoteDict, saveDataDict) + curItem.Clear() + remainDelCnt -= itemCount + + if remainDelCnt <= 0: + return True + + GameWorld.ErrLog("扣除物品失败,物品不足! itemID=%s,delCount=%s,remainDelCnt=%s,eventName=%s" + % (itemID, delCount, remainDelCnt, eventName), curPlayer.GetPlayerID()) + return False + ## 删除物品 # @param curPlayer 当前玩家 # @param packindex 背包索引 @@ -2534,7 +2575,7 @@ return True -def GivePlayerItemOrMail(curPlayer, itemList, mailKey=None, event=["", False, {}], isNotifyAward=True): +def GivePlayerItemOrMail(curPlayer, itemList, mailKey=None, event=["", False, {}], isNotifyAward=True, notifyDataEx=None): ##给物品,背包满则发邮件 if not itemList: return @@ -2570,7 +2611,7 @@ if isNotifyAward: eventName = event[0] if event else "" - NotifyGiveAwardInfo(curPlayer, giveItemList, eventName) + NotifyGiveAwardInfo(curPlayer, giveItemList, eventName, dataEx=notifyDataEx) return def NotifyGiveAwardInfo(curPlayer, giveItemInfo, eventName="", exp=0, moneyInfo=None, dataEx=None): diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py index 6df29d6..4ed2bea 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py @@ -170,6 +170,7 @@ import PlayerActLoginNew import PlayerActBuyCountGift import PlayerActLunhuidian +import PlayerActFamilyGCZ import PlayerActYunshi import PlayerActTask @@ -1006,6 +1007,7 @@ PlayerCutTree.OnPlayerLogin(curPlayer) PlayerMineArea.OnPlayerLogin(curPlayer) PlayerGuaji.OnPlayerLogin(curPlayer) + PlayerActFamilyGCZ.OnPlayerLogin(curPlayer) # 上线查询一次充值订单 curPlayer.SendDBQueryRecharge() @@ -5706,6 +5708,9 @@ # 仙盟充值互助活动奖励 elif rewardType == ChConfig.Def_RewardType_FamilyCTGAssist: PlayerActFamilyCTGAssist.GetFamilyCTGAssistAward(curPlayer, dataEx, dataExStr) + # 仙盟攻城战活动奖励 + elif rewardType == ChConfig.Def_RewardType_FamilyGCZ: + PlayerActFamilyGCZ.GetFamilyGCZAward(curPlayer, dataEx, tick) # 天道树奖励 elif rewardType == ChConfig.Def_RewardType_TiandaoTree: PlayerXiangong.GetTiandaoTreeAward(curPlayer, dataEx) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py index 0245418..3e623b8 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py @@ -206,6 +206,19 @@ return actInfo return {} +def GetCrossActInfoByZoneID(actName, zoneID): + ## 根据分区获取跨服对应的跨服活动信息 + actInfoDict = PyGameData.g_crossActInfoDict.get(actName, {}) + if not actInfoDict: + return {} + for actInfo in actInfoDict.values(): + if not actInfo.get(ShareDefine.ActKey_State, 0): + continue + ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {}) + if zoneID == ipyDataDict.get("ZoneID", 0): + return actInfo + return {} + def NotifyCrossActEnd(curPlayer, actName): '''通知跨服运营活动结束 防止跨服服务器与子服时间不一致导致可能出现活动实际已关闭 diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActFamilyGCZ.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActFamilyGCZ.py new file mode 100644 index 0000000..4c3d753 --- /dev/null +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActFamilyGCZ.py @@ -0,0 +1,525 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package Player.PlayerActFamilyGCZ +# +# @todo:仙盟攻城战 +# @author hxp +# @date 2025-04-09 +# @version 1.0 +# +# 详细描述: 仙盟攻城战 +# +#------------------------------------------------------------------------------- +#"""Version = 2025-04-09 16:00""" +#------------------------------------------------------------------------------- + +import ChConfig +import GameWorld +import ShareDefine +import IpyGameDataPY +import NetPackCommon +import CrossRealmPlayer +import ChPyNetSendPack +import IPY_GameWorld +import PlayerControl +import ItemControler +import ItemCommon + +import time + +## 1-公示期;99-领奖期;轮次状态=轮次*10+轮次阶段;轮次阶段:1-分组战备;2-战斗;3-休战 +FamilyGCZState_Publicity = 1 # 公示期 +FamilyGCZState_Award = 99 # 结束领奖期 + +# 轮次状态信息 +FamilyGCZRoundState_Group = 1 # 分组+战备 +FamilyGCZRoundState_Fight = 2 # 战斗 +FamilyGCZRoundState_Over = 3 # 休战结算 + +# 攻击类型 +( +AtkType_Normal, # 普通单攻 1 +AtkType_SkillSingle, # 技能单攻 2 +AtkType_SkillArea, # 技能群攻 3 +) = range(1, 1 + 3) + +def GetRoundState(state): + ## 获取轮次、状态信息 + if state < 10 or state == FamilyGCZState_Award: + return 0, state + return state / 10, state % 10 + +def SendToGameServer_FamilyGCZ(curPlayer, msgType, dataMsg=""): + playerID = curPlayer.GetPlayerID() + msgList = str([msgType, dataMsg]) + GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, "FamilyGCZ", msgList, len(msgList)) + GameWorld.DebugLog("仙盟攻城战发送GameServer: %s, %s" % (msgType, dataMsg), playerID) + return + +def GameServer_FamilyGCZ(curPlayer, msgData, tick): + ## 收到GameServer攻城战信息 + curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_FamilyGCZ, 0) + + msgType, dataMsg, ret = msgData + + if not ret: + return + + if msgType == "FamilyGCZPlayerActInfo": + __CheckPlayerFamilyGCZByCrossGameServer(curPlayer, dataMsg) + + elif msgType == "FamilyGCZAtkResult": + __OnFamilyGCZAtkResult(curPlayer, dataMsg) + + elif msgType == "FamilyGCZAward": + __OnFamilyGCZAward(curPlayer, dataMsg) + + return + +def OnPlayerLogin(curPlayer): + __CheckPlayerFamilyGCZByMapServer(curPlayer) + return + +def RefreshActFamilyGCZInfo(): + ## 收到GameServer同步的活动信息,刷新活动信息 + playerManager = GameWorld.GetPlayerManager() + for index in xrange(playerManager.GetPlayerCount()): + curPlayer = playerManager.GetPlayerByIndex(index) + if not GameWorld.IsNormalPlayer(curPlayer): + continue + + __CheckPlayerFamilyGCZByMapServer(curPlayer) + + return + +def __CheckPlayerFamilyGCZByMapServer(curPlayer): + ## 本服地图仅检查结束重置即可 + + playerID = curPlayer.GetPlayerID() + playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZID) + playerZoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZZoneID) + playerRoundNum = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZRoundNum) + + actInfo = CrossRealmPlayer.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, playerZoneID) + actID = actInfo.get(ShareDefine.ActKey_ID, 0) + state = actInfo.get(ShareDefine.ActKey_State, 0) + if not playerActID and not playerZoneID: + GameWorld.DebugLog("仙盟攻城战活动玩家没有活动数据不需要重置! playerZoneID=%s,playerActID=%s" % (playerZoneID, playerActID), playerID) + if state: + roundNum, _ = GetRoundState(state) + if roundNum and roundNum != playerRoundNum: + __doPlayerRoundChange(curPlayer, playerRoundNum, roundNum) + return + + ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {}) + zoneID = ipyDataDict.get("ZoneID", 0) + + if state and playerActID == actID and playerZoneID == zoneID: + GameWorld.DebugLog("仙盟攻城战活动玩家正常活动中不需要重置! playerZoneID=%s,playerActID=%s,state=%s" % (playerZoneID, playerActID, state), playerID) + return + GameWorld.DebugLog("仙盟攻城战活动玩家重置End! zoneID=%s,actID=%s,playerZoneID=%s,playerActID=%s,state=%s" + % (zoneID, actID, playerZoneID, playerActID, state), playerID) + + __doPlayerFamilyGCZReset(curPlayer) + return + +def __CheckPlayerFamilyGCZByCrossGameServer(curPlayer, joinInfo): + '''检查玩家参与的活动信息,以锁定盟为准的活动统一根据跨服GameServer同步的参与信息处理 + 锁定名单信息都在跨服GameServer,所以跨服GameServer统一管理 + 注:结束重置的在本服地图直接处理即可 + ''' + + playerID = curPlayer.GetPlayerID() + zoneID, familyID = joinInfo + + actInfo = CrossRealmPlayer.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + actID = actInfo.get(ShareDefine.ActKey_ID, 0) + state = actInfo.get(ShareDefine.ActKey_State, 0) + + playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZID) + playerZoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZZoneID) + if playerActID == actID and playerZoneID == zoneID: + GameWorld.DebugLog("仙盟攻城战活动ID不变,不处理! zoneID=%s,actID=%s,state=%s,familyID=%s" % (zoneID, actID, state, familyID), playerID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZFamilyID, familyID) + if state: + Sync_FamilyGCZPlayerInfo(curPlayer) + return + + GameWorld.DebugLog("仙盟攻城战活动玩家重置! zoneID=%s,actID=%s,playerZoneID=%s,playerActID=%s" + % (zoneID, actID, playerZoneID, playerActID), playerID) + __doPlayerFamilyGCZReset(curPlayer, state, actID, zoneID, familyID) + return + +def __doPlayerRoundChange(curPlayer, playerRoundNum, roundNum): + ## 轮次变更 + playerID = curPlayer.GetPlayerID() + GameWorld.DebugLog(" 仙盟攻城战活动玩家轮次变更! playerRoundNum=%s,roundNum=%s" % (playerRoundNum, roundNum), playerID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZRoundNum, roundNum) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZContributionCnt, 0) + addEnergy = IpyGameDataPY.GetFuncCfg("FamilyGCZEnergy", 3) + if addEnergy > 0: + SetEnergy(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + addEnergy, False) + Sync_FamilyGCZPlayerInfo(curPlayer) + return + +def __doPlayerFamilyGCZReset(curPlayer, state=0, actID=0, zoneID=0, familyID=0): + ## 活动变更重置 + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZID, actID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZZoneID, zoneID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZFamilyID, familyID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZRoundNum, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZContributionCnt, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergy, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergyTime, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZAwardState, 0) + +# # 回收道具 +# for itemID in IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 5): +# ItemControler.RecycleItem(curPlayer, itemID, "ActLianqiRecycleItem") + + if state: + maxEnergy = IpyGameDataPY.GetFuncCfg("FamilyGCZEnergy", 1) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergy, maxEnergy) + Sync_FamilyGCZPlayerInfo(curPlayer) + + return True + +def OnProcess(curPlayer): + if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZID): + return + curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + maxEnergy = IpyGameDataPY.GetFuncCfg("FamilyGCZEnergy", 1) + if curEnergy >= maxEnergy: + #GameWorld.DebugLog("仙盟攻城战体力已满,无需恢复! curEnergy=%s >= %s" % (curEnergy, maxEnergy), curPlayer.GetPlayerID()) + return + needSeconds = IpyGameDataPY.GetFuncCfg("FamilyGCZEnergy", 2) * 60 + if not needSeconds: + return + curTime = int(time.time()) + lastTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergyTime) + if not lastTime: + lastTime = curTime + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergyTime, lastTime) + return + passTime = curTime - lastTime + addEnergy = passTime / needSeconds + if addEnergy <= 0: + return + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergyTime, curTime) + updEnergy = SetEnergy(curPlayer, min(curEnergy + addEnergy, maxEnergy)) + GameWorld.DebugLog("时间恢复仙盟攻城战体力: passTime=%s(%s-%s),addEnergy=%s,updEnergy=%s" + % (passTime, curTime, lastTime, addEnergy, updEnergy), curPlayer.GetPlayerID()) + return + +def SetEnergy(curPlayer, setEnergy, isNotify=True): + ## 设置体力 + maxEnergy = IpyGameDataPY.GetFuncCfg("FamilyGCZEnergy", 1) + curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + updEnergy = min(maxEnergy, max(setEnergy, 0)) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergy, updEnergy) + + if updEnergy >= maxEnergy: + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergyTime, 0) + elif curEnergy >= maxEnergy and updEnergy < maxEnergy: + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZEnergyTime, int(time.time())) + + if isNotify: + Sync_FamilyGCZPlayerInfo(curPlayer) + return updEnergy + +#// C1 24 仙盟攻城战捐献 #tagCMFamilyGCZContribution +# +#struct tagCMFamilyGCZContribution +#{ +# tagHead Head; +# BYTE ContributionType; //捐献类型: 0-低级;1-高级 +# DWORD UseCount; //物品捐献时使用个数 +#}; +def OnFamilyGCZContribution(index, clientData, tick): + curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index) + contributionType = clientData.ContributionType + useCount = clientData.UseCount + + # 大本营被摧毁无法再捐献,前端自己判断,后端不限制 + + if contributionType == 1: + __doContiributionHigh(curPlayer, useCount) + else: + __doContiributionLow(curPlayer) + return + +def __doContiributionLow(curPlayer): + ## 低级捐献 - 货币 + playerID = curPlayer.GetPlayerID() + moneyType = IpyGameDataPY.GetFuncCfg("FamilyGCZContributionLow", 1) + costMoneyList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZContributionLow", 2) + if not moneyType or not costMoneyList: + return + maxCnt = len(costMoneyList) + contriCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZContributionCnt) + if contriCnt >= maxCnt: + GameWorld.DebugLog("仙盟攻城战已达本轮最大低级捐献次数! contriCnt=%s >= %s" % (contriCnt, maxCnt), playerID) + return + costMoney = costMoneyList[contriCnt] + if not costMoney or not PlayerControl.PayMoney(curPlayer, moneyType, costMoney, "FamilyGCZ"): + return + contriCnt += 1 + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZContributionCnt, contriCnt) + Sync_FamilyGCZPlayerInfo(curPlayer) + + addCampExp = IpyGameDataPY.GetFuncCfg("FamilyGCZContributionLow", 3) + randItemWeightList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZContributionLow", 4) + randItemInfo = GameWorld.GetResultByWeightList(randItemWeightList) + if randItemInfo and len(randItemInfo) >= 2: + ItemControler.GivePlayerItemOrMail(curPlayer, [randItemInfo], event=["FamilyGCZContiribution", False, {}]) + + GameWorld.DebugLog("仙盟攻城战低级捐献! contriCnt=%s,moneyType=%s,costMoney=%s,addCampExp=%s,randItemInfo=%s" + % (contriCnt, moneyType, costMoney, addCampExp, randItemInfo), playerID) + dataMsg = {"ActMsgType":"AddCampExp", "playerID":playerID, "addCampExp":addCampExp} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + +def __doContiributionHigh(curPlayer, useCount): + ## 高级捐献 - 物品 + playerID = curPlayer.GetPlayerID() + costItemID = IpyGameDataPY.GetFuncCfg("FamilyGCZContributionHigh", 1) + + costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, costItemID, useCount) + lackCnt = useCount - bindCnt - unBindCnt + if lackCnt > 0: + GameWorld.DebugLog("仙盟攻城战高级捐献消耗道具不足! costItemID=%s,useCount=%s,bindCnt=%s,unBindCnt=%s,lackCnt=%s" + % (costItemID, useCount, bindCnt, unBindCnt, lackCnt)) + return + # 扣除消耗 + ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, useCount, "FamilyGCZContiribution") + + addCampExp = IpyGameDataPY.GetFuncCfg("FamilyGCZContributionHigh", 2) * useCount + randItemWeightList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZContributionHigh", 3) + awardItemList = [] + for _ in range(useCount): + randItemInfo = GameWorld.GetResultByWeightList(randItemWeightList) + if randItemInfo and len(randItemInfo) >= 2: + awardItemList.append(randItemInfo) + if awardItemList: + ItemControler.GivePlayerItemOrMail(curPlayer, GameWorld.MergeItemList(awardItemList), event=["FamilyGCZContiribution", False, {}]) + + GameWorld.DebugLog("仙盟攻城战高级捐献! costItemID=%s,useCount=%s,addCampExp=%s,awardItemList=%s" + % (costItemID, useCount, addCampExp, awardItemList), playerID) + dataMsg = {"ActMsgType":"AddCampExp", "playerID":playerID, "addCampExp":addCampExp} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + +#// C1 25 仙盟攻城战攻击 #tagCMFamilyGCZAtk +# +#struct tagCMFamilyGCZAtk +#{ +# tagHead Head; +# BYTE AtkType; //攻击类型: 1-普通单攻;2-技能单攻;3-技能群攻; +# DWORD TagCityID; //目标城池ID,一般是仙盟ID或者特殊城池ID如修罗城城池,普攻单攻需指定目标,群攻技能发0 +# DWORD TagGuardID; //目标守卫ID,一般是玩家ID或者特殊守卫ID如修罗城守卫,普攻单攻需指定目标,技能攻击发0 +#}; +def OnFamilyGCZAtk(index, clientData, tick): + curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index) + atkType = clientData.AtkType + tagCityID = clientData.TagCityID + tagGuardID = clientData.TagGuardID + + playerID = curPlayer.GetPlayerID() + + zoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZZoneID) + actInfo = CrossRealmPlayer.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State, 0) + roundNum, roundState = GetRoundState(state) + if not roundNum or roundState != FamilyGCZRoundState_Fight: + GameWorld.ErrLog("仙盟攻城战非攻击阶段: state=%s,roundNum=%s,roundState=%s" % (state, roundNum, roundState), playerID) + return + + hurtFamilyCnt = 1 + useItemID = 0 + # 普攻 + if atkType == AtkType_Normal: + curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + if not curEnergy: + useItemID = IpyGameDataPY.GetFuncCfg("FamilyGCZAtk", 2) + if not useItemID: + return + if not ItemCommon.FindItemInPackByItemID(curPlayer, useItemID, IPY_GameWorld.rptItem): + GameWorld.DebugLog("仙盟攻城战普攻道具不足! useItemID=%s" % useItemID, playerID) + return + hurtMulti = IpyGameDataPY.GetFuncCfg("FamilyGCZAtk", 1) + + # 技能 + else: + useItemID = IpyGameDataPY.GetFuncCfg("FamilyGCZAtk", 4) + if not useItemID: + return + if not ItemCommon.FindItemInPackByItemID(curPlayer, useItemID, IPY_GameWorld.rptItem): + GameWorld.DebugLog("仙盟攻城战技能道具不足! useItemID=%s" % useItemID, playerID) + return + hurtMulti = IpyGameDataPY.GetFuncCfg("FamilyGCZAtk", 3) + + # 群攻 + if atkType == AtkType_SkillArea: + hurtFamilyCnt = IpyGameDataPY.GetFuncCfg("FamilyGCZAtk", 5) + + tick = GameWorld.GetGameWorld().GetTick() + if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_FamilyGCZ, tick): + GameWorld.DebugLog("攻城战请求CD中...", playerID) + PlayerControl.NotifyCode(curPlayer, "RequestLater") + return + + dataMsg = {"ActMsgType":"GCZAtk", "zoneID":zoneID, "playerID":playerID, "atkType":atkType, + "tagCityID":tagCityID, "tagGuardID":tagGuardID, "hurtMulti":hurtMulti, + "useItemID":useItemID, "hurtFamilyCnt":hurtFamilyCnt} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + +def __OnFamilyGCZAtkResult(curPlayer, retInfo): + ## 跨服同步回来的攻击结果 + #"atkRet":atkRet, "errMsg":errMsg, "reqMsg":msgData, "hurtDict":hurtDict, "killCntTotal":killCntTotal + + playerID = curPlayer.GetPlayerID() + atkRet = retInfo["atkRet"] + errMsg = retInfo["errMsg"] + hurtDict = retInfo["hurtDict"] + killCntTotal = retInfo["killCntTotal"] + reqMsg = retInfo["reqMsg"] + + atkType = reqMsg["atkType"] + useItemID = reqMsg["useItemID"] + + GameWorld.DebugLog("仙盟攻城战攻击结果! atkType=%s,takRet=%s:%s" % (atkType, atkRet, errMsg), playerID) + if atkRet != 0 or errMsg != "OK": + # 攻击失败可暂时不处理 + return + + # 攻击成功处理 + + # 扣除物品 + if useItemID: + delCount = 1 + if not ItemControler.DelPlayerItemByPacks(curPlayer, useItemID, delCount, "FamilyGCZAtk"): + return + GameWorld.DebugLog(" 扣除道具: useItemID=%s" % (useItemID), playerID) + + fixAwardItemList = [] # 固定奖励 + # 普通攻击 + if atkType == AtkType_Normal: + if useItemID: + fixAwardItemList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZAtkAward", 2) + else: + fixAwardItemList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZAtkAward", 1) + # 非道具普攻,扣体力 + curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + updEnergy = SetEnergy(curPlayer, curEnergy - 1) + GameWorld.DebugLog(" 扣除体力: curEnergy=%s,updEnergy=%s" % (curEnergy, updEnergy), playerID) + + # 技能攻击 + elif atkType in [AtkType_SkillSingle, AtkType_SkillArea]: + fixAwardItemList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZAtkAward", 3) + + killAwardItemList = [] + killAwardRandCnt = IpyGameDataPY.GetFuncCfg("FamilyGCZAtkAward", 5) * killCntTotal + killAwardWeightList = IpyGameDataPY.GetFuncEvalCfg("FamilyGCZAtkAward", 4) + for _ in range(killAwardRandCnt): + randItem = GameWorld.GetResultByWeightList(killAwardWeightList) + if randItem and isinstance(randItem, list) and len(randItem) == 3: + killAwardItemList.append(randItem) + + hurtCnt = len(hurtDict) + hurtValueTotal = sum(hurtDict.values()) + GameWorld.DebugLog(" hurtCnt=%s,hurtValueTotal=%s,killCntTotal=%s" % (hurtCnt, hurtValueTotal, killCntTotal), playerID) + + notifyDataEx = {"atkType":atkType, "killCntTotal":killCntTotal, "hurtCnt":hurtCnt, "hurtValueTotal":hurtValueTotal} + giveAwardItemList = GameWorld.MergeItemList(fixAwardItemList + killAwardItemList) + GameWorld.DebugLog(" giveAwardItemList=%s,fixAwardItemList=%s,killAwardItemList=%s" % (giveAwardItemList, fixAwardItemList, killAwardItemList), playerID) + ItemControler.GivePlayerItemOrMail(curPlayer, giveAwardItemList, event=["FamilyGCZAtk", False, {}], notifyDataEx=notifyDataEx) + return + +#// C1 26 仙盟攻城战竞猜 #tagCMFamilyGCZGuess +# +#struct tagCMFamilyGCZGuess +#{ +# tagHead Head; +# BYTE SelectCnt; +# DWORD SelectFamilyIDList[SelectCnt]; // 竞猜选择的仙盟ID排名顺序 +#}; +def OnFamilyGCZGuess(index, clientData, tick): + curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index) + selectFamilyIDList = clientData.SelectFamilyIDList + playerID = curPlayer.GetPlayerID() + zoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZZoneID) + dataMsg = {"ActMsgType":"Guess", "zoneID":zoneID, "playerID":playerID, "selectFamilyIDList":selectFamilyIDList} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + +def GetFamilyGCZAward(curPlayer, awardType, tick): + ## 领奖 0-竞猜奖励;1-个人排行奖励;2-仙盟排名奖励; + playerID = curPlayer.GetPlayerID() + awardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZAwardState) + if awardState&pow(2, awardType): + GameWorld.DebugLog("仙盟攻城战已领取该奖励! awardType=%s,awardState=%s" % (awardType, awardState), playerID) + return + + zoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZZoneID) + actInfo = CrossRealmPlayer.GetCrossActInfoByZoneID(ShareDefine.CrossActName_FamilyGCZ, zoneID) + if not actInfo: + return + state = actInfo.get(ShareDefine.ActKey_State, 0) + if state != FamilyGCZState_Award: + GameWorld.ErrLog("仙盟攻城战非领奖阶段: state=%s" % state, playerID) + return + + if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_FamilyGCZ, tick): + GameWorld.DebugLog("攻城战请求CD中...", playerID) + PlayerControl.NotifyCode(curPlayer, "RequestLater") + return + + dataMsg = {"ActMsgType":"GetAward", "zoneID":zoneID, "playerID":playerID, "awardType":awardType} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FamilyGCZ, dataMsg) + return + +def __OnFamilyGCZAward(curPlayer, dataMsg): + ## 跨服同步回来的领奖结果 + #"zoneID":zoneID, "playerID":playerID, "actID":actID, "awardType":awardType, "awardItemList":awardItemList + zoneID = dataMsg["zoneID"] + playerID = dataMsg["playerID"] + actID = dataMsg["actID"] + awardType = dataMsg["awardType"] + awardItemList = dataMsg["awardItemList"] + awardValue = dataMsg.get("awardValue", 0) + fmLV = dataMsg.get("fmLV", 0) + playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZID) + awardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZAwardState) + if awardState&pow(2, awardType): + GameWorld.Log("仙盟攻城战发放奖励时已领取该奖励! awardType=%s,awardState=%s,zoneID=%s,actID=%s" + % (awardType, awardState, zoneID, actID), playerID) + return + + GameWorld.DebugLog("仙盟攻城战发放奖励! awardType=%s,awardValue=%s,fmLV=%s,awardItemList=%s,awardState=%s" + % (awardType, awardValue, fmLV, awardItemList, awardState), playerID) + + # 同一个活动,更新领奖记录 + if playerActID == actID: + updAwardState = awardState|pow(2, awardType) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyGCZAwardState, updAwardState) + GameWorld.DebugLog(" 更新领奖记录! awardType=%s,awardState=%s,updAwardState=%s" % (awardType, awardState, updAwardState), playerID) + Sync_FamilyGCZPlayerInfo(curPlayer) + + drDict = {"zoneID":zoneID, "actID":actID, "awardType":awardType, "awardValue":awardValue, "fmLV":fmLV} + ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["FamilyGCZAward", True, drDict]) + return + +def Sync_FamilyGCZPlayerInfo(curPlayer): + clientPack = ChPyNetSendPack.tagMCFamilyGCZPlayerInfo() + clientPack.ContributionCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZContributionCnt) + clientPack.Energy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergy) + clientPack.EnergyTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZEnergyTime) + clientPack.AwardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyGCZAwardState) + NetPackCommon.SendFakePack(curPlayer, clientPack) + return + diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py index 0b8de83..0218108 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py @@ -86,6 +86,7 @@ import PlayerActHorsePetTrain import PlayerActLianqi import PlayerActGodGift +import PlayerActFamilyGCZ import PlayerActFamilyCTGAssist import PlayerActRechargeRebateGold import PlayerActManyDayRecharge @@ -1576,6 +1577,9 @@ elif actionName == ShareDefine.CrossActName_Lianqi: PlayerActLianqi.RefreshCrossActLianqiInfo() + elif actionName == ShareDefine.CrossActName_FamilyGCZ: + PlayerActFamilyGCZ.RefreshActFamilyGCZInfo() + return if key == ShareDefine.Def_Notify_WorldKey_CrossZoneName: diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py index 13e0de7..f4b95b2 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py @@ -55,6 +55,7 @@ import FormulaControl import PlayerGoldGift import PlayerActLianqi +import PlayerActFamilyGCZ import PlayerFlashSale import PlayerChatBox import PlayerFace @@ -1300,6 +1301,8 @@ FBLogic.OnCustomSceneProcess(curPlayer, tick) #炼器 PlayerActLianqi.OnProcess(curPlayer) + #仙盟攻城战 + PlayerActFamilyGCZ.OnProcess(curPlayer) #跨服数据同步,放最后 CrossPlayerData.ProcessCrossPlayer(curPlayer, tick) return diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FamilyGCZ.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FamilyGCZ.py new file mode 100644 index 0000000..645f194 --- /dev/null +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FamilyGCZ.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package Player.RemoteQuery.GY_Query_FamilyGCZ +# +# @todo:仙盟攻城战 +# @author hxp +# @date 2025-04-09 +# @version 1.0 +# +# 详细描述: 仙盟攻城战 +# +#------------------------------------------------------------------------------- +#"""Version = 2025-04-09 16:00""" +#------------------------------------------------------------------------------- + +import GameWorld +import PlayerActFamilyGCZ + +#--------------------------------------------------------------------- +#逻辑实现 +## 请求逻辑 +# @param query_Type 请求类型 +# @param query_ID 请求的玩家ID +# @param packCMDList 发包命令 [ ] +# @param tick 当前时间 +# @return "True" or "False" or "" +# @remarks 函数详细说明. +def DoLogic(query_Type, query_ID, packCMDList, tick): + return "" + +#--------------------------------------------------------------------- +#执行结果 +## 执行结果 +# @param curPlayer 发出请求的玩家 +# @param callFunName 功能名称 +# @param funResult 查询的结果 +# @param tick 当前时间 +# @return None +# @remarks 函数详细说明. +def DoResult(curPlayer, callFunName, funResult, tick): + GameWorld.DebugLog("GY_Query_FamilyGCZ DoResult %s" % str(funResult), curPlayer.GetPlayerID()) + if funResult != "": + PlayerActFamilyGCZ.GameServer_FamilyGCZ(curPlayer, eval(funResult), tick) + return + diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py index 25a3322..39d2b8e 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py @@ -364,10 +364,11 @@ CrossActName_Gubao = "CrossActGubao" # 古宝养成 - 跨服 CrossActName_HorsePetTrain = "CrossActHorsePetTrain" # 骑宠养成 - 跨服 CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服 +CrossActName_FamilyGCZ = "CrossActFamilyGCZ" # 仙盟攻城战 #跨服运营活动列表 CrossActNameList = [CrossActName_CTGBillboard, CrossActName_AllRecharge, CrossActName_LuckyCloudBuy, CrossActName_BossTrial, - CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi] + CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi, CrossActName_FamilyGCZ] #需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束 CrossActLockServerGroupIDList = [CrossActName_CTGBillboard, CrossActName_AllRecharge] @@ -375,6 +376,7 @@ ActKey_ID = "ID" # 活动ID,唯一标识的ID,一般是活动开启的time值 ActKey_State = "State" # 活动状态 0-未开启, >0开启中,也代表当日的第几个时间段 ActKey_StateJoin = "StateJoin" # 活动某些功能可参与状态 0-还不可参与, >0可参与,一般可参与时该状态等于state +ActKey_StateError = "StateError" # 按流程走的活动状态是否已异常 ActKey_CfgID = "CfgID" # 活动表配置ID ActKey_ActNum = "ActNum" # 活动分组编号 ActKey_DayIndex = "DayIndex" # 当前活动天索引,0开始,代表第1天 @@ -917,7 +919,10 @@ Def_CBT_HorsePetTrainScore, # 骑宠养成积分 - 个人榜 164 Def_CBT_CrossRealmPK, # 跨服PK竞技场 165 Def_CBT_LianqiScore, # 炼器积分 - 个人榜 166 -) = range(150, 166 + 1) +Def_CBT_FamilyGCZScore, # 仙盟攻城战 - 仙盟积分总榜 167 (zoneID, 0) +Def_CBT_FamilyGCZPlayerHurt, # 仙盟攻城战 - 玩家伤害总榜 168 (zoneID, 0) +Def_CBT_FamilyGCZRoundHurt, # 仙盟攻城战 - 本轮分组仙盟伤害榜 169 (zoneID, batType*100+groupNum) +) = range(150, 169 + 1) #职业对应战力排行榜类型 JobFightPowerBillboardDict = { @@ -1435,7 +1440,12 @@ #通用信息记录类型 - 新 从 300 开始,原通用记录类型最大到255 Def_GameRecTypeList = ( Def_GameRecType_Xiangong, # 仙宫记录 300 - ) = range(300, 1 + 300) + Def_GameRecType_FamilyDelSyncCross, # 仙盟删除同步跨服状态本服记录, familyID 301 + Def_GameRecType_FamilyGCZMgr, # 仙盟攻城战公共管理信息记录, zoneID 302 + Def_GameRecType_FamilyGCZJoinFamily, # 仙盟攻城战参与仙盟信息, zoneID 303 + Def_GameRecType_FamilyGCZJoinMember, # 仙盟攻城战参与成员信息, zoneID 304 + Def_GameRecType_FamilyGCZCityWall, # 仙盟攻城战城池信息, zoneID 305 + ) = range(300, 1 + 305) #通用信息记录新 - 字典key配置,如果有配置,则可额外按对应记录Value值存储字典,方便快速取值,可配置Value编号 1~8,配空默认 Value1 Def_GameRecValueKeyDict = { Def_GameRecType_Xiangong:[1], @@ -1640,6 +1650,7 @@ CrossServerMsg_CrossServerState = "CrossServerState" # 跨服服务器状态变更 CrossServerMsg_PlayerLoginout = "PlayerLoginout" # 玩家上下线状态同步 CrossServerMsg_ExitCrossServer = "ExitCrossServer" # 退出跨服服务器 +CrossServerMsg_SendFakePack = "SendFakePack" # 给子服玩家发送封包 CrossServerMsg_Notify = "Notify" # 提示信息 CrossServerMsg_ChatCrossWorld = "ChatCrossWorld" # 跨服世界聊天 CrossServerMsg_ViewPlayerCacheRet = "ViewPlayerCacheRet"# 查看跨服玩家信息结果 @@ -1693,6 +1704,8 @@ CrossServerMsg_FuncTeamInfo = "FuncTeamInfo" # 功能队伍信息同步 CrossServerMsg_FuncTeamDel = "FuncTeamDel" # 功能队伍删除同步 CrossServerMsg_FuncTeamList = "FuncTeamList" # 功能队伍列表同步 +CrossServerMsg_FamilyDelRet = "FamilyDelRet" # 仙盟删除结果 +CrossServerMsg_FamilyGCZ = "FamilyGCZ" # 仙盟攻城战 # 子服发送跨服信息定义 ClientServerMsg_ServerInitOK = "ServerInitOK" # 子服启动成功 @@ -1742,6 +1755,8 @@ ClientServerMsg_HorsePetTrainScore = "HorsePetTrainScore" # 骑宠养成积分 ClientServerMsg_QueryXiangong = "QueryXiangong" # 查看仙宫仙名录 ClientServerMsg_LianqiScore = "LianqiScore" # 炼器积分 +ClientServerMsg_SyncFamilyInfo = "SyncFamilyInfo" # 仙盟信息同步 +ClientServerMsg_FamilyGCZ = "FamilyGCZ" # 仙盟攻城战 #跨服广播类型定义 CrossNotify_CrossAct = "CrossAct" -- Gitblit v1.8.0