From 8a7181b35a5f4063fb84fcb3120394faeaba2f77 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期一, 07 十二月 2020 19:19:50 +0800
Subject: [PATCH] 8585 【港台】【BT】【长尾】【后端】竞技场(初版)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Arena.py              |   54 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py                                              |   30 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py               |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py                                    |    1 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py                                           |    6 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py                                              |    2 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldArena.py                                       |  986 ++++++++++++++++++++++++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py                                                           |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/QuestRunner.py                     |   39 -
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py                                              |   10 
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                            |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                                |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py                               |    8 
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                                         |    8 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                           |   49 -
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Arena.py                              |   63 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_ArenaBattle.py |   43 +
 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini                                                                 |   11 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py                                                |   16 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py                             |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                                    |    8 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                                                  |    9 
 ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py                                                     |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py                             |  336 +++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/ClearOpenServerDay.py                                      |    7 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py                                     |    7 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                                          |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                            |   16 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddArenaBattleCount.py          |   47 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py                            |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py                      |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                       |   16 
 32 files changed, 1,674 insertions(+), 126 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
index 2681efc..9fa7b62 100644
--- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
+++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -147,6 +147,17 @@
 PacketSubCMD_1=0xA2
 PacketCallFunc_1=Client_PYWatchBillboard
 
+;竞技场
+[GameWorldArena]
+ScriptName = GameWorldLogic\GameWorldArena.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xA9
+PacketSubCMD_1=0xA8
+PacketCallFunc_1=OnQueryArenaBattleRecord
 
 ;镖车
 [PlayerTruck.py]
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 619a29e..fe630dd 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -588,6 +588,8 @@
             ShareDefine.Def_BT_Campaign_Wash            : 100,           #洗练战力(开服活动榜)
             ShareDefine.Def_BT_FCCostGold               : 5,             #消费排行榜(仙界盛典)
             ShareDefine.Def_BT_NewFCCostGold            : 5,             #消费排行榜(仙界盛典)
+            
+            ShareDefine.Def_BT_Arena                    : 1000,          #竞技场榜
             }
 
 #排行榜保存类型(和BillboardType匹配), 默认保存, 如果不保存,可配置进去
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/ClearOpenServerDay.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/ClearOpenServerDay.py
index faed2a0..717ac12 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/ClearOpenServerDay.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/ClearOpenServerDay.py
@@ -13,11 +13,9 @@
 #
 # @change: "2012-07-20 19:00" whx 世界等级和开服天书有关,也要清除
 # @change: "2013-12-06 15:00" hxp 增加通知MapServer开服天数
-# @change: "2014-11-27 16:30" hxp 增加开服活动数据重置相关; 增加清除竞技场数据
 # @change: "2014-12-02 11:30" hxp 增加合服状态及天数;强制刷新全服活动
 # @change: "2014-12-03 14:30" hxp 增加合服活动重置
 # @change: "2015-01-21 16:00" hxp 增加重置合服寻宝活动
-# @change: "2015-06-16 15:00" hxp 屏蔽清除竞技场数据; 玩家允许None
 #
 #------------------------------------------------------------------------------ 
 #"""Version = 2015-06-16 15:00"""
@@ -29,6 +27,7 @@
 import PlayerBillboard
 import PlayerUniversalGameRec
 import GameWorldProcess
+import GameWorldArena
 import GameWorldBoss
 import GMCommon
 
@@ -83,6 +82,10 @@
     # 广播分流boss状态
     GameWorldBoss.Sync_BossShuntLineInfo()
     
+    # 竞技场重置
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState, 0)
+    GameWorldArena.__DoArenaSeasonReset("GMReset")
+    
     if curPlayer:
         PlayerEventCounter.Sync_OpenServerDay(curPlayer)
         GameWorld.DebugAnswer(curPlayer, '开服星期%s, 天数:%s 是否合服:%s, 合服天数:%s'%\
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
index ae54f4e..44f3767 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
@@ -15,7 +15,6 @@
 # @change: "2013-03-20 18:00" Alee 添加DEBUG输出函数DebugLog
 # @change: "2013-09-10 20:10" Alee 函数DebugLog改用GetDebugLevel才有效
 # @change: "2014-05-16 10:30" xmnathan 增加交易所管理器接口
-# @change: "2014-08-01 15:30" xmnathan 增加天梯竞技场管理器接口
 # @change: "2014-09-22 10:00" xmnathan 增加GM工具补偿管理器接口
 # @change: "2015-01-14 00:30" hxp 增加服务器平台区服ID获取
 # @change: "2015-01-14 20:30" hxp 增加CanHappen函数
@@ -916,8 +915,9 @@
 #  @param itemList 待选列表
 #  @return object
 def GetResultByRandomList(randList, defValue=None, maxRateValue=ChConfig.Def_MaxRateValue):
-    rate = random.randint(0, maxRateValue)
-    
+    if not randList:
+        return defValue
+    rate = random.randint(0, randList[-1][0])
     return GetResultByRiseList(randList, rate, defValue)
 
 ## 增长列表(类似饼图)从中获得指定的信息
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldArena.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldArena.py
new file mode 100644
index 0000000..64beb6f
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldArena.py
@@ -0,0 +1,986 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldArena
+#
+# @todo:竞技场 - 本服
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 竞技场 - 本服,OnWeekEx 重置,开服前X定制天内固定为一个赛季,合服不处理
+#
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerControl
+import FormulaControl
+import PlayerBillboard
+import PlayerViewCache
+import PlayerCompensation
+import PlayerDBGSEvent
+import ChPyNetSendPack
+import NetPackCommon
+import IpyGameDataPY
+import PyGameData
+
+import random
+import time
+import json
+
+MaxRobotID = 9900 # 最大机器人ID,不超过 9999
+RandRobotID = 9000 # 预留给随机机器人用的起始ID,不超过 MaxRobotID,且 (MaxRobotID - RandRobotID) 不能超过 MaxBattleRecCount
+MaxBattleRecCount = 50 # 玩家最大对战记录保存条数
+
+Def_RecType_ArenaBattleRecord = ShareDefine.Def_UniversalGameRecType_ArenaBattleRecord
+
+## 竞技场匹配玩家信息,仅做内存缓存,不做持久化存储,重启服务器时效,相当于维护服务器后玩家可免费刷新一次
+class ArenaMatchPlayer():
+    
+    def __init__(self):
+        # name、RealmLV、FightPower 不记录,真实玩家读查看缓存,机器人前端自行处理
+        # RealmLV 读境界表按等级取对应境界
+        # FightPower 取等级表取对应参考战力
+        self.ResetData()
+        return
+    
+    def ResetData(self):
+        # 刷新匹配的时候需要重置下,不重复创建实例
+        self.tagPlayerID = 0 # 小于10000的为机器人ID
+        self.tagLV = 0
+        self.tagJob = 0
+        self.tagScore = 0
+        return
+    
+class ArenaBattleRec():
+    ''' 竞技场对战记录数据
+        额外说明:
+        因为有主动对战的才会上榜,而只有对战过的的才会被匹配到,所以可认为只要有对战记录,最后一条记录即为最新的数据记录
+        因此可以用来存储自身相关的数据,可用于离线被别人匹配到时暂存数据用,上线后取最后一条对战记录更新数据
+    '''
+    
+    def __init__(self, playerID):
+        self.playerID = playerID
+        # name、RealmLV、FightPower 不记录,真实玩家读查看缓存,机器人前端自行处理
+        # RealmLV 读境界表按等级取对应境界
+        # FightPower 取等级表取对应参考战力
+        self.tagPlayerID = 0 # 小于10000的为机器人ID
+        self.tagLV = 0
+        self.tagJob = 0
+        self.tagScore = 0
+        
+        self.addScore = 0
+        self.isWin = 0
+        self.battleTime = 0
+        
+        # 额外存储的个人记录
+        self.isDispose = 0 # 是否已经处理过该记录,离线/脱机被挑战时,暂时为未处理,上线后同步处理
+        self.updScore = 0
+        return
+    
+''' 对战记录  ShareDefine.Def_UniversalGameRecType_ArenaBattleRecord
+value1        playerID    玩家ID
+value2        tagPlayerID    目标玩家ID,小于10000为机器人
+value3        tagLVJob        目标等级职业,一般机器人时有用  lv*10 + job
+value4        tagScore        目标积分,非实时积分,一般机器人时有用
+strValue1    resultInfo    isWin,addScore
+strValue2    updInfo    isDispose,updScore
+'''
+
+''' 榜单数据 '''
+def GetArenaBillID(billData): return billData.GetID()
+def GetArenaBillName(billData): return billData.GetName1()
+def SetArenaBillName(billData, name): return billData.SetName1(name)
+def GetArenaBillJob(billData): return billData.GetType2()
+def GetArenaBillRealmLV(billData): return billData.GetValue1()
+def SetArenaBillRealmLV(billData, realmLV): return billData.SetValue1(realmLV)
+def GetArenaBillLV(billData): return billData.GetValue2()
+def SetArenaBillLV(billData, lv): billData.SetValue2(lv)
+def GetArenaBillScore(billData): return billData.GetCmpValue()
+def GetArenaBillFightPower(billData): return billData.GetCmpValue2()
+def SetArenaBillFightPower(billData, fightPower): billData.SetCmpValue2(fightPower)
+                
+def OnServerStart():
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    recDataList = universalRecMgr.GetTypeList(Def_RecType_ArenaBattleRecord)
+    GameWorld.Log("开服加载本服竞技场对战记录! %s" % recDataList.Count())
+    for index in xrange(recDataList.Count()):
+        recData = recDataList.At(index)
+        playerID = recData.GetValue1()
+        
+        battleRec = ArenaBattleRec(playerID)
+        battleRec.battleTime = recData.GetTime()
+        battleRec.tagPlayerID = recData.GetValue2()
+        battleRec.tagLV = recData.GetValue3() / 10
+        battleRec.tagJob = recData.GetValue3() % 10
+        battleRec.tagScore = recData.GetValue4()
+        
+        strValue1 = recData.GetStrValue1()
+        resultInfo = strValue1.split(",") if strValue1 else []
+        battleRec.isWin = int(resultInfo[0] if len(resultInfo) > 0 else 0)
+        battleRec.addScore = int(resultInfo[1] if len(resultInfo) > 1 else 0)
+        
+        strValue2 = recData.GetStrValue2()
+        updInfo = strValue2.split(",") if strValue2 else []
+        battleRec.isDispose = int(updInfo[0] if len(updInfo) > 0 else 0)
+        battleRec.updScore = int(updInfo[1] if len(updInfo) > 1 else 0)
+        
+        battleRecList = GetPlayerArenaBattleRecList(playerID)
+        battleRecList.append(battleRec)
+        
+        GameWorld.DebugLog("    加载玩家对战记录: playerID=%s, |%s| %s" % (playerID, strValue1, json.dumps(battleRec , default=lambda obj:obj.__dict__)))
+        
+        
+    OSSeasonState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState)
+    if not OSSeasonState and __DoArenaSeasonReset("OnServerStart"):
+        pass
+    
+    # 没有重置 或 重置失败 才处理以下内容
+    else:
+        billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_Arena)
+        if billBoard:
+            # 有数据的话设置本功能配置的最大榜单数
+            if billBoard.GetCount() > 0:
+                robotMaxCount = IpyGameDataPY.GetFuncCfg("ArenaRobot", 1)
+                PlayerBillboard.UpdateBillboardMaxCount(ShareDefine.Def_BT_Arena, robotMaxCount)
+            else:
+                __ResetArenaRobotBillboard()
+    return
+
+def OnServerClose():
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    universalRecMgr.Delete(Def_RecType_ArenaBattleRecord)
+    
+    GameWorld.Log("关服保存本服竞技场记录! %s" % len(PyGameData.g_arenaPlayerBattleRecDict))
+    recDataList = universalRecMgr.GetTypeList(Def_RecType_ArenaBattleRecord)
+    for battleRecList in PyGameData.g_arenaPlayerBattleRecDict.values():
+        for battleRec in battleRecList:
+            recData = recDataList.AddRec()
+            recData.SetTime(battleRec.battleTime)
+            
+            recData.SetValue1(battleRec.playerID)
+            recData.SetValue2(battleRec.tagPlayerID)
+            recData.SetValue3(battleRec.tagLV * 10 + battleRec.tagJob)
+            recData.SetValue4(battleRec.tagScore)
+            
+            recData.SetStrValue1("%s,%s" % (int(battleRec.isWin), battleRec.addScore))
+            recData.SetStrValue2("%s,%s" % (int(battleRec.isDispose), battleRec.updScore))
+            
+    return
+
+def GetPlayerArenaBattleRecList(playerID):
+    ## 获取玩家对战记录列表
+    if playerID not in PyGameData.g_arenaPlayerBattleRecDict:
+        PyGameData.g_arenaPlayerBattleRecDict[playerID] = []
+    return PyGameData.g_arenaPlayerBattleRecDict[playerID]
+
+def IsArenaBattlePlayer(playerID): return playerID in PyGameData.g_arenaPlayerBattleRecDict
+
+def SendMapServerArenaInfo():
+    ## 通知地图信息
+    
+    return
+
+def OnPlayerLogin(curPlayer):
+    ## 玩家登录
+    
+    if PlayerControl.GetIsTJG(curPlayer):
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    curBattleRecList = GetPlayerArenaBattleRecList(playerID)
+    
+    updScore = None
+    # 倒序遍历
+    for battleRec in curBattleRecList[::-1]:
+        if battleRec.isDispose:
+            continue
+        battleRec.isDispose = 1
+        
+        if updScore == None:
+            updScore = battleRec.updScore # 只更新一次,即最后一条记录
+            
+    if updScore != None:
+        __SyncPlayerBechallengedUpdScore(curPlayer, updScore)
+        
+    return
+
+def OnDayEx():
+    
+    # 先处理每日结算
+    __DoGiveBillboardAward("Day")
+    
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1    
+    if openServerDay <= customMaxServerDay:
+        GameWorld.Log("OnDayEx时竞技场开服定制赛季进行中,不处理! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
+        return
+    
+    # 竞技场开服前定制X天赛季状态  0-未比赛过,1-进行中,>1结算时的开服天
+    OSSeasonState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState)
+    if OSSeasonState > 1:
+        GameWorld.Log("OnDayEx时竞技场开服定制赛季已结算过,不处理! OSSeasonState=%s" % (OSSeasonState))
+        return
+    
+    __DoArenaSeasonReset("OpenServerSeason")
+    return
+
+def OnWeekEx():
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
+    if openServerDay <= customMaxServerDay:
+        GameWorld.Log("OnWeekEx时在开服定制天内,不处理竞技场赛季重置! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
+        return
+    
+    OSSeasonState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState)
+    if not OSSeasonState or OSSeasonState == 1 or OSSeasonState == openServerDay:
+        GameWorld.Log("OnWeekEx时竞技场开服定制赛季进行中或同一天结算,不处理重置! openServerDay=%s,OSSeasonState=%s" % (openServerDay, OSSeasonState))        
+        return
+    
+    __DoArenaSeasonReset("OnWeekExSeason")
+    return
+
+def __DoArenaSeasonReset(resetName):
+    ''' 赛季重置
+           赛季规则:前定制运营最大开服天为一个赛季,后续按 OnWeekEx 重置
+    '''
+    
+    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
+    OSSeasonState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState)
+    worldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
+    GameWorld.Log("重置竞技场! resetName=%s,openServerDay=%s,OSSeasonState=%s,worldLV=%s" 
+                  % (resetName, openServerDay, OSSeasonState, worldLV))
+    
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    if openServerDay <= customMaxServerDay and OSSeasonState != 0:
+        GameWorld.Log("开服定制天内不能重置!")
+        return
+    
+    # 结算上赛季排行奖励
+    __DoGiveBillboardAward("Week")
+    
+    # 重置排行榜
+    __ResetArenaRobotBillboard()
+    
+    # 删除对战记录
+    GameWorld.GetUniversalRecMgr().Delete(Def_RecType_ArenaBattleRecord)
+    PyGameData.g_arenaPlayerBattleRecDict = {}
+    
+    # 更新新赛季信息
+    if openServerDay <= customMaxServerDay and OSSeasonState == 0:
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState, 1)
+    else:
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ArenaOSSeasonState, customMaxServerDay + 1)
+        
+    # 最后通知地图新赛季信息
+    SendMapServerArenaInfo()
+    GameWorld.Log("=============== 重置竞技场OK ===============")
+    return True
+
+def __ResetArenaRobotBillboard():
+    ## 重置竞技场机器人排行榜,赛季重置时  或  启动服务器时榜单数据为空(合服首次启动)
+    
+    # 清除榜单
+    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
+        return
+    billBoard.Clear()
+    robotMaxCount = IpyGameDataPY.GetFuncCfg("ArenaRobot", 1)
+    GameWorld.Log("    重置初始化竞技场机器人榜单! robotMaxCount=%s" % robotMaxCount)
+    PlayerBillboard.UpdateBillboardMaxCount(ShareDefine.Def_BT_Arena, robotMaxCount)
+    
+    # 获取机器人随机等级、积分列表
+    robotLVList = __RandRobotLVList(robotMaxCount)
+    robotScoreList = __RandRobotScoreList(robotMaxCount)
+    
+    GameWorld.Log("    robotLVList: %s, %s" % (len(robotLVList), robotLVList))
+    GameWorld.Log("    robotScoreList: %s, %s" % (len(robotScoreList), robotScoreList))
+    
+    openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
+    # 机器人插入榜单,倒序插入,不用排序
+    robotID = 0
+    for i in xrange(robotMaxCount - 1, -1, -1):
+        robotLV = robotLVList[i]
+        robotScore = robotScoreList[i]
+        robotID += 1
+        robotName = "" # 固定,前端自行显示
+        opInfo = ""
+        robotJob = random.choice(openJobList) # 随机开放的职业
+        robotRealmLV = 0 # 前端 读境界表取等级对应境界
+        robotFightPower = 0 # 前端 读等级表取等级对应战力
+        
+        type2 = robotJob
+        value1 = robotRealmLV
+        value2 = robotLV
+        cmpValue = robotScore
+        cmpValue2 = robotFightPower
+        PlayerBillboard.UpdatePlayerBillboard(robotID, robotName, opInfo, ShareDefine.Def_BT_Arena, type2, value1, value2, cmpValue, autoSort=False, cmpValue2=cmpValue2)
+        
+    billBoard.Sort()
+    return
+
+def __RandRobotLVList(robotMaxCount):
+    ''' 随机机器人等级
+    @param robotMaxCount: 机器人数量
+    @return: 升序排好的机器人等级列表
+    '''
+    
+    robotMinLV, robotMaxLV = __GetRobotLVRange()
+    
+    # 难度等级步长,为了难度递增时,等级看起来乱一点,又能确保难度递增,所以加入此概念
+    difficultLVStep = IpyGameDataPY.GetFuncCfg("ArenaRobot", 4)
+    
+    lvList = []
+    lvCount = robotMaxLV - robotMinLV + 1 # 等级差值数量
+    lvAvg = lvCount / float(robotMaxCount) # 人均等级
+    oneLVRobotCount = 1 / lvAvg # 1个等级理论上有几个机器人
+    
+    minLV = 0
+    difficultRobotCountEx = 0
+    for lv in xrange(robotMinLV, robotMaxLV + difficultLVStep, difficultLVStep):
+        if lv >= robotMaxLV:
+            break
+        if minLV == 0:
+            minLV = lv
+        maxLV = lv + difficultLVStep - 1
+        
+        difficultRobotCount = oneLVRobotCount * difficultLVStep + difficultRobotCountEx # 同个难度等级机器人总数
+        difficultRobotCountEx = difficultRobotCount % 1
+        
+        if difficultRobotCount < 1:
+            continue
+        
+        for _ in xrange(int(difficultRobotCount)):
+            lvList.append(random.randint(minLV, maxLV))
+            
+        minLV = 0
+        
+    if len(lvList) > robotMaxCount:
+        lvList = lvList[:robotMaxCount]
+    else:
+        # 如果还不够,直接用最后一个难度补足人数
+        while len(lvList) < robotMaxCount:
+            lvList.append(random.randint(robotMaxLV - difficultLVStep, robotMaxLV))
+            
+    lvList[0] = robotMinLV
+    lvList[-1] = robotMaxLV
+    return lvList
+
+def __GetRobotLVRange():
+    ## 获取赛季机器人等级范围
+    worldLV = max(1, PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv))
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    maxCnt = ipyDataMgr.GetWorldLVCount()
+    worldLVTime = 0
+    if worldLV <= maxCnt:
+        worldLVIpyData = ipyDataMgr.GetWorldLVByIndex(worldLV - 1)
+        worldLVTime = worldLVIpyData.GetOpenServerSecond()
+        
+    minLV, maxLV = IpyGameDataPY.GetFuncEvalCfg("ArenaRobot", 2) # 机器人最小、最大等级
+    
+    robotMaxLV = minLV
+    maxWorldLVTime = eval(IpyGameDataPY.GetFuncCfg("ArenaRobot", 3))
+    for i in xrange(worldLV - 1, maxCnt):
+        ipyData = ipyDataMgr.GetWorldLVByIndex(i)
+        if i == maxCnt - 1:
+            robotMaxLV = ipyData.GetWorldLV()
+        else:
+            nextIpyData = IpyGameDataPY.IPY_Data().GetWorldLVByIndex(i + 1)
+            if ipyData.GetOpenServerSecond() <= maxWorldLVTime < nextIpyData.GetOpenServerSecond():
+                robotMaxLV = ipyData.GetWorldLV()
+                break
+            
+    robotMaxLV = max(minLV, min(maxLV, robotMaxLV))
+    GameWorld.Log("    机器人等级范围: worldLV=%s,worldLVTime=%s,maxWorldLVTime=%s,minLV=%s,robotMaxLV=%s" 
+                  % (worldLV, worldLVTime, maxWorldLVTime, minLV, robotMaxLV))
+    return minLV, robotMaxLV
+
+def __RandRobotScoreList(robotMaxCount):
+    ''' 随机机器人积分
+    @param minScore: 机器人最小积分
+    @param maxScore: 机器人最大积分
+    @param robotMaxCount: 机器人数量
+    @return: 升序排好的机器人积分列表
+    '''
+    
+    minScore, maxScore = IpyGameDataPY.GetFuncEvalCfg("ArenaSet", 1)
+    
+    scoreCount = maxScore - minScore + 1 # 积分差值数量
+    scoreAvg = scoreCount / float(robotMaxCount) # 人均积分
+    
+    oneScoreRobotCount = 1 / scoreAvg # 1个积分理论上有几个机器人
+        
+    scoreList = []
+    minS = 0
+    robotCountEx = 0
+    for score in xrange(minScore, maxScore + 1):
+        if minS == 0:
+            minS = score
+            
+        robotCount = oneScoreRobotCount * 1 + robotCountEx
+        robotCountEx = robotCount % 1
+        
+        if robotCount < 1:
+            continue
+        
+        for _ in xrange(int(robotCount)):
+            if minS == score:
+                scoreList.append(score)
+            else:
+                scoreList.append(random.randint(minS, score))
+        minS = 0
+    
+    if len(scoreList) > robotMaxCount:
+        scoreList = scoreList[:robotMaxCount]
+    else:
+        # 如果还不够,直接用最后一个难度补足人数
+        while len(scoreList) < robotMaxCount:
+            scoreList.append(maxScore)
+            
+    scoreList[0] = minScore
+    scoreList[-1] = maxScore
+    scoreList.sort()
+    return scoreList
+
+def __DoGiveBillboardAward(awardType):
+    ## 竞技场结算排行奖励, 每日、赛季通用
+    
+    GameWorld.Log("=== 竞技场结算排行奖励! === %s" % awardType)
+    
+    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
+        return
+    
+    if awardType == "Day":
+        billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 1, {})
+        floorAwardList = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 2)
+    elif awardType == "Week":
+        billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 3, {})
+        floorAwardList = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 4)
+    else:
+        return
+    
+    orderList = []
+    for orderStr in billboradAwardDict.keys():
+        orderList.append(int(orderStr))
+    orderList.sort()
+    GameWorld.Log("    奖励名次列表: %s" % orderList)
+    
+    awardOrder = orderList[0]
+    orderPlayerIDDict = {}
+    billboardCount, billboardMaxCount = billBoard.GetCount(), billBoard.GetMaxCount()
+    GameWorld.Log("    榜单数据数! billboardCount=%s,billboardMaxCount=%s" % (billboardCount, billboardMaxCount))
+    for index in xrange(billboardCount):
+        billBoardData = billBoard.At(index)
+        if not billBoardData:
+            continue
+        order = index + 1
+        
+        if order > awardOrder:
+            nextOrderIndex = orderList.index(awardOrder) + 1
+            if nextOrderIndex >= len(orderList):
+                break
+            awardOrder = orderList[nextOrderIndex]
+            
+        playerID = billBoardData.GetID()
+        if playerID <= MaxRobotID:
+            # 机器人不处理
+            continue
+        
+        #playerName = billBoardData.GetName1()
+        orderPlayerIDDict[playerID] = [order, awardOrder]
+        
+        awardList = billboradAwardDict[str(awardOrder)]
+        PlayerCompensation.SendMailByKey("ArenaBillboardAward%s" % awardType, [playerID], awardList, [order])
+        
+    GameWorld.Log("    奖励玩家名次信息: %s" % orderPlayerIDDict)
+    
+    # 其他的获得保底奖励
+    orderPlayerIDList = orderPlayerIDDict.keys()
+    floorPlayerIDList = []
+    for playerID in PyGameData.g_arenaPlayerBattleRecDict.keys():
+        if playerID in orderPlayerIDList:
+            continue
+        floorPlayerIDList.append(playerID)
+        PlayerCompensation.SendMailByKey("ArenaFloorAward%s" % awardType, [playerID], floorAwardList)
+        
+    GameWorld.Log("    奖励保底玩家信息: %s" % floorPlayerIDList)
+    return
+
+def MapServer_Arena(curPlayer, msgList):
+    GameWorld.DebugLog("MapServer_Arena %s" % str(msgList), curPlayer.GetPlayerID())
+    if not msgList:
+        return
+    
+    cmd = msgList[0]
+    cmdDict = msgList[1] if len(msgList) > 1 else {}
+    retDict = {}
+    
+    # 匹配刷新
+    if cmd == "MatchRefresh":
+        __DoArenaMatchRefresh(curPlayer, cmdDict["isRefresh"], cmdDict["playerLV"], cmdDict["playerScore"])
+        
+    # 对战结算
+    elif cmd == "BattleResult":
+        retDict = __DoArenaBattleResult(curPlayer, cmdDict)
+        
+    return msgList + [retDict]
+
+def __DoArenaMatchRefresh(curPlayer, isRefresh, playerLV, playerScore):
+    ## 玩家刷新匹配对手
+    
+    playerID = curPlayer.GetPlayerID()
+    higherOrderPerList = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 1)
+    lowerOrderPerList = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 2)
+    
+    GameWorld.DebugLog("竞技场玩家刷新匹配列表: isRefresh=%s,playerLV=%s,playerScore=%s" % (isRefresh, playerLV, playerScore), playerID)
+    GameWorld.DebugLog("    higherOrderPerList=%s,lowerOrderPerList=%s" % (higherOrderPerList, lowerOrderPerList), playerID)
+    
+    # 匹配对象缓存
+    needMatchCount = len(higherOrderPerList) + len(lowerOrderPerList)
+    #GameWorld.DebugLog("    匹配缓存: %s" % PyGameData.g_arenaPlayerMatchDict, playerID)
+    if playerID not in PyGameData.g_arenaPlayerMatchDict:
+        PyGameData.g_arenaPlayerMatchDict[playerID] = []
+    matchList = PyGameData.g_arenaPlayerMatchDict[playerID]
+    if len(matchList) > needMatchCount:
+        matchList = matchList[:needMatchCount] # 删除多余的个数,一般都是相同的,除非修改匹配数重读配置
+    if not isRefresh and len(matchList) == needMatchCount:
+        # 非刷新的并且已经有记录的直接同步
+        GameWorld.DebugLog("    非刷新且有数据,直接同步!", playerID)
+        __SyncMatchList(curPlayer, matchList)
+        return
+    
+    #maxOrder = IpyGameDataPY.GetFuncCfg("ArenaRobot", 1) # 这里不读配置,直接使用榜单数
+    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
+        return
+    playerOrder = billBoard.IndexOfByID(playerID) + 1  # 玩家在排行榜中的名次,没有名次为-1
+    maxOrder = billBoard.GetCount()
+    if playerOrder <= 0:
+        playerOrder = maxOrder + 1
+        
+    GameWorld.DebugLog("    maxOrder=%s,playerOrder=%s" % (maxOrder, playerOrder), playerID)
+    
+    matchOrderList = [] # 匹配到的名次
+    # 非第一名的匹配比自身名次高的
+    if playerOrder > 1 and higherOrderPerList:
+        higherOrderCount = playerOrder - 1 # 比玩家高的名次的个数
+        # 小于10个的直接纯随机
+        if 0 < higherOrderCount < 10:
+            randOrderList = range(1, playerOrder)
+            random.shuffle(randOrderList)
+            matchOrderList.extend(randOrderList[:len(higherOrderPerList)])
+            GameWorld.DebugLog("    直接随机较高名次! higherOrderCount=%s,randOrderList=%s,matchOrderList=%s" 
+                               % (higherOrderCount, randOrderList, matchOrderList), playerID)
+            
+        # 按比例划分
+        elif higherOrderCount >= 10:
+            randMaxOrder = playerOrder - 1
+            for per in higherOrderPerList:
+                per = min(per, 100) # 最多到100
+                tagOrder = int(playerOrder - higherOrderCount * per / 100.0)
+                if tagOrder <= 0 or randMaxOrder <= 0 or tagOrder > randMaxOrder:
+                    GameWorld.ErrLog("竞技场匹配高名次玩家比例范围配置错误! playerOrder(%s) - higherOrderCount(%s)*per(%s) = tagOrder(%s) <= 0 or randMaxOrder(%s)<=0 or tagOrder > randMaxOrder higherOrderPerList=%s" 
+                                     % (playerOrder, higherOrderCount, per, tagOrder, randMaxOrder, higherOrderPerList))
+                    break
+                randOrder = random.randint(tagOrder, randMaxOrder)
+                if randOrder != playerOrder and randOrder not in matchOrderList:
+                    matchOrderList.append(randOrder)
+                GameWorld.DebugLog("    根据比例随机较高名次! higherOrderCount=%s,per=%s,randOrder=(%s~%s)%s,matchOrderList=%s" 
+                                   % (higherOrderCount, per, tagOrder, randMaxOrder, randOrder, matchOrderList), playerID)
+                randMaxOrder = tagOrder - 1
+                
+    # 高名次不足的,用低名次补足,一般是前几名才会有这个需求
+    higherLackCount = max(0, len(higherOrderPerList) - len(matchOrderList))
+    
+    # 非最后一名的匹配比自身名次低的
+    if 1 <= playerOrder < maxOrder and lowerOrderPerList:
+        lowerOrderCount = maxOrder - playerOrder # 比玩家低的名次的个数
+        # 小于10个的直接纯随机
+        if 0 < lowerOrderCount < 10:
+            randOrderList = range(playerOrder + 1, maxOrder + 1)
+            random.shuffle(randOrderList)
+            matchOrderList.extend(randOrderList[:len(lowerOrderPerList)])
+            GameWorld.DebugLog("    直接随机较低名次! lowerOrderCount=%s,randOrderList=%s,matchOrderList=%s" 
+                               % (lowerOrderCount, randOrderList, matchOrderList), playerID)
+            
+        # 按比例划分
+        elif lowerOrderCount >= 10:
+            randMinOrder = playerOrder + 1
+            for per in lowerOrderPerList:
+                per = min(per, 100) # 最多到100
+                tagOrder = int(playerOrder + lowerOrderCount * per / 100.0)
+                if tagOrder > maxOrder or randMinOrder > maxOrder or randMinOrder > tagOrder:
+                    GameWorld.ErrLog("竞技场匹配低名次玩家比例范围配置错误! playerOrder(%s) - lowerOrderCount(%s)*per(%s) = tagOrder(%s) > maxOrder(%s) or randMinOrder(%s)>maxOrder or randMinOrder > tagOrder lowerOrderPerList=%s" 
+                                     % (playerOrder, lowerOrderCount, per, tagOrder, maxOrder, randMinOrder, lowerOrderPerList))
+                    break
+                randOrder = random.randint(randMinOrder, tagOrder)
+                if randOrder != playerOrder and randOrder not in matchOrderList:
+                    matchOrderList.append(randOrder)
+                GameWorld.DebugLog("    根据比例随机较低名次! lowerOrderCount=%s,per=%s,randOrder=(%s~%s)%s,matchOrderList=%s" 
+                                   % (lowerOrderCount, per, randMinOrder, tagOrder, randOrder, matchOrderList), playerID)
+                randMinOrder = tagOrder + 1
+                
+            # 高名次不足还需要额外补的,直接从玩家名次+1 ~ 最后一个低百分比名次 间随机
+            doCount = 50
+            while higherLackCount > 0 and doCount > 0:
+                doCount -= 1
+                randOrderMin = playerOrder + 1
+                randOrderMax = min(tagOrder, maxOrder)
+                randOrder = random.randint(randOrderMin, randOrderMax)
+                if randOrder != playerOrder and randOrder not in matchOrderList:
+                    matchOrderList.append(randOrder)
+                    higherLackCount -= 1
+                    GameWorld.DebugLog("    高名次不足,使用较低名次补充! higherLackCount=%s,randOrder=(%s~%s)%s,matchOrderList=%s" 
+                                       % (higherLackCount, randOrderMin, randOrderMax, randOrder, matchOrderList), playerID)
+                    
+    matchOrderList.sort()
+    GameWorld.DebugLog("    最终匹配到的名次列表: matchOrderList=%s" % matchOrderList, playerID)
+    
+    # 随机机器人备用信息
+    openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
+    
+    randRobotLVPerRange = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 3)
+    minLV, maxLV = IpyGameDataPY.GetFuncEvalCfg("ArenaRobot", 2) # 机器人最小、最大等级
+    randMinLV = min(minLV, int(playerLV * randRobotLVPerRange[0] / 100.0))
+    randMaxLV = min(maxLV, int(playerLV * randRobotLVPerRange[1] / 100.0))
+    
+    randRobotScorePerRange = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 4)
+    randMinScore = int(playerScore * randRobotScorePerRange[0] / 100.0)
+    randMaxScore = int(playerScore * randRobotScorePerRange[1] / 100.0)
+    
+    # 找出对战列表中最新的一条随机机器人ID,用于后面生成新的随机机器人ID用,确保不重复
+    lastRandRobotID = RandRobotID
+    curBattleRecList = GetPlayerArenaBattleRecList(playerID)
+    for battleRec in curBattleRecList[::-1]:
+        if battleRec.tagPlayerID >= RandRobotID and battleRec.tagPlayerID <= MaxRobotID:
+            lastRandRobotID = battleRec.tagPlayerID
+            break
+        
+    GameWorld.DebugLog("    随机机器人备用信息: lastRandRobotID=%s,LV(%s ~ %s),score(%s ~ %s)" 
+                       % (lastRandRobotID, randMinLV, randMaxLV, randMinScore, randMaxScore), playerID)
+    
+    for i in xrange(needMatchCount):
+        if len(matchList) > i:
+            matchPlayer = matchList[i]
+        else:
+            matchPlayer = ArenaMatchPlayer()
+            matchList.append(matchPlayer)
+        matchPlayer.ResetData()
+        
+        if matchOrderList:
+            matchOrder = matchOrderList.pop(0)
+            matchIndex = matchOrder - 1
+            # 在榜单上的直接取榜单数据
+            if billBoard and 0 <= matchIndex < billBoard.GetCount():
+                billData = billBoard.At(matchIndex)
+                matchPlayer.tagPlayerID = GetArenaBillID(billData)
+                
+                # 被匹配的时候被动更新榜单中的玩家数据,不排序,只更新数值,这些数值不影响排序,战斗力为二级排序,可忽略
+                if matchPlayer.tagPlayerID > MaxRobotID:
+                    curCache = PlayerViewCache.FindViewCache(matchPlayer.tagPlayerID)
+                    if curCache:
+                        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+                        SetArenaBillName(billData, cacheDict["Name"])
+                        SetArenaBillRealmLV(billData, cacheDict["RealmLV"])
+                        SetArenaBillLV(billData, cacheDict["LV"])
+                        SetArenaBillFightPower(billData, cacheDict["FightPower"])
+                        
+                matchPlayer.tagLV = GetArenaBillLV(billData)
+                matchPlayer.tagJob = GetArenaBillJob(billData)
+                matchPlayer.tagScore = GetArenaBillScore(billData)
+                
+                GameWorld.DebugLog("    %s 匹配在榜单上的: tagPlayerID=%s,tagLV=%s,tagScore=%s,matchOrder=%s" 
+                                   % (i + 1, matchPlayer.tagPlayerID, matchPlayer.tagLV, matchPlayer.tagScore, matchOrder), playerID)
+                continue
+            
+        # 剩下的随机生成不在榜单上的机器人
+        lastRandRobotID += 1
+        if lastRandRobotID > MaxRobotID:
+            lastRandRobotID = RandRobotID
+        matchPlayer.tagPlayerID = lastRandRobotID
+        matchPlayer.tagJob = random.choice(openJobList)
+        matchPlayer.tagLV = random.randint(randMinLV, randMaxLV)
+        matchPlayer.tagScore = random.randint(randMinScore, randMaxScore)
+        GameWorld.DebugLog("    %s 匹配非榜单上的: tagPlayerID=%s,tagLV=%s,tagScore=%s" 
+                           % (i + 1,matchPlayer.tagPlayerID, matchPlayer.tagLV, matchPlayer.tagScore), playerID)
+        
+    PyGameData.g_arenaPlayerMatchDict[playerID] = matchList
+    #GameWorld.DebugLog("    更新匹配缓存: %s" % PyGameData.g_arenaPlayerMatchDict, playerID)
+    __SyncMatchList(curPlayer, matchList)
+    return
+
+def __SyncMatchList(curPlayer, matchList):
+    ## 同步匹配列表
+    clientPack = ChPyNetSendPack.tagGCArenaMatchList()
+    clientPack.MatchList = []
+    for matchPlayer in matchList:
+        matchInfo = ChPyNetSendPack.tagGCArenaMatchInfo()
+        matchInfo.PlayerID = matchPlayer.tagPlayerID
+        matchInfo.Job = matchPlayer.tagJob
+        matchInfo.LV = matchPlayer.tagLV
+        matchInfo.Score = matchPlayer.tagScore
+        
+        # 玩家读取额外信息, 机器人其他信息不处理,这里直接读最新的查看缓存,防止刷新不及时(并不是实时数据,只是相对实时,前端可自行控制刷新频率)
+        if matchInfo.PlayerID > MaxRobotID:
+            curCache = PlayerViewCache.FindViewCache(matchInfo.PlayerID)
+            if curCache:
+                cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+                matchInfo.PlayerName = cacheDict["Name"]
+                matchInfo.RealmLV = cacheDict["RealmLV"]
+                matchInfo.FightPower = cacheDict["FightPower"]
+                
+        clientPack.MatchList.append(matchInfo)
+    clientPack.MatchCount = len(clientPack.MatchList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+def __DoArenaBattleResult(curPlayer, cmdDict):
+    ## 地图玩家同步战斗结果
+    
+    retDict = {}
+    retDict.update(cmdDict)
+    
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.DebugLog("竞技场玩家战斗结果: %s" % str(cmdDict), playerID)
+    
+    tagPlayerID = cmdDict["tagPlayerID"]
+    isWin = cmdDict["isWin"]
+    playerLV = cmdDict["playerLV"]
+    playerScore = cmdDict["playerScore"]
+    
+    if not tagPlayerID:
+        return retDict
+    
+    ''' 关于对手
+        来源: 
+        1. 匹配列表中
+        2. 对战记录中直接发起的挑战
+        说明:
+    1. 可能是机器人,且机器人积分不会变化
+    2. 不一定在榜上,因为可能在榜上的时候被匹配走了,但是后来被挤出榜单,然后受到玩家挑战
+    3. 如果是玩家,理论上都有对战记录,因为在榜上的玩家才会被匹配走,而只有主动对战过才有可能上榜
+    '''
+   
+    curScore = playerScore
+    isFindTag = False
+    tagLV, tagJob, tagScore = 0, 0, 0
+    
+    # 先找匹配列表
+    matchList = PyGameData.g_arenaPlayerMatchDict.get(playerID, [])
+    for matchPlayer in matchList:
+        if matchPlayer.tagPlayerID == tagPlayerID:
+            isFindTag = True
+            tagLV, tagJob, tagScore = matchPlayer.tagLV, matchPlayer.tagJob, matchPlayer.tagScore
+            GameWorld.DebugLog("    对手在匹配列表中! tagLV=%s, tagJob=%s, tagScore=%s" % (tagLV, tagJob, tagScore), playerID)
+            break
+        
+    # 在找对战记录列表
+    curBattleRecList = GetPlayerArenaBattleRecList(playerID)
+    if not isFindTag:
+        for battleRec in curBattleRecList:
+            if battleRec.tagPlayerID == tagPlayerID:
+                isFindTag = True
+                tagLV, tagJob, tagScore = battleRec.tagLV, battleRec.tagJob, battleRec.tagScore
+                GameWorld.DebugLog("    对手在对战记录中! tagLV=%s, tagJob=%s, tagScore=%s" % (tagLV, tagJob, tagScore), playerID)
+                break
+            
+    if not isFindTag:
+        GameWorld.ErrLog("找不到对战对手,不在匹配列表或对战记录里!不处理结算!tagPlayerID=%s" % tagPlayerID, playerID)
+        return retDict
+    
+    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
+        return retDict
+    
+    if tagPlayerID > MaxRobotID:
+        tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
+        tagOnline = 1 if (tagPlayer and not PlayerControl.GetIsTJG(tagPlayer)) else 0 # 目标玩家是否在线
+        
+        tagBattleRecList = GetPlayerArenaBattleRecList(tagPlayerID)
+        # 虽说理论上都有记录,但是代码层面还是做好为None时的防范
+        tagBattleRec = tagBattleRecList[-1] if len(tagBattleRecList) > 0 else None
+        if tagBattleRec:
+            tagScore = tagBattleRec.updScore
+            GameWorld.DebugLog("    对手是玩家,从对手最新对战记录中获得对手最新积分! tagScore=%s" % tagScore, playerID)            
+    
+    playerJob = curPlayer.GetJob()
+    playerName = curPlayer.GetName()
+    realmLV = cmdDict["realmLV"]
+    fightPower = cmdDict["fightPower"]
+    
+    opInfo = ""
+    # 结算自己
+    addScore = __CalcBattleAddScore(curScore, tagScore, isWin)
+    updScore = max(0, playerScore + addScore)
+    GameWorld.DebugLog("    更新自身积分: addScore=%s,updScore=%s" % (addScore, updScore), playerID)
+    
+    curOrder = billBoard.IndexOfByID(playerID) + 1  # 更新前获取名次
+    PlayerBillboard.UpdatePlayerBillboard(playerID, playerName, opInfo, ShareDefine.Def_BT_Arena, playerJob,
+                                          realmLV, playerLV, updScore, autoSort=False, cmpValue2=fightPower)
+    
+    awardItemList = []
+    if isWin:
+        randItemList = IpyGameDataPY.GetFuncEvalCfg("ArenaBattleAward", 3)
+        awardItemInfo = GameWorld.GetResultByRandomList(randItemList)
+        if awardItemInfo:
+            awardItemList.append(awardItemInfo)
+            
+    # 结算对手,仅玩家时结算,机器人不处理
+    if tagPlayerID > MaxRobotID:
+        tagAddScore = __CalcBattleAddScore(tagScore, curScore, not isWin)
+        updTagScore = max(0, tagScore + tagAddScore)
+        GameWorld.DebugLog("    更新对手积分: tagAddScore=%s,updTagScore=%s" % (tagAddScore, updTagScore), playerID)
+        tagCache = PlayerViewCache.FindViewCache(tagPlayerID)
+        if tagCache:
+            cacheDict = PlayerViewCache.GetCachePropDataDict(tagCache)
+            tagOpInfo = ""
+            tagPlayerName = cacheDict["Name"]
+            tagRealmLV = cacheDict["RealmLV"]
+            tagFightPower = cacheDict["FightPower"]
+            PlayerBillboard.UpdatePlayerBillboard(tagPlayerID, tagPlayerName, tagOpInfo, ShareDefine.Def_BT_Arena, tagJob,
+                                                  tagRealmLV, tagLV, updTagScore, autoSort=False, cmpValue2=tagFightPower)
+    else:
+        updTagScore = tagScore
+        GameWorld.DebugLog("    机器人对手,积分不变!updTagScore=%s" % updTagScore, playerID)
+        
+    # 都更新完后排序一次
+    billBoard.Sort()
+    updOrder = billBoard.IndexOfByID(playerID) + 1 # 取最新名次
+    retDict.update({"addScore":addScore, "updScore":updScore, "curOrder":curOrder, "updOrder":updOrder,
+                    "awardItemList":awardItemList, "isOK":True})
+    
+    battleRecMaxCount = min(MaxBattleRecCount, IpyGameDataPY.GetFuncCfg("ArenaSet", 4))
+    
+    # 插入对战记录
+    battleTime = int(time.time())
+    battleRec = ArenaBattleRec(playerID)
+    battleRec.battleTime = battleTime
+    battleRec.tagPlayerID = tagPlayerID
+    battleRec.tagLV = tagLV
+    battleRec.tagJob = tagJob
+    battleRec.tagScore = updTagScore
+    battleRec.isWin = int(isWin)
+    battleRec.addScore = addScore
+    battleRec.isDispose = 1
+    battleRec.updScore = updScore
+    curBattleRecList.append(battleRec)
+    if len(curBattleRecList) > battleRecMaxCount:
+        curBattleRecList = curBattleRecList[len(curBattleRecList) - battleRecMaxCount:]
+        PyGameData.g_arenaPlayerBattleRecDict[playerID] = curBattleRecList
+    __SyncArenaBattleRecord(curPlayer, [battleRec])
+    
+    if tagPlayerID > MaxRobotID:
+        # 对手玩家反向增加对战记录
+        tagBattleRec = ArenaBattleRec(tagPlayerID)
+        tagBattleRec.battleTime = battleTime
+        tagBattleRec.tagPlayerID = playerID
+        tagBattleRec.tagLV = playerLV
+        tagBattleRec.tagJob = playerJob
+        tagBattleRec.tagScore = updScore
+        tagBattleRec.isWin = int(not isWin)
+        tagBattleRec.addScore = tagAddScore
+        tagBattleRec.isDispose = 1 if tagOnline else 0
+        tagBattleRec.updScore = updTagScore
+        tagBattleRecList.append(tagBattleRec)
+        if len(tagBattleRecList) > battleRecMaxCount:
+            tagBattleRecList = tagBattleRecList[len(tagBattleRecList) - battleRecMaxCount:]
+            PyGameData.g_arenaPlayerBattleRecDict[tagPlayerID] = tagBattleRecList
+        if tagOnline:
+            __SyncArenaBattleRecord(tagPlayer, [tagBattleRec])
+            __SyncPlayerBechallengedUpdScore(tagPlayer, updTagScore)
+            
+    GameWorld.DebugLog("    最新所有对战记录缓存! %s" % PyGameData.g_arenaPlayerBattleRecDict)
+    GameWorld.DebugLog("    retDict=%s" % retDict, playerID)
+    
+    # 对战结束,最后免费刷新一次匹配列表
+    __DoArenaMatchRefresh(curPlayer, True, playerLV, updScore)
+    return retDict
+
+def __SyncPlayerBechallengedUpdScore(curPlayer, updScore):
+    ## 通知地图玩家被挑战更新积分,在线被挑战 或 离线/脱机被挑战上线后同步
+    
+    playerID = curPlayer.GetPlayerID()
+    tagMapID = curPlayer.GetRealMapID()
+    cmdStr = str(["UpdScore", {"updScore":updScore}])
+    GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, playerID, tagMapID, "Arena",
+                                                       cmdStr, len(cmdStr), curPlayer.GetRouteServerIndex())
+    return
+
+def __CalcBattleAddScore(curScore, tagScore, isWin):
+    ## 计算对战增加积分
+    diffScore = curScore - tagScore # 积分差,有正负
+    calcScoreFormatDict = IpyGameDataPY.GetFuncEvalCfg("ArenaBattleAward", 1) if isWin else IpyGameDataPY.GetFuncEvalCfg("ArenaBattleAward", 2)
+    scoreKeyList = calcScoreFormatDict.keys()
+    scoreKeyList.sort()
+    calcKey = ""
+    for scoreKey in scoreKeyList:
+        if diffScore <= scoreKey:
+            calcKey = scoreKey
+            break
+        
+    if not calcKey:
+        return 0
+    
+    compileKey = "ArenaBattleScore_%s_%s" % (int(isWin), str(calcKey))
+    formatStr = calcScoreFormatDict[calcKey]
+    addScore = eval(FormulaControl.GetCompileFormula(compileKey, formatStr))
+    GameWorld.DebugLog("    计算得分公式: diffScore=%s,isWin=%s,compileKey=%s,formatStr=%s,addScore=%s" 
+                       % (diffScore, isWin, compileKey, formatStr, addScore))
+    return addScore
+
+#// A9 A8 查看竞技场对战记录 #tagCGQueryArenaBattleRecord
+#
+#struct    tagCGQueryArenaBattleRecord
+#{
+#    tagHead        Head;
+#};
+def OnQueryArenaBattleRecord(index, clientData, tick):
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    if not curPlayer:
+        return
+    __SyncArenaBattleRecord(curPlayer, [])
+    return
+
+def __SyncArenaBattleRecord(curPlayer, battleRecList):
+    ## 同步对战记录
+    if not battleRecList:
+        playerID = curPlayer.GetPlayerID()
+        battleRecList = GetPlayerArenaBattleRecList(playerID)
+        
+    clientPack = ChPyNetSendPack.tagGCArenaBattleRecordList()
+    clientPack.BattleRecordList = []
+    for battleRec in battleRecList:
+        recInfo = ChPyNetSendPack.tagGCArenaBattleRecord()
+        recInfo.PlayerID = battleRec.tagPlayerID
+        recInfo.Job = battleRec.tagJob
+        recInfo.LV = battleRec.tagLV
+        recInfo.AddScore = str(battleRec.addScore)
+        recInfo.AddScoreLen = len(recInfo.AddScore)
+        recInfo.IsWin = battleRec.isWin
+        recInfo.Time = battleRec.battleTime
+        
+        if recInfo.PlayerID > MaxRobotID:
+            curCache = PlayerViewCache.FindViewCache(recInfo.PlayerID)
+            if curCache:
+                cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+                recInfo.PlayerName = cacheDict["Name"]
+                recInfo.RealmLV = cacheDict["RealmLV"]
+                recInfo.FightPower = cacheDict["FightPower"]
+                
+        clientPack.BattleRecordList.append(recInfo)
+        
+    clientPack.RecordCount = len(clientPack.BattleRecordList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+
+
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
index b34e962..8860fd5 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -25,7 +25,6 @@
 # @change: "2014-02-27 12:00" hxp 增加世界boss逻辑
 # @change: "2014-04-26 19:30" hxp 增加领地战活动
 # @change: "2014-06-21 15:20" hxp 增加特惠活动
-# @change: "2014-08-04 17:30" xmnathan 天梯每日更新
 # @change: "2014-08-15 17:00" xmnathan 修改OnDay函数内的执行顺序
 # @change: "2014-10-08 10:30" xmnathan add 定时清理过期补偿
 # @change: "2014-10-29 22:00" hxp MapServerInitOK增加扩展key状态通知
@@ -97,6 +96,7 @@
 import IpyGameDataPY
 import PlayerFamilyParty
 import GameWorldFamilyWar
+import GameWorldArena
 import AuctionHouse
 import PlayerXMZZ
 import PlayerTeam
@@ -1235,6 +1235,8 @@
     ChPlayer.LoadPlayerLVData()
     #加载助战信息
     PlayerFBHelpBattle.OnServerStart()
+    #本服竞技场
+    GameWorldArena.OnServerStart()
     #跨服PK
     CrossRealmPK.OnGameServerInitOK()
     #世界boss被杀次数重置
@@ -1412,6 +1414,8 @@
     
     # 跨服PK
     CrossRealmPK.OnMapServerInitOK()
+    # 本服竞技场
+    GameWorldArena.SendMapServerArenaInfo()
     
     SendAllMapGlobalDropInfo() # 全局掉落控制
     
@@ -1926,6 +1930,7 @@
     PlayerTeam.OnServerClose(tick)
     ChPlayer.SavePlayerLVData()
     PlayerFBHelpBattle.OnServerClose()
+    GameWorldArena.OnServerClose()
     GameWorld.Log("通知C++关服!")
     GameWorld.GetGameWorld().OnServerClose()
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
index a165f35..efdfb0b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -61,6 +61,7 @@
 import PyGameData
 import GMShell
 import IPY_PlayerDefine
+import GameWorldArena
 import CrossRealmPK
 import AuctionHouse
 import PlayerAssist
@@ -183,6 +184,8 @@
         GameWorldActionControl.OnPlayerLogin(curPlayer)
         #玩家等级记录
         PyGameData.g_todayPlayerLVDict[curPlayer.GetID()] = curPlayer.GetLV()
+        #竞技场
+        GameWorldArena.OnPlayerLogin(curPlayer)
         #跨服PK
         CrossRealmPK.OnPlayerLogin(curPlayer)
         #诛仙BOSS
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
index 57e9abd..f604d6c 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerBillboard.py
@@ -151,6 +151,33 @@
     GameWorld.Log('billboardIndex %s clear.'%billboardIndex)
     return
 
+def UpdateBillboardMaxCount(billboardIndex, updMaxCount, isDelExtra=True):
+    ''' 变更竞技场榜单最大数据数
+    @param updMaxCount: 更新的最大数据排名
+    @param isDelExtra: 是否删除原榜单排名数据超过更新后的最大排名,默认删除
+    '''
+    billBoard = GameWorld.GetBillboard().FindBillboard(billboardIndex)
+    if not billBoard:
+        return
+    curCount = billBoard.GetCount()
+    curMaxCount = billBoard.GetMaxCount()
+    # 不超过程序内置配置的最大数量
+    if billboardIndex in ChConfig.Def_BT_Cnt:
+        updMaxCount = min(updMaxCount, ChConfig.Def_BT_Cnt[billboardIndex])
+    if curMaxCount == updMaxCount:
+        return
+    billBoard.SetMaxCount(updMaxCount)
+    GameWorld.Log("    变更榜单最大数据数! billboardIndex=%s,curCount=%s,curMaxCount=%s,updMaxCount=%s" 
+                  % (billboardIndex, curCount, curMaxCount, updMaxCount))
+    
+    # 清除多余榜单数据
+    if isDelExtra and curCount > updMaxCount:
+        for delIndex in xrange(curCount - 1, updMaxCount - 1, -1):
+            if delIndex >= 0:
+                GameWorld.Log("        DeleteByIndex: %s" % delIndex)
+                billBoard.DeleteByIndex(delIndex)
+    return
+
 ####################################################################################################
 
 #class   IPY_GSetWatchBillboardState
@@ -213,6 +240,9 @@
     if packType in ChConfig.Def_InterdictLook_BT_Type:
         #不可通过此封包查看
         return
+    if ChConfig.Def_BT_Cnt.get(packType, 0) > 100:
+        GameWorld.DebugLog("该榜单最大名次较大,需使用分页查询! A9 A2 查看排行榜#tagCPYWatchBillboard")
+        return
     if not __CheckWatchCD(curPlayer, packType, tick):
         return
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
index 1e4371b..fc99fab 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -12,7 +12,6 @@
 #
 # @change: "2011-02-23 14:20" panwei 系统提示函数重写
 # @change: "2011-07-15 19:30" Alee 队伍通知
-# @change: "2011-09-02 16:20" panwei 新增竞技场设置和获取决斗值接口
 # @change: "2012-11-06 15:00" jiang 新增竞威望设置和获取威望设接口
 # @change: "2012-11-07 17:30" wdb 新增跨服预选赛排位信息
 # @change: "2012-11-14 12:00" jiang 修改扩展属性字段记录的属性类型必须和MapServer一致
@@ -160,21 +159,6 @@
 
 
 #waring:以下使用的扩展属性字段记录的属性类型必须和MapServer一致
-#------------------------------------------------------------------------------ 
-##设置决斗值(竞技场用)
-# @param curPlayer 玩家
-# @param value 数值
-# @return None
-def SetVsFightValue(curPlayer, value):
-    return
-
-
-##获取决斗值(竞技场用)
-# @param curPlayer 玩家
-# @return 决斗值
-def GetVsFightValue(curPlayer):
-    return 0
-
 #------------------------------------------------------------------------------ 
 ## 设置威望
 #  @param curPlayer: 玩家实例
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
index 366cb50..1f74503 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
@@ -155,6 +155,8 @@
 Def_HorsePetBossTime = "HorsePetBossTime%s"
 #跨服服务器是否维护中
 Def_CrossServerClose = "CrossServerClose"
+#竞技场开服前定制X天赛季状态  0-未比赛过,1-进行中,>1结算时的开服天
+Def_ArenaOSSeasonState = "ArenaOSSeasonState"
 
 def SetInitOpenServerTime(initTime):
     openDatetime = GameWorld.ChangeTimeNumToDatetime(initTime)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
index cb2b1bd..5d0a9db 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -28,6 +28,7 @@
 import PlayerFBHelpBattle
 import PlayerFairyDomain
 import ChPyNetSendPack
+import GameWorldArena
 import NetPackCommon
 import PlayerDuJie
 #---------------------------------------------------------------------
@@ -81,6 +82,8 @@
     PlayerViewCache.DoOnDayEx()
     #缥缈OnDay
     PlayerFairyDomain.OnDayEx()
+    #竞技场
+    GameWorldArena.OnDayEx()
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
         curPlayer = playerManager.GetPlayerByIndex(i)
@@ -116,6 +119,9 @@
 
 def DoLogic_GameServer_OnWeekEx(tick):
     
+    # 竞技场
+    GameWorldArena.OnWeekEx()
+    
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
         curPlayer = playerManager.GetPlayerByIndex(i)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index 1401d34..42df784 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -74,6 +74,7 @@
 import AuctionHouse
 import PlayerFairyDomain
 import GameWorldSkyTower
+import GameWorldArena
 import GameWorldItem
 import PlayerAssist
 
@@ -934,6 +935,14 @@
             return
         resultName = '%s' % ret
     
+    # 竞技场
+    if callName =="Arena":
+        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
+        if not curPlayer:
+            return
+        ret = GameWorldArena.MapServer_Arena(curPlayer, eval(resultName))
+        resultName = '%s' % ret if ret != None else '' # 需要重置间隔,每次都回复
+        
     # 天星塔
     if callName == "SkyTower":
         ret = GameWorldSkyTower.MapServer_SkyTowerInfo(eval(resultName))
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
index 87ef793..2797827 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -21,6 +21,7 @@
 import GameWorld
 import PlayerControl
 import NetPackCommon
+import GameWorldArena
 import ChPyNetSendPack
 import PlayerFBHelpBattle
 import PyGameDataStruct
@@ -40,6 +41,9 @@
     if PlayerFBHelpBattle.IsInHelpBattleCheckInList(playerID):
         return True
     
+    if GameWorldArena.IsArenaBattlePlayer(playerID):
+        return True
+    
     SaveDBLimitLV = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1)
     #校验玩家等级
     if playerLV < SaveDBLimitLV:
@@ -50,6 +54,12 @@
 def IsSaveAllViewCache(playerID):
     ## 是否保存所有缓存数据
     
+    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(playerID):
+        return True
+    
+    if GameWorldArena.IsArenaBattlePlayer(playerID):
+        return True
+    
     NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
     #校验玩家是否上排行榜
     billboardMgr = GameWorld.GetBillboard()
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index 246e322..3d93548 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -83,6 +83,9 @@
 
 g_fbHelpBattleCheckInPlayerDict = {} # 副本助战玩家登记缓存 {playerID:HelpBattlePlayer, ...}
 
+g_arenaPlayerBattleRecDict = {} # 本服竞技场玩家挑战记录缓存 {playerID:[ArenaBattleRec, ...], ...}
+g_arenaPlayerMatchDict = {} # 本服竞技场玩家匹配记录缓存 {playerID:[ArenaMatchPlayer, ...], ...}
+
 g_autoViceleaderDict = {}#自动安排副盟主的玩家记录{familyID:[]}
 g_forbidAutoViceleaderFamily = [] #禁止自动安排副盟主的仙盟[familyID,..]
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index 29e074b..b4b8dfa 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -658,9 +658,10 @@
     Def_BT_Campaign_Wash,                     #洗练战力(开服活动榜)
     
     Def_BT_SkyTower,                          #天星塔榜
+    Def_BT_Arena,                             #竞技场榜
     
-    Def_BT_Max,                               #排行榜最大类型
-) = range(0, 27 + 2) 
+    Def_BT_Max, #排行榜最大类型
+) = range(0, 28 + 2) 
     
 #职业对应战力排行榜类型
 JobFightPowerBillboardDict = {
@@ -969,6 +970,7 @@
 GameFuncID_TJG = 147            # 脱机挂
 GameFuncID_SuperGift = 150      # 超值礼包
 GameFuncID_ZhuXianBoss = 163    # 诛仙BOSS
+GameFuncID_Arena = 189          # 竞技场
 # 以下为暂时无用的
 GameFuncID_Truck = 33           # 运镖
 GameFuncID_RunDaily = 34        # 日常跑环
@@ -1057,7 +1059,7 @@
                                 Def_UniversalGameRecType_LuckyTreasure, #幸运鉴宝大奖记录12
                                 Def_UniversalGameRecType_FairyDomain, #缥缈仙域事件次数记录13
                                 Def_UniversalGameRecType_Reward,    # 通用奖励表(TopBar)14
-                                Def_UniversalGameRecType_15,
+                                Def_UniversalGameRecType_ArenaBattleRecord, # 竞技场玩家挑战记录 15
                                 Def_UniversalGameRecType_16,
                                 Def_UniversalGameRecType_17,
                                 Def_UniversalGameRecType_18,
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 477c8b3..d29ef5c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1454,6 +1454,22 @@
 PacketSubCMD_2=0x11
 PacketCallFunc_2=OnRequestAssistTeamFB
 
+;竞技场
+[PlayerArena]
+ScriptName = Player\PlayerArena.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 2
+
+PacketCMD_1=0xB2
+PacketSubCMD_1=0x09
+PacketCallFunc_1=OnArenaMatch
+
+PacketCMD_2=0xB2
+PacketSubCMD_2=0x10
+PacketCallFunc_2=OnArenaBattle
+
 ;缥缈仙域
 [PlayerFairyDomain]
 ScriptName = Player\PlayerFairyDomain.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index e9887b5..9e49cce 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -457,6 +457,7 @@
 Def_Effect_HorsePetSkinExp = 253 #骑宠觉醒值
 Def_Effect_ItemGiveTreasureScore = 254      #使用道具给予寻宝积分
 Def_Effect_VIPLVCard = 256    #VIP等级直升卡 直接升到VIPx级,只加经验,享受VIP特权    效果值A: vip等级    效果值B: 领取是否默认直接使用
+Def_Effect_AddArenaBattleCount = 257    #增加竞技场挑战次数,A值为增加次数
 #----以下未使用或代码依然存在的---
 Def_Effect_ItemGiveGongXun = 1920        #使用道具给予功勋
 Def_Effect_ItemGiveRuneJH = 1925       #使用道具给予符印精华
@@ -1801,9 +1802,11 @@
 Def_FBMapID_CrossGrasslandLing = 32040
 #跨服仙草园
 Def_FBMapID_CrossGrasslandXian = 32050
+#竞技场战斗
+Def_FBMapID_ArenaBattle = 31290
 
 #前端自定义场景地图
-ClientCustomScene = [Def_FBMapID_PersonalBoss]
+ClientCustomScene = [Def_FBMapID_PersonalBoss, Def_FBMapID_ArenaBattle]
 
 #注册上传跨服服务器数据后直接进入跨服服务器的地图
 RegisterEnter_CrossServerMapIDList = [Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
@@ -1911,6 +1914,7 @@
                 'Guard':[Def_FBMapID_Guard], #守护副本
                 'SealDemon':[Def_FBMapID_SealDemon, Def_FBMapID_SealDemonEx], #封魔坛
                 'XMZZ':[Def_FBMapID_XMZZ], #仙魔之争
+                'ArenaBattle':[Def_FBMapID_ArenaBattle],#竞技场战斗
                 'CrossRealmPK':[Def_FBMapID_CrossRealmPK], #跨服竞技场
                 'CrossDemonKing':[Def_FBMapID_DemonKing, Def_FBMapID_CrossDemonKing], #妖王
                 'CrossGrassland':[Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian], #草园
@@ -2222,6 +2226,7 @@
                          1000 * 1,                        # vip体验时效
                          1000 * 1,                        # 限时抢购
                          1000 * 5,                        # 请求协助间隔
+                         1000 * 10,                        # 竞技场间隔
                          ]
 TYPE_Player_Tick_Count = len(TYPE_Player_Tick_Time) 
 
@@ -2296,6 +2301,7 @@
 TYPE_Player_Tick_VIPExperience,        #vip体验时效
 TYPE_Player_Tick_FlashSale,        #限时抢购
 TYPE_Player_Tick_RequestAssist,        #请求协助间隔
+TYPE_Player_Tick_Arena,        #竞技场间隔
 ) = range(0, TYPE_Player_Tick_Count)
 
 #---------------------------------------------------------------------
@@ -4015,6 +4021,14 @@
 Def_PDict_TodayAssistMoney = "TodayAssistMoney" # 今日已获得协助货币奖励
 Def_PDict_TodayAssistMoneySocial = "TodayAssistMoneySocial" # 今日已获得协助货币 社交关系额外加成
 
+#竞技场
+Def_PDict_ArenaOSSeasonState = "ArenaOSSeasonState" # 开服前定制X天赛季状态  0-未比赛过,1-进行中,>1结算时的开服天
+Def_PDict_ArenaScore = "ArenaScore" # 当前积分
+Def_PDict_ArenaBattleCountDay = "ArenaBattleCountDay" # 今日已战斗次数
+Def_PDict_ArenaMatchRefreshCount = "ArenaMatchRefreshCount" # 匹配刷新列表次数
+Def_PDict_ArenaItemAddCount = "ArenaItemAddCount" # 今日已使用物品增加次数
+Def_PDict_ArenaBattleTagID = "ArenaBattleTagID" # 当前对战的对手ID
+
 #-------------------------------------------------------------------------------
 #可以从07 41封包购买的背包类型,和对应字典{背包类型:[字典key, 默认格子数]}
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
index d10e480..97c439b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
@@ -47,7 +47,6 @@
 # @change: "2014-06-23 14:30" Alee 关闭输出
 # @change: "2014-07-24 21:30" hxp 增加设置跑环任务星级,一键完成所有跑环任务
 # @change: "2014-07-31 21:30" hxp 取消红名不能与NPC对话限制
-# @change: "2014-08-08 10:00" hxp 增加天梯竞技场任务事件触发
 # @change: "2014-08-26 11:00" hxp NotifyOneMission增加参数选择是否同步该任务全部字典信息
 # @change: "2014-12-25 16:10" ljd 同步上一次背包开格时间
 # @change: "2015-01-10 23:00" hxp 仓库购买特殊处理
@@ -1456,13 +1455,6 @@
 # @return 返回值无意义
 def EventRespons_FBEvent(curPlayer, eventName):
     RunQuestEvent(curPlayer, "fb_event", eventName, Def_RunQuestType_Normal)
-    
-##天梯竞技场事件触发
-# @param curPlayer 玩家实例
-# @param eventName 事件名
-# @return 返回值无意义
-def EventRespons_ArenaEvent(curPlayer, eventName):
-    RunQuestEvent(curPlayer, "arena_event", eventName, Def_RunQuestType_Normal)
 
 
 ##添加好友成功触发
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
index 7dedfe8..dc7c070 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
@@ -32,7 +32,6 @@
 # @change: "2014-06-05 15:30" hxp 商店NPC物品购买增加每日可购买次数上限支持
 # @change: "2014-08-04 16:00" Alee 套装物品商店修改
 # @change: "2014-08-07 20:40" Alee 宝藏积分兑换卓越属性装备固定2条属性
-# @change: "2014-08-12 11:30" xmnathan 天梯竞技 点数购买绑定
 # @change: "2014-10-20 16:20" Alee 兑换套装3卓越
 # @change: "2014-11-05 15:00" Alee 商店购买绑定修改
 # @change: "2014-12-11 16:30" hxp 商店兑换装备增加支持配置装备对应卓越条数
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/QuestRunner.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/QuestRunner.py
index fed877d..f263d1c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/QuestRunner.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/QuestRunner.py
@@ -2436,16 +2436,6 @@
     return startM <= curMinute <= overM
 
 #---------------------------------------------------------------------
-##竞技场活动是否开启
-# @param curPlayer 玩家实例
-# @param curMission 任务实例
-# @param curConditionNode 节点信息
-# @return 返回值, 是否判断成功
-# @remarks <Check_Vsroomisbegin result="期望值"/> 
-def ConditionType_Check_Vsroomisbegin(curPlayer, curMission, curConditionNode):
-    return
-
-#---------------------------------------------------------------------
 ##指定任务类型个数是否达到指定数
 # @param curPlayer 玩家实例
 # @param curMission 任务实例
@@ -3950,19 +3940,6 @@
 # @remarks  <Lost_Money_By_Lv moneytype=""/> 
 def DoType_Lost_Money_By_Lv(curPlayer, curMission, curActionNode):
     return
-    
-#---------------------------------------------------------------------
-##扣除竞技点
-# @param curPlayer 玩家实例
-# @param curMission 任务实例
-# @param curActionNode节点信息
-# @return 返回值无意义
-# @remarks  <DoType_Lost_Vspoint value=""/> 
-def DoType_Lost_Vspoint(curPlayer, curMission, curActionNode):
-    value = int(curActionNode.GetAttribute("value"))
-    PlayerControl.ReduceVsSportsPoint(curPlayer, value)
-    return
-
 #---------------------------------------------------------------------
 ##开通仓库
 # @param curPlayer 玩家实例
@@ -6404,22 +6381,6 @@
     conditionValue = GameWorld.ToIntDef(curConditionNode.GetAttribute("value"), 0)
     fbpasslv = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MWFBPassLevel % mwid)
     return fbpasslv >= conditionValue
-
-#---------------------------------------------------------------------
-##是否拥有足够的竞技点
-# @param curPlayer 玩家实例
-# @param curMission 任务实例
-# @param curConditionNode节点信息
-# @return 返回值, 是否通过检查
-# @remarks  <Have_Vspoint value="数值", result="期望的结果" /> 
-def ConditionType_Have_Vspoint(curPlayer, curMission, curConditionNode):
-    result = GameWorld.ToIntDef(curConditionNode.GetAttribute("result"), 0)
-    value = GameWorld.ToIntDef(curConditionNode.GetAttribute("value"), 0)
-    
-    if PlayerControl.GetVsSportsPoint(curPlayer) >= value:
-        return 1 == result
-    
-    return 0 == result
 
 #---------------------------------------------------------------------
 ##是否家族长
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Arena.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Arena.py
new file mode 100644
index 0000000..ed4202e
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Arena.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.Arena
+#
+# @todo:竞技场
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 竞技场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerControl
+import PlayerBillboard
+import GameFuncComm
+import PlayerArena
+import ChConfig
+
+## GM命令执行入口
+#  @param curPlayer 当前玩家
+#  @param msgList 参数列表 [addSkillID]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, msgList):
+    
+    if not msgList:
+        GameWorld.DebugAnswer(curPlayer, "重置玩家竞技场: Arena 0")
+        GameWorld.DebugAnswer(curPlayer, "设置玩家积分: Arena 积分")
+        GameWorld.DebugAnswer(curPlayer, "重置赛季直接用 test_OnWeek (需开服7天后)")
+        return
+    
+    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
+        GameWorld.DebugAnswer(curPlayer, "竞技场功能未开启!")
+        return
+    
+    value1 = msgList[0]
+    if value1 <= 0:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaOSSeasonState, 0)
+        PlayerArena.__DoArenaSeasonReset(curPlayer)
+        GameWorld.DebugAnswer(curPlayer, "重置成功!")
+        return
+    
+    else:
+        GameWorld.DebugAnswer(curPlayer, "设置竞技场积分: %s" % value1)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, value1)
+        PlayerArena.Sync_ArenaInfo(curPlayer)
+        
+        # 同步排行榜
+        cmpValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+        cmpValue2 = curPlayer.GetFightPower()
+        cmpValue3 = 0
+        value1 = curPlayer.GetOfficialRank()
+        value2 = curPlayer.GetLV()
+        PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Arena, cmpValue, cmpValue2, cmpValue3, value1, value2)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_ArenaBattle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_ArenaBattle.py
new file mode 100644
index 0000000..c71d235
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_ArenaBattle.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_ArenaBattle
+#
+# @todo:竞技场战斗
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 竞技场战斗,目前主要做自定义副本流程桥梁吧,暂时没什么额外逻辑,战斗过程前端自行处理,后端只处理击杀木桩后结算
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import PlayerArena
+
+## 是否能够通过活动查询进入
+def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
+    return True
+
+## 是否需要做进入副本通用检查条件逻辑,默认需要检查
+def OnNeedCheckCanEnterFBComm(curPlayer, mapID, lineID):
+    ## 进行中的不需要重复检查,防止断线重连被禁止进入
+    return False
+
+## 客户端进入自定义场景
+def OnEnterCustomScene(curPlayer, mapID, lineID):
+    return
+
+## 判断可否召唤木桩怪
+def OnCanSummonPriWoodPile(curPlayer, mapID, lineID, npcID, count):
+    return True
+
+## 自定义场景副本击杀NPC
+def DoCustomScene_Player_KillNPC(curPlayer, curNPC, mapID, lineID):
+    PlayerArena.OnKillBattleNPC(curPlayer, curNPC)
+    return
+
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
index 2c13293..7baaa44 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
@@ -726,6 +726,7 @@
                             ChConfig.Def_Effect_VIPLVCard:"Item_VIPLVCard", # VIP等级直升卡
                             ChConfig.Def_Effect_ResetBossKillCnt:"Item_ResetBossKillCnt", # 重置boss击杀疲劳
                             ChConfig.Def_Effect_AddFBCnt:"Item_AddFBCnt", # 增加副本可进入次数
+                            ChConfig.Def_Effect_AddArenaBattleCount:"Item_AddArenaBattleCount", # 增加竞技场挑战次数
                             ChConfig.Def_Effect_AddKillBossCnt:"Item_AddKillBossCnt", # 增加BOSS可击杀次数
                             ChConfig.Def_Effect_AddMagicWeaponUpExp:"Item_AddMagicWeaponUpExp", # 增加法宝升星经验
                             ChConfig.Def_Effect_ChatBubbleBox:"Item_ChatBubbleBox", # 激活聊天气泡框
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
index 852fbcc..1a224f2 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -2638,6 +2638,8 @@
 
 def GivePlayerItemOrMail(curPlayer, itemList, mailKey=None, event=["", False, {}]):
     ##给物品,背包满则发邮件
+    if not itemList:
+        return
     needPackSpaceDict = {}
     for itemID, itemCnt, isAuctionItem in itemList:
         curItem = GameWorld.GetGameData().GetItemByTypeID(itemID)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddArenaBattleCount.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddArenaBattleCount.py
new file mode 100644
index 0000000..cfe6ed8
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_AddArenaBattleCount.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package UseItem.Item_AddArenaBattleCount
+#
+# @todo:增加竞技场挑战次数
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 增加竞技场挑战次数
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import ItemCommon
+import PlayerControl
+import PlayerArena
+import ChConfig
+
+#------------------------------------------------------------------------------ 
+
+#------------------------------------------------------------------------------ 
+##使用物品,触发物品附加效果 增加BOSS可击杀次数
+# @param curPlayer 玩家实例
+# @param curRoleItem 物品实例
+# @param tick 时间戳
+# @return 是否使用物品成功
+# @remarks 使用物品,触发物品附加效果
+def BatchUseItem(curPlayer, curRoleItem, tick, useCnt, exData):
+    useItemEff = curRoleItem.GetEffectByIndex(0)
+    addCnt = useItemEff.GetEffectValue(0) * useCnt
+    if addCnt <= 0:
+        return
+    
+    updItemAddCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaItemAddCount) + addCnt
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaItemAddCount, updItemAddCount)
+    PlayerArena.Sync_ArenaInfo(curPlayer)
+    
+    #扣除物品
+    ItemCommon.DelItem(curPlayer, curRoleItem, useCnt)
+    
+    # 竞技场挑战次数增加<color=#109d06FF>%s0</color>次
+    PlayerControl.NotifyCode(curPlayer, "ArenaBattleCountAdd", [addCnt])
+    return True
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 b48fdb8..2f6b764 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -112,6 +112,7 @@
 import ChNetSendPack
 import FamilyRobBoss
 import FBHelpBattle
+import PlayerArena
 import PyGameData
 import PlayerCoin
 import PlayerGeTui
@@ -626,6 +627,9 @@
     # 跨服PK
     PlayerCrossRealmPK.DoPlayerLogin(curPlayer)
     
+    # 竞技场
+    PlayerArena.OnLogin(curPlayer)
+    
     # 自定义货币值同步
     PlayerControl.NotifyPlayerAllCurrency(curPlayer)
     #通知基础属性
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
index 2900423..a943dd9 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
@@ -44,6 +44,7 @@
 import IPY_GameWorld
 import ItemCommon
 import ItemControler
+import PlayerArena
 import PlayerTJG
 
 
@@ -65,6 +66,7 @@
                      ShareDefine.GameFuncID_AddPoint:lambda curObj:PlayerControl.DoAddPointOpen(curObj),
                      ShareDefine.GameFuncID_Talent:lambda curObj:PlayerGreatMaster.DoTalentOpen(curObj),
                      ShareDefine.GameFuncID_TJG:lambda curObj:PlayerTJG.DoTJGOpen(curObj),
+                     ShareDefine.GameFuncID_Arena:lambda curObj:PlayerArena.DoArenaOpen(curObj),
                      #ShareDefine.GameFuncID_RunDaily:lambda curObj:FBCommon.DoFuncOpen_RunDaily(curObj),
                      #ShareDefine.GameFuncID_RunFamily:lambda curObj:FBCommon.DoFuncOpen_RunFamily(curObj),
                      #ShareDefine.GameFuncID_RefineExp:lambda curObj:Operate_PlayerBuyZhenQi.DoFuncOpen_RefineExp(curObj),
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
new file mode 100644
index 0000000..770b755
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
@@ -0,0 +1,336 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerArena
+#
+# @todo:竞技场 - 本服
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 竞技场 - 本服
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import ShareDefine
+import GameFuncComm
+import PlayerControl
+import IpyGameDataPY
+import ChPyNetSendPack
+import NetPackCommon
+import GameWorld
+import ChConfig
+import FBCommon
+import IPY_GameWorld
+import ItemControler
+
+def DoArenaOpen(curPlayer):
+    ## 竞技场功能开启
+    __DoArenaSeasonReset(curPlayer)
+    return
+
+def OnLogin(curPlayer):
+    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
+        return
+    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
+    if not OSSeasonState:
+        __DoArenaSeasonReset(curPlayer)
+    else:
+        Sync_ArenaInfo(curPlayer)
+    return
+
+def OnDayEx(curPlayer):
+    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaItemAddCount, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
+    Sync_ArenaInfo(curPlayer)
+    
+    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    if openServerDay <= customMaxServerDay:
+        GameWorld.DebugLog("OnDayEx时竞技场开服定制赛季进行中,不处理! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
+        return
+    
+    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
+    if OSSeasonState > 1:
+        GameWorld.DebugLog("OnDayEx时竞技场开服定制赛季已结算过,不处理! OSSeasonState=%s" % (OSSeasonState))
+        return
+    
+    __DoArenaSeasonReset(curPlayer)
+    return
+
+def OnWeekEx(curPlayer):
+    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
+        return
+    
+    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    if openServerDay <= customMaxServerDay:
+        GameWorld.DebugLog("OnWeekEx时在开服定制天内,不处理竞技场赛季重置! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
+        return
+    
+    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
+    if not OSSeasonState or OSSeasonState == 1 or OSSeasonState == openServerDay:
+        GameWorld.DebugLog("OnWeekEx时竞技场开服定制赛季进行中或同一天结算,不处理重置! openServerDay=%s,OSSeasonState=%s" % (openServerDay, OSSeasonState))     
+        return
+    
+    __DoArenaSeasonReset(curPlayer)
+    return
+
+def __DoArenaSeasonReset(curPlayer):
+    ## 玩家重置竞技场
+    
+    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
+    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+    
+    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
+    if openServerDay <= customMaxServerDay and OSSeasonState != 0:
+        GameWorld.DebugLog("开服定制天内不能重置!")
+        return
+    
+    minScore, maxScore = IpyGameDataPY.GetFuncEvalCfg("ArenaSet", 1)
+    setScore = minScore
+    if openServerDay <= customMaxServerDay and OSSeasonState == 0:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaOSSeasonState, 1)
+        GameWorld.DebugLog("竞技场开服定制赛季! setScore=%s" % setScore)
+    else:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaOSSeasonState, customMaxServerDay + 1)
+        
+        # 按比例降低积分,都减去最低分的差值算比例
+        setScoreMax = IpyGameDataPY.GetFuncCfg("ArenaSet", 2)
+        preSeasonscore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+        if preSeasonscore <= minScore:
+            setScore = minScore
+        elif preSeasonscore >= maxScore:
+            setScore = setScoreMax
+        else:     
+            calcScore = preSeasonscore - minScore
+            setScore = minScore + int(calcScore * (setScoreMax - minScore) / float(maxScore - minScore))
+            
+        GameWorld.DebugLog("竞技场赛季重置! preSeasonscore=%s,setScore=%s" % (preSeasonscore, setScore))
+        
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, setScore)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaItemAddCount, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
+    Sync_ArenaInfo(curPlayer)
+    return
+
+def CheckArenaBattleCount(curPlayer):
+    ## 验证是否还有对战次数
+    todayBattleCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay)
+    itemAddCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaItemAddCount)
+    dayFreeCount = IpyGameDataPY.GetFuncCfg("ArenaSet", 3)
+    return todayBattleCount < (dayFreeCount + itemAddCount)
+
+#// B2 09 竞技场匹配玩家 #tagCMArenaMatch
+#
+#struct    tagCMArenaMatch
+#{
+#    tagHead         Head;
+#    BYTE        IsRefresh;    // 0-打开界面无匹配数据时时查询,1-强制刷新匹配列表
+#};
+def OnArenaMatch(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    isRefresh = clientData.IsRefresh
+    
+    playerID = curPlayer.GetPlayerID()
+    refreshCountLimit = IpyGameDataPY.GetFuncCfg("ArenaSet", 5)
+    if isRefresh and refreshCountLimit:
+        refreshCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount)
+        if refreshCount >= refreshCountLimit:
+            GameWorld.DebugLog("竞技场刷新匹配玩家次数已满!refreshCount=%s >= %s" % (refreshCount, refreshCountLimit), playerID)
+            return
+        
+    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Arena, tick):
+        GameWorld.DebugLog("竞技场匹配操作CD中...", playerID)
+        PlayerControl.NotifyCode(curPlayer, "RequestLater")
+        return
+    
+    playerLV = curPlayer.GetLV()
+    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    msgInfo = str(["MatchRefresh", {"isRefresh":isRefresh, "playerLV":playerLV, "playerScore":playerScore}])
+    GameWorld.DebugLog("竞技场发送GameServer匹配: %s" % msgInfo, playerID)
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "Arena", msgInfo, len(msgInfo))
+    return
+
+#// B2 10 竞技场挑战玩家 #tagCMArenaBattle
+#
+#struct    tagCMArenaBattle
+#{
+#    tagHead         Head;
+#    DWORD        TagPlayerID;    // 目标玩家ID或机器人ID
+#    BYTE        Result;    // 0-进入自定义场景发送通知后端;1-胜利(后端处理,暂时不需要发送此状态);2-失败(前端被对手击杀需要发送此状态)
+#};
+def OnArenaBattle(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    tagPlayerID = clientData.TagPlayerID
+    result = clientData.Result
+    
+    GameWorld.DebugLog("竞技场挑战玩家! tagPlayerID=%s,result=%s" % (tagPlayerID, result), playerID)
+    if not tagPlayerID:
+        return
+    
+    if not result:
+        GameWorld.DebugLog("更新竞技场对战对手ID! tagPlayerID=%s" % tagPlayerID, playerID)
+        # 记录对手ID
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleTagID, tagPlayerID)
+        return
+    
+    isWin = 1 if result == 1 else 0
+    # 木桩被击杀,后端判断,其他前端同步
+    if isWin:
+        GameWorld.ErrLog("前端不能同步竞技场胜利状态!", playerID)
+        return
+    
+    recTagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
+    GameWorld.DebugLog("竞技场被对手击杀! tagPlayerID=%s,recTagPlayerID=%s" % (tagPlayerID, recTagPlayerID), playerID)
+    if tagPlayerID != recTagPlayerID:
+        GameWorld.ErrLog("竞技场结算时对手ID不一致! tagPlayerID(%s) != recTagPlayerID(%s)" % (tagPlayerID, recTagPlayerID), playerID)
+        __DoArenaBattleOver(curPlayer)
+        return
+    
+    # 失败结算入口: 前端同步
+    SendGameServer_ArenaBattleOver(curPlayer, isWin)
+    return
+
+def OnKillBattleNPC(curPlayer, curNPC):
+    ## 击杀对手,前端本,使用木桩NPC作为对手
+    
+    if curNPC.GetGameObjType() != IPY_GameWorld.gotNPC or curNPC.GetType() not in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
+        GameWorld.DebugLog("击杀非木桩NPC,不结算!")
+        return
+    
+    # 胜利结算入口:后端验证击杀对手
+    tagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
+    GameWorld.DebugLog("竞技场击杀对手! tagPlayerID=%s" % tagPlayerID, curPlayer.GetPlayerID())
+    isWin = 1
+    SendGameServer_ArenaBattleOver(curPlayer, isWin)
+    return
+
+def SendGameServer_ArenaBattleOver(curPlayer, isWin):
+    ## 发送GameServer通知战斗结算
+    
+    playerID = curPlayer.GetPlayerID()
+    tagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
+    if not tagPlayerID:
+        GameWorld.ErrLog("竞技场结算时没有对手ID!", playerID)
+        __DoArenaBattleOver(curPlayer)
+        return
+    
+    if not CheckArenaBattleCount(curPlayer):
+        GameWorld.ErrLog("竞技场已经没有对战次数!", playerID)
+        __DoArenaBattleOver(curPlayer)
+        return
+    
+    tick = GameWorld.GetGameWorld().GetTick()
+    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Arena, tick):
+        GameWorld.ErrLog("结算竞技场CD中!tagPlayerID=%s" % tagPlayerID, playerID)
+        return
+    
+    playerLV = curPlayer.GetLV()
+    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    msgInfo = str(["BattleResult", {"tagPlayerID":tagPlayerID, "isWin":isWin, "playerLV":playerLV, "playerScore":playerScore, 
+                                    "realmLV":curPlayer.GetOfficialRank(), "fightPower":curPlayer.GetFightPower()}])
+    GameWorld.DebugLog("竞技场发送GameServer结算: %s" % msgInfo, playerID)
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "Arena", msgInfo, len(msgInfo))
+    return
+
+def __DoArenaBattleOver(curPlayer, retDict={}):
+    ## 主动战斗结算奖励
+    # @param isOK: True时才结算奖励,防止某些异常情况无法结算通知前端FBOver,导致卡副本
+    
+    GameWorld.DebugLog("结算竞技场对战奖励! retDict=%s" % retDict)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleTagID, 0)
+    
+    isOK = retDict.get("isOK", False)
+    isWin = retDict.get("isWin", 0)
+    if not isOK:
+        # 一直异常的情况直接同步结束包,防止不结算卡副本
+        FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_ArenaBattle, 0, isWin)
+        return
+    
+    #GameServer MapServer 同步有一定时间差,本功能存在被动挑战引发积分变动的情况,
+    #curScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    addScore = retDict["addScore"]
+    updScore = retDict["updScore"]
+    curOrder = retDict["curOrder"]
+    updOrder = retDict["updOrder"]
+    
+    # 扣次数
+    todayBattleCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay) + 1
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, todayBattleCount)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
+        
+    # 更新积分
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, updScore)
+    
+    # 胜利给额外奖励
+    itemList = retDict.get("awardItemList", [])
+    ItemControler.GivePlayerItemOrMail(curPlayer, itemList)
+    jsonItemList = FBCommon.GetJsonItemList(itemList)
+    
+    overDict = {FBCommon.Over_itemInfo:jsonItemList, "addScore":addScore, "updScore":updScore, "curOrder":curOrder, "updOrder":updOrder}
+    FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_ArenaBattle, 0, isWin, overDict)
+    Sync_ArenaInfo(curPlayer)
+    return
+
+def __DoUpdateArenaScore(curPlayer, cmdDict={}):
+    ''' 玩家直接更新积分,有以下几种情况,都是被挑战的,只更新积分
+    1. 被动挑战在线时直接更新积分
+    2. 离线/脱机时被挑战,上线后同步最新积分
+    '''
+    
+    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    updScore = cmdDict.get("updScore", playerScore)
+    if updScore == playerScore:
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, updScore)
+    Sync_ArenaInfo(curPlayer)
+    return
+
+def GameServer_ArenaResult(curPlayer, msgList, tick):
+    if not msgList:
+        return
+    
+    cmd = msgList[0]
+    cmdDict = msgList[1] if len(msgList) > 1 else {}
+    retDict = msgList[2] if len(msgList) > 2 else {}
+    
+    # 刷新匹配
+    if cmd == "MatchRefresh":
+        isRefresh = cmdDict.get("isRefresh", False)
+        refreshCountLimit = IpyGameDataPY.GetFuncCfg("ArenaSet", 5)
+        if isRefresh and refreshCountLimit:
+            updRefreshCount = min(250, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount) + 1)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, updRefreshCount)
+            GameWorld.DebugLog("更新竞技场刷新匹配次数! updRefreshCount=%s" % updRefreshCount)
+            Sync_ArenaInfo(curPlayer)
+            
+    # 主动对战结果
+    elif cmd == "BattleResult":
+        __DoArenaBattleOver(curPlayer, retDict)
+        
+    # 被动挑战更新积分
+    elif cmd == "UpdScore":
+        __DoUpdateArenaScore(curPlayer, cmdDict)
+        
+    return
+
+def Sync_ArenaInfo(curPlayer):
+    clientPack = ChPyNetSendPack.tagMCArenaPlayerInfo()
+    clientPack.Score = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    clientPack.BattleCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay)
+    clientPack.MatchRefreshCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount)
+    clientPack.ItemAddBattleCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaItemAddCount)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    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 ea7c8fc..7dd2c75 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -6160,55 +6160,6 @@
 #===============================================================================
 # #@warning: ExAttr6~ExAttr10, 新增2个布尔默认参数, 是否通知客户端, 是否通知GameServer, 默认值为False
 #===============================================================================
-##设置决斗值(竞技场用)
-# @param curPlayer 玩家
-# @param value 数值
-# @return None
-def SetVsFightValue(curPlayer, value):
-    return
-
-##获取决斗值(竞技场用)
-# @param curPlayer 玩家
-# @return 决斗值
-def GetVsFightValue(curPlayer):
-    return 0
-
-##获取竞技点(竞技场用)
-# @param curPlayer 玩家
-# @return 竞技点
-def GetVsSportsPoint(curPlayer):
-    return 0
-
-##设置竞技点(不可直接调用)
-# @param curPlayer 玩家
-# @return 
-def __SetVsSportsPoint(curPlayer, value):
-    return
-
-##竞技点减少(竞技场用)
-# @param curPlayer 玩家
-# @return 
-def ReduceVsSportsPoint(curPlayer, value):
-    curValue = GetVsSportsPoint(curPlayer)
-    #调用接口
-    __SetVsSportsPoint(curPlayer, max(0, curValue - value))
-    #lostValue 您失去了{%S1%}点竞技点
-    NotifyCode(curPlayer, "Arena_pan_474794", [value])
-    return    
-    
-##获得龙脉等级
-# @param curPlayer 玩家
-# @return 龙脉等级
-def GetLongMaiLV(curPlayer):
-    return 0
-
-
-##设置龙脉等级
-# @param curPlayer 玩家
-# @param value 数值
-# @return None
-def SetLongMaiLV(curPlayer, value):
-    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 81d9dd6..00a3214 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -99,6 +99,7 @@
 import FBHelpBattle
 import QuestManager
 import PlayerAssist
+import PlayerArena
 import PyGameData
 import PlayerTJG
 
@@ -557,6 +558,8 @@
         PlayerFairyDomain.OnDay(curPlayer)
         #仙盟宴会
         GameLogic_FamilyParty.OnDayFamilyPartyPlayer(curPlayer)
+        #竞技场
+        PlayerArena.OnDayEx(curPlayer)
         #协助
         PlayerAssist.DoPlayerOnDay(curPlayer)
         
@@ -686,6 +689,8 @@
     elif onEventType == ShareDefine.Def_OnEventTypeEx:
         #触发每周任务重置脚本
         EventShell.EventResponse_OnWeek(curPlayer)
+        #竞技场
+        PlayerArena.OnWeekEx(curPlayer)
         PlayerFamily.OnWeekEx(curPlayer)
     
     # 以下为支持两种重置模式切换配置的
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Arena.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Arena.py
new file mode 100644
index 0000000..b5f40cc
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Arena.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_Arena
+#
+# @todo:竞技场
+# @author hxp
+# @date 2020-12-07
+# @version 1.0
+#
+# 详细描述: 竞技场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-07 19:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerArena
+import ChConfig
+
+#---------------------------------------------------------------------
+#逻辑实现
+## 请求逻辑
+#  @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):
+    GameWorld.DebugLog("GY_Query_Arena DoLogic %s" % str(packCMDList), query_ID)
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(query_ID)
+    if not curPlayer or curPlayer.IsEmpty():
+        return
+    PlayerArena.GameServer_ArenaResult(curPlayer, packCMDList, tick)
+    return ""
+
+#---------------------------------------------------------------------
+#执行结果
+## 执行结果
+#  @param curPlayer 发出请求的玩家
+#  @param callFunName 功能名称
+#  @param funResult 查询的结果
+#  @param tick 当前时间
+#  @return None
+#  @remarks 函数详细说明.
+def DoResult(curPlayer, callFunName, funResult, tick):
+    GameWorld.DebugLog("GY_Query_Arena DoResult %s" % str(funResult), curPlayer.GetPlayerID())
+    if funResult != "":
+        PlayerArena.GameServer_ArenaResult(curPlayer, eval(funResult), tick)
+    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_Arena, 0)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index 29e074b..b4b8dfa 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -658,9 +658,10 @@
     Def_BT_Campaign_Wash,                     #洗练战力(开服活动榜)
     
     Def_BT_SkyTower,                          #天星塔榜
+    Def_BT_Arena,                             #竞技场榜
     
-    Def_BT_Max,                               #排行榜最大类型
-) = range(0, 27 + 2) 
+    Def_BT_Max, #排行榜最大类型
+) = range(0, 28 + 2) 
     
 #职业对应战力排行榜类型
 JobFightPowerBillboardDict = {
@@ -969,6 +970,7 @@
 GameFuncID_TJG = 147            # 脱机挂
 GameFuncID_SuperGift = 150      # 超值礼包
 GameFuncID_ZhuXianBoss = 163    # 诛仙BOSS
+GameFuncID_Arena = 189          # 竞技场
 # 以下为暂时无用的
 GameFuncID_Truck = 33           # 运镖
 GameFuncID_RunDaily = 34        # 日常跑环
@@ -1057,7 +1059,7 @@
                                 Def_UniversalGameRecType_LuckyTreasure, #幸运鉴宝大奖记录12
                                 Def_UniversalGameRecType_FairyDomain, #缥缈仙域事件次数记录13
                                 Def_UniversalGameRecType_Reward,    # 通用奖励表(TopBar)14
-                                Def_UniversalGameRecType_15,
+                                Def_UniversalGameRecType_ArenaBattleRecord, # 竞技场玩家挑战记录 15
                                 Def_UniversalGameRecType_16,
                                 Def_UniversalGameRecType_17,
                                 Def_UniversalGameRecType_18,

--
Gitblit v1.8.0