hxp
2019-03-04 3d658259b25c4914c766c43aeea883bdd0847c5d
6250 【后端】【2.0】拍卖行开发单
11个文件已修改
3个文件已添加
2085 ■■■■■ 已修改文件
ServerPython/CoreServerGroup/GameServer/PyNetPack.ini 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py 1367 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py 230 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/AuctionItem.py 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerAuctionHouse.py 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AuctionHouse.py 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -221,6 +221,34 @@
PacketSubCMD_1=0x03
PacketCallFunc_1=OnPYQueryBourseItemOnSale
;拍卖行
[AuctionHouse]
ScriptName = GameWorldLogic\AuctionHouse.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 5
PacketCMD_1=0xB5
PacketSubCMD_1=0x10
PacketCallFunc_1=OnQueryAuctionItem
PacketCMD_2=0xB5
PacketSubCMD_2=0x17
PacketCallFunc_2=OnQueryTagAuctionItem
PacketCMD_3=0xB5
PacketSubCMD_3=0x12
PacketCallFunc_3=OnQueryAuctionRecord
PacketCMD_4=0xB5
PacketSubCMD_4=0x16
PacketCallFunc_4=OnQueryAttentionAuctionItem
PacketCMD_5=0xB5
PacketSubCMD_5=0x18
PacketCallFunc_5=OnAttentionAuctionItemChange
;境界渡劫
[PlayerDuJie.py]
ScriptName = Player\PlayerDuJie.py
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -795,3 +795,38 @@
VIPPrivilege_XianyuanCoinUpperAdd,    #33 仙缘币上限加成
VIPPrivilege_XianyuanCoinAddPer,    #34 仙缘币获得倍率加成(万分比)
) = range(1, 35)
Def_MailMoneySource = "MoneySource" # 邮件货币来源key
#游戏货币来源类型定义
(
Def_GiveMoney_Unknown, # δ֪ 0
Def_GiveMoney_GM,
Def_GiveMoney_CTG,
Def_GiveMoney_GMTCTG,
Def_GiveMoney_CoinToGold,
Def_GiveMoney_SuperAccountCreate, # 创角赠送 5
Def_GiveMoney_Mission, # 任务
Def_GiveMoney_Pray, # 祈祷
Def_GiveMoney_UseItem, # 使用物品
Def_GiveMoney_Pickup, # ʰȡ
Def_GiveMoney_Bourse, # 交易所 10
Def_GiveMoney_GoldInvest, # 绑钻投资
Def_GiveMoney_Recover, # 资源找回
Def_GiveMoney_RedPacket, # 红包
Def_GiveMoney_RefineGift, # 炼制奖励
Def_GiveMoney_Mail, # 邮件(补偿) 15
Def_GiveMoney_RuneDecompose, # 符印
Def_GiveMoney_Warehouse, # 仓库
Def_GiveMoney_SellPackItem, # 出售背包物品
Def_GiveMoney_CollectNPC, # 采集NPC
Def_GiveMoney_HighLadder, # 天梯竞技场 20
Def_GiveMoney_StallItem, # 摆摊
Def_GiveMoney_Trade, # 交易
Def_GiveMoney_Truck, # 运镖
Def_GiveMoney_FreeGoods, # 极品白拿
Def_GiveMoney_BindJadeWheel, # 绑玉转盘 25
Def_GiveMoney_GatherSoulDecompose, #聚魂分解 26
Def_GiveMoney_AuctionBidReturn, #拍卖竞价返还
Def_GiveMoney_AuctionGain, #拍卖获得利润
) = range(1000, 1000 + 29)
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
@@ -6,91 +6,1334 @@
#
# @todo:拍卖行
# @author hxp
# @date 2019-02-19
# @date 2019-03-04
# @version 1.0
#
# 详细描述: 拍卖行
#
#-------------------------------------------------------------------------------
#"""Version = 2019-02-19 12:00"""
#"""Version = 2019-03-04 17:00"""
#-------------------------------------------------------------------------------
import CommFunc
import GameWorld
import PyDataManager
import PlayerControl
import DataRecordPack
import PyGameDataStruct
import PlayerCompensation
import ChPyNetSendPack
import IpyGameDataPY
import NetPackCommon
import PlayerBourse
import PlayerFamily
import ChConfig
import operator
import time
import math
import json
#拍卖关注管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
class AuctionAttentionManager(object):
# 拍卖记录类型定义
AuctionRecordTypeList = (
AuctionRecordType_MyAuction, # 我的拍品
AuctionRecordType_FamilyAuction, # 仙盟拍品
AuctionRecordType_MyBid, # 我的竞拍
) = range(3)
    
    def __init__(self):
# 拍卖记录结果定义
AuctionRecordResultList = (
AuctionRecordResult_SellFail, # 流拍
AuctionRecordResult_SellOK, # 拍卖成交
AuctionRecordResult_Recycle, # 系统回收
AuctionRecordResult_BidOK, # 竞价成功
AuctionRecordResult_BidFail, # 竞价失败
AuctionRecordResult_MoveToWorld, # 仙盟拍品转移到全服拍品
) = range(6)
# 当前拍品归类 0-全服拍品 1-仙盟私有拍品
AuctionType_World = 0
AuctionType_Family = 1
#拍卖行状态开关
def GetAuctionHouseState(): return PlayerBourse.GetOpenState()
def OnPlayerLogin(curPlayer):
    Sync_PlayerAuctionItemInfo(curPlayer)
    Sync_FamilyAuctionItemInfo(curPlayer, curPlayer.GetFamilyID())
    Sync_PlayerBiddingItemInfo(curPlayer)
    Sync_PlayerAttentionAuctionItemID(curPlayer, False)
        return
    
    ## ===========================================================================================
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        GameWorld.Log("Save AuctionAttention count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionAttention count :%s" % cnt)
        return pos
#拍卖记录管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
class AuctionRecordManager(object):
    def __init__(self):
def OnPlayerLeaveServer(curPlayer):
    playerID = curPlayer.GetPlayerID()
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    auctionItemMgr.myAttentionItemDict.pop(playerID, None)
        return
    
    ## ===========================================================================================
##--------------------------------------- 拍卖记录 -------------------------------------------------
def GetMyAuctionItemRecord(playerID):
    ## 获取我的拍品记录
    return PyDataManager.GetAuctionRecordManager().myAuctionItemRecordDict.get(playerID, [])
    
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
def GetMyBiddingItemRecord(playerID):
    ## 获取我的竞拍记录
    return PyDataManager.GetAuctionRecordManager().myBidItemRecordDict.get(playerID, [])
        
        GameWorld.Log("Save AuctionRecord count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
def GetFamilyAuctionItemRecord(familyID):
    ## 获取仙盟拍品记录
    return PyDataManager.GetAuctionRecordManager().familyAuctionItemRecordDict.get(familyID, [])
    
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionRecord count :%s" % cnt)
        return pos
#拍卖物品管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
class AuctionItemManager(object):
    def __init__(self):
def AddAuctionRecord(auctionItem, recordResult):
    ''' 添加拍卖行记录
    @param auctionItem: 相关的拍品实例
    @param recordResult: 记录结果 0-流拍 1-拍卖成交 2-回收 3-竞价成功 4-竞价失败
    '''
    if not auctionItem:
        return
    
    ## ===========================================================================================
    playerID, familyID, bidderID = auctionItem.PlayerID, auctionItem.FamilyID, auctionItem.BidderID
    recordPlayerID, recordFamilyID = 0, 0
    
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
    if recordResult in [AuctionRecordResult_BidOK, AuctionRecordResult_BidFail]:
        recordType = AuctionRecordType_MyBid
        recordPlayerID = bidderID
    else:
        if familyID:
            recordType = AuctionRecordType_FamilyAuction
            recordFamilyID = familyID
        else:
            recordType = AuctionRecordType_MyAuction
            recordPlayerID = playerID
        
        GameWorld.Log("Save AuctionItem count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    if not recordPlayerID and not recordFamilyID:
        return
    
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionItem count :%s" % cnt)
    newRecordData = PyGameDataStruct.tagDBAuctionRecord()
    newRecordData.ItemGUID = auctionItem.ItemGUID
    newRecordData.PlayerID = recordPlayerID
    newRecordData.FamilyID = recordFamilyID
    newRecordData.RecordType = recordType
    newRecordData.RecordResult = recordResult
    newRecordData.RecordTime = GameWorld.GetCurrentDataTimeStr()
    newRecordData.BidderPrice = auctionItem.BidderPrice
    newRecordData.BidderName = auctionItem.BidderName
    newRecordData.ItemID = auctionItem.ItemID
    newRecordData.Count = auctionItem.Count
    newRecordData.UserData = auctionItem.UserData
    newRecordData.UserDataLen = auctionItem.UserDataLen
    AddNewAuctionRecord(newRecordData)
        
        return pos
    if recordFamilyID:
        Sync_PlayerAuctionRecordInfo(None, recordType, newRecordData, recordFamilyID)
    elif recordPlayerID:
        recordPlayer = GameWorld.GetPlayerManager().FindPlayerByID(recordPlayerID)
        if recordPlayer and not PlayerControl.GetIsTJG(recordPlayer):
            Sync_PlayerAuctionRecordInfo(recordPlayer, recordType, newRecordData)
    return
    
def AddNewAuctionRecord(newRecordData):
    playerID = newRecordData.PlayerID
    familyID = newRecordData.FamilyID
    recordType = newRecordData.RecordType
    if recordType == AuctionRecordType_MyAuction:
        keyID = playerID
        recordDict = PyDataManager.GetAuctionRecordManager().myAuctionItemRecordDict
    elif recordType == AuctionRecordType_FamilyAuction:
        keyID = familyID
        recordDict = PyDataManager.GetAuctionRecordManager().familyAuctionItemRecordDict
    elif recordType == AuctionRecordType_MyBid:
        keyID = playerID
        recordDict = PyDataManager.GetAuctionRecordManager().myBidItemRecordDict
    else:
        return
    recordList = recordDict.get(keyID, [])
    maxCount = min(50, IpyGameDataPY.GetFuncCfg("AuctionHouse", 3))
    if len(recordList) >= maxCount:
        del recordList[0]
    recordList.append(newRecordData)
    recordDict[keyID] = recordList
    return
##-------------------------------------- 拍卖关注 ------------------------------------------------
def GetPlayerAuctionAttention(attentionMgr, playerID):
    ## 获取玩家关注的物品ID列表
    if playerID not in attentionMgr.playerAttentionDict:
        return []
    attentionObj = attentionMgr.playerAttentionDict[playerID]
    attentionItemIDList = attentionObj.AttentionItemIDList
    return attentionItemIDList
def AddPlayerAuctionAttention(attentionMgr, playerID, itemID):
    ## 添加玩家关注的物品ID
    if playerID not in attentionMgr.playerAttentionDict:
        dbData = PyGameDataStruct.tagDBAuctionAttention()
        dbData.PlayerID = playerID
        __InitAuctionAttentionAttrEx(dbData)
        attentionMgr.playerAttentionDict[playerID] = dbData
    attentionObj = attentionMgr.playerAttentionDict[playerID]
    attentionItemIDList = attentionObj.AttentionItemIDList
    if len(attentionItemIDList) >= IpyGameDataPY.GetFuncCfg("AuctionHouse", 5):
        GameWorld.DebugLog("关注拍品数达到上限!", playerID)
        return
    if itemID in attentionItemIDList:
        return True
    attentionItemIDList.append(itemID)
    attentionObj.AttentionInfo = str(attentionItemIDList)
    attentionObj.AttentionLen = len(attentionObj.AttentionInfo)
    return True
def DelPlayerAuctionAttention(attentionMgr, playerID, itemID):
    ## 删除玩家关注的物品ID
    if playerID not in attentionMgr.playerAttentionDict:
        return
    attentionObj = attentionMgr.playerAttentionDict[playerID]
    attentionItemIDList = attentionObj.AttentionItemIDList
    if itemID not in attentionItemIDList:
        return
    attentionItemIDList.remove(itemID)
    attentionObj.AttentionInfo = str(attentionItemIDList)
    attentionObj.AttentionLen = len(attentionObj.AttentionInfo)
    return True
def OnLoadAuctionAttentionDataEx(attentionData):
    ## 加载拍卖关注表时附加处理
    __InitAuctionAttentionAttrEx(attentionData)
    return
def __InitAuctionAttentionAttrEx(attentionData):
    ## 初始化拍卖关注实例附加属性
    setattr(attentionData, "AttentionItemIDList", [] if not attentionData.AttentionInfo else json.loads(attentionData.AttentionInfo))
    return
##-------------------------------------------------------------------------------------------------
def OnLoadAuctionItemDataEx(dbData):
    ## 加载拍卖物品表时附加处理
    __InitAuctionItemAttrEx(dbData)
    playerID = dbData.PlayerID
    familyID = dbData.FamilyID
    bidderID = dbData.BidderID
    pyAuctionItemMgr = PyDataManager.GetAuctionItemManager()
    pyAuctionItemMgr.allAuctionItemByEndTimeList.append(dbData)
    if dbData.AuctionType == AuctionType_World:
        pyAuctionItemMgr.worldAuctionItemList.append(dbData)
    if familyID:
        familyItemList = pyAuctionItemMgr.familyAuctionItemDict.get(familyID, [])
        familyItemList.append(dbData)
        pyAuctionItemMgr.familyAuctionItemDict[familyID] = familyItemList
    if playerID:
        myItemList = pyAuctionItemMgr.myAuctionItemDict.get(playerID, [])
        myItemList.append(dbData)
        pyAuctionItemMgr.myAuctionItemDict[playerID] = myItemList
        if str(playerID) in dbData.BidderIDInfo:
            if playerID == bidderID:
                nowBidItemList = pyAuctionItemMgr.nowBiddingAuctionItemDict.get(playerID, [])
                nowBidItemList.append(dbData)
                pyAuctionItemMgr.nowBiddingAuctionItemDict[playerID] = nowBidItemList
            else:
                hisBidItemList = pyAuctionItemMgr.hisBiddingAuctionItemDict.get(playerID, [])
                hisBidItemList.append(dbData)
                pyAuctionItemMgr.hisBiddingAuctionItemDict[playerID] = hisBidItemList
    return
def OnLoadAuctionItemDataOK():
    ## 加载拍卖物品表完成后的处理
    __SortAuctionitem()
    return
def __InitAuctionItemAttrEx(auctionItem, ipyData=None):
    ## 初始化拍品实例附加属性
    if not ipyData:
        ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", auctionItem.ItemID)
    setattr(auctionItem, "Sortpriority", 99999 - (0 if not ipyData else ipyData.GetSortpriority())) # 排序优先级归组
    setattr(auctionItem, "BiddingQueryID", 0) # 当前正在竞价的玩家ID
    setattr(auctionItem, "BiddingQueryTick", 0) # 当前正在竞价的tick
    setattr(auctionItem, "EndTime", 0) # 结束竞价time值
    __SetAuctionItemEndTime(auctionItem, ipyData)
    return True
def __SetAuctionItemEndTime(auctionItem, ipyData):
    ## 更新拍品结束竞价time值
    if not ipyData:
        return
    addTimeStr = auctionItem.AddTime
    auctionType = auctionItem.AuctionType
    addTime = GameWorld.ChangeTimeStrToNum(addTimeStr)
    noticeMinutes = ipyData.GetNoticeSaleMinutes()
    saleMinutes = ipyData.GetFamilySaleMinutes() if auctionType == AuctionType_Family else ipyData.GetWorldSaleMinutes()
    auctionItem.EndTime = addTime + (noticeMinutes + saleMinutes) * 60
    __AddAuctionItemEndTimeByBid(auctionItem)
    return
def __AddAuctionItemEndTimeByBid(auctionItem):
    # 根据最后一次竞价时间进行加时
    if not auctionItem.BidderPrice:
        return
    bidTime = GameWorld.ChangeTimeStrToNum(auctionItem.BiddingTime)
    endTime = bidTime + IpyGameDataPY.GetFuncCfg("AuctionHouse", 4)
    if endTime < auctionItem.EndTime:
        return
    auctionItem.EndTime = endTime
    return True
def __GetAuctionItemDRDict(auctionItem):
    drDict = {"GUID":auctionItem.ItemGUID, "PlayerID":auctionItem.PlayerID, "FamilyID":auctionItem.FamilyID,
              "ItemID":auctionItem.ItemID, "Count":auctionItem.Count, "AuctionType":auctionItem.AuctionType,
              "AddTime":auctionItem.AddTime, "BiddingTime":auctionItem.BiddingTime, "BidderID":auctionItem.BidderID,
              "BidderPrice":auctionItem.BidderPrice, "UserData":auctionItem.UserData,
              "EndTime":"" if not auctionItem.EndTime else GameWorld.ChangeTimeNumToStr(auctionItem.EndTime),
              "FamilyPlayerIDInfo":auctionItem.FamilyPlayerIDInfo, "BidderIDInfo":auctionItem.BidderIDInfo}
    return drDict
def GetAuctionItem(itemGUID):
    ## 获取拍品实例
    return PyDataManager.GetAuctionItemManager().allAuctionItemDict.get(itemGUID)
def GetPlayerAuctionItemList(playerID):
    ## 玩家拍卖中的拍品列表
    return PyDataManager.GetAuctionItemManager().myAuctionItemDict.get(playerID, [])
def GetFamilyAuctionItemList(familyID):
    ## 仙盟拍卖中的拍品列表
    return PyDataManager.GetAuctionItemManager().familyAuctionItemDict.get(familyID, [])
def OnAuctionItemTimeProcess(curTime):
    ## 拍卖行拍品定时处理,每秒触发一次
    allAuctionItemByEndTimeList = PyDataManager.GetAuctionItemManager().allAuctionItemByEndTimeList
    if not allAuctionItemByEndTimeList:
        return
    endItemList = [] # 结束竞价的拍品列表
    moveToWorldItemList = [] # 转移到全服拍卖的仙盟拍品列表
    doCount = len(allAuctionItemByEndTimeList)
    while doCount > 0 and allAuctionItemByEndTimeList:
        doCount -= 1
        auctionItem = allAuctionItemByEndTimeList[0]
        if curTime < auctionItem.EndTime:
            break
        allAuctionItemByEndTimeList.pop(0)
        # 没有人竞价的仙盟拍品
        if not auctionItem.BidderPrice and auctionItem.FamilyID and auctionItem.AuctionType == AuctionType_Family:
            moveToWorldItemList.append(auctionItem)
        else:
            endItemList.append(auctionItem)
    __EndAuctionItem(endItemList, "ByTime")
    __MoveFamilyAuctionItemToWorld(moveToWorldItemList)
    return
def __MoveFamilyAuctionItemToWorld(auctionItemList):
    ## 仙盟拍品转移到全服
    if not auctionItemList:
        return
    curTimeStr = GameWorld.GetCurrentDataTimeStr()
    attentionMgr = PyDataManager.GetAuctionAttentionManager()
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    notifyWorldAddItemList = [] # 新增全服拍品通知 [[itemGUID, itemID, playerID], ...]
    for auctionItem in auctionItemList:
        itemGUID = auctionItem.ItemGUID
        itemID = auctionItem.ItemID
        itemCount = auctionItem.Count
        playerID = auctionItem.PlayerID
        familyID = auctionItem.FamilyID
        ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
        auctionItem.AuctionType = AuctionType_World
        auctionItem.AddTime = curTimeStr
        __SetAuctionItemEndTime(auctionItem, ipyData)
        auctionItemMgr.allAuctionItemByEndTimeList.append(auctionItem)
        auctionItemMgr.worldAuctionItemList.append(auctionItem)
        notifyWorldAddItemList.append([itemGUID, itemID, playerID])
        # 添加进我的关注
        for attentionPlayerID, attentionList in auctionItemMgr.myAttentionItemDict.items():
            if itemID not in GetPlayerAuctionAttention(attentionMgr, attentionPlayerID):
                continue
            if auctionItem not in attentionList:
                attentionList.append(auctionItem)
        if ipyData.GetNeedWorldNotify():
            PlayerControl.WorldNotify(0, "Paimai4", [itemID, ipyData.GetNoticeSaleMinutes()])
        drDict = {"AuctionItemInfo":__GetAuctionItemDRDict(auctionItem)}
        DR_AuctionHouse(None, "FamilyToWorld", drDict)
        GameWorld.DebugLog("仙盟拍品转移到全服: itemID=%s,itemCount=%s,familyID=%s,itemGUID=%s"
                           % (itemID, itemCount, familyID, itemGUID))
    __SortAuctionitem()
    __SyncRefreshAuctionItem(auctionItemList)
    __NotifyAuctionPlayerAddItem(notifyWorldAddItemList)
    return
def __SortAuctionitem(isSortWorldItem=True):
    ''' 刷新全部拍品排序
        后端排序
        1.全服拍品: 因为全服拍品数量比较大,采用只查询指定个数拍品,所以只能由后端排序后同步
        2.全部拍品竞价结束时间:后端需要处理竞价结束
        前端排序:
        1.个人拍品:个数较少,全部同步,由前端自己排序
        2.仙盟拍品:个数较少,全部同步,由前端自己排序
        3.竞价拍品:个数较少,全部同步,由前端自己整合排序,区分最高竞价、历史竞价
        4.关注拍品:个数较少,全部同步,由前端自己排序
        触发排序时机:
        1-上架新全服拍品
        2-仙盟拍品转移全服拍品,相当于上架新全服拍品
        3-竞价拍品触发加时时,需要对结束时间重排,竞价加时的只触发加时,对全服拍品的排序没有影响,故可不重拍全服拍品
    '''
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    auctionItemMgr.allAuctionItemByEndTimeList.sort(key=operator.attrgetter("EndTime"))
    if isSortWorldItem:
        auctionItemMgr.worldAuctionItemList.sort(key=operator.attrgetter("Sortpriority", "AddTime"))
        auctionItemMgr.worldAuctionItemQueryDict = {} # 重置全服拍品条件查询,下次有玩家查询时再重新刷新
    return
def __EndAuctionItem(endItemList, endEvent):
    ''' 结束拍品竞拍
    @param delItemStateDict: 删除的拍品竞拍状态
    '''
    if not endItemList:
        return 0
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    clearAuctionItemList = []
    for auctionItem in endItemList:
        if not auctionItem:
            continue
        itemGUID = auctionItem.ItemGUID
        itemID = auctionItem.ItemID
        itemCount = auctionItem.Count
        playerID = auctionItem.PlayerID
        familyID = auctionItem.FamilyID
        bidderID = auctionItem.BidderID # 当前竞价玩家ID
        bidderPrice = auctionItem.BidderPrice # 当前竞价,有人竞价的话代表竞拍成功
        endType = ""
        # 有人竞价,成交
        if bidderID and bidderPrice:
            endType = "OK"
            # 竞拍成功邮件,发放物品
            paramList = [bidderPrice]
            detail = {"ItemGUID":itemGUID}
            addItemList = [{"ItemID":itemID, "Count":itemCount, "IsBind":True, "UserData":auctionItem.UserData}]
            PlayerCompensation.SendMailByKey("PaimaiMail3", [bidderID], addItemList, paramList, detail=detail)
            AddAuctionRecord(auctionItem, AuctionRecordResult_BidOK)
            # 拍卖成功收益,都以玩家收益向上取整
            if familyID and auctionItem.FamilyPlayerIDInfo:
                familyPlayerIDList = json.loads(auctionItem.FamilyPlayerIDInfo)
                taxRate = IpyGameDataPY.GetFuncCfg("AuctionTaxrate", 2) # 仙盟拍品税率百分比
                personMaxRate = IpyGameDataPY.GetFuncCfg("AuctionTaxrate", 3) # 仙盟拍品个人最大收益百分比
                giveTotalGold = int(math.ceil(bidderPrice * (100 - taxRate) / 100.0))
                giveMaxGold = int(math.ceil(giveTotalGold * personMaxRate / 100.0))
                memCount = len(familyPlayerIDList)
                giveGoldAverage = min(giveMaxGold, int(math.ceil(giveTotalGold * 1.0 / memCount))) # 有收益的人平分
                # 仙盟拍品收益邮件
                detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice, "FamilyPlayerIDList":familyPlayerIDList,
                          ChConfig.Def_MailMoneySource:ChConfig.Def_GiveMoney_AuctionGain}
                paramList = [itemID, auctionItem.BidderName, bidderPrice, taxRate, giveGoldAverage, personMaxRate]
                PlayerCompensation.SendMailByKey("PaimaiMail6", familyPlayerIDList, [], paramList, gold=giveGoldAverage, detail=detail)
            elif playerID:
                taxRate = IpyGameDataPY.GetFuncCfg("AuctionTaxrate", 1) # 全服拍品税率百分比
                givePlayerGold = int(math.ceil(bidderPrice * (100 - taxRate) / 100.0))
                # 个人拍卖收益邮件
                detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice,
                          ChConfig.Def_MailMoneySource:ChConfig.Def_GiveMoney_AuctionGain}
                paramList = [itemID, auctionItem.BidderName, bidderPrice, taxRate, givePlayerGold]
                PlayerCompensation.SendMailByKey("PaimaiMail5", [playerID], [], paramList, gold=givePlayerGold, detail=detail)
            AddAuctionRecord(auctionItem, AuctionRecordResult_SellOK)
        else:
            # 仙盟拍品回收
            if familyID:
                endType = "Recycle"
                AddAuctionRecord(auctionItem, AuctionRecordResult_Recycle)
            # 个人拍品流拍,物品返还
            else:
                endType = "Return"
                # 流拍返还物品邮件
                paramList = []
                detail = {"ItemGUID":itemGUID}
                addItemList = [{"ItemID":itemID, "Count":itemCount, "IsBind":True, "UserData":auctionItem.UserData}]
                PlayerCompensation.SendMailByKey("PaimaiMail4", [playerID], addItemList, paramList, detail=detail)
                AddAuctionRecord(auctionItem, AuctionRecordResult_SellFail)
        drDict = {"AuctionItemInfo":__GetAuctionItemDRDict(auctionItem), "EndType":endType, "EndEvent":endEvent}
        DR_AuctionHouse(None, "EndAuctionItem", drDict)
        GameWorld.DebugLog("结束竞拍: itemID=%s,itemCount=%s,familyID=%s,endType=%s,endEvent=%s,itemGUID=%s"
                           % (itemID, itemCount, familyID, endType, endEvent, itemGUID), playerID)
        auctionItemMgr.allAuctionItemDict.pop(itemGUID, None)
        if auctionItem in auctionItemMgr.allAuctionItemByEndTimeList:
            auctionItemMgr.allAuctionItemByEndTimeList.remove(auctionItem)
        if auctionItem in auctionItemMgr.worldAuctionItemList:
            auctionItemMgr.worldAuctionItemList.remove(auctionItem)
        for queryItemList in auctionItemMgr.worldAuctionItemQueryDict.values():
            if auctionItem in queryItemList:
                queryItemList.remove(auctionItem)
        if familyID and familyID in auctionItemMgr.familyAuctionItemDict:
            familyItemList = auctionItemMgr.familyAuctionItemDict[familyID]
            if auctionItem in familyItemList:
                familyItemList.remove(auctionItem)
        for nowBiddingItemList in auctionItemMgr.nowBiddingAuctionItemDict.values():
            if auctionItem in nowBiddingItemList:
                nowBiddingItemList.remove(auctionItem)
        for hisBiddingItemList in auctionItemMgr.hisBiddingAuctionItemDict.values():
            if auctionItem in hisBiddingItemList:
                hisBiddingItemList.remove(auctionItem)
        if playerID and playerID in auctionItemMgr.myAuctionItemDict:
            playerItemList = auctionItemMgr.myAuctionItemDict[playerID]
            if auctionItem in playerItemList:
                playerItemList.remove(auctionItem)
        for attentionItemList in auctionItemMgr.myAttentionItemDict.values():
            if auctionItem in attentionItemList:
                attentionItemList.remove(auctionItem)
        clearItem = ChPyNetSendPack.tagGCClearAuctionItem()
        clearItem.ItemGUID = itemGUID
        clearAuctionItemList.append(clearItem)
    if not clearAuctionItemList:
        return 0
    clearCount = len(clearAuctionItemList)
    clientPack = ChPyNetSendPack.tagGCClearAuctionItemInfo()
    clientPack.ClearAuctionItemList = clearAuctionItemList
    clientPack.ClearCount = len(clientPack.ClearAuctionItemList)
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        player = playerManager.GetActivePlayerAt(i)
        if player == None:
            continue
        if PlayerControl.GetIsTJG(player):
            continue
        NetPackCommon.SendFakePack(player, clientPack)
    return clearCount
def MapServer_AuctionHouseLogic(curPlayer, msgList, tick):
    ## 地图玩家拍卖处理
    playerID = 0 if not curPlayer else curPlayer.GetPlayerID()
    queryType, queryData = msgList
    result = []
    GameWorld.Log("收到地图拍卖行信息: queryType=%s,queryData=%s" % (queryType, queryData), playerID)
    if not GetAuctionHouseState():
        if curPlayer:
            PlayerControl.NotifyCode(curPlayer, "AuctionHouseClose")
        return
    # 查询玩家可否上架
    if queryType == "AddAuctionItemQuery":
        canSell = __CheckPlayerCanAddAuctionItem(curPlayer)
        if not canSell:
            return
        result = [canSell]
    # 执行上架物品
    elif queryType == "AddAuctionItem":
        addAuctionItemList = queryData
        __AddAuctionItemByList(curPlayer, addAuctionItemList)
        return
    # 查询玩家可否竞价物品
    elif queryType == "BidAuctionItemQuery":
        itemGUID, biddingPrice = queryData
        itemID, errInfo = __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, True)
        GameWorld.DebugLog("    itemID=%s,errInfo=%s" % (itemID, errInfo), playerID)
        if errInfo:
            return
        if not itemID:
            return
        result = [itemID]
    # 执行玩家竞价物品
    elif queryType == "BidAuctionItem":
        itemGUID, biddingPrice = queryData
        itemID, errInfo = __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, False)
        if errInfo:
            GameWorld.DebugLog("    errInfo=%s" % errInfo, playerID)
            drDict = {"ItemGUID":itemGUID, "BiddingPrice":biddingPrice, "ErrInfo":errInfo}
            DR_AuctionHouse(curPlayer, "BidAuctionItemError", drDict)
        return
    elif queryType == "ClearAuctionItem":
        __DoGMClearAuctionItem(curPlayer)
        return
    elif queryType == "PrintAuctionItem":
        __DoGMPrintAuctionItem(curPlayer)
        return
    resultMsg = str([queryType, queryData, result])
    if curPlayer:
        curPlayer.MapServer_QueryPlayerResult(0, 0, "AuctionHouse", resultMsg, len(resultMsg))
    return
def __CheckPlayerCanAddAuctionItem(curPlayer):
    ## 检查玩家可否上架拍品
    playerID = curPlayer.GetPlayerID()
    maxSellCount = IpyGameDataPY.GetFuncCfg("AuctionHouse", 2)
    if maxSellCount:
        playerAuctionItemList = GetPlayerAuctionItemList(playerID)
        playerSellCount = len(playerAuctionItemList)
        canSell = playerSellCount < maxSellCount
        if not canSell:
            PlayerControl.NotifyCode(curPlayer, "SellCountLimit")
        return canSell
    return True
def __AddAuctionItemByList(curPlayer, addAuctionItemList):
    ''' 批量添加拍品
    @param curPlayer: 可能为None
    '''
    notifyWorldAddItemList = [] # 新增全服拍品通知 [[itemGUID, itemID, playerID], ...]
    notifyFamilyAddItemDict = {} # 新增仙盟拍品通知 {familyID:[auctionItem, ...], ...}
    for playerID, familyID, familyPlayerIDList, itemData in addAuctionItemList:
        if not playerID and not familyID:
            continue
        auctionItem = __DoAddAuctionItem(curPlayer, playerID, familyID, familyPlayerIDList, itemData)
        if not auctionItem:
            continue
        if familyID:
            familyAddItemList = notifyFamilyAddItemDict.get(familyID, [])
            familyAddItemList.append(auctionItem)
            notifyFamilyAddItemDict[familyID] = familyAddItemList
        else:
            itemGUID = auctionItem.ItemGUID
            itemID = auctionItem.ItemID
            notifyWorldAddItemList.append([itemGUID, itemID, playerID])
    if notifyFamilyAddItemDict or notifyWorldAddItemList:
        isSortWorldItem = notifyWorldAddItemList != []
        __SortAuctionitem(isSortWorldItem=isSortWorldItem)
    # 通知新增仙盟拍品
    for familyID, familyAddItemList in notifyFamilyAddItemDict.items():
        Sync_FamilyAuctionItemInfo(None, familyID, familyAddItemList)
    # 通知全服拍品关注玩家
    __NotifyAuctionPlayerAddItem(notifyWorldAddItemList)
    return
def __DoAddAuctionItem(curPlayer, playerID, familyID, familyPlayerIDList, itemData):
    ## 添加拍品
    itemID = itemData.get("ItemID", 0)
    ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
    if not ipyData:
        return
    itemGUID = itemData.get("GUID", "")
    auctionItem = PyGameDataStruct.tagDBAuctionItem()
    auctionItem.ItemGUID = itemGUID
    auctionItem.PlayerID = playerID
    auctionItem.FamilyID = familyID
    auctionItem.ItemID = itemID
    auctionItem.Count = itemData.get("ItemCount", 0)
    auctionItem.AddTime = GameWorld.GetCurrentDataTimeStr()
    auctionItem.ItemType = itemData.get("ItemType", 0)
    auctionItem.ItemJobLimit = itemData.get("ItemJobLimit", 0)
    auctionItem.ItemClassLV = itemData.get("ItemClassLV", 0)
    auctionItem.UserData = itemData.get("UserData", "")
    auctionItem.UserDataLen = len(auctionItem.UserData)
    auctionItem.FamilyPlayerIDInfo = str(familyPlayerIDList)
    auctionItem.FamilyPlayerIDLen = len(auctionItem.FamilyPlayerIDInfo)
    if not __InitAuctionItemAttrEx(auctionItem):
        return
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    auctionItemMgr.allAuctionItemDict[auctionItem.ItemGUID] = auctionItem
    auctionItemMgr.allAuctionItemByEndTimeList.append(auctionItem)
    if familyID:
        auctionItem.AuctionType = AuctionType_Family
        familyItemList = auctionItemMgr.familyAuctionItemDict.get(familyID, [])
        familyItemList.append(auctionItem)
        auctionItemMgr.familyAuctionItemDict[familyID] = familyItemList
    else:
        auctionItem.AuctionType = AuctionType_World
        auctionItemMgr.worldAuctionItemList.append(auctionItem)
        # 添加进我的拍卖
        if playerID:
            myAuctionItemList = auctionItemMgr.myAuctionItemDict.get(playerID, [])
            myAuctionItemList.append(auctionItem)
            auctionItemMgr.myAuctionItemDict[playerID] = myAuctionItemList
            if curPlayer:
                Sync_PlayerAuctionItemInfo(curPlayer, auctionItem)
        # 添加进我的关注
        attentionMgr = PyDataManager.GetAuctionAttentionManager()
        for attentionPlayerID, attentionList in auctionItemMgr.myAttentionItemDict.items():
            if itemID not in GetPlayerAuctionAttention(attentionMgr, attentionPlayerID):
                continue
            if auctionItem not in attentionList:
                attentionList.append(auctionItem)
        if ipyData.GetNeedWorldNotify():
            PlayerControl.WorldNotify(0, "Paimai4", [itemID, ipyData.GetNoticeSaleMinutes()])
    drDict = {"AuctionItemInfo":__GetAuctionItemDRDict(auctionItem)}
    DR_AuctionHouse(curPlayer, "AddAuctionItem", drDict)
    GameWorld.DebugLog("上架拍品: playerID=%s,familyID=%s,%s" % (playerID, familyID, drDict), playerID)
    GameWorld.DebugLog("更新拍品数: %s" % len(auctionItemMgr.allAuctionItemDict))
    return auctionItem
def __NotifyAuctionPlayerAddItem(notifyWorldAddItemList):
    ## 通知关注物品的玩家新上架物品了
    if not notifyWorldAddItemList:
        return
    attentionMgr = PyDataManager.GetAuctionAttentionManager()
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        player = playerManager.GetActivePlayerAt(i)
        if player == None:
            continue
        if PlayerControl.GetIsTJG(player):
            continue
        playerAttentionIDList = GetPlayerAuctionAttention(attentionMgr, player.GetPlayerID())
        if not playerAttentionIDList:
            continue
        infoPack = None
        for itemGUID, itemID, playerID in notifyWorldAddItemList:
            if playerID == player.GetPlayerID():
                # 自己上架的物品不通知
                continue
            if itemID not in playerAttentionIDList:
                continue
            if not infoPack:
                infoPack = ChPyNetSendPack.tagGCAddAuctionItemInfo()
            itemInfo = ChPyNetSendPack.tagGCAddAuctionItem()
            itemInfo.ItemGUID = itemGUID
            itemInfo.ItemID = itemID
            infoPack.AddAuctionItemList.append(itemInfo)
        if infoPack:
            infoPack.AddCount = len(infoPack.AddAuctionItemList)
            NetPackCommon.SendFakePack(player, infoPack)
    return
def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck):
    ''' 玩家竞价物品
    @param curPlayer: 竞价的玩家
    @param itemGUID: 拍品GUID
    @param biddingPrice: 竞价
    @param isOnlyCheck: 是否仅检查可否竞价
    '''
    errInfo = ""
    itemID = 0
    auctionItem = GetAuctionItem(itemGUID)
    if not auctionItem:
        # 拍品不存在
        PlayerControl.NotifyCode(curPlayer, "Paimai3")
        errInfo = "not auctionItem"
        return itemID, errInfo
    itemID = auctionItem.ItemID
    ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
    if not ipyData:
        errInfo = "not ipyData"
        return itemID, errInfo
    playerID = curPlayer.GetPlayerID()
    addTimeStr = auctionItem.AddTime
    auctionType = auctionItem.AuctionType # 0-全服拍品,1-仙盟拍品
    addTime = GameWorld.ChangeTimeStrToNum(addTimeStr)
    curTime = int(time.time())
    passMinutes = (curTime - addTime) / 60
    noticeMinutes = ipyData.GetNoticeSaleMinutes()
    if passMinutes < noticeMinutes:
        GameWorld.ErrLog("拍品尚未开放竞价! itemGUID=%s,itemID=%s,addTimeStr=%s" % (itemGUID, itemID, addTimeStr), playerID)
        errInfo = "in notice time"
        return itemID, errInfo
    if auctionType == AuctionType_Family:
        itemFamilyID = auctionItem.FamilyID
        playerFamilyID = curPlayer.GetFamilyID()
        if not playerFamilyID or playerFamilyID != itemFamilyID:
            GameWorld.ErrLog("该拍品为仙盟私有拍品,非本仙盟人员不可竞拍! itemGUID=%s,itemID=%s,itemFamilyID=%s,playerFamilyID=%s"
                             % (itemGUID, itemID, itemFamilyID, playerFamilyID), playerID)
            errInfo = "is family auction item"
            return itemID, errInfo
    if curTime >= auctionItem.EndTime:
        GameWorld.ErrLog("拍品已结束竞价! itemGUID=%s,itemID=%s,addTimeStr=%s" % (itemGUID, itemID, addTimeStr), playerID)
        errInfo = "end bid"
        return itemID, errInfo
    nextPrice = ipyData.GetBasePrice() if not auctionItem.BidderPrice else (auctionItem.BidderPrice + ipyData.GetBiddingAdd())
    buyoutPrice = ipyData.GetBuyoutPrice() # 允许没有一口价的,代表可以一直竞价
    nextPrice = nextPrice if not buyoutPrice else min(nextPrice, buyoutPrice) # 不超过一口价
    if not (biddingPrice == nextPrice or (buyoutPrice and biddingPrice == buyoutPrice)):
        # 竞价价格错误
        PlayerControl.NotifyCode(curPlayer, "Paimai2")
        errInfo = "bid price error! biddingPrice=%s,nextPrice=%s,buyoutPrice=%s,itemGUID=%s,itemID=%s" % (biddingPrice, nextPrice, buyoutPrice, itemGUID, itemID)
        return itemID, errInfo
    if isOnlyCheck:
        queryTick = auctionItem.BiddingQueryTick
        if queryTick and tick - queryTick < 10000:
            # 有玩家正在竞价,请稍等
            PlayerControl.NotifyCode(curPlayer, "Paimai1")
            errInfo = "other player bidding"
            return itemID, errInfo
        auctionItem.BiddingQueryID = playerID
        auctionItem.BiddingQueryTick = tick
        return itemID, errInfo
    if auctionItem.BiddingQueryID != playerID:
        PlayerControl.NotifyCode(curPlayer, "Paimai2")
        errInfo = "bidding player error"
        return itemID, errInfo
    lastBidderID = auctionItem.BidderID
    lastBidderPrice = auctionItem.BidderPrice
    itemCount = auctionItem.Count
    isBuyout = buyoutPrice and biddingPrice >= buyoutPrice # 大于等于一口价,直接成交
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    nowBiddingAuctionItemDict = auctionItemMgr.nowBiddingAuctionItemDict
    hisBiddingAuctionItemDict = auctionItemMgr.hisBiddingAuctionItemDict
    # 邮件返还上个竞价者
    if lastBidderID and lastBidderPrice:
        detail = {"ItemID":itemID, "ItemGUID":itemGUID, "Count":itemCount, ChConfig.Def_MailMoneySource:ChConfig.Def_GiveMoney_AuctionBidReturn}
        if isBuyout:
            # 竞拍失败,仅通知
            paramList = [itemID, lastBidderPrice]
            PlayerCompensation.SendMailByKey("PaimaiMail2", [lastBidderID], [], paramList, gold=lastBidderPrice, detail=detail)
        else:
            # 竞拍失败,可继续竞价邮件
            paramList = [itemID, lastBidderPrice, itemGUID]
            PlayerCompensation.SendMailByKey("PaimaiMail1", [lastBidderID], [], paramList, gold=lastBidderPrice, detail=detail)
        AddAuctionRecord(auctionItem, AuctionRecordResult_BidFail)
        isSyncBiddingItem = False
        nowBiddingAuctionItemList = nowBiddingAuctionItemDict.get(lastBidderID, [])
        if auctionItem in nowBiddingAuctionItemList:
            nowBiddingAuctionItemList.remove(auctionItem)
            nowBiddingAuctionItemDict[lastBidderID] = nowBiddingAuctionItemList
            isSyncBiddingItem = True
        hisBiddingAuctionItemList = hisBiddingAuctionItemDict.get(lastBidderID, [])
        if auctionItem not in hisBiddingAuctionItemList:
            hisBiddingAuctionItemList.append(auctionItem)
            hisBiddingAuctionItemDict[lastBidderID] = hisBiddingAuctionItemList
            isSyncBiddingItem = True
        if isSyncBiddingItem:
            lastBidder = GameWorld.GetPlayerManager().FindPlayerByID(lastBidderID)
            if lastBidder and not PlayerControl.GetIsTJG(lastBidder):
                Sync_PlayerBiddingItemInfo(lastBidder, auctionItem)
    # 更新竞价信息
    auctionItem.BiddingQueryID = 0
    auctionItem.BiddingTick = 0
    auctionItem.BiddingTime = GameWorld.GetCurrentDataTimeStr()
    auctionItem.BidderID = playerID
    auctionItem.BidderName = curPlayer.GetName()
    auctionItem.BidderPrice = biddingPrice
    isSyncBiddingItem = False
    nowBiddingAuctionItemList = nowBiddingAuctionItemDict.get(playerID, [])
    if auctionItem not in nowBiddingAuctionItemList:
        nowBiddingAuctionItemList.append(auctionItem)
        nowBiddingAuctionItemDict[playerID] = nowBiddingAuctionItemList
        isSyncBiddingItem = True
    hisBiddingAuctionItemList = hisBiddingAuctionItemDict.get(playerID, [])
    if auctionItem in hisBiddingAuctionItemList:
        hisBiddingAuctionItemList.remove(auctionItem)
        hisBiddingAuctionItemDict[playerID] = hisBiddingAuctionItemList
        isSyncBiddingItem = True
    if isSyncBiddingItem:
        Sync_PlayerBiddingItemInfo(curPlayer, auctionItem)
    # 添加历史竞价者
    if str(playerID) not in auctionItem.BidderIDInfo:
        auctionItem.BidderIDInfo += "%s|" % playerID
        auctionItem.BidderIDLen = len(auctionItem.BidderIDInfo)
    GameWorld.DebugLog("玩家竞价拍品: itemGUID=%s,itemID=%s,isBuyout=%s,lastBidderID=%s,lastBidderPrice=%s,bidderIDInfo=%s"
                       % (itemGUID, itemID, isBuyout, lastBidderID, lastBidderPrice, auctionItem.BidderIDInfo), playerID)
    if isBuyout:
        __EndAuctionItem([auctionItem], "Buyout")
    else:
        if __AddAuctionItemEndTimeByBid(auctionItem):
            __SortAuctionitem(isSortWorldItem=False)
        drDict = {"AuctionItemInfo":__GetAuctionItemDRDict(auctionItem)}
        DR_AuctionHouse(curPlayer, "BidAuctionItem", drDict)
        __SyncRefreshAuctionItem([auctionItem])
    return itemID, errInfo
def __SyncRefreshAuctionItem(auctionItemList):
    ''' // B5 08 拍卖行刷新拍品 #tagGCRefreshAuctionItemInfo
        1-仙盟拍品转移到全服时通知; 2-拍品有人竞价时刷新
    '''
    refreshAuctionItemList = []
    for auctionItem in auctionItemList:
        refreshItem = ChPyNetSendPack.tagGCRefreshAuctionItem()
        refreshItem.ItemGUID = auctionItem.ItemGUID
        refreshItem.AuctionType = auctionItem.AuctionType
        refreshItem.AddTime = auctionItem.AddTime
        refreshItem.BidderID = auctionItem.BidderID
        refreshItem.BidderPrice = auctionItem.BidderPrice
        refreshAuctionItemList.append(refreshItem)
    if not refreshAuctionItemList:
        return
    clientPack = ChPyNetSendPack.tagGCRefreshAuctionItemInfo()
    clientPack.RefreshAuctionItemList = refreshAuctionItemList
    clientPack.RefreshCount = len(clientPack.RefreshAuctionItemList)
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetActivePlayerCount()):
        player = playerManager.GetActivePlayerAt(i)
        if player == None:
            continue
        if PlayerControl.GetIsTJG(player):
            continue
        NetPackCommon.SendFakePack(player, clientPack)
    return
def __DoGMClearAuctionItem(curPlayer):
    if curPlayer.GetGMLevel() != 90:
        return
    allAuctionItemByEndTimeList = PyDataManager.GetAuctionItemManager().allAuctionItemByEndTimeList
    if not allAuctionItemByEndTimeList:
        GameWorld.DebugAnswer(curPlayer, "当前没有拍品!")
        return
    endItemList = []
    for auctionItem in allAuctionItemByEndTimeList:
        endItemList.append(auctionItem)
    clearCount = __EndAuctionItem(endItemList, "GMClear")
    GameWorld.DebugAnswer(curPlayer, "清空拍品数=%s" % clearCount)
    return
def __DoGMPrintAuctionItem(curPlayer):
    if curPlayer.GetGMLevel() != 90:
        return
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    allAuctionItemByEndTimeList = auctionItemMgr.allAuctionItemByEndTimeList
    GameWorld.DebugLog("TimeList总拍品数: =%s" % len(allAuctionItemByEndTimeList))
    for i, auctionItem in enumerate(allAuctionItemByEndTimeList):
        GameWorld.DebugLog("    i=%s, %s" % (i, __GetAuctionItemDRDict(auctionItem)))
    GameWorld.DebugLog("AllDict总拍品数: =%s" % len(auctionItemMgr.allAuctionItemDict))
    GameWorld.DebugLog("全服拍品个数: =%s" % len(auctionItemMgr.worldAuctionItemList))
    for familyID, familyItemList in auctionItemMgr.familyAuctionItemDict.items():
        GameWorld.DebugLog("仙盟拍品个数: familyID=%s, %s" % (familyID, len(familyItemList)))
    for playerID, myItemList in auctionItemMgr.myAuctionItemDict.items():
        GameWorld.DebugLog("玩家拍品个数: playerID=%s, %s" % (playerID, len(myItemList)))
    for playerID, nowBiddingItemList in auctionItemMgr.nowBiddingAuctionItemDict.items():
        GameWorld.DebugLog("玩家最高竞价拍品个数: playerID=%s, %s" % (playerID, len(nowBiddingItemList)))
    for playerID, hisBiddingItemList in auctionItemMgr.hisBiddingAuctionItemDict.items():
        GameWorld.DebugLog("玩家历史竞价拍品个数: playerID=%s, %s" % (playerID, len(hisBiddingItemList)))
    for playerID, attentionItemList in auctionItemMgr.myAttentionItemDict.items():
        GameWorld.DebugLog("玩家关注拍品个数: playerID=%s, %s" % (playerID, len(attentionItemList)))
    return
#// B5 10 拍卖行查询拍卖中的物品 #tagCGQueryAuctionItem
#
#struct    tagCGQueryAuctionItem
#{
#    tagHead    Head;
#    BYTE    Job;    //过滤职业,0为不限制
#    BYTE    ItemTypeCount;
#    DWORD    ItemTypeList[ItemTypeCount];    //指定的物品类型
#    BYTE    ClassLV;    //过滤阶数,0为不限制
#    BYTE    SpecItemIDCount;    //指定物品ID个数
#    DWORD    SpecItemIDList[SpecItemIDCount];    //指定物品ID
#    char    FromItemGUID[40];        //从哪个物品开始查询
#    BYTE    QueryDir;        //查询方向,1-往后查,2-往前查
#    BYTE    QueryCount;    //查询个数,0为全部
#};
def OnQueryAuctionItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    job = clientData.Job
    itemTypeList = clientData.ItemTypeList
    classLV = clientData.ClassLV
    specItemIDList = clientData.SpecItemIDList
    fromItemGUID = clientData.FromItemGUID
    queryDir = clientData.QueryDir
    queryCount = clientData.QueryCount
    __Sync_WorldAuctionItemQueryResult(curPlayer, job, itemTypeList, classLV, specItemIDList, fromItemGUID, queryDir, queryCount)
    return
#// B5 17 拍卖行查询定位目标拍品 #tagCGQueryTagAuctionItem
#
#struct    tagCGQueryTagAuctionItem
#{
#    tagHead        Head;
#    char        ItemGUID[40];
#    DWORD        ItemID;
#};
def OnQueryTagAuctionItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagItemGUID = clientData.ItemGUID
    queryDir = 3
    __Sync_WorldAuctionItemQueryResult(curPlayer, fromItemGUID=tagItemGUID, queryDir=queryDir)
    return
def __Sync_WorldAuctionItemQueryResult(curPlayer, job=0, itemTypeList=[], classLV=0, specItemIDList=[], fromItemGUID="", queryDir=1, queryCount=10):
    ## 根据过滤条件同步全服拍品列表,目前仅全服拍品需要通过查询服务器获得,个人拍品及仙盟拍品由于个数较少直接由上线或变更时主动同步
    fromAuctionItem = None
    if fromItemGUID:
        fromAuctionItem = GetAuctionItem(fromItemGUID)
        if not fromAuctionItem:
            GameWorld.DebugLog("查询的目标拍品不存在! fromItemGUID=%s" % fromItemGUID)
            PlayerControl.NotifyCode(curPlayer, "Paimai5")
            return
    # {(job, (itemType, ...), itemClassLV, (itemID, ...)):[tagDBAuctionItem, ...], ...}
    queryKey = (job, tuple(itemTypeList), classLV, tuple(specItemIDList))
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    worldAuctionItemQueryDict = auctionItemMgr.worldAuctionItemQueryDict
    if queryKey not in worldAuctionItemQueryDict:
        # 载入对应查询条件拍品缓存
        auctionItemQueryList = []
        for worldAuctionItem in auctionItemMgr.worldAuctionItemList:
            if job and worldAuctionItem.ItemJobLimit != job:
                continue
            if itemTypeList and worldAuctionItem.ItemType not in itemTypeList:
                continue
            if classLV and worldAuctionItem.ItemClassLV != classLV:
                continue
            if specItemIDList and worldAuctionItem.ItemID not in specItemIDList:
                continue
            auctionItemQueryList.append(worldAuctionItem)
        worldAuctionItemQueryDict[queryKey] = auctionItemQueryList
    else:
        auctionItemQueryList = worldAuctionItemQueryDict[queryKey]
    queryTotalCount = len(auctionItemQueryList)
    fromIndex = 0
    if fromAuctionItem:
        if fromAuctionItem not in auctionItemQueryList:
            GameWorld.ErrLog("查询的目标拍品不在所在的过滤的条件里! fromItemGUID=%s" % fromItemGUID)
            PlayerControl.NotifyCode(curPlayer, "Paimai5")
            return
        fromIndex = auctionItemQueryList.index(fromAuctionItem)
    # 向前查,其他的默认向后查
    if queryDir == 2:
        startIndex = max(0, fromIndex - queryCount + 1)
        syncItemList = auctionItemQueryList[startIndex:fromIndex + 1]
        queryRemainlCount = startIndex
    # 向后查
    else:
        syncItemList = auctionItemQueryList[fromIndex:fromIndex + queryCount]
        queryRemainlCount = max(0, queryTotalCount - fromIndex - queryCount)
    clientPack = ChPyNetSendPack.tagGCAuctionItemInfo()
    clientPack.Job = job
    clientPack.ItemTypeList = itemTypeList
    clientPack.ItemTypeCount = len(clientPack.ItemTypeList)
    clientPack.ClassLV = classLV
    clientPack.SpecItemIDList = specItemIDList
    clientPack.SpecItemIDCount = len(clientPack.SpecItemIDList)
    clientPack.FromItemGUID = fromItemGUID
    clientPack.QueryDir = queryDir
    clientPack.QueryCount = queryCount
    clientPack.QueryRemainlCount = queryRemainlCount
    clientPack.AuctionItemList = []
    for auctionItem in syncItemList:
        itemInfo = ChPyNetSendPack.tagGCAuctionItem()
        itemInfo.ItemGUID = auctionItem.ItemGUID
        itemInfo.FamilyID = auctionItem.FamilyID
        itemInfo.ItemID = auctionItem.ItemID
        itemInfo.ItemCount = auctionItem.Count
        itemInfo.AddTime = auctionItem.AddTime
        itemInfo.BidderPrice = auctionItem.BidderPrice
        itemInfo.UserData = auctionItem.UserData
        itemInfo.UserDataLen = auctionItem.UserDataLen
        clientPack.AuctionItemList.append(itemInfo)
    clientPack.AuctionItemCount = len(clientPack.AuctionItemList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
#// B5 12 拍卖行查询拍卖记录 #tagCGQueryAuctionRecord
#
#struct    tagCGQueryAuctionRecord
#{
#    tagHead    Head;
#    BYTE        RecordType;    //记录类型 0-我的拍品记录 1-仙盟拍品记录 2-我的竞拍记录
#};
def OnQueryAuctionRecord(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    recordType = clientData.RecordType
    Sync_PlayerAuctionRecordInfo(curPlayer, recordType, None, curPlayer.GetFamilyID())
    return
#// B5 16 拍卖行查询关注中的拍品 #tagCGQueryAttentionAuctionItem
#
#struct    tagCGQueryAttentionAuctionItem
#{
#    tagHead    Head;
#};
def OnQueryAttentionAuctionItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    myAttentionItemDict = auctionItemMgr.myAttentionItemDict
    if playerID in myAttentionItemDict:
        attentionItemList = myAttentionItemDict[playerID]
    else:
        attentionItemList = []
        attentionMgr = PyDataManager.GetAuctionAttentionManager()
        attentionItemIDList = GetPlayerAuctionAttention(attentionMgr, playerID)
        if attentionItemIDList:
            for auctionItem in auctionItemMgr.worldAuctionItemList:
                if auctionItem.ItemID not in attentionItemIDList:
                    continue
                attentionItemList.append(auctionItem)
            myAttentionItemDict[playerID] = attentionItemList
    clientPack = ChPyNetSendPack.tagGCAttentionAuctionItemInfo()
    clientPack.AuctionItemList = []
    for attentionItem in attentionItemList:
        itemObj = ChPyNetSendPack.tagGCAttentionAuctionItem()
        itemObj.ItemGUID = attentionItem.ItemGUID
        itemObj.FamilyID = attentionItem.FamilyID
        itemObj.ItemID = attentionItem.ItemID
        itemObj.ItemCount = attentionItem.Count
        itemObj.AddTime = attentionItem.AddTime
        itemObj.BidderPrice = attentionItem.BidderPrice
        itemObj.UserData = attentionItem.UserData
        itemObj.UserDataLen = attentionItem.UserDataLen
        clientPack.AuctionItemList.append(itemObj)
    clientPack.AuctionItemCount = len(clientPack.AuctionItemList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
#// B5 18 拍卖行修改关注物品 #tagCGAttentionAuctionItemChange
#
#struct    tagCGAttentionAuctionItemChange
#{
#    tagHead        Head;
#    DWORD        ItemID;
#    BYTE        IsAttention;    //是否关注,取消关注发0
#};
def OnAttentionAuctionItemChange(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    itemID = clientData.ItemID
    isAttention = clientData.IsAttention
    attentionMgr = PyDataManager.GetAuctionAttentionManager()
    if isAttention:
        if not AddPlayerAuctionAttention(attentionMgr, playerID, itemID):
            return
    else:
        if not DelPlayerAuctionAttention(attentionMgr, playerID, itemID):
            return
    Sync_PlayerAttentionAuctionItemID(curPlayer, True)
    # 关注信息变更,清空关注拍品实例缓存
    auctionItemMgr = PyDataManager.GetAuctionItemManager()
    auctionItemMgr.myAttentionItemDict.pop(playerID, None)
    return
def Sync_FamilyAuctionItemInfo(curPlayer, familyID, itemInfoList=[]):
    # // B5 05 拍卖行仙盟拍卖中的物品信息 #tagGCFamilyAuctionItemInfo
    if not familyID:
        return
    if not itemInfoList:
        itemInfoList = GetFamilyAuctionItemList(familyID)
    if not itemInfoList:
        return
    itemInfoPack = ChPyNetSendPack.tagGCFamilyAuctionItemInfo()
    itemInfoPack.AuctionItemList = []
    for auctionItem in itemInfoList:
        packItem = ChPyNetSendPack.tagGCFamilyAuctionItem()
        packItem.ItemGUID = auctionItem.ItemGUID
        packItem.FamilyID = auctionItem.FamilyID
        packItem.ItemID = auctionItem.ItemID
        packItem.ItemCount = auctionItem.Count
        packItem.AddTime = auctionItem.AddTime
        packItem.BidderPrice = auctionItem.BidderPrice
        packItem.UserData = auctionItem.UserData
        packItem.UserDataLen = auctionItem.UserDataLen
        packItem.FamilyPlayerIDInfo = auctionItem.FamilyPlayerIDInfo
        packItem.FamilyPlayerIDLen = auctionItem.FamilyPlayerIDLen
        packItem.AuctionType = auctionItem.AuctionType
        itemInfoPack.AuctionItemList.append(packItem)
    itemInfoPack.AuctionItemCount = len(itemInfoPack.AuctionItemList)
    if curPlayer:
        NetPackCommon.SendFakePack(curPlayer, itemInfoPack)
    else:
        PlayerFamily.SendFamilyFakePack(familyID, itemInfoPack)
    return
def Sync_PlayerAuctionItemInfo(curPlayer, auctionItem=None):
    # // B5 02 拍卖行玩家拍卖中的物品信息 #tagGCPlayerAuctionItemInfo
    if auctionItem:
        syncItemList = [auctionItem]
    else:
        syncItemList = GetPlayerAuctionItemList(curPlayer.GetPlayerID())
    if not syncItemList:
        return
    itemInfoPack = ChPyNetSendPack.tagGCPlayerAuctionItemInfo()
    itemInfoPack.AuctionItemList = []
    for auctionItem in syncItemList:
        packItem = ChPyNetSendPack.tagGCPlayerAuctionItem()
        packItem.ItemGUID = auctionItem.ItemGUID
        packItem.FamilyID = auctionItem.FamilyID
        packItem.ItemID = auctionItem.ItemID
        packItem.ItemCount = auctionItem.Count
        packItem.AddTime = auctionItem.AddTime
        packItem.BidderPrice = auctionItem.BidderPrice
        packItem.UserData = auctionItem.UserData
        packItem.UserDataLen = auctionItem.UserDataLen
        itemInfoPack.AuctionItemList.append(packItem)
    itemInfoPack.AuctionItemCount = len(itemInfoPack.AuctionItemList)
    NetPackCommon.SendFakePack(curPlayer, itemInfoPack)
    return
def Sync_PlayerAuctionRecordInfo(curPlayer, recordType, newRecordData=None, familyID=0):
    ## B5 03 拍卖行玩家拍卖记录 #tagGCPlayerAuctionRecordInfo
    if recordType == AuctionRecordType_MyAuction and curPlayer:
        syncRecordList = [newRecordData] if newRecordData else GetMyAuctionItemRecord(curPlayer.GetPlayerID())
    elif recordType == AuctionRecordType_FamilyAuction and familyID:
        syncRecordList = [newRecordData] if newRecordData else GetFamilyAuctionItemRecord(familyID)
    elif recordType == AuctionRecordType_MyBid and curPlayer:
        syncRecordList = [newRecordData] if newRecordData else GetMyBiddingItemRecord(curPlayer.GetPlayerID())
    else:
        return
    clientPack = ChPyNetSendPack.tagGCPlayerAuctionRecordInfo()
    clientPack.AuctionRecordList = []
    for recordData in syncRecordList:
        record = ChPyNetSendPack.tagGCPlayerAuctionRecord()
        record.ItemGUID = recordData.ItemGUID
        record.FamilyID = recordData.FamilyID
        record.RecordType = recordData.RecordType
        record.RecordResult = recordData.RecordResult
        record.RecordTime = recordData.RecordTime
        record.BidderPrice = recordData.BidderPrice
        record.BidderName = recordData.BidderName
        record.ItemID = recordData.ItemID
        record.ItemCount = recordData.Count
        record.UserData = recordData.UserData
        record.UserDataLen = recordData.UserDataLen
        clientPack.AuctionRecordList.append(record)
    clientPack.Count = len(clientPack.AuctionRecordList)
    if curPlayer:
        NetPackCommon.SendFakePack(curPlayer, clientPack)
    elif familyID and recordType == AuctionRecordType_FamilyAuction:
        PlayerFamily.SendFamilyFakePack(familyID, clientPack)
    return
def Sync_PlayerBiddingItemInfo(curPlayer, auctionItem=None):
    #// B5 10 拍卖行玩家竞价中的物品信息 #tagGCBiddingItemInfo
    # 上线同步、玩家相关的竞价拍品竞价变更时同步
    if auctionItem:
        syncItemList = [auctionItem]
    else:
        playerID = curPlayer.GetPlayerID()
        auctionItemMgr = PyDataManager.GetAuctionItemManager()
        nowBiddingAuctionItemList = auctionItemMgr.nowBiddingAuctionItemDict.get(playerID, [])
        hisBiddingAuctionItemList = auctionItemMgr.hisBiddingAuctionItemDict.get(playerID, [])
        syncItemList = nowBiddingAuctionItemList + hisBiddingAuctionItemList
    if not syncItemList:
        return
    itemInfoPack = ChPyNetSendPack.tagGCBiddingItemInfo()
    itemInfoPack.AuctionItemList = []
    for auctionItem in syncItemList:
        packItem = ChPyNetSendPack.tagGCBiddingItem()
        packItem.ItemGUID = auctionItem.ItemGUID
        packItem.FamilyID = auctionItem.FamilyID
        packItem.ItemID = auctionItem.ItemID
        packItem.ItemCount = auctionItem.Count
        packItem.AddTime = auctionItem.AddTime
        packItem.BidderID = auctionItem.BidderID
        packItem.BidderPrice = auctionItem.BidderPrice
        packItem.UserData = auctionItem.UserData
        packItem.UserDataLen = auctionItem.UserDataLen
        itemInfoPack.AuctionItemList.append(packItem)
    itemInfoPack.AuctionItemCount = len(itemInfoPack.AuctionItemList)
    NetPackCommon.SendFakePack(curPlayer, itemInfoPack)
    return
def Sync_PlayerAttentionAuctionItemID(curPlayer, isForce=False):
    # // B5 07 拍卖行关注的物品ID #tagGCAttentionAuctionItemID
    attentionMgr = PyDataManager.GetAuctionAttentionManager()
    attentionItemIDList = GetPlayerAuctionAttention(attentionMgr, curPlayer.GetPlayerID())
    if not attentionItemIDList and not isForce:
        return
    clientPack = ChPyNetSendPack.tagGCAttentionAuctionItemID()
    clientPack.AttentionItemIDList = attentionItemIDList
    clientPack.AttentionCount = len(clientPack.AttentionItemIDList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def DR_AuctionHouse(curPlayer, eventName, drDict):
    accID = "" if not curPlayer else curPlayer.GetAccID()
    playerID = 0 if not curPlayer else curPlayer.GetPlayerID()
    dataDict = {"EventName":eventName, "PlayerID":playerID, "AccID":accID}
    dataDict.update(drDict)
    DataRecordPack.SendEventPack("AuctionHouse", dataDict, curPlayer)
    return
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -100,6 +100,7 @@
import IpyGameDataPY
import PlayerFamilyParty
import GameWorldFamilyWar
import AuctionHouse
import PlayerXMZZ
import PlayerTeam
import PyGameData
@@ -287,6 +288,8 @@
def __Func_HighPrecisionProcess(tick):
    if not GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_IsGameWorldInit):
        return
    curTime = int(time.time())
    #仙盟宴会答题定时器
    PlayerFamilyParty.FamilyParty_Process(tick)
    # 帮主弹劾时钟调用
@@ -305,6 +308,9 @@
    #操作Python表
    PlayerDBOper.PyDBProccess(tick)
    
    #拍卖行
    AuctionHouse.OnAuctionItemTimeProcess(curTime)
    #每整分钟处理一次
    curDateTime = datetime.datetime.today()
    curMinute = curDateTime.minute
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -67,6 +67,7 @@
import GMShell
import IPY_PlayerDefine
import CrossRealmPK
import AuctionHouse
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -149,6 +150,8 @@
        PlayerTruck.SyncPlayerTruckStartTime(curPlayer)
        #通知玩家交易所挂单情况
        PlayerBourse.OnPlayerLogin(curPlayer)
        #拍卖行
        AuctionHouse.OnPlayerLogin(curPlayer)
        #上线广播
        __CheckWorldNotifyOnLogin(curPlayer, tick)
@@ -512,7 +515,8 @@
    PlayerGeTui.NewGuyCallBackGeTui(curPlayer, tick)
    # 设置家族成员离线时间
    SetPlayerOfflineTime(curPlayer)
    #拍卖行
    AuctionHouse.OnPlayerLeaveServer(curPlayer)
    #------------镖车逻辑
    #TruckPlayerDisconnectProcess(curPlayer, tick)
    return
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py
@@ -40,6 +40,7 @@
import PlayerFamilySWRH
import PlayerViewCache
import GameWorldBoss
import AuctionHouse
import PlayerTalk
import PlayerTeam
@@ -368,7 +369,8 @@
    PlayerFamilyBoss.NotifyFamilyBossFBInfo(jionPlayer)
    #通知家族仓库
    PyDataManager.GetFamilyStoreItemManager().SyncFamilyStoreItem(jionPlayer, curFamily.GetID())
    #仙盟拍品
    AuctionHouse.Sync_FamilyAuctionItemInfo(jionPlayer, curFamily.GetID())
    SetMemberFightPower(familyMember, jionPlayer.GetFightPower())
    AddFamilyIDToFightPowerChangeList(curFamily.GetID())
    
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -73,6 +73,7 @@
import CrossRealmPK
import ChPyNetSendPack
import NetPackCommon
import AuctionHouse
import time
import datetime
@@ -780,6 +781,16 @@
        PlayerBourse.OnGivePlayerBourseGainsResult(curPlayer, eval(resultName))
        return
    
    # 拍卖行
    if callName == "AuctionHouse":
        curPlayer = None
        if srcPlayerID:
            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
            if not curPlayer:
                return
        AuctionHouse.MapServer_AuctionHouseLogic(curPlayer, eval(resultName), tick)
        return
    if callName == "TeamMemFuncData":
        PlayerTeam.MapServer_TeamMemFuncData(srcPlayerID, eval(resultName))
        return
ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
@@ -23,10 +23,13 @@
import PyGameData
import CrossRealmPK
import AuctionHouse
import PyGameDataStruct
import CommFunc
def GetSavePyData():
    result = PyGameData.g_pyGameDataManager.GetSaveData()
    GameWorld.DebugLog("GetSavePyData!! id = %s-%s"%(id(PyGameData.g_pyGameDataManager), len(result)))
    pyGameDataMgr = GetPyGameDataManager()
    result = pyGameDataMgr.GetSaveData()
    GameWorld.DebugLog("GetSavePyData!! id = %s-%s"%(id(pyGameDataMgr), len(result)))
    result = binascii.b2a_hex(result)
    #GameWorld.DebugLog("GetSavePyData!! result = %s-%s"%(result, len(result)))
    # 字节码在C++转化会发生错误must be string without null bytes, not str,但是可以正常保存,错误会在下次调用便宜接口才会触发
@@ -35,19 +38,141 @@
def LoadPyGameData(gameBuffer, pos):
    PyGameData.g_pyGameDataManager = PyGameDataManager()
    GameWorld.Log("LoadPyGameData!!id = %s %s"%(id(PyGameData.g_pyGameDataManager), len(gameBuffer)))
    return PyGameData.g_pyGameDataManager.LoadGameData(gameBuffer, pos)
    pyGameDataMgr = GetPyGameDataManager()
    GameWorld.Log("LoadPyGameData!!id = %s %s"%(id(pyGameDataMgr), len(gameBuffer)))
    return pyGameDataMgr.LoadGameData(gameBuffer, pos)
#拍卖记录管理,该类只做数据缓存存取,不写功能逻辑,防止重读脚本时功能逻辑脚本不生效
class AuctionRecordManager(object):
    def __init__(self):
        self.myAuctionItemRecordDict = {} # 我的拍品记录 {playerID:[tagDBAuctionRecord, ...], ...}
        self.myBidItemRecordDict = {} # 我的竞拍记录 {playerID:[tagDBAuctionRecord, ...], ...}
        self.familyAuctionItemRecordDict = {} # 仙盟拍品记录 {familyID:[tagDBAuctionRecord, ...], ...}
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for recordDict in [self.myAuctionItemRecordDict, self.myBidItemRecordDict, self.familyAuctionItemRecordDict]:
            for recordList in recordDict.values():
                for dbData in recordList:
                    cnt += 1
                    savaData += dbData.getBuffer()
        GameWorld.Log("Save AuctionRecord count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionRecord count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = PyGameDataStruct.tagDBAuctionRecord()
            dbData.clear()
            pos += dbData.readData(datas, pos, dataslen)
            AuctionHouse.AddNewAuctionRecord(dbData)
        return pos
#拍卖关注管理,该类只做数据缓存存取,不写功能逻辑,防止重读脚本时功能逻辑脚本不生效
class AuctionAttentionManager(object):
    def __init__(self):
        self.playerAttentionDict = {} # 玩家关注拍卖品ID {playerID:tagDBAuctionAttention, ...}
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for dbData in self.playerAttentionDict.values():
            cnt += 1
            savaData += dbData.getBuffer()
        GameWorld.Log("Save AuctionAttention count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionAttention count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = PyGameDataStruct.tagDBAuctionAttention()
            dbData.clear()
            pos += dbData.readData(datas, pos, dataslen)
            self.playerAttentionDict[dbData.PlayerID] = dbData
            AuctionHouse.OnLoadAuctionAttentionDataEx(dbData)
        return pos
    def __InitAuctionAttentionAttrEx(self, attentionData):
        ## 初始化拍卖关注实例附加属性
        setattr(attentionData, "AttentionItemIDList", [] if not attentionData.AttentionInfo else eval(attentionData.AttentionInfo))
        return
#拍卖物品数据缓存,该类只做数据缓存存取,不写功能逻辑,防止重读脚本时功能逻辑脚本不生效
class AuctionItemManager():
    def __init__(self):
        self.allAuctionItemDict = {} # 所有拍品字典缓存 {ItemGUID:tagDBAuctionItem, ...}
        self.allAuctionItemByEndTimeList = [] # 根据结束时间排序的所有拍品缓存 [tagDBAuctionItem, ...]
        self.worldAuctionItemList = [] # 全服拍品列表缓存 [tagDBAuctionItem, ...]
        self.worldAuctionItemQueryDict = {} # 全服拍品过滤查询缓存,添加拍品时重置 {(job, (itemType, ...), itemClassLV, (itemID, ...)):[tagDBAuctionItem, ...], ...}
        self.familyAuctionItemDict = {} # 仙盟拍品列表缓存,包含转移到全服的仙盟拍品 {familyID:[tagDBAuctionItem, ...], ...}
        self.nowBiddingAuctionItemDict = {} # 玩家当前是最高竞价的拍品,含所有拍品 {playerID:[tagDBAuctionItem, ...], ...}
        self.hisBiddingAuctionItemDict = {} # 玩家曾经参与过竞价的拍品,含所有拍品 {playerID:[tagDBAuctionItem, ...], ...}
        self.myAuctionItemDict = {} # 玩家拍卖中的物品 ,不包含仙盟拍品,由前端界面自行整合数据 {playerID:[tagDBAuctionItem, ...], ...}
        self.myAttentionItemDict = {} # 玩家关注中的物品 ,不包含仙盟拍品,由前端界面自行整合数据,只保存在线的玩家,离线清除,上线不同步,由前端查询 {playerID:[tagDBAuctionItem, ...], ...}
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for dbData in self.allAuctionItemDict.values():
            cnt += 1
            savaData += dbData.getBuffer()
        GameWorld.Log("Save AuctionItem count :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load AuctionItem count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = PyGameDataStruct.tagDBAuctionItem()
            dbData.clear()
            pos += dbData.readData(datas, pos, dataslen)
            self.allAuctionItemDict[dbData.ItemGUID] = dbData
            AuctionHouse.OnLoadAuctionItemDataEx(dbData)
        AuctionHouse.OnLoadAuctionItemDataOK()
        return pos
# 个人社交相关表
# 好友表,仇人表,最近联系人,黑名单,四张表公用的社交信息表
class PyGameDataManager(object):
    def __init__(self):
        self.AuctionAttention = AuctionHouse.AuctionAttentionManager()
        self.AuctionRecord = AuctionHouse.AuctionRecordManager()
        self.AuctionItem = AuctionHouse.AuctionItemManager()
        self.AuctionAttentionManager = AuctionAttentionManager()
        self.AuctionRecordManager = AuctionRecordManager()
        self.AuctionItemManager = AuctionItemManager()
        self.crossPKUnNotifyOverInfo = CrossRealmPK.CrossPKUnNotifyOverInfoManager()
        self.crossPKBillboard = CrossRealmPK.CrossPKBillboardManager()
        self.XMZZManager = PlayerXMZZ.XMZZManager()
@@ -65,9 +190,9 @@
    def GetSaveData(self):
        buff = ""
        buff += self.AuctionAttention.GetSaveData()
        buff += self.AuctionRecord.GetSaveData()
        buff += self.AuctionItem.GetSaveData()
        buff += self.AuctionAttentionManager.GetSaveData()
        buff += self.AuctionRecordManager.GetSaveData()
        buff += self.AuctionItemManager.GetSaveData()
        buff += self.crossPKUnNotifyOverInfo.GetSaveData()
        buff += self.crossPKBillboard.GetSaveData()
        buff += self.XMZZManager.GetSaveData()
@@ -84,9 +209,9 @@
        return buff
    
    def LoadGameData(self, gameBuffer, pos):
        pos = self.AuctionAttention.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.AuctionRecord.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.AuctionItem.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.AuctionAttentionManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.AuctionRecordManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.AuctionItemManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.crossPKUnNotifyOverInfo.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.crossPKBillboard.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.XMZZManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
@@ -102,75 +227,90 @@
        pos = self.socialInfoManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        return pos
# 拍卖记录表
def GetAuctionAttentionManager():
    return PyGameData.g_pyGameDataManager.AuctionAttention
def GetPyGameDataManager():
    ## py数据库表数据管理器
    pyGameDataMgr = PyGameData.g_pyGameDataManager
    if not pyGameDataMgr:
        pyGameDataMgr = PyGameDataManager()
        PyGameData.g_pyGameDataManager = pyGameDataMgr
    return pyGameDataMgr
# 拍卖记录表
def GetAuctionRecordManager():
    return PyGameData.g_pyGameDataManager.AuctionRecord
# 拍卖物品表
def GetAuctionItemManager():
    return PyGameData.g_pyGameDataManager.AuctionItem
    ## 拍卖物品缓存数据管理
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.AuctionItemManager
def GetAuctionAttentionManager():
    # 拍卖记录表
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.AuctionAttentionManager
def GetAuctionRecordManager():
    # 拍卖记录表
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.AuctionRecordManager
# 跨服竞技场未通知玩家的比赛结果
def GetCrossPKUnNotifyOverInfoManager():
    return PyGameData.g_pyGameDataManager.crossPKUnNotifyOverInfo
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.crossPKUnNotifyOverInfo
# 跨服竞技场排行榜管理
def GetCrossPKBillboardManager():
    return PyGameData.g_pyGameDataManager.crossPKBillboard
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.crossPKBillboard
# 仙魔之争管理
def GetXMZZManager():
    return PyGameData.g_pyGameDataManager.XMZZManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.XMZZManager
# 封魔坛结果管理
def GetSealDemonRecordManager():
    return PyGameData.g_pyGameDataManager.sealDemonManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.sealDemonManager
# Boss关注记录管理
def GetBossAttentionManager():
    return PyGameData.g_pyGameDataManager.bossAttentionManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.bossAttentionManager
# 交易所物品最近成交单价管理
def GetBourseItemLastPriceManager():
    return PyGameData.g_pyGameDataManager.bourseItemLastPriceManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.bourseItemLastPriceManager
# 交易所记录管理
def GetBourseRecordManager():
    return PyGameData.g_pyGameDataManager.bourseRecordManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.bourseRecordManager
# 战盟仓库物品管理
def GetFamilyStoreItemManager():
    return PyGameData.g_pyGameDataManager.familyStoreItemManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.familyStoreItemManager
# 好友系统
def GetFriendManager():
    return PyGameData.g_pyGameDataManager.friendManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.friendManager
# 社交信息管理
def GetPersonalSocialManager():
    return PyGameData.g_pyGameDataManager.socialInfoManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.socialInfoManager
# 仇人系统
def GetEnemyManager():
    return PyGameData.g_pyGameDataManager.enemyManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.enemyManager
# 最近联系人系统
def GetContactsManager():
    return PyGameData.g_pyGameDataManager.contactsManager
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.contactsManager
# 黑名单系统
def GetBlacklistManager():
    return PyGameData.g_pyGameDataManager.blacklistManager
#===============================================================================
# PyGameData.g_pyGameDataManager = PyGameDataManager()
#
# PyGameData.g_pyGameDataManager.GetFriendManager().AddFriendBoth(3, 4)
# PyGameData.g_pyGameDataManager.GetFriendManager().AddFriendBoth(3, 5)
# PyGameData.g_pyGameDataManager.GetFriendManager().AddFriendBoth(3, 6)
# PyGameData.g_pyGameDataManager.GetFriendManager().AddFriendBoth(6, 4)
#===============================================================================
    pyGameDataMgr = GetPyGameDataManager()
    return pyGameDataMgr.blacklistManager
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1103,6 +1103,22 @@
PacketSubCMD_2=0x02
PacketCallFunc_2=OnPlayerBuyBourseItem
;拍卖行
[PlayerAuctionHouse]
ScriptName = Player\PlayerAuctionHouse.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 2
PacketCMD_1=0xB5
PacketSubCMD_1=0x13
PacketCallFunc_1=OnSellAuctionItem
PacketCMD_2=0xB5
PacketSubCMD_2=0x14
PacketCallFunc_2=OnBiddingAuctionItem
;法宝
[PlayerMagicWeapon]
ScriptName = Player\PlayerMagicWeapon.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -4656,6 +4656,7 @@
Def_Cost_CrossRealmPK, # 跨服PK
Def_Cost_LuckyTreasure, #幸运鉴宝
Def_Cost_MysteryShopRefresh, # 神秘商店刷新
Def_Cost_AuctionBid, # 拍卖行竞价
#-----------以下为暂时没用的,先不删除,如有新增消费点则放在这些之前------------
Def_Cost_RefreshArrestTask, # 刷新悬赏任务
Def_Cost_OffLineExp, # 兑换离线经验
@@ -4672,24 +4673,24 @@
Def_Cost_Trade, # 交易
Def_Cost_Rename, # 改名
Def_Cost_SkillLvUp, # 技能升级
) = range(2000, 2000 + 59)
) = range(2000, 2000 + 60)
Def_Cost_Reason_SonKey = "reason_name_son" # 消费点原因子类说明key
# 消费返利不处理的消费类型列表
CostRebate_DisableType = [Def_Cost_BourseBuy, Def_Cost_BourseCharge, Def_Cost_FreeGoods, Def_Cost_FamilyRedPacket,
                          Def_Cost_Unknown, "GMSetMoney", "Warehouse"]
                          Def_Cost_Unknown, "GMSetMoney", "Warehouse", Def_Cost_AuctionBid]
CostProfit_CostType = [Def_Cost_BourseBuy, Def_Cost_BourseCharge, Def_Cost_Unknown,
                       "GMSetMoney", "Warehouse"]
                       "GMSetMoney", "Warehouse", Def_Cost_AuctionBid]
# 消费VIP不处理的消费类型列表
CostVIP_CostType = [Def_Cost_BourseBuy, Def_Cost_BourseCharge, Def_Cost_Unknown,
                    "GMSetMoney", "Warehouse"]
                    "GMSetMoney", "Warehouse", Def_Cost_AuctionBid]
# 可在跨服中消费的类型列表
MergeServerCanCostType = [Def_Cost_UseSpeaker, Def_Cost_Revive, Def_Cost_FBEncourage]
#内部仙玉不能用的消费类型列表
UnUseInner_CostType = [Def_Cost_BourseBuy, Def_Cost_FamilyRedPacket]
UnUseInner_CostType = [Def_Cost_BourseBuy, Def_Cost_FamilyRedPacket, Def_Cost_AuctionBid]
# 消费类型对应信息字典{消费类型:[eventName, 中文说明reason_name, 发送给9377的数据是否分消费子类], }
# 由于9377那边数据建议所有消费点总和最好不超过500个,故这里对部分发送给对方的数据进行归组为不分子类,或直接归属于商城分组
#     .使用原价购买的物品统一归属为商城组,消费对应为AutoBuy的也归属于商城分组
@@ -4759,8 +4760,11 @@
Def_Cost_CrossRealmPK:"CrossRealmPK",
Def_Cost_LuckyTreasure:"LuckyTreasure",
Def_Cost_MysteryShopRefresh:"MysteryShopRefresh",
Def_Cost_AuctionBid:"AuctionBid",
}
## -----------------------------------------------------
Def_MailMoneySource = "MoneySource" # 邮件货币来源key
#游戏货币来源类型定义
(
@@ -4791,7 +4795,9 @@
Def_GiveMoney_FreeGoods, # 极品白拿 
Def_GiveMoney_BindJadeWheel, # 绑玉转盘 25
Def_GiveMoney_GatherSoulDecompose, #聚魂分解 26
) = range(1000, 1000 + 27)
Def_GiveMoney_AuctionBidReturn, #拍卖竞价返还
Def_GiveMoney_AuctionGain, #拍卖获得利润
) = range(1000, 1000 + 29)
Def_Give_Reason_SonKey = "reason_name_son" # 原因子类说明key
@@ -4824,6 +4830,8 @@
Def_GiveMoney_FreeGoods:"FreeGoods",
Def_GiveMoney_BindJadeWheel:"BindJadeWheel",
Def_GiveMoney_GatherSoulDecompose:"GatherSoulDecompose",
Def_GiveMoney_AuctionBidReturn:"AuctionBidReturn",
Def_GiveMoney_AuctionGain:"AuctionGain",
}
##==================================================================================================
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/AuctionItem.py
New file
@@ -0,0 +1,110 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.AuctionItem
#
# @todo:拍卖行
# @author hxp
# @date 2019-03-04
# @version 1.0
#
# 详细描述: 拍卖行
#
#-------------------------------------------------------------------------------
#"""Version = 2019-03-04 17:00"""
#-------------------------------------------------------------------------------
import GameWorld
import ItemControler
import PlayerAuctionHouse
import IpyGameDataPY
#逻辑实现
## GM命令执行入口
#  @param curPlayer 当前玩家
#  @param msgList 参数列表
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, msgList):
    GameWorld.DebugAnswer(curPlayer, "--------- %s" % GameWorld.GetCurrentDataTimeStr())
    if not msgList:
        __Help(curPlayer)
        return
    paramA = msgList[0]
    paramCount = len(msgList)
    playerID = curPlayer.GetPlayerID()
    isBind = False
    # 清空拍品
    if paramA == 0:
        PlayerAuctionHouse.QueryGameServer_AuctionHouse(playerID, "ClearAuctionItem", [])
        return
    # 打印拍品信息
    if paramA == 3:
        PlayerAuctionHouse.QueryGameServer_AuctionHouse(playerID, "PrintAuctionItem", [])
        return
    # 添加个人拍品
    elif paramA == 1 and paramCount >= 2:
        itemID = msgList[1]
        itemCount = max(1, msgList[2] if paramCount > 2 else 1)
        auctionGroup = max(1, msgList[3] if paramCount > 3 else 1)
        ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
        if not ipyData:
            GameWorld.DebugAnswer(curPlayer, "非拍卖物品无法上架")
            return
        auctionItemList = []
        if itemCount < auctionGroup:
            GameWorld.DebugAnswer(curPlayer, "物品个数不能少于组数")
            return
        groupItemCount = itemCount / auctionGroup
        for i in xrange(auctionGroup):
            if i == auctionGroup - 1:
                groupItemCount += itemCount % auctionGroup
            curItem = ItemControler.GetOutPutItemObj(itemID, groupItemCount, isBind)
            auctionItemList.append([curItem])
        PlayerAuctionHouse.__DoAddAuctionItem(curPlayer, auctionItemList)
    # 添加仙盟拍品
    elif paramA == 2 and paramCount >= 2:
        familyID = curPlayer.GetFamilyID()
        if not familyID:
            GameWorld.DebugAnswer(curPlayer, "没有仙盟无法上架仙盟拍品")
            return
        itemID = msgList[1]
        itemCount = max(1, msgList[2] if paramCount > 2 else 1)
        auctionGroup = max(1, msgList[3] if paramCount > 3 else 1)
        if itemCount < auctionGroup:
            GameWorld.DebugAnswer(curPlayer, "物品个数不能少于组数")
            return
        ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
        if not ipyData:
            GameWorld.DebugAnswer(curPlayer, "非拍卖物品无法上架")
            return
        familyPlayerIDList = msgList[4:] if paramCount > 4 else []
        if playerID not in familyPlayerIDList:
            familyPlayerIDList.append(playerID)
        familyAuctionItemList = [[itemID, itemCount, auctionGroup]]
        familyAuctionItemDict = {familyID:[familyPlayerIDList, familyAuctionItemList]}
        PlayerAuctionHouse.DoAddFamilyAuctionItem(familyAuctionItemDict)
    else:
        __Help(curPlayer)
        return
    return
def __Help(curPlayer):
    GameWorld.DebugAnswer(curPlayer, "清空所有拍品: AuctionItem 0")
    GameWorld.DebugAnswer(curPlayer, "添加个人拍品: AuctionItem 1 物品ID 个数 分几组")
    GameWorld.DebugAnswer(curPlayer, "添加仙盟拍品: AuctionItem 2 物品ID 个数 分几组 受益玩家IDA 玩家IDB...")
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
@@ -340,6 +340,9 @@
#  @return curSingleItem
#  @remarks 函数详细说明.
def CreateSingleItem(itemID, itemCount=1, isBind=1, expireTime=0):
    if itemCount < 1:
        GameWorld.ErrLog("创建物品个数不能少于1! itemID=%s,itemCount=%s" % (itemID, itemCount))
        return
    curSingleItem = GameWorld.GetItemFactory().CreateItem(itemID)
    if not curSingleItem:
        return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerAuctionHouse.py
New file
@@ -0,0 +1,198 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.PlayerAuctionHouse
#
# @todo:玩家拍卖行处理
# @author hxp
# @date 2019-03-04
# @version 1.0
#
# 详细描述: 玩家拍卖行处理
#
#-------------------------------------------------------------------------------
#"""Version = 2019-03-04 17:00"""
#-------------------------------------------------------------------------------
import GameWorld
import IPY_GameWorld
import IpyGameDataPY
import DataRecordPack
import PlayerControl
import ItemControler
import ItemCommon
import ChConfig
#// B5 13 拍卖行上架拍品 #tagCMSellAuctionItem
#
#struct    tagCMSellAuctionItem
#{
#    tagHead Head;
#    BYTE        ItemIndex;    //物品在背包中索引
#};
def OnSellAuctionItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    itemIndex = clientData.ItemIndex
    GameWorld.DebugLog("玩家上架拍品: itemIndex=%s" % (itemIndex), playerID)
    playerPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
    curItem = playerPack.GetAt(itemIndex)
    if curItem.IsEmpty():
        return
    if curItem.GetIsBind():
        GameWorld.Log("非拍品,绑定无法上架!", playerID)
        return
    itemGUID = curItem.GetGUID()
    itemID = curItem.GetItemTypeID()
    ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
    if not ipyData:
        return
    QueryGameServer_AuctionHouse(playerID, "AddAuctionItemQuery", [itemIndex, itemGUID, itemID])
    return
#// B5 14 拍卖行竞价物品 #tagCMBiddingAuctionItem
#
#struct    tagCMBiddingAuctionItem
#{
#    tagHead    Head;
#    char    ItemGUID[40];
#    WORD    BiddingPrice;    //竞价价格
#};
def OnBiddingAuctionItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    itemGUID = clientData.ItemGUID
    biddingPrice = clientData.BiddingPrice
    if not PlayerControl.HaveMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, biddingPrice):
        return
    QueryGameServer_AuctionHouse(playerID, "BidAuctionItemQuery", [itemGUID, biddingPrice])
    return
def QueryGameServer_AuctionHouse(playerID, queryType, queryData):
    msgInfo = str([queryType, queryData])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, "AuctionHouse", msgInfo, len(msgInfo))
    GameWorld.DebugLog("拍卖行发送GameServer: playerID=%s,queryType=%s,queryData=%s" % (playerID, queryType, queryData))
    return
def QueryResult_AuctionHouse(curPlayer, resultList):
    ## 拍卖行GameServer返回处理
    if len(resultList) != 3:
        return
    queryType, queryData, result = resultList
    if queryType == "AddAuctionItemQuery":
        itemIndex, itemGUID, itemID = queryData
        if not result or not result[0]:
            return
        __DoPlayerSellAuctionItem(curPlayer, itemIndex, itemGUID, itemID)
    elif queryType == "BidAuctionItemQuery":
        itemGUID, biddingPrice = queryData
        if not result or not result[0]:
            return
        itemID = result[0]
        __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, itemID)
    return
def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, itemID):
    ## 玩家竞价拍品
    # 地图只处理扣除竞价价格
    infoDict = {"ItemID":itemID, "ItemGUID":itemGUID, "BiddingPrice":biddingPrice}
    if not PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, biddingPrice, ChConfig.Def_Cost_AuctionBid, infoDict):
        return
    DR_AuctionHouse(curPlayer, "PlayerPayBid", infoDict)
    playerID = curPlayer.GetPlayerID()
    QueryGameServer_AuctionHouse(playerID, "BidAuctionItem", [itemGUID, biddingPrice])
    return
def __DoPlayerSellAuctionItem(curPlayer, itemIndex, itemGUID, itemID):
    ## 玩家上架拍品
    playerID = curPlayer.GetPlayerID()
    playerPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
    curItem = playerPack.GetAt(itemIndex)
    if curItem.IsEmpty():
        return
    if curItem.GetIsBind():
        GameWorld.Log("非拍品,无法上架!", playerID)
        return
    curItemGUID = curItem.GetGUID()
    curItemID = curItem.GetItemTypeID()
    if itemGUID != curItemGUID or itemID != curItemID:
        GameWorld.Log("请求上架的拍品已变化,无法上架!", playerID)
        return
    __DoAddAuctionItem(curPlayer, [[curItem]])
    return
def DoAddFamilyAuctionItem(familyAuctionItemDict):
    ''' 上架仙盟拍品,因为仙盟拍品默认上架,所以使用批量上架
    @param familyAuctionItemDict: {仙盟ID:[[享受收益的成员ID, ...], [[拍品ID,总个数,拍品组数], ...]], ...}
    '''
    isBind = False
    auctionItemList = []
    for familyID, auctionInfo in familyAuctionItemDict.items():
        familyPlayerIDList, familyAuctionItemList = auctionInfo
        for itemID, itemCount, auctionGroup in familyAuctionItemList:
            ipyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
            if not ipyData:
                GameWorld.ErrLog("非拍卖物品,无法上架仙盟拍品! familyID=%s,itemID=%s,itemCount=%s" % (familyID, itemID, itemCount))
                continue
            groupItemCount = itemCount / auctionGroup
            for i in xrange(auctionGroup):
                if i == auctionGroup - 1:
                    groupItemCount += itemCount % auctionGroup
                curItem = ItemControler.GetOutPutItemObj(itemID, groupItemCount, isBind)
                if not curItem:
                    continue
                auctionItemList.append([curItem, familyID, familyPlayerIDList])
    __DoAddAuctionItem(None, auctionItemList)
    return
def __DoAddAuctionItem(curPlayer, auctionItemList):
    ''' 上架拍品,支持批量上架
    @param curPlayer: 非个人拍品时为None
    @param auctionItemList: [[curItem], [curItem, familyID, familyPlayerIDList], ...]
    '''
    playerID = 0 if not curPlayer else curPlayer.GetPlayerID()
    addAuctionItemList = []
    for itemInfo in auctionItemList:
        curItem = itemInfo[0]
        familyID, familyPlayerIDList = 0, []
        if not curPlayer and len(itemInfo) == 3:
            familyID, familyPlayerIDList = itemInfo[1:]
        itemID = curItem.GetItemTypeID()
        itemData = {"GUID":curItem.GetGUID(), "ItemID":itemID, "ItemCount":curItem.GetCount(),
                    "ItemType":curItem.GetType(), "ItemJobLimit":curItem.GetJobLimit(), "ItemClassLV":ItemCommon.GetItemClassLV(curItem),
                    "UserData":curItem.GetUserData()}
        #扣物品
        if curPlayer and not familyID:
            ItemCommon.DelItem(curPlayer, curItem, curItem.GetCount())
        else:
            if curItem.GetIsBind():
                GameWorld.Log("非拍品,绑定无法上架!", playerID)
                curItem.Clear()
                continue
            curItem.Clear()
        drDict = {"FamilyID":familyID, "FamilyPlayerIDList":familyPlayerIDList, "ItemData":itemData}
        DR_AuctionHouse(curPlayer, "MapClearItem", drDict)
        addAuctionItemList.append([playerID, familyID, familyPlayerIDList, itemData])
        GameWorld.DebugLog("上架拍品: playerID=%s,familyID=%s,%s" % (playerID, familyID, drDict), playerID)
    QueryGameServer_AuctionHouse(playerID, "AddAuctionItem", addAuctionItemList)
    return
def DR_AuctionHouse(curPlayer, eventName, drDict):
    accID = "" if not curPlayer else curPlayer.GetAccID()
    playerID = 0 if not curPlayer else curPlayer.GetPlayerID()
    dataDict = {"EventName":eventName,"PlayerID":playerID, "AccID":accID}
    dataDict.update(drDict)
    DataRecordPack.SendEventPack("AuctionHouse", dataDict, curPlayer)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_AuctionHouse.py
New file
@@ -0,0 +1,51 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.RemoteQuery.GY_Query_AuctionHouse
#
# @todo:拍卖行
# @author hxp
# @date 2019-03-04
# @version 1.0
#
# 详细描述: 拍卖行
#
#-------------------------------------------------------------------------------
#"""Version = 2019-03-04 17:00"""
#-------------------------------------------------------------------------------
import PlayerAuctionHouse
import GameWorld
## 请求逻辑
#  @param query_Type 请求类型
#  @param query_ID 请求的玩家ID
#  @param packCMDList 发包命令 [ ]
#  @param tick 当前时间
#  @return resultDisc
def DoLogic(query_Type, query_ID, packCMDList, tick):
    return
#---------------------------------------------------------------------
## 执行结果
#  @param curPlayer 发出请求的玩家
#  @param callFunName 功能名称
#  @param funResult 查询的结果
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def DoResult(curPlayer, callFunName, funResult, tick):
    try:
        funResultList = eval(funResult)
    except:
        GameWorld.ErrLog("GY_Query_AuctionHouse %s eval Error" % funResult, curPlayer.GetPlayerID())
        return
    GameWorld.DebugLog("GY_Query_AuctionHouse ResultList=%s" % str(funResultList), curPlayer.GetPlayerID())
    PlayerAuctionHouse.QueryResult_AuctionHouse(curPlayer, funResultList)
    return