ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMineArea.py
@@ -15,11 +15,13 @@
#"""Version = 2024-03-07 19:30"""
#-------------------------------------------------------------------------------
import ChConfig
import GameWorld
import NetPackCommon
import PyDataManager
import ChPyNetSendPack
import PyGameDataStruct
import PlayerCompensation
import PlayerViewCache
import PlayerDBGSEvent
import PlayerControl
@@ -42,6 +44,7 @@
# 物品实例额外属性名
MineItemAttr_MoveSpeed = "MoveSpeed"
MineItemAttr_EndTime = "EndTime"
MineItemAttr_HelpTick = "HelpTick"
# 物品类型
MineType_Normal = 0 # 常规物品
@@ -163,7 +166,6 @@
        self.viewAreaPlayerIDDict = {} # 正在查看某个福地中的玩家ID {areaPlayerID:[viewPlayerID, ...], ...}
        
        self.neighborIDListDict = {} # 玩家周围福地玩家ID列表 {playerID:[playerID, ...], ...}
        self.socialIDListDict = {} # 玩家有关系道友福地玩家ID列表 {playerID:[playerID, ...], ...} playerID列表倒序
        return
    
    def AddViewAreaPlayerID(self, viewPlayerID, areaPlayerID):
@@ -226,6 +228,7 @@
        # 不入库的属性
        setattr(mineItemData, MineItemAttr_EndTime, 0)
        setattr(mineItemData, MineItemAttr_MoveSpeed, 0)
        setattr(mineItemData, MineItemAttr_HelpTick, 0)
        return
    
    def GetMineItem(self, playerID, index):
@@ -282,21 +285,61 @@
            mineItemData.clear()
            pos += mineItemData.readData(datas, pos, dataslen)
            
            OnLoadMineItemData(mineItemData)
            playerID = mineItemData.PlayerID
            index = mineItemData.Index
            if playerID not in self.playerMineItemDict:
                self.playerMineItemDict[playerID] = {}
            itemDict = self.playerMineItemDict[playerID]
            itemDict[index] = mineItemData
            # 启动直接覆盖同玩家索引位数据,这里存在一个问题,合服后假人玩家ID是重复的,一般是新服的替换旧服的假人
            
        OnLoadMineItemOK()
        return pos
def DoOnDayEx():
    if GameWorld.IsCrossServer():
        return
    '''
            待处理:合服本身会删除部分玩家数据,之后如果多次合服后数据量较大再考虑处理
    1. 删除1星期前的自己拉物品记录,至少保留最近10条被人抢记录
    2. 删除1星期前未领取的奖励记录
    3. 清除超过1星期没有更新福地记录的玩家数据,保底保留x个玩家
    '''
#    socialAreaMax = IpyGameDataPY.GetFuncCfg("MineAreaRob", 1) # 道友福地个数
#    inValidSeconds = 7 * 24 * 3600
#    curTime = int(time.time())
#    outofDateTime = curTime - inValidSeconds
#    delPlayerIDList = []
#    recordMgr = PyDataManager.GetDBPyMineAreaRecordManager()
#    for playerID, recordList in recordMgr.playerMineRecordListDict.items():
#        isActiveAreaPlayer = False
#        beRobbedPlayerIDList = []
#        for recordData in recordList[::-1]: # 反序处理
#            if recordData.RecordTime > outofDateTime:
#                isActiveAreaPlayer = True # 近期内还有记录的视为福地活跃玩家,无论主动或被抢记录
#            if recordData.RecordType == MineAreaRecordType_BeRobbed:
#                # 至少保留被x个不同玩家抢的记录,用于更新关心道友福地
#                tagPlayerID = recordData.TagPlayerID
#                if len(beRobbedPlayerIDList) < socialAreaMax and tagPlayerID not in beRobbedPlayerIDList:
#                    beRobbedPlayerIDList.append(tagPlayerID)
#                    continue
#            if recordData.RecordTime <= outofDateTime:
#                recordList.remove(recordData) # 删除过期数据
#
#        if not isActiveAreaPlayer:
#            if playerID not in delPlayerIDList:
#                delPlayerIDList.append(playerID)
    return
def DoMineAreaFuncOpen(curPlayer):
    ## 福地功能开启
    playerID = curPlayer.GetPlayerID()
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    # 还没有福地物品数据,则刷新初始化
    if playerID not in mineItemMgr.playerMineItemDict:
        __DoMineItemRefresh(playerID, curPlayer)
    __DoMineItemRefresh(playerID, curPlayer)
    return
def OnPlayerLogin(curPlayer):
    if GameWorld.IsCrossServer():
        return
    playerID = curPlayer.GetPlayerID()
    
    # 自己福地数据
@@ -315,43 +358,10 @@
        
    return
def OnLoadMineItemData(mineItemData):
    ## 加载矿物
    playerID = mineItemData.PlayerID
    index = mineItemData.Index
    mineID = mineItemData.MineID
    if not mineID:
        return
    mineType = mineItemData.MineType
    workerCount = mineItemData.WorkerCount
    robPlayerID = mineItemData.RobPlayerID
    robWorkerCount = mineItemData.RobWorkerCount
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    if playerID not in mineItemMgr.playerMineItemDict:
        mineItemMgr.playerMineItemDict[playerID] = {}
    itemDict = mineItemMgr.playerMineItemDict[playerID]
    itemDict[index] = mineItemData
    mineItemMgr.AddMineAreaPlayerID(playerID)
    if mineType == MineType_Super and not workerCount and not robWorkerCount and mineItemData not in mineItemMgr.freeSuperItemList:
        mineItemMgr.freeSuperItemList.append(mineItemData)
    if workerCount:
        mineItemMgr.AddPlayerPullingItem(playerID, mineItemData)
    if robPlayerID and robWorkerCount:
        mineItemMgr.AddPlayerPullingItem(robPlayerID, mineItemData)
    __RefreshMineItemSpeed(mineItemData)
    return
def OnLoadMineItemOK():
    __SortMineItem()
    __MakeFackArea()
    if GameWorld.IsCrossServer():
        return
    
    # 启动默认补充空位置物品...
    refreshIndexList = range(IpyGameDataPY.GetFuncCfg("MineAreaBase", 1))
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    for areaPlayerID, itemDict in mineItemMgr.playerMineItemDict.items():
@@ -364,11 +374,32 @@
            if not mineItemData or not mineItemData.MineID:
                emptyIndexList.append(index)
                continue
        if not emptyIndexList:
            continue
        GameWorld.DebugLog("启动默认补充空位置物品: areaPlayerID=%s,emptyIndexList=%s" % (areaPlayerID, emptyIndexList))
        __DoMineItemRefresh(areaPlayerID, refreshIndexList=emptyIndexList)
            # 矿物初始数据处理
            mineType = mineItemData.MineType
            workerCount = mineItemData.WorkerCount
            robPlayerID = mineItemData.RobPlayerID
            robWorkerCount = mineItemData.RobWorkerCount
            mineItemMgr.AddMineAreaPlayerID(areaPlayerID)
            if mineType == MineType_Super and not workerCount and not robWorkerCount and mineItemData not in mineItemMgr.freeSuperItemList:
                mineItemMgr.freeSuperItemList.append(mineItemData)
            if workerCount:
                mineItemMgr.AddPlayerPullingItem(areaPlayerID, mineItemData)
            if robPlayerID and robWorkerCount:
                mineItemMgr.AddPlayerPullingItem(robPlayerID, mineItemData)
            __RefreshMineItemSpeed(mineItemData)
        if emptyIndexList:
            GameWorld.DebugLog("启动默认补充空位置物品: areaPlayerID=%s,emptyIndexList=%s" % (areaPlayerID, emptyIndexList))
            __DoMineItemRefresh(areaPlayerID, refreshIndexList=emptyIndexList)
    __SortMineItem()
    __MakeFackArea()
    return
def __MakeFackArea():
@@ -397,7 +428,7 @@
    playerID = mineItemData.PlayerID
    index = mineItemData.Index
    mineID = mineItemData.MineID
    curPos = GameWorld.ToIntDef(mineItemData.Position, Def_PositionMid)
    curPos = GameWorld.ToFloat(mineItemData.Position, Def_PositionMid)
    if not playerID or not mineID:
        return curPos
    
@@ -405,7 +436,7 @@
    robWorkerCount = mineItemData.RobWorkerCount
    if not curWorkerCount and not robWorkerCount:
        return curPos
    moveSpeed = getattr(mineItemData, MineItemAttr_MoveSpeed)
    moveSpeed = getattr(mineItemData, MineItemAttr_MoveSpeed, 0)
    if not moveSpeed:
        return curPos
    passSeconds = curTime - mineItemData.UpdTime
@@ -430,7 +461,7 @@
    if not playerID or not mineID:
        return
    
    curPos = GameWorld.ToIntDef(mineItemData.Position, Def_PositionMid)
    curPos = GameWorld.ToFloat(mineItemData.Position, Def_PositionMid)
    allMineItemByEndTimeList = PyDataManager.GetDBPyMineAreaItemManager().allMineItemByEndTimeList
    curWorkerCount = mineItemData.WorkerCount
    robWorkerCount = mineItemData.RobWorkerCount
@@ -499,6 +530,9 @@
        battleRatio = workerBattleRatioList[len(workerBattleRatioList) - 1] if batWorkerCount > len(workerBattleRatioList) else workerBattleRatioList[batWorkerCount - 1]
        
    needSeconds = int(dist * itemWeight * baseTime * workRatio * battleRatio) # 还需工作时长,秒
    if needSeconds <= 0:
        return 0, 0
    moveSpeed = dist / float(needSeconds) # 移动速度  x格/秒
    needHms = "%02d:%02d:%02d" % (needSeconds / 3600, needSeconds % 3600 / 60, needSeconds % 60)
    
@@ -525,15 +559,11 @@
    GameWorld.Log("福地系统定时刷新! %s" % str(curHourMinute))
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    for playerID in mineItemMgr.playerMineItemDict.keys():
        __DoMineItemRefresh(playerID, isSuper=True)
        __DoMineItemRefresh(playerID, isSys=True)
    return
def OnMineItemTimeProcess(curTime, tick):
    ## 定时处理,每秒触发一次
    # 待优化处理...
    # 定时删除多余数据,如过天处理,多余记录
    # 合服多余数据清理,合服假人ID重复问题
    
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    __Process_EndItemRefresh(mineItemMgr.endSelfItemList, IpyGameDataPY.GetFuncCfg("MineAreaSysRefresh", 2), curTime)
@@ -606,7 +636,7 @@
    while doCount > 0 and allMineItemByEndTimeList:
        doCount -= 1
        mineItemData = allMineItemByEndTimeList[index]
        endTime = getattr(mineItemData, MineItemAttr_EndTime)
        endTime = getattr(mineItemData, MineItemAttr_EndTime, 0)
        if curTime < endTime:
            break
        
@@ -671,6 +701,8 @@
    AddMineItemRecord(awardPlayerID, MineAreaRecordType_Pull, areaPlayerID, mineID, curTime)
    if areaPlayerID != awardPlayerID:
        AddMineItemRecord(areaPlayerID, MineAreaRecordType_BeRobbed, awardPlayerID, mineID, curTime)
        DecRobValue(awardPlayerID, areaPlayerID, 1)
        AddRobValue(areaPlayerID, awardPlayerID, 1)
        
        # 被抢的
        if IpyGameDataPY.GetFuncCfg("MineAreaSysRefresh", 3) > 0:
@@ -693,6 +725,9 @@
    return
def AddMineItemRecord(playerID, recordType, tagPlayerID, mineID, curTime):
    if playerID <= Def_FakeAreaCount:
        # 假人不记录
        return
    recordData = PyGameDataStruct.tagDBPyMineAreaRecord()
    recordData.PlayerID = playerID
    recordData.RecordType = recordType
@@ -703,60 +738,199 @@
    recordMgr = PyDataManager.GetDBPyMineAreaRecordManager()
    recordList = recordMgr.AddPlayerRecord(recordData)
    
    # 被人抢,更新关系福地ID记录
    if recordData.RecordType == MineAreaRecordType_BeRobbed and playerID > Def_FakeAreaCount:
        __DoUpdSocialPlayerIDList(playerID)
    if len(recordList) > Def_RecordMax:
        recordList.pop(0) # 删除最早一条
    return
def __DoUpdSocialPlayerIDList(playerID):
    ## 更新有关系的道友ID列表
    recordMgr = PyDataManager.GetDBPyMineAreaRecordManager()
    recordList = recordMgr.playerMineRecordListDict.get(playerID, [])
    socialAreaMax = IpyGameDataPY.GetFuncCfg("MineAreaRob", 1) # 道友福地个数
    socialIDList = [] # 反序
    for recData in recordList[::-1]:
        if recData.RecordType != MineAreaRecordType_BeRobbed:
            ## 优先保留被抢记录关系玩家
def DecRobValue(playerID, tagPlayerID, decValue):
    ## 减少敌对值
    playerRecMgr = PyDataManager.GetDBPlayerRecDataManager()
    robRecData = playerRecMgr.GetPlayerRecDataFirst(ShareDefine.Def_PlayerRecType_MineAreaRecord, playerID, False)
    if not robRecData:
        GameWorld.DebugLog("没有敌对福地记录!", playerID)
        return 0
    # 抢劫的人减少与对方敌对值
    setRobValue = 0
    robValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    GameWorld.DebugLog("减少与对方敌对值: tagPlayerID=%s,decValue=%s" % (tagPlayerID, decValue), playerID)
    GameWorld.DebugLog("    bef robValueList=%s" % robValueList, playerID)
    for index, robValueInfo in enumerate(robValueList):
        robValue, pID = robValueInfo
        if pID != tagPlayerID:
            continue
        if recData.TagPlayerID not in socialIDList:
            socialIDList.append(recData.TagPlayerID)
            if len(socialIDList) >= socialAreaMax:
                break
        robValue -= decValue
        GameWorld.DebugLog("    tagPlayerID=%s,更新敌对值=%s" % (tagPlayerID, robValue), playerID)
        if robValue <= 0:
            robValueList.pop(index)
        else:
            robValueList[index] = [robValue, pID]
        setRobValue = robValue
        robRecData.SetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, robValueList, True)
        break
    robValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    GameWorld.DebugLog("    aft robValueList=%s" % robValueList, playerID)
    return setRobValue
def AddRobValue(playerID, tagPlayerID, addValue):
    ## 被抢的人增加与对方敌对值,并置顶
    if playerID <= Def_FakeAreaCount:
        return 0
    GameWorld.DebugLog("增加与对方敌对值: tagPlayerID=%s,addValue=%s" % (tagPlayerID, addValue), playerID)
    setRobValue = 0
    playerRecMgr = PyDataManager.GetDBPlayerRecDataManager()
    robRecData = playerRecMgr.GetPlayerRecDataFirst(ShareDefine.Def_PlayerRecType_MineAreaRecord, playerID, True)
    robValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    GameWorld.DebugLog("    bef robValueList=%s" % robValueList, playerID)
    for index, robValueInfo in enumerate(robValueList):
        robValue, pID = robValueInfo
        if pID != tagPlayerID:
            continue
        robValueList.pop(index)
        setRobValue = robValue
        break
    setRobValue += addValue
    GameWorld.DebugLog("    tagPlayerID=%s,更新敌对值=%s" % (tagPlayerID, setRobValue), playerID)
    robValueList.insert(0, [setRobValue, tagPlayerID])
    robRecData.SetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, robValueList)
    robValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    GameWorld.DebugLog("    aft robValueList=%s" % robValueList, playerID)
    return setRobValue
def GetRobPlayerIDList(playerID):
    ## 获取敌对玩家ID列表
    if playerID <= Def_FakeAreaCount:
        return []
    playerRecMgr = PyDataManager.GetDBPlayerRecDataManager()
    robRecData = playerRecMgr.GetPlayerRecDataFirst(ShareDefine.Def_PlayerRecType_MineAreaRecord, playerID, False)
    if not robRecData:
        return []
    robIDList = []
    rPlayerRobValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    for robValueInfo in rPlayerRobValueList:
        _, pID = robValueInfo
        robIDList.append(pID)
    return robIDList
def GetRobValueDict(playerID):
    ## 获取敌对玩家敌对值字典
    if playerID <= Def_FakeAreaCount:
        return {}
    playerRecMgr = PyDataManager.GetDBPlayerRecDataManager()
    robRecData = playerRecMgr.GetPlayerRecDataFirst(ShareDefine.Def_PlayerRecType_MineAreaRecord, playerID, False)
    if not robRecData:
        return {}
    robValueDict = {}
    rPlayerRobValueList = robRecData.GetUserDataByKey(ChConfig.Def_RecDataKey_RobValueList, [])
    for robValueInfo in rPlayerRobValueList:
        robValue, pID = robValueInfo
        robValueDict[pID] = robValue
    return robValueDict
def OnTurnFightRequest(curPlayer, mapID, funcLineID, tagPlayerID, valueList):
    # 摇人帮助请求、自己驱赶请求
    if funcLineID == 0 or funcLineID == 1:
        return __OnMineHelpRequest(curPlayer, mapID, funcLineID, tagPlayerID, valueList)
    return
def OnTurnFightOver(curPlayer, mapID, funcLineID, tagPlayerID, valueList, fightRet, awardItemList):
    # 摇人帮助结果、自己驱赶结果
    if funcLineID == 0 or funcLineID == 1:
        return __OnMineHelpOver(curPlayer, mapID, funcLineID, tagPlayerID, valueList, fightRet, awardItemList)
    return
def __OnMineHelpRequest(curPlayer, mapID, funcLineID, tagPlayerID, valueList):
    # 摇人帮助请求、自己驱赶请求
    playerID = curPlayer.GetPlayerID()
    if not valueList or len(valueList) < 2:
        GameWorld.DebugLog("没有指定valueList!", playerID)
        return
    areaPlayerID = valueList[0]
    itemIndex = valueList[1]
    if funcLineID == 0:
        if playerID == areaPlayerID:
            GameWorld.DebugLog("不能帮助自己! areaPlayerID=%s" % areaPlayerID, playerID)
            return
    elif funcLineID == 1:
        if playerID != areaPlayerID:
            GameWorld.DebugLog("不是自己的福地,无法自己驱赶! areaPlayerID=%s" % areaPlayerID, playerID)
            return
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    socialIDListBef = mineItemMgr.socialIDListDict.get(playerID, [])
    # 优先使用历史记录
    if len(socialIDList) < socialAreaMax:
        for socialIDBef in socialIDListBef:
            if socialIDBef not in socialIDList:
                socialIDList.append(socialIDBef)
                if len(socialIDList) >= socialAreaMax:
                    break
    # 优先随机真人
    if len(socialIDList) < socialAreaMax and mineItemMgr.realAreaPlayerIDList:
        random.shuffle(mineItemMgr.realAreaPlayerIDList)
        for areaPlayerID in mineItemMgr.realAreaPlayerIDList:
            if areaPlayerID not in socialIDList and areaPlayerID != playerID:
                socialIDList.append(areaPlayerID)
                if len(socialIDList) >= socialAreaMax:
                    break
    # 不够补充假人
    if len(socialIDList) < socialAreaMax and mineItemMgr.fackAreaPlayerIDList:
        random.shuffle(mineItemMgr.fackAreaPlayerIDList)
        for areaPlayerID in mineItemMgr.fackAreaPlayerIDList:
            if areaPlayerID not in socialIDList:
                socialIDList.append(areaPlayerID)
                if len(socialIDList) >= socialAreaMax:
                    break
    mineItemMgr.socialIDListDict[playerID] = socialIDList
    return socialIDList
    mineItemData = mineItemMgr.GetMineItem(areaPlayerID, itemIndex)
    mineID = mineItemData.MineID
    if not mineID:
        # 该资源已消失
        PlayerControl.NotifyCode(curPlayer, "MineDisappeared")
        return
    robPlayerID = mineItemData.RobPlayerID
    if not robPlayerID or robPlayerID != tagPlayerID:
        # 当前资源无争夺者或已被其他玩家完成
        PlayerControl.NotifyCode(curPlayer, "MineHelpFinished")
        return
    tick = GameWorld.GetGameWorld().GetTick()
    helpTick = getattr(mineItemData, MineItemAttr_HelpTick, 0)
    if helpTick and tick - helpTick < 10000:
        GameWorld.DebugLog("已经有其他人在帮助中!", playerID)
        return
    setattr(mineItemData, MineItemAttr_HelpTick, tick)
    return True
def __OnMineHelpOver(curPlayer, mapID, funcLineID, tagPlayerID, valueList, fightRet, awardItemList):
    # 摇人帮助结果、自己驱赶结果
    playerID = curPlayer.GetPlayerID()
    helpPlayerName = curPlayer.GetName()
    areaPlayerID = valueList[0]
    itemIndex = valueList[1]
    isWin = fightRet[0]
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    mineItemData = mineItemMgr.GetMineItem(areaPlayerID, itemIndex)
    setattr(mineItemData, MineItemAttr_HelpTick, 0)
    if not isWin:
        #GameWorld.DebugLog("帮助失败")
        return
    robPlayerID = mineItemData.RobPlayerID
    # 赶走抢夺者
    if robPlayerID and robPlayerID == tagPlayerID:
        __DoCancelPull(tagPlayerID, areaPlayerID, itemIndex, "out")
    # 帮助的发奖
    if funcLineID == 0:
        robCacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(tagPlayerID))
        robPlayerName = robCacheDict.get("Name", "")
        areaCacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(areaPlayerID))
        areaPlayerName = areaCacheDict.get("Name", "")
        # 邮件发放奖励
        PlayerCompensation.SendMailByKey("MineHelpAward", [playerID], awardItemList, [areaPlayerName, robPlayerName])
        # 通知福地玩家
        PlayerCompensation.SendMailByKey("MineHelpReqOK", [areaPlayerID], [], [helpPlayerName, robPlayerName])
    # 自己驱赶的
    elif funcLineID == 1:
        # 自己驱赶的,不用再通知地图,直接return
        return
    return True
def MapServer_MineArea(curPlayer, msgList):
    mapID = curPlayer.GetRealMapID()
@@ -770,16 +944,22 @@
    
    # 拉物品
    if msgType == "Pull":
        __DoPullItem(playerID, curPlayer, dataMsg)
        ret = __DoPullItem(playerID, curPlayer, dataMsg)
    # 刷新福地物品
    elif msgType == "MineItemRefresh":
        playerID, isSuper = dataMsg
        __DoMineItemRefresh(playerID, curPlayer, isSuper=isSuper)
        __DoMineItemRefresh(playerID, curPlayer, isSuper=isSuper, queryType=99, queryValue=isSuper)
    # 地图结算奖励OK
    elif msgType == "MineAreaAwardGetOK":
        __DoMineAreaAwardGetOK(curPlayer, dataMsg)
    # 刷新周围玩家
    elif msgType == "MineRobRefresh":
        tick = GameWorld.GetGameWorld().GetTick()
        queryType, queryValue = 3, 1
        SyncNeighborAreaInfo(curPlayer, tick, queryType, queryValue)
        
    if ret == None:
        return
@@ -792,7 +972,7 @@
        return
    if workerCount <= 0:
        if not isPreview:
            __DoCancelPull(playerID, areaPlayerID, itemIndex)
            __DoCancelPull(playerID, areaPlayerID, itemIndex, "cancel")
        return
    GameWorld.DebugLog("请求福地拉物品! areaPlayerID=%s,itemIndex=%s,workerCount=%s,workerState=%s,workerTotal=%s,isPreview=%s" 
                       % (areaPlayerID, itemIndex, workerCount, workerState, workerTotal, isPreview), playerID)
@@ -841,7 +1021,7 @@
    
    if isPreview:
        ## 预览速度时间
        curPos = GameWorld.ToIntDef(mineItemData.Position, Def_PositionMid)
        curPos = GameWorld.ToFloat(mineItemData.Position, Def_PositionMid)
        if playerID == areaPlayerID:
            curWorkerCount = assignWorkerCount
            curWorkerState = workerState
@@ -883,9 +1063,9 @@
    __RefreshMineItemSpeed(mineItemData, True)
    
    SyncMineAreaItemInfo(areaPlayerID, [itemIndex], notifyPlayerIDListEx)
    return
    return [areaPlayerID]
def __DoCancelPull(playerID, areaPlayerID, itemIndex):
def __DoCancelPull(playerID, areaPlayerID, itemIndex, reason=""):
    ## 取消拉取
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    mineItemData = mineItemMgr.GetMineItem(areaPlayerID, itemIndex)
@@ -920,9 +1100,12 @@
        __RefreshMineItemSpeed(mineItemData, True)
        
    SyncMineAreaItemInfo(areaPlayerID, [itemIndex], notifyPlayerIDListEx)
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
    if curPlayer:
        MapServer_QueryPlayerResult(curPlayer, "MineAreaCancelPull", [areaPlayerID, reason])
    return
def __DoMineItemRefresh(areaPlayerID, areaPlayer=None, isSys=False, isSuper=False, isNotify=True, refreshIndexList=None, setPosition=None, setItemLV=None, setMineID=None):
def __DoMineItemRefresh(areaPlayerID, areaPlayer=None, isSys=False, isSuper=False, isNotify=True, refreshIndexList=None, setPosition=None, setItemLV=None, setMineID=None, queryType=0, queryValue=0):
    '''刷新福地物品
    @param areaPlayerID: 福地玩家ID,可能是假人
    @param areaPlayer: 福地玩家实例
@@ -1021,7 +1204,7 @@
        GameWorld.DebugLog("    index=%s,randMineID=%s,position=%s,mineType=%s,itemLV=%s" % (index, randMineID, position, mineType, itemLV), areaPlayerID)
        
    if isNotify and refreshDict:
        SyncMineAreaItemInfo(areaPlayerID, refreshDict.keys())
        SyncMineAreaItemInfo(areaPlayerID, refreshDict.keys(), queryType=queryType, queryValue=queryValue)
    return refreshDict
#// B0 33 福地查看 #tagCGMineAreaView
@@ -1029,7 +1212,7 @@
#struct    tagCGMineAreaView
#{
#    tagHead        Head;
#    BYTE        QueryType;    // 查询同步类型:0-后端主动同步;1-查看指定福地;2-查看道友福地列表;3-查看周围随机福地列表;4-退出他人福地
#    BYTE        QueryType;    // 查询同步类型:0-后端主动同步;1-查看指定福地;2-查看道友福地列表;3-查看周围随机福地列表;4-退出他人福地;5-查看记录
#    DWORD        QueryValue;    // 查询值,类型1时-发送目标玩家ID;3时-发送是否重新随机
#};
def OnMineAreaView(index, clientData, tick):
@@ -1058,15 +1241,20 @@
                
    # 查看周围随机福地列表
    elif queryType == 3:
        queryValue = 0 # GameServer默认只给查询,刷新列表改为从MapServer发起 B0 31 福地物品刷新 #tagCMMineItemRefresh 请求
        SyncNeighborAreaInfo(curPlayer, tick, queryType, queryValue)
        
    # 退出他人福地
    elif queryType == 4:
        PyDataManager.GetDBPyMineAreaItemManager().DelViewAreaPlayerID(playerID)
        
    # 查看记录
    elif queryType == 5:
        SyncAreaRecord(curPlayer)
    return
def SyncMineAreaItemInfo(areaPlayerID, mineIndexList, notifyPlayerIDListEx=None):
def SyncMineAreaItemInfo(areaPlayerID, mineIndexList, notifyPlayerIDListEx=None, queryType=0, queryValue=0):
    '''某个福地物品变更时同步,会同步给相关玩家
    @param areaPlayerID: 福地玩家ID,可能是假人
    @param mineIndexList: 需要同步的矿物索引
@@ -1083,9 +1271,9 @@
        notifyPlayerIDList.append(areaPlayerID)
        
    # 列表中
    for playerID, socialIDList in mineItemMgr.socialIDListDict.items():
        if areaPlayerID in socialIDList:
            notifyPlayerIDList.append(playerID)
    robPlayerIDList = GetRobPlayerIDList(areaPlayerID)
    if robPlayerIDList:
        notifyPlayerIDList += robPlayerIDList
    for playerID, neighborIDList in mineItemMgr.neighborIDListDict.items():
        if areaPlayerID in neighborIDList:
            notifyPlayerIDList.append(playerID)
@@ -1107,7 +1295,7 @@
    if not notifyPlayerIDList:
        return
    
    clientPack = __GetMineAreaInfoPack([[areaPlayerID, mineIndexList]])
    clientPack = __GetMineAreaInfoPack([[areaPlayerID, mineIndexList]], queryType=queryType, queryValue=queryValue)
    # 去重同步
    playerManager = GameWorld.GetPlayerManager()
    for playerID in set(notifyPlayerIDList):
@@ -1122,16 +1310,12 @@
    return
def SyncSocialAreaInfo(curPlayer, queryType=0, queryValue=0):
    ## 同步有关系的道友福地列表
    ## 同步有关系的道友福地列表 - 敌对列表
    playerID = curPlayer.GetPlayerID()
    mineItemMgr = PyDataManager.GetDBPyMineAreaItemManager()
    if playerID in mineItemMgr.socialIDListDict:
        socialIDList = mineItemMgr.socialIDListDict[playerID]
    else:
        socialIDList = __DoUpdSocialPlayerIDList(playerID)
    socialIDList = GetRobPlayerIDList(playerID)
    robValueDict = GetRobValueDict(playerID)
    areaMineList = [[areaPlayerID, []] for areaPlayerID in socialIDList]
    clientPack = __GetMineAreaInfoPack(areaMineList, queryType, queryValue)
    clientPack = __GetMineAreaInfoPack(areaMineList, queryType, queryValue, robValueDict)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
@@ -1154,7 +1338,8 @@
        neighborIDList = mineItemMgr.neighborIDListDict.get(playerID, [])
        
    if not neighborIDList:
        random.shuffle(mineItemMgr.realAreaPlayerIDList)
        # 优先随机真人
        random.shuffle(mineItemMgr.realAreaPlayerIDList)
        random.shuffle(mineItemMgr.fackAreaPlayerIDList)
        areaPlayerIDList = mineItemMgr.realAreaPlayerIDList + mineItemMgr.fackAreaPlayerIDList
        if playerID in areaPlayerIDList:
@@ -1163,9 +1348,14 @@
            if neighborIDBef in areaPlayerIDList:
                areaPlayerIDList.remove(neighborIDBef)
        neighborCount = IpyGameDataPY.GetFuncCfg("MineAreaRob", 2)
        realmLV = curPlayer.GetOfficialRank()
        officialNeighborCountList = IpyGameDataPY.GetFuncEvalCfg("MineAreaRob2", 1)
        for needRLV, nCount in officialNeighborCountList:
            if realmLV >= needRLV:
                neighborCount = nCount
        neighborIDList = areaPlayerIDList[:neighborCount]
        mineItemMgr.neighborIDListDict[playerID] = neighborIDList
        GameWorld.DebugLog("刷新周围随机福地: %s" % neighborIDList, playerID)
        GameWorld.DebugLog("刷新周围随机福地: realmLV=%s,neighborCount=%s,%s" % (realmLV, neighborCount, neighborIDList), playerID)
        
    areaMineList = [[areaPlayerID, []] for areaPlayerID in neighborIDList]
    clientPack = __GetMineAreaInfoPack(areaMineList, queryType, queryValue)
@@ -1196,7 +1386,7 @@
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def __GetMineAreaInfoPack(areaMineList, queryType=0, queryValue=0):
def __GetMineAreaInfoPack(areaMineList, queryType=0, queryValue=0, robValueDict=None):
    ''' 获取同步福地详细信息包
    @param areaMineList: [[areaPlayerID, mineIndexList], ...] 按指定福地ID顺序列表获取,mineIndexList为空时同步该福地全部物品,否则只同步指定索引物品
    '''
@@ -1211,8 +1401,11 @@
        if areaPlayerID > Def_FakeAreaCount:
            cacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(areaPlayerID))
            areaInfo.PlayerName = cacheDict.get("Name", "")
            areaInfo.Job = cacheDict.get("Job", 0)
            areaInfo.Face = cacheDict.get("Face", 0)
            areaInfo.FacePic = cacheDict.get("FacePic", 0)
            areaInfo.RobValue = robValueDict.get(areaPlayerID, 0) if robValueDict else 0 # 敌对值,前端仅queryType为2时才更新敌对值
        areaInfo.MineItemList = []
        if not mineIndexList:
            mineIndexList = range(IpyGameDataPY.GetFuncCfg("MineAreaBase", 1))
@@ -1225,16 +1418,18 @@
            mineItem.UpdTime = mineItemData.UpdTime
            mineItem.Position = mineItemData.Position
            mineItem.PosLen = len(mineItem.Position)
            mineItem.MoveSpeed = "%s" % getattr(mineItemData, MineItemAttr_MoveSpeed)
            mineItem.MoveSpeed = "%s" % getattr(mineItemData, MineItemAttr_MoveSpeed, 0)
            mineItem.SpeedLen = len(mineItem.MoveSpeed)
            mineItem.EndTime = getattr(mineItemData, MineItemAttr_EndTime)
            mineItem.EndTime = getattr(mineItemData, MineItemAttr_EndTime, 0)
            mineItem.WorkerCount = mineItemData.WorkerCount
            mineItem.RobPlayerID = mineItemData.RobPlayerID
            mineItem.RobWorkerCount = mineItemData.RobWorkerCount
            if mineItemData.RobPlayerID:
                robCacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(mineItemData.RobPlayerID))
                mineItem.RobPlayerName = robCacheDict.get("Name", "")
                mineItem.RobJob = robCacheDict.get("Job", 0)
                mineItem.RobFace = robCacheDict.get("Face", 0)
                mineItem.RobFacePic = robCacheDict.get("FacePic", 0)
            areaInfo.MineItemList.append(mineItem)
        areaInfo.MineCount = len(areaInfo.MineItemList)
        
@@ -1242,6 +1437,30 @@
    clientPack.AreaCount = len(clientPack.AreaList)
    return clientPack
def SyncAreaRecord(curPlayer):
    playerID = curPlayer.GetPlayerID()
    recordMgr = PyDataManager.GetDBPyMineAreaRecordManager()
    recordList = recordMgr.playerMineRecordListDict.get(playerID, [])
    clientPack = ChPyNetSendPack.tagGCMineAreaRecordInfo()
    clientPack.AreaRecordList = []
    for recData in recordList:
        recordInfo = ChPyNetSendPack.tagGCMineAreaRecord()
        recordInfo.RecordType = recData.RecordType
        recordInfo.TagPlayerID = recData.TagPlayerID
        recordInfo.RecordTime = recData.RecordTime
        recordInfo.MineID = recData.MineID
        if playerID != recordInfo.TagPlayerID and recordInfo.TagPlayerID > Def_FakeAreaCount:
            tagCacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(recordInfo.TagPlayerID))
            recordInfo.TagPlayerName = tagCacheDict.get("Name", "")
            recordInfo.TagJob = tagCacheDict.get("Job", 0)
            recordInfo.TagFace = tagCacheDict.get("Face", 0)
            recordInfo.TagFacePic = tagCacheDict.get("FacePic", 0)
        clientPack.AreaRecordList.append(recordInfo)
    clientPack.RecordCount = len(clientPack.AreaRecordList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
#// B0 34 福地请求结算奖励 #tagCGMineAreaAwardGet
#
#struct    tagCGMineAreaAwardGet