From 2b91d1223f3d78bd2efa970478d1ed63666e131c Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 10 十二月 2025 11:40:43 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(优化演武场匹配逻辑;)
---
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py | 2
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py | 36 ++++++++
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py | 191 +++++++++++++++++++++++++++++++----------------
3 files changed, 162 insertions(+), 67 deletions(-)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
index b907893..2bd50a4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
@@ -22,6 +22,7 @@
import IpyGameDataPY
import IPY_GameWorld
import PlayerEventCounter
+import PlayerViewCache
import PlayerControl
import NetPackCommon
import PlayerOnline
@@ -83,6 +84,7 @@
GameWorld.Log("服务器启动初始化InitGameWorld: serverID=%s" % serverID)
DBDataMgr.OnServerStart() # 优先加载公共数据
LoadDBPlayer()
+ PlayerViewCache.LoadRobot()
PyGameData.g_initGameTime = int(time.time()) # 放到加载数据之后
#初始话开服时间、星期几
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
index 92bd1af..0120ebe 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
@@ -215,12 +215,12 @@
playerID = curPlayer.GetPlayerID()
playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
matchScoreList = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 1)
+ needMatchCount = len(matchScoreList)
GameWorld.DebugLog("竞技场玩家刷新匹配列表: isRefresh=%s,playerScore=%s,gmMatchIDList=%s,isSys=%s" % (isRefresh, playerScore, gmMatchIDList, isSys), playerID)
- GameWorld.DebugLog(" matchScoreList=%s" % (matchScoreList), playerID)
+ GameWorld.DebugLog("needMatchCount=%s,matchScoreList=%s" % (needMatchCount, matchScoreList), playerID)
# 匹配对象缓存
- needMatchCount = len(matchScoreList)
if playerID not in PyGameData.g_arenaPlayerMatchDict:
PyGameData.g_arenaPlayerMatchDict[playerID] = []
matchIDList = PyGameData.g_arenaPlayerMatchDict[playerID]
@@ -236,69 +236,124 @@
if not costMoney or not moneyValue or not PlayerControl.PayMoney(curPlayer, costMoney, moneyValue, "Arena"):
return
- billboardMgr = DBDataMgr.GetBillboardMgr()
- billBoard = billboardMgr.GetBillboard(ShareDefine.Def_BT_Arena)
- if not billBoard:
- return
- maxOrder = billBoard.GetCount()
- playerOrder = billBoard.IndexOfByID(playerID) + 1 # 玩家在排行榜中的名次,没有名次为-1
-
- matchRobotCntDict = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 3)
- if playerOrder > 0:
- matchRobotRange = GameWorld.GetOrderValueByDict(matchRobotCntDict, playerOrder)
- matchRobotCnt = random.randint(matchRobotRange[0], matchRobotRange[1])
- else:
- matchRobotCnt = needMatchCount
- matchPlayerCnt = needMatchCount - matchRobotCnt
- GameWorld.DebugLog(" maxOrder=%s,playerOrder=%s,matchRobotCnt=%s,matchPlayerCnt=%s" % (maxOrder, playerOrder, matchRobotCnt, matchPlayerCnt), playerID)
-
- fromLowerCnt, matchPerRank = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 2)
- toOrder = playerOrder + fromLowerCnt * matchPerRank # 从低名次往高名次匹配
- GameWorld.DebugLog(" fromLowerCnt=%s,matchPerRank=%s,toOrder=%s" % (fromLowerCnt, matchPerRank, toOrder), playerID)
+ matchIDList = [] # 最终匹配的玩家ID列表
matchOrderList = [] # 匹配到的名次
viewCacheDict = {}
- for _ in range(matchPlayerCnt):
- fromOrder = max(1, toOrder - matchPerRank)
- if toOrder <= fromOrder:
- break
- orderList = range(fromOrder, toOrder)
- random.shuffle(orderList)
- if playerOrder in orderList:
- orderList.remove(playerOrder) # 不包含自己
- if not orderList:
- break
-
- for order in orderList:
- if order > maxOrder:
+
+ robotFPCoefficient = IpyGameDataPY.GetFuncCfg("ArenaMatchRobot", 1) # 必定匹配机器人的玩家战力系数,玩家战力*该系数<=机器人最高战力时必定匹配机器人
+ playerFightPower = PlayerControl.GetFightPower(curPlayer)
+ robotFPSortList = PlayerViewCache.GetRobotFightPowerSortList()
+ robotFightPowerMax = robotFPSortList[0][0] if robotFPSortList else 0
+ robotCntTotal = len(robotFPSortList)
+ GameWorld.DebugLog("玩家战力=%s,机器人最大战力=%s,匹配机器人战力系数=%s,机器人总数=%s"
+ % (playerFightPower, robotFightPowerMax, robotFPCoefficient, robotCntTotal), playerID)
+ reFightPower = playerFightPower * robotFPCoefficient # 参考战力
+ if reFightPower <= robotFightPowerMax:
+ # 匹配机器人相对玩家战力百分比范围列表 [[相对玩家战力百分比A, B], ..],支持负数,如-30就是机器人比玩家低30%战力,10就是机器人比玩家高10%战力
+ matchRobotFPPerList = IpyGameDataPY.GetFuncEvalCfg("ArenaMatchRobot", 2)
+ GameWorld.DebugLog("全部匹配机器人: %s, reFightPower=%s <= %s" % (matchRobotFPPerList, reFightPower, robotFightPowerMax), playerID)
+ loopIndex = 0
+ for fpPerRange in matchRobotFPPerList[::-1]: # 从高战力往低战力匹配
+ fpPerA, fpPerB = fpPerRange
+ GameWorld.DebugLog(" 处理匹配机器人战力段: fpPerA=%s,fpPerB=%s,loopIndex=%s" % (fpPerA, fpPerB, loopIndex), playerID)
+ if loopIndex >= robotCntTotal:
continue
- billData = billBoard.At(order - 1)
- tagID = billData.GetID()
- viewCache = PlayerViewCache.FindBattleViewCache(tagID)
- if not viewCache:
- GameWorld.DebugLog(" 无战斗缓存的玩家不匹配: tagID=%s,order=%s,fromOrder=%s,toOrder=%s" % (tagID, order, fromOrder, toOrder), playerID)
- continue
- matchOrderList.append(order)
- viewCacheDict[tagID] = viewCache
-
- if fromOrder == 1:
- if len(matchOrderList) >= matchPlayerCnt:
+ robotFPIDList = []
+ for robotIndex in range(loopIndex, robotCntTotal):
+ robotFightPower, robotID = robotFPSortList[robotIndex]
+ fpPer = (robotFightPower / float(playerFightPower) - 1) * 100
+ if fpPer < fpPerA:
+ GameWorld.DebugLog(" 比低百分比还小的战力跳出,进入下一段匹配逻辑: %s,robotID=%s,robotFightPower=%s,fpPer=%s < %s"
+ % (robotIndex, robotID, robotFightPower, fpPer, fpPerA), playerID)
break
- else:
+ loopIndex = robotIndex + 1
+ if fpPer > fpPerB:
+ #GameWorld.DebugLog(" 比高百分比还大的战力跳过,不匹配: %s,robotID=%s,robotFightPower=%s,fpPer=%s > %s"
+ # % (robotIndex, robotID, robotFightPower, fpPer, fpPerB), playerID)
+ continue
+ robotFPIDList.append([robotFightPower, robotID])
+ #GameWorld.DebugLog(" 战力在匹配段范围内,可匹配: %s,robotID=%s,robotFightPower=%s,%s <= fpPer(%s) <= %s"
+ # % (robotIndex, robotID, robotFightPower, fpPerA, fpPer, fpPerB), playerID)
+
+ if not robotFPIDList:
+ GameWorld.DebugLog(" 该战力范围段没有符合的机器人!", playerID)
+ continue
+ random.shuffle(robotFPIDList)
+ robotFightPower, robotID = robotFPIDList[0]
+ matchIDList.append(robotID)
+ GameWorld.DebugLog(" 匹配机器人: robotID=%s,robotFightPower=%s" % (robotID, robotFightPower), playerID)
+
+ if len(matchIDList) < needMatchCount:
+ GameWorld.DebugLog(" 可匹配的机器人还不够,从剩下未遍历的机器人内匹配: loopIndex=%s" % loopIndex, playerID)
+ if loopIndex < robotCntTotal:
+ randIndexList = range(loopIndex, robotCntTotal)
+ random.shuffle(randIndexList)
+ matchIndexList = randIndexList[:needMatchCount-len(matchIDList)]
+ matchIndexList.sort()
+ for robotIndex in matchIndexList:
+ robotFightPower, robotID = robotFPSortList[robotIndex]
+ matchIDList.append(robotID)
+ GameWorld.DebugLog(" 匹配机器人: robotID=%s,robotFightPower=%s" % (robotID, robotFightPower), playerID)
+
+ else:
+ # 匹配真人
+ GameWorld.DebugLog("匹配真人: reFightPower=%s > %s" % (reFightPower, robotFightPowerMax), playerID)
+ billboardMgr = DBDataMgr.GetBillboardMgr()
+ billBoard = billboardMgr.GetBillboard(ShareDefine.Def_BT_Arena)
+ if not billBoard:
+ return
+
+ maxOrder = billBoard.GetCount()
+ playerOrder = billBoard.IndexOfByID(playerID) + 1 # 玩家在排行榜中的名次,没有名次为-1
+ leastRobotCnt = IpyGameDataPY.GetFuncCfg("ArenaMatchRobot", 3)
+ matchPlayerCnt = needMatchCount - leastRobotCnt
+ GameWorld.DebugLog(" maxOrder=%s,playerOrder=%s,matchPlayerCnt=%s,leastRobotCnt=%s" % (maxOrder, playerOrder, matchPlayerCnt, leastRobotCnt), playerID)
+
+ fromLowerCnt, matchPerRank = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 2)
+ toOrder = playerOrder + fromLowerCnt * matchPerRank # 从低名次往高名次匹配
+ GameWorld.DebugLog(" fromLowerCnt=%s,matchPerRank=%s,toOrder=%s" % (fromLowerCnt, matchPerRank, toOrder), playerID)
+
+ for _ in range(matchPlayerCnt):
+ fromOrder = max(1, toOrder - matchPerRank)
+ if toOrder <= fromOrder:
+ break
+ orderList = range(fromOrder, toOrder)
+ random.shuffle(orderList)
+ if playerOrder in orderList:
+ orderList.remove(playerOrder) # 不包含自己
+ if not orderList:
break
- GameWorld.DebugLog(" 匹配玩家: fromOrder=%s,toOrder=%s,matchOrderList=%s" % (fromOrder, toOrder, matchOrderList), playerID)
- toOrder = fromOrder - 1
+ for order in orderList:
+ if order > maxOrder:
+ continue
+ billData = billBoard.At(order - 1)
+ tagID = billData.GetID()
+ viewCache = PlayerViewCache.FindBattleViewCache(tagID)
+ if not viewCache:
+ GameWorld.DebugLog(" 无战斗缓存的玩家不匹配: tagID=%s,order=%s,fromOrder=%s,toOrder=%s" % (tagID, order, fromOrder, toOrder), playerID)
+ continue
+ matchOrderList.append(order)
+ viewCacheDict[tagID] = viewCache
+
+ if fromOrder == 1:
+ if len(matchOrderList) >= matchPlayerCnt:
+ break
+ else:
+ break
+
+ GameWorld.DebugLog(" 匹配玩家: fromOrder=%s,toOrder=%s,matchOrderList=%s" % (fromOrder, toOrder, matchOrderList), playerID)
+ toOrder = fromOrder - 1
+
+ matchOrderList.sort()
+ for matchOrder in matchOrderList:
+ if matchOrder > maxOrder or matchOrder <= 0:
+ break
+ billData = billBoard.At(matchOrder - 1)
+ tagID = billData.GetID()
+ matchIDList.append(tagID)
+ GameWorld.DebugLog(" 匹配榜单结果: matchIDList=%s,matchOrderList=%s" % (matchIDList, matchOrderList), playerID)
- matchOrderList.sort()
- matchIDList = [] # 最终匹配的玩家ID列表
- for matchOrder in matchOrderList:
- if matchOrder > maxOrder or matchOrder <= 0:
- break
- billData = billBoard.At(matchOrder - 1)
- tagID = billData.GetID()
- matchIDList.append(tagID)
- GameWorld.DebugLog(" 匹配榜单结果: matchIDList=%s,matchOrderList=%s" % (matchIDList, matchOrderList), playerID)
-
# GM指定匹配测试
if gmMatchIDList != None and curPlayer.GetGMLevel():
for gmMatchID in gmMatchIDList:
@@ -322,18 +377,24 @@
GameWorld.DebugLog(" 指定匹配结果: matchIDList=%s" % (matchIDList), playerID)
needRobotCnt = needMatchCount - len(matchIDList)
- GameWorld.DebugLog(" 还需机器人数=%s" % (needRobotCnt), playerID)
- ipyDataMgr = IpyGameDataPY.IPY_Data()
- robotMax = ipyDataMgr.GetRobotCount()
+ GameWorld.DebugLog(" 最终还需机器人数=%s" % (needRobotCnt), playerID)
+ robotFPIDList = []
doCnt = 100
- while doCnt > 0 and needRobotCnt > 0 and robotMax:
+ while doCnt > 0 and needRobotCnt > 0 and robotCntTotal:
doCnt -= 1
- robotIndex = random.randint(0, robotMax - 1)
- robotIpyData = ipyDataMgr.GetRobotByIndex(robotIndex)
- robotID = robotIpyData.GetID()
+ robotIndex = random.randint(0, robotCntTotal - 1)
+ robotFightPower, robotID = robotFPSortList[robotIndex]
if robotID not in matchIDList:
matchIDList.append(robotID)
+ robotFPIDList.append([robotFightPower, robotID])
needRobotCnt -= 1
+ if robotFPIDList:
+ robotFPIDList.sort(reverse=True)
+ #GameWorld.DebugLog(" 补充机器人战力ID排序=%s" % (robotFPIDList), playerID)
+ for _, robotID in robotFPIDList:
+ if robotID in matchIDList:
+ matchIDList.remove(robotID)
+ matchIDList.append(robotID)
GameWorld.DebugLog(" 最终匹配结果: matchIDList=%s" % matchIDList, playerID)
PyGameData.g_arenaPlayerMatchDict[playerID] = matchIDList
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
index 1f63b95..0178843 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCache.py
@@ -352,9 +352,41 @@
}
return robotDict
-def UpdRobotViewCache(curCache, robotID):
+def LoadRobot():
+ ## 加载机器人缓存,在服务器启动、重读配置时加载
+ robotFPSortList = []
+ viewCacheMgr = DBDataMgr.GetPlayerViewCacheMgr()
+ ipyDataMgr = IpyGameDataPY.IPY_Data()
+ for index in range(ipyDataMgr.GetRobotCount()):
+ ipyData = ipyDataMgr.GetRobotByIndex(index)
+ robotPlayerID = ipyData.GetID()
+ curCache = viewCacheMgr.GetPlayerViewCache(robotPlayerID)
+ if not curCache:
+ curCache = viewCacheMgr.AddPlayerViewCache(robotPlayerID)
+ if not curCache:
+ continue
+ UpdRobotViewCache(curCache, robotPlayerID, ipyData)
+ robotFPSortList.append([curCache.GetFightPowerTotal(), robotPlayerID])
+ robotFPSortList.sort(reverse=True) # 战力倒序排序
+ IpyGameDataPY.SetConfigEx("robotFPSortList", robotFPSortList)
+ GameWorld.Log("加载机器人战力排序: %s, %s" % (len(robotFPSortList), robotFPSortList))
+ return robotFPSortList
+
+def GetRobotFightPowerSortList():
+ ## 机器人战力倒序排序列表
+ # @return: 倒序排序列表 [[战力, 机器人ID], ...],外部使用可随机修改,不会打乱原始排序
+ sortList = []
+ robotFPSortList = IpyGameDataPY.GetConfigEx("robotFPSortList")
+ if not robotFPSortList:
+ robotFPSortList = LoadRobot()
+ if robotFPSortList:
+ sortList += robotFPSortList
+ return sortList
+
+def UpdRobotViewCache(curCache, robotID, robotIpyData=None):
## 更新机器人查看缓存
- robotIpyData = IpyGameDataPY.GetIpyGameData("Robot", robotID)
+ if not robotIpyData:
+ robotIpyData = IpyGameDataPY.GetIpyGameData("Robot", robotID)
if not robotIpyData:
return
try:
--
Gitblit v1.8.0