util_match.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. --[[
  2. Descripttion:战斗房间
  3. version:
  4. Author: Neo,Huang
  5. Date: 2023-11-16 23:24:42
  6. LastEditors: Neo,Huang
  7. LastEditTime: 2023-11-16 23:25:34
  8. --]]
  9. local lib_battle_redis = require("lib_battle_redis")
  10. local timeUtil = require("utils.timeUtil")
  11. local redisBattleUtil = require("redisBattleUtil")
  12. local util_player = require("utils.util_player")
  13. local util_box = require("utils.util_box")
  14. local gameConst = require("const.gameConst")
  15. local util_user = require("utils.util_user")
  16. local nodeMgr = require("nodeMgr")
  17. local util_battle = require("utils.util_battle")
  18. local battleData = require("data.battle")
  19. local bagData = require("data.bag")
  20. local boxAdapt = require("adapt.boxAdapt")
  21. local resAdapt = require("adapt.resAdapt")
  22. local root = {}
  23. local function _get_global_room_key()
  24. return "global:room"
  25. end
  26. local function _get_room_key(id)
  27. return string.format("room:%s", tostring(id))
  28. end
  29. local function _get_active_room_id_key()
  30. return "active:rooms"
  31. end
  32. -- 分配房间ID
  33. function root:gen_room_id()
  34. local key = _get_global_room_key()
  35. local subKey = "max:room:id"
  36. local id = lib_battle_redis:hincrby(key, subKey, 1)
  37. if id > 200000000 then
  38. id = 1
  39. lib_battle_redis:hset(key, subKey, id)
  40. end
  41. return id
  42. end
  43. -- 获取当前活跃房间ID列表
  44. function root:get_active_room_id_list()
  45. local key = _get_active_room_id_key()
  46. return lib_battle_redis:smembers(key)
  47. end
  48. -- 打包房间玩家信息
  49. function root:pack_room_player_info(roomId, uid)
  50. local info = self:get_room_player_info(roomId, uid)
  51. if is_empty(info) then
  52. return
  53. end
  54. info.playerInfo = util_player:get_base_info(uid)
  55. return info
  56. end
  57. -- 打包房间玩家信息列表
  58. function root:pack_room_player_info_list(playerList)
  59. if is_empty(playerList) then
  60. return
  61. end
  62. local infoList = {}
  63. for _, v in ipairs(playerList) do
  64. local info = {
  65. playerInfo = util_player:get_base_info(v.uid),
  66. seatId = v.seatId,
  67. status = v.status
  68. }
  69. table.insert(infoList, info)
  70. end
  71. return infoList
  72. end
  73. -- 打包房间信息
  74. function root:pack_room_info(roomId)
  75. if is_empty(roomId) then
  76. return
  77. end
  78. local key = _get_room_key(roomId)
  79. -- 房间是否存在
  80. local isExist = lib_battle_redis:exists(key)
  81. if not isExist then
  82. return
  83. end
  84. local info = {
  85. roomId = roomId,
  86. playCount = redisBattleUtil.hget_int(key, "playCount"),
  87. battleBoxList = redisBattleUtil.hget_json(key, "boxIdList"),
  88. status = redisBattleUtil.hget_int(key, "status"),
  89. createTime = redisBattleUtil.hget_int(key, "createTime")
  90. }
  91. -- 玩家信息列表
  92. local playerList = redisBattleUtil.hget_json(key, "playerList")
  93. info.playerList = self:pack_room_player_info_list(playerList)
  94. return info
  95. end
  96. -- 打包所有房间信息
  97. function root:pack_room_info_list()
  98. local roomIdList = self:get_active_room_id_list()
  99. if is_empty(roomIdList) then
  100. return
  101. end
  102. local roomInfoList = {}
  103. for _, v in ipairs(roomIdList) do
  104. local roomId = tonumber(v)
  105. local info = self:pack_room_info(roomId)
  106. if not is_empty(info) then
  107. table.insert(roomInfoList, info)
  108. end
  109. end
  110. return roomInfoList
  111. end
  112. -- 打包玩家房间信息
  113. function root:pack_player_room_info(uid)
  114. if is_empty(uid) then
  115. return
  116. end
  117. local roomId = battleData:get_room_id(uid)
  118. if is_empty(roomId) then
  119. return
  120. end
  121. return self:pack_room_info(roomId)
  122. end
  123. -- 创建房间
  124. function root:create_room(uid, playCount, boxIdList)
  125. if is_empty(uid) then
  126. return false
  127. end
  128. if is_empty(playCount) or playCount < 2 or playCount > 3 then
  129. return false
  130. end
  131. if is_empty(boxIdList) or #boxIdList < 1 then
  132. return false
  133. end
  134. local roomId = self:gen_room_id()
  135. -- 设置房间信息
  136. local playerList = {{uid = uid, seatId = 1, status = 1}}
  137. local key = _get_room_key(roomId)
  138. redisBattleUtil.hset(key, "createTime", timeUtil.now()) -- 创建时间
  139. redisBattleUtil.hset(key, "hostUid", uid) -- 房主
  140. redisBattleUtil.hset(key, "playCount", playCount) -- 战斗人数
  141. redisBattleUtil.hset(key, "boxIdList", boxIdList) -- 战斗箱子ID列表
  142. redisBattleUtil.hset(key, "playerList", playerList) -- 玩家列表
  143. redisBattleUtil.hset(key, "status", 0) -- 战斗状态
  144. -- 房间进入准备战斗集合
  145. key = _get_active_room_id_key()
  146. lib_battle_redis:sadd(key, roomId)
  147. return true, roomId
  148. end
  149. -- 房间是否存在
  150. function root:is_room_exist(roomId)
  151. local key = _get_room_key(roomId)
  152. -- 房间是否存在
  153. return lib_battle_redis:exists(key)
  154. end
  155. -- 座位是否已被占
  156. function root:get_seat_player(roomId, seatId)
  157. if is_empty(roomId) or is_empty(seatId) then
  158. return
  159. end
  160. local key = _get_room_key(roomId)
  161. -- 房间是否存在
  162. local isExist = lib_battle_redis:exists(key)
  163. if not isExist then
  164. return
  165. end
  166. local playerList = redisBattleUtil.hget_json(key, "playerList")
  167. for _, v in ipairs(playerList) do
  168. if v.seatId and v.seatId == seatId then
  169. return v.uid
  170. end
  171. end
  172. end
  173. -- 进入房间
  174. function root:enter_room(uid, roomId)
  175. if is_empty(uid) or is_empty(roomId) then
  176. return false
  177. end
  178. local key = _get_room_key(roomId)
  179. -- 房间是否存在
  180. local isExist = lib_battle_redis:exists(key)
  181. if not isExist then
  182. return false
  183. end
  184. local playerList = redisBattleUtil.hget_json(key, "playerList")
  185. for _, v in ipairs(playerList) do
  186. if v.uid == uid then
  187. -- 玩家已进入房间
  188. return false
  189. end
  190. end
  191. table.insert(playerList, {uid = uid, status = 0})
  192. redisBattleUtil.hset(key, "playerList", playerList)
  193. return true
  194. end
  195. -- 坐下
  196. function root:seat_down(uid, roomId, seatId)
  197. if is_empty(uid) or is_empty(roomId) or is_empty(seatId) then
  198. return false
  199. end
  200. local key = _get_room_key(roomId)
  201. -- 房间是否存在
  202. local isExist = lib_battle_redis:exists(key)
  203. if not isExist then
  204. return false
  205. end
  206. local isMatch = false
  207. local playerList = redisBattleUtil.hget_json(key, "playerList")
  208. for _, v in ipairs(playerList) do
  209. if v.uid == uid then
  210. v.seatId = seatId
  211. v.status = 1
  212. isMatch = true
  213. break
  214. end
  215. end
  216. if not isMatch then
  217. table.insert(playerList, {uid = uid, seatId = seatId, status = 1})
  218. end
  219. redisBattleUtil.hset(key, "playerList", playerList)
  220. return true
  221. end
  222. -- 站起
  223. function root:stand_up(uid, roomId)
  224. if is_empty(uid) or is_empty(roomId) then
  225. return false
  226. end
  227. local key = _get_room_key(roomId)
  228. -- 房间是否存在
  229. local isExist = lib_battle_redis:exists(key)
  230. if not isExist then
  231. return false
  232. end
  233. local isMatch = false
  234. local playerList = redisBattleUtil.hget_json(key, "playerList")
  235. for _, v in ipairs(playerList) do
  236. if v.uid == uid then
  237. if v.seatId == nil or v.seatId == 0 then
  238. return false
  239. end
  240. v.seatId = nil
  241. v.status = 0
  242. isMatch = true
  243. break
  244. end
  245. end
  246. if not isMatch then
  247. return false
  248. end
  249. redisBattleUtil.hset(key, "playerList", playerList)
  250. return true
  251. end
  252. -- 离开房间
  253. function root:leave(uid, roomId)
  254. if is_empty(uid) or is_empty(roomId) then
  255. return false
  256. end
  257. local key = _get_room_key(roomId)
  258. -- 房间是否存在
  259. local isExist = lib_battle_redis:exists(key)
  260. if not isExist then
  261. return false
  262. end
  263. local playerList = redisBattleUtil.hget_json(key, "playerList")
  264. for k, v in ipairs(playerList) do
  265. if v.uid == uid then
  266. table.remove(playerList, k)
  267. break
  268. end
  269. end
  270. redisBattleUtil.hset(key, "playerList", playerList)
  271. return true
  272. end
  273. -- 获取房间玩家信息
  274. function root:get_room_player_info(roomId, uid)
  275. if is_empty(roomId) or is_empty(uid) then
  276. return
  277. end
  278. local key = _get_room_key(roomId)
  279. -- 房间是否存在
  280. local isExist = lib_battle_redis:exists(key)
  281. if not isExist then
  282. return
  283. end
  284. local playerList = redisBattleUtil.hget_json(key, "playerList")
  285. for _, v in ipairs(playerList) do
  286. if v.uid == uid then
  287. return v
  288. end
  289. end
  290. end
  291. -- 获取房间消耗价格
  292. function root:get_room_price(roomId)
  293. local key = _get_room_key(roomId)
  294. local boxIdList = redisBattleUtil.hget_json(key, "boxIdList")
  295. if is_empty(boxIdList) then
  296. return
  297. end
  298. return boxAdapt:battle_get_box_price(boxIdList)
  299. end
  300. -- 获取房间状态
  301. -- 0:等待 1:进行中 2:结算 3:销毁
  302. function root:get_room_status(roomId)
  303. if is_empty(roomId) then
  304. return 3
  305. end
  306. local key = _get_room_key(roomId)
  307. -- 房间是否存在
  308. local isExist = lib_battle_redis:exists(key)
  309. if not isExist then
  310. return 3
  311. end
  312. local status = redisBattleUtil.hget_int(key, "status")
  313. return status
  314. end
  315. -- 销毁房间
  316. function root:destroy_room(roomId)
  317. if is_empty(roomId) then
  318. return false
  319. end
  320. local key = _get_room_key(roomId)
  321. -- 房间是否存在
  322. local isExist = lib_battle_redis:exists(key)
  323. if not isExist then
  324. -- 从活跃房间集合删除
  325. lib_battle_redis:sismember(_get_active_room_id_key(), roomId)
  326. return false
  327. end
  328. local status = redisBattleUtil.hget_int(key, "status")
  329. if status >= 0 then
  330. -- 战斗已开始
  331. return false
  332. end
  333. -- 删除房间信息
  334. lib_battle_redis:del(key)
  335. -- 从活跃房间集合删除
  336. lib_battle_redis:sismember(_get_active_room_id_key(), roomId)
  337. return true
  338. end
  339. -- 是否等待开战结束
  340. function root:is_wait_battle_end(roomId)
  341. if is_empty(roomId) then
  342. return false
  343. end
  344. local key = _get_room_key(roomId)
  345. -- 房间是否存在
  346. local isExist = lib_battle_redis:exists(key)
  347. if not isExist then
  348. return true
  349. end
  350. local currTime = timeUtil.now()
  351. local createTime = redisBattleUtil.hget_int(key, "createTime")
  352. local waitSeconds = boxAdapt:battle_const("no_full_close_room_time") or 10
  353. if currTime < createTime + waitSeconds then
  354. return false
  355. end
  356. return true
  357. end
  358. ----------------------------------------
  359. -- 战斗
  360. ---------------------------------------
  361. -- 房间是否开始战斗
  362. function root:is_room_start_battle(roomId)
  363. local status = self:get_room_status(roomId)
  364. if status > 0 then
  365. return false
  366. end
  367. local seatCount = 0
  368. local key = _get_room_key(roomId)
  369. local playerList = redisBattleUtil.hget_json(key, "playerList")
  370. for _, v in ipairs(playerList) do
  371. if v.seatId and v.seatId > 0 then
  372. seatCount = seatCount + 1
  373. end
  374. end
  375. local playCount = redisBattleUtil.hget_int(key, "playCount")
  376. return seatCount >= playCount
  377. end
  378. -- 生成战斗编号
  379. function root:gen_battle_id(roomId)
  380. local currTime = timeUtil.now()
  381. return string.format("BT%s%08d", os.date("%Y%m%d", currTime), roomId)
  382. end
  383. -- 战斗
  384. function root:start_battle(roomId)
  385. if is_empty(roomId) then
  386. return false
  387. end
  388. local key = _get_room_key(roomId)
  389. -- 房间是否存在
  390. local isExist = lib_battle_redis:exists(key)
  391. if not isExist then
  392. -- 从活跃房间集合删除
  393. lib_battle_redis:sismember(_get_active_room_id_key(), roomId)
  394. return false
  395. end
  396. -- 更新状态
  397. redisBattleUtil.hset(key, "status", 1)
  398. local battleId = self:gen_battle_id(roomId)
  399. local battleBoxList = redisBattleUtil.hget_json(key, "boxIdList")
  400. local playerList = redisBattleUtil.hget_json(key, "playerList")
  401. -- 射击轮次
  402. local rounds = {}
  403. local totalPrice = 0
  404. for k, v in ipairs(battleBoxList) do
  405. local roundInfo = {round = k, shotList = {}}
  406. for _, _v in ipairs(playerList) do
  407. if _v.seatId and _v.seatId > 0 then
  408. local itemId = util_box:battle_get_box_drop_item_and_count(v)
  409. local price = resAdapt:get_item_price(itemId)
  410. local shotInfo = {
  411. uid = _v.uid,
  412. itemId = itemId,
  413. price = price
  414. }
  415. table.insert(roundInfo.shotList, shotInfo)
  416. totalPrice = totalPrice + price
  417. end
  418. end
  419. table.insert(rounds, roundInfo)
  420. end
  421. -- 胜利玩家
  422. local mapUidPrice = {}
  423. for _, v in ipairs(rounds) do
  424. for _, _v in ipairs(v.shotList) do
  425. mapUidPrice[_v.uid] = (mapUidPrice[_v.uid] or 0) + _v.price
  426. end
  427. end
  428. local winUid = nil
  429. local maxPrice = nil
  430. for uid, price in pairs(mapUidPrice) do
  431. if maxPrice == nil or price > maxPrice then
  432. winUid = uid
  433. end
  434. end
  435. -- 战斗玩家列表
  436. local n1Price = resAdapt:get_item_price(gameConst.ITEM_ID.N1)
  437. local battlePlayerList = {}
  438. for _, v in ipairs(playerList) do
  439. if v.seatId and v.seatId > 0 then
  440. if v.uid == winUid then
  441. -- 收集所有玩家射击
  442. local info = {uid = v.uid, seatId = v.seatId, shotList = {}}
  443. for _, _v in ipairs(rounds) do
  444. for _, __v in ipairs(_v.shotList) do
  445. table.insert(info.shotList, {itemId = __v.itemId, price = __v.price})
  446. end
  447. end
  448. table.insert(battlePlayerList, info)
  449. else
  450. -- 安慰奖
  451. local info = {
  452. uid = v.uid,
  453. seatId = v.seatId,
  454. shotList = {{itemId = gameConst.ITEM_ID.N1, price = n1Price}}
  455. }
  456. table.insert(battlePlayerList, info)
  457. end
  458. end
  459. end
  460. -- 发放奖励
  461. for _, v in ipairs(battleBoxList) do
  462. local items = {}
  463. for _, _v in ipairs(v.shotList) do
  464. table.insert(items, {id = v.itemId, count = 1})
  465. end
  466. local keyEvent = string.format("battle-settle-%s-%s", battleId, tostring(v.uid == winUid and 1 or 0))
  467. bagData:add_items(v.uid, items, keyEvent)
  468. end
  469. redisBattleUtil.hset(key, "status", 2)
  470. local settle = {
  471. roomInfo = self:pack_room_info(roomId),
  472. winUid = winUid,
  473. battleId = battleId,
  474. rounds = rounds,
  475. battlePlayerList = battlePlayerList
  476. }
  477. -- 通知所有房间玩家
  478. for _, v in ipairs(playerList) do
  479. util_user:user_proto_notify(v.uid, "on_room_battle_settle", {settle = settle})
  480. end
  481. -- 新增战斗记录
  482. util_battle:add_battle_record(settle, totalPrice)
  483. -- 关闭房间
  484. -- 删除房间信息
  485. lib_battle_redis:del(key)
  486. -- 从活跃房间集合删除
  487. lib_battle_redis:sismember(_get_active_room_id_key(), roomId)
  488. -- 通知在线玩家 - 销毁房间
  489. nodeMgr.broadcast_proto_notify("on_room_destroy", {roomId = roomId})
  490. end
  491. ----------------------------------------
  492. -- 玩家战斗信息
  493. ----------------------------------------
  494. local bagData = require("data.bag")
  495. -- 绑定房间
  496. function root:band_room(uid, roomId, costItems)
  497. if is_empty(uid) or is_empty(costItems) then
  498. return
  499. end
  500. battleData:band_room(uid, roomId, costItems)
  501. -- 消耗道具
  502. local keyEvent = string.format("battle-seat-down-%s", tostring(roomId))
  503. bagData:consume_items(uid, costItems, keyEvent)
  504. end
  505. -- 解绑房间
  506. -- ty - 解绑类型: leave:离开 dismiss:解散 seat:更换座位 settle:结算
  507. function root:unband_room(uid, ty)
  508. if is_empty(uid) then
  509. return
  510. end
  511. local costItems = battleData:get_room_cost_items(uid)
  512. if (ty == "leave" or ty == "dismiss" or ty == "seat") and not is_empty(costItems) then
  513. -- 返回物品
  514. local keyEvent = string.format("battle-%s", ty)
  515. bagData:add_items(uid, costItems, keyEvent)
  516. end
  517. battleData:band_room(uid)
  518. return true
  519. end
  520. return root