actor.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. package mapExchange
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. "f1-game/internal/code"
  5. "f1-game/internal/data"
  6. "f1-game/internal/enum"
  7. nameActor "f1-game/internal/name/actor"
  8. nameRemote "f1-game/internal/name/remote"
  9. "f1-game/internal/pb"
  10. "f1-game/internal/types"
  11. ao "f1-game/nodes/game/player/asset/origin"
  12. mapCall "f1-game/nodes/map/internal/call"
  13. "f1-game/nodes/map/internal/db"
  14. dbExchange "f1-game/nodes/map/internal/db/data/exchange"
  15. "time"
  16. cherryNUID "github.com/cherry-game/cherry/extend/nuid"
  17. ctime "github.com/cherry-game/cherry/extend/time"
  18. cfacade "github.com/cherry-game/cherry/facade"
  19. clog "github.com/cherry-game/cherry/logger"
  20. cactor "github.com/cherry-game/cherry/net/actor"
  21. )
  22. // 交易所管理actor
  23. type actor struct {
  24. cactor.Base
  25. tables *db.MapExchangeTables
  26. }
  27. func Init(app cfacade.IApplication, tables *db.MapExchangeTables, exchangeDeliverTables map[int64]*db.MapExchangeDeliverTable) {
  28. actor := &actor{
  29. tables: tables,
  30. }
  31. app.ActorSystem().CreateActor(actor.AliasID(), actor)
  32. // 创建发货的 子actor
  33. actor.Child().Create(nameActor.Map_ExchangeDeliver, newActorDeliver(exchangeDeliverTables))
  34. }
  35. func (p *actor) AliasID() string {
  36. return nameActor.Map_Exchange
  37. }
  38. func (p *actor) OnInit() {
  39. p.Remote().Register(nameRemote.MapExchange_HistoryPrice, p.historyPrice)
  40. p.Remote().Register(nameRemote.MapExchange_Item, p.exchangeItem)
  41. p.Remote().Register(nameRemote.MapExchange_BuyItem, p.exchangeBuyItem)
  42. p.Remote().Register(nameRemote.MapExchange_QueryFilter, p.queryFilter)
  43. p.Remote().Register(nameRemote.MapExchange_MyItems, p.myItems)
  44. p.Remote().Register(nameRemote.MapExchange_ItemUpdate, p.itemUpdate)
  45. p.Timer().Add(3*time.Second, p.every3STimer)
  46. p.Timer().Add(15*time.Second, p.every15STimer)
  47. }
  48. func (p *actor) OnFindChild(m *cfacade.Message) (cfacade.IActor, bool) {
  49. childID := m.TargetPath().ChildID
  50. if childActor, found := p.Child().Get(childID); found {
  51. return childActor, true
  52. }
  53. clog.Warnf("child actor not found: %s", childID)
  54. return nil, false
  55. }
  56. // 3秒定时器
  57. func (p *actor) every3STimer() {
  58. // 处理待上架的列表
  59. p.onPending()
  60. // 处理求购商品状态更新
  61. p.onWishItemUpState()
  62. // 处理出售商品状态更新
  63. p.onSellItemUpState()
  64. }
  65. // 15秒定时器
  66. func (p *actor) every15STimer() {
  67. // 处理求购匹配的列表
  68. p.onWishMatch()
  69. }
  70. // 处理待上架的列表
  71. func (p *actor) onPending() {
  72. start := ctime.Now()
  73. for _, item := range p.tables.PendingListed {
  74. if item.ItemDetail.Status != enum.ExchangeStatus_Pending {
  75. continue
  76. }
  77. // 更新为上架状态
  78. item.ItemDetail.Status = enum.ExchangeStatus_Listed
  79. item.Save2Queue()
  80. if item.ItemDetail.ActType == enum.ExchangeActType_Sell {
  81. // 添加到出售查询列表
  82. p.tables.SellQueryListed.Add(item)
  83. if p.tables.SellQueryListed.Count() > data.Const.ExchangeCatLimit {
  84. if sellItem, found := p.tables.SellQueryListed.RemoveAt(0); found {
  85. // 将超出限制的物品标记为隐藏
  86. sellItem.ItemDetail.IsFlag = true
  87. }
  88. }
  89. }
  90. }
  91. // 清空待上架的列表
  92. p.tables.PendingListed.Clear()
  93. cost := time.Since(start.Time)
  94. if cost > 20*time.Millisecond {
  95. clog.Warnf("onPending cost too much. cost: %v", cost)
  96. }
  97. }
  98. // 处理求购匹配的列表
  99. func (p *actor) onWishMatch() {
  100. start := ctime.Now()
  101. for _, wishItem := range p.tables.WishMap {
  102. // 跳过非上架状态的求购项
  103. if wishItem.ItemDetail.Status != enum.ExchangeStatus_Listed {
  104. continue
  105. }
  106. // 跳过已达上限的求购项
  107. if wishItem.ItemDetail.IsWishLimit {
  108. continue
  109. }
  110. p.handleWishMatch(wishItem)
  111. }
  112. cost := time.Since(start.Time)
  113. if cost > 20*time.Millisecond {
  114. clog.Warnf("onWishMatch cost too much. cost: %v", cost)
  115. }
  116. }
  117. // 单个求购匹配逻辑
  118. func (p *actor) handleWishMatch(wishItem *db.MapExchangeTable) {
  119. var (
  120. pageSize = data.Const.ExchangePageSize
  121. wishPlayerID = wishItem.ItemDetail.PlayerID
  122. goodsID = wishItem.ItemDetail.Asset.ID
  123. wishCount = wishItem.ItemDetail.Asset.Num
  124. wishPrice = wishItem.ItemDetail.Price
  125. )
  126. filter := db.GetWishMatchFilter(wishPlayerID, goodsID, wishPrice)
  127. comparator := db.GetWishMatchComparator()
  128. _, filterList := p.tables.SellQueryListed.Query(1, pageSize, filter, comparator)
  129. if len(filterList) == 0 {
  130. return
  131. }
  132. // 匹配的逻辑处理
  133. sellItem := filterList[0]
  134. // 交易数量
  135. count := min(sellItem.ItemDetail.Asset.Num, wishCount)
  136. // 数量扣除
  137. sellItem.ItemDetail.Asset.Num -= count
  138. //修改求购商品的状态
  139. wishItem.ItemDetail.Asset.Num -= count
  140. sellItem.Save2Queue()
  141. wishItem.Save2Queue()
  142. clog.Infof("onWishMatch match success. wish:%s, sell:%s, count:%d", wishItem.TransID, sellItem.TransID, count)
  143. errCode := mapCall.Exchange.ItemDeliver(wishPlayerID, sellItem.ToDetailProto(), count, wishPrice)
  144. if code.IsFail(errCode) {
  145. clog.Warnf("ItemDeliver failed. errCode: %d, wishPlayerID: %d, sellItem: %s, count: %d, wishPrice: %d", errCode, wishPlayerID, sellItem.TransID, count, wishPrice)
  146. }
  147. }
  148. // 处理出售商品状态更新
  149. func (p *actor) onSellItemUpState() {
  150. start := ctime.Now()
  151. tempFlagList := types.NewList[*db.MapExchangeTable]()
  152. for transID, sellItem := range p.tables.SellMap {
  153. // 判断商品是否已经售罄
  154. if sellItem.ItemDetail.Asset.Num < 1 {
  155. sellItem.ItemDetail.Status = enum.ExchangeStatus_Filled
  156. sellItem.ItemDetail.FilledTime = start.ToMillisecond()
  157. sellItem.IsDelete = true
  158. sellItem.Save2Queue()
  159. // 移除已经完成交易的商品
  160. p.tables.SellQueryListed.Remove(sellItem)
  161. p.tables.SellMap.Remove(transID)
  162. // 出售方同步删除
  163. mapCall.Player.ExchangeItemRemove(sellItem.ItemDetail.PlayerID, enum.ExchangeActType_Sell, sellItem.TransID)
  164. clog.Infof("onSellItemUpState remove sold item: %s", sellItem.TransID)
  165. continue
  166. }
  167. // 时间到了,处理下架
  168. if sellItem.ItemDetail.Status == enum.ExchangeStatus_Listed &&
  169. sellItem.ItemDetail.CanceledTime <= start.ToMillisecond() {
  170. sellItem.ItemDetail.Status = enum.ExchangeStatus_Canceled
  171. sellItem.Save2Queue()
  172. // 通知玩家下架
  173. mapCall.Player.ExchangeItemCanceled(sellItem.ItemDetail.PlayerID, sellItem.ToDetailProto())
  174. }
  175. // 移除已下架的商品
  176. if sellItem.ItemDetail.Status >= enum.ExchangeStatus_Canceled {
  177. // 移除可补充标记
  178. if sellItem.ItemDetail.IsFlag {
  179. sellItem.ItemDetail.IsFlag = false
  180. }
  181. p.tables.SellQueryListed.Remove(sellItem)
  182. if sellItem.ItemDetail.Status > enum.ExchangeStatus_Canceled {
  183. // 如果是取回了就标记删除
  184. if sellItem.ItemDetail.Status == enum.ExchangeStatus_Retrieve {
  185. sellItem.IsDelete = true
  186. sellItem.Save2Queue()
  187. mapCall.Player.ExchangeItemRetrieve(sellItem.ItemDetail.PlayerID, sellItem.ToDetailProto())
  188. }
  189. p.tables.SellMap.Remove(transID)
  190. clog.Infof("onSellItemUpState remove item from SellMap: %s", transID)
  191. }
  192. continue
  193. }
  194. if sellItem.ItemDetail.IsFlag {
  195. tempFlagList.Add(sellItem)
  196. }
  197. }
  198. // 补充的数量
  199. addCount := data.Const.ExchangeCatLimit - p.tables.SellQueryListed.Count()
  200. if !tempFlagList.IsEmpty() && addCount > 0 {
  201. // 排序,按时间倒序补充
  202. tempFlagList.Sort(db.GetListedTimeComparator(true))
  203. // 往查询列表添加addCount个数量
  204. count := min(tempFlagList.Size(), int(addCount))
  205. for i := range count {
  206. if item, found := tempFlagList.Get(i); found {
  207. // 移除可补充标记
  208. item.ItemDetail.IsFlag = false
  209. p.tables.SellQueryListed.Add(item)
  210. }
  211. }
  212. clog.Debugf("onSellItemUpState add sell item. count: %d", count)
  213. // 重新排序一下
  214. p.tables.SellQueryListed.Sort(db.GetListedTimeComparator(false))
  215. }
  216. cost := time.Since(start.Time)
  217. if cost > 20*time.Millisecond {
  218. clog.Warnf("onItemCanceled cost too much. cost: %v", cost)
  219. }
  220. }
  221. // 处理求购商品状态更新
  222. func (p *actor) onWishItemUpState() {
  223. start := ctime.Now()
  224. for index, wishItem := range p.tables.WishMap {
  225. if wishItem.ItemDetail.Asset.Num < 1 {
  226. wishItem.ItemDetail.Status = enum.ExchangeStatus_Filled
  227. wishItem.ItemDetail.FilledTime = start.ToMillisecond()
  228. wishItem.IsDelete = true
  229. wishItem.Save2Queue()
  230. // 移除求购列表
  231. p.tables.WishMap.Remove(index)
  232. // 删除玩家关联求购商品
  233. mapCall.Player.ExchangeItemRemove(wishItem.ItemDetail.PlayerID, enum.ExchangeActType_Wish, wishItem.TransID)
  234. clog.Infof("onWishItemUpState remove wish item: %s", wishItem.TransID)
  235. continue
  236. }
  237. // 时间到了,下架
  238. if wishItem.ItemDetail.Status == enum.ExchangeStatus_Listed &&
  239. wishItem.ItemDetail.CanceledTime <= start.ToMillisecond() {
  240. wishItem.ItemDetail.Status = enum.ExchangeStatus_Canceled
  241. wishItem.Save2Queue()
  242. // 通知玩家下架
  243. mapCall.Player.ExchangeItemCanceled(wishItem.ItemDetail.PlayerID, wishItem.ToDetailProto())
  244. }
  245. // 如果下架了
  246. if wishItem.ItemDetail.Status >= enum.ExchangeStatus_Canceled {
  247. // 如果是取回了就标记删除
  248. if wishItem.ItemDetail.Status == enum.ExchangeStatus_Retrieve {
  249. wishItem.IsDelete = true
  250. wishItem.Save2Queue()
  251. mapCall.Player.ExchangeItemRetrieve(wishItem.ItemDetail.PlayerID, wishItem.ToDetailProto())
  252. }
  253. // 只有交易成功和取回才移除
  254. if wishItem.ItemDetail.Status > enum.ExchangeStatus_Canceled {
  255. p.tables.WishMap.Remove(index)
  256. clog.Infof("onWishItemUpState remove item from WishMap: %s", wishItem.TransID)
  257. }
  258. }
  259. }
  260. cost := time.Since(start.Time)
  261. if cost > 20*time.Millisecond {
  262. clog.Warnf("onItemCanceled cost too much. cost: %v", cost)
  263. }
  264. }
  265. // 交易商品
  266. func (p *actor) exchangeItem(req *pb.PlayerExchangeItem) (*pb.ExchangeDetail, int32) {
  267. var (
  268. itemInfo = req.ItemInfo // 商品信息
  269. actType = enum.ExchangeActType(itemInfo.ActType) // 类型:1-出售,2-求购
  270. playerID = req.PlayerID // 玩家ID
  271. )
  272. // 上架最大毫秒数
  273. maxListedMilliSec := db.GetMaxListedMilliSec(actType)
  274. newItemDetail := dbExchange.NewItemDetail(actType, playerID, itemInfo.Asset.Id, itemInfo.Asset.Num, itemInfo.Price, maxListedMilliSec)
  275. isOk := newItemDetail.LoadConfig()
  276. if !isOk {
  277. return nil, code.ExchangeItemConfigError
  278. }
  279. newMapExchangeTable := db.NewMapExchangeTable(cherryNUID.Next(), newItemDetail)
  280. newMapExchangeTable.Save2Queue()
  281. p.tables.PendingListed.Add(newMapExchangeTable)
  282. switch actType {
  283. case enum.ExchangeActType_Sell:
  284. // 添加到出售集合
  285. p.tables.SellMap.Put(newMapExchangeTable.TransID, newMapExchangeTable)
  286. case enum.ExchangeActType_Wish:
  287. // 添加到求购集合
  288. p.tables.WishMap.Put(newMapExchangeTable.TransID, newMapExchangeTable)
  289. // 更新商品求购价格
  290. mapExchangeStatsTable, found := db.GetMapExchangeStatsTable(itemInfo.Asset.Id)
  291. if !found {
  292. mapExchangeStatsTable = db.NewMapExchangeStatsTable(itemInfo.Asset.Id)
  293. }
  294. mapExchangeStatsTable.UpdateWishPrice(itemInfo.Price)
  295. }
  296. rsp := newMapExchangeTable.ToDetailProto()
  297. clog.Infof("exchangeItem success. newMapExchangeTable: %+v", newMapExchangeTable)
  298. return rsp, code.OK
  299. }
  300. // 获取资源历史求购价格
  301. func (p *actor) historyPrice(req *pb.I32) (*pb.I32I32, int32) {
  302. var (
  303. itemID = req.Value // 商品ID
  304. rsp = &pb.I32I32{} // 响应数据
  305. )
  306. mapExchangeStatsTable, found := db.GetMapExchangeStatsTable(itemID)
  307. if found {
  308. rsp.Key = mapExchangeStatsTable.MinWishPrice
  309. rsp.Value = mapExchangeStatsTable.MaxWishPrice
  310. }
  311. return rsp, code.OK
  312. }
  313. // 购买商品
  314. func (p *actor) exchangeBuyItem(req *pb.PlayerExchangeBuyItem) (rsp *pb.ExchangeBuyResult, errCode int32) {
  315. var (
  316. playerID = req.PlayerID // 玩家ID
  317. gameNodeID = req.GameNodeID // 玩家游戏节点ID
  318. transID = req.TransID // 商品流水号ID
  319. count = req.Count // 购买数量
  320. )
  321. errCode = code.OK // 不管错误码都要返回
  322. mapExchangeTable, found := p.tables.GetExchangeTable(enum.ExchangeActType_Sell, transID)
  323. if !found {
  324. rsp = &pb.ExchangeBuyResult{
  325. Code: code.ExchangeItemNotFound,
  326. Detail: &pb.ExchangeDetail{
  327. TransactionID: transID,
  328. },
  329. }
  330. return
  331. }
  332. // 判断商品状态
  333. if mapExchangeTable.ItemDetail.Status > enum.ExchangeStatus_Listed {
  334. rsp = p.buildBuyResult(mapExchangeTable, code.ExchangeItemSoldOut)
  335. return
  336. }
  337. // 商品数量不足
  338. if count > mapExchangeTable.ItemDetail.Asset.Num {
  339. rsp = p.buildBuyResult(mapExchangeTable, code.ExchangeCountNotEnough)
  340. return
  341. }
  342. // 扣除资源
  343. exchangeGoodsRow, found := data.ExchangeGoods.GetByID(mapExchangeTable.ItemDetail.Asset.ID)
  344. if !found {
  345. rsp = p.buildBuyResult(mapExchangeTable, code.ConfigNotFound_ExchangeGoods)
  346. return
  347. }
  348. var (
  349. // 交易道具ID(金币)
  350. itemID = exchangeGoodsRow.ItemID
  351. // 单价
  352. price = mapExchangeTable.ItemDetail.Price
  353. // 总价
  354. sumPrice = int64(price) * count
  355. asset = types.NewAsset(itemID, sumPrice)
  356. assets = types.Assets{&asset}
  357. )
  358. // 扣除购买的物品
  359. if _, errcode := actorRemote.GamePlayer.AssetSub(gameNodeID, playerID, assets, ao.ExchangeBuyItemCost); code.IsFail(errcode) {
  360. rsp = p.buildBuyResult(mapExchangeTable, errcode)
  361. return
  362. }
  363. // 扣除数量
  364. mapExchangeTable.ItemDetail.Asset.Num -= count
  365. mapExchangeTable.Save2Queue()
  366. if errcode := mapCall.Exchange.ItemDeliver(playerID, mapExchangeTable.ToDetailProto(), count, 0); code.IsFail(errcode) {
  367. clog.Warnf("exchangeBuyItem ItemDeliver failed. errcode: %d, playerID: %d, count: %d, mapExchangeTable: %+v", errcode, playerID, count, mapExchangeTable)
  368. }
  369. rsp = p.buildBuyResult(mapExchangeTable, code.OK)
  370. clog.Infof("exchangeBuyItem success. mapExchangeTable: [%+v] buy count: [%d]", mapExchangeTable, count)
  371. return
  372. }
  373. func (p *actor) buildBuyResult(mapExchangeTable *db.MapExchangeTable, code int32) *pb.ExchangeBuyResult {
  374. return &pb.ExchangeBuyResult{
  375. Code: code,
  376. Detail: mapExchangeTable.ToDetailProto(),
  377. }
  378. }
  379. // 根据条件查询地图交易所的商品列表
  380. func (p *actor) queryFilter(req *pb.ExchangeQueryFilter) (*pb.ExchangeDetailList, int32) {
  381. var (
  382. pageNum = req.PageNum // 页码
  383. itemIDList = req.ItemIDList // 物品ID列表
  384. subTypeList = req.SubTypeList // 类型列表(道具表二级类型)
  385. qualityList = req.QualityList // 品质列表
  386. priceSort = enum.ExchangeSortType(req.PriceSort) // 按单价排序
  387. countSort = enum.ExchangeSortType(req.CountSort) // 按数量排序
  388. pageSize = data.Const.ExchangePageSize // 每页数量
  389. rsp = &pb.ExchangeDetailList{PageNum: pageNum}
  390. )
  391. filter := db.GetFilterByParams(itemIDList, subTypeList, qualityList)
  392. comparator := db.GetComparatorByParams(priceSort, countSort)
  393. total, list := p.tables.SellQueryListed.Query(pageNum, pageSize, filter, comparator)
  394. rsp.Total = total
  395. for _, mapExchangeTable := range list {
  396. rsp.List = append(rsp.List, mapExchangeTable.ToDetailProto())
  397. }
  398. clog.Debugf("queryFilter success. total: %d, list count: %d, pageNum: %d", total, len(list), pageNum)
  399. return rsp, code.OK
  400. }
  401. // 获取玩家的交易商品列表
  402. func (p *actor) myItems(req *pb.PlayerExchangeMyItem) (*pb.ExchangeDetailList, int32) {
  403. var (
  404. playerID = req.PlayerID
  405. actType = enum.ExchangeActType(req.ActType)
  406. transactionIDs = req.TransIDs
  407. )
  408. rsp := &pb.ExchangeDetailList{}
  409. if transactionIDs == nil || len(transactionIDs.List) == 0 {
  410. return rsp, code.OK
  411. }
  412. for _, transID := range transactionIDs.List {
  413. mapExchangeTable, found := p.tables.GetExchangeTable(actType, transID)
  414. if !found {
  415. clog.Warnf("myItems not found. playerID: %d, transID: %s", playerID, transID)
  416. continue
  417. }
  418. rsp.List = append(rsp.List, mapExchangeTable.ToDetailProto())
  419. }
  420. clog.Debugf("myItems success. playerID: %d, list count: %d", playerID, len(rsp.List))
  421. return rsp, code.OK
  422. }
  423. // 更新商品: 下架,重新上架,取回(如果没有下架就先下架再取回)
  424. func (p *actor) itemUpdate(req *pb.PlayerExchangeItemUpdate) int32 {
  425. var (
  426. playerID = req.PlayerID // 玩家ID
  427. transID = req.TransID // 商品流水号ID
  428. updateType = enum.ExchangeUpdateType(req.UpdateType) // 更新类型:1-下架,2-重新上架,3-取回
  429. actType = enum.ExchangeActType(req.ActType)
  430. nowMilliSec = ctime.Now().ToMillisecond()
  431. )
  432. mapExchangeTable, found := p.tables.GetExchangeTable(actType, transID)
  433. if !found {
  434. return code.ExchangeItemNotFound
  435. }
  436. switch updateType {
  437. case enum.ExchangeUpdateType_Cancel:
  438. {
  439. if mapExchangeTable.ItemDetail.Status > enum.ExchangeStatus_Listed {
  440. return code.ExchangeItemSoldOut
  441. }
  442. mapExchangeTable.ItemDetail.Status = enum.ExchangeStatus_Canceled
  443. mapExchangeTable.ItemDetail.CanceledTime = nowMilliSec
  444. mapExchangeTable.Save2Queue()
  445. // 下架商品
  446. p.tables.SellQueryListed.Remove(mapExchangeTable)
  447. clog.Infof("itemUpdate SellQueryListed remove. playerID: %d, transID: %s", playerID, transID)
  448. }
  449. case enum.ExchangeUpdateType_ReList:
  450. {
  451. if mapExchangeTable.ItemDetail.Status != enum.ExchangeStatus_Canceled {
  452. return code.ExchangeItemNotSoldOut
  453. }
  454. // 重新设置上架商品状态
  455. mapExchangeTable.Relist(nowMilliSec, req.IsWishLimit)
  456. // 重新上架商品
  457. p.tables.PendingListed.Add(mapExchangeTable)
  458. clog.Infof("itemUpdate PendingListed add. playerID: %d, transID: %s", playerID, transID)
  459. }
  460. case enum.ExchangeUpdateType_Retrieve:
  461. {
  462. // 取回之前如果商品没有下架,则先下架再取回
  463. if mapExchangeTable.ItemDetail.Status < enum.ExchangeStatus_Canceled {
  464. mapExchangeTable.ItemDetail.CanceledTime = nowMilliSec
  465. p.tables.SellQueryListed.Remove(mapExchangeTable)
  466. clog.Infof("itemUpdate Retrieve SellQueryListed remove. playerID: %d, transID: %s", playerID, transID)
  467. }
  468. // 标记取回状态
  469. mapExchangeTable.ItemDetail.Status = enum.ExchangeStatus_Retrieve
  470. mapExchangeTable.ItemDetail.RetrieveTime = nowMilliSec
  471. mapExchangeTable.Save2Queue()
  472. clog.Infof("itemUpdate Retrieve ok. playerID: %d, transID: %s", playerID, transID)
  473. }
  474. }
  475. return code.OK
  476. }