wait.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. package qznn
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/rand"
  6. "runtime/debug"
  7. "time"
  8. "github.com/shopspring/decimal"
  9. "github.com/sirupsen/logrus"
  10. "gogs.daxia.dev/huanan/pkg.daxia.dev/db"
  11. "gorm.io/gorm"
  12. "nn.daxia.dev/gameproto"
  13. "nn.daxia.dev/model"
  14. "nn.daxia.dev/nxd"
  15. )
  16. func (p *Game) WaitReady(room Room) error {
  17. select {
  18. case <-room.ReadyCh:
  19. //
  20. case <-time.After(5 * time.Second):
  21. //
  22. }
  23. return nil
  24. }
  25. func (p *Game) WaitChooseMaster(room Room) error {
  26. select {
  27. case <-room.ChooseMasterCh:
  28. //
  29. case <-time.After(7 * time.Second):
  30. //
  31. }
  32. p.locker.Lock()
  33. defer p.locker.Unlock()
  34. roomUserIDList, err := p.getRoomUserIDList(room.ID)
  35. if err != nil {
  36. logrus.Error(err)
  37. return err
  38. }
  39. //设置状态
  40. userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusReady)
  41. if err != nil {
  42. logrus.Error(err)
  43. return err
  44. }
  45. for _, userID := range userIDList {
  46. userItem := p.PlayerMap[userID]
  47. userItem.Status = PlayerStatusChooseMaster
  48. userItem.MasterMul = 0
  49. p.PlayerMap[userID] = userItem
  50. p.EventInfo(userID, "选庄", "通知默认不抢")
  51. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMaster, &gameproto.ChooseMaster{
  52. UserID: uint32(userID),
  53. Mul: uint32(0),
  54. RoomID: uint32(room.ID),
  55. })
  56. }
  57. //获取修正后的状态用户
  58. userIDList, err = p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMaster)
  59. if err != nil {
  60. logrus.Error(err)
  61. return err
  62. }
  63. maxMasterMul := 0
  64. for _, userID := range userIDList {
  65. userItem := p.PlayerMap[userID]
  66. if userItem.MasterMul > maxMasterMul {
  67. maxMasterMul = userItem.MasterMul
  68. }
  69. }
  70. masterIDList := make([]int32, 0)
  71. for _, userID := range userIDList {
  72. userItem := p.PlayerMap[userID]
  73. if userItem.MasterMul != maxMasterMul {
  74. continue
  75. }
  76. masterIDList = append(masterIDList, userID)
  77. }
  78. //更新用户,选取庄家
  79. index := rand.Intn(len(masterIDList))
  80. masterUserID := masterIDList[index]
  81. p.EventInfo(masterUserID, "选庄", "选为庄家")
  82. userItem := p.PlayerMap[masterUserID]
  83. userItem.IsMaster = true
  84. if userItem.MasterMul == 0 {
  85. userItem.MasterMul = 1
  86. }
  87. p.PlayerMap[masterUserID] = userItem
  88. //更新
  89. err = db.GetDB().Model(model.GameOrder{}).Where("user_id = ? and issue = ?", masterUserID, room.Issue).Update("is_master", 1).Error
  90. if err != nil {
  91. logrus.Error(err)
  92. return err
  93. }
  94. //通知
  95. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMasterFinish, &gameproto.ChooseMasterFinish{
  96. MasterUserID: uint32(masterUserID),
  97. MulList: []uint32{1, 4, 8, 11, 15},
  98. RoomID: uint32(room.ID),
  99. })
  100. return nil
  101. }
  102. func (p *Game) WaitChooseMul(room Room) error {
  103. p.locker.Lock()
  104. {
  105. room.Status = RoomStatusChooseMul
  106. room.StatusStartTime = time.Now().Unix()
  107. p.RoomMap[room.ID] = room
  108. }
  109. //master直接发送,跳过开牌流程
  110. userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMaster)
  111. if err != nil {
  112. logrus.Error(err)
  113. //FOCUS:UnLock
  114. p.locker.Unlock()
  115. return err
  116. }
  117. //master提前发送
  118. for _, userID := range userIDList {
  119. userItem, exists := p.PlayerMap[userID]
  120. if !exists {
  121. logrus.Error("not exist:", userID)
  122. continue
  123. }
  124. if !userItem.IsMaster {
  125. continue
  126. }
  127. userItem.Status = PlayerStatusChooseMul
  128. userItem.Mul = 1
  129. p.PlayerMap[userID] = userItem
  130. p.EventInfo(userID, "选倍数", "庄家默认倍数1")
  131. nxd.SendMsgToUserK(uint32(userID), gameproto.NotifyTypeEnum_NotifyTypeChooseMul, &gameproto.ChooseMul{
  132. UserID: uint32(userID),
  133. Mul: uint32(1),
  134. RoomID: uint32(room.ID),
  135. CardList: GetNNCardList(userItem.CardList),
  136. })
  137. break
  138. }
  139. p.locker.Unlock()
  140. logrus.Infof("等待选择倍数")
  141. select {
  142. case <-room.ChooseMulCh:
  143. //
  144. case <-time.After(7 * time.Second):
  145. //
  146. }
  147. p.locker.Lock()
  148. defer p.locker.Unlock()
  149. roomUserIDList, err := p.getRoomUserIDList(room.ID)
  150. if err != nil {
  151. logrus.Error(err)
  152. return err
  153. }
  154. logrus.Infof("未选取的用户,开始自动选取")
  155. for _, userID := range roomUserIDList {
  156. userItem, exists := p.PlayerMap[userID]
  157. if !exists {
  158. logrus.Error("not exist:", userID)
  159. continue
  160. }
  161. if userItem.Status != PlayerStatusChooseMaster {
  162. continue
  163. }
  164. userItem.Status = PlayerStatusChooseMul
  165. userItem.Mul = 1
  166. p.PlayerMap[userID] = userItem
  167. p.EventInfo(userID, "选倍数", "默认倍数1")
  168. //通知
  169. for _, sendToUserID := range roomUserIDList {
  170. var cardList []uint32
  171. if userID == sendToUserID {
  172. cardList = GetNNCardList(userItem.CardList)
  173. }
  174. nxd.SendMsgToUserK(uint32(sendToUserID), gameproto.NotifyTypeEnum_NotifyTypeChooseMul, &gameproto.ChooseMul{
  175. UserID: uint32(userID),
  176. Mul: uint32(1),
  177. RoomID: uint32(room.ID),
  178. CardList: cardList,
  179. })
  180. }
  181. }
  182. logrus.Infof("通知选择倍数完成, 用户数:%d", len(roomUserIDList))
  183. //通知
  184. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMulFinish, &gameproto.ChooseMulFinish{
  185. RoomID: uint32(room.ID),
  186. })
  187. return nil
  188. }
  189. func (p *Game) WaitOpen(room Room) error {
  190. p.locker.Lock()
  191. {
  192. room.Status = RoomStatusOpen
  193. room.StatusStartTime = time.Now().Unix()
  194. p.RoomMap[room.ID] = room
  195. }
  196. p.locker.Unlock()
  197. select {
  198. case <-room.OpenCh:
  199. //
  200. case <-time.After(15 * time.Second):
  201. //
  202. }
  203. p.locker.Lock()
  204. defer func() {
  205. {
  206. userIDList, _ := p.getRoomUserIDList(room.ID)
  207. for _, userID := range userIDList {
  208. playerItem, exists := p.PlayerMap[userID]
  209. if !exists {
  210. continue
  211. }
  212. p.EventInfo(userID, "Run", fmt.Sprintf("执行完毕,状态:%d", playerItem.Status))
  213. if playerItem.Status != PlayerStatusWaitReady {
  214. logrus.Panicf("完成,但状态不对:%d-%d", userID, playerItem.Status)
  215. }
  216. }
  217. for _, userID := range userIDList {
  218. if UserIsOnline(uint(userID)) {
  219. continue
  220. }
  221. p.EventInfo(userID, "Run", "玩家离线,踢走")
  222. p.Leave(userID, false)
  223. }
  224. }
  225. p.locker.Unlock()
  226. }()
  227. roomUserIDList, err := p.getRoomUserIDList(room.ID)
  228. if err != nil {
  229. logrus.Error(err)
  230. return err
  231. }
  232. userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMul)
  233. if err != nil {
  234. logrus.Error(err)
  235. return err
  236. }
  237. for _, userID := range userIDList {
  238. userItem, exists := p.PlayerMap[userID]
  239. if !exists {
  240. logrus.Error("not exist:", userID)
  241. continue
  242. }
  243. userItem.Status = PlayerStatusOpen
  244. p.PlayerMap[userID] = userItem
  245. p.EventInfo(userID, "开牌", "默认开牌")
  246. //通知
  247. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpen, &gameproto.Open{
  248. RoomID: uint32(room.ID),
  249. UserID: uint32(userID),
  250. CardList: GetNNCardList(userItem.CardList),
  251. })
  252. }
  253. timeNow := time.Now()
  254. msg := &gameproto.OpenFinish{
  255. RoomID: uint32(room.ID),
  256. PayoutInfoList: []*gameproto.PayoutInfo{},
  257. }
  258. err = db.GetDB().Transaction(func(tx *gorm.DB) error {
  259. defer func() {
  260. if err := recover(); err != nil {
  261. logrus.Error(err)
  262. fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
  263. }
  264. }()
  265. payoutInfoList, err := p.payout(tx, room.BaseAmount, room.ID)
  266. if err != nil {
  267. return err
  268. }
  269. for _, payoutInfo := range payoutInfoList {
  270. userID := payoutInfo.PlayerID
  271. winAmount := payoutInfo.Amount
  272. userItem, exists := p.PlayerMap[userID]
  273. if !exists {
  274. logrus.Fatal("not exist:", userID)
  275. continue
  276. }
  277. beforeUserModel := model.User{}
  278. err := tx.Model(model.User{}).Where("id = ?", userID).First(&beforeUserModel).Error
  279. if err != nil {
  280. return err
  281. }
  282. if room.RoomType == int32(model.RoomTypeFree) {
  283. err = tx.Exec("update users as a, users as b set a.credits_qznn = 0, a.credits = b.credits + b.credits_qznn + ? where a.id = ? and b.id = ? and b.credits_qznn + ? >= 0",
  284. payoutInfo.Amount, userID, userID, payoutInfo.Amount).Error
  285. if err != nil {
  286. logrus.Error(err)
  287. return err
  288. }
  289. afterUserModel := model.User{}
  290. err = tx.Model(model.User{}).Where("id = ?", userID).First(&afterUserModel).Error
  291. if err != nil {
  292. return err
  293. }
  294. //设置注单
  295. err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, userID).Updates(map[string]interface{}{
  296. "is_draw": 1,
  297. "draw_time": &timeNow,
  298. "is_win": payoutInfo.Amount.GreaterThan(decimal.Zero),
  299. "win_amount": payoutInfo.Amount,
  300. "before_amount": beforeUserModel.Credits.Add(beforeUserModel.CreditsQZNN),
  301. "after_amount": afterUserModel.Credits,
  302. }).Error
  303. if err != nil {
  304. return err
  305. }
  306. currUserModel := model.User{}
  307. err = tx.Model(model.User{}).Where("id = ?", userID).First(&currUserModel).Error
  308. if err != nil {
  309. return err
  310. }
  311. //这里已经解除冻结
  312. userItem.Credits = currUserModel.Credits
  313. p.PlayerMap[userID] = userItem
  314. //设置结算信息
  315. userCredist, _ := userItem.Credits.Round(2).Float64()
  316. msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
  317. UserID: uint32(userID),
  318. WinAmount: winAmount.StringFixed(2),
  319. IsMaster: payoutInfo.IsMaster,
  320. Credits: userCredist,
  321. })
  322. } else {
  323. err = tx.Exec("update users as a, users as b set a.balance_qznn = 0, a.balance = b.balance + b.balance_qznn + ? where a.id = ? and b.id = ? and b.balance_qznn + ? >= 0",
  324. payoutInfo.Amount, userID, userID, payoutInfo.Amount).Error
  325. if err != nil {
  326. logrus.Error(err)
  327. return err
  328. }
  329. afterUserModel := model.User{}
  330. err = tx.Model(model.User{}).Where("id = ?", userID).First(&afterUserModel).Error
  331. if err != nil {
  332. return err
  333. }
  334. //设置注单
  335. err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, userID).Updates(map[string]interface{}{
  336. "is_draw": 1,
  337. "draw_time": &timeNow,
  338. "is_win": payoutInfo.Amount.GreaterThan(decimal.Zero),
  339. "win_amount": payoutInfo.Amount,
  340. "before_amount": beforeUserModel.Balance.Add(beforeUserModel.BalanceQZNN),
  341. "after_amount": afterUserModel.Balance,
  342. }).Error
  343. if err != nil {
  344. return err
  345. }
  346. currUserModel := model.User{}
  347. err = tx.Model(model.User{}).Where("id = ?", userID).First(&currUserModel).Error
  348. if err != nil {
  349. return err
  350. }
  351. //已经解除冻结
  352. userItem.Balance = currUserModel.Balance
  353. p.PlayerMap[userID] = userItem
  354. //设置结算信息
  355. userBalance, _ := userItem.Balance.Round(2).Float64()
  356. msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
  357. UserID: uint32(userID),
  358. WinAmount: winAmount.StringFixed(2),
  359. IsMaster: payoutInfo.IsMaster,
  360. Balance: userBalance,
  361. })
  362. }
  363. }
  364. return nil
  365. })
  366. if err != nil {
  367. logrus.Error(err, "===============")
  368. return err
  369. }
  370. roomUserIDList, _ = p.getRoomUserIDList(room.ID)
  371. //更新一下用户信息
  372. userModelList := make([]model.User, 0)
  373. err = db.GetDB().Model(model.User{}).Where("id in ?", roomUserIDList).Scan(&userModelList).Error
  374. if err != nil {
  375. logrus.Error(err)
  376. return err
  377. }
  378. if len(roomUserIDList) != len(userModelList) {
  379. logrus.Panicf("len(roomUserIDList) != len(userModelList), %d != %d, %v, %v",
  380. len(roomUserIDList), len(userModelList), roomUserIDList, userModelList)
  381. }
  382. for _, userID := range roomUserIDList {
  383. userItem := p.PlayerMap[userID]
  384. userItem.IsMaster = false
  385. userItem.Status = PlayerStatusWaitReady
  386. p.PlayerMap[userID] = userItem
  387. }
  388. for _, userModel := range userModelList {
  389. userID := int32(userModel.ID)
  390. userItem := p.PlayerMap[userID]
  391. userItem.Balance = userModel.Balance
  392. userItem.Credits = userModel.Credits
  393. userItem.HeadImg = userModel.HeadImg
  394. userItem.Name = userModel.Name
  395. userItem.IsMaster = false
  396. userItem.Status = PlayerStatusWaitReady
  397. p.EventInfo(userID, "开牌", "更新用户状态为等待开牌")
  398. p.PlayerMap[userID] = userItem
  399. }
  400. //清理新号,免得卡主
  401. close(room.ReadyCh)
  402. close(room.ChooseMasterCh)
  403. close(room.ChooseMulCh)
  404. close(room.OpenCh)
  405. room.ReadyCh = make(chan bool)
  406. room.ChooseMasterCh = make(chan bool)
  407. room.ChooseMulCh = make(chan bool)
  408. room.OpenCh = make(chan bool)
  409. room.Status = RoomStatusWaitReady
  410. room.StatusStartTime = time.Now().Unix()
  411. p.RoomMap[room.ID] = room
  412. //通知
  413. roomUserIDList, err = p.getRoomUserIDList(room.ID)
  414. if err != nil {
  415. logrus.Error(err)
  416. return err
  417. }
  418. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpenFinish, msg)
  419. //判断是否满足准入,不满足,踢走
  420. for _, userID := range roomUserIDList {
  421. userItem := p.PlayerMap[userID]
  422. if room.RoomType == int32(model.RoomTypeNormal) {
  423. if userItem.Balance.LessThan(decimal.NewFromInt(10)) {
  424. p.LeaveRoomInner(userID, false)
  425. }
  426. } else {
  427. p.LeaveRoomInner(userID, false)
  428. }
  429. }
  430. return nil
  431. }
  432. func (p *Game) getRoomUserIDListWithStatus(roomID int32, status PlayerStatus) ([]int32, error) {
  433. roomItem, exists := p.RoomMap[roomID]
  434. if !exists {
  435. return nil, errors.New("room not exists")
  436. }
  437. userIDList := make([]int32, 0)
  438. for _, chairItem := range roomItem.ChairList {
  439. if chairItem.PlayerID == 0 {
  440. continue
  441. }
  442. playerItem, exists := p.PlayerMap[chairItem.PlayerID]
  443. if !exists {
  444. continue
  445. }
  446. if playerItem.Status != status {
  447. continue
  448. }
  449. userIDList = append(userIDList, chairItem.PlayerID)
  450. }
  451. return userIDList, nil
  452. }
  453. func (p *Game) getRoomUserIDList(roomID int32) ([]int32, error) {
  454. roomItem, exists := p.RoomMap[roomID]
  455. if !exists {
  456. return nil, errors.New("room not exists")
  457. }
  458. userIDList := make([]int32, 0)
  459. for _, chairItem := range roomItem.ChairList {
  460. if chairItem.PlayerID == 0 {
  461. continue
  462. }
  463. userIDList = append(userIDList, chairItem.PlayerID)
  464. }
  465. return userIDList, nil
  466. }