From 164b1a9e2eb3f9908e95e0050de828f0e35cb74b Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期一, 23 五月 2022 16:38:31 +0800
Subject: [PATCH] 9415 【BT5】【后端】古神战场(初版:包含战场副本外的所有功能;副本中暂仅支持击杀玩家玩法)

---
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnWeek.py                                                  |   31 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBattlefield.py                                          | 1120 +++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActivity.py                               |   25 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py                                                          |  356 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                                         |  180 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                                     |  333 ++++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py                                                |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                                          |    2 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                                              |  180 ++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py                                                          |  333 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CrossBattle.py                             |  118 +
 ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py                                                                |   18 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py                                                   |    9 
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                                 |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                                     |    2 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CrossFB.py                                                      |  212 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py                     |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                                |   27 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossBattlefield.py        |   48 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py                                                |    4 
 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini                                                                      |   15 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py                                    |    4 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                                                       |   10 
 ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py                                                  |   34 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py                   |   11 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py                                             |   31 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossBattlefield.py                       |  232 +++
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                                               |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossBattlefield.py |  890 ++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                                 |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py                                       |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py                                           |    9 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py                                            |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py                           |   10 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnDay.py                                                   |   45 
 35 files changed, 4,201 insertions(+), 128 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
index 875d8e5..5d94c14 100644
--- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
+++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -364,6 +364,21 @@
 PacketSubCMD_1=0x05
 PacketCallFunc_1=OnQueryNotifyEquipDetailInfo
 
+[CrossBattlefield]
+ScriptName = GameWorldLogic\CrossBattlefield.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 2
+
+PacketCMD_1=0xC0
+PacketSubCMD_1=0x07
+PacketCallFunc_1=OnCrossBattlefieldJoinByCall
+
+PacketCMD_2=0xC0
+PacketSubCMD_2=0x08
+PacketCallFunc_2=OnCrossBattlefieldCallKick
+
 [CrossRealmPK]
 ScriptName = GameWorldLogic\CrossRealmPK.py
 Writer = hxp
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 7a8650d..8b8846e 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -702,6 +702,8 @@
 Def_FBMapID_CrossGrasslandLing = 32040
 #跨服仙草园
 Def_FBMapID_CrossGrasslandXian = 32050
+#跨服战场
+Def_FBMapID_CrossBattlefield = 32060
 #情缘副本
 Def_FBMapID_Love = 31300
 
@@ -717,6 +719,7 @@
                          Def_FBMapID_CrossDemonKing:"CrossZonePK",
                          Def_FBMapID_CrossGrasslandLing:"CrossZonePK",
                          Def_FBMapID_CrossGrasslandXian:"CrossZonePK",
+                         Def_FBMapID_CrossBattlefield:"CrossZonePK",
                          }
 #跨服分区对应地图配置表名 - 仅适用于固定地图及虚拟分线的跨服玩法
 Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 96ef755..f1a2139 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -3987,6 +3987,126 @@
 
 
 #------------------------------------------------------
+# C0 08 跨服战场召集场次踢人 #tagCGCrossBattlefieldCallKick
+
+class  tagCGCrossBattlefieldCallKick(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("TagPlayerID", c_int),    #目标玩家ID,即要被踢出去的玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x08
+        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 = 0x08
+        self.Hour = 0
+        self.Minute = 0
+        self.TagPlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCrossBattlefieldCallKick)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 08 跨服战场召集场次踢人 //tagCGCrossBattlefieldCallKick:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                TagPlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.TagPlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGCrossBattlefieldCallKick=tagCGCrossBattlefieldCallKick()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCrossBattlefieldCallKick.Cmd,m_NAtagCGCrossBattlefieldCallKick.SubCmd))] = m_NAtagCGCrossBattlefieldCallKick
+
+
+#------------------------------------------------------
+# C0 07 跨服战场加入召集场次 #tagCGCrossBattlefieldJoinByCall
+
+class  tagCGCrossBattlefieldJoinByCall(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("BuyPlayerID", c_int),    #加入目标玩家的召集队伍,即购买召集场的玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x07
+        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 = 0x07
+        self.Hour = 0
+        self.Minute = 0
+        self.BuyPlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCrossBattlefieldJoinByCall)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 07 跨服战场加入召集场次 //tagCGCrossBattlefieldJoinByCall:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                BuyPlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.BuyPlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGCrossBattlefieldJoinByCall=tagCGCrossBattlefieldJoinByCall()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCrossBattlefieldJoinByCall.Cmd,m_NAtagCGCrossBattlefieldJoinByCall.SubCmd))] = m_NAtagCGCrossBattlefieldJoinByCall
+
+
+#------------------------------------------------------
 # C0 03 强制退出跨服状态 #tagCGForceQuitCrossState
 
 class  tagCGForceQuitCrossState(Structure):
@@ -18941,6 +19061,66 @@
 
 
 #------------------------------------------------------
+# C1 09 跨服战场购买开启场次 #tagCMCrossBattlefieldBuyOpen
+
+class  tagCMCrossBattlefieldBuyOpen(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("Faction", c_ubyte),    #阵营 1-红;2-蓝
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.Hour = 0
+        self.Minute = 0
+        self.Faction = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMCrossBattlefieldBuyOpen)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 09 跨服战场购买开启场次 //tagCMCrossBattlefieldBuyOpen:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                Faction:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.Faction
+                                )
+        return DumpString
+
+
+m_NAtagCMCrossBattlefieldBuyOpen=tagCMCrossBattlefieldBuyOpen()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCrossBattlefieldBuyOpen.Cmd,m_NAtagCMCrossBattlefieldBuyOpen.SubCmd))] = m_NAtagCMCrossBattlefieldBuyOpen
+
+
+#------------------------------------------------------
 # C1 06 跨服NPC对话 #tagCMCrossNPCTalk
 
 class  tagCMCrossNPCTalk(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
index 7d369cc..6a91da3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -12288,6 +12288,283 @@
 
 
 #------------------------------------------------------
+# C0 09 跨服战场玩家购买战场信息 #tagGCCrossBattlefieldBuyInfo
+
+class  tagGCCrossBattlefieldPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)
+    PlayerName = ""    #(char PlayerName[33])
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)//等级
+    RealmLV = 0    #(WORD RealmLV)//境界
+    FightPower = 0    #(DWORD FightPower)//战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)//战力整除亿部分
+    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.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.RealmLV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 33
+        length += 1
+        length += 2
+        length += 2
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteString(data, 33, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                RealmLV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.RealmLV,
+                                self.FightPower,
+                                self.FightPowerEx
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyPlayer(Structure):
+    BuyPlayerID = 0    #(DWORD BuyPlayerID)//购买的玩家ID,即召集人
+    Faction = 0    #(BYTE Faction)//阵营 1-红;2-蓝
+    FactionPlayerCount = 0    #(BYTE FactionPlayerCount)
+    FactionPlayerList = list()    #(vector<tagGCCrossBattlefieldPlayer> FactionPlayerList)//阵营所有玩家列表,包含召集人
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.BuyPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Faction,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.FactionPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.FactionPlayerCount):
+            temFactionPlayerList = tagGCCrossBattlefieldPlayer()
+            _pos = temFactionPlayerList.ReadData(_lpData, _pos)
+            self.FactionPlayerList.append(temFactionPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.BuyPlayerID = 0
+        self.Faction = 0
+        self.FactionPlayerCount = 0
+        self.FactionPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += 1
+        for i in range(self.FactionPlayerCount):
+            length += self.FactionPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.BuyPlayerID)
+        data = CommFunc.WriteBYTE(data, self.Faction)
+        data = CommFunc.WriteBYTE(data, self.FactionPlayerCount)
+        for i in range(self.FactionPlayerCount):
+            data = CommFunc.WriteString(data, self.FactionPlayerList[i].GetLength(), self.FactionPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                BuyPlayerID:%d,
+                                Faction:%d,
+                                FactionPlayerCount:%d,
+                                FactionPlayerList:%s
+                                '''\
+                                %(
+                                self.BuyPlayerID,
+                                self.Faction,
+                                self.FactionPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyHM(Structure):
+    Hour = 0    #(BYTE Hour)//战场开启时
+    Minute = 0    #(BYTE Minute)//战场开启分
+    BuyPlayerCount = 0    #(BYTE BuyPlayerCount)
+    BuyPlayerList = list()    #(vector<tagGCCrossBattlefieldBuyPlayer> BuyPlayerList)//购买本场次的玩家信息列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.Hour,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Minute,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.BuyPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BuyPlayerCount):
+            temBuyPlayerList = tagGCCrossBattlefieldBuyPlayer()
+            _pos = temBuyPlayerList.ReadData(_lpData, _pos)
+            self.BuyPlayerList.append(temBuyPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.Hour = 0
+        self.Minute = 0
+        self.BuyPlayerCount = 0
+        self.BuyPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.BuyPlayerCount):
+            length += self.BuyPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.Hour)
+        data = CommFunc.WriteBYTE(data, self.Minute)
+        data = CommFunc.WriteBYTE(data, self.BuyPlayerCount)
+        for i in range(self.BuyPlayerCount):
+            data = CommFunc.WriteString(data, self.BuyPlayerList[i].GetLength(), self.BuyPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Hour:%d,
+                                Minute:%d,
+                                BuyPlayerCount:%d,
+                                BuyPlayerList:%s
+                                '''\
+                                %(
+                                self.Hour,
+                                self.Minute,
+                                self.BuyPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyInfo(Structure):
+    Head = tagHead()
+    HMCount = 0    #(BYTE HMCount)// 为0时清空重置,其他为增量更新
+    HMBuyList = list()    #(vector<tagGCCrossBattlefieldBuyHM> HMBuyList)//购买场次列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x09
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.HMCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.HMCount):
+            temHMBuyList = tagGCCrossBattlefieldBuyHM()
+            _pos = temHMBuyList.ReadData(_lpData, _pos)
+            self.HMBuyList.append(temHMBuyList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x09
+        self.HMCount = 0
+        self.HMBuyList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        for i in range(self.HMCount):
+            length += self.HMBuyList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.HMCount)
+        for i in range(self.HMCount):
+            data = CommFunc.WriteString(data, self.HMBuyList[i].GetLength(), self.HMBuyList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                HMCount:%d,
+                                HMBuyList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.HMCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossBattlefieldBuyInfo=tagGCCrossBattlefieldBuyInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBattlefieldBuyInfo.Head.Cmd,m_NAtagGCCrossBattlefieldBuyInfo.Head.SubCmd))] = m_NAtagGCCrossBattlefieldBuyInfo
+
+
+#------------------------------------------------------
 # C0 07 跨服排行榜信息 #tagGCCrossBillboardInfo
 
 class  tagGCCrossBillboardData(Structure):
@@ -40971,6 +41248,62 @@
 
 
 #------------------------------------------------------
+# C1 07 跨服战场玩家信息 #tagMCCrossBattlefieldPlayerInfo
+
+class  tagMCCrossBattlefieldPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("BuyOpenCountToday", c_ubyte),    # 今日已购买开启战场次数
+                  ("HighScoreToday", c_int),    # 今日最高积分
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x07
+        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 = 0x07
+        self.BuyOpenCountToday = 0
+        self.HighScoreToday = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCrossBattlefieldPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 07 跨服战场玩家信息 //tagMCCrossBattlefieldPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                BuyOpenCountToday:%d,
+                                HighScoreToday:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.BuyOpenCountToday,
+                                self.HighScoreToday
+                                )
+        return DumpString
+
+
+m_NAtagMCCrossBattlefieldPlayerInfo=tagMCCrossBattlefieldPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCrossBattlefieldPlayerInfo.Cmd,m_NAtagMCCrossBattlefieldPlayerInfo.SubCmd))] = m_NAtagMCCrossBattlefieldPlayerInfo
+
+
+#------------------------------------------------------
 # C1 02 跨服PK玩家奖励记录 #tagMCCrossRealmPKAwardState
 
 class  tagMCCrossRealmPKAwardState(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CrossFB.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CrossFB.py
new file mode 100644
index 0000000..c30a19c
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/CrossFB.py
@@ -0,0 +1,212 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.CrossFB
+#
+# @todo:跨服副本
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服副本
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PyGameData
+import IpyGameDataPY
+import PlayerFB
+
+#---------------------------------------------------------------------
+#逻辑实现
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList [cmdIndex gmAccID msg]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, gmList):
+    ## 本服处理
+    GameWorld.DebugAnswer(curPlayer, "----------------------------")
+    if not gmList:
+        GameWorld.DebugAnswer(curPlayer, "输出人数: CrossFB mapID")
+        GameWorld.DebugAnswer(curPlayer, "虚拟进入: CrossFB mapID 功能线路 人数 等级")
+        GameWorld.DebugAnswer(curPlayer, "添加人数: CrossFB 1 场景ID 虚拟线路 在线 离线")
+        GameWorld.DebugAnswer(curPlayer, "扣除人数: CrossFB 2 场景ID 虚拟线路 在线 离线")
+    return
+
+def OnMergeServerExec(gmList, tick):
+    ## 跨服处理
+    
+    serverGroupID = gmList[-2]
+    playerID = gmList[-1]
+    
+    dynamicLineMapDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 1, {})
+    gmList = gmList[:-2]
+    if not gmList:
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "---以下为可分流场景虚拟线路条数")
+        for mapID, mapIDList in dynamicLineMapDict.items():
+            gameMap = GameWorld.GetMap(mapID)
+            if not gameMap:
+                continue
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "动态分流: %s【mapID:%s】" % (gameMap.GetMapName(), mapID))
+            for realMapID in mapIDList:
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "    分流场景虚拟线路数:%s\t%s" 
+                                           % (realMapID, PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0)))
+        return
+    
+    value0 = gmList[0]
+    mapID = value0
+    if value0 in [1, 2]:
+        if len(gmList) != 5:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "参数不足,请重新输入")
+            return
+        realMapID, copyMapID, fbPlayerCount, offlineCount = gmList[1:]
+        
+        key = (realMapID, copyMapID)
+        if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "不存在该场景线路或未开启!realMapID=%s,copyMapID=%s" % (realMapID, copyMapID))
+            return
+        copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key] # CrossCopyMapInfo
+        
+        mapID = __GetMapIDByRealMapID(dynamicLineMapDict, realMapID)
+        if mapID not in dynamicLineMapDict:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "分流场景地图错误")
+            return
+        
+        # 添加
+        if value0 == 1:
+            robotID = __GetMapRobotID(dynamicLineMapDict[mapID])
+            for _ in xrange(fbPlayerCount):
+                robotID += 1
+                copyMapObj.fbPlayerDict[robotID] = serverGroupID
+                
+            for _ in xrange(offlineCount):
+                robotID += 1
+                copyMapObj.offlinePlayerDict[robotID] = serverGroupID
+                
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "场景%s线%s:添加在线(%s),离线(%s)" % (realMapID, copyMapID, fbPlayerCount, offlineCount))
+            
+        # 扣除
+        else:
+            delFBPlayerCount, delOfflinePlayerCount = 0, 0
+            fbPlayerIDList = copyMapObj.fbPlayerDict.keys()
+            for pID in fbPlayerIDList:
+                if pID < 10000:
+                    copyMapObj.fbPlayerDict.pop(pID, 0)
+                    delFBPlayerCount += 1
+                    if delFBPlayerCount >= fbPlayerCount:
+                        break
+                    
+            offlinePlayerIDList = copyMapObj.offlinePlayerDict.keys()
+            for pID in offlinePlayerIDList:
+                if pID < 10000:
+                    copyMapObj.offlinePlayerDict.pop(pID, 0)
+                    delOfflinePlayerCount += 1
+                    if delOfflinePlayerCount >= offlineCount:
+                        break
+            
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "场景%s线%s:删除在线(%s),离线(%s)" % (realMapID, copyMapID, delFBPlayerCount, delOfflinePlayerCount))
+            
+        waitPlayerCount, fbPlayerCount, offlinePlayerCount = len(copyMapObj.waitPlayerDict), len(copyMapObj.fbPlayerDict), len(copyMapObj.offlinePlayerDict)
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "    %s,功能区-线-场:%s-%s-%s,等待%s,副本%s,离线%s" 
+                                   % (copyMapID, copyMapObj.zoneID, copyMapObj.funcLineID, copyMapObj.newFuncLineNum, 
+                                      waitPlayerCount, fbPlayerCount, offlinePlayerCount))
+        
+    # 虚拟玩家进入: CrossFB mapID funcLineID 等级 人数
+    elif len(gmList) >= 4:
+        mapID, funcLineID, enterCount, lv = gmList
+        if mapID not in dynamicLineMapDict:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "mapID错误")
+            return
+        
+        robotID = __GetMapRobotID(dynamicLineMapDict[mapID])
+        
+        GameWorld.DebugLog("mapID=%s,robotID=%s" % (mapID, robotID))
+        okCount = 0
+        copyMapObj = None
+        for _ in xrange(enterCount):
+            robotID += 1
+            msgData = {"PlayerID":robotID, "MapID":mapID, "FuncLineID":funcLineID, "LV":lv}
+            copyMapObj = PlayerFB.ClientServerMsg_EnterFB(serverGroupID, msgData, tick)
+            if not copyMapObj:
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "进入失败,查看跨服GameServer日志")
+                break
+            okCount += 1
+            copyMapObj.waitPlayerDict.pop(robotID, None)
+            copyMapObj.offlinePlayerDict.pop(robotID, None)
+            copyMapObj.fbPlayerDict[robotID] = serverGroupID
+            
+        if copyMapObj:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "虚拟进入:%s - %s, LV:(%s), 个数(%s), 成功(%s)" % (mapID, funcLineID, lv, enterCount, okCount))
+            waitPlayerCount, fbPlayerCount, offlinePlayerCount = len(copyMapObj.waitPlayerDict), len(copyMapObj.fbPlayerDict), len(copyMapObj.offlinePlayerDict)
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "    %s,功能区-线-场:%s-%s-%s,等待%s,副本%s,离线%s" 
+                                       % (copyMapObj.copyMapID, copyMapObj.zoneID, copyMapObj.funcLineID, copyMapObj.newFuncLineNum, 
+                                          waitPlayerCount, fbPlayerCount, offlinePlayerCount))
+            
+    elif len(gmList) == 1:
+        pass
+    else:
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "参数个数错误!")
+        return
+    
+    gameMap = GameWorld.GetMap(mapID)
+    if mapID not in dynamicLineMapDict or not gameMap:
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "不存在该分流副本地图! %s" % mapID)
+        return
+    
+    GameWorld.DebugAnswerCross(playerID, serverGroupID, "---分流场景明细: %s【mapID:%s】" % (gameMap.GetMapName(), mapID))
+    dynamicMapIDList = dynamicLineMapDict[mapID]
+    for realMapID in dynamicMapIDList:
+        copyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0)
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "分流场景【%s】虚拟线路数%s条" % (realMapID, copyMapCount))
+        
+        playerCountTotal = 0
+        for copyMapID in xrange(copyMapCount):
+            key = (realMapID, copyMapID)
+            if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
+                continue
+            copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key] # CrossCopyMapInfo
+            
+            waitPlayerCount, fbPlayerCount, offlinePlayerCount = len(copyMapObj.waitPlayerDict), len(copyMapObj.fbPlayerDict), len(copyMapObj.offlinePlayerDict)
+            playerCount = waitPlayerCount + fbPlayerCount + offlinePlayerCount
+            #if not playerCount:
+            #    continue
+            
+            playerCountTotal += playerCount
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "    %s,功能区-线-场:%s-%s-%s,等待%s,副本%s,离线%s" 
+                                       % (copyMapID, copyMapObj.zoneID, copyMapObj.funcLineID, copyMapObj.newFuncLineNum, 
+                                          waitPlayerCount, fbPlayerCount, offlinePlayerCount))
+            
+        if not playerCountTotal:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "    该分流场景地图没人!")
+            
+    return
+
+def OnGetMergeParam(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    serverGroupID = GameWorld.GetServerGroupID()
+    return [serverGroupID, playerID]
+
+def __GetMapIDByRealMapID(dynamicLineMapDict, realMapID):
+    for mapID, mapIDList in dynamicLineMapDict.items():
+        if realMapID in mapIDList:
+            return mapID
+    return 0
+
+def __GetMapRobotID(dynamicMapIDList):
+    robotID = 0
+    for realMapID in dynamicMapIDList:
+        copyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0)
+        for copyMapID in xrange(copyMapCount):
+            key = (realMapID, copyMapID)
+            if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
+                continue
+            copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key] # CrossCopyMapInfo
+            playerIDList = list(set(copyMapObj.waitPlayerDict.keys() + copyMapObj.fbPlayerDict.keys() + copyMapObj.offlinePlayerDict.keys()))
+            for playerID in playerIDList:
+                if playerID < 10000 and playerID > robotID:
+                    robotID = playerID
+    return robotID
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnDay.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnDay.py
index 4b0c18e..41fce87 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnDay.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnDay.py
@@ -33,22 +33,16 @@
 #  @return None
 #  @remarks 函数详细说明. 有的任务一天只能做限定次数,或有的操作一天只能做一次
 #  用来刷新任务状态或其它
-def OnExec(curPlayer,playerList):
+def OnExec(curPlayer, gmList):
+    __DoExecOnDay(gmList)
+    return
+
+def __DoExecOnDay(gmList):
     timeStr = GameWorld.GetCurrentDataTimeStr()
     tick = GameWorld.GetGameWorld().GetTick()
-    
-    if len(playerList) == 0:
-        DoLogic_GM_OnDay( timeStr , tick )
-        return
-    
-    count = playerList[0]
-    
-    if count > 5:
-        return
-    
-    for i in range( count ):
-        DoLogic_GM_OnDay( timeStr , tick )
-            
+    count = 1 if not gmList else min(gmList[0], 5)
+    for _ in xrange(count):
+        DoLogic_GM_OnDay(timeStr , tick)
     return
 
 ## 世界服务器执行  test_OnHour test_OnDay 一次 并通知在线所有玩家
@@ -56,25 +50,34 @@
 #  @param tick     当前tick
 #  @return 无返回值
 #  @remarks 函数详细说明:世界服务器执行 test_OnHour test_OnDay 一次
-def DoLogic_GM_OnDay( timeStr , tick ):
+def DoLogic_GM_OnDay(timeStr , tick):
     playerManager = GameWorld.GetPlayerManager()
     
-    for i in range( 0, playerManager.GetPlayerCount() ):
-        curPlayer = playerManager.GetPlayerByIndex( i )
+    for i in range(0, playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(i)
         
         if not curPlayer or curPlayer.IsEmpty():
             continue
         
-        mapID = GameWorld.GetQueryPlayerMapID( curPlayer )
+        mapID = GameWorld.GetQueryPlayerMapID(curPlayer)
         
         if not mapID:
             continue
         
-        playerManager.MapServer_QueryPlayer( 0, 0, curPlayer.GetID(), mapID, 'GMDateTime', 'GMOnDay', len("GMOnDay"))
+        playerManager.MapServer_QueryPlayer(0, 0, curPlayer.GetID(), mapID, 'GMDateTime', 'GMOnDay', len("GMOnDay"))
         
     GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OnDayEx, 0)
     
-    GameWorldProcess.OnHour( timeStr , tick )
-    GameWorldProcess.OnDay( timeStr , tick )
+    GameWorldProcess.OnHour(timeStr , tick)
+    GameWorldProcess.OnDay(timeStr , tick)
     GameWorldProcess.OnDayEx(tick)
     return
+
+def OnGetMergeParam(curPlayer):
+    ## 跨服命令额外参数
+    return []
+
+def OnMergeServerExec(gmList, tick):
+    ## 跨服执行命令
+    __DoExecOnDay(gmList)
+    return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnWeek.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnWeek.py
index baca40c..0c500b1 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnWeek.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/test_OnWeek.py
@@ -31,22 +31,16 @@
 #  @param playerList 命令执行的次数 小于=于3 
 #  @return None
 #  @remarks 函数详细说明. 世界服务器执行OnWeek
-def OnExec(curPlayer,playerList):
+def OnExec(curPlayer, gmList):
+    __DoExecOnWeek(gmList)
+    return
+
+def __DoExecOnWeek(gmList):
     timeStr = GameWorld.GetCurrentDataTimeStr()
     tick = GameWorld.GetGameWorld().GetTick()
-    
-    if len(playerList) == 0:
-        DoLogic_GM_OnWeek( timeStr , tick )
-        return
-    
-    count = playerList[0]
-    
-    if count > 3:
-        return
-        
-    for i in range( count ):
-        DoLogic_GM_OnWeek( timeStr, tick )
-            
+    count = 1 if not gmList else min(gmList[0], 5)
+    for _ in xrange(count):
+        DoLogic_GM_OnWeek(timeStr , tick)
     return
 
 ## 全局函数简要说明:世界服务器执行  test_OnWeek  一次 并通知在线所有玩家
@@ -79,3 +73,12 @@
     GameWorldProcess.OnWeek( timeStr , tick )
     GameWorldProcess.OnWeekEx(tick)
     return
+
+def OnGetMergeParam(curPlayer):
+    ## 跨服命令额外参数
+    return []
+
+def OnMergeServerExec(gmList, tick):
+    ## 跨服执行命令
+    __DoExecOnWeek(gmList)
+    return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
index 256d3c3..ce05c72 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
@@ -1126,6 +1126,24 @@
     curPlayer.DebugAnswer(text)
     return
 
+def CrossServerMsg_DebugAnswer(msgData):
+    playerID, text = msgData
+    curPlayer = GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    curPlayer.DebugAnswer(text)
+    return
+
+def DebugAnswerCross(playerID, serverGroupID, text):
+    DebugLog(text)
+    text = text.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
+    
+    import CrossRealmMsg
+    dataMsg = [playerID, text]
+    serverGroupIDList = [serverGroupID]
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_DebugAnswer, dataMsg, serverGroupIDList)
+    return
+
 def GetMap(mapID): return IpyGameDataPY.GetIpyGameData("ChinMap", mapID)
 
 def GetNPCData(npcID): return IpyGameDataPY.GetIpyGameData("ChinNPC", npcID)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBattlefield.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBattlefield.py
new file mode 100644
index 0000000..0521929
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBattlefield.py
@@ -0,0 +1,1120 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossBattlefield
+#
+# @todo:跨服战场
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服战场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+
+import datetime
+import PyGameData
+import CrossRealmPK
+import CrossRealmMsg
+import PlayerControl
+import PyDataManager
+import ChPyNetSendPack
+import CrossRealmPlayer
+import PlayerCompensation
+import PlayerViewCache
+import CrossBillboard
+import IpyGameDataPY
+import NetPackCommon
+import ShareDefine
+import GameWorld
+import PlayerFB
+import ChConfig
+
+import operator
+import time
+
+'''
+热更配置
+修改开启时间,只能等当天都结束了才能更新,即隔天生效,不然可能导致已购买场次的玩家购买数据丢失
+其他配置暂无影响,可直接热更
+
+合服
+开放时间同跨服PK一样,赛季结束期间不可购买,不可开启,给分区调整腾出空间,功能不考虑分区变更带来的问题
+'''
+
+Def_RecType_CrossBattlefieldBuy = ShareDefine.Def_UniversalGameRecType_CrossBattlefieldBuy
+'''
+玩家开启的跨服战场
+ShareDefine.Def_UniversalGameRecType_CrossBattlefieldBuy
+time:time                购买时间
+value1:zoneID            分区ID
+value2:hmNum            时分场次编号
+value3:playerID        购买的玩家ID
+value4:factionID        所选择的阵营ID
+
+StrValue3:[callPlayerID,...]    召集来的玩家ID,包含自己
+'''
+
+class CrossBattlefieldBuy():
+    ''' 跨服战场购买记录
+    '''
+    def __init__(self):
+        self.Clear()
+        return
+    
+    def Clear(self):
+        self.buyTime = 0
+        self.hmNum = 0
+        self.zoneID = 0
+        self.playerID = 0
+        self.factionID = 0
+        self.callPlayerIDList = []
+        
+        # 子服用,跨服服务器同步数据时负值; 不存库,玩家属性缓存信息,本服玩家取自己服务器最新缓存
+        self.callPlayerDict = {} # {playerID:{attrName:value, ...}, ...}
+        return
+    
+    def GetSyncClientServerString(self):
+        self.callPlayerDict = {}
+        for playerID in self.callPlayerIDList:
+            curCache = PlayerViewCache.FindViewCache(playerID)
+            if not curCache:
+                continue
+            cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+            self.callPlayerDict[playerID] = {"Name":cacheDict["Name"], "Job":cacheDict["Job"], "LV":cacheDict["LV"], 
+                                             "RealmLV":cacheDict["RealmLV"], "FightPower":cacheDict["FightPower"]}
+            
+        return {"buyTime":self.buyTime, "hmNum":self.hmNum, "zoneID":self.zoneID, "playerID":self.playerID, "factionID":self.factionID,
+                "callPlayerIDList":self.callPlayerIDList, "callPlayerDict":self.callPlayerDict}
+        
+    def SetAttr(self, attrDict):
+        for k, v in attrDict.items():
+            setattr(self, k, v)
+        return
+
+def OnServerStart():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    PyGameData.g_crossBattlefieldBuyInfo = {}
+    
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    recDataList = universalRecMgr.GetTypeList(Def_RecType_CrossBattlefieldBuy)
+    GameWorld.Log("加载跨服战场购买记录! %s" % recDataList.Count())
+    
+    for index in xrange(recDataList.Count()):
+        recData = recDataList.At(index)
+        zoneID = recData.GetValue1()
+        hmNum = recData.GetValue2()
+        playerID = recData.GetValue3()
+        factionID = recData.GetValue4()
+        
+        strValue3 = recData.GetStrValue3()
+            
+        buyRec = CrossBattlefieldBuy()
+        buyRec.buyTime = recData.GetTime()
+        buyRec.zoneID = zoneID
+        buyRec.hmNum = hmNum
+        buyRec.playerID = playerID
+        buyRec.factionID = factionID
+        buyRec.callPlayerIDList = eval(strValue3) if strValue3 else []
+        
+        buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+        buyPlayerInfo[playerID] = buyRec
+        
+        GameWorld.Log("    %s" % buyRec.GetSyncClientServerString())
+        
+    return
+
+def OnServerClose():
+    if not GameWorld.IsCrossServer():
+        return
+    
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    universalRecMgr.Delete(Def_RecType_CrossBattlefieldBuy)
+    
+    GameWorld.Log("保存跨服战场购买记录!")
+    
+    recDataList = universalRecMgr.GetTypeList(Def_RecType_CrossBattlefieldBuy)
+    for _, buyHMInfo in PyGameData.g_crossBattlefieldBuyInfo.items():
+        for _, buyPlayerInfo in buyHMInfo.items():
+            for buyRec in buyPlayerInfo.values():
+                GameWorld.Log("    %s" % buyRec.GetSyncClientServerString())
+                
+                recData = recDataList.AddRec()
+                recData.SetTime(buyRec.buyTime)
+                
+                recData.SetValue1(buyRec.zoneID)
+                recData.SetValue2(buyRec.hmNum)
+                recData.SetValue3(buyRec.playerID)
+                recData.SetValue4(buyRec.factionID)
+                
+                recData.SetStrValue3(str(buyRec.callPlayerIDList).replace(" ", ""))
+                
+    return
+
+def GetHMNum(openHour, openMinute): return openHour * 100 + openMinute
+def GetHMByNum(hmNum): return hmNum / 100, hmNum % 100
+
+def OnPlayerLogin(curPlayer):
+    serverGroupID = GameWorld.GetServerGroupID()
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    SyncCrossBattlefieldBuyInfo(None, zoneID)
+    return
+
+def DoOnDayEx():
+    if not GameWorld.IsCrossServer():
+        return
+    PyGameData.g_crossBattlefieldBuyInfo = {}
+    Sync_CrossBattlefieldDataToClientServer()
+    return
+
+def DoOnWeekEx():
+    if not GameWorld.IsCrossServer():
+        return
+    
+    enterWeekOrderAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBillboard", 3, {}) # 周参与榜名次对应奖励物品列表 {"名次":[[物品ID,个数,是否拍品], ...], ...} , 名次配置支持段配置
+    callWeekOrderAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBillboard", 4, {}) # 周召集榜名次对应奖励物品列表 {"名次":[[物品ID,个数,是否拍品], ...], ...} , 名次配置支持段配置
+    scoreWeekOrderAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBillboard", 5, {}) # 周参与榜名次对应奖励物品列表 {"名次":[[物品ID,个数,是否拍品], ...], ...} , 名次配置支持段配置
+    
+    enterWeekOrderIntAwardDict = {int(k):v for k, v in enterWeekOrderAwardDict.items()}
+    callWeekOrderIntAwardDict = {int(k):v for k, v in callWeekOrderAwardDict.items()}
+    scoreWeekOrderIntAwardDict = {int(k):v for k, v in scoreWeekOrderAwardDict.items()}
+    
+    billboardDict = {
+                     ShareDefine.Def_CBT_BattlefieldWJoin:[enterWeekOrderIntAwardDict, "CrossBattlefieldEnterOrderWeek"],
+                     ShareDefine.Def_CBT_BattlefieldWCall:[callWeekOrderIntAwardDict, "CrossBattlefieldCallOrderWeek"],
+                     ShareDefine.Def_CBT_BattlefieldWScore:[scoreWeekOrderIntAwardDict, "CrossBattlefieldScoreOrderWeek"],
+                     }
+    # 结算周榜
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    for billboardType, doInfo in billboardDict.items():
+        awardDict, mailKey = doInfo
+        groupList = billboardMgr.GetBillboardGroupList(billboardType)
+        GameWorld.Log("过周结算跨服战场周榜奖励: billboardType=%s,groupList=%s" % (billboardType, groupList))
+        for billboardType, groupValue1, groupValue2 in groupList:
+            billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+            if not billboardObj:
+                continue
+            billboardObj.SortData()
+            for i in xrange(billboardObj.GetCount()):
+                billboardData = billboardObj.At(i)
+                if not billboardData:
+                    continue
+                playerID = billboardData.ID
+                rank = i + 1
+                awardItemList = GameWorld.GetOrderValueByDict(awardDict, rank)
+                paramList = [rank]
+                PlayerCompensation.SendMailByKey(mailKey, [playerID], awardItemList, paramList, crossMail=True)
+                    
+            billboardObj.ClearData()
+            
+    return
+
+def GetCrossBattlefieldState():
+    return GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield)
+
+def IsBattlefieldCallPlayer(playerID):
+    ## 是否战场召集玩家,包含被召集玩家
+    for buyHMInfo in PyGameData.g_crossBattlefieldBuyInfo.values():
+        for buyPlayerInfo in buyHMInfo.values():
+            for buyRec in buyPlayerInfo.values():
+                if playerID in buyRec.callPlayerIDList:
+                    return True
+    return False
+
+def GetBuyPlayerInfo(zoneID, hmNum):
+    ## 获取战场购买召集场次玩家信息
+    ## @return: buyPlayerInfo={playerID:CrossBattlefieldBuy, ...}
+    if zoneID not in PyGameData.g_crossBattlefieldBuyInfo:
+        PyGameData.g_crossBattlefieldBuyInfo[zoneID] = {}
+    buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo[zoneID]
+    if hmNum not in buyHMInfo:
+        buyHMInfo[hmNum] = {}
+    buyPlayerInfo = buyHMInfo[hmNum]
+    return buyPlayerInfo
+
+def Sync_CrossBattlefieldDataToClientServer(serverGroupID=0):
+    ''' 同步跨服战场数据到子服务器
+    @param serverGroupID: 为0时同步所有子服
+    '''
+    
+    GameWorld.Log("同步给子服跨服战场数据: syncServerGroupID=%s" % (serverGroupID))
+    if serverGroupID:
+        ipyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+        if not ipyData:
+            return
+        crossZoneList = [ipyData]
+    else:
+        crossZoneName = GameWorld.GetCrossZoneName()
+        crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
+        
+    if not crossZoneList:
+        return
+    
+    # 通知状态 - 全区一致
+    battlefieldState = GetCrossBattlefieldState()
+    dataMsg = {"battlefieldState":battlefieldState}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_BattlefieldState, dataMsg)
+    
+    for zoneIpyData in crossZoneList:
+        zoneID = zoneIpyData.GetZoneID()
+        serverGroupIDList = [serverGroupID] if serverGroupID else zoneIpyData.GetServerGroupIDList()
+        
+        # 通知购买信息
+        Send_CrossServerMsg_BattlefieldBuy(zoneID, serverGroupIDList)
+                
+    return
+
+def Send_CrossServerMsg_BattlefieldBuy(zoneID, serverGroupIDList, opData=None):
+    # 通知子服购买信息
+    
+    buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo.get(zoneID, {})
+    if opData:
+        hmNum = GetHMNum(opData["openHour"], opData["openMinute"])
+        hmNumList = [hmNum]
+    else:
+        hmNumList = buyHMInfo.keys()
+        
+    syncBuyHMInfo = {}
+    for hmNum in hmNumList:
+        if hmNum not in buyHMInfo:
+            continue
+        buyPlayerInfo = buyHMInfo[hmNum]
+        
+        syncBuyPlayerInfo = {}
+        for playerID, buyRec in buyPlayerInfo.items():
+            syncBuyPlayerInfo[playerID] = buyRec.GetSyncClientServerString()
+        syncBuyHMInfo[hmNum] = syncBuyPlayerInfo
+        
+    sendMsg = {"zoneID":zoneID, "syncBuyHMInfo":syncBuyHMInfo, "opData":opData}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_BattlefieldBuy, sendMsg, serverGroupIDList)
+    return
+
+def OnMapServerInitOK():
+    # 通知地图服务器状态
+    SyncMapServerCrossBattlefieldBuyInfo()
+    return
+
+def SyncMapServerCrossBattlefieldBuyInfo():
+    #if not GameWorld.IsCrossServer():
+    #    return
+    syncMapBuyInfo = {}
+    for zoneID, buyHMInfo in PyGameData.g_crossBattlefieldBuyInfo.items():
+        syncMapBuyInfo[zoneID] = {}
+        for hmNum, buyPlayerInfo in buyHMInfo.items():
+            buyInfo = {}
+            for playerID, buyRec in buyPlayerInfo.items():
+                buyInfo[playerID] = {"callPlayerIDList":buyRec.callPlayerIDList, "factionID":buyRec.factionID}
+            syncMapBuyInfo[zoneID][hmNum] = buyInfo
+    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossBattlefieldCallTeamInfo, syncMapBuyInfo)
+    return
+
+def OnMinuteProcess():
+    if not GameWorld.IsCrossServer():
+        return
+    
+    Dispose_CrossBattlefieldState()
+    return
+
+def __GetCrossBattlefieldTime(isRefreshState=True):
+    
+    key = "CrossBattlefieldTimeInfo"
+    CrossBattlefieldTimeInfo = IpyGameDataPY.GetConfigEx(key)
+    serverTime = GameWorld.GetServerTime()
+    reloadSign = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day)
+    if CrossBattlefieldTimeInfo and CrossBattlefieldTimeInfo[0] == reloadSign:
+        GameWorld.DebugLog("已经加载过本日跨服战场时间状态信息!reloadSign=%s" % reloadSign)
+        return False, CrossBattlefieldTimeInfo[1]
+    
+    sysOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 1)
+    callOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 2)
+    allOpenHMList = sysOpenHMList + callOpenHMList
+    dailyIpyData = IpyGameDataPY.GetIpyGameData("DailyAction", ShareDefine.DailyActionID_CrossBattlefield)
+    fbTotalMinutes = dailyIpyData.GetDuration() if dailyIpyData else 10
+    
+    openNotifyMinuteList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 3)
+    
+    battleTimeInfoList = []
+    
+    startDateStr = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day)
+    for openHour, openMinute in allOpenHMList:
+        
+        openDateTime = datetime.datetime.strptime("%s %02d:%02d:00" % (startDateStr, openHour, openMinute), ChConfig.TYPE_Time_Format)
+        closeDateTime = openDateTime + datetime.timedelta(minutes=fbTotalMinutes)
+        
+        notifyOpenTimeDict = {}
+        for notifyOpenMinute in openNotifyMinuteList:
+            notifyOpenDateTime = openDateTime + datetime.timedelta(minutes=-notifyOpenMinute)
+            notifyOpenTimeDict[notifyOpenDateTime] = notifyOpenMinute
+            
+        battleTimeInfoList.append([openHour, openMinute, openDateTime, closeDateTime, notifyOpenTimeDict])
+        
+    CrossBattlefieldTimeInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, battleTimeInfoList])
+    
+    GameWorld.Log("本日跨服战场时间状态信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
+    GameWorld.Log("    allOpenHMList=%s,fbTotalMinutes=%s" % (allOpenHMList, fbTotalMinutes))
+    GameWorld.Log("=============================================================")
+    if isRefreshState:
+        Dispose_CrossBattlefieldState(True)
+        
+    return True, CrossBattlefieldTimeInfo[1]
+
+def Dispose_CrossBattlefieldState(reloadRefresh=False):
+    
+    isReload, battlefieldTimeList = __GetCrossBattlefieldTime(False)
+    isReload = isReload or reloadRefresh
+    
+    # 这里时间需精确到分钟,不然后面的比较会匹配不到
+    curDateTime = GameWorld.GetServerTime()
+    curDateTime = datetime.datetime.strptime("%d-%d-%d %d:%d:00" % (curDateTime.year, curDateTime.month, curDateTime.day,
+                                                                    curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
+    
+    battlefieldState = 0
+    for openHour, openMinute, openDateTime, closeDateTime, notifyOpenTimeDict in battlefieldTimeList:
+        
+        # 全服广播提示信息
+        if curDateTime in notifyOpenTimeDict:
+            notifyOpenMinute = notifyOpenTimeDict[curDateTime]
+            __DoBattlefieldOpenNotify(openHour, openMinute, notifyOpenMinute)
+            
+        if openDateTime <= curDateTime < closeDateTime:
+            battlefieldState = openHour * 100 + openMinute
+            
+    stateKey = ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield
+    gameWorld = GameWorld.GetGameWorld()
+    beforeState = gameWorld.GetDictByKey(stateKey)
+    
+    if not isReload and beforeState == battlefieldState:
+        #已经是这个状态了
+        return
+    
+    GameWorld.SendMapServerMsgEx(stateKey, battlefieldState) #通知Mapserver,设置字典
+    gameWorld.SetDict(stateKey, battlefieldState) #更新字典值
+    GameWorld.Log("跨服战场状态变更: beforeState=%s,battlefieldState=%s" % (beforeState, battlefieldState))
+    
+    # 开启副本
+    if battlefieldState and beforeState != battlefieldState:
+        # 移除已经存在的副本线路
+        PyGameData.g_crossDynamicLineInfo.pop(ChConfig.Def_FBMapID_CrossBattlefield, None)
+        
+        crossZoneName = GameWorld.GetCrossZoneName()
+        crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
+        if not crossZoneList:
+            crossZoneList = []
+            
+        hmNum = battlefieldState
+        openHour, openMinute = GetHMByNum(hmNum)
+        sysOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 1)
+        
+        for zoneIpyData in crossZoneList:
+            zoneID = zoneIpyData.GetZoneID()
+            
+            seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+            if seasonState != 1:
+                GameWorld.Log("    跨服PK赛季未开启中,跨服战场不开启! zoneID=%s" % zoneID)
+                continue
+            
+            # 系统局确保每个等级段都有一场
+            if [openHour, openMinute] in sysOpenHMList:
+                dynamicLineLVRangeDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 4, {})
+                lvRangeInfoList = dynamicLineLVRangeDict.get(ChConfig.Def_FBMapID_CrossBattlefield, [])
+                GameWorld.Log("    开启战场系统局,确保每个等级段都有一场: zoneID=%s,lvRangeInfoList=%s" % (zoneID, lvRangeInfoList))
+                if lvRangeInfoList:
+                    funcLineIDList = range(len(lvRangeInfoList))
+                    PlayerFB.OpenCrossDynamicLineBySys(zoneID, ChConfig.Def_FBMapID_CrossBattlefield, funcLineIDList, True)
+                    
+            # 有购买的场次默认只开一场
+            else:
+                buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo.get(zoneID, {})
+                if hmNum in buyHMInfo and len(buyHMInfo[hmNum]) > 0:
+                    GameWorld.Log("    有召集的场次开启分区战场! zoneID=%s" % (zoneID))
+                    funcLineIDList = [0]
+                    PlayerFB.OpenCrossDynamicLineBySys(zoneID, ChConfig.Def_FBMapID_CrossBattlefield, funcLineIDList, True)
+                else:
+                    GameWorld.Log("    无召集的场次不开分区战场! zoneID=%s" % (zoneID))
+                    
+    # 同步子服务器
+    dataMsg = {"battlefieldState":battlefieldState}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_BattlefieldState, dataMsg)
+    return
+
+def __DoBattlefieldOpenNotify(openHour, openMinute, notifyOpenMinute):
+    ''' 执行跨服战场开启广播
+                    跨服PK赛季未开启状态下,跨服战场同步关闭,故也不广播
+                    还要限制开服天开启
+    '''
+    
+    gameWorld = GameWorld.GetGameWorld()
+    sysOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 1)
+    if [openHour, openMinute] in sysOpenHMList:
+        
+        crossZoneName = GameWorld.GetCrossZoneName()
+        crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
+        if not crossZoneList:
+            return
+        
+        for zoneIpyData in crossZoneList:
+            zoneID = zoneIpyData.GetZoneID()
+            
+            seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+            if seasonState != 1:
+                GameWorld.DebugLog("跨服PK赛季未开启中,跨服战场系统开启广播不处理!")
+                continue
+            
+            notifyKey = "CrossBattlefieldOpenSys"
+            paramList = [notifyOpenMinute]
+            country = 0
+            serverGroupIDList = []
+            crossNotifyList = []
+            crossNotifyList.append([ShareDefine.CrossNotify_World, [country, notifyKey, paramList]])
+            PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList)
+            
+        return
+    
+    curHMNum = GetHMNum(openHour, openMinute)
+    
+    for zoneID, buyHMInfo in PyGameData.g_crossBattlefieldBuyInfo.items():
+        
+        seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+        if seasonState != 1:
+            GameWorld.DebugLog("跨服PK赛季未开启中,跨服战场玩家开启广播不处理!")
+            continue
+        
+        zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(ChConfig.Def_FBMapID_CrossBattlefield, zoneID)
+        if zoneIpyData:
+            continue
+        serverGroupIDList = zoneIpyData.GetServerGroupIDList()
+        
+        if curHMNum not in buyHMInfo:
+            continue
+        
+        buyPlayerInfo = buyHMInfo[curHMNum]
+        if not buyPlayerInfo:
+            continue
+        
+        matchTickSortList = sorted(buyPlayerInfo.values(), key=operator.attrgetter("buyTime"))
+        buyRec = matchTickSortList[0]
+        
+        notifyKey = "CrossBattlefieldOpenPlayer"
+        paramList = [buyRec.playerName, notifyOpenMinute]
+        country = 0
+        crossNotifyList = []
+        crossNotifyList.append([ShareDefine.CrossNotify_World, [country, notifyKey, paramList]])
+        PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList)
+        
+    return
+
+def GetCrossBattlefieldOpenTime(zoneID):
+    ## 获取跨服战场副本当前是否开放的时间点
+    #  @return: None-当前未开放;
+    #  @return: hour, minute  -  当前开放中的时间时分,可进入
+    
+    gameWorld = GameWorld.GetGameWorld()
+    hmNum = GetCrossBattlefieldState()
+    if not hmNum:
+        return
+    
+    seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+    if seasonState != 1:
+        return
+    
+    openHour, openMinute = GetHMByNum(hmNum)
+    sysOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 1)
+    isCallBattle = [openHour, openMinute] not in sysOpenHMList
+    if isCallBattle:
+        if zoneID not in PyGameData.g_crossBattlefieldBuyInfo:
+            GameWorld.DebugLog("该分区没有使用召集令! zoneID=%s" % zoneID)
+            return
+        buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo[zoneID]
+        if hmNum not in buyHMInfo:
+            GameWorld.DebugLog("该时段还未使用召集令! zoneID=%s,hmNum=%s" % (zoneID, hmNum))
+            return
+        
+    return isCallBattle, openHour, openMinute
+
+def GetCallPlayerCopymapObj(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, includeOffline, tick):
+    ## 获取玩家召集令队伍对应的副本分线
+    ## @return tagCopyMapObj
+    
+    hmNum = GetCrossBattlefieldState()
+    if not hmNum:
+        return
+    
+    if mapID not in PyGameData.g_crossDynamicLineInfo:
+        PyGameData.g_crossDynamicLineInfo[mapID] = {}
+    zoneLineDict = PyGameData.g_crossDynamicLineInfo[mapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
+    zoneLineKey = (zoneID, funcLineID)
+    if zoneLineKey not in zoneLineDict:
+        zoneLineDict[zoneLineKey] = []
+    funcLineObjList = zoneLineDict[zoneLineKey]
+    if not funcLineObjList:
+        return
+    
+    # 召集令场次,每个分区固定只有一场
+    for _, funcLineObj in enumerate(funcLineObjList, 1):
+        realMapID, copyMapID = funcLineObj.realMapID, funcLineObj.copyMapID
+        if not realMapID:
+            continue
+        key = (realMapID, copyMapID)
+        if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
+            continue
+        copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
+        
+        if copyMapObj.zoneID != zoneID:
+            continue
+        
+        # 召集令成员不受人数限制
+        buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo.get(zoneID, {})
+        if hmNum not in buyHMInfo:
+            continue
+        buyPlayerInfo = buyHMInfo[hmNum]
+        for buyRec in buyPlayerInfo.values():
+            if playerID in buyRec.callPlayerIDList:
+                GameWorld.DebugLog("召集令成员不受人数限制,可进入! playerID=%s" % playerID)
+                return copyMapObj
+        
+        canEnter = copyMapObj.OnRequestEnterCrossCopyMap(playerID, tick, copyMapPlayerMax, includeOffline)
+        if canEnter:
+            return copyMapObj
+        
+    return
+
+def ClientServerMsg_BattlefieldBuyOpen(serverGroupID, msgData):
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    
+    gameWorld = GameWorld.GetGameWorld()
+    seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+    if seasonState != 1:
+        GameWorld.Log("跨服PK赛季未开启中,跨服战场也不能开启,无法购买!")
+        return
+    
+    playerID = msgData["playerID"] # 角色ID
+    playerName = msgData["playerName"] # 玩家名
+    job = msgData["playerJob"] # 职业
+    playerLV = msgData["playerLV"] # 职业
+    realmLV = msgData["realmLV"] # 境界
+    fightPower = msgData["fightPower"] # 战斗力
+    buyOpenCountWeek = msgData["buyOpenCountWeek"] # 本周已购买召集场次
+    
+    openHour = msgData["openHour"]
+    openMinute = msgData["openMinute"]
+    faction = msgData["faction"]
+    
+    hmNum = GetHMNum(openHour, openMinute)
+    
+    if zoneID not in PyGameData.g_crossBattlefieldBuyInfo:
+        PyGameData.g_crossBattlefieldBuyInfo[zoneID] = {}
+    buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo[zoneID]
+    if hmNum not in buyHMInfo:
+        buyHMInfo[hmNum] = {}
+    buyPlayerInfo = buyHMInfo[hmNum]
+    
+    if playerID in buyPlayerInfo:
+        GameWorld.Log("玩家已经购买过该召集场次! zoneID=%s,openHour=%s,openMinute=%s" % (zoneID, openHour, openMinute), playerID)
+        return
+    
+    curFactionCount, othFactionCount = 0, 0
+    for callPlayerID, buyRec in buyPlayerInfo.items():
+        if buyRec.factionID == faction:
+            curFactionCount += 1
+        else:
+            othFactionCount += 1
+            
+        if playerID in buyRec.callPlayerIDList:
+            GameWorld.Log("玩家已经在该召集场次阵营里! zoneID=%s,openHour=%s,openMinute=%s,callPlayerID=%s,callPlayerIDList=%s" 
+                          % (zoneID, openHour, openMinute, callPlayerID, buyRec.callPlayerIDList), playerID)
+            return
+        
+    if curFactionCount > othFactionCount:
+        GameWorld.Log("阵营平衡限制,不可再购买该跨服战场阵营! zoneID=%s,openHour=%s,openMinute=%s,faction=%s,curFactionCount(%s) > othFactionCount(%s)" 
+                      % (zoneID, openHour, openMinute, faction, curFactionCount, othFactionCount), playerID)
+        return
+    
+    # ================ 可以购买,以下执行添加购买场次阵营逻辑  ================
+    
+    # 更新缓存
+    curCache = PlayerViewCache.FindViewCache(playerID, True)
+    if curCache:
+        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+        cacheDict["Name"] = playerName
+        cacheDict["Job"] = job
+        cacheDict["LV"] = playerLV
+        cacheDict["RealmLV"] = realmLV
+        cacheDict["FightPower"] = fightPower        
+    
+    # 新增场次购买记录
+    buyTime = int(time.time())
+    buyRec = CrossBattlefieldBuy()
+    buyRec.buyTime = buyTime
+    buyRec.zoneID = zoneID
+    buyRec.hmNum = hmNum
+    buyRec.playerID = playerID
+    buyRec.factionID = faction
+    buyRec.callPlayerIDList = [playerID]
+    buyPlayerInfo[playerID] = buyRec
+    
+    # 上榜
+    billboardCallCountLimit = IpyGameDataPY.GetFuncCfg("CrossBattlefieldBillboard", 2) # 周召集榜上榜至少次数
+    groupValue1, dataID, name1, name2 = zoneID, playerID, playerName, ""
+    type2, value1, value2 = job, realmLV, 0
+    cmpValue = buyOpenCountWeek + 1
+    if cmpValue >= billboardCallCountLimit:
+        CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_BattlefieldWCall, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue)
+        
+    SyncMapServerCrossBattlefieldBuyInfo()
+    
+    # 通知子服
+    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
+    msgData.update({"opType":"BuyOpen", "buyTime":buyTime})
+    Send_CrossServerMsg_BattlefieldBuy(zoneID, serverGroupIDList, msgData)
+    return
+
+def ClientServerMsg_BattlefieldCallJoin(serverGroupID, msgData):
+    # "openHour":openHour, "openMinute":openMinute, "buyPlayerID":buyPlayerID, "tagPlayerID":tagPlayerID, "playerID":playerID
+    
+    openHour = msgData["openHour"]
+    openMinute = msgData["openMinute"]
+    buyPlayerID = msgData["buyPlayerID"]
+    tagPlayerID = msgData["tagPlayerID"]
+    playerID = msgData["playerID"]
+    
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    
+    hmNum = GetHMNum(openHour, openMinute)
+    buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+    if buyPlayerID not in buyPlayerInfo:
+        GameWorld.ErrLog("跨服战场不存在该玩家的召集队伍! hmNum=%s,buyPlayerID=%s" % (hmNum, buyPlayerID), playerID)
+        return
+    buyRec = buyPlayerInfo[buyPlayerID]
+    
+    callTeamMemMax = IpyGameDataPY.GetFuncCfg("CrossBattlefieldCall", 1)
+    if len(buyRec.callPlayerIDList) >= callTeamMemMax:
+        GameWorld.ErrLog("跨服战场召集人数已满! hmNum=%s,buyPlayerID=%s,callPlayerIDList=%s" % (hmNum, buyPlayerID, buyRec.callPlayerIDList), playerID)
+        return
+    
+    if tagPlayerID not in buyRec.callPlayerIDList:
+        buyRec.callPlayerIDList.append(tagPlayerID)
+        
+    SyncMapServerCrossBattlefieldBuyInfo()
+    
+    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
+    msgData.update({"opType":"CallJoin"})
+    Send_CrossServerMsg_BattlefieldBuy(zoneID, serverGroupIDList, msgData)
+    return
+
+def ClientServerMsg_BattlefieldCallKick(serverGroupID, msgData):
+    # "openHour":openHour, "openMinute":openMinute, "buyPlayerID":buyPlayerID, "tagPlayerID":tagPlayerID, "playerID":playerID
+    
+    openHour = msgData["openHour"]
+    openMinute = msgData["openMinute"]
+    buyPlayerID = msgData["buyPlayerID"]
+    tagPlayerID = msgData["tagPlayerID"]
+    playerID = msgData["playerID"]
+    
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    
+    hmNum = GetHMNum(openHour, openMinute)
+    buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+    if buyPlayerID not in buyPlayerInfo:
+        GameWorld.ErrLog("跨服战场不存在该玩家的召集队伍! hmNum=%s,buyPlayerID=%s" % (hmNum, buyPlayerID), playerID)
+        return
+    buyRec = buyPlayerInfo[buyPlayerID]
+    
+    if tagPlayerID not in buyRec.callPlayerIDList:
+        GameWorld.ErrLog("跨服战场召集队伍没有该玩家! hmNum=%s,buyPlayerID=%s,tagPlayerID=%s not in callPlayerIDList=%s" 
+                           % (hmNum, buyPlayerID, tagPlayerID, buyRec.callPlayerIDList), playerID)
+        return
+    buyRec.callPlayerIDList.remove(tagPlayerID)
+    
+    SyncMapServerCrossBattlefieldBuyInfo()
+    
+    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
+    msgData.update({"opType":"CallKick"})
+    Send_CrossServerMsg_BattlefieldBuy(zoneID, serverGroupIDList, msgData)
+    return
+
+def MapServer_CrossBattlefieldOver(msgList):
+    ## 跨服战场地图结算
+    overTime = int(time.time())
+    hmNum = GetCrossBattlefieldState()
+    fbPropertyID, zoneID, funcLineID, winnerFaction, superItemInfo, superItemPlayerID, superItemPlayerName, scoreKingID, scoreKingName, battlePlayerList = msgList
+    GameWorld.Log("跨服战场地图同步结果: hmNum=%s,zoneID=%s,funcLineID=%s,winnerFaction=%s,superItemInfo=%s,superItemPlayerID=%s,scoreKingID=%s,battlePlayerCount=%s" 
+                  % (hmNum, zoneID, funcLineID, winnerFaction, superItemInfo, superItemPlayerID, scoreKingID, len(battlePlayerList)), fbPropertyID)
+    
+    winnerOrderAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAward", 2, {}) # 胜利方名次对应奖励物品列表 {"名次":[[物品ID,个数,是否拍品], ...], ...} , 名次配置支持段配置
+    loserOrderAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAward", 3, {}) # 失败方名次对应奖励物品列表 {"名次":[[物品ID,个数,是否拍品], ...], ...} , 名次配置支持段配置
+    winnerAwardList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAward", 4) # 胜利方固定结算奖励列表 [[物品ID,个数,是否拍品], ...]
+    loserAwardList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAward", 5) # 失败方固定结算奖励列表 [[物品ID,个数,是否拍品], ...]
+    
+    winnerOrderIntAwardDict = {int(k):v for k, v in winnerOrderAwardDict.items()}
+    loserOrderIntAwardDict = {int(k):v for k, v in loserOrderAwardDict.items()}
+    
+    billboardEnterCountLimit = IpyGameDataPY.GetFuncCfg("CrossBattlefieldBillboard", 1) # 周参与榜上榜至少次数
+    
+    syncPlayerDataInfo = {}
+    winnerPlayerIDList, loserPlayerIDList = [], []
+    for playerInfo in battlePlayerList:
+        faction, rank, playerID, job, realmLV, name, score, highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter = playerInfo
+        
+        isWinner = 0
+        paramList = [rank]
+        if faction == winnerFaction:
+            isWinner = 1
+            winnerPlayerIDList.append(playerID)
+            orderAwardMailKey = "CrossBattlefieldOrderWin"
+            orderAwardItemList = GameWorld.GetOrderValueByDict(winnerOrderIntAwardDict, rank)
+            GameWorld.Log("    获胜阵营玩家: faction=%s,rank=%s,playerID=%s" % (faction, rank, playerID), fbPropertyID)
+        else:
+            loserPlayerIDList.append(playerID)
+            orderAwardMailKey = "CrossBattlefieldOrderLose"
+            orderAwardItemList = GameWorld.GetOrderValueByDict(loserOrderIntAwardDict, rank)
+            GameWorld.Log("    失败阵营玩家: faction=%s,rank=%s,playerID=%s" % (faction, rank, playerID), fbPropertyID)
+            
+        # 排名奖励邮件
+        PlayerCompensation.SendMailByKey(orderAwardMailKey, [playerID], orderAwardItemList, paramList, crossMail=True)
+        
+        # 更新周参与榜单
+        groupValue1, dataID, name1, name2 = zoneID, playerID, name, ""
+        type2, value1, value2 = job, realmLV, 0
+        enterCountWeek += 1
+        cmpValue = enterCountWeek
+        if cmpValue >= billboardEnterCountLimit:
+            CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_BattlefieldWJoin, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue)
+            
+        # 更新周高分榜单
+        if score > highScoreToday:
+            highScoreWeekTotal += (score - highScoreToday)
+            highScoreToday = score
+            cmpValue = highScoreWeekTotal
+            CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_BattlefieldWScore, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue)
+            
+        GameWorld.Log("    战场阵营玩家: faction=%s,isWinner=%s,rank=%s,playerID=%s,score=%s,highScoreToday=%s,highScoreWeekTotal=%s,enterCountWeek=%s,isCallEnter=%s" 
+                      % (faction, isWinner, rank, playerID, score, highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter), fbPropertyID)
+        
+        syncPlayerDataInfo[playerID] = [highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter]
+        
+    # 参与奖励邮件
+    if winnerPlayerIDList:
+        PlayerCompensation.SendMailByKey("CrossBattlefieldJoinWin", winnerPlayerIDList, winnerAwardList, crossMail=True)
+    if loserPlayerIDList:
+        PlayerCompensation.SendMailByKey("CrossBattlefieldJoinLose", loserPlayerIDList, loserAwardList, crossMail=True)
+    
+    # 大奖获得者邮件
+    superItemID, superItemCount = 0, 0
+    if superItemPlayerID and superItemInfo and len(superItemInfo) == 3:
+        superItemID, superItemCount = superItemInfo[0], superItemInfo[1]
+        PlayerCompensation.SendMailByKey("CrossBattlefieldSuperAward", [superItemPlayerID], [superItemInfo], crossMail=True)
+        
+    crossZoneName = GameWorld.GetCrossZoneName()
+    zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossZonePK", crossZoneName, zoneID)
+    serverGroupIDList = zoneIpyData.GetServerGroupIDList() if zoneIpyData else []
+    
+    # 通知子服更新参与玩家数据
+    sendMsg = {"zoneID":zoneID, "overTime":overTime, "syncPlayerDataInfo":syncPlayerDataInfo}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_BattlefieldOver, sendMsg, serverGroupIDList)
+    
+    # 结算广播
+    nextBattleTimeStr = ""
+    openHour, openMinute = GetHMByNum(hmNum)
+    sysOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 1)
+    callOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 2)
+    allOpenHMList = sysOpenHMList + callOpenHMList
+    allOpenHMList.sort()
+    if [openHour, openMinute] in allOpenHMList:
+        nextOpenIndex = allOpenHMList.index([openHour, openMinute]) + 1
+        nextOpenHour, nextOpenMinute = allOpenHMList[nextOpenIndex] if len(allOpenHMList) > nextOpenIndex else allOpenHMList[0]
+        nextBattleTimeStr = "%02d:%02d" % (nextOpenHour, nextOpenMinute)
+        
+    # 本分区全服:XX阵营胜利,xxx为本场积分王,xxx获得了古神大奖XXX,下个场次预计将在XX点开放。
+    if battlePlayerList:
+        msgParamList = [winnerFaction, scoreKingName, superItemPlayerName, superItemID, superItemCount, nextBattleTimeStr]
+        PlayerControl.WorldNotifyCross(serverGroupIDList, 0, "CrossBattlefieldOver", msgParamList)
+    return
+
+####################################################################################################
+
+def CrossServerMsg_BattlefieldState(msgData):
+    battlefieldState = msgData["battlefieldState"]
+    
+    gameWorld = GameWorld.GetGameWorld()
+    
+    seasonState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState)
+    beforeState = GetCrossBattlefieldState()
+    beforeState = beforeState if (beforeState and seasonState == 1) else 0
+    
+    realBattlefieldState = battlefieldState if (battlefieldState and seasonState == 1) else 0
+    
+    GameWorld.DebugLog("收到跨服服务器同步的战场状态: battlefieldState=%s,seasonState=%s,beforeState=%s,realBattlefieldState=%s" 
+                       % (battlefieldState, seasonState, beforeState, realBattlefieldState))
+    
+    key = ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield
+    gameWorld.SetDict(key, realBattlefieldState)
+    GameWorld.SendMapServerMsgEx(key, realBattlefieldState)
+    return
+
+def CrossServerMsg_BattlefieldOver(msgData):
+    GameWorld.DebugLog("收到跨服服务器同步的战场结算信息: %s" % msgData)
+    
+    zoneID = msgData["zoneID"]
+    overTime = msgData["overTime"]
+    syncPlayerDataInfo = msgData["syncPlayerDataInfo"]
+    
+    gameWorld = GameWorld.GetGameWorld()
+    pkZoneID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
+    if zoneID != pkZoneID:
+        GameWorld.ErrLog("非本服所属分区的跨服战场购买信息! pkZoneID(%s) != zoneID(%s) %s" % (pkZoneID, zoneID, str(msgData)))
+        return
+    
+    for playerID, playerData in syncPlayerDataInfo.items():
+        highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter = playerData
+        if PlayerControl.GetDBPlayerAccIDByID(playerID):
+            msgInfo = ["BattlefieldOver", [overTime, highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter]]
+            CrossRealmPlayer.MapServer_QueryCrossPlayerResult(playerID, "CrossBattlefield", msgInfo)
+            
+    return
+
+def CrossServerMsg_BattlefieldBuy(msgData):
+    GameWorld.DebugLog("收到跨服服务器同步的战场购买信息: %s" % msgData)
+    
+    zoneID = msgData["zoneID"]
+    syncBuyHMInfo = msgData["syncBuyHMInfo"]
+    opData = msgData.get("opData", {})
+    
+    gameWorld = GameWorld.GetGameWorld()
+    pkZoneID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
+    if zoneID != pkZoneID:
+        GameWorld.ErrLog("非本服所属分区的跨服战场购买信息! pkZoneID(%s) != zoneID(%s) %s" % (pkZoneID, zoneID, str(msgData)))
+        return
+    
+    if not syncBuyHMInfo:
+        PyGameData.g_crossBattlefieldBuyInfo.pop(zoneID, None)
+        
+    # 更新数据
+    for hmNum, syncBuyPlayerInfo in syncBuyHMInfo.items():
+        buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+        for buyPlayerID, attrDict in syncBuyPlayerInfo.items():
+            buyRec = CrossBattlefieldBuy()
+            buyRec.SetAttr(attrDict)
+            buyPlayerInfo[buyPlayerID] = buyRec
+            
+    SyncMapServerCrossBattlefieldBuyInfo()
+    
+    if not opData or "opType" not in opData:
+        SyncCrossBattlefieldBuyInfo(None, zoneID)
+        return
+    opType = opData["opType"]
+    openHour = opData["openHour"]
+    openMinute = opData["openMinute"]
+    hmNum = GetHMNum(openHour, openMinute)
+    SyncCrossBattlefieldBuyInfo(None, zoneID, hmNum)
+    
+    if opType == "BuyOpen":
+        playerID = opData["playerID"]
+        playerName = opData["playerName"]
+        PlayerControl.WorldNotify(0, "CrossBattlefieldBuyOpen", [playerName, "%d:%02d" % (openHour, openMinute)])
+        
+        if PlayerControl.GetDBPlayerAccIDByID(playerID):
+            faction = opData["faction"]
+            buyTime = opData["buyTime"]
+            todayBuyOpenCount = opData["todayBuyOpenCount"]
+            msgInfo = ["BattlefieldBuy", [openHour, openMinute, faction, todayBuyOpenCount, buyTime]]
+            CrossRealmPlayer.MapServer_QueryCrossPlayerResult(playerID, "CrossBattlefield", msgInfo)
+            
+    elif opType == "CallJoin":
+        pass
+    
+    elif opType == "CallKick":
+        pass
+    
+    return
+
+def SyncCrossBattlefieldBuyInfo(curPlayer, zoneID, hmNum=None):
+    ## 通知战场召集场次购买信息
+    
+    buyHMInfo = PyGameData.g_crossBattlefieldBuyInfo.get(zoneID, {})
+    hmNumList = [hmNum] if hmNum != None else buyHMInfo.keys()
+    
+    clientPack = ChPyNetSendPack.tagGCCrossBattlefieldBuyInfo()
+    clientPack.HMBuyList = []
+    for hmNum in hmNumList:
+        h, m = GetHMByNum(hmNum)
+        hmPack = ChPyNetSendPack.tagGCCrossBattlefieldBuyHM()
+        hmPack.Hour = h
+        hmPack.Minute = m
+        hmPack.BuyPlayerList = []
+        
+        buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+        for buyPlayerID, buyRec in buyPlayerInfo.items():
+            buyPlayerPack = ChPyNetSendPack.tagGCCrossBattlefieldBuyPlayer()
+            buyPlayerPack.BuyPlayerID = buyPlayerID
+            buyPlayerPack.Faction = buyRec.factionID
+            buyPlayerPack.FactionPlayerList = []
+            
+            for callPlayerID in buyRec.callPlayerIDList:
+                playerPack = ChPyNetSendPack.tagGCCrossBattlefieldPlayer()
+                playerPack.PlayerID = callPlayerID
+                if callPlayerID in buyRec.callPlayerDict:
+                    factionPlayerInfo = buyRec.callPlayerDict[callPlayerID]
+                    fightPower = factionPlayerInfo["FightPower"]
+                    playerPack.PlayerName = factionPlayerInfo["Name"]
+                    playerPack.Job = factionPlayerInfo["Job"]
+                    playerPack.LV = factionPlayerInfo["LV"]
+                    playerPack.RealmLV = factionPlayerInfo["RealmLV"]
+                    playerPack.FightPower = fightPower % ShareDefine.Def_PerPointValue
+                    playerPack.FightPowerEx = fightPower / ShareDefine.Def_PerPointValue
+                buyPlayerPack.FactionPlayerList.append(playerPack)
+            buyPlayerPack.FactionPlayerCount = len(buyPlayerPack.FactionPlayerList)
+            
+            hmPack.BuyPlayerList.append(buyPlayerPack)
+        hmPack.BuyPlayerCount = len(hmPack.BuyPlayerList)
+        
+        clientPack.HMBuyList.append(hmPack)
+    clientPack.HMCount = len(clientPack.HMBuyList)
+    
+    if curPlayer:
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+    else:
+        # 广播全服玩家
+        playerManager = GameWorld.GetPlayerManager()
+        for i in xrange(playerManager.GetPlayerCount()):
+            curPlayer = playerManager.GetPlayerByIndex(i)
+            if curPlayer == None or not curPlayer.GetInitOK() or PlayerControl.GetIsTJG(curPlayer):
+                continue
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+#// C0 07 跨服战场加入召集场次 #tagCGCrossBattlefieldJoinByCall
+#
+#struct    tagCGCrossBattlefieldJoinByCall
+#{
+#    tagHead        Head;
+#    BYTE    Hour;        //战场开启时
+#    BYTE    Minute;        //战场开启分
+#    DWORD    BuyPlayerID;    //加入目标玩家的召集队伍,即购买召集场的玩家ID
+#};
+def OnCrossBattlefieldJoinByCall(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    openHour = clientData.Hour
+    openMinute = clientData.Minute
+    buyPlayerID = clientData.BuyPlayerID
+    tagPlayerID = playerID
+    
+    closeBuyMinute = IpyGameDataPY.GetFuncCfg("CrossBattlefieldOpen", 4) # 开启前X分钟后关闭购买
+    crossServerTimeStr = GameWorld.GetCrossServerTimeStr()
+    crossServerDateTime = GameWorld.ChangeStrToDatetime(crossServerTimeStr)
+    
+    startTimeStr = "%s-%s-%s %s:%s:00" % (crossServerDateTime.year, crossServerDateTime.month, crossServerDateTime.day, openHour, openMinute)
+    startDateTime = GameWorld.ChangeStrToDatetime(startTimeStr)
+    endBuyDateTime = startDateTime + datetime.timedelta(minutes=-closeBuyMinute)
+    if crossServerDateTime >= endBuyDateTime:
+        GameWorld.Log("该时间点战场已关闭召集,不能再召集加入! openHour=%s,openMinute=%s,crossServerDateTime(%s) >= endBuyDateTime(%s)" 
+                      % (openHour, openMinute, crossServerDateTime, endBuyDateTime), playerID)
+        return
+    
+    serverGroupID = GameWorld.GetServerGroupID()
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    
+    hmNum = GetHMNum(openHour, openMinute)
+    buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+    if buyPlayerID not in buyPlayerInfo:
+        GameWorld.ErrLog("不存在该玩家的跨服战场召集队伍! hmNum=%s,buyPlayerID=%s" % (hmNum, buyPlayerID), playerID)
+        return
+    buyRec = buyPlayerInfo[buyPlayerID]
+    
+    callTeamMemMax = IpyGameDataPY.GetFuncCfg("CrossBattlefieldCall", 1)
+    if len(buyRec.callPlayerIDList) >= callTeamMemMax:
+        GameWorld.DebugLog("召集人数已满! hmNum=%s,buyPlayerID=%s,callPlayerIDList=%s" % (hmNum, buyPlayerID, buyRec.callPlayerIDList), playerID)
+        return
+    
+    # 请求查询跨服服务器
+    dataMsg = {"openHour":openHour, "openMinute":openMinute, "buyPlayerID":buyPlayerID, "tagPlayerID":tagPlayerID, "playerID":playerID}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_BattlefieldCallJoin, dataMsg)
+    return
+
+
+#// C0 08 跨服战场召集场次踢人 #tagCGCrossBattlefieldCallKick
+#
+#struct    tagCGCrossBattlefieldCallKick
+#{
+#    tagHead        Head;
+#    BYTE    Hour;        //战场开启时
+#    BYTE    Minute;        //战场开启分
+#    DWORD    TagPlayerID;    //目标玩家ID,即要被踢出去的玩家ID
+#};
+def OnCrossBattlefieldCallKick(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    openHour = clientData.Hour
+    openMinute = clientData.Minute
+    tagPlayerID = clientData.TagPlayerID
+    buyPlayerID = playerID
+    
+    if buyPlayerID == tagPlayerID:
+        return
+    
+    closeBuyMinute = IpyGameDataPY.GetFuncCfg("CrossBattlefieldOpen", 4) # 开启前X分钟后关闭购买
+    crossServerTimeStr = GameWorld.GetCrossServerTimeStr()
+    crossServerDateTime = GameWorld.ChangeStrToDatetime(crossServerTimeStr)
+    
+    startTimeStr = "%s-%s-%s %s:%s:00" % (crossServerDateTime.year, crossServerDateTime.month, crossServerDateTime.day, openHour, openMinute)
+    startDateTime = GameWorld.ChangeStrToDatetime(startTimeStr)
+    endBuyDateTime = startDateTime + datetime.timedelta(minutes= -closeBuyMinute)
+    if crossServerDateTime >= endBuyDateTime:
+        GameWorld.Log("该时间点战场已关闭召集,不能再召集踢人! openHour=%s,openMinute=%s,crossServerDateTime(%s) >= endBuyDateTime(%s)" 
+                      % (openHour, openMinute, crossServerDateTime, endBuyDateTime), playerID)
+        return
+    
+    serverGroupID = GameWorld.GetServerGroupID()
+    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
+    if not zoneIpyData:
+        return
+    zoneID = zoneIpyData.GetZoneID()
+    
+    hmNum = GetHMNum(openHour, openMinute)
+    buyPlayerInfo = GetBuyPlayerInfo(zoneID, hmNum)
+    if buyPlayerID not in buyPlayerInfo:
+        GameWorld.ErrLog("不存在该玩家的跨服战场召集队伍! hmNum=%s,buyPlayerID=%s" % (hmNum, buyPlayerID), playerID)
+        return
+    buyRec = buyPlayerInfo[buyPlayerID]
+    
+    if tagPlayerID not in buyRec.callPlayerIDList:
+        GameWorld.DebugLog("该召集队伍没有该玩家! hmNum=%s,buyPlayerID=%s,tagPlayerID=%s not in callPlayerIDList=%s" 
+                           % (hmNum, buyPlayerID, tagPlayerID, buyRec.callPlayerIDList), playerID)
+        return
+    
+    # 请求查询跨服服务器
+    dataMsg = {"openHour":openHour, "openMinute":openMinute, "buyPlayerID":buyPlayerID, "tagPlayerID":tagPlayerID, "playerID":playerID}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_BattlefieldCallKick, dataMsg)
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
index e76c9ef..9d1c297 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
@@ -282,10 +282,14 @@
     SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, [serverGroupID], queryData)
     return
 
-def SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, serverGroupIDList=[], queryData={}):
+def SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, serverGroupIDList=None, queryData=None):
     ## 同步跨服榜单到子服
     if not GameWorld.IsCrossServer():
         return
+    if serverGroupIDList == None:
+        serverGroupIDList = []
+    if queryData == None:
+        queryData = {}
     billboardMgr = PyDataManager.GetCrossBillboardManager()
     billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
     crossServerDataVer = billboardObj.GetCrossServerDataVer()
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
index ae35d95..dd90ae3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -23,6 +23,7 @@
 import CrossRealmPlayer
 import PlayerCompensation
 import CrossActionControl
+import CrossBattlefield
 import CrossBillboard
 import GameWorldBoss
 import CrossRealmPK
@@ -120,6 +121,15 @@
         elif msgType == ShareDefine.ClientServerMsg_AddBuff:
             MapServer_CrossAddBuff(msgData)
             
+        elif msgType == ShareDefine.ClientServerMsg_BattlefieldBuyOpen:
+            CrossBattlefield.ClientServerMsg_BattlefieldBuyOpen(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_BattlefieldCallJoin:
+            CrossBattlefield.ClientServerMsg_BattlefieldCallJoin(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_BattlefieldCallKick:
+            CrossBattlefield.ClientServerMsg_BattlefieldCallKick(serverGroupID, msgData)
+            
         # 需要发送到地图服务器处理的
         elif msgType in [ShareDefine.ClientServerMsg_Reborn, ShareDefine.ClientServerMsg_CollectNPC]:
             MapServer_CrossServerReceiveMsg(msgType, msgData, serverGroupID)
@@ -149,6 +159,7 @@
     '''
     CrossRealmPlayer.Sync_CrossCommInitDataToClientServer(serverGroupID)
     CrossRealmPK.Sync_CrossPKInitDataToClientServer(tick, serverGroupID)
+    CrossBattlefield.Sync_CrossBattlefieldDataToClientServer(serverGroupID)
     CrossBoss.Sync_CrossBossInitDataToClientServer(serverGroupID)
     CrossActionControl.Sync_CrossActInfoToClientServer(serverGroupID)
     CrossLuckyCloudBuy.Sync_LuckyCloudBuyDataToClientServer(tick, serverGroupID)
@@ -195,7 +206,7 @@
     return
 ## ================================================================================================
 
-def SendMsgToClientServer(msgType, dataMsg, serverGroupIDList=[]):
+def SendMsgToClientServer(msgType, dataMsg, serverGroupIDList=None):
     ''' 广播信息到子服务器上
         @param serverGroupIDList: 发送指定的服务器组ID列表,内部已经针对列表中组ID去重,
         所以外部逻辑可直接添加,不用考虑组ID重复问题,没有指定服务器组ID时,默认广播所有子服
@@ -204,7 +215,9 @@
         return
     if not dataMsg:
         return
-    
+    if serverGroupIDList == None:
+        serverGroupIDList = []
+        
     srcMsg = {"MsgType":msgType, "Data":dataMsg, "CrossServerTime":GameWorld.GetCurrentDataTimeStr()}
     sendMsg = cPickle.dumps(srcMsg, 2)
     if not GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_GameWorldInitOK):
@@ -289,6 +302,15 @@
         elif msgType == ShareDefine.CrossServerMsg_LuckyCloudBuyNum:
             CrossLuckyCloudBuy.CrossServerMsg_LuckyCloudBuyNum(msgData)
             
+        elif msgType == ShareDefine.CrossServerMsg_BattlefieldState:
+            CrossBattlefield.CrossServerMsg_BattlefieldState(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_BattlefieldBuy:
+            CrossBattlefield.CrossServerMsg_BattlefieldBuy(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_BattlefieldOver:
+            CrossBattlefield.CrossServerMsg_BattlefieldOver(msgData)
+            
         elif msgType == ShareDefine.CrossServerMsg_SyncBillboard:
             CrossBillboard.CrossServerMsg_SyncBillboard(msgData, tick)
             
@@ -342,7 +364,10 @@
                 tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
                 if tagPlayer:
                     GameWorld.DebugAnswer(tagPlayer, "跨服服务器时间: %s" % GameWorld.GetCrossServerTimeStr())
-                    
+            
+        elif msgType == ShareDefine.CrossServerMsg_DebugAnswer:
+            GameWorld.CrossServerMsg_DebugAnswer(msgData)
+            
         else:
             GameWorld.ErrLog("没有该信息类型逻辑处理!")
             
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
index 7ed6e28..bc415ec 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
@@ -975,6 +975,10 @@
         dailyIpyData = ipyDataMgr.GetDailyActionByIndex(i)
         dailyID = dailyIpyData.GetDailyID()
         
+        if dailyID in [ShareDefine.DailyActionID_CrossBattlefield]:
+            GameWorld.Log("    不需要处理的日常活动! dailyID=%s" % dailyID)
+            continue
+        
         # 是当天开服天定制活动的不处理常规活动
         if dailyID in customDailyIDList:
             GameWorld.Log("    常规活动ID配置是今天的定制活动ID,不处理!: dailyID=%s" % dailyID)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
index f700782..76ded9f 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
@@ -428,6 +428,40 @@
     PyGameData.g_crossSetPlayerAttr = {}
     return
 
+def OnPlayerLogin(curPlayer):
+    if not IsCrossServerOpen():
+        return
+    
+    LoginDoUnNotifyCrossMsg(curPlayer)
+    return
+    
+def MapServer_QueryCrossPlayerResult(playerID, callName, msgInfo):
+    ## 同步地图跨服玩家处理信息,玩家可能不在线,缓存后等玩家上线处理,暂不考虑存档问题,服务器维护后未处理的命令将失效
+    
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if curPlayer:
+        msgInfo = str(msgInfo)
+        curPlayer.MapServer_QueryPlayerResult(0, 0, callName, msgInfo, len(msgInfo))
+    else:
+        # 缓存起来,等上线后处理
+        if playerID not in PyGameData.g_unNotifyPlayerCrossMsgDict:
+            PyGameData.g_unNotifyPlayerCrossMsgDict[playerID] = []
+        msgList = PyGameData.g_unNotifyPlayerCrossMsgDict[playerID]
+        msgList.append([callName, msgInfo])
+        GameWorld.Log("玩家不在线,添加未通知的跨服命令: %s, msgInfo=%s" % (callName, msgInfo), playerID)
+        
+    return
+
+def LoginDoUnNotifyCrossMsg(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    msgList = PyGameData.g_unNotifyPlayerCrossMsgDict.pop(playerID, [])
+    if not msgList:
+        return
+    for callName, msgInfo in msgList:
+        GameWorld.Log("上线处理未通知的跨服命令: %s, msgInfo=%s" % (callName, msgInfo), playerID)
+        msgInfo = str(msgInfo)
+        curPlayer.MapServer_QueryPlayerResult(0, 0, callName, msgInfo, len(msgInfo))
+    return
 
 
     
\ No newline at end of file
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
index 0d7d64e..ae36d67 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
@@ -309,7 +309,7 @@
     
 def SendPersonalItemMailBatch(batchMailInfoList):
     ## 批量发送邮件
-    mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource = batchMailInfoList
+    mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource, crossMail = batchMailInfoList
     
     lenPlayerID = len(batchPlayerIDList)
     lenItem = len(batchAddItemList)
@@ -334,7 +334,7 @@
         silver = batchSilver[i] if lenSilver == lenPlayerID else 0
         detail = batchDetail[i] if lenDetail == lenPlayerID else ""
         content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, str(paramList))
-        SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail, moneySource=moneySource)
+        SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail, moneySource=moneySource, crossMail=crossMail)
         
     return
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
index 24c18df..c03779b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -32,6 +32,7 @@
 import NetPackCommon
 import PlayerDuJie
 import PlayerCharm
+import CrossBattlefield
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -87,6 +88,8 @@
     PlayerFairyDomain.OnDayEx()
     #竞技场
     GameWorldArena.OnDayEx()
+    #跨服战场
+    CrossBattlefield.DoOnDayEx()
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
         curPlayer = playerManager.GetPlayerByIndex(i)
@@ -126,6 +129,8 @@
     
     # 竞技场
     GameWorldArena.OnWeekEx()
+    # 跨服战场
+    CrossBattlefield.DoOnWeekEx()
     
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
index a8d5e9e..48853d9 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
@@ -31,19 +31,26 @@
 import GameWorld
 import ChConfig
 import IPY_PlayerDefine
+import CrossBattlefield
 import CrossRealmPlayer
 import CrossRealmMsg
 import ShareDefine
 import CrossBoss
+import time
 
+DynamicShuntType_No = 0 # 不分流
+DynamicShuntType_Fill = 1    # 填满式分流,按存在的线路人数多的优先填充,都满后开启新线路
+DynamicShuntType_Equally = 2 # 均摊式分流,按存在的线路人数少的优先填充,都满后开启新线路
 #---------------------------------------------------------------------
 
 ## 跨服地图动态分配的功能线路,如果有人数上限的,则同分区同地图玩法的可能同时存在多个相同功能线路的数据
+##  {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
 class CrossFuncLineInfo():
     
     def __init__(self):
         self.realMapID = 0
         self.copyMapID = 0
+        self.newFuncLineNum = 0
         self.funcLineDataCache = None # 功能线路自定义缓存数据
         return
     
@@ -52,37 +59,48 @@
         self.copyMapID = 0
         return
 
-## 跨服地图动态分配的虚拟线路信息
+## 跨服地图动态分配的虚拟线路信息 {(mapID, copyMapID):CrossCopyMapInfo, ...}
 class CrossCopyMapInfo():
     
     def __init__(self, zoneID, funcLineID):
         self.zoneID = zoneID
         self.funcLineID = funcLineID
+        self.newFuncLineNum = 0
+        self.realMapID = 0
+        self.copyMapID = 0
         self.openState = IPY_PlayerDefine.fbosClosed
         self.fbPlayerDict = {} # 副本中的玩家信息 {playerID:serverGroupID, ...}
         self.waitPlayerDict = {} # 等待进入的玩家信息 {playerID:[serverGroupID, tick], ...}
         self.offlinePlayerDict = {} # 掉线的玩家信息,非主动退出的 {playerID:serverGroupID, ...}
+        self.enterPlayerIDList = [] # 有进入过此分线的玩家ID列表,不会清除 [playerID, ...]
         return
     
-    def OnRequestEnterCrossCopyMap(self, playerID, serverGroupID, tick, copyMapPlayerMax):
-        # 已经在请求队列里,可进入
-        if playerID in self.waitPlayerDict or not copyMapPlayerMax:
-            self.waitPlayerDict[playerID] = [serverGroupID, tick]
-            return True
+    def GetCopyMapPlayerCount(self, includeOffline, tick):
+        ## 获取该分线玩家数
+        # @param includeOffline: 是否包含离线玩家
         
         # 移除请求进入超时的玩家
         for waitPlayerID, playerInfo in self.waitPlayerDict.items():
-            serverGroupID, requestTick = playerInfo
+            _, requestTick = playerInfo
             if tick - requestTick > 60000: # 请求进入时间保留1分钟
                 self.waitPlayerDict.pop(waitPlayerID)
                 
         # 判断是否超过人数上限
         fbPlayerCount, waitPlayerCount = len(self.fbPlayerDict), len(self.waitPlayerDict)
-        if fbPlayerCount + waitPlayerCount >= copyMapPlayerMax:
-            return False
+        totalPlayerCount = fbPlayerCount + waitPlayerCount
+        if includeOffline:
+            totalPlayerCount += len(self.offlinePlayerDict)
+            
+        return totalPlayerCount
+    
+    def IsMustCopyMapPlayer(self, playerID):
+        ## 是否必定在此分线的玩家, 在请求队列里 或 曾经进入到该分线的,都强制认为属于该分线的玩家
+        return playerID in self.waitPlayerDict or playerID in self.enterPlayerIDList
         
-        self.waitPlayerDict[playerID] = [serverGroupID, tick]
-        return True
+    def OnRequestEnterCrossCopyMap(self, playerID, tick, copyMapPlayerMax, includeOffline):
+        if not copyMapPlayerMax or self.IsMustCopyMapPlayer(playerID):
+            return True
+        return self.GetCopyMapPlayerCount(includeOffline, tick) < copyMapPlayerMax
     
 #---------------------------------------------------------------------
 def GetFBLineIpyData(mapID, lineID, isDefaultLine=True):
@@ -127,37 +145,127 @@
     playerID = msgData["PlayerID"]
     mapID = msgData["MapID"]
     funcLineID = msgData["FuncLineID"]
+    playerLV = msgData["LV"]
     
     zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(mapID, serverGroupID)
     if not zoneIpyData:
         return
     zoneID = zoneIpyData.GetZoneID()
     
-    dynamicLineMaxPlayerCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 2)
-    copyMapPlayerMax = dynamicLineMaxPlayerCountDict.get(mapID, 0) # 0为不限制人数,默认不限制
+    openHour, openMinute = None, None
+    dynamicShuntType = DynamicShuntType_Fill
+    includeOffline = False
+    tagCopyMapObj = None
+    
+    # 基础验证是否可进入等 及 数据准备
     if mapID == ChConfig.Def_FBMapID_CrossDemonKing:
         bossID = msgData["BossID"]
         if not CrossBoss.GetCrossBossIsAliveOrCanReborn(zoneID, bossID):
-            GameWorld.DebugLog("当前跨服妖王死亡状态,不可进入! serverGroupID=%s,funcLineID=%s,zoneID=%s,bossID=%s" % (serverGroupID, funcLineID, zoneID, bossID))
+            GameWorld.ErrLog("当前跨服妖王死亡状态,不可进入! funcLineID=%s,zoneID=%s,bossID=%s" % (funcLineID, zoneID, bossID), playerID)
             return
         
     elif mapID in [ChConfig.Def_FBMapID_CrossGrasslandLing, ChConfig.Def_FBMapID_CrossGrasslandXian]:
         pass
-        
+    
+    elif mapID == ChConfig.Def_FBMapID_CrossBattlefield:
+        openTimeInfo = CrossBattlefield.GetCrossBattlefieldOpenTime(zoneID)
+        if not openTimeInfo:
+            PlayerControl.NotifyCodeCross(serverGroupID, playerID, "FBIsNotOpen")
+            GameWorld.ErrLog("非活动时间或未开启! funcLineID=%s,zoneID=%s" % (funcLineID, zoneID), playerID)
+            return
+        dynamicShuntType = DynamicShuntType_Equally
+        isCallBattle, openHour, openMinute = openTimeInfo
+        if isCallBattle:
+            # 召集场次默认 funcLineID 为0,不分等级,不分流
+            funcLineID = 0
+            dynamicShuntType = DynamicShuntType_No
+            includeOffline = True
     else:
         return
     
-    mapCopyLineInfo = __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick)
-    if not mapCopyLineInfo:
+    dynamicLineMaxPlayerCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 2)
+    copyMapPlayerMin, copyMapPlayerMax = dynamicLineMaxPlayerCountDict.get(mapID, [0, 0]) # 0为不限制人数,默认不限制
+    
+    # 除个别地图外,最优先进入上次进入的未关闭分线
+    if mapID not in []:
+        for _, copyMapObj in PyGameData.g_crossDynamicLineCopyMapInfo.items():
+            if copyMapObj.IsMustCopyMapPlayer(playerID):
+                tagCopyMapObj = copyMapObj
+                break
+            
+    # 如果没有进入过,则按功能看是否有特殊指定规则
+    if tagCopyMapObj == None:
+        if mapID == ChConfig.Def_FBMapID_CrossBattlefield:
+            if isCallBattle:
+                copyMapPlayerMax = IpyGameDataPY.GetFuncCfg("CrossBattlefieldCall", 2)
+                tagCopyMapObj = CrossBattlefield.GetCallPlayerCopymapObj(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, includeOffline, tick)
+            
+    # 如果还没有取到对应的分流线,则按默认规则处理
+    if tagCopyMapObj == None and dynamicShuntType:
+        # 非特殊动态规则,走常规逻辑
+        dynamicLineLVRangeDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 4)
+        if mapID in dynamicLineLVRangeDict:
+            lvRangeList = dynamicLineLVRangeDict[mapID]
+            for lvFuncLineID, lvRange in enumerate(lvRangeList):
+                if lvRange[0] <= playerLV <= lvRange[1]:
+                    funcLineID = lvFuncLineID
+                    copyMapPlayerMin, copyMapPlayerMax = lvRange[2], lvRange[3]
+                    GameWorld.DebugLog("进入跨服地图等级自动适配功能线路ID: mapID=%s,playerLV=%s,funcLineID=%s,copyMapPlayerMin=%s,copyMapPlayerMax=%s" 
+                                       % (mapID, playerLV, funcLineID, copyMapPlayerMin, copyMapPlayerMax))
+                    break
+                
+        shuntPlayerMax = copyMapPlayerMax
+        
+        minCountTimeDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 3) # 分流下限人数有效时间配置,单位秒,{dataMapID:秒, ...}
+        if mapID in minCountTimeDict:
+            playerMinTimeSet = minCountTimeDict[mapID]
+            curTime = GameWorld.GetServerTime()
+            if openHour == None or openMinute == None:
+                GameWorld.ErrLog("副本开启时间未知! mapID=%s,funcLineID=%s,zoneID=%s" % (mapID, funcLineID, zoneID), playerID)
+                return
+            
+            openDateTimeStr = "%d-%02d-%02d %02d:%02d:00" % (curTime.year, curTime.month, curTime.day, openHour, openMinute)
+            openDateTime = GameWorld.ChangeStrToDatetime(openDateTimeStr)
+            passTime = curTime - openDateTime
+            '''
+                                                在线(包含请求中)          <= 单场下限值
+                                                在线(包含请求中)+ 离线 <= 单场上限值
+                                                
+                                                前X秒大于 单场下限值 开新一场
+                                                任意时刻大于 单场上限值 必开新一场
+            '''
+            if passTime.seconds <= playerMinTimeSet:
+                shuntPlayerMax = copyMapPlayerMin
+                includeOffline = False
+            else:
+                shuntPlayerMax = copyMapPlayerMax
+                includeOffline = True
+                
+        tagCopyMapObj = __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, 
+                                                  shuntPlayerMax, copyMapPlayerMax, includeOffline, tick, dynamicShuntType)
+        
+    if not tagCopyMapObj:
+        PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBFull")
+        GameWorld.ErrLog("找不到可分流的副本线路! mapID=%s,funcLineID=%s,zoneID=%s" % (mapID, funcLineID, zoneID), playerID)
         return
-    realMapID, copyMapID, openState = mapCopyLineInfo
-    if openState != IPY_PlayerDefine.fbosOpen:
+        
+    realMapID, copyMapID, openState = tagCopyMapObj.realMapID, tagCopyMapObj.copyMapID, tagCopyMapObj.openState
+    
+    if openState == IPY_PlayerDefine.fbosWaitForClose:
+        PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBClose")
+        GameWorld.ErrLog("分流的副本线路关闭中! mapID=%s,funcLineID=%s,zoneID=%s,realMapID=%s,copyMapID=%s,openState=%s" 
+                         % (mapID, funcLineID, zoneID, realMapID, copyMapID, openState), playerID)
         return
     
-    playerIDList = [playerID]
-    retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID]
-    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID])
-    return
+    tagCopyMapObj.waitPlayerDict[playerID] = [serverGroupID, tick]
+    GameWorld.DebugLog("    分配进入跨服场景: realMapID=%s, copyMapID=%s, openState=%s" % (realMapID, copyMapID, openState), playerID)
+    if openState == IPY_PlayerDefine.fbosOpen:
+        funcLineID = tagCopyMapObj.funcLineID
+        playerIDList = [playerID]
+        retInfo = [playerIDList, mapID, realMapID, copyMapID, funcLineID]
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterFBRet, retInfo, [serverGroupID])
+        
+    return tagCopyMapObj
 
 def CrossServerMsg_EnterFBRet(msgData, tick):
     ## 收到跨服服务器动态分配的跨服副本进入信息
@@ -172,26 +280,50 @@
         
     return
 
-def __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, copyMapPlayerMax, tick):
+def __GetCrossDynamicLineInfo(playerID, serverGroupID, mapID, funcLineID, zoneID, shuntPlayerMax, copyMapPlayerMax, includeOffline, tick, dynamicShuntType):
     '''获取跨服分区对应动态分配的副本地图虚拟线路信息, 由于需要支持多地图分流,所以直接由GameServer管理分配
             每个功能线路支持按人数分流,超过最大人数后可开启一条相同功能线路的虚拟线路进行分流,所以同一分区同一地图的功能线路ID可能对应多条虚拟线路
+        分流方式:
+            DynamicShuntType_Fill = 1    # 填满式分流,按存在的线路人数多的优先填充,都满后开启新线路
+            DynamicShuntType_Equally = 2 # 均摊式分流,按存在的线路人数少的优先填充,都满后开启新线路
+        分流规则:
+                    时间仅决定分流人数,不影响常规分配逻辑
+        1. 优先分配到人数小于分流人数的场次
+        2. 超过分流人数的场次依次往人数少的场次分配
+        3. 当当前已开放的场次都达到人数分流人数,则开启新场次,没有空闲的场,则往未达到人数上限的场次依次分配,直到达到所有场次上限
+    
+            关于 shuntPlayerMax 的选择: 可根据副本规则制定
+            如前X分钟内可设定一个小于  copyMapPlayerMax 的分流人数值快速铺满各分流场次
+            当大于X分钟后则可设置 shuntPlayerMax = copyMapPlayerMax 进行饱和分流
+            
+            当所有分流场次达到  shuntPlayerMax 后,可尝试开启新分流线路,进行分流
+         shuntPlayerMax < copyMapPlayerMax 的情况,如果没有办法开启新分流线路,则可继续强制根据分流类型分配线路,只要未达到 copyMapPlayerMax 人数,还是可以进入副本的
+        shuntPlayerMax >= copyMapPlayerMax 的情况,如果没有办法开启新分流线路,则标识副本所有线路已达到饱和状态,不能再进入副本了
+            
+            当  shuntPlayerMax 为 0 时,达标不限制人数上限,及不分流,都在同一条线路,一般跨服副本不建议设置为0,人数太多,不合理
+            
+    @param shuntPlayerMax: 分流最大人数限制
+    @param copyMapPlayerMax: 实际最大可容纳的人数限制,一般大于等于分流人数限制
+    @param includeOffline: 是否包含本线路离线玩家
+    @param dynamicShuntType: 分流类型,可选择  填满式分流  或 均摊式分流
     '''
     
     zoneLineKey = (zoneID, funcLineID)
-    if mapID not in PyGameData.g_crossDynamicLineInfo:
-        PyGameData.g_crossDynamicLineInfo[mapID] = {}
-    zoneLineDict = PyGameData.g_crossDynamicLineInfo[mapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
-    if zoneLineKey not in zoneLineDict:
-        zoneLineDict[zoneLineKey] = []
-    funcLineObjList = zoneLineDict[zoneLineKey]
+    zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {})
+    funcLineObjList = zoneLineDict.get(zoneLineKey, [])
+    isPlayerFullMax = (shuntPlayerMax >= copyMapPlayerMax)
     
-    newFuncLineNum = None
-    newFuncLineObj = None
-    for index, funcLineObj in enumerate(funcLineObjList, 1):
+    GameWorld.DebugLog("获取动态分流线路: serverGroupID=%s,mapID=%s,funcLineID=%s,zoneID=%s,shuntPlayerMax=%s,copyMapPlayerMax=%s,includeOffline=%s,dynamicShuntType=%s" 
+                       % (serverGroupID, mapID, funcLineID, zoneID, shuntPlayerMax, copyMapPlayerMax, includeOffline, dynamicShuntType), playerID)
+    #GameWorld.DebugLog("    funcLineObjList=%s" % funcLineObjList, playerID)
+    
+    canUseShuntLine = False # 是否直接使用分流线路,如果否的话,当人数未达到真正饱和时,则还可直接分配对应分流类型的线路
+    minPlayerCount, maxPlayerCount = 0, 0
+    minCopyMapObj, maxCopyMapObj = None, None
+    for _, funcLineObj in enumerate(funcLineObjList, 1):
         realMapID, copyMapID = funcLineObj.realMapID, funcLineObj.copyMapID
+        #GameWorld.DebugLog("    realMapID=%s, copyMapID=%s" % (realMapID, copyMapID))
         if not realMapID:
-            if not newFuncLineObj:
-                newFuncLineNum, newFuncLineObj = index, funcLineObj
             continue
         
         key = (realMapID, copyMapID)
@@ -203,59 +335,161 @@
         copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
         openState = copyMapObj.openState
         if openState == IPY_PlayerDefine.fbosWaitForClose:
-            if not copyMapPlayerMax:
-                PlayerControl.CrossNotifyCode(serverGroupID, playerID, "HazyRegionClose")
+            # 没有限制分流人数的情况,代表都在同一场,这种情况下当副本已经在关闭的状态下,则代表已经结束了,不可再进入
+            if not shuntPlayerMax:
+                PlayerControl.NotifyCodeCross(serverGroupID, playerID, "CrossFBClose")
                 return
-            #GameWorld.DebugLog("    虚拟线路等待关闭中! index=%s,realMapID=%s,copyMapID=%s" % (index, realMapID, copyMapID))
+            #GameWorld.DebugLog("    虚拟线路等待关闭中! realMapID=%s,copyMapID=%s" % (realMapID, copyMapID))
             continue
         
-        canEnter = copyMapObj.OnRequestEnterCrossCopyMap(playerID, serverGroupID, tick, copyMapPlayerMax)
-        if canEnter:
-            #GameWorld.DebugLog("可进入动态分布的虚拟线路! realMapID=%s,copyMapID=%s,openState=%s" % (realMapID, copyMapID, openState))
-            #GameWorld.DebugLog("    副本中的玩家ID: %s" % copyMapObj.fbPlayerDict)
-            #GameWorld.DebugLog("    等待中的玩家ID: %s" % copyMapObj.waitPlayerDict)
-            return realMapID, copyMapID, openState
+        if not shuntPlayerMax or copyMapObj.IsMustCopyMapPlayer(playerID):
+            return copyMapObj
         
+        playerCount = copyMapObj.GetCopyMapPlayerCount(includeOffline, tick)
+        if minCopyMapObj == None or playerCount < minPlayerCount:
+            minPlayerCount = playerCount
+            minCopyMapObj = copyMapObj
+        
+        if maxCopyMapObj == None or playerCount > maxPlayerCount:
+            maxPlayerCount = playerCount
+            maxCopyMapObj = copyMapObj
+            
+        # 存在线路未达到规定的分流人数,则可直接使用分流线路
+        if playerCount < shuntPlayerMax:
+            canUseShuntLine = True
+            
+    #GameWorld.DebugLog("    isPlayerFullMax=%s,canUseShuntLine=%s" % (isPlayerFullMax, canUseShuntLine))
+    dynamicShuntCopyMap = None # 分流类型决定的分流线路
+    
+    # 均摊式
+    if dynamicShuntType == DynamicShuntType_Equally:
+        dynamicShuntCopyMap = minCopyMapObj
+    # 填满式
+    elif dynamicShuntType == DynamicShuntType_Fill:
+        dynamicShuntCopyMap = maxCopyMapObj
+    else:
+        return
+        
+    shuntCopyMap = None
+    if canUseShuntLine:
+        shuntCopyMap = dynamicShuntCopyMap
+        
+    #GameWorld.DebugLog("    shuntCopyMap=%s" % shuntCopyMap)
+    if not shuntCopyMap:
+        isLog = isPlayerFullMax
+        shuntCopyMap = __OpenNewFuncLine(mapID, zoneID, funcLineID, isLog)
+        
+        # 即 shuntPlayerMax < copyMapPlayerMax 的情况
+        if not shuntCopyMap and not isPlayerFullMax:
+            shuntCopyMap = dynamicShuntCopyMap
+            
+    if not shuntCopyMap:
+        return
+    
+    shuntCopyMap.waitPlayerDict[playerID] = [serverGroupID, tick]
+    
+    return shuntCopyMap
+
+def __OpenNewFuncLine(mapID, zoneID, funcLineID, isLog=True):
+    ## 新开功能线路分流
+    
+    if mapID not in PyGameData.g_crossDynamicLineInfo:
+        PyGameData.g_crossDynamicLineInfo[mapID] = {}
+    zoneLineDict = PyGameData.g_crossDynamicLineInfo[mapID] # 跨服动态线路信息 {dataMapID:{(zoneID, funcLineID):[CrossFuncLineInfo, CrossFuncLineInfo, ...], ...}, ...}
+    zoneLineKey = (zoneID, funcLineID)
+    if zoneLineKey not in zoneLineDict:
+        zoneLineDict[zoneLineKey] = []
+    funcLineObjList = zoneLineDict[zoneLineKey]
+    
     dynamicLineMapDict = IpyGameDataPY.GetFuncEvalCfg("CrossDynamicLineMap", 1)
     dynamicMapIDList = dynamicLineMapDict.get(mapID, [mapID])
     
     openMapID, openCopyMapID = 0, 0
-    for realMapID in dynamicMapIDList:
-        maxCopyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0)
-        for copyMapID in xrange(maxCopyMapCount):
+    maxCopyMapCount = PyGameData.g_crossMapCopyMapCountDict.get(dynamicMapIDList[0], 0)
+    # 外层为虚拟线路总数遍历,内层为分流地图,这样可以均匀分流到各个分流地图,减少单地图压力
+    for copyMapID in xrange(maxCopyMapCount):
+        for realMapID in dynamicMapIDList:
+            if copyMapID >= PyGameData.g_crossMapCopyMapCountDict.get(realMapID, 0):
+                continue
             if (realMapID, copyMapID) not in PyGameData.g_crossDynamicLineCopyMapInfo:
                 openMapID, openCopyMapID = realMapID, copyMapID
                 break
         if openMapID:
             break
+        
     if not openMapID:
-        GameWorld.ErrLog("没有空余的虚拟线路,无法动态开启跨服副本!mapID=%s, funcLineID=%s, zoneID=%s, dynamicMapIDList=%s" 
-                         % (mapID, funcLineID, zoneID, dynamicMapIDList))
+        if isLog:
+            GameWorld.ErrLog("没有空余的虚拟线路,无法动态开启跨服副本! mapID=%s,zoneID=%s,funcLineID=%s,dynamicMapIDList=%s" 
+                             % (mapID, zoneID, funcLineID, dynamicMapIDList))
         return
     
+    realMapID, copyMapID = openMapID, openCopyMapID
+        
+    newFuncLineObj = None
+    for funcLineObj in funcLineObjList:
+        if not funcLineObj.realMapID:
+            newFuncLineObj = funcLineObj
+            break
+        
     if newFuncLineObj == None:
         newFuncLineObj = CrossFuncLineInfo()
         funcLineObjList.append(newFuncLineObj)
-        newFuncLineNum = len(funcLineObjList)
-    realMapID, copyMapID = openMapID, openCopyMapID
+        
+    newFuncLineNum = 1
+    lineNumList = [lineObj.newFuncLineNum for lineObj in funcLineObjList]
+    for num in xrange(1, len(lineNumList) + 1):
+        if num not in lineNumList:
+            newFuncLineNum = num
+            break
+    GameWorld.DebugLog("    lineNumList=%s,newFuncLineNum=%s" % (lineNumList, newFuncLineNum))
+    
     newFuncLineObj.realMapID = realMapID
     newFuncLineObj.copyMapID = copyMapID
-    funcLineDataCache = newFuncLineObj.funcLineDataCache
+    newFuncLineObj.newFuncLineNum = newFuncLineNum
+    
+    copyMapObj = CrossCopyMapInfo(zoneID, funcLineID)
+    copyMapObj.realMapID = realMapID
+    copyMapObj.copyMapID = copyMapID
+    copyMapObj.newFuncLineNum = newFuncLineNum
     
     key = (realMapID, copyMapID)
-    copyMapObj = CrossCopyMapInfo(zoneID, funcLineID)
     PyGameData.g_crossDynamicLineCopyMapInfo[key] = copyMapObj
-    copyMapObj.waitPlayerDict[playerID] = [serverGroupID, tick]
-    openState = copyMapObj.openState
     
-    propertyID = int("%d%03d%d" % (zoneID, funcLineID, newFuncLineNum))
-    GameWorld.DebugLog("不存在该分区功能线路ID,重新分配: zoneID=%s,funcLineID=%s,realMapID=%s,copyMapID=%s,propertyID=%s" 
-                       % (zoneID, funcLineID, realMapID, copyMapID, propertyID))
+    propertyID = int("%d%03d%02d" % (zoneID, funcLineID, newFuncLineNum))
+    GameWorld.Log("    新开分区动态副本功能线路: zoneID=%s,funcLineID=%s,newFuncLineNum=%s,realMapID=%s,copyMapID=%s,propertyID=%s" 
+                  % (zoneID, funcLineID, newFuncLineNum, realMapID, copyMapID, propertyID))
     
     # 通知地图开启新的地图虚拟分线
+    funcLineDataCache = newFuncLineObj.funcLineDataCache
     msgInfo = str([copyMapID, propertyID, funcLineDataCache])
     GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, realMapID, "OpenFB", msgInfo, len(msgInfo))
-    return realMapID, copyMapID, openState
+    return copyMapObj
+
+def OpenCrossDynamicLineBySys(zoneID, mapID, funcLineIDList, checkExist):
+    ## 系统开启跨服动态线路
+    
+    GameWorld.Log("    系统开启跨服动态线路: zoneID=%s, mapID=%s, funcLineIDList=%s, checkExist=%s" % (zoneID, mapID, funcLineIDList, checkExist))
+    
+    for funcLineID in funcLineIDList:
+        
+        if checkExist:   
+            fincLineObj = None
+            zoneLineKey = (zoneID, funcLineID)
+            zoneLineDict = PyGameData.g_crossDynamicLineInfo.get(mapID, {})
+            funcLineObjList = zoneLineDict.get(zoneLineKey, [])
+            for funcLineObj in funcLineObjList:
+                if funcLineObj.realMapID:
+                    fincLineObj = funcLineObj
+                    break
+                
+            if fincLineObj:
+                GameWorld.ErrLog("已经存在开放中的线路,不重复开启动态副本线路! mapID=%s, funcLineID=%s, zoneID=%s, realMapID=%s, copyMapID=%s" 
+                                 % (mapID, funcLineID, zoneID, funcLineObj.realMapID, funcLineObj.copyMapID))
+                continue
+            
+        __OpenNewFuncLine(mapID, zoneID, funcLineID)
+        
+    return
 
 def GetCrossDynamicLineZoneID(mapID, realMapID, copyMapID):
     ## 获取跨服动态分配的虚拟线路对应分区ID
@@ -345,6 +579,8 @@
                 funcLineObj.OnCopyMapClose()
                 zoneID, funcLineID = key
                 GameWorld.Log("    分区对应功能线路虚拟分线关闭: zoneID=%s,dataMapID%s,funcLineID=%s" % (zoneID, dataMapID, funcLineID))
+                if not funcLineObj.funcLineDataCache:
+                    funcLineObjList.remove(funcLineObj)
                 break
     
     key = (mapID, copyMapID)
@@ -401,6 +637,8 @@
     copyMapObj.waitPlayerDict.pop(playerID, None)
     copyMapObj.offlinePlayerDict.pop(playerID, None)
     copyMapObj.fbPlayerDict[playerID] = serverGroupID
+    if playerID not in copyMapObj.enterPlayerIDList:
+        copyMapObj.enterPlayerIDList.append(playerID)
     
     #GameWorld.DebugLog("玩家登录动态分配的跨服地图: GetMapID=%s,GetRealMapID=%s,GetFBID()=%s,serverGroupID=%s" 
     #                   % (curPlayer.GetMapID(), mapID, copyMapID, serverGroupID), playerID)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index e3a8409..4d45f72 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -70,6 +70,7 @@
 import CrossRealmPlayer
 import CrossRealmMsg
 import CrossRealmPK
+import CrossBattlefield
 import ChPyNetSendPack
 import NetPackCommon
 import AuctionHouse
@@ -508,10 +509,10 @@
         return
     
     if callName == "SendMail":
-        title, content, getDays, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource = eval(resultName)
+        title, content, getDays, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail = eval(resultName)
         limitTime = str(GameWorld.GetDatetimeByDiffDays(getDays))
         limitTime = limitTime.split(".")[0]
-        PlayerCompensation.SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail, moneySource=moneySource)
+        PlayerCompensation.SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail, moneySource=moneySource, crossMail=crossMail)
         return
     
     if callName == "SendMailBatch":
@@ -649,6 +650,11 @@
         CrossRealmPlayer.OnCrossRealmRegOK(srcPlayerID, eval(resultName), tick)
         return
     
+    # 跨服战场结算
+    if callName =="CrossBattlefieldOver":
+        CrossBattlefield.MapServer_CrossBattlefieldOver(eval(resultName))
+        return
+    
     #py喇叭聊天
     if callName == 'PYSpeaker':
         curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
index 3e4270a..322b1a8 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -24,6 +24,7 @@
 import GameWorldArena
 import ChPyNetSendPack
 import PlayerFBHelpBattle
+import CrossBattlefield
 import PyGameDataStruct
 import IpyGameDataPY
 import PyDataManager
@@ -44,6 +45,9 @@
     if GameWorldArena.IsArenaBattlePlayer(playerID):
         return True
     
+    if CrossBattlefield.IsBattlefieldCallPlayer(playerID):
+        return True
+    
     SaveDBLimitLV = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1)
     #校验玩家等级
     if playerLV < SaveDBLimitLV:
@@ -58,6 +62,9 @@
         return True
     
     if GameWorldArena.IsArenaBattlePlayer(playerID):
+        return True
+    
+    if CrossBattlefield.IsBattlefieldCallPlayer(playerID):
         return True
     
     NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
@@ -116,7 +123,7 @@
     ## 获取缓存基础属性字典信息
     if not hasattr(curCache, "PropDataDict"):
         curCache.PropDataDict = {}
-    if not curCache.PropDataDict:
+    if not curCache.PropDataDict and curCache.PropData:
         curCache.PropDataDict = eval(curCache.PropData)
     return curCache.PropDataDict
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index dce06af..3e9c217 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -139,6 +139,10 @@
 
 g_crossFBFuncLinePlayerCountInfo = {} # 跨服副本功能线路人数信息,本服缓存 {mapID:{funcLineID:[playerCount], ...}, ...}
 
+g_unNotifyPlayerCrossMsgDict = {} # 未通知玩家的跨服命令 {playerID:{msgType:[msgInfo], ...}, ...}
+
+g_crossBattlefieldBuyInfo = {} # 跨服战场购买记录 {zoneID:{hmNum:{playerID:CrossBattlefieldBuy, ...}, ...}, ...}
+
 g_familyTalkCache = {} #{familyID:[[time,content,extras],..]}
 g_worldTalkCache = [] #[[time,name, playerID, content,extras],..]
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index b64d1b7..8d8ad16 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -650,6 +650,18 @@
 PacketSubCMD_1=0x10
 PacketCallFunc_1=OnLuckyCloudBuy
 
+;跨服战场
+[PlayerCrossBattlefield]
+ScriptName = Player\PlayerCrossBattlefield.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xC1
+PacketSubCMD_1=0x09
+PacketCallFunc_1=OnCrossBattlefieldBuyOpen
+
 ;改名功能
 [UpdatePlayerName]
 ScriptName = Player\UpdatePlayerName.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 96ef755..f1a2139 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -3987,6 +3987,126 @@
 
 
 #------------------------------------------------------
+# C0 08 跨服战场召集场次踢人 #tagCGCrossBattlefieldCallKick
+
+class  tagCGCrossBattlefieldCallKick(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("TagPlayerID", c_int),    #目标玩家ID,即要被踢出去的玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x08
+        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 = 0x08
+        self.Hour = 0
+        self.Minute = 0
+        self.TagPlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCrossBattlefieldCallKick)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 08 跨服战场召集场次踢人 //tagCGCrossBattlefieldCallKick:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                TagPlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.TagPlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGCrossBattlefieldCallKick=tagCGCrossBattlefieldCallKick()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCrossBattlefieldCallKick.Cmd,m_NAtagCGCrossBattlefieldCallKick.SubCmd))] = m_NAtagCGCrossBattlefieldCallKick
+
+
+#------------------------------------------------------
+# C0 07 跨服战场加入召集场次 #tagCGCrossBattlefieldJoinByCall
+
+class  tagCGCrossBattlefieldJoinByCall(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("BuyPlayerID", c_int),    #加入目标玩家的召集队伍,即购买召集场的玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x07
+        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 = 0x07
+        self.Hour = 0
+        self.Minute = 0
+        self.BuyPlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGCrossBattlefieldJoinByCall)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 07 跨服战场加入召集场次 //tagCGCrossBattlefieldJoinByCall:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                BuyPlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.BuyPlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGCrossBattlefieldJoinByCall=tagCGCrossBattlefieldJoinByCall()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGCrossBattlefieldJoinByCall.Cmd,m_NAtagCGCrossBattlefieldJoinByCall.SubCmd))] = m_NAtagCGCrossBattlefieldJoinByCall
+
+
+#------------------------------------------------------
 # C0 03 强制退出跨服状态 #tagCGForceQuitCrossState
 
 class  tagCGForceQuitCrossState(Structure):
@@ -18941,6 +19061,66 @@
 
 
 #------------------------------------------------------
+# C1 09 跨服战场购买开启场次 #tagCMCrossBattlefieldBuyOpen
+
+class  tagCMCrossBattlefieldBuyOpen(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Hour", c_ubyte),    #战场开启时
+                  ("Minute", c_ubyte),    #战场开启分
+                  ("Faction", c_ubyte),    #阵营 1-红;2-蓝
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.Hour = 0
+        self.Minute = 0
+        self.Faction = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMCrossBattlefieldBuyOpen)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 09 跨服战场购买开启场次 //tagCMCrossBattlefieldBuyOpen:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Hour:%d,
+                                Minute:%d,
+                                Faction:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Hour,
+                                self.Minute,
+                                self.Faction
+                                )
+        return DumpString
+
+
+m_NAtagCMCrossBattlefieldBuyOpen=tagCMCrossBattlefieldBuyOpen()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCrossBattlefieldBuyOpen.Cmd,m_NAtagCMCrossBattlefieldBuyOpen.SubCmd))] = m_NAtagCMCrossBattlefieldBuyOpen
+
+
+#------------------------------------------------------
 # C1 06 跨服NPC对话 #tagCMCrossNPCTalk
 
 class  tagCMCrossNPCTalk(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 7d369cc..6a91da3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -12288,6 +12288,283 @@
 
 
 #------------------------------------------------------
+# C0 09 跨服战场玩家购买战场信息 #tagGCCrossBattlefieldBuyInfo
+
+class  tagGCCrossBattlefieldPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)
+    PlayerName = ""    #(char PlayerName[33])
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)//等级
+    RealmLV = 0    #(WORD RealmLV)//境界
+    FightPower = 0    #(DWORD FightPower)//战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)//战力整除亿部分
+    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.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.RealmLV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 33
+        length += 1
+        length += 2
+        length += 2
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteString(data, 33, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                RealmLV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.RealmLV,
+                                self.FightPower,
+                                self.FightPowerEx
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyPlayer(Structure):
+    BuyPlayerID = 0    #(DWORD BuyPlayerID)//购买的玩家ID,即召集人
+    Faction = 0    #(BYTE Faction)//阵营 1-红;2-蓝
+    FactionPlayerCount = 0    #(BYTE FactionPlayerCount)
+    FactionPlayerList = list()    #(vector<tagGCCrossBattlefieldPlayer> FactionPlayerList)//阵营所有玩家列表,包含召集人
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.BuyPlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Faction,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.FactionPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.FactionPlayerCount):
+            temFactionPlayerList = tagGCCrossBattlefieldPlayer()
+            _pos = temFactionPlayerList.ReadData(_lpData, _pos)
+            self.FactionPlayerList.append(temFactionPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.BuyPlayerID = 0
+        self.Faction = 0
+        self.FactionPlayerCount = 0
+        self.FactionPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += 1
+        for i in range(self.FactionPlayerCount):
+            length += self.FactionPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.BuyPlayerID)
+        data = CommFunc.WriteBYTE(data, self.Faction)
+        data = CommFunc.WriteBYTE(data, self.FactionPlayerCount)
+        for i in range(self.FactionPlayerCount):
+            data = CommFunc.WriteString(data, self.FactionPlayerList[i].GetLength(), self.FactionPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                BuyPlayerID:%d,
+                                Faction:%d,
+                                FactionPlayerCount:%d,
+                                FactionPlayerList:%s
+                                '''\
+                                %(
+                                self.BuyPlayerID,
+                                self.Faction,
+                                self.FactionPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyHM(Structure):
+    Hour = 0    #(BYTE Hour)//战场开启时
+    Minute = 0    #(BYTE Minute)//战场开启分
+    BuyPlayerCount = 0    #(BYTE BuyPlayerCount)
+    BuyPlayerList = list()    #(vector<tagGCCrossBattlefieldBuyPlayer> BuyPlayerList)//购买本场次的玩家信息列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.Hour,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Minute,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.BuyPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BuyPlayerCount):
+            temBuyPlayerList = tagGCCrossBattlefieldBuyPlayer()
+            _pos = temBuyPlayerList.ReadData(_lpData, _pos)
+            self.BuyPlayerList.append(temBuyPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.Hour = 0
+        self.Minute = 0
+        self.BuyPlayerCount = 0
+        self.BuyPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.BuyPlayerCount):
+            length += self.BuyPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.Hour)
+        data = CommFunc.WriteBYTE(data, self.Minute)
+        data = CommFunc.WriteBYTE(data, self.BuyPlayerCount)
+        for i in range(self.BuyPlayerCount):
+            data = CommFunc.WriteString(data, self.BuyPlayerList[i].GetLength(), self.BuyPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Hour:%d,
+                                Minute:%d,
+                                BuyPlayerCount:%d,
+                                BuyPlayerList:%s
+                                '''\
+                                %(
+                                self.Hour,
+                                self.Minute,
+                                self.BuyPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossBattlefieldBuyInfo(Structure):
+    Head = tagHead()
+    HMCount = 0    #(BYTE HMCount)// 为0时清空重置,其他为增量更新
+    HMBuyList = list()    #(vector<tagGCCrossBattlefieldBuyHM> HMBuyList)//购买场次列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x09
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.HMCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.HMCount):
+            temHMBuyList = tagGCCrossBattlefieldBuyHM()
+            _pos = temHMBuyList.ReadData(_lpData, _pos)
+            self.HMBuyList.append(temHMBuyList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x09
+        self.HMCount = 0
+        self.HMBuyList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        for i in range(self.HMCount):
+            length += self.HMBuyList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.HMCount)
+        for i in range(self.HMCount):
+            data = CommFunc.WriteString(data, self.HMBuyList[i].GetLength(), self.HMBuyList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                HMCount:%d,
+                                HMBuyList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.HMCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossBattlefieldBuyInfo=tagGCCrossBattlefieldBuyInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBattlefieldBuyInfo.Head.Cmd,m_NAtagGCCrossBattlefieldBuyInfo.Head.SubCmd))] = m_NAtagGCCrossBattlefieldBuyInfo
+
+
+#------------------------------------------------------
 # C0 07 跨服排行榜信息 #tagGCCrossBillboardInfo
 
 class  tagGCCrossBillboardData(Structure):
@@ -40971,6 +41248,62 @@
 
 
 #------------------------------------------------------
+# C1 07 跨服战场玩家信息 #tagMCCrossBattlefieldPlayerInfo
+
+class  tagMCCrossBattlefieldPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("BuyOpenCountToday", c_ubyte),    # 今日已购买开启战场次数
+                  ("HighScoreToday", c_int),    # 今日最高积分
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x07
+        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 = 0x07
+        self.BuyOpenCountToday = 0
+        self.HighScoreToday = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCrossBattlefieldPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 07 跨服战场玩家信息 //tagMCCrossBattlefieldPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                BuyOpenCountToday:%d,
+                                HighScoreToday:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.BuyOpenCountToday,
+                                self.HighScoreToday
+                                )
+        return DumpString
+
+
+m_NAtagMCCrossBattlefieldPlayerInfo=tagMCCrossBattlefieldPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCrossBattlefieldPlayerInfo.Cmd,m_NAtagMCCrossBattlefieldPlayerInfo.SubCmd))] = m_NAtagMCCrossBattlefieldPlayerInfo
+
+
+#------------------------------------------------------
 # C1 02 跨服PK玩家奖励记录 #tagMCCrossRealmPKAwardState
 
 class  tagMCCrossRealmPKAwardState(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CrossBattle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CrossBattle.py
new file mode 100644
index 0000000..6fe7508
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/CrossBattle.py
@@ -0,0 +1,118 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.CrossBattle
+#
+# @todo:跨服战场
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服战场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import GameLogic_CrossBattlefield
+import ShareDefine
+import ChConfig
+import FBCommon
+
+
+## 逻辑实现
+#  @param curPlayer
+#  @param cmdList 参数列表
+#  @return None
+def OnExec(curPlayer, cmdList):
+    
+    if not cmdList:
+        GameWorld.DebugAnswer(curPlayer, "--------------------------------")
+        GameWorld.DebugAnswer(curPlayer, "设置玩家击杀: CrossBattle 1 击杀数 [可选玩家ID]")
+        GameWorld.DebugAnswer(curPlayer, "设置玩家积分: CrossBattle 2 总积分 [可选玩家ID]")
+        GameWorld.DebugAnswer(curPlayer, "设置阵营击杀: CrossBattle 3 击杀数 [可选阵营ID]")
+        GameWorld.DebugAnswer(curPlayer, "设置阵营积分: CrossBattle 4 总积分 [可选阵营ID]")
+        GameWorld.DebugAnswer(curPlayer, "重置大奖信息: CrossBattle 5 [可选是否重新随机]")
+        GameWorld.DebugAnswer(curPlayer, "可选玩家/阵营ID没填则默认自身")
+        return
+    
+    tick = GameWorld.GetGameWorld().GetTick()
+    playerID = curPlayer.GetPlayerID()
+    mapID = FBCommon.GetRecordMapID(GameWorld.GetMap().GetMapID())
+    value1 = cmdList[0]
+    if value1 in [1, 2, 3, 4, 5, 6] and not GameWorld.IsCrossServer() or mapID != ChConfig.Def_FBMapID_CrossBattlefield:
+        GameWorld.DebugAnswer(curPlayer, "该命令需在跨服战场使用CrossServer发送")
+        return
+    
+    # 设置玩家击杀
+    if value1 == 1:
+        setCount = cmdList[1] if len(cmdList) > 1 else 1
+        tagPlayerID = cmdList[2] if len(cmdList) > 2 else playerID
+        battleObj = GameLogic_CrossBattlefield.GetBattlePlayerObj(tagPlayerID)
+        battleObj.killCount = setCount
+        GameWorld.DebugAnswer(curPlayer, "玩家(%s)击杀数: %s" % (tagPlayerID, battleObj.killCount))
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, GameLogic_CrossBattlefield.DoFBHelp, 0, GameLogic_CrossBattlefield.refreshFactionPlayer) # 触发刷新FBHelp
+        return
+    
+    # 设置玩家积分
+    if value1 == 2:
+        setScore = cmdList[1] if len(cmdList) > 1 else 1
+        tagPlayerID = cmdList[2] if len(cmdList) > 2 else playerID
+        battleObj = GameLogic_CrossBattlefield.GetBattlePlayerObj(tagPlayerID)
+        battleObj.score = setScore
+        GameWorld.DebugAnswer(curPlayer, "玩家(%s)积分: %s" % (tagPlayerID, battleObj.score))
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, GameLogic_CrossBattlefield.DoFBHelp, 0, GameLogic_CrossBattlefield.refreshFactionPlayer) # 触发刷新FBHelp
+        return
+    
+    # 设置阵营击杀
+    if value1 == 3:
+        setCount = cmdList[1] if len(cmdList) > 1 else 1
+        tagFaction = cmdList[2] if len(cmdList) > 2 else 0
+        if not tagFaction or tagFaction not in ShareDefine.CampTypeList:
+            battleObj = GameLogic_CrossBattlefield.GetBattlePlayerObj(playerID)
+            tagFaction = battleObj.faction
+        factionObj = GameLogic_CrossBattlefield.GetBattleFactionObj(tagFaction)
+        factionObj.killCount = setCount
+        GameWorld.DebugAnswer(curPlayer, "阵营(%s)击杀数: %s" % (tagFaction, factionObj.killCount))
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, GameLogic_CrossBattlefield.DoFBHelp, 0, GameLogic_CrossBattlefield.refreshFactionPlayer) # 触发刷新FBHelp
+        return
+    
+    # 设置阵营积分
+    if value1 == 4:
+        setScore = cmdList[1] if len(cmdList) > 1 else 1
+        tagFaction = cmdList[2] if len(cmdList) > 2 else 0
+        if not tagFaction or tagFaction not in ShareDefine.CampTypeList:
+            battleObj = GameLogic_CrossBattlefield.GetBattlePlayerObj(playerID)
+            tagFaction = battleObj.faction
+        factionObj = GameLogic_CrossBattlefield.GetBattleFactionObj(tagFaction)
+        factionObj.score = setScore
+        GameWorld.DebugAnswer(curPlayer, "阵营(%s)积分: %s" % (tagFaction, factionObj.score))
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, GameLogic_CrossBattlefield.DoFBHelp, 0, GameLogic_CrossBattlefield.refreshFactionPlayer) # 触发刷新FBHelp
+        return
+    
+    # 重置大奖信息
+    if value1 == 5:
+        isRand = cmdList[1] if len(cmdList) > 1 else 1
+        worldObj = GameLogic_CrossBattlefield.GetBattleWorld()
+        worldObj.superItemPlayerID = 0
+        worldObj.superItemPlayerName = ""
+        if isRand:
+            worldObj.RandSuperTask()
+        for faction in ShareDefine.CampTypeList:
+            if not faction:
+                continue
+            factionObj = GameLogic_CrossBattlefield.GetBattleFactionObj(faction)
+            factionObj.superTaskValue = 0
+            factionObj.superTaskFinishCount = 0
+            factionObj.setSuperTaskValueMax(worldObj)
+            for battleObj in factionObj.factionPlayerDict.values():
+                battleObj.superTaskValue = 0
+                battleObj.superTaskFinishCount = 0
+                battleObj.setSuperTaskValueMax(worldObj)
+        GameWorld.DebugAnswer(curPlayer, "重置大奖信息OK!")
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, GameLogic_CrossBattlefield.DoFBHelp, 0, GameLogic_CrossBattlefield.refreshFactionPlayer) # 触发刷新FBHelp
+        return
+    
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
index 57ac0d1..4a1a011 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -1766,6 +1766,15 @@
     #DebugLog("日期相差天数大于1,不同一天!")
     return False
 
+def CheckTimeIsSameWeek(checkTime):
+    '''判断指定time值与当天时间对比是否为游戏内的同一周;特殊时间点过天后才算不同天
+    @return: 是否同一周
+    '''
+    checkDate = ChangeTimeNumToDatetime(checkTime)
+    checkWeek = datetime.datetime.isocalendar(checkDate)[1]
+    curWeek = GetWeekOfYear()
+    return checkWeek == curWeek
+
 ## 获取玩家的区服名,仅在跨服有效
 #  @param curPlayer 玩家实例
 #  @return: 区服名
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
index 1957e35..5c8e794 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -917,7 +917,7 @@
     gameFB = GameWorld.GetGameFB()
     gameFB.SetFBStep(step)
     gameFB.SetFBStepTick(tick)
-    GameWorld.Log("SetFBStep %s, tick=%s" % (step, tick))
+    GameWorld.Log("SetFBStep %s, tick=%s" % (step, tick), GameWorld.GetGameWorld().GetPropertyID())
     return
 #---------------------------------------------------------------------
 ## 给客户端弹消息
@@ -2595,13 +2595,16 @@
 def GetFBAreaRewardTechPoint(gameWorld, playerID):
     return gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetTechPoint%playerID)
 
-def NotifyCopyMapPlayerFBHelp(tick, fbHelpFunc, interval=10000):
+def NotifyCopyMapPlayerFBHelp(tick, fbHelpFunc, interval=10000, befLogicFunc=None):
     gameFB = GameWorld.GetGameFB()
     lastTick = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_NotifyFBHelpTick)
     if tick - lastTick < interval:
         return
     gameFB.SetGameFBDict(ChConfig.Def_FB_NotifyFBHelpTick, tick)
     
+    if befLogicFunc:
+        befLogicFunc(tick)
+        
     playerManager = GameWorld.GetMapCopyPlayerManager()
     for index in xrange(playerManager.GetPlayerCount()):
         curPlayer = playerManager.GetPlayerByIndex(index)
@@ -2612,9 +2615,9 @@
 
 def GetCrossDynamicLineMapZoneID():
     ## 获取跨服动态线路地图本线路跨服分区
-    return GameWorld.GetGameWorld().GetPropertyID() / 10000
+    return GameWorld.GetGameWorld().GetPropertyID() / 100000
 
 def GetCrossDynamicLineMapFuncLineID():
     ## 获取跨服动态线路地图本线路功能线路ID
-    return GameWorld.GetGameWorld().GetPropertyID() % 10000 / 10
+    return GameWorld.GetGameWorld().GetPropertyID() % 100000 / 100
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossBattlefield.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossBattlefield.py
new file mode 100644
index 0000000..5db11ee
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossBattlefield.py
@@ -0,0 +1,890 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_CrossBattlefield
+#
+# @todo:跨服战场
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服战场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+
+import FBCommon
+import GameWorld
+import NPCCommon
+import PyGameData
+import IPY_GameWorld
+import IpyGameDataPY
+import PlayerActivity
+import GameWorldProcess
+import PlayerControl
+import ShareDefine
+import SkillCommon
+import BuffSkill
+import ChConfig
+import GameMap
+
+import operator
+import random
+import time
+
+#当前副本地图的状态
+(
+FB_Step_Open, # 地图开启
+FB_Step_Prepare, # 地图准备
+FB_Step_Fighting, # 战斗中
+FB_Step_LeaveTime, # 自由时间
+FB_Step_Over, # 副本关闭
+) = range(5)
+
+(
+Time_Prepare, # 副本准备时间 0
+Time_Fight, # 副本战斗时间 1
+Time_Leave, # 副本离开时间 2
+) = range(3)
+
+# 大奖任务类型
+SuperTaskList = (
+SuperTaskType_Kill, # 击杀 1
+SuperTaskType_Score, # 积分 2
+) = range(1, 1 + 2)
+
+GameFBData_BattleWorld = "BattleWorld"
+GameFBData_FactionInfo = "FactionInfo"
+GameFBData_PlayerInfo = "PlayerInfo"
+
+## 战场公共世界管理类
+class BattleWorld():
+    
+    def __init__(self):
+        self.superItemInfo = [] # 大奖信息 [物品ID,个数,是否拍品]
+        self.superItemPlayerID = 0 # 大奖中奖者玩家ID
+        self.superItemPlayerName = "" # 大奖中奖者玩家名
+        self.superTaskType = 0 # 大奖任务类型
+        self.RandSuperTask()
+        return
+    
+    def RandSuperTask(self):
+        # 随机生成大奖任务
+        fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+        superItemWeightList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAwardSuper", 1)
+        superItemInfo = GameWorld.GetResultByWeightList(superItemWeightList)
+        self.superItemInfo = superItemInfo if superItemInfo else []
+        self.superTaskType = random.choice(SuperTaskList)
+        GameWorld.Log("随机战场大奖: superTaskType=%s,superItemInfo=%s" % (self.superTaskType, self.superItemInfo), fbPropertyID)
+        return
+    
+    
+## 战斗实体基类
+class BattleBase(object):
+    
+    BattleType_Player = "Player"
+    BattleType_Faction = "Faction"
+    
+    def __init__(self, ID):
+        self.fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+        self.battleType = ""
+        self.ID = ID
+        self.name = ""
+        self.score = 0 # 积分
+        self.scoreSortTime = 0 # 积分变更排序time值,用于同积分时,先到排名靠前
+        self.superTaskValue = 0 # 大奖任务当前进度
+        self.superTaskValueMax = 0 # 大奖任务完成需要的进度值
+        self.superTaskFinishCount = 0 # 大奖任务完成次数
+        self.killCount = 0 # 击杀数
+        self.continueKillCount = 0 # 连杀数
+        self.beKilledCount = 0 # 被击杀数
+        return
+    
+    def addScore(self, worldObj, addValue):
+        self.score += addValue
+        calcTime = 3471264000 #GameWorld.ChangeTimeStrToNum("2080-01-01 00:00:00")
+        self.scoreSortTime = max(0, calcTime - int(time.time()))
+        GameWorld.DebugLog("    增加积分: battleType=%s,ID=%s,addValue=%s,updScore=%s" % (self.battleType, self.ID, addValue, self.score), self.fbPropertyID)
+        self.addSuperTaskValue(worldObj, SuperTaskType_Score, addValue)
+        return
+    
+    def addKillCount(self, worldObj, addCount):
+        self.killCount += addCount
+        self.continueKillCount += addCount # 同步增加连杀
+        self.addSuperTaskValue(worldObj, SuperTaskType_Kill, addCount)
+        return
+    
+    def addBeKilledCount(self, addCount):
+        self.beKilledCount += addCount
+        self.continueKillCount = 0 # 被击杀时,连杀重置
+        return
+    
+    def setSuperTaskValueMax(self, worldObj):
+        if worldObj == None:
+            worldObj = GetBattleWorld()
+        taskType = worldObj.superTaskType
+        if taskType == SuperTaskType_Kill:
+            superTaskValueMaxList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAwardSuper2", 1)
+        elif taskType == SuperTaskType_Score:
+            superTaskValueMaxList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldAwardSuper2", 2)
+        else:
+            return
+        
+        if self.battleType == self.BattleType_Player:
+            curValueMaxList = superTaskValueMaxList[0]
+        elif self.battleType == self.BattleType_Faction:
+            curValueMaxList = superTaskValueMaxList[1]
+        else:
+            return
+        
+        if not curValueMaxList:
+            return
+        
+        if self.superTaskFinishCount >= len(curValueMaxList):
+            valueMax = curValueMaxList[-1]
+        else:
+            valueMax = curValueMaxList[self.superTaskFinishCount]
+        self.superTaskValueMax = valueMax
+        GameWorld.Log("    更新大奖任务进度完成所需值! battleType=%s,ID=%s,taskType=%s,superTaskFinishCount=%s,superTaskValueMax=%s" 
+                      % (self.battleType, self.ID, taskType, self.superTaskFinishCount, self.superTaskValueMax), self.fbPropertyID)
+        return
+    
+    def addSuperTaskValue(self, worldObj, taskType, addValue):        
+        if taskType != worldObj.superTaskType:
+            #GameWorld.DebugLog("    非战场大奖任务类型,不处理! taskType=%s != superTaskType(%s)" % (taskType, worldObj.superTaskType), self.fbPropertyID)
+            return
+        
+        if len(worldObj.superItemInfo) != 3:
+            GameWorld.ErrLog("大奖任务物品异常,不处理! taskType=%s,superItemInfo=%s" % (taskType, worldObj.superItemInfo), self.fbPropertyID)
+            return
+        
+        if worldObj.superItemPlayerID:
+            GameWorld.DebugLog("    大奖已经产出,不再处理! superItemPlayerID=%s" % worldObj.superItemPlayerID, self.fbPropertyID)
+            return
+            
+        if not self.superTaskValueMax:
+            self.setSuperTaskValueMax(worldObj)
+        if not self.superTaskValueMax:
+            return
+        
+        self.superTaskValue += addValue
+        if self.superTaskValue < self.superTaskValueMax:
+            GameWorld.DebugLog("    更新大奖进度! battleType=%s,ID=%s,taskType=%s,addValue=%s,superTaskValue=%s < %s" 
+                               % (self.battleType, self.ID, taskType, addValue, self.superTaskValue, self.superTaskValueMax), self.fbPropertyID)
+            return
+        self.superTaskValue -= self.superTaskValueMax
+        self.superTaskFinishCount += 1
+        GameWorld.Log("    完成大奖任务! battleType=%s,ID=%s,taskType=%s,superTaskFinishCount=%s" 
+                      % (self.battleType, self.ID, taskType, self.superTaskFinishCount), self.fbPropertyID)
+        self.setSuperTaskValueMax(worldObj)
+        
+        superRate = self.getSuperItemRate()
+        tick = GameWorld.GetGameWorld().GetTick()
+        if not GameWorld.CanHappen(superRate):
+            GameWorld.Log("        大奖没有中奖! battleType=%s,ID=%s,taskType=%s,superRate=%s" 
+                          % (self.battleType, self.ID, taskType, superRate), self.fbPropertyID)
+            FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0, refreshFactionPlayer)
+            return
+        
+        superItemPlayerID = self.getSuperItemPlayerID()
+        GameWorld.Log("        大奖中奖! battleType=%s,ID=%s,taskType=%s,superRate=%s,superItemPlayerID=%s" 
+                      % (self.battleType, self.ID, taskType, superRate, superItemPlayerID), self.fbPropertyID)
+        if not superItemPlayerID:
+            return
+        worldObj.superItemPlayerID = superItemPlayerID
+        itemID, itemCount = worldObj.superItemInfo[0], worldObj.superItemInfo[1]
+        battleObj = GetBattlePlayerObj(superItemPlayerID)
+        worldObj.superItemPlayerName = battleObj.name
+        PlayerControl.FBNotify("CrossBattlefieldSuperItemPlayer", [battleObj.faction, battleObj.name, itemID, itemCount])
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0, refreshFactionPlayer)
+        return
+    
+    def getSuperItemRate(self): return 0
+    def getSuperItemPlayerID(self): return 0
+    
+## 战场阵营类
+class BattleFaction(BattleBase):
+    
+    def __init__(self, faction):
+        super(BattleFaction, self).__init__(faction)
+        self.faction = faction
+        self.battleType = self.BattleType_Faction
+        self.factionPlayerDict = {} # {playerID:BattlePlayer, ...}
+        self.battlePlayerSortList = [] # 阵营积分排名玩家列表 [BattlePlayer, ...]
+        self.scoreKingIDList = [] # 前x名积分王ID列表 [playerID, ...] ,只算在线的,所以不一定是积分排名前x名
+        
+        self.onlineFightPowerTotal = 0 # 在线人数总战力
+        self.onlinePlayerIDList = [] # 在线玩家ID列表 [playerID, ...]
+        self.setSuperTaskValueMax(None)
+        return
+    
+    def getSuperItemRate(self):
+        single = IpyGameDataPY.GetFuncCfg("CrossBattlefieldAwardSuper", 3)
+        return single * len(self.onlinePlayerIDList)
+    def getSuperItemPlayerID(self):
+        if not self.onlinePlayerIDList:
+            return 0
+        return random.choice(self.onlinePlayerIDList)
+    
+    def addScore(self, worldObj, addValue):
+        super(BattleFaction, self).addScore(worldObj, addValue)
+        
+        battleOverScore = IpyGameDataPY.GetFuncCfg("CrossBattlefieldFB", 2)
+        if self.score < battleOverScore:
+            return
+        
+        GameWorld.Log("阵营积分达到获胜积分,获胜! faction=%s,updScore=%s" % (self.faction, self.score), self.fbPropertyID)
+        tick = GameWorld.GetGameWorld().GetTick()
+        DoOver(self.faction, tick)
+        return
+    
+## 战场玩家类
+class BattlePlayer(BattleBase):
+    
+    def __init__(self, playerID):
+        super(BattlePlayer, self).__init__(playerID)
+        self.battleType = self.BattleType_Player
+        self.faction = 0
+        self.accID = ""
+        self.job = 1
+        self.realmLV = 0
+        self.fightPower = 0
+        self.highScoreToday = 0 # 本日最高积分
+        self.highScoreWeekTotal = 0 # 本周每日最高分累计
+        self.enterCountWeek = 0 # 本周累计进入次数
+        self.onlineCalcTick = 0 # 在线统计tick
+        self.onlineTimes = 0 # 活动累计在线时长,毫秒
+        self.setSuperTaskValueMax(None)
+        return
+    
+    def getSuperItemRate(self): return IpyGameDataPY.GetFuncCfg("CrossBattlefieldAwardSuper", 2)
+    def getSuperItemPlayerID(self): return self.ID
+    
+def GetBattleWorld():
+    worldObj = FBCommon.GetGameFBData(GameFBData_BattleWorld)
+    if not worldObj:
+        worldObj = BattleWorld()
+        FBCommon.SetGameFBData(GameFBData_BattleWorld, worldObj)
+    return worldObj
+
+def GetBattleFactionObj(faction):
+    factionObj = None
+    factionInfoDict = FBCommon.GetGameFBData(GameFBData_FactionInfo)
+    if faction in factionInfoDict:
+        factionObj = factionInfoDict[faction]
+    else:        
+        factionObj = BattleFaction(faction)
+        factionInfoDict[faction] = factionObj
+    return factionObj
+
+def GetBattlePlayerObj(playerID):
+    playerObj = None
+    playerInfoDict = FBCommon.GetGameFBData(GameFBData_PlayerInfo)
+    if playerID in playerInfoDict:
+        playerObj = playerInfoDict[playerID]
+    else:        
+        playerObj = BattlePlayer(playerID)
+        playerInfoDict[playerID] = playerObj
+    return playerObj
+    
+def GetBFStepTime(): return IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldFB", 1) # 阶段时间
+
+def OnOpenFB(tick):
+    #fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    FBCommon.SetGameFBData(GameFBData_BattleWorld, None)
+    FBCommon.SetGameFBData(GameFBData_FactionInfo, {})
+    FBCommon.SetGameFBData(GameFBData_PlayerInfo, {})
+    
+    GetBattleWorld()
+    GetBattleFactionObj(ShareDefine.CampType_Justice)
+    GetBattleFactionObj(ShareDefine.CampType_Evil)
+    
+    FBCommon.SetFBStep(FB_Step_Prepare, tick)
+    return
+
+def OnCloseFB(tick):
+    GameWorld.GetGameWorld().SetPropertyID(0)
+    FBCommon.SetGameFBData(GameFBData_BattleWorld, None)
+    FBCommon.SetGameFBData(GameFBData_FactionInfo, None)
+    FBCommon.SetGameFBData(GameFBData_PlayerInfo, None)
+    return
+
+def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
+    if GameWorld.IsCrossServer():
+        return True
+    
+    playerID = curPlayer.GetPlayerID()
+    hmNum = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield)
+    for zoneID, hmCallTeamInfo in PyGameData.g_crossBattlefieldCallTeamInfo.items():
+        callTeamInfo = hmCallTeamInfo.get(hmNum, {})
+        for buyPlayerID, callTeam in callTeamInfo.items():
+            if playerID in callTeam["callPlayerIDList"]:
+                GameWorld.DebugLog("    在战场召集队伍里,免费进入! zoneID=%s,hmNum=%s,buyPlayerID=%s,callPlayerIDList=%s" 
+                                   % (zoneID, hmNum, buyPlayerID, callTeam["callPlayerIDList"]), playerID)
+                return True
+            
+    remainCnt = PlayerActivity.GetDailyActionrRemainCnt(curPlayer, ShareDefine.DailyActionID_CrossBattlefield)
+    GameWorld.DebugLog("    战场剩余可进入次数! hmNum=%s,remainCnt=%s" % (hmNum, remainCnt), playerID)
+    return remainCnt > 0
+
+def OnChangeMapAsk(ask, tick):
+    return IPY_GameWorld.cmeAccept
+
+##副本玩家进入点, 玩家分散在半径3格范围
+def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
+    return random.choice(IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldPos", 1))
+
+def DoEnterFB(curPlayer, tick):    
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    playerID = curPlayer.GetPlayerID()
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    
+    if fbStep not in [FB_Step_Prepare, FB_Step_Fighting]:
+        GameWorld.Log("DoEnterFB... fbPropertyID=%s,fbStep=%s PlayerLeaveFB" % (fbPropertyID, fbStep), playerID)
+        PlayerControl.PlayerLeaveFB(curPlayer)
+        return
+    
+    fightPower = PlayerControl.GetFightPower(curPlayer)
+    battleObj = GetBattlePlayerObj(playerID)
+    battleObj.job = curPlayer.GetJob()
+    battleObj.accID = curPlayer.GetAccID()
+    battleObj.name = curPlayer.GetPlayerName()
+    battleObj.realmLV = curPlayer.GetOfficialRank()
+    battleObj.fightPower = fightPower
+    battleObj.highScoreToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_HighScoreToday)
+    battleObj.highScoreWeekTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_HighScoreTotalWeek)
+    battleObj.enterCountWeek = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_EnterCountWeek)
+    
+    GameWorld.Log("DoEnterFB... fbPropertyID=%s,fbStep=%s,faction=%s" % (fbPropertyID, fbStep, battleObj.faction), playerID)
+    
+    if fbStep == FB_Step_Prepare:
+        notify_tick = GetBFStepTime()[Time_Prepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True)
+        
+    elif fbStep == FB_Step_Fighting:
+        notify_tick = GetBFStepTime()[Time_Fight] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True)
+        isToSafePos = not battleObj.faction
+        allotPlayerFaction(playerID, fightPower, curPlayer, isToSafePos, tick)
+        
+    return
+
+##获得副本帮助信息, 用于通知阵营比分条
+def DoFBHelp(curPlayer, tick):
+    #gameWorld = GameWorld.GetGameWorld()
+    playerID = curPlayer.GetPlayerID()
+    
+    worldObj = GetBattleWorld()
+    battleObj = GetBattlePlayerObj(playerID)
+        
+    playerInfo = {"score":battleObj.score, "superTaskValue":battleObj.superTaskValue, 
+                  "superTaskValueMax":battleObj.superTaskValueMax, "superTaskFinishCount":battleObj.superTaskFinishCount}
+    
+    factionInfo = {}
+    for faction in [ShareDefine.CampType_Justice, ShareDefine.CampType_Evil]:
+        factionObj = GetBattleFactionObj(faction)
+        factionInfo[str(faction)] = {"score":factionObj.score, "superTaskValue":factionObj.superTaskValue, 
+                                     "superTaskValueMax":factionObj.superTaskValueMax, "superTaskFinishCount":factionObj.superTaskFinishCount}
+    
+    worldInfo = {"superTaskType":worldObj.superTaskType, "superItemPlayerName":worldObj.superItemPlayerName, "superItemInfo":worldObj.superItemInfo}
+    
+    helpDict = {"playerInfo":playerInfo, "factionInfo":factionInfo, "worldInfo":worldInfo}
+    #GameWorld.DebugLog("DoFBHelp %s" % helpDict, playerID)
+    FBCommon.Notify_FBHelp(curPlayer, helpDict)
+    return
+
+##玩家退出副本
+def DoExitFB(curPlayer, tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    if fbStep != FB_Step_Fighting:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    faction = curPlayer.GetFaction()
+    fightPower = PlayerControl.GetFightPower(curPlayer)
+    
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    GameWorld.Log("DoExitFB... playerID=%s,faction=%s,fightPower=%s,fbStep=%s" 
+                  % (playerID, faction, fightPower, fbStep), fbPropertyID)
+    
+    battleObj = GetBattlePlayerObj(playerID)
+    battleObj.onlineCalcTick = 0
+    
+    if not faction:
+        return
+    
+    factionObj = GetBattleFactionObj(faction)
+    factionObj.onlineFightPowerTotal = max(0, factionObj.onlineFightPowerTotal - fightPower)
+    if playerID in factionObj.onlinePlayerIDList:
+        factionObj.onlinePlayerIDList.remove(playerID)
+        
+    GameWorld.Log("    faction=%s,onlineFightPowerTotal=%s,onlinePlayerIDList=%s" 
+                  % (faction, factionObj.onlineFightPowerTotal, factionObj.onlinePlayerIDList), fbPropertyID)
+    return
+
+##玩家主动离开副本.
+def DoPlayerLeaveFB(curPlayer, tick):
+    return
+
+##副本总逻辑计时器
+# @param tick 时间戳
+# @return 无意义
+# @remarks 副本总逻辑计时器
+def OnProcess(tick):
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    
+    # 副本准备
+    if fbStep == FB_Step_Prepare:
+        __DoLogic_FB_Prepare(tick)
+        
+    # 副本进行中
+    elif fbStep == FB_Step_Fighting:
+        __DoLogic_FB_Fighting(tick)
+        
+    # 副本结束
+    elif fbStep == FB_Step_LeaveTime:
+        __DoLogic_FB_Over(tick)
+        
+    return
+
+def __DoLogic_FB_Prepare(tick):
+    
+    remaindTick = GetBFStepTime()[Time_Prepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+    if remaindTick > 0:
+        return
+    
+    FBCommon.SetFBStep(FB_Step_Fighting, tick)
+    
+    playerInfoDict = {}
+    playerInfoList = []
+    fightTime = GetBFStepTime()[Time_Fight] * 1000
+    playerManager = GameWorld.GetMapCopyPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        playerID = curPlayer.GetPlayerID()
+        if not playerID:
+            continue
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, fightTime, True)
+        
+        fightPower = PlayerControl.GetFightPower(curPlayer)
+        
+        playerInfo = {"playerID":playerID, "fightPower":fightPower, "curPlayer":curPlayer}
+        playerInfoList.append(playerInfo)
+        playerInfoDict[playerID] = playerInfo
+        
+#    ##--------- 山寨分配测试代码 --------------
+#    for i in xrange(15):
+#        playerID = i + 1
+#        fightPower = random.randint(100000, 10000000000)
+#        playerInfoList.append({"playerID":playerID, "fightPower":fightPower, "curPlayer":None})
+#    ##--------- 山寨分配测试代码 --------------
+    
+    # 按战力排序
+    # 当超过副本下限人数时,往人数低的阵营划分; 否则 往战力低的阵营划分
+    playerInfoList.sort(key=operator.itemgetter("fightPower"), reverse=True)
+    
+    isToSafePos = True
+    
+    # 先分配召集队伍
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    zoneID = FBCommon.GetCrossDynamicLineMapZoneID()
+    hmNum = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield)
+    hmCallTeamInfo = PyGameData.g_crossBattlefieldCallTeamInfo.get(zoneID, {})
+    callTeamInfo = hmCallTeamInfo.get(hmNum, {})
+    
+    GameWorld.Log("准备开始战斗,分配阵营: zoneID=%s,hmNum=%s,callTeamInfo=%s,playerCountTotal=%s" % (zoneID, hmNum, callTeamInfo, len(playerInfoList)), fbPropertyID)
+    callPlayerIDList = []
+    for callTeam in callTeamInfo.values():
+        for playerID in callTeam["callPlayerIDList"]:
+            callPlayerIDList.append(playerID)
+            if playerID not in playerInfoDict:
+                continue
+            playerInfo = playerInfoDict[playerID]
+            playerID = playerInfo["playerID"]
+            fightPower = playerInfo["fightPower"]
+            curPlayer = playerInfo["curPlayer"]
+            allotPlayerFaction(playerID, fightPower, curPlayer, isToSafePos, tick)
+            
+    for playerInfo in playerInfoList:
+        playerID = playerInfo["playerID"]
+        fightPower = playerInfo["fightPower"]
+        curPlayer = playerInfo["curPlayer"]
+        if playerID in callPlayerIDList:
+            continue
+        allotPlayerFaction(playerID, fightPower, curPlayer, isToSafePos, tick)
+        
+    return
+
+def allotPlayerFaction(playerID, fightPower, curPlayer, isToSafePos, tick):
+    ## 分配玩家阵营
+    
+    zoneID = FBCommon.GetCrossDynamicLineMapZoneID()
+    hmNum = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield)
+    hmCallTeamInfo = PyGameData.g_crossBattlefieldCallTeamInfo.get(zoneID, {})
+    callTeamInfo = hmCallTeamInfo.get(hmNum, {})
+    
+    callFaction = None
+    for callTeam in callTeamInfo.values():
+        if playerID in callTeam["callPlayerIDList"]:
+            callFaction = callTeam["factionID"]
+            break
+            
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    battleObj = GetBattlePlayerObj(playerID)
+    faction = battleObj.faction
+    if callFaction:
+        faction = callFaction # 召集阵营为固定阵营
+        
+    if not faction:
+        jFactionObj = GetBattleFactionObj(ShareDefine.CampType_Justice)
+        eFactionObj = GetBattleFactionObj(ShareDefine.CampType_Evil)
+        
+        onlinePlayerTotal = len(jFactionObj.onlinePlayerIDList) + len(eFactionObj.onlinePlayerIDList)
+        fbPlayerCountSet = IpyGameDataPY.GetFuncCfg("CrossBattlefieldFB", 3) # 副本下限人数设定
+        
+        # 当超过副本下限人数时,往人数低的阵营划分; 否则 往战力低的阵营划分
+        if onlinePlayerTotal > fbPlayerCountSet:
+            faction = ShareDefine.CampType_Justice if len(jFactionObj.onlinePlayerIDList) <= len(eFactionObj.onlinePlayerIDList) else ShareDefine.CampType_Evil
+        else:
+            faction = ShareDefine.CampType_Justice if jFactionObj.onlineFightPowerTotal <= eFactionObj.onlineFightPowerTotal else ShareDefine.CampType_Evil
+            
+    battleObj.faction = faction
+    battleObj.onlineCalcTick = tick
+    
+    factionObj = GetBattleFactionObj(faction)
+    
+    if playerID not in factionObj.factionPlayerDict:
+        factionObj.factionPlayerDict[playerID] = battleObj
+        
+    # 在线才会添加,所以处理在线相关
+    factionObj.onlineFightPowerTotal += fightPower
+    if playerID not in factionObj.onlinePlayerIDList:
+        factionObj.onlinePlayerIDList.append(playerID)
+        
+    GameWorld.Log("    分配阵营: callFaction=%s,faction=%s,playerID=%s,fightPower=%s,onlineFightPowerTotal=%s,onlinePlayerIDList=%s,isToSafePos=%s" 
+                  % (callFaction, faction, playerID, fightPower, factionObj.onlineFightPowerTotal, factionObj.onlinePlayerIDList, isToSafePos), fbPropertyID)
+    
+    if curPlayer:
+        curPlayer.SetFaction(faction)
+        if isToSafePos:
+            __RandFactionSafeArea(curPlayer)
+            
+    return
+
+## 重置副本复活玩家坐标点
+def OnResetFBRebornPlacePos(curPlayer, rebornPlace, tick):
+    __RandFactionSafeArea(curPlayer)
+    return
+
+def __RandFactionSafeArea(curPlayer):
+    faction = curPlayer.GetFaction()
+    factionSafeAreaRandPosList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldPos", 2)
+    if faction and faction <= len(factionSafeAreaRandPosList):
+        safePosX, safePosY, radius = random.choice(factionSafeAreaRandPosList[faction - 1])
+        posPoint = GameMap.GetEmptyPlaceInArea(safePosX, safePosY, radius)
+        posX, posY = posPoint.GetPosX(), posPoint.GetPosY()
+    else:
+        posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
+    curPlayer.ResetPos(posX, posY)
+    return
+
+def __DoLogic_FB_Fighting(tick):
+    
+    remaindTick = GetBFStepTime()[Time_Fight] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+    if remaindTick > 0:
+        FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 5000, refreshFactionPlayer)
+        return
+    
+    jFactionObj = GetBattleFactionObj(ShareDefine.CampType_Justice)
+    eFactionObj = GetBattleFactionObj(ShareDefine.CampType_Evil)
+    jFactionScore = jFactionObj.score
+    eFactionScore = eFactionObj.score
+    
+    winnerFaction = ShareDefine.CampType_Justice if jFactionScore >= eFactionScore else ShareDefine.CampType_Evil
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    GameWorld.Log("副本时间到,积分高的阵营获胜! winnerFaction=%s,jFactionScore=%s,eFactionScore=%s" 
+                  % (winnerFaction, jFactionScore, eFactionScore), fbPropertyID)
+    DoOver(winnerFaction, tick)
+    return
+
+def __DoLogic_FB_Over(tick):
+    remaindTick = GetBFStepTime()[Time_Leave] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+    if remaindTick > 0:
+        return
+    
+    GameWorldProcess.CloseFB(tick)
+    FBCommon.SetFBStep(FB_Step_Over, tick)
+    return
+
+##处理副本中杀死玩家逻辑
+def DoFBOnKill_Player(curPlayer, defender, tick):
+    playerID = curPlayer.GetPlayerID()
+    tagPlayerID = defender.GetPlayerID()
+    faction = curPlayer.GetFaction()
+    tagFaction = defender.GetFaction()
+    curBattleObj = GetBattlePlayerObj(playerID)
+    tagBattleObj = GetBattlePlayerObj(tagPlayerID)
+    if not faction or not tagFaction:
+        GameWorld.ErrLog("击杀玩家没有阵营! playerID=%s,faction=%s,tagPlayerID=%s,tagFaction=%s" 
+                         % (playerID, faction, tagPlayerID, tagFaction), playerID)
+        return
+    
+    worldObj = GetBattleWorld()
+    curFactionObj = GetBattleFactionObj(faction)
+    tagFactionObj = GetBattleFactionObj(tagFaction)
+        
+    GameWorld.DebugLog("击杀玩家! playerID=%s,faction=%s,tagPlayerID=%s,tagFaction=%s" 
+                       % (playerID, faction, tagPlayerID, tagFaction), playerID)
+    
+    # 1. 处理玩家
+    killPlayerScore = IpyGameDataPY.GetFuncCfg("CrossBattlefieldKill", 1)
+    addPlayerScore = 0
+    addPlayerScore += killPlayerScore
+    #addPlayerScore += ... # 其他加分
+    curBattleObj.addScore(worldObj, addPlayerScore)
+    curBattleObj.addKillCount(worldObj, 1)
+    tagBattleObj.addBeKilledCount(1)
+    
+    # 2. 处理阵营
+    addFactionScore = 0
+    addFactionScore += addPlayerScore # 阵营积分同步增加玩家得分
+    # 击杀积分王,阵营积分额外增加
+    for index, kingID in enumerate(tagFactionObj.scoreKingIDList):
+        if kingID == tagPlayerID:
+            killScoreKingScoreList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldScoreKing", 3)
+            if index < len(killScoreKingScoreList):
+                kingScore = killScoreKingScoreList[index]
+                addFactionScore += kingScore
+                GameWorld.DebugLog("    对方是积分王,阵营额外获得积分:  index=%s,kingScore=%s" % (index, kingScore), playerID)
+                
+            killScoreKingNotifyList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldScoreKing", 4)
+            if index < len(killScoreKingNotifyList):
+                msgMark = killScoreKingNotifyList[index]
+                defMapID = defender.GetMapID()
+                defPosX = defender.GetPosX()
+                defPosY = defender.GetPosY()
+                PlayerControl.FBNotify(msgMark, [faction, curPlayer.GetPlayerName(), tagFaction, defender.GetPlayerName(), defMapID, defPosX, defPosY])
+                
+            break
+    #addFactionScore += ... # 其他加分
+    curFactionObj.addScore(worldObj, addFactionScore)
+    curFactionObj.addKillCount(worldObj, 1)
+    tagFactionObj.addBeKilledCount(1)
+    return True
+
+def refreshFactionPlayer(tick):
+    ## 刷新阵营玩家相关
+    
+    scoreKingScoreMin = IpyGameDataPY.GetFuncCfg("CrossBattlefieldScoreKing", 1)
+    scoreKingBuffIDList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldScoreKing", 2)
+    scoreKingCount = len(scoreKingBuffIDList)
+    
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    for faction in [ShareDefine.CampType_Justice, ShareDefine.CampType_Evil]:
+        factionObj = GetBattleFactionObj(faction)
+        
+        befKingIDList = factionObj.scoreKingIDList
+        
+        factionObj.battlePlayerSortList = factionObj.factionPlayerDict.values()
+        factionObj.battlePlayerSortList.sort(key=operator.attrgetter("score", "scoreSortTime"), reverse=True)
+        
+        aftKingIDList = []
+        aftKingObjList = []
+        for batObj in factionObj.battlePlayerSortList:
+            playerID = batObj.ID
+            curPlayer = copyMapMgr.FindPlayerByID(playerID)
+            if not curPlayer:
+                continue
+            
+            if batObj.onlineCalcTick:
+                batObj.onlineTimes += max(0, tick - batObj.onlineCalcTick)
+                batObj.onlineCalcTick = tick
+                
+            if batObj.score < scoreKingScoreMin:
+                continue
+            
+            if len(aftKingIDList) < scoreKingCount:
+                aftKingIDList.append(playerID)
+                aftKingObjList.append([curPlayer, batObj])
+                
+        if befKingIDList == aftKingIDList:
+            #GameWorld.DebugLog("    阵营积分王不变: faction=%s,befKingIDList=%s,aftKingIDList=%s" % (faction, befKingIDList, aftKingIDList))
+            continue
+        
+        GameWorld.DebugLog("    阵营积分王变更: faction=%s,befKingIDList=%s,aftKingIDList=%s" % (faction, befKingIDList, aftKingIDList))
+        
+        # 更新buff
+        for index, objInfo in enumerate(aftKingObjList):
+            curPlayer, batObj = objInfo
+            
+            playerID = curPlayer.GetPlayerID()
+            
+            addBuffID = scoreKingBuffIDList[index] if index < len(scoreKingBuffIDList) else 0
+            
+            if playerID in befKingIDList:
+                befIndex = befKingIDList.index(playerID)
+                if index == befIndex:
+                    GameWorld.DebugLog("        积分王名次不变,不需要变更buff! index=%s" % index, playerID)
+                    continue
+                delBuffID = scoreKingBuffIDList[befIndex] if befIndex < len(scoreKingBuffIDList) else 0
+                if delBuffID:
+                    GameWorld.DebugLog("        积分王名次变更! 删除旧buff! befIndex=%s,delBuffID=%s" % (befIndex, delBuffID), playerID)
+                    BuffSkill.DelBuffBySkillID(curPlayer, delBuffID, tick)
+                    
+            if addBuffID:
+                GameWorld.DebugLog("        积分王名次变更! 添加新buff! index=%s,addBuffID=%s" % (index, addBuffID), playerID)
+                SkillCommon.AddBuffBySkillType_NoRefurbish(curPlayer, addBuffID, tick)
+                
+        for befIndex, playerID in enumerate(befKingIDList):
+            if playerID in aftKingIDList:
+                continue
+            delBuffID = scoreKingBuffIDList[befIndex] if befIndex < len(scoreKingBuffIDList) else 0
+            if delBuffID:
+                GameWorld.DebugLog("        积分王被挤掉! 删除旧buff! befIndex=%s,delBuffID=%s" % (befIndex, delBuffID), playerID)
+                BuffSkill.DelBuffBySkillID(curPlayer, delBuffID, tick)
+                
+        factionObj.scoreKingIDList = aftKingIDList
+        
+    return
+
+def DoOver(winnerFaction, tick):
+    fbPropertyID = GameWorld.GetGameWorld().GetPropertyID()
+    zoneID = FBCommon.GetCrossDynamicLineMapZoneID()
+    funcLineID = FBCommon.GetCrossDynamicLineMapFuncLineID()
+    GameWorld.Log("跨服战场结算! zoneID=%s,funcLineID=%s,winnerFaction=%s" % (zoneID, funcLineID, winnerFaction), fbPropertyID)
+    
+    FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0, refreshFactionPlayer) # 结算前强刷一次
+    
+    #awardOnlineTimes = IpyGameDataPY.GetFuncCfg("CrossBattlefieldAward", 1) # 结算奖励需参与活动时长,秒钟
+    
+    #gameFB = GameWorld.GetGameFB()
+    worldObj = GetBattleWorld()
+    leaveTime = GetBFStepTime()[Time_Leave] * 1000
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    
+    superItemPlayerID = worldObj.superItemPlayerID
+    superItemPlayerName = worldObj.superItemPlayerName
+    # 没人中奖则随机给其中一位在线的玩家
+    if not superItemPlayerID:
+        onlinePlayerIDList = []
+        for index in xrange(copyMapMgr.GetPlayerCount()):
+            curPlayer = copyMapMgr.GetPlayerByIndex(index)
+            playerID = curPlayer.GetPlayerID()
+            if not playerID:
+                continue
+            onlinePlayerIDList.append(playerID)
+        if onlinePlayerIDList:
+            superItemPlayerID = random.choice(onlinePlayerIDList)
+            superPlayerObj = GetBattlePlayerObj(superItemPlayerID)
+            superItemPlayerName = superPlayerObj.name
+            worldObj.superItemPlayerID = superItemPlayerID
+            worldObj.superItemPlayerName = superItemPlayerName
+            GameWorld.Log("没人中大奖,则随机其中一位在线玩家! superItemPlayerID=%s,onlinePlayerIDList=%s" 
+                          % (superItemPlayerID, onlinePlayerIDList), fbPropertyID)
+            
+    GameWorld.Log("大奖获奖信息: superItemInfo=%s,superItemPlayerID=%s" % (worldObj.superItemInfo, superItemPlayerID), fbPropertyID)
+    
+    hmNum = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossBattlefield)
+    hmCallTeamInfo = PyGameData.g_crossBattlefieldCallTeamInfo.get(zoneID, {})
+    callTeamInfo = hmCallTeamInfo.get(hmNum, {})
+    allCallPlayerIDList = []
+    for callTeam in callTeamInfo.values():
+        allCallPlayerIDList.extend(callTeam["callPlayerIDList"])
+        
+    scoreKingID, scoreKingName = 0, "" # 本场积分王: 获胜方在线第一名积分
+    battlePlayerList = []
+    for faction in [ShareDefine.CampType_Justice, ShareDefine.CampType_Evil]:
+        factionObj = GetBattleFactionObj(faction)
+        factionScore = factionObj.score
+        isWinner = (faction == winnerFaction)
+        scoreKingIDList = factionObj.scoreKingIDList
+        GameWorld.Log("结算阵营! faction=%s,factionScore=%s,isWinner=%s,playerCount=%s,onlineFightPowerTotal=%s,onlinePlayerIDList=%s,scoreKingIDList=%s" 
+                      % (faction, factionScore, isWinner, len(factionObj.battlePlayerSortList), factionObj.onlineFightPowerTotal, factionObj.onlinePlayerIDList, scoreKingIDList), fbPropertyID)
+        if isWinner and scoreKingIDList:
+            scoreKingID = scoreKingIDList[0]
+            scoreKingObj = GetBattlePlayerObj(scoreKingID)
+            scoreKingName = scoreKingObj.name
+            
+        rankPlayerList = []
+        for battleObj in factionObj.battlePlayerSortList[:20]:
+            rankPlayerList.append({"Name":battleObj.name, "Job":battleObj.job, "Score":battleObj.score})
+            
+        overDict = {"rankPlayerList":rankPlayerList, "faction":faction, "superItemPlayerName":superItemPlayerName, "scoreKingName":scoreKingName}
+        for rank, battleObj in enumerate(factionObj.battlePlayerSortList, 1):
+            playerID = battleObj.ID
+            score = battleObj.score
+            job = battleObj.job
+            realmLV = battleObj.realmLV
+            name = battleObj.name
+            highScoreToday = battleObj.highScoreToday
+            highScoreWeekTotal = battleObj.highScoreWeekTotal
+            enterCountWeek = battleObj.enterCountWeek
+            onlineTimes = battleObj.onlineTimes / 1000
+            GameWorld.Log("     rank=%s,playerID=%s,score=%s,fightPower=%s,onlineTimes=%s,accID=%s" 
+                          % (rank, playerID, score, battleObj.fightPower, onlineTimes, battleObj.accID), fbPropertyID)
+            
+            #服务端暂不做参与时长奖励限制
+            #if onlineTimes < awardOnlineTimes:
+            #    GameWorld.Log("    活动时长不足,不给奖励! faction=%s,playerID=%s,isWinner=%s" % (faction, playerID, isWinner), fbPropertyID)
+            #    continue
+            
+            isCallEnter = 1 if playerID in allCallPlayerIDList else 0 # 是否召集进入的
+            playerInfo = [faction, rank, playerID, job, realmLV, name, score, highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter]
+            battlePlayerList.append(playerInfo)
+            
+            player = copyMapMgr.FindPlayerByID(playerID)
+            if not player:
+                continue
+            player.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, leaveTime, True)
+            
+            lineID = 0
+            overDict.update({FBCommon.Over_rank:rank, "score":score, "highScoreToday":highScoreToday, "onlineTimes":onlineTimes})
+            FBCommon.NotifyFBOver(player, ChConfig.Def_FBMapID_CrossBattlefield, lineID, isWinner, overDict)
+            
+    GameWorld.Log("本场最终结算积分王: scoreKingID=%s" % scoreKingID, fbPropertyID)
+            
+    # 同步GameServer 比赛结果
+    superItemInfo = worldObj.superItemInfo
+    msgInfo = str([fbPropertyID, zoneID, funcLineID, winnerFaction, superItemInfo, superItemPlayerID, superItemPlayerName, scoreKingID, scoreKingName, battlePlayerList])
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossBattlefieldOver", msgInfo, len(msgInfo))
+    
+    FBCommon.SetFBStep(FB_Step_LeaveTime, tick)
+    return
+
+## 执行副本杀怪逻辑
+def DoFB_Player_KillNPC(curPlayer, curNPC, tick):
+    #curNPC.SetDict(ChConfig.Def_NPC_Dict_Faction, 0)
+    npcFaction = NPCCommon.GetFaction(curNPC)
+    if npcFaction:
+        __OnPlayerKillOtherFactionRobot(curPlayer, npcFaction, tick)
+    else:
+        __OnPlayerKillNeutralNPC(curPlayer, curNPC, tick)
+    return
+
+def __OnPlayerKillOtherFactionRobot(curPlayer, npcFaction, tick):
+    ## 玩家击杀其他阵营机器人玩家
+    return
+
+def __OnPlayerKillNeutralNPC(curPlayer, curNPC, tick):
+    ## 玩家击杀中立怪物
+    return
+
+## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
+def CheckCanAttackTagObjInFB(attacker, defender):
+    gameFB = GameWorld.GetGameFB()
+    if gameFB.GetFBStep() != FB_Step_Fighting:
+        return False
+    return True
+
+## 玩家攻击玩家是否有惩罚
+def DoFBAttackHasPunish(atkPlayer, defPlayer):
+    return False
+
+## 是否副本复活
+def OnPlayerReborn():
+    return True
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
index bfea990..2fa2745 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
@@ -184,7 +184,8 @@
     return
 
 def GameServer_DynamicLineMapStateChange(gameWorld, state):
-    if gameWorld.GetMapID() not in ChConfig.Def_CrossDynamicLineMap:
+    mapID = FBCommon.GetRecordMapID(gameWorld.GetMapID())
+    if mapID not in ChConfig.Def_CrossDynamicLineMap:
         return
     
     realMapID, copyMapID = gameWorld.GetRealMapID(), gameWorld.GetCopyMapID()
@@ -620,7 +621,8 @@
         msgInfo = str([gameWorld.GetMapID(), gameWorld.GetLineID(), gameWorld.GetRealMapID(), gameWorld.GetCopyMapID()])
         GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CommMapServerInitOK", msgInfo, len(msgInfo))
         
-    if gameWorld.GetMapID() in ChConfig.Def_CrossDynamicLineMap and gameWorld.GetCopyMapID() == gameWorld.GetGameWorldCount() - 1:
+    dataMapID = FBCommon.GetRecordMapID(gameWorld.GetMapID())
+    if dataMapID in ChConfig.Def_CrossDynamicLineMap and gameWorld.GetCopyMapID() == gameWorld.GetGameWorldCount() - 1:
         msgInfo = str([gameWorld.GetRealMapID(), gameWorld.GetGameWorldCount()])
         GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "DynamicLineMapInitOK", msgInfo, len(msgInfo))
         
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
index 40400c8..5eda952 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -135,7 +135,9 @@
 def SetSuppressFightPower(curNPC, value): return curNPC.SetThunderDef(min(value, ShareDefine.Def_UpperLimit_DWord))
 def GetCommendFightPower(curNPC): return curNPC.GetFireDef() # 火防代表推荐战力
 def GetDropOwnerType(curNPC): return curNPC.GetThunderAtk() # 雷攻代表掉落归属类型
-def GetFaction(curNPC): return curNPC.GetCountry()
+def GetFaction(curNPC):
+    faction = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_Faction)
+    return faction if faction else curNPC.GetCountry()
 def GetSkillAtkRate(curNPC): return curNPC.GetPoisionAtk() # 毒攻代表NPC技能伤害加成万分率
 def GetFinalHurt(curNPC): return curNPC.GetFireAtk() # 火攻代表NPC最终固定伤害加成, 普攻也有效果
 def SetFinalHurt(curNPC, hurt): return curNPC.SetFireAtk(hurt) # 火攻代表NPC最终固定伤害加成, 普攻也有效果
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 827d9b2..f6781a1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -73,6 +73,7 @@
 import PlayerGatherSoul
 import PlayerFairyDomain
 import PlayerCrossRealmPK
+import PlayerCrossBattlefield
 import GameFuncComm
 import PlayerMagicWeapon
 import GameLogic_TrialTower
@@ -713,6 +714,7 @@
     
     # 跨服PK
     PlayerCrossRealmPK.DoPlayerLogin(curPlayer)
+    PlayerCrossBattlefield.DoPlayerLogin(curPlayer)
     
     # 幸运云购
     PlayerLuckyCloudBuy.OnPlayerLogin(curPlayer)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActivity.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActivity.py
index 827fb21..419d510 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActivity.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActivity.py
@@ -82,6 +82,9 @@
             curPBCnt = __GetPDictValue(curPlayer, key)  #单次进度值
             if curPBCnt:
                 __SetPDictValue(curPlayer, key, 0)
+            key = ChConfig.Def_PDict_Activity_AddTotal % ipyData.GetID()
+            if __GetPDictValue(curPlayer, key):
+                __SetPDictValue(curPlayer, key, 0)
         #总活跃度重置
         __SetPDictValue(curPlayer, ChConfig.Def_PDict_Activity_TotalPoint, 0)
         # 重置领奖记录
@@ -238,10 +241,18 @@
     onceActivityTime = dailyQuestData.GetOnceActivityTime()
     if not onceActivity:
         return
-    if maxActiveValue and finishCnt > maxActiveValue / onceActivity * onceActivityTime:
-        #GameWorld.DebugLog("活跃度可完成次数已达到上限,activityNum=%s" % (activityNum))
-        return
-    
+    curAddTotal = None
+    if maxActiveValue:
+        if dailyQuestData.GetRelatedType() == RelatedType_1 and dailyQuestData.GetRelatedID() in [ShareDefine.DailyActionID_CrossBattlefield]:
+            curAddTotal = __GetPDictValue(curPlayer, ChConfig.Def_PDict_Activity_AddTotal % activityNum)  #单次进度值
+            if curAddTotal >= maxActiveValue:
+                GameWorld.DebugLog("活跃度可完成次数已达到上限,activityNum=%s,curAddTotal=%s >= %s" % (activityNum, curAddTotal, maxActiveValue))
+                return
+        else:
+            if finishCnt > maxActiveValue / onceActivity * onceActivityTime:
+                #GameWorld.DebugLog("活跃度可完成次数已达到上限,activityNum=%s" % (activityNum))
+                return
+            
     key = ChConfig.Def_PDict_Activity_FinishCnt % activityNum
     curPBCnt = __GetPDictValue(curPlayer, key)  #单次进度值
     
@@ -250,6 +261,10 @@
     
     __SetPDictValue(curPlayer, key, addPbCnt)
     
+    if curAddTotal != None:
+        curAddTotal += addValue
+        __SetPDictValue(curPlayer, ChConfig.Def_PDict_Activity_AddTotal % activityNum, curAddTotal)
+        
     #
     DoAddActivity(curPlayer, addValue, True)
     return
@@ -476,7 +491,7 @@
     
     # 由GameServer决定
     # 目前跨服PK暂不需要判断,因为跨服PK次数结算在本服,玩家可能上次未结算离线,等非匹配期间上线,也需要加上,所以暂不判断
-    if dailyID not in [ShareDefine.DailyActionID_CrossReamPK]:
+    if dailyID not in [ShareDefine.DailyActionID_CrossReamPK, ShareDefine.DailyActionID_CrossBattlefield]:
         if not GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_DailyActionState % dailyID):
             GameWorld.DebugLog("日常活动未开启!dailyID=%s" % dailyID)
             return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index 575ba44..41301f6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -328,7 +328,7 @@
     return
 
 #---------------------------------------------------------------------
-def SendMailBatch(mailTypeKey, batchPlayerIDList, batchAddItemList=[], batchParamList=[], batchGold=[], batchGoldPaper=[], batchSilver=[], batchDetail=[], moneySource=ChConfig.Def_GiveMoney_Mail):
+def SendMailBatch(mailTypeKey, batchPlayerIDList, batchAddItemList=[], batchParamList=[], batchGold=[], batchGoldPaper=[], batchSilver=[], batchDetail=[], moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     '''批量发送邮件, 用于瞬间需要发送多封(大量)邮件的,比如一些公共副本活动等结算时
     @param mailTypeKey: 邮件模板key
     @param batchPlayerIDList: [playerIDList, playerIDList, ...]
@@ -352,17 +352,17 @@
                 bGoldPaper = [batchGoldPaper[i]] if len(batchGoldPaper) > i else []
                 bSilver = [batchSilver[i]] if len(batchSilver) > i else []
                 bDetail = [batchDetail[i]] if len(batchDetail) > i else []
-                AddUnLoginOKPlayerMailCache(playerID, "ByMailTemplate", [mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource])
+                AddUnLoginOKPlayerMailCache(playerID, "ByMailTemplate", [mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail])
                 playerIDList.pop(playerIDList.index(playerID))
                 continue
             
-    msgInfo = str([mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource])
+    msgInfo = str([mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource, crossMail])
     GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "SendMailBatch", msgInfo, len(msgInfo))
     GameWorld.Log("SendMailBatch %s, batchPlayerIDList=%s, batchAddItemList=%s, batchParamList=%s, batchGold=%s, batchGoldPaper=%s, batchSilver=%s" 
                   % (mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver))
     return
 
-def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     '''
     @param detail: 记录邮件流向用
     '''
@@ -370,7 +370,7 @@
         mailTypeKey = ShareDefine.DefaultLackSpaceMailType
     
     content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, json.dumps(paramList, ensure_ascii=False))
-    SendMail("", content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource)
+    SendMail("", content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
     return
 
 def SendCrossMail(serverGroupID, mailTypeKey, playerIDList, addItemList, paramList=[]):
@@ -412,7 +412,7 @@
 ## 功能发放物品补偿/奖励邮件
 #  @param addItemList [(itemID, itemCnt, 是否拍品), {或物品信息字典}, ...]
 #  @return
-def SendMail(title, content, getDays, playerIDList, addItemList, gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+def SendMail(title, content, getDays, playerIDList, addItemList, gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     if not playerIDList:
         return
     
@@ -424,7 +424,7 @@
         return
     
     # 跨服服务器不允许发送邮件
-    if GameWorld.IsCrossServer():
+    if GameWorld.IsCrossServer() and not crossMail:
         return
     
     sendPlayerIDList = []
@@ -437,7 +437,7 @@
         sendPlayerIDList.append(playerID)
         
     combineItemList = CombineMailItem(addItemList)
-    cmdList = [title, content, getDays, sendPlayerIDList, combineItemList, gold, goldPaper, silver, detail, moneySource]
+    cmdList = [title, content, getDays, sendPlayerIDList, combineItemList, gold, goldPaper, silver, detail, moneySource, crossMail]
     GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "SendMail", '%s' % (cmdList), len(str(cmdList)))
     return True
 
@@ -476,8 +476,8 @@
             title, content, getDays, addItemList, gold, goldPaper, silver, detail, moneySource = mailInfo
             SendMail(title, content, getDays, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource)
         elif cacheType == "ByMailTemplate":
-            mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource = mailInfo
-            SendMailBatch(mailTypeKey, [playerIDList], bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource)
+            mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail = mailInfo
+            SendMailBatch(mailTypeKey, [playerIDList], bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail)
     return
 
 def CombineMailItem(addItemList):
@@ -1785,7 +1785,10 @@
         
         if not FBLogic.OnEnterFBEvent(curPlayer, mapID, lineID, tick):
             GameWorld.DebugLog("    OnEnterFBEvent False!", curPlayer.GetPlayerID())
-            NotifyCode(curPlayer, "SingleEnterDefaul")
+            if mapID in [ChConfig.Def_FBMapID_CrossBattlefield]:
+                NotifyCode(curPlayer, "GeRen_chenxin_268121")
+            else:
+                NotifyCode(curPlayer, "SingleEnterDefaul")
             return
         
     # 需要动态分布线路的地图,发送到跨服服务器进行分配
@@ -1797,7 +1800,7 @@
                 return
             extendInfo["BossID"] = bossID
             
-        msgDict = {"PlayerID":curPlayer.GetPlayerID(), "MapID":mapID, "FuncLineID":lineID}
+        msgDict = {"PlayerID":curPlayer.GetPlayerID(), "MapID":mapID, "FuncLineID":lineID, "LV":curPlayer.GetLV()}
         if extendInfo:
             msgDict.update(extendInfo)
         GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_EnterFB, msgDict)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossBattlefield.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossBattlefield.py
new file mode 100644
index 0000000..79a64da
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossBattlefield.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerCrossBattlefield
+#
+# @todo:跨服战场
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服战场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+import GameWorld
+import ShareDefine
+import PlayerControl
+import IpyGameDataPY
+import datetime
+import CrossRealmPlayer
+import ChConfig
+import ItemCommon
+import IPY_GameWorld
+import ChPyNetSendPack
+import NetPackCommon
+import ItemControler
+import PlayerActivity
+
+
+def DoPlayerLogin(curPlayer):
+    if GameWorld.IsCrossServer():
+        return
+    SyncCrossBattlefieldPlayerInfo(curPlayer)
+    return
+
+def DoPlayerOnDay(curPlayer):
+    if GameWorld.IsCrossServer():
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_HighScoreToday, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_BuyOpenCountToday, 0)
+    
+    SyncCrossBattlefieldPlayerInfo(curPlayer)
+    return
+
+def DoPlayerOnWeek(curPlayer):
+    if GameWorld.IsCrossServer():
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_EnterCountWeek, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_BuyOpenCountWeek, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_HighScoreTotalWeek, 0)
+    return
+
+#// C1 09 跨服战场购买开启场次 #tagCMCrossBattlefieldBuyOpen
+#
+#struct    tagCMCrossBattlefieldBuyOpen
+#{
+#    tagHead        Head;
+#    BYTE    Hour;        //战场开启时
+#    BYTE    Minute;        //战场开启分
+#    BYTE    Faction;        //阵营 1-红;2-蓝
+#};
+def OnCrossBattlefieldBuyOpen(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    hour = clientData.Hour
+    minute = clientData.Minute
+    faction = clientData.Faction
+    
+    if GameWorld.IsCrossServer():
+        GameWorld.DebugLog("跨服服务器无法发起匹配!", playerID)
+        return
+    
+    if not CrossRealmPlayer.IsCrossServerOpen():
+        PlayerControl.NotifyCode(curPlayer, "CrossMatching18")
+        return
+    
+    if faction not in [ChConfig.CampType_Justice, ChConfig.CampType_Evil]:
+        GameWorld.DebugLog("没有该战场阵营选择! faction=%s" % faction, playerID)
+        return
+    
+    callOpenHMList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldOpen", 2)
+    if [hour, minute] not in callOpenHMList:
+        GameWorld.Log("非可召集的战场场次! hour=%s,minute=%s,callOpenHMList=%s" % (hour, minute, callOpenHMList), playerID)
+        return
+    
+    closeBuyMinute = IpyGameDataPY.GetFuncCfg("CrossBattlefieldOpen", 4) # 开启前X分钟后关闭购买
+    crossServerTimeStr = GameWorld.GetCrossServerTimeStr()
+    crossServerDateTime = GameWorld.ChangeStrToDatetime(crossServerTimeStr)
+    
+    startTimeStr = "%s-%s-%s %s:%s:00" % (crossServerDateTime.year, crossServerDateTime.month, crossServerDateTime.day, hour, minute)
+    startDateTime = GameWorld.ChangeStrToDatetime(startTimeStr)
+    endBuyDateTime = startDateTime + datetime.timedelta(minutes= -closeBuyMinute)
+    if crossServerDateTime >= endBuyDateTime:
+        GameWorld.Log("该时间点战场已关闭召集,不能再召集! hour=%s,minute=%s,crossServerDateTime(%s) >= endBuyDateTime(%s)" 
+                      % (hour, minute, crossServerDateTime, endBuyDateTime), playerID)
+        return
+    
+    moneyBuyMaxCount, moneyType, moneyCount = 0, 0, 0
+    todayBuyOpenCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_BuyOpenCountToday)
+    buyOpenMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBuyOpen", 1)
+    if len(buyOpenMoneyInfo) == 3:
+        moneyBuyMaxCount, moneyType, moneyCount = buyOpenMoneyInfo
+        
+    # 购买消耗货币
+    if todayBuyOpenCount < moneyBuyMaxCount:
+        if not PlayerControl.HaveMoney(curPlayer, moneyType, moneyCount):
+            GameWorld.DebugLog("跨服战场召集开启货币不足! moneyType=%s,moneyCount=%s" % (moneyType, moneyCount), playerID)
+            return
+    else:
+        costItemID = IpyGameDataPY.GetFuncCfg("CrossBattlefieldBuyOpen", 2)
+        costItem = ItemCommon.FindItemInPackByItemID(curPlayer, costItemID, IPY_GameWorld.rptItem)
+        if not ItemCommon.CheckItemCanUse(costItem):
+            GameWorld.DebugLog("跨服战场召集开启道具不足! costItemID=%s" % costItemID, playerID)
+            return
+        
+    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Battlefield, tick):
+        PlayerControl.NotifyCode(curPlayer, "RequestLater")
+        return
+    
+    dataMsg = {"openHour":hour, "openMinute":minute, "faction":faction, "todayBuyOpenCount":todayBuyOpenCount,
+               "accID":curPlayer.GetAccID(),
+               "playerID":playerID,
+               "playerName":CrossRealmPlayer.GetCrossPlayerName(curPlayer),
+               "playerJob":curPlayer.GetJob(),
+               "playerLV":curPlayer.GetLV(),
+               "realmLV":curPlayer.GetOfficialRank(),
+               "fightPower":PlayerControl.GetFightPower(curPlayer),
+               "buyOpenCountWeek":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_BuyOpenCountWeek)
+               }
+    GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_BattlefieldBuyOpen, dataMsg)
+    return
+
+def GameServer_CrossBattlefield_DoResult(curPlayer, msgData):
+    msgType, dataMsg = msgData[:2]
+    #ret = msgData[2] if len(msgData) > 2 else None
+    
+    ## 战场购买开启场次 
+    if msgType == "BattlefieldBuy":
+        __DoBattlefieldBuy(curPlayer, dataMsg)
+                
+    elif msgType == "BattlefieldOver":
+        __DoBattlefieldOver(curPlayer, dataMsg)
+        
+    return
+
+def __DoBattlefieldBuy(curPlayer, dataMsg):
+    
+    playerID = curPlayer.GetPlayerID()
+    openHour, openMinute, faction, todayBuyOpenCount, buyTime = dataMsg
+    updTodayBuyOpenCount, updWeekBuyOpenCount = 0, 0
+    
+    isToday = GameWorld.CheckTimeIsSameServerDayEx(buyTime)
+    if isToday:
+        todayBuyOpenCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_BuyOpenCountToday)
+        updTodayBuyOpenCount = todayBuyOpenCount + 1
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_BuyOpenCountToday, updTodayBuyOpenCount)
+        SyncCrossBattlefieldPlayerInfo(curPlayer)
+        
+    isSameWeek = GameWorld.CheckTimeIsSameWeek(buyTime)
+    if isSameWeek:
+        weekBuyOpenCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_BuyOpenCountWeek)
+        updWeekBuyOpenCount = weekBuyOpenCount + 1
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_BuyOpenCountWeek, updWeekBuyOpenCount)
+        
+    GameWorld.Log("购买召集跨服战场结果: openHour=%s,openMinute=%s,faction=%s,updTodayBuyOpenCount=%s,updWeekBuyOpenCount=%s,buyTime=%s,isToday=%s,isSameWeek=%s" 
+                  % (openHour, openMinute, faction, updTodayBuyOpenCount, updWeekBuyOpenCount, GameWorld.ChangeTimeNumToStr(buyTime), isToday, isSameWeek), playerID)
+    
+    moneyBuyMaxCount, moneyType, moneyCount = 0, 0, 0
+    buyOpenMoneyInfo = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBuyOpen", 1)
+    if len(buyOpenMoneyInfo) == 3:
+        moneyBuyMaxCount, moneyType, moneyCount = buyOpenMoneyInfo
+        
+    infoDict = {ChConfig.Def_Cost_Reason_SonKey:"BattlefieldBuyOpen", "buyTime":buyTime, "isToday":isToday, "isSameWeek":isSameWeek, 
+                "updTodayBuyOpenCount":updTodayBuyOpenCount, "updWeekBuyOpenCount":updWeekBuyOpenCount}
+    # 购买消耗货币
+    if todayBuyOpenCount < moneyBuyMaxCount:
+        if not PlayerControl.PayMoney(curPlayer, moneyType, moneyCount, ChConfig.Def_Cost_CrossBattlefield, infoDict):
+            return
+    else:
+        costItemID = IpyGameDataPY.GetFuncCfg("CrossBattlefieldBuyOpen", 2)
+        costItem = ItemCommon.FindItemInPackByItemID(curPlayer, costItemID, IPY_GameWorld.rptItem)
+        if not ItemCommon.CheckItemCanUse(costItem):
+            costItem = ItemCommon.FindItemInPackByItemID(curPlayer, costItemID, IPY_GameWorld.rptWarehouse)
+        if not ItemCommon.CheckItemCanUse(costItem):
+            return
+        ItemCommon.DelItem(curPlayer, costItem, 1, True, "CrossBattlefield", infoDict)
+        
+    # 固定礼包
+    buyAwardItemList = IpyGameDataPY.GetFuncEvalCfg("CrossBattlefieldBuyOpen", 3)
+    ItemControler.GivePlayerItemOrMail(curPlayer, buyAwardItemList)
+    return
+
+def __DoBattlefieldOver(curPlayer, dataMsg):
+    
+    playerID = curPlayer.GetPlayerID()
+    overTime, highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter = dataMsg
+            
+    isToday = GameWorld.CheckTimeIsSameServerDayEx(overTime)
+    isSameWeek = GameWorld.CheckTimeIsSameWeek(overTime)
+    GameWorld.Log("跨服战场结算玩家结果: highScoreToday=%s,highScoreWeekTotal=%s,enterCountWeek=%s,isCallEnter=%s,overTime=%s,isToday=%s,isSameWeek=%s" 
+                  % (highScoreToday, highScoreWeekTotal, enterCountWeek, isCallEnter, GameWorld.ChangeTimeNumToStr(overTime), isToday, isSameWeek), playerID)
+    
+    if isToday:
+        addCnt = 1
+        # 非召集进入的需要增加日常次数
+        if not isCallEnter:
+            PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_CrossBattlefield, addCnt)
+        # 召集进入由于是免费进入,不许要增加日常次数,直接增加日常活跃
+        else:
+            activityNum = PlayerActivity.GetActivityNum(PlayerActivity.RelatedType_1, ShareDefine.DailyActionID_CrossBattlefield)
+            PlayerActivity.AddActivityFinishCnt(curPlayer, activityNum, None, addCnt)
+            
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_HighScoreToday, highScoreToday)
+        SyncCrossBattlefieldPlayerInfo(curPlayer)
+        
+    if isSameWeek:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_EnterCountWeek, enterCountWeek)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Battlefield_HighScoreTotalWeek, highScoreWeekTotal)
+        
+    return
+
+def SyncCrossBattlefieldPlayerInfo(curPlayer):
+    clientPack = ChPyNetSendPack.tagMCCrossBattlefieldPlayerInfo()
+    clientPack.BuyOpenCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_BuyOpenCountToday)
+    clientPack.HighScoreToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Battlefield_HighScoreToday)
+    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 2e585d3..60852d6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -61,6 +61,7 @@
 import PlayerGoldInvest
 import PlayerNewGuyCard
 import PlayerCrossRealmPK
+import PlayerCrossBattlefield
 import PlayerPet
 import BossHurtMng
 import PlayerRecover
@@ -576,6 +577,8 @@
         FBHelpBattle.DoPlayerOnDay(curPlayer)
         #跨服竞技场
         PlayerCrossRealmPK.DoPlayerOnDay(curPlayer)
+        #跨服战场
+        PlayerCrossBattlefield.DoPlayerOnDay(curPlayer)
         #缥缈仙域
         PlayerFairyDomain.OnDay(curPlayer)
         #仙盟宴会
@@ -716,7 +719,8 @@
         #竞技场
         PlayerArena.OnWeekEx(curPlayer)
         PlayerFamily.OnWeekEx(curPlayer)
-    
+        PlayerCrossBattlefield.DoPlayerOnWeek(curPlayer)
+        
     # 以下为支持两种重置模式切换配置的
     FBCommon.FBOnWeek(curPlayer, onEventType)
     
@@ -1490,6 +1494,10 @@
             PlayerLuckyCloudBuy.OnLuckyCloudBuyChange()
             return
         
+        if key == ShareDefine.Def_Notify_WorldKey_CrossBattlefieldCallTeamInfo:
+            PyGameData.g_crossBattlefieldCallTeamInfo = eval(msgValue)
+            return
+        
         if msgValue.isdigit():
             value = int(msgValue)
         else:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossBattlefield.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossBattlefield.py
new file mode 100644
index 0000000..b25ab78
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossBattlefield.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_CrossBattlefield
+#
+# @todo:跨服战场
+# @author hxp
+# @date 2022-01-06
+# @version 1.0
+#
+# 详细描述: 跨服战场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-01-06 20:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ChConfig
+import PlayerCrossBattlefield
+
+#------------------------------------------------------------------------------ 
+## 执行逻辑
+#  @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):
+    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_Battlefield, 0)
+    msgData = eval(funResult)
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.Log("GameServer_CrossBattlefield_DoResult msgData=%s" % (msgData), playerID)
+    PlayerCrossBattlefield.GameServer_CrossBattlefield_DoResult(curPlayer, msgData)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index cb0f2eb..b7da1e1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -101,6 +101,8 @@
 g_crossPlayerItemsChangeInfo = {} #跨服玩家物品变化信息 {playerID:{"背包类型-物品位":itemMD5, ...}, ...}
 g_crossPlayerSkillsChangeInfo = {} #跨服玩家技能变化信息 {playerID:[技能ID], ...}
 
+g_crossBattlefieldCallTeamInfo = {} # 跨服战场召集队伍信息 {zoneID:{hmNum:{playerID:[召集队伍玩家ID列表], ...}, ...}, ...}
+
 g_ZhuXianBossPlayerHurtDict = {} #诛仙BOSS玩家伤害排行信息
 
 g_Qudao_DoubleBill = {} # 渠道删档充值返利

--
Gitblit v1.8.0