hxp
2019-09-22 d236760ececff7046f3a68d61f865e1edb9429c1
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
@@ -27,6 +27,7 @@
import PlayerBourse
import PlayerFamily
import ShareDefine
import PyGameData
import ChConfig
import random
@@ -51,7 +52,8 @@
AuctionRecordResult_BidOK, # 竞价成功
AuctionRecordResult_BidFail, # 竞价失败
AuctionRecordResult_MoveToWorld, # 仙盟拍品转移到全服拍品
) = range(6)
AuctionRecordResult_Unsell, # 下架
) = range(7)
# 当前拍品归类 0-全服拍品 1-仙盟私有拍品
AuctionType_World = 0
@@ -217,10 +219,22 @@
def __InitAuctionAttentionAttrEx(attentionData):
    ## 初始化拍卖关注实例附加属性
    setattr(attentionData, "AttentionItemIDList", [] if not attentionData.AttentionInfo else json.loads(attentionData.AttentionInfo))
    setattr(attentionData, "AttentionItemIDList", [])
    if attentionData.AttentionInfo.startswith("[") and attentionData.AttentionInfo.endswith("]"):
        attentionData.AttentionItemIDList = json.loads(attentionData.AttentionInfo)
    return
##-------------------------------------------------------------------------------------------------
def OnGameServerInitOK():
    ## 服务器启动成功
    allAuctionItemByEndTimeList = PyDataManager.GetAuctionItemManager().allAuctionItemByEndTimeList
    # 由于服务器未启动成功时取不到正确的开服天,所以启动成功后刷新一下拍品系统回购时间
    for auctionItem in allAuctionItemByEndTimeList:
        __SetAuctionItemSysBuyTime(auctionItem)
    __SortAuctionitem()
    return
def OnLoadAuctionItemDataEx(dbData):
    ## 加载拍卖物品表时附加处理
@@ -270,9 +284,73 @@
    setattr(auctionItem, "BiddingQueryID", 0) # 当前正在竞价的玩家ID
    setattr(auctionItem, "BiddingQueryTick", 0) # 当前正在竞价的tick
    setattr(auctionItem, "EndTime", 0) # 结束竞价time值
    setattr(auctionItem, "SysBuyTime", 0) # 系统一口价时间
    
    __SetAuctionItemSysBuyTime(auctionItem)
    __SetAuctionItemEndTime(auctionItem, ipyData)
    return True
def __SetAuctionItemSysBuyTime(auctionItem):
    ## 更新系统一口价该拍品时间
    if not GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_GameWorldInitOK):
        #GameWorld.DebugLog("服务器未启动好,取不到正确的开服天,不处理拍品系统回购时间!")
        return
    #itemGUID = auctionItem.ItemGUID
    itemID = auctionItem.ItemID
    itemType = auctionItem.ItemType
    playerID = auctionItem.PlayerID
    familyID = auctionItem.FamilyID
    if not playerID and not familyID:
        #GameWorld.DebugLog("该拍品为系统上架的拍品,不设置系统一口价时间! GUID=%s,itemID=%s" % (itemGUID, itemID))
        return
    if familyID:
        #GameWorld.DebugLog("该拍品为仙盟拍品,不设置系统一口价时间! GUID=%s,itemID=%s,familyID=%s" % (itemGUID, itemID, familyID))
        return
    # 注意: 因为GameServer没传是否套装,所以暂时按策划的ID规则来处理,最后一位代表是否套装
    if itemID % 10 == 1:
        #GameWorld.DebugLog("该拍品为套装拍品,不设置系统一口价时间! itemID=%s" % (itemID))
        return
    if auctionItem.BidderID:
        #GameWorld.DebugLog("该拍品已经有人竞价,不设置系统一口价时间! itemID=%s,bidderID=%s" % (itemID, auctionItem.BidderID))
        return
    classLV = auctionItem.ItemClassLV
    classSysBuyRateDict = IpyGameDataPY.GetFuncEvalCfg("AuctionItemSystem", 5)
    if classLV in classSysBuyRateDict:
        sysBuyRate = classSysBuyRateDict[classLV]
        if not GameWorld.CanHappen(sysBuyRate, 100):
            #GameWorld.DebugLog("该拍品阶概率不回收,不设置系统一口价时间! itemID=%s,classLV=%s,sysBuyRate=%s" % (itemID, classLV, sysBuyRate))
            return
    canSysBuyItemTypeList = IpyGameDataPY.GetFuncEvalCfg("AuctionItemSystem", 2)
    if itemType not in canSysBuyItemTypeList:
        #GameWorld.DebugLog("该拍品类型不可被系统一口价,不设置系统一口价时间! itemID=%s,itemType=%s" % (itemID, itemType))
        return
    sysBuyTimeRange = {}
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    oscDaySysBuyTimeRangeDict = IpyGameDataPY.GetFuncEvalCfg("AuctionItemSystem", 1, {})
    openServerDayList = oscDaySysBuyTimeRangeDict.keys()
    openServerDayList.sort()
    for oscDay in openServerDayList:
        if openServerDay <= oscDay:
            sysBuyTimeRange = oscDaySysBuyTimeRangeDict[oscDay]
            break
    if len(sysBuyTimeRange) != 2:
        #GameWorld.DebugLog("该开服天没有配置系统中间商回购支持! openServerDay=%s, %s" % (openServerDay, oscDaySysBuyTimeRangeDict))
        return
    randMinutes = random.randint(sysBuyTimeRange[0], sysBuyTimeRange[1])
    addTimeStr = auctionItem.AddTime
    addTime = GameWorld.ChangeTimeStrToNum(addTimeStr)
    auctionItem.SysBuyTime = addTime + randMinutes * 60
    pyAuctionItemMgr = PyDataManager.GetAuctionItemManager()
    pyAuctionItemMgr.sysBuyoutItemByTimeList.append(auctionItem)
    #GameWorld.DebugLog("更新拍品系统一口价时间: GUID=%s,itemID=%s,addTime=%s(%s),openServerDay=%s,randMinutes=%s(%s),sysBuyTime=%s"
    #                   % (itemGUID, itemID, addTime, addTimeStr, openServerDay, randMinutes, sysBuyTimeRange, auctionItem.SysBuyTime))
    return
def __SetAuctionItemEndTime(auctionItem, ipyData):
    ## 更新拍品结束竞价time值
@@ -419,7 +497,7 @@
    GameWorld.Log("=============================================================")
    return AuctionSystemItem[1]
def OnAuctionItemMinuteProcess():
def OnAuctionItemMinuteProcess(tick):
    ## 拍卖行拍品定时处理,每整分钟触发一次
    
    # 这里时间需精确到分钟,不然后面的比较会匹配不到
@@ -428,7 +506,10 @@
                                                                    curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
    
    randMailKey = ""
    sysAuctionItemList = []
    addItemTick = tick
    sysAuctionItemList = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemList") # 系统等待上架的拍品列表
    if not sysAuctionItemList:
        sysAuctionItemList = []
    addSystemAuctionItemInfo = __GetAuctionSystemItemInfo()
    for cfgID, ipyData, addAuctionItemDatetimeList in addSystemAuctionItemInfo:
        if curDateTime not in addAuctionItemDatetimeList:
@@ -436,20 +517,29 @@
        #cfgID = ipyData.GetCfgID()
        addCountWeightList = ipyData.GetItemCountWeightList()
        auctionItemWeightList = ipyData.GetAuctionItemWeightList()
        randSecondRange = ipyData.GetAddRandSecondRange()
        
        addCount = GameWorld.GetResultByWeightList(addCountWeightList)
        addSysItemList = []
        GameWorld.Log("增加等待上架的系统拍品信息: cfgID=%s,addCount=%s,addItemTick=%s" % (cfgID, addCount, addItemTick))
        for _ in xrange(addCount):
            itemInfo = GameWorld.GetResultByWeightList(auctionItemWeightList)
            if itemInfo != None:
                addSysItemList.append(itemInfo)
        GameWorld.Log("增加上架系统拍品信息: cfgID=%s,addCount=%s, %s" % (cfgID, addCount, addSysItemList))
        sysAuctionItemList += addSysItemList
                randSeconds = 0
                if len(randSecondRange) == 2:
                    randSeconds = random.randint(randSecondRange[0], randSecondRange[1])
                elif len(randSecondRange) == 1:
                    randSeconds = randSecondRange[0]
                addItemTick = addItemTick + randSeconds * 1000
                sysAuctionItemList.append([addItemTick, itemInfo])
                GameWorld.Log("    增加等待上架的系统拍品: randSeconds=%s,addItemTick=%s,itemInfo=%s" % (randSeconds, addItemTick, itemInfo))
        randMailKeyList = ipyData.GetRandMailKeyList()
        if randMailKeyList:
            randMailKey = random.choice(randMailKeyList)
            
    IpyGameDataPY.SetConfigEx("SysWaitAuctionItemList", sysAuctionItemList)
    #GameWorld.DebugLog("等待系统上架的拍品列表: %s" % sysAuctionItemList)
    # 随机邮件通知 
    if randMailKey:
        playerIDList = []
@@ -463,13 +553,34 @@
                continue
            playerIDList.append(player.GetPlayerID())
        PlayerCompensation.SendMailByKey(randMailKey, playerIDList, addItemList)
    return
def __DoSysWaitAddAuctionItem(tick):
    sysAuctionItemList = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemList") # 系统等待上架的拍品列表
    if not sysAuctionItemList:
        return
    doCount = len(sysAuctionItemList)
    while doCount > 0 and sysAuctionItemList:
        doCount -= 1
        addItemTick, itemInfo = sysAuctionItemList[0]
        if tick < addItemTick:
            #GameWorld.DebugLog("未到系统等待上架的拍品tick,不处理! tick=%s,sysAuctionItemList=%s" % (tick, sysAuctionItemList))
            break
        sysAuctionItemList.pop(0)
        GameWorld.DebugLog("系统等待上架的拍品tick已到,可上架! tick=%s >= addItemTick=%s,itemInfo=%s,sysAuctionItemList=%s" % (tick, addItemTick, itemInfo, sysAuctionItemList))
        DoAddSystemAuctionItem([itemInfo])
        
    if sysAuctionItemList:
        DoAddSystemAuctionItem(sysAuctionItemList)
    return
def OnAuctionItemTimeProcess(curTime, tick):
    ## 拍卖行拍品定时处理,每秒触发一次
    __DoSysBuyoutItemByTime(curTime)
    __DoSysWaitAddAuctionItem(tick)
    allAuctionItemByEndTimeList = PyDataManager.GetAuctionItemManager().allAuctionItemByEndTimeList
    if not allAuctionItemByEndTimeList:
        return
@@ -497,6 +608,89 @@
    __EndAuctionItem(endItemList, "ByTime")
    __MoveFamilyAuctionItemToWorld(moveToWorldItemList)
    return
def __DoSysBuyoutItemByTime(curTime):
    ## 系统一口价拍品
    sysBuyoutItemByTimeList = PyDataManager.GetAuctionItemManager().sysBuyoutItemByTimeList
    if not sysBuyoutItemByTimeList:
        return
    sysAuctionItemList = []
    color = 4 # 固定橙色
    isSuit = 0 # 固定非套装
    star = 0 # 固定0星
    endItemList = [] # 结束竞价的拍品列表
    doCount = len(sysBuyoutItemByTimeList)
    while doCount > 0 and sysBuyoutItemByTimeList:
        doCount -= 1
        auctionItem = sysBuyoutItemByTimeList[0]
        if curTime <= auctionItem.SysBuyTime:
            break
        sysBuyoutItemByTimeList.pop(0)
        if auctionItem.BidderPrice or auctionItem.BidderID:
            continue
        classLV = auctionItem.ItemClassLV
        if not classLV:
            continue
        itemID = auctionItem.ItemID
        ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
        if not ipyData:
            continue
        buyoutPrice = ipyData.GetBuyoutPrice()
        if not buyoutPrice:
            continue
        buyoutPrice *= auctionItem.Count
        auctionItem.BidderPrice = buyoutPrice # 没人竞价的系统直接一口价回收
        endItemList.append(auctionItem)
        # 生成系统补上架的装备信息
        randPlaceList = IpyGameDataPY.GetFuncEvalCfg("AuctionItemSystem", 4)
        if not randPlaceList:
            curPlace = itemID % 1000 / 10 # 倒数2、3位代表部位
            placeList = [curPlace]
        else:
            placeList = randPlaceList
        totalPlayerCount = 0
        jobWeightList = []
        openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
        for job in openJobList:
            jobPlayerCount = len(PyGameData.g_onedayJobPlayerLoginoffTimeDict.get(job, {}))
            jobPlayerCount = max(1, jobPlayerCount) # 人数默认至少1个
            totalPlayerCount += jobPlayerCount
            jobWeightList.append([jobPlayerCount, job])
            GameWorld.DebugLog("职业人数: job=%s,count=%s" % (job, jobPlayerCount))
        maxJobPer = IpyGameDataPY.GetFuncCfg("AuctionItemSystem", 3) # 单职业最大百分比
        if maxJobPer and maxJobPer < 100 and totalPlayerCount:
            minJobPer = 100 - maxJobPer # 单职业至少百分比
            for jobWeightInfo in jobWeightList:
                jobPlayerCount = jobWeightInfo[0]
                jobPer = int(jobPlayerCount * 100.0 / totalPlayerCount)
                jobPer = min(max(minJobPer, jobPer), maxJobPer)
                jobWeightInfo[0] = jobPer
        GameWorld.DebugLog("随机上架职业装备比重: jobWeightList=%s" % jobWeightList)
        job = GameWorld.GetResultByWeightList(jobWeightList)
        itemJobList = [job] if job != None else openJobList
        sysAuctionItemList.append([classLV, color, placeList, isSuit, star, itemJobList])
    if not endItemList:
        return
    __EndAuctionItem(endItemList, "SysBuyout")
    # 系统回收拍品后立即按规则补上架拍品
    if sysAuctionItemList:
        DoAddSystemAuctionItem(sysAuctionItemList)
    return
def __MoveFamilyAuctionItemToWorld(auctionItemList):
    ## 仙盟拍品转移到全服
@@ -569,6 +763,7 @@
    if isSortWorldItem:
        auctionItemMgr.worldAuctionItemList.sort(key=operator.attrgetter("Sortpriority", "AddTime"))
        auctionItemMgr.worldAuctionItemQueryDict = {} # 重置全服拍品条件查询,下次有玩家查询时再重新刷新
        auctionItemMgr.sysBuyoutItemByTimeList.sort(key=operator.attrgetter("SysBuyTime"))
    return
def __EndAuctionItem(endItemList, endEvent):
@@ -593,15 +788,16 @@
        bidderPrice = auctionItem.BidderPrice # 当前竞价,有人竞价的话代表竞拍成功
        endType = ""
        # 有人竞价,成交
        if bidderID and bidderPrice:
        if bidderPrice:
            endType = "OK"
            
            # 竞拍成功邮件,发放物品
            paramList = [bidderPrice]
            detail = {"ItemGUID":itemGUID}
            addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":False, "UserData":auctionItem.UserData}]
            PlayerCompensation.SendMailByKey("PaimaiMail3", [bidderID], addItemList, paramList, detail=detail)
            AddAuctionRecord(auctionItem, AuctionRecordResult_BidOK)
            if bidderID:
                paramList = [bidderPrice]
                detail = {"ItemGUID":itemGUID}
                addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":False, "UserData":auctionItem.UserData}]
                PlayerCompensation.SendMailByKey("PaimaiMail3", [bidderID], addItemList, paramList, detail=detail)
                AddAuctionRecord(auctionItem, AuctionRecordResult_BidOK)
            
            # 拍卖成功收益,都以玩家收益向上取整
            if familyID and auctionItem.FamilyPlayerIDInfo:
@@ -618,7 +814,7 @@
                    # 仙盟拍品收益邮件
                    detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice, "FamilyPlayerIDList":familyPlayerIDList}
                    paramList = [itemID, itemID, bidderPrice, taxRate, giveGoldAverage, personMaxRate]
                    PlayerCompensation.SendMailByKey("PaimaiMail8", familyPlayerIDList, [], paramList, gold=giveGoldAverage,
                    PlayerCompensation.SendMailByKey("PaimaiMail8", familyPlayerIDList, [], paramList, goldPaper=giveGoldAverage,
                                                     detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionGain)
                else:
                    GameWorld.ErrLog("仙盟拍品没有人获得收益!familyID=%s,itemID=%s,itemGUID=%s" % (familyID, itemID, itemGUID))
@@ -631,7 +827,7 @@
                # 个人拍卖收益邮件
                detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice}
                paramList = [itemID, itemID, bidderPrice, taxRate, givePlayerGold]
                PlayerCompensation.SendMailByKey("PaimaiMail7", [playerID], [], paramList, gold=givePlayerGold,
                PlayerCompensation.SendMailByKey("PaimaiMail7", [playerID], [], paramList, goldPaper=givePlayerGold,
                                                 detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionGain)
                
            else:
@@ -652,13 +848,17 @@
            elif playerID:
                endType = "Return"
                
                # 流拍返还物品邮件
                # 返还物品邮件
                paramList = []
                detail = {"ItemGUID":itemGUID}
                addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":True, "UserData":auctionItem.UserData}]
                PlayerCompensation.SendMailByKey("PaimaiMail4", [playerID], addItemList, paramList, detail=detail)
                AddAuctionRecord(auctionItem, AuctionRecordResult_SellFail)
                # 下架
                if endEvent == "Unsell":
                    PlayerCompensation.SendMailByKey("PaimaiMail9", [playerID], addItemList, paramList, detail=detail)
                    AddAuctionRecord(auctionItem, AuctionRecordResult_Unsell)
                else:
                    PlayerCompensation.SendMailByKey("PaimaiMail4", [playerID], addItemList, paramList, detail=detail)
                    AddAuctionRecord(auctionItem, AuctionRecordResult_SellFail)
            else:
                endType = "SystemDelete"
                GameWorld.Log("系统拍品流拍: itemGUID=%s,itemID=%s" % (itemGUID, itemID))
@@ -686,6 +886,9 @@
            if auctionItem in familyItemList:
                familyItemList.remove(auctionItem)
                
        if auctionItem in auctionItemMgr.sysBuyoutItemByTimeList:
            auctionItemMgr.sysBuyoutItemByTimeList.remove(auctionItem)
        for nowBiddingItemList in auctionItemMgr.nowBiddingAuctionItemDict.values():
            if auctionItem in nowBiddingItemList:
                nowBiddingItemList.remove(auctionItem)
@@ -774,6 +977,12 @@
            
        return
    
    # 下架拍品
    elif queryType == "UnsellAuctionItem":
        itemGUID = queryData[0]
        __DoUnsellAuctionItem(curPlayer, itemGUID)
        return
    elif queryType == "ClearAuctionItem":
        __DoGMClearAuctionItem(curPlayer)
        return
@@ -936,6 +1145,31 @@
            NetPackCommon.SendFakePack(player, infoPack)
    return
def __DoUnsellAuctionItem(curPlayer, itemGUID):
    ## 下架拍品
    auctionItem = GetAuctionItem(itemGUID)
    if not auctionItem:
        # 拍品不存在
        PlayerControl.NotifyCode(curPlayer, "Paimai3")
        return
    playerID = curPlayer.GetPlayerID()
    itemID = auctionItem.ItemID
    if auctionItem.FamilyID:
        GameWorld.ErrLog("仙盟拍品无法下架!itemGUID=%s,itemID=%s,itemFamilyID=%s"
                         % (itemGUID, itemID, auctionItem.FamilyID), playerID)
        return
    if auctionItem.PlayerID != playerID:
        GameWorld.ErrLog("不是玩家自己的拍品无法下架!itemGUID=%s,itemID=%s,itemPlayerID=%s"
                         % (itemGUID, itemID, auctionItem.PlayerID), playerID)
        return
    if auctionItem.BidderPrice:
        # 竞价中的拍品不能下架
        PlayerControl.NotifyCode(curPlayer, "Paimai9")
        return
    __EndAuctionItem([auctionItem], "Unsell")
    return
def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck):
    ''' 玩家竞价物品
    @param curPlayer: 竞价的玩家
@@ -1023,12 +1257,12 @@
        if isBuyout:
            # 竞拍失败,仅通知
            paramList = [itemID, itemID, lastBidderPrice]
            PlayerCompensation.SendMailByKey("PaimaiMail2", [lastBidderID], [], paramList, gold=lastBidderPrice,
            PlayerCompensation.SendMailByKey("PaimaiMail2", [lastBidderID], [], paramList, goldPaper=lastBidderPrice,
                                             detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionBidReturn)
        else:
            # 竞拍失败,可继续竞价邮件
            paramList = [itemID, itemID, lastBidderPrice, itemGUID]
            PlayerCompensation.SendMailByKey("PaimaiMail1", [lastBidderID], [], paramList, gold=lastBidderPrice,
            PlayerCompensation.SendMailByKey("PaimaiMail1", [lastBidderID], [], paramList, goldPaper=lastBidderPrice,
                                             detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionBidReturn)
        AddAuctionRecord(auctionItem, AuctionRecordResult_BidFail)
        
@@ -1077,6 +1311,10 @@
    GameWorld.DebugLog("玩家竞价拍品: itemGUID=%s,itemID=%s,isBuyout=%s,lastBidderID=%s,lastBidderPrice=%s,bidderIDInfo=%s" 
                       % (itemGUID, itemID, isBuyout, lastBidderID, lastBidderPrice, auctionItem.BidderIDInfo), playerID)
    
    if auctionItem in auctionItemMgr.sysBuyoutItemByTimeList:
        auctionItemMgr.sysBuyoutItemByTimeList.remove(auctionItem)
        #GameWorld.DebugLog("拍品有人竞价了,移除系统一口价拍品列表!")
    if isBuyout:        
        __EndAuctionItem([auctionItem], "Buyout")
    else:
@@ -1152,9 +1390,12 @@
    for i, auctionItem in enumerate(allAuctionItemByEndTimeList):
        GameWorld.DebugLog("    i=%s, %s" % (i, __GetAuctionItemDRDict(auctionItem)))
        
    GameWorld.DebugLog("AllDict总拍品数: =%s" % len(auctionItemMgr.allAuctionItemDict))
    GameWorld.DebugLog("AllDict总拍品数: %s" % len(auctionItemMgr.allAuctionItemDict))
    
    GameWorld.DebugLog("全服拍品个数: =%s" % len(auctionItemMgr.worldAuctionItemList))
    GameWorld.DebugLog("全服拍品个数: %s" % len(auctionItemMgr.worldAuctionItemList))
    GameWorld.DebugLog("系统一口价拍品个数: %s" % len(auctionItemMgr.sysBuyoutItemByTimeList))
    for familyID, familyItemList in auctionItemMgr.familyAuctionItemDict.items():
        GameWorld.DebugLog("仙盟拍品个数: familyID=%s, %s" % (familyID, len(familyItemList)))
        
@@ -1545,6 +1786,7 @@
def DoAddSystemAuctionItem(sysAuctionItemList):
    ''' 上架系统拍品
    @param sysAuctionItemList: [物品ID, [阶,颜色,[部位, ...],是否套装,星级,[可选参数职业, ...]], ...]
    '''
    mapID = ChConfig.Def_FBMapID_MainCity
    GameWorld.Log("发送地图上架系统拍品: mapID=%s, %s" % (mapID, sysAuctionItemList))