129 【战斗】战斗系统-服务端(支持多地图战斗)
| | |
| | | Writer = alee
|
| | | Releaser = alee
|
| | | RegType = 0
|
| | | RegisterPackCount = 1
|
| | | RegisterPackCount = 2
|
| | |
|
| | |
|
| | | PacketCMD_1=0xC2
|
| | | PacketSubCMD_1=0x01
|
| | | PacketCallFunc_1=OnTest
|
| | |
|
| | | PacketCMD_2=0xC2
|
| | | PacketSubCMD_2=0x02
|
| | | PacketCallFunc_2=OnSSCommMsg
|
| | |
| | | return batObjMgr
|
| | |
|
| | | def OnMinute():
|
| | | GameWorld.Log("战斗单位数量: %s" % len(GetBatObjMgr().batObjDict))
|
| | | #GameWorld.Log("战斗单位数量: %s" % len(GetBatObjMgr().batObjDict))
|
| | | return
|
| | |
|
| | | def NotifyObjInfoRefresh(batObj, attrID, value):
|
| | |
| | | import GameWorld
|
| | | import PlayerLLMJ
|
| | | import PlayerPrestigeSys
|
| | | import CrossServerPackLogic
|
| | | import IpyGameDataPY
|
| | | import PlayerOnline
|
| | | import NPCCommon
|
| | |
| | | import random
|
| | | import time
|
| | | import json
|
| | | import shutil
|
| | | import os
|
| | |
|
| | | g_gmTestFightReq = []
|
| | |
| | | # pvp 或 pve 必须要满足其中一种
|
| | | return
|
| | |
|
| | | # 先默认本地图处理,后续优化多战斗地图支持
|
| | | |
| | | reqServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | reqInfo = [reqServerID, guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, npcLineupIDList, strongerLV, difficulty, reqData]
|
| | | OnMsg_BattleRequest(reqInfo)
|
| | | reqInfo = [guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, npcLineupIDList, strongerLV, difficulty, reqData]
|
| | | multiMapSet = IpyGameDataPY.GetFuncCfg("TurnFightProcess", 1)
|
| | | # 多地图战斗 0-本地图处理;1-多地图处理;2-debug模式默认本地图处理,非debug默认多地图处理
|
| | | isMultiMap = False
|
| | | if multiMapSet == 1:
|
| | | isMultiMap = True
|
| | | elif multiMapSet == 2:
|
| | | if not GameWorld.GetGameWorld().GetDebugLevel():
|
| | | isMultiMap = True
|
| | | |
| | | if isMultiMap:
|
| | | CrossServerPackLogic.SendToBattleServer(ShareDefine.SSMsg_BattleRequest, reqInfo, reqPlayerID)
|
| | | else:
|
| | | SSMsg_BattleRequest(reqInfo, reqServerID)
|
| | | return
|
| | |
|
| | | def OnMsg_BattleRequest(reqInfo):
|
| | | def SSMsg_BattleRequest(reqInfo, fromServerID):
|
| | | ## 请求执行战斗,由本地图或其他服务器地图分配过来的战斗请求
|
| | | reqServerID, guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, npcLineupIDList, strongerLV, difficulty, reqData = reqInfo
|
| | | guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, npcLineupIDList, strongerLV, difficulty, reqData = reqInfo
|
| | |
|
| | | if npcLineupIDList:
|
| | | turnFight = DoTurnFightPVE(guid, mapID, funcLineID, reqPlayerID, reqServerID, lineupDictA, npcLineupIDList, strongerLV, difficulty)
|
| | | turnFight = DoTurnFightPVE(guid, mapID, funcLineID, reqPlayerID, fromServerID, lineupDictA, npcLineupIDList, strongerLV, difficulty)
|
| | | else:
|
| | | turnFight = DoTurnFightPVP(guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, reqServerID)
|
| | | turnFight = DoTurnFightPVP(guid, mapID, funcLineID, lineupDictA, lineupDictB, reqPlayerID, fromServerID)
|
| | |
|
| | | winFaction = None
|
| | | statMsg = {}
|
| | |
| | | retInfo = [guid, mapID, funcLineID, reqPlayerID, winFaction, statMsg, dateStr, reqData]
|
| | |
|
| | | # 本地图自己处理的
|
| | | if reqServerID == GameWorld.GetGameWorld().GetServerID():
|
| | | OnMsg_BattleResult(retInfo)
|
| | | if fromServerID == GameWorld.GetGameWorld().GetServerID():
|
| | | SSMsg_BattleResult(retInfo, fromServerID)
|
| | |
|
| | | # 其他服务器地图请求的,发送战斗结果回去
|
| | | else:
|
| | | pass
|
| | | |
| | | CrossServerPackLogic.SendToServer(ShareDefine.SSMsg_BattleResult, retInfo, [fromServerID], playerID=reqPlayerID)
|
| | | return
|
| | |
|
| | | def OnMsg_BattleResult(retInfo):
|
| | | def SSMsg_BattleResult(retInfo, fromServerID):
|
| | | ## 收到战斗结果信息
|
| | |
|
| | | guid, mapID, funcLineID, reqPlayerID, winFaction, statMsg, dateStr, reqData = retInfo
|
| | |
| | | funcLineID = turnFight.funcLineID
|
| | | GameWorld.DebugLog("--- 战斗结束处理 ---, winFaction=%s, costTime=%ss, %s" % (winFaction, turnFight.costTime, guid))
|
| | | if mapID != ChConfig.Def_FBMapID_Main:
|
| | | GameWorld.Log("战斗耗时: %ss, mapID=%s,funcLineID=%s" % (turnFight.costTime, mapID, funcLineID))
|
| | | GameWorld.Log("战斗耗时: %ss, mapID=%s,funcLineID=%s,turnNum=%s/%s" % (turnFight.costTime, mapID, funcLineID, turnFight.turnNum, turnFight.turnMax))
|
| | |
|
| | | # 统计明细
|
| | | batObjMgr = BattleObj.GetBatObjMgr()
|
| | |
| | |
|
| | | return DumpString
|
| | | #------------------------------------------------------
|
| | | # C2 02 跨服通用信息包 #tagSSCommMsg
|
| | |
|
| | | class tagSSCommMsg(Structure):
|
| | | Head = tagHead()
|
| | | FromServerID = 0 #(DWORD FromServerID)//哪个服发的
|
| | | ServerTime = 0 #(DWORD ServerTime)//来源服务器时间戳
|
| | | TypeLen = 0 #(BYTE TypeLen)
|
| | | MsgType = "" #(String MsgType)
|
| | | Len = 0 #(DWORD Len)
|
| | | Data = "" #(String Data)
|
| | | data = None
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | self.Head.Cmd = 0xC2
|
| | | self.Head.SubCmd = 0x02
|
| | | return
|
| | |
|
| | | def ReadData(self, _lpData, _pos=0, _Len=0):
|
| | | self.Clear()
|
| | | _pos = self.Head.ReadData(_lpData, _pos)
|
| | | self.FromServerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.ServerTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.TypeLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
|
| | | self.MsgType,_pos = CommFunc.ReadString(_lpData, _pos,self.TypeLen)
|
| | | self.Len,_pos = CommFunc.ReadDWORD(_lpData, _pos)
|
| | | self.Data,_pos = CommFunc.ReadString(_lpData, _pos,self.Len)
|
| | | return _pos
|
| | |
|
| | | def Clear(self):
|
| | | self.Head = tagHead()
|
| | | self.Head.Clear()
|
| | | self.Head.Cmd = 0xC2
|
| | | self.Head.SubCmd = 0x02
|
| | | self.FromServerID = 0
|
| | | self.ServerTime = 0
|
| | | self.TypeLen = 0
|
| | | self.MsgType = ""
|
| | | self.Len = 0
|
| | | self.Data = ""
|
| | | return
|
| | |
|
| | | def GetLength(self):
|
| | | length = 0
|
| | | length += self.Head.GetLength()
|
| | | length += 4
|
| | | length += 4
|
| | | length += 1
|
| | | length += len(self.MsgType)
|
| | | length += 4
|
| | | length += len(self.Data)
|
| | |
|
| | | return length
|
| | |
|
| | | def GetBuffer(self):
|
| | | data = ''
|
| | | data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
|
| | | data = CommFunc.WriteDWORD(data, self.FromServerID)
|
| | | data = CommFunc.WriteDWORD(data, self.ServerTime)
|
| | | data = CommFunc.WriteBYTE(data, self.TypeLen)
|
| | | data = CommFunc.WriteString(data, self.TypeLen, self.MsgType)
|
| | | data = CommFunc.WriteDWORD(data, self.Len)
|
| | | data = CommFunc.WriteString(data, self.Len, self.Data)
|
| | | return data
|
| | |
|
| | | def OutputString(self):
|
| | | DumpString = '''
|
| | | Head:%s,
|
| | | FromServerID:%d,
|
| | | ServerTime:%d,
|
| | | TypeLen:%d,
|
| | | MsgType:%s,
|
| | | Len:%d,
|
| | | Data:%s
|
| | | '''\
|
| | | %(
|
| | | self.Head.OutputString(),
|
| | | self.FromServerID,
|
| | | self.ServerTime,
|
| | | self.TypeLen,
|
| | | self.MsgType,
|
| | | self.Len,
|
| | | self.Data
|
| | | )
|
| | | return DumpString
|
| | |
|
| | |
|
| | | m_NAtagSSCommMsg=tagSSCommMsg()
|
| | | ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSSCommMsg.Head.Cmd,m_NAtagSSCommMsg.Head.SubCmd))] = m_NAtagSSCommMsg
|
| | |
|
| | |
|
| | | #------------------------------------------------------
|
| | | # C2 01 跨服服务器间的测试包 #tagSSTest
|
| | |
|
| | | class tagSSTest(Structure):
|
| | |
| | | # 跨服服务器间的封包 既是收包也是发包
|
| | |
|
| | | import GameWorld
|
| | | import ChServerToServerPyPack
|
| | | import ShareDefine
|
| | | import NetPackCommon
|
| | | import ChServerToServerPyPack
|
| | | import TurnAttack
|
| | | import PyGameData
|
| | | import ChPlayer
|
| | |
|
| | | import traceback
|
| | | import cPickle
|
| | | import time
|
| | |
|
| | | def OnTest(netPack):
|
| | |
|
| | | GameWorld.Log("收到跨服包 " + str(netPack.Data))
|
| | |
|
| | |
|
| | | def SendTest():
|
| | | def SendTest(dirType, serverList):
|
| | | pack = ChServerToServerPyPack.tagSSTest()
|
| | | pack.Data = 12
|
| | | #0全广播,1通知主服务器排除合服子服,2通知服务器包含合服子服, 3通知跨服服务器
|
| | | NetPackCommon.SendCrossServerToServerPack(1, "[501]", pack.GetBuffer())
|
| | | NetPackCommon.SendCrossServerToServerPack(dirType, serverList, pack.GetBuffer())
|
| | | return
|
| | |
|
| | | def GetCrossServerID():
|
| | | ## 获取本服务器所属的跨服中心服务器
|
| | | return 0
|
| | |
|
| | | def SendToCrossServer(msgType, dataMsg):
|
| | | ## 发送信息到跨服服务器
|
| | | if GameWorld.IsCrossServer():
|
| | | return
|
| | | if not dataMsg:
|
| | | return
|
| | | if msgType not in [ShareDefine.ClientServerMsg_ServerInitOK]:
|
| | | isOpen = GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossServerOpen)
|
| | | if not isOpen:
|
| | | GameWorld.Log("跨服服务器未开启或维护中不发送消息! SendMsgToCrossServer => %s" % msgType)
|
| | | return
|
| | | crossServerID = GetCrossServerID()
|
| | | if not crossServerID:
|
| | | return
|
| | | |
| | | playerID = 0
|
| | | if isinstance(dataMsg, dict):
|
| | | playerID = dataMsg.get("playerID", 0)
|
| | | if not playerID:
|
| | | playerID = dataMsg.get("PlayerID", 0)
|
| | | |
| | | GameWorld.Log("SendMsgToCrossServer => %s, %s, %s" % (msgType, crossServerID, dataMsg), playerID)
|
| | | SendToServer(msgType, dataMsg, [crossServerID], ShareDefine.dirType_Cross, playerID, isLog=False)
|
| | | return
|
| | |
|
| | | def SendToClientServer(msgType, dataMsg, serverIDList=None):
|
| | | ''' 发送信息到子服务器
|
| | | @param serverGroupIDList: 发送指定的服务器组ID列表,内部已经针对列表中组ID去重,
|
| | | 所以外部逻辑可直接添加,不用考虑组ID重复问题,没有指定服务器组ID时,默认广播所有子服
|
| | | '''
|
| | | if not GameWorld.IsCrossServer():
|
| | | return
|
| | | |
| | | if not PyGameData.g_serverInitOK:
|
| | | GameWorld.ErrLog("跨服服务器未启动好,不允许向子服发送数据! %s, %s, %s" % (msgType, serverIDList, dataMsg))
|
| | | return
|
| | | |
| | | playerID = 0
|
| | | if isinstance(dataMsg, dict):
|
| | | playerID = dataMsg.get("playerID", 0)
|
| | | if not playerID:
|
| | | playerID = dataMsg.get("PlayerID", 0)
|
| | | |
| | | GameWorld.Log("SendToClientServer => %s, %s, %s" % (msgType, serverIDList, dataMsg), playerID)
|
| | | SendToServer(msgType, dataMsg, serverIDList, ShareDefine.dirType_Main, playerID, isLog=False) # 默认发给主服即可
|
| | | return
|
| | |
|
| | | def SendToBattleServer(msgType, dataMsg, playerID=0):
|
| | | SendToServer(msgType, dataMsg, dirType=ShareDefine.dirType_Battle, playerID=playerID)
|
| | | return
|
| | |
|
| | | def SendToServer(msgType, dataMsg, serverIDList=None, dirType=ShareDefine.dirType_Main, playerID=0, isLog=True):
|
| | | '''发送给其他服务器
|
| | | @param msgType: 功能信息类型字符定义
|
| | | @param dataMsg: 发送的数据,任意格式,由功能自行决定
|
| | | @param serverIDList: 指定目标服务器ID 或 服务器ID列表
|
| | | '''
|
| | | |
| | | if isinstance(serverIDList, int):
|
| | | serverIDList = [serverIDList]
|
| | | elif not isinstance(serverIDList, list):
|
| | | serverIDList = []
|
| | | else:
|
| | | serverIDList = list(set(serverIDList)) # 去重
|
| | | |
| | | if isLog:
|
| | | GameWorld.Log("SendToServer => %s, %s, %s" % (msgType, serverIDList, dataMsg), playerID)
|
| | | |
| | | # 协议要用最高级2,可减少长度
|
| | | sendMsg = cPickle.dumps(dataMsg, 2)
|
| | | |
| | | pack = ChServerToServerPyPack.tagSSCommMsg()
|
| | | pack.FromServerID = GameWorld.GetGameWorld().GetServerID()
|
| | | pack.ServerTime = int(time.time())
|
| | | pack.MsgType = msgType
|
| | | pack.TypeLen = len(pack.MsgType)
|
| | | pack.Data = sendMsg
|
| | | pack.Len = len(pack.Data)
|
| | | NetPackCommon.SendCrossServerToServerPack(dirType, serverIDList, pack.GetBuffer())
|
| | | return
|
| | |
|
| | | def OnSSCommMsg(netPack):
|
| | | ## 收到其他服务器发来的消息
|
| | | |
| | | fromServerID = netPack.FromServerID
|
| | | fromServerTime = netPack.ServerTime
|
| | | msgType = netPack.MsgType
|
| | | recvMsg = netPack.Data
|
| | | |
| | | if not PyGameData.g_serverInitOK:
|
| | | GameWorld.Log("服务器未启动好,不处理其他服务器信息! %s, fromServerID=%s" % (msgType, fromServerID))
|
| | | return
|
| | | |
| | | try:
|
| | | dataMsg = cPickle.loads(recvMsg)
|
| | | if GameWorld.IsCrossServer():
|
| | | GameWorld.Log("OnCrossServerReceiveMsg: %s, fromServerID=%s, %s" % (msgType, fromServerID, dataMsg))
|
| | | else:
|
| | | GameWorld.Log("OnClientServerReceiveMsg: %s, fromServerID=%s, %s" % (msgType, fromServerID, dataMsg))
|
| | | |
| | | crossServerID = GetCrossServerID()
|
| | | if crossServerID == fromServerID:
|
| | | __fixCrossServerTime(msgType, fromServerTime)
|
| | | |
| | | if msgType == ShareDefine.SSMsg_BattleRequest:
|
| | | TurnAttack.SSMsg_BattleRequest(dataMsg, fromServerID)
|
| | | elif msgType == ShareDefine.SSMsg_BattleResult:
|
| | | TurnAttack.SSMsg_BattleResult(dataMsg, fromServerID)
|
| | | |
| | | except:
|
| | | GameWorld.RaiseException("服务器接收信息处理报错 \r\n%s" % str(traceback.format_exc()))
|
| | | return
|
| | |
|
| | | def __fixCrossServerTime(msgType, crossServerTime):
|
| | | # 子服矫正跨服服务器时间
|
| | | curServerTime = int(time.time())
|
| | | curServerCrossServerTime = GameWorld.ChangeTimeStrToNum(GameWorld.GetCrossServerTimeStr())
|
| | | diffSeconds = curServerCrossServerTime - crossServerTime # 本服计算误差
|
| | | |
| | | PyGameData.g_crossServerTimeInfo = [crossServerTime, curServerTime] # 覆盖更新
|
| | | |
| | | # 误差超过30秒 或强制同步时间的
|
| | | if abs(diffSeconds) >= 30 or msgType == ShareDefine.CrossServerMsg_CrossServerTime:
|
| | | GameWorld.DebugLog("同步跨服服务器时间,本服与跨服服务器时间计算误差! diffSeconds=%s" % (diffSeconds))
|
| | | playerManager = GameWorld.GetPlayerManager()
|
| | | for i in xrange(playerManager.GetPlayerCount()):
|
| | | curPlayer = playerManager.GetPlayerByIndex(i)
|
| | | if not GameWorld.IsNormalPlayer(curPlayer):
|
| | | continue
|
| | | ChPlayer.Sync_PyServerDataTimeToClient(curPlayer)
|
| | | return
|
| | |
|
| | |
|
| | |
| | | curTime = int(time.time())
|
| | | if not saveToDB:
|
| | | if curTime > PyGameData.g_lastRTBTime and curTime - PyGameData.g_lastRTBTime < BackupInterval * 60:
|
| | | GameWorld.DebugLog("备档冷却中! 上次备档时间=%s" % (GameWorld.ChangeTimeNumToStr(PyGameData.g_lastRTBTime)))
|
| | | #GameWorld.DebugLog("备档冷却中! 上次备档时间=%s" % (GameWorld.ChangeTimeNumToStr(PyGameData.g_lastRTBTime)))
|
| | | return
|
| | |
|
| | | serverID = GameWorld.GetGameWorld().GetServerID()
|
| | |
| | | ## 跨服服务器时间
|
| | | if IsCrossServer():
|
| | | return GetCurrentDataTimeStr()
|
| | | lastCrossServerTime, lastServerTime, _ = PyGameData.g_crossServerTimeInfo
|
| | | lastCrossServerTime, lastServerTime = PyGameData.g_crossServerTimeInfo
|
| | | if not lastCrossServerTime:
|
| | | return GetCurrentDataTimeStr()
|
| | | curTime = int(time.time())
|
| | |
| | | PyGameData.g_crossZoneName = msgValue
|
| | | return
|
| | |
|
| | | if key == ShareDefine.Def_Notify_WorldKey_CrossServerTime:
|
| | | PyGameData.g_crossServerTimeInfo = eval(msgValue)
|
| | | playerManager = GameWorld.GetPlayerManager()
|
| | | for index in xrange(playerManager.GetPlayerCount()):
|
| | | curPlayer = playerManager.GetPlayerByIndex(index)
|
| | | if not GameWorld.IsNormalPlayer(curPlayer):
|
| | | continue
|
| | | ChPlayer.Sync_PyServerDataTimeToClient(curPlayer)
|
| | | return
|
| | | |
| | | # 幸运云购
|
| | | if key == ShareDefine.Def_Notify_WorldKey_LuckyCloudBuyInfo:
|
| | | PyGameData.g_luckyCloudBuyInfo = eval(msgValue)
|
| | |
| | |
|
| | | g_luckyCloudBuyInfo = {} # 幸运云购最新一期信息
|
| | |
|
| | | g_crossServerTimeInfo = [0, 0, 0] # 跨服时间信息 [crossServerTime, curServerTime, syncMapTime]
|
| | | g_crossServerTimeInfo = [0, 0] # 跨服时间信息 [crossServerTime, curServerTime]
|
| | | g_crossZoneName = "" # 跨服分区名
|
| | | g_crossRegPlayerAttrDict = {} #跨服注册时登记的会影响战力的属性值 {playerID:[value, ...], ...}
|
| | | g_crossSyncTickDict = {} #需要同步跨服数据的玩家同步tick字典 {playerID:tick, ...}
|
| | |
| | |
|
| | | def OnCrossServerToServerPack(self, db, pack):
|
| | |
|
| | | if CommonDefine.IsDebug():
|
| | | import binascii
|
| | | mylog.debug('buf = %s'%binascii.b2a_hex(pack.getBuffer()))
|
| | | #if CommonDefine.IsDebug():
|
| | | # import binascii
|
| | | # mylog.debug('buf = %s'%binascii.b2a_hex(pack.getBuffer()))
|
| | |
|
| | | try:
|
| | | recvPack = MergeServerRecvProtocol.tagLPStringData()
|
| | |
| | | CampType_Evil, #邪恶(与 Def_ID2Win 一致)
|
| | | ] = range(3)
|
| | |
|
| | | # json里的配表 服务器类型(0主服,1子服,2跨服,3战斗服)]
|
| | | serverType_Main = 0 # 0主服
|
| | | serverType_Child = 1 # 1子服
|
| | | serverType_Cross = 2 # 2跨服
|
| | | serverType_Battle = 3 # 3战斗服
|
| | |
|
| | | # dirType //0全广播,1通知主服务器排除合服子服,2通知服务器包含合服子服, 3通知跨服服务器 ,4通知战斗服务器
|
| | | dirType_All = 0 # 0全广播
|
| | | dirType_Main = 1 # 1通知主服务器排除合服子服
|
| | | dirType_Child = 2 # 2通知服务器包含合服子服
|
| | | dirType_Cross = 3 # 3通知跨服服务器
|
| | | dirType_Battle = 4 # 4通知战斗服务器
|
| | |
|
| | | # 服务器间的信息定义
|
| | | SSMsg_BattleRequest = "SS_BattleRequest"
|
| | | SSMsg_BattleResult = "SS_BattleResult"
|
| | |
|
| | | # 跨服服务器发送子服信息定义
|
| | | CrossServerMsg_CrossServerState = "CrossServerState" # 跨服服务器状态变更
|
| | | CrossServerMsg_PlayerLoginout = "PlayerLoginout" # 玩家上下线状态同步
|