wait.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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 p.locker.Unlock()
  205. roomUserIDList, err := p.getRoomUserIDList(room.ID)
  206. if err != nil {
  207. logrus.Error(err)
  208. return err
  209. }
  210. userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMul)
  211. if err != nil {
  212. logrus.Error(err)
  213. return err
  214. }
  215. for _, userID := range userIDList {
  216. userItem, exists := p.PlayerMap[userID]
  217. if !exists {
  218. logrus.Error("not exist:", userID)
  219. continue
  220. }
  221. userItem.Status = PlayerStatusOpen
  222. p.PlayerMap[userID] = userItem
  223. p.EventInfo(userID, "开牌", "默认开牌")
  224. //通知
  225. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpen, &gameproto.Open{
  226. RoomID: uint32(room.ID),
  227. UserID: uint32(userID),
  228. CardList: GetNNCardList(userItem.CardList),
  229. })
  230. }
  231. userIDList, err = p.getRoomUserIDListWithStatus(room.ID, PlayerStatusOpen)
  232. if err != nil {
  233. logrus.Error(err)
  234. return err
  235. }
  236. //获取庄家的牌
  237. var masterPlayerItem Player
  238. for _, userID := range userIDList {
  239. playerItem := p.PlayerMap[userID]
  240. if !playerItem.IsMaster {
  241. continue
  242. }
  243. masterPlayerItem = playerItem
  244. break
  245. }
  246. masterCardList := GetNNCardList(masterPlayerItem.CardList)
  247. masterTotalWinAmount := decimal.NewFromInt(0)
  248. timeNow := time.Now()
  249. msg := &gameproto.OpenFinish{
  250. RoomID: uint32(room.ID),
  251. PayoutInfoList: []*gameproto.PayoutInfo{},
  252. }
  253. err = db.GetDB().Transaction(func(tx *gorm.DB) error {
  254. defer func() {
  255. if err := recover(); err != nil {
  256. logrus.Error(err)
  257. fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
  258. }
  259. }()
  260. for _, userID := range userIDList {
  261. if userID == masterPlayerItem.ID {
  262. continue
  263. }
  264. userItem, exists := p.PlayerMap[userID]
  265. if !exists {
  266. logrus.Error("not exist:", userID)
  267. continue
  268. }
  269. var isWin bool
  270. var winAmount decimal.Decimal
  271. userCardList := GetNNCardList(userItem.CardList)
  272. masterWin, isEqual, cardLevel := WinLevel(masterCardList, userCardList)
  273. if !masterWin {
  274. _, _, cardLevel = WinLevel(userCardList, masterCardList)
  275. }
  276. if isEqual {
  277. isWin = false
  278. winAmount = decimal.NewFromInt(0)
  279. } else {
  280. if !masterWin {
  281. isWin = true
  282. //赢庄家
  283. winAmount = room.BaseAmount.Mul(decimal.NewFromInt(int64(masterPlayerItem.MasterMul))).Mul(decimal.NewFromInt(int64(userItem.Mul))).Mul(decimal.NewFromInt(int64(cardLevel)))
  284. } else {
  285. isWin = false
  286. //输给庄家
  287. winAmount = room.BaseAmount.Mul(decimal.NewFromInt(int64(masterPlayerItem.MasterMul))).Mul(decimal.NewFromInt(int64(userItem.Mul))).Mul(decimal.NewFromInt(-1)).Mul(decimal.NewFromInt(int64(cardLevel)))
  288. }
  289. }
  290. err = tx.Model(model.User{}).Where("id = ? and balance + ? > 0", userID, winAmount).
  291. Update("balance", gorm.Expr("balance + ?", winAmount)).Error
  292. if err != nil {
  293. return err
  294. }
  295. //设置注单
  296. err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, userID).Updates(map[string]interface{}{
  297. "is_draw": 1,
  298. "draw_time": &timeNow,
  299. "is_win": isWin,
  300. "win_amount": winAmount,
  301. }).Error
  302. if err != nil {
  303. return err
  304. }
  305. currUserModel := model.User{}
  306. err = tx.Model(model.User{}).Where("id = ?", userID).First(&currUserModel).Error
  307. if err != nil {
  308. return err
  309. }
  310. userItem.Balance = currUserModel.Balance
  311. p.PlayerMap[userID] = userItem
  312. //设置结算信息
  313. userBalance, _ := userItem.Balance.Round(2).Float64()
  314. msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
  315. UserID: uint32(userID),
  316. WinAmount: float32(winAmount.Mul(decimal.NewFromInt(100)).IntPart()) / 100,
  317. IsMaster: false,
  318. Balance: userBalance,
  319. })
  320. masterTotalWinAmount = masterTotalWinAmount.Add(winAmount.Mul(decimal.NewFromInt(-1)))
  321. }
  322. err = tx.Model(model.User{}).Where("id = ? and balance + ? > 0", masterPlayerItem.ID, masterTotalWinAmount).
  323. Update("balance", gorm.Expr("balance + ?", masterTotalWinAmount)).Error
  324. if err != nil {
  325. logrus.Error(err)
  326. return err
  327. }
  328. err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, masterPlayerItem.ID).Updates(map[string]interface{}{
  329. "is_draw": 1,
  330. "draw_time": &timeNow,
  331. "is_win": masterTotalWinAmount.GreaterThan(decimal.Zero),
  332. "win_amount": masterTotalWinAmount,
  333. }).Error
  334. //设置master结算信息,更新余额
  335. currUserModel := model.User{}
  336. err = tx.Model(model.User{}).Where("id = ?", masterPlayerItem.ID).First(&currUserModel).Error
  337. if err != nil {
  338. logrus.Error(err)
  339. return err
  340. }
  341. masterPlayerItem.Balance = currUserModel.Balance
  342. p.PlayerMap[masterPlayerItem.ID] = masterPlayerItem
  343. masterBalance, _ := masterPlayerItem.Balance.Round(2).Float64()
  344. msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
  345. UserID: uint32(masterPlayerItem.ID),
  346. WinAmount: float32(masterTotalWinAmount.Mul(decimal.NewFromInt(100)).IntPart()) / 100,
  347. IsMaster: true,
  348. Balance: masterBalance,
  349. })
  350. return nil
  351. })
  352. if err != nil {
  353. logrus.Error(err, "===============")
  354. return err
  355. }
  356. //更新一下用户信息
  357. userModelList := make([]model.User, 0)
  358. err = db.GetDB().Model(model.User{}).Where("id in ?", roomUserIDList).Scan(&userModelList).Error
  359. if err != nil {
  360. logrus.Error(err)
  361. return err
  362. }
  363. if len(roomUserIDList) != len(userModelList) {
  364. logrus.Panicf("len(roomUserIDList) != len(userModelList), %d != %d, %v, %v",
  365. len(roomUserIDList), len(userModelList), roomUserIDList, userModelList)
  366. }
  367. for _, userID := range roomUserIDList {
  368. userItem := p.PlayerMap[userID]
  369. userItem.IsMaster = false
  370. userItem.Status = PlayerStatusWaitReady
  371. p.PlayerMap[userID] = userItem
  372. }
  373. for _, userModel := range userModelList {
  374. userID := int32(userModel.ID)
  375. userItem := p.PlayerMap[userID]
  376. userItem.Balance = userModel.Balance
  377. userItem.HeadImg = userModel.HeadImg
  378. userItem.Name = userModel.Name
  379. userItem.IsMaster = false
  380. userItem.Status = PlayerStatusWaitReady
  381. p.EventInfo(userID, "开牌", "更新用户状态为等待开牌")
  382. p.PlayerMap[userID] = userItem
  383. }
  384. room.Status = RoomStatusWaitReady
  385. room.StatusStartTime = time.Now().Unix()
  386. p.RoomMap[room.ID] = room
  387. //通知
  388. roomUserIDList, err = p.getRoomUserIDList(room.ID)
  389. if err != nil {
  390. logrus.Error(err)
  391. return err
  392. }
  393. nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpenFinish, msg)
  394. return nil
  395. }
  396. func (p *Game) getRoomUserIDListWithStatus(roomID int32, status PlayerStatus) ([]int32, error) {
  397. roomItem, exists := p.RoomMap[roomID]
  398. if !exists {
  399. return nil, errors.New("room not exists")
  400. }
  401. userIDList := make([]int32, 0)
  402. for _, chairItem := range roomItem.ChairList {
  403. if chairItem.PlayerID == 0 {
  404. continue
  405. }
  406. playerItem, exists := p.PlayerMap[chairItem.PlayerID]
  407. if !exists {
  408. continue
  409. }
  410. if playerItem.Status != status {
  411. continue
  412. }
  413. userIDList = append(userIDList, chairItem.PlayerID)
  414. }
  415. return userIDList, nil
  416. }
  417. func (p *Game) getRoomUserIDList(roomID int32) ([]int32, error) {
  418. roomItem, exists := p.RoomMap[roomID]
  419. if !exists {
  420. return nil, errors.New("room not exists")
  421. }
  422. userIDList := make([]int32, 0)
  423. for _, chairItem := range roomItem.ChairList {
  424. if chairItem.PlayerID == 0 {
  425. continue
  426. }
  427. userIDList = append(userIDList, chairItem.PlayerID)
  428. }
  429. return userIDList, nil
  430. }