qznn.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. //描述整个游戏,提供接口给外部使用,挂了,就全部挂
  2. /**
  3. ## 游戏中的情况下,用户退出
  4. 使用延迟退出机制,游戏中的用户,不处理退出的事件,等这盘游戏结束后处理
  5. 如果没有游戏中的情况,则马上处理
  6. */
  7. package qznn
  8. import (
  9. "errors"
  10. "fmt"
  11. "math/rand"
  12. "runtime/debug"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "github.com/bwmarrin/snowflake"
  17. "github.com/patrickmn/go-cache"
  18. "github.com/sasha-s/go-deadlock"
  19. "github.com/shopspring/decimal"
  20. "github.com/sirupsen/logrus"
  21. "gogs.daxia.dev/huanan/pkg.daxia.dev/db"
  22. "gorm.io/gorm"
  23. "nn.daxia.dev/gameproto"
  24. "nn.daxia.dev/model"
  25. "nn.daxia.dev/nxd"
  26. "nn.daxia.dev/online"
  27. )
  28. type kkMap map[string]interface{}
  29. type PlayerStatus int
  30. type RoomStatus int
  31. var ErrNotFound = errors.New("record not found")
  32. var ErrPwd = errors.New("password not correct")
  33. const (
  34. RoomIDEmpty = int32(0)
  35. PlayerStatusWaitReady PlayerStatus = 1 //等待准备
  36. PlayerStatusReady PlayerStatus = 2 //已经准备
  37. PlayerStatusChooseMaster PlayerStatus = 3 //已经选择庄
  38. PlayerStatusChooseMul PlayerStatus = 4 //已经选择倍数
  39. PlayerStatusOpen PlayerStatus = 5 //已经开奖
  40. RoomStatusWaitReady RoomStatus = 1 //等待准备
  41. RoomStatusReady RoomStatus = 2 //已经有两个准备好,等待其他玩家准备
  42. RoomStatusChooseMaster RoomStatus = 3 //正在选择庄家
  43. RoomStatusChooseMul RoomStatus = 4 //正在选择倍数
  44. RoomStatusOpen RoomStatus = 5 //正在开奖
  45. )
  46. type Chair struct {
  47. ID int32 //索引,1-5
  48. PlayerID int32 //用户ID
  49. }
  50. type Room struct {
  51. ID int32 //房间ID
  52. Name string //名称
  53. Passwd string //密码
  54. RoomType int32 //房间类型
  55. ChairList []Chair //桌子
  56. BaseAmount decimal.Decimal //底金
  57. Issue string //当前期号
  58. Status RoomStatus //房间当前状态
  59. StatusStartTime int64 //房间当前状态开始的时间
  60. ReadyCh chan bool //当房间全部用户准备好,触发
  61. ChooseMasterCh chan bool //全部选择完庄,触发
  62. ChooseMulCh chan bool //全部选择完倍数,触发
  63. OpenCh chan bool //全部开牌完毕,触发
  64. }
  65. type Player struct {
  66. ID int32
  67. Name string
  68. HeadImg string
  69. Balance decimal.Decimal //余额
  70. Credits decimal.Decimal //游戏积分
  71. RoomID int32 //当前所在房间ID
  72. JoinTime time.Time //加入时间
  73. Status PlayerStatus
  74. IsMaster bool //是否为庄家
  75. MasterMul int //抢庄的倍数
  76. Mul int //倍数
  77. CardList NNCardList //牌
  78. }
  79. type Game struct {
  80. RoomMap map[int32]Room
  81. PlayerMap map[int32]Player
  82. IDGener *snowflake.Node
  83. LogID int64
  84. //nextDelPlayerIDList *list.List //下一轮游戏开始会删,可能离线了
  85. locker deadlock.Mutex
  86. }
  87. var gameInstance *Game
  88. func GetInstance() *Game {
  89. if gameInstance != nil {
  90. return gameInstance
  91. }
  92. node, err := snowflake.NewNode(1)
  93. if err != nil {
  94. logrus.Error(err)
  95. return nil
  96. }
  97. gameInstance = &Game{
  98. RoomMap: map[int32]Room{},
  99. PlayerMap: map[int32]Player{},
  100. IDGener: node,
  101. //nextDelPlayerIDList: list.New(),
  102. locker: deadlock.Mutex{},
  103. }
  104. gameInstance.Start()
  105. return gameInstance
  106. }
  107. func (p *Game) Start() {
  108. //初始化房间
  109. chairList := make([]Chair, 0)
  110. for i := 0; i < 5; i++ {
  111. chairList = append(chairList, Chair{
  112. ID: int32(i),
  113. PlayerID: 0,
  114. })
  115. }
  116. roomID := 1
  117. //10个免费房间,10个收费房间
  118. for i := 0; i < 10; i++ {
  119. room := Room{
  120. ID: int32(roomID),
  121. RoomType: int32(model.RoomTypeFree),
  122. ChairList: make([]Chair, 5),
  123. BaseAmount: decimal.NewFromInt(3),
  124. Status: RoomStatusWaitReady,
  125. ReadyCh: make(chan bool),
  126. ChooseMasterCh: make(chan bool),
  127. ChooseMulCh: make(chan bool),
  128. OpenCh: make(chan bool),
  129. }
  130. copy(room.ChairList, chairList)
  131. p.RoomMap[int32(roomID)] = room
  132. roomID++
  133. }
  134. for i := 0; i < 10; i++ {
  135. room := Room{
  136. ID: int32(roomID),
  137. RoomType: int32(model.RoomTypeNormal),
  138. ChairList: make([]Chair, 5),
  139. BaseAmount: decimal.NewFromInt(3),
  140. Status: RoomStatusWaitReady,
  141. ReadyCh: make(chan bool),
  142. ChooseMasterCh: make(chan bool),
  143. ChooseMulCh: make(chan bool),
  144. OpenCh: make(chan bool),
  145. }
  146. copy(room.ChairList, chairList)
  147. p.RoomMap[int32(roomID)] = room
  148. roomID++
  149. }
  150. }
  151. func (p *Game) Connect(playerID int32) error {
  152. //处理房间
  153. userModel := model.User{}
  154. err := userModel.GetUserByID(uint32(playerID))
  155. if err != nil {
  156. logrus.Error(err)
  157. return err
  158. }
  159. p.locker.Lock()
  160. defer p.locker.Unlock()
  161. p.JoinNoLock(playerID)
  162. roomList, currPlayerList, logID := gameInstance.GetLogNoLock(int32(playerID))
  163. roomListProto := make([]*gameproto.Room, 0)
  164. userIDList := make([]uint32, 0)
  165. atRoom := false
  166. var currRoom Room
  167. for _, roomItem := range roomList {
  168. baseAmountDeciaml := roomItem.BaseAmount.Mul(decimal.NewFromInt(100))
  169. baseAmount := float64(baseAmountDeciaml.IntPart()) / 100
  170. roomListProto = append(roomListProto, &gameproto.Room{
  171. ID: uint32(roomItem.ID),
  172. Name: roomItem.Name,
  173. RoomType: gameproto.RoomType(roomItem.RoomType),
  174. NeedPwd: roomItem.Passwd != "",
  175. BaseAmount: baseAmount,
  176. ChairUserID1: uint32(roomItem.ChairList[0].PlayerID),
  177. ChairUserID2: uint32(roomItem.ChairList[1].PlayerID),
  178. ChairUserID3: uint32(roomItem.ChairList[2].PlayerID),
  179. ChairUserID4: uint32(roomItem.ChairList[3].PlayerID),
  180. ChairUserID5: uint32(roomItem.ChairList[4].PlayerID),
  181. })
  182. for i := 0; i < 5; i++ {
  183. if roomItem.ChairList[i].PlayerID == 0 {
  184. continue
  185. }
  186. if roomItem.ChairList[i].PlayerID == int32(userModel.ID) {
  187. atRoom = true
  188. currRoom = roomItem
  189. }
  190. userIDList = append(userIDList, uint32(roomItem.ChairList[i].PlayerID))
  191. }
  192. }
  193. var roomDetail gameproto.RoomDetail
  194. if atRoom {
  195. roomItem := currRoom
  196. baseAmountDeciaml := roomItem.BaseAmount.Mul(decimal.NewFromInt(100))
  197. baseAmount := float64(baseAmountDeciaml.IntPart()) / 100
  198. roomDetail = gameproto.RoomDetail{
  199. ID: uint32(roomItem.ID),
  200. Name: roomItem.Name,
  201. RoomType: gameproto.RoomType(roomItem.RoomType),
  202. NeedPwd: roomItem.Passwd != "",
  203. BaseAmount: baseAmount,
  204. ChairUserID1: uint32(roomItem.ChairList[0].PlayerID),
  205. ChairUserID2: uint32(roomItem.ChairList[1].PlayerID),
  206. ChairUserID3: uint32(roomItem.ChairList[2].PlayerID),
  207. ChairUserID4: uint32(roomItem.ChairList[3].PlayerID),
  208. ChairUserID5: uint32(roomItem.ChairList[4].PlayerID),
  209. Status: uint32(currRoom.Status),
  210. StatusStartTime: roomItem.StatusStartTime,
  211. RoomUserList: make([]*gameproto.RoomUser, 0),
  212. TimeNow: time.Now().Unix(),
  213. }
  214. for _, player := range currPlayerList {
  215. balanceFloat, _ := player.Balance.Round(2).Float64()
  216. var cardList []uint32
  217. if player.Status == PlayerStatusOpen {
  218. cardList = GetNNCardList(player.CardList)
  219. }
  220. if player.ID == int32(userModel.ID) {
  221. //如果准备好了,就显示3张牌
  222. if player.Status != PlayerStatusWaitReady {
  223. cardList = GetNNCardListLimit(player.CardList, 3)
  224. }
  225. //如果选择了倍数,就返回5张
  226. if player.Status == PlayerStatusChooseMul {
  227. cardList = GetNNCardList(player.CardList)
  228. }
  229. }
  230. roomDetail.RoomUserList = append(roomDetail.RoomUserList, &gameproto.RoomUser{
  231. UserID: uint32(player.ID),
  232. CardList: cardList,
  233. IsMaster: player.IsMaster,
  234. MasterMul: uint32(player.MasterMul),
  235. Mul: uint32(player.Mul),
  236. Status: uint32(player.Status),
  237. Balance: balanceFloat,
  238. })
  239. }
  240. }
  241. balance, _ := strconv.ParseFloat(userModel.Balance.StringFixed(2), 64)
  242. logrus.Debugf("join game user id:%d", userModel.ID)
  243. var userListProto []*gameproto.User
  244. if len(userIDList) != 0 {
  245. var err error
  246. userListModel, err := (model.User{}).GetUserByIDList(userIDList)
  247. if err != nil {
  248. logrus.Error("failed:", err)
  249. return err
  250. }
  251. userListProto = make([]*gameproto.User, 0)
  252. for _, userModel := range userListModel {
  253. userListProto = append(userListProto, &gameproto.User{
  254. UserID: uint32(userModel.ID),
  255. Name: userModel.Name,
  256. Img: userModel.HeadImg,
  257. })
  258. }
  259. }
  260. connectProto := gameproto.Connect{
  261. UserID: uint32(userModel.ID),
  262. LogID: logID,
  263. Name: userModel.Nickname,
  264. Img: userModel.HeadImg,
  265. Balance: balance,
  266. RoomList: roomListProto,
  267. UserList: userListProto,
  268. RoomDetail: &roomDetail,
  269. }
  270. UserActive(userModel.ID)
  271. nxd.SendMsgToUserK(uint32(userModel.ID), gameproto.NotifyTypeEnum_NotifyTypeConnect, &connectProto)
  272. logrus.Debugf("send connect user id:%d", userModel.ID)
  273. return nil
  274. }
  275. func (p *Game) Join(playerID int32) error {
  276. p.locker.Lock()
  277. defer p.locker.Unlock()
  278. return p.JoinNoLock(playerID)
  279. }
  280. func (p *Game) JoinNoLock(playerID int32) error {
  281. userModel := model.User{}
  282. err := userModel.GetUserByID(uint32(playerID))
  283. if err != nil {
  284. logrus.Error(err)
  285. return err
  286. }
  287. _, exists := p.PlayerMap[playerID]
  288. if exists {
  289. return nil
  290. }
  291. roomID := RoomIDEmpty
  292. room, _, err := p.getUserRoomID(playerID)
  293. if err == nil {
  294. roomID = room.ID
  295. }
  296. player := Player{
  297. ID: playerID,
  298. Name: userModel.Name,
  299. HeadImg: userModel.HeadImg,
  300. Balance: userModel.Balance,
  301. Credits: decimal.NewFromInt(0),
  302. RoomID: roomID,
  303. Status: PlayerStatusWaitReady,
  304. JoinTime: time.Now(),
  305. }
  306. p.PlayerMap[playerID] = player
  307. p.EventInfo(playerID, "加入游戏", "加入游戏")
  308. return nil
  309. }
  310. func (p *Game) Leave(playerID int32) error {
  311. p.locker.Lock()
  312. defer p.locker.Unlock()
  313. playerItem, exists := p.PlayerMap[playerID]
  314. if !exists {
  315. p.EventInfo(playerID, "退出房间", "用户不存在")
  316. return nil
  317. }
  318. if playerItem.Status != PlayerStatusWaitReady {
  319. p.EventInfo(playerID, "退出房间", fmt.Sprintf("用户不是等待开始状态,无法退出,状态:%d", playerItem.Status))
  320. return nil
  321. }
  322. delete(p.PlayerMap, playerID)
  323. for _, roomItem := range p.RoomMap {
  324. for index, chairItem := range roomItem.ChairList {
  325. if chairItem.PlayerID != playerID {
  326. continue
  327. }
  328. chairItem.PlayerID = 0
  329. roomItem.ChairList[index] = chairItem
  330. p.EventInfo(playerID, "退出房间", "清理桌子信息")
  331. //发信息,表示离开
  332. nxd.SendMsgToAllUserK(gameproto.NotifyTypeEnum_NotifyTypeLeaveRoom, &gameproto.LeaveRoom{
  333. RoomID: uint32(roomItem.ID),
  334. ChairID: uint32(chairItem.ID),
  335. UserID: uint32(playerID),
  336. })
  337. return nil
  338. }
  339. }
  340. p.EventInfo(playerID, "退出房间", "清理用户信息")
  341. return nil
  342. }
  343. func (p *Game) ChooseRndChair(playerID int32) error {
  344. p.locker.Lock()
  345. defer p.locker.Unlock()
  346. p.EventInfo(playerID, "随机选桌子", "开始")
  347. maxRoomID := -1
  348. maxChairID := -1
  349. maxUserCount := -1
  350. for _, roomItem := range p.RoomMap {
  351. if roomItem.Passwd != "" {
  352. continue
  353. }
  354. userCount := 0
  355. for _, chairItem := range roomItem.ChairList {
  356. if chairItem.PlayerID == 0 {
  357. continue
  358. }
  359. userCount++
  360. }
  361. if userCount == 4 {
  362. continue
  363. }
  364. if userCount > maxUserCount {
  365. maxUserCount = userCount
  366. maxRoomID = int(roomItem.ID)
  367. for _, chairItem := range roomItem.ChairList {
  368. if chairItem.PlayerID != 0 {
  369. continue
  370. }
  371. maxChairID = int(chairItem.ID)
  372. break
  373. }
  374. }
  375. }
  376. if maxRoomID != -1 && maxChairID != -1 {
  377. p.EventInfo(playerID, "随机选桌子", fmt.Sprintf("找到桌子:%d-%d", maxRoomID, maxChairID))
  378. return p.ChooseChair(playerID, int32(maxRoomID), int32(maxChairID), "", false)
  379. }
  380. p.EventInfo(playerID, "随机选桌子", "没有找到桌子")
  381. return ErrNotFound
  382. }
  383. func (p *Game) ChooseChair(playerID int32, roomID int32, chairID int32, passwd string, userLock bool) error {
  384. if userLock {
  385. p.locker.Lock()
  386. defer p.locker.Unlock()
  387. }
  388. p.EventInfo(playerID, "选桌子", "开始")
  389. err := p.ChooseChairNoLock(playerID, roomID, chairID, passwd)
  390. if err != nil {
  391. p.EventInfo(playerID, "选桌子", "选择失败:"+err.Error())
  392. return err
  393. }
  394. p.EventInfo(playerID, "选桌子", "选取成功")
  395. return nil
  396. }
  397. func (p *Game) ChooseChairNoLock(playerID int32, roomID int32, chairID int32, passwd string) error {
  398. logrus.Info("ChooseChair...")
  399. playerItem, exists := p.PlayerMap[playerID]
  400. if !exists {
  401. p.EventInfo(playerID, "选桌子-inner", "用户不存在")
  402. return errors.New("用户不存在")
  403. }
  404. //离开房间
  405. if roomID == 0 {
  406. p.EventInfo(playerID, "选桌子-inner", "退出房间")
  407. for rKey, room := range p.RoomMap {
  408. for cKey, chairItem := range room.ChairList {
  409. if chairItem.PlayerID != playerID {
  410. continue
  411. }
  412. //设置为0
  413. room.ChairList[cKey].PlayerID = 0
  414. p.RoomMap[rKey] = room
  415. playerItem.RoomID = 0
  416. playerItem.Status = PlayerStatusWaitReady
  417. playerItem.IsMaster = false
  418. playerItem.MasterMul = 1
  419. playerItem.Mul = 1
  420. p.PlayerMap[playerID] = playerItem
  421. p.EventInfo(playerID, "选桌子-inner", "退出完成")
  422. //通知
  423. nxd.SendMsgToAllUserK(gameproto.NotifyTypeEnum_NotifyTypeLeaveRoom, &gameproto.LeaveRoom{
  424. RoomID: uint32(room.ID),
  425. ChairID: uint32(chairItem.ID),
  426. UserID: uint32(playerID),
  427. User: &gameproto.User{
  428. UserID: uint32(playerItem.ID),
  429. Name: playerItem.Name,
  430. Img: playerItem.HeadImg,
  431. },
  432. })
  433. return nil
  434. }
  435. }
  436. return nil
  437. }
  438. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("寻找桌子,房间ID:%d", roomID))
  439. //同一个房间,切换,不影响
  440. if playerItem.RoomID != 0 {
  441. if playerItem.RoomID != roomID && playerItem.RoomID != RoomIDEmpty {
  442. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("没退出房间,就进入新的房间,不允许,之前房间:%d,进入房间:%d", playerItem.RoomID, roomID))
  443. logrus.Error("没退出房间,就进入新的房间,不允许")
  444. return errors.New("没退出房间,就进入新的房间,不允许")
  445. }
  446. }
  447. roomItem, exists := p.RoomMap[roomID]
  448. if !exists {
  449. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("房间不存,房间ID:%d", roomID))
  450. return ErrNotFound
  451. }
  452. if roomItem.Passwd != passwd {
  453. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("房间密码不对,输入密码:%s", passwd))
  454. return errors.New("密码不正确")
  455. }
  456. //椅子不确定,选一个
  457. if chairID == -1 {
  458. p.EventInfo(playerID, "选桌子-inner", "随机选取桌子")
  459. //选一次,判断是否已经在房间,是的话,直接返回之前的桌子
  460. for _, chair := range roomItem.ChairList {
  461. if chair.PlayerID == playerItem.ID {
  462. chairID = chair.ID
  463. break
  464. }
  465. }
  466. if chairID == -1 {
  467. for _, chair := range roomItem.ChairList {
  468. if chair.PlayerID == 0 {
  469. chairID = chair.ID
  470. break
  471. }
  472. }
  473. }
  474. }
  475. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("选取的桌子:%d", chairID))
  476. if chairID == -1 {
  477. p.EventInfo(playerID, "选桌子-inner", "房间已经满人了")
  478. return errors.New("房间已经满人了")
  479. }
  480. if int(chairID) >= len(roomItem.ChairList) {
  481. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("chair id 超过范围:%d", chairID))
  482. return errors.New("chair id 超过范围")
  483. }
  484. //够底注才能进
  485. if playerItem.Balance.LessThan(roomItem.BaseAmount) {
  486. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("余额不足,无法进入房间,余额:%v,限额:%v", playerItem.Balance, roomItem.BaseAmount))
  487. return errors.New("余额不足,无法进入房间")
  488. }
  489. chairItem := roomItem.ChairList[chairID]
  490. if chairItem.PlayerID == playerID {
  491. p.EventInfo(playerID, "选桌子-inner", "已经在桌子上")
  492. return nil
  493. }
  494. if chairItem.PlayerID != 0 {
  495. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("桌子上有其他人:%d", chairItem.PlayerID))
  496. return errors.New("有人了")
  497. }
  498. roomItem.ChairList[chairID] = Chair{
  499. ID: chairID,
  500. PlayerID: playerID,
  501. }
  502. playerItem.RoomID = roomID
  503. playerItem.Status = PlayerStatusWaitReady
  504. playerItem.IsMaster = false
  505. playerItem.MasterMul = 1
  506. playerItem.Mul = 1
  507. p.PlayerMap[playerID] = playerItem
  508. p.EventInfo(playerID, "选桌子-inner", fmt.Sprintf("选完桌子:%d", chairID))
  509. //通知,房间外的用户收到用户进入信息,房间内的,会带上房间详情
  510. userIDList := online.GetAllUser()
  511. roomUserIDlist := make([]int32, 0)
  512. notInRoomUserIDlist := make([]int32, 0)
  513. for _, userID := range userIDList {
  514. currPlayer, exists := p.PlayerMap[int32(userID)]
  515. if !exists {
  516. continue
  517. }
  518. if currPlayer.RoomID == roomID {
  519. roomUserIDlist = append(roomUserIDlist, int32(userID))
  520. } else {
  521. notInRoomUserIDlist = append(notInRoomUserIDlist, int32(userID))
  522. }
  523. }
  524. p.EventInfo(playerID, "选桌子-inner", "通知房间外的用户,有人进入房间")
  525. nxd.SendMsgToUserList(notInRoomUserIDlist, gameproto.NotifyTypeEnum_NotifyTypeJoinRoom, &gameproto.JoinRoom{
  526. RoomID: uint32(roomID),
  527. ChairID: uint32(chairID),
  528. UserID: uint32(playerID),
  529. GameStatus: uint32(roomItem.Status),
  530. User: &gameproto.User{UserID: uint32(playerItem.ID), Name: playerItem.Name, Img: playerItem.HeadImg},
  531. })
  532. baseAmountDeciaml := roomItem.BaseAmount.Mul(decimal.NewFromInt(100))
  533. baseAmount := float64(baseAmountDeciaml.IntPart()) / 100
  534. roomDetail := gameproto.RoomDetail{
  535. ID: uint32(roomItem.ID),
  536. Name: roomItem.Name,
  537. RoomType: gameproto.RoomType(roomItem.RoomType),
  538. NeedPwd: roomItem.Passwd != "",
  539. BaseAmount: baseAmount,
  540. ChairUserID1: uint32(roomItem.ChairList[0].PlayerID),
  541. ChairUserID2: uint32(roomItem.ChairList[1].PlayerID),
  542. ChairUserID3: uint32(roomItem.ChairList[2].PlayerID),
  543. ChairUserID4: uint32(roomItem.ChairList[3].PlayerID),
  544. ChairUserID5: uint32(roomItem.ChairList[4].PlayerID),
  545. Status: uint32(roomItem.Status),
  546. StatusStartTime: roomItem.StatusStartTime,
  547. RoomUserList: make([]*gameproto.RoomUser, 0),
  548. TimeNow: time.Now().Unix(),
  549. }
  550. currPlayerList := make([]Player, 0)
  551. for _, chairItem := range roomItem.ChairList {
  552. if chairItem.PlayerID == 0 {
  553. continue
  554. }
  555. currPlayer, exists := p.PlayerMap[chairItem.PlayerID]
  556. if !exists {
  557. continue
  558. }
  559. currPlayerList = append(currPlayerList, currPlayer)
  560. }
  561. for _, player := range currPlayerList {
  562. balanceFloat, _ := player.Balance.Round(2).Float64()
  563. var cardList []uint32
  564. if player.Status == PlayerStatusOpen {
  565. p.EventInfo(player.ID, "选桌子-inner", "玩家开牌状态,带上牌的信息")
  566. cardList = GetNNCardList(player.CardList)
  567. }
  568. roomDetail.RoomUserList = append(roomDetail.RoomUserList, &gameproto.RoomUser{
  569. UserID: uint32(player.ID),
  570. CardList: cardList,
  571. IsMaster: player.IsMaster,
  572. MasterMul: uint32(player.MasterMul),
  573. Mul: uint32(player.Mul),
  574. Status: uint32(player.Status),
  575. Balance: balanceFloat,
  576. })
  577. }
  578. p.EventInfo(playerID, "选桌子-inner", "通知房间内的用户,有人进入房间,带上房间详情")
  579. nxd.SendMsgToUserList(roomUserIDlist, gameproto.NotifyTypeEnum_NotifyTypeJoinRoom, &gameproto.JoinRoom{
  580. RoomID: uint32(roomID),
  581. ChairID: uint32(chairID),
  582. UserID: uint32(playerID),
  583. GameStatus: uint32(roomItem.Status),
  584. User: &gameproto.User{UserID: uint32(playerItem.ID), Name: playerItem.Name, Img: playerItem.HeadImg},
  585. RoomDetail: &roomDetail,
  586. })
  587. return nil
  588. }
  589. func (p *Game) CreateRoom(playerID int32, roomType int32, passwd, name string, baseAmount int) (*Room, error) {
  590. if roomType != int32(model.RoomTypeFree) && roomType != int32(model.RoomTypeNormal) {
  591. return nil, errors.New("参数错误,房间类型不对")
  592. }
  593. if len(passwd) < 3 {
  594. return nil, errors.New("参数错误,密码长度不能少于3")
  595. }
  596. p.locker.Lock()
  597. defer p.locker.Unlock()
  598. p.EventInfo(playerID, "创建房间", "开始")
  599. baseAmountDecimal := decimal.NewFromInt(int64(baseAmount))
  600. playerItem := p.PlayerMap[playerID]
  601. roomID := len(p.RoomMap) + 1
  602. if playerItem.Balance.LessThan(baseAmountDecimal) {
  603. p.EventInfo(playerID, "创建房间", fmt.Sprintf("余额小于房间准入金额, %v-%v", playerItem.Balance, baseAmountDecimal))
  604. return nil, errors.New("参数错误,余额小于房间准入金额")
  605. }
  606. room := Room{
  607. ID: int32(roomID),
  608. RoomType: roomType,
  609. Name: name,
  610. Passwd: passwd,
  611. ChairList: make([]Chair, 5),
  612. BaseAmount: baseAmountDecimal,
  613. Status: RoomStatusWaitReady,
  614. StatusStartTime: 0,
  615. ReadyCh: make(chan bool),
  616. ChooseMasterCh: make(chan bool),
  617. ChooseMulCh: make(chan bool),
  618. OpenCh: make(chan bool),
  619. }
  620. chairList := make([]Chair, 0)
  621. for i := 0; i < 5; i++ {
  622. chairList = append(chairList, Chair{
  623. ID: int32(i),
  624. PlayerID: 0,
  625. })
  626. }
  627. copy(room.ChairList, chairList)
  628. p.RoomMap[int32(roomID)] = room
  629. p.EventInfo(playerID, "创建房间", "通知创建房间成功")
  630. //通知
  631. nxd.SendMsgToAllUserK(gameproto.NotifyTypeEnum_NotifyTypeCreateRoom, &gameproto.CreateRoom{
  632. ID: uint32(room.ID),
  633. CreatorID: uint32(playerID),
  634. Name: room.Name,
  635. NeedPwd: passwd != "",
  636. RoomType: gameproto.RoomType(room.RoomType),
  637. BaseAmount: float64(room.BaseAmount.Mul(decimal.NewFromInt(100)).IntPart()) / 100,
  638. ChairUserID1: 0,
  639. ChairUserID2: 0,
  640. ChairUserID3: 0,
  641. ChairUserID4: 0,
  642. ChairUserID5: 0,
  643. })
  644. p.EventInfo(playerID, "创建房间", "选择桌子")
  645. err := p.ChooseChairNoLock(playerID, int32(roomID), 0, passwd)
  646. if err != nil {
  647. logrus.Error(err)
  648. return nil, err
  649. }
  650. return &room, nil
  651. }
  652. func (p *Game) Ready(playerID int32) error {
  653. p.locker.Lock()
  654. defer p.locker.Unlock()
  655. playerItem := p.PlayerMap[playerID]
  656. if playerItem.RoomID == RoomIDEmpty {
  657. p.EventInfo(playerID, "准备", "用户不在房间")
  658. return errors.New("没进入房间")
  659. }
  660. if playerItem.Status != PlayerStatusWaitReady {
  661. p.EventInfo(playerID, "准备", fmt.Sprintf("用户状态不对:%d", playerItem.Status))
  662. return errors.New("状态不对")
  663. }
  664. roomItem := p.RoomMap[playerItem.RoomID]
  665. if roomItem.Status != RoomStatusWaitReady && roomItem.Status != RoomStatusReady {
  666. p.EventInfo(playerID, "准备", fmt.Sprintf("房间状态不对:%d", roomItem.Status))
  667. return errors.New("房间状态不对")
  668. }
  669. playerItem.Status = PlayerStatusReady
  670. p.PlayerMap[playerID] = playerItem
  671. //通知
  672. userIDList, err := p.getRoomUserIDList(roomItem.ID)
  673. if err != nil {
  674. logrus.Error(err)
  675. return err
  676. }
  677. p.EventInfo(playerID, "准备", "通知房间用户,已经准备好")
  678. nxd.SendMsgToUserList(userIDList, gameproto.NotifyTypeEnum_NotifyTypeReady, &gameproto.Ready{
  679. RoomID: uint32(roomItem.ID),
  680. UserID: uint32(playerID),
  681. })
  682. readyUserCount := 0
  683. allReady := true
  684. for _, chairItem := range roomItem.ChairList {
  685. if chairItem.PlayerID == 0 {
  686. continue
  687. }
  688. chairPlayer := p.PlayerMap[chairItem.PlayerID]
  689. if chairPlayer.Status != PlayerStatusReady && chairPlayer.Status != PlayerStatusWaitReady {
  690. logrus.Panicf("-状态不对:%d", chairPlayer.Status)
  691. }
  692. if chairPlayer.Status != PlayerStatusReady {
  693. allReady = false
  694. continue
  695. }
  696. readyUserCount++
  697. }
  698. if readyUserCount <= 1 {
  699. p.EventInfo(playerID, "准备", "已经准备的用户<=1")
  700. return nil
  701. }
  702. //两个人以上的情况,判断是否全部准备好
  703. if allReady {
  704. p.EventInfo(playerID, "准备", "全部准备好,发送通知")
  705. go func() {
  706. defer func() {
  707. recover()
  708. }()
  709. roomItem.ReadyCh <- true
  710. }()
  711. }
  712. if roomItem.Status == RoomStatusReady {
  713. p.EventInfo(playerID, "准备", "房间已经是准备状态")
  714. return nil
  715. }
  716. //有两个玩家等待,房间状态切换为准备状态,不能取消了
  717. issue := genIssue(playerItem.RoomID)
  718. chairID, err := p.getChairID(playerID, roomItem)
  719. if err != nil {
  720. logrus.Error(err)
  721. return err
  722. }
  723. roomItem.Issue = issue
  724. roomItem.Status = RoomStatusReady
  725. roomItem.StatusStartTime = time.Now().Unix()
  726. p.RoomMap[playerItem.RoomID] = roomItem
  727. p.EventInfo(playerID, "准备", "开始游戏,期号:"+issue)
  728. nxd.SendMsgToUserList(userIDList, gameproto.NotifyTypeEnum_NotifyTypeWaitReady, &gameproto.WaitReady{
  729. RoomID: uint32(roomItem.ID),
  730. Issue: issue,
  731. })
  732. go func() {
  733. defer func() {
  734. if err := recover(); err != nil {
  735. logrus.Error(err)
  736. fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
  737. }
  738. }()
  739. p.locker.Lock()
  740. {
  741. p.EventInfo(playerID, "准备", fmt.Sprintf("等待房间准备:%d", roomItem.ID))
  742. }
  743. p.locker.Unlock()
  744. p.WaitReady(roomItem)
  745. func() {
  746. //TODO: 优化并发
  747. p.locker.Lock()
  748. defer p.locker.Unlock()
  749. p.EventInfo(playerID, "准备", "等待房间完毕")
  750. //切换为准备完毕,限制进入了
  751. roomItem.Status = RoomStatusChooseMaster
  752. roomItem.StatusStartTime = time.Now().Unix()
  753. p.RoomMap[roomItem.ID] = roomItem
  754. //已经准备好的用户,生成牌
  755. userIDList, err = p.getRoomUserIDListWithStatus(roomItem.ID, PlayerStatusReady)
  756. if err != nil {
  757. logrus.Error(err)
  758. return
  759. }
  760. err = db.GetDB().Transaction(func(tx *gorm.DB) error {
  761. for _, userID := range userIDList {
  762. openNumCardList := getOpenNumList(issue, roomItem.ID, chairID)
  763. openNumCardStrList := make([]string, 0)
  764. for _, item := range openNumCardList {
  765. cardNum := item.Num + 13*(item.Suit-1)
  766. openNumCardStrList = append(openNumCardStrList, fmt.Sprintf("%d", cardNum))
  767. }
  768. userItem := p.PlayerMap[userID]
  769. userItem.CardList = CardList2NNCardList(openNumCardList)
  770. p.PlayerMap[userID] = userItem
  771. gameOrderModel := model.GameOrder{
  772. UserID: uint(userID),
  773. RoomID: uint(roomItem.ID),
  774. Issue: issue,
  775. OpenNumber: strings.Join(openNumCardStrList, ","),
  776. BaseAmount: roomItem.BaseAmount,
  777. IsDraw: 0,
  778. DrawTime: nil,
  779. IsMaster: 0,
  780. MasterMul: 0,
  781. Mul: 1,
  782. IsWin: 0,
  783. WinAmount: decimal.NewFromInt(0),
  784. BetIP: "",
  785. GameID: 1,
  786. }
  787. err = tx.Model(gameOrderModel).Create(&gameOrderModel).Error
  788. if err != nil {
  789. logrus.Error(err)
  790. return err
  791. }
  792. }
  793. p.EventInfo(playerID, "准备", "生成订单成功")
  794. return nil
  795. })
  796. if err != nil {
  797. logrus.Error(err)
  798. return
  799. }
  800. }()
  801. p.Run(allReady, roomItem, issue)
  802. }()
  803. return nil
  804. }
  805. func (p *Game) UnReady(playerID int32) error {
  806. p.locker.Lock()
  807. defer p.locker.Unlock()
  808. playerItem := p.PlayerMap[playerID]
  809. if playerItem.RoomID == RoomIDEmpty {
  810. return errors.New("没进入房间")
  811. }
  812. if playerItem.Status != PlayerStatusReady {
  813. return errors.New("状态不对")
  814. }
  815. roomItem := p.RoomMap[playerItem.RoomID]
  816. if roomItem.Status != RoomStatusWaitReady {
  817. return errors.New("状态不对")
  818. }
  819. readyUserCount := 0
  820. for _, chairItem := range roomItem.ChairList {
  821. if chairItem.PlayerID == 0 {
  822. continue
  823. }
  824. chairPlayer := p.PlayerMap[chairItem.PlayerID]
  825. if chairPlayer.Status != PlayerStatusReady {
  826. continue
  827. }
  828. readyUserCount++
  829. }
  830. //设置用户
  831. playerItem.Status = PlayerStatusWaitReady
  832. p.PlayerMap[playerID] = playerItem
  833. //通知
  834. userIDList, err := p.getRoomUserIDList(roomItem.ID)
  835. if err != nil {
  836. logrus.Error(err)
  837. return err
  838. }
  839. nxd.SendMsgToUserList(userIDList, gameproto.NotifyTypeEnum_NotifyTypeUnReady, &gameproto.UnReady{
  840. RoomID: uint32(roomItem.ID),
  841. UserID: uint32(playerID),
  842. })
  843. return nil
  844. }
  845. func (p *Game) ChooseMaster(playerID int32, mul int32) error {
  846. p.locker.Lock()
  847. defer p.locker.Unlock()
  848. playerItem := p.PlayerMap[playerID]
  849. if playerItem.RoomID == RoomIDEmpty {
  850. return errors.New("没进入房间")
  851. }
  852. if playerItem.Status != PlayerStatusReady {
  853. return errors.New("状态不对")
  854. }
  855. roomItem := p.RoomMap[playerItem.RoomID]
  856. if roomItem.Status != RoomStatusChooseMaster {
  857. return errors.New("状态不对")
  858. }
  859. //更新用户信息
  860. playerItem.Status = PlayerStatusChooseMaster
  861. playerItem.MasterMul = int(mul)
  862. p.PlayerMap[playerID] = playerItem
  863. allChoose := true
  864. for _, chairItem := range roomItem.ChairList {
  865. if chairItem.PlayerID == 0 {
  866. continue
  867. }
  868. chairPlayer := p.PlayerMap[chairItem.PlayerID]
  869. if chairPlayer.Status == PlayerStatusReady {
  870. allChoose = false
  871. break
  872. }
  873. }
  874. err := db.GetDB().Model(model.GameOrder{}).Where("user_id = ? and issue = ?", playerID, roomItem.Issue).Update("master_mul", mul).Error
  875. if err != nil {
  876. logrus.Error(err)
  877. return err
  878. }
  879. //通知
  880. userIDList, err := p.getRoomUserIDList(roomItem.ID)
  881. if err != nil {
  882. logrus.Error(err)
  883. return err
  884. }
  885. for _, userID := range userIDList {
  886. nxd.SendMsgToUserK(uint32(userID), gameproto.NotifyTypeEnum_NotifyTypeChooseMaster, &gameproto.ChooseMaster{
  887. UserID: uint32(playerID),
  888. Mul: uint32(mul),
  889. RoomID: uint32(roomItem.ID),
  890. })
  891. }
  892. //全部选完,就进入下一阶段
  893. if allChoose {
  894. go func() {
  895. defer func() {
  896. recover()
  897. }()
  898. roomItem.ChooseMasterCh <- true
  899. }()
  900. }
  901. return nil
  902. }
  903. func (p *Game) ChooseMul(playerID int32, mul int32) error {
  904. p.locker.Lock()
  905. defer p.locker.Unlock()
  906. playerItem := p.PlayerMap[playerID]
  907. if playerItem.RoomID == RoomIDEmpty {
  908. return errors.New("没进入房间")
  909. }
  910. if playerItem.Status != PlayerStatusChooseMaster {
  911. return errors.New("状态不对")
  912. }
  913. roomItem := p.RoomMap[playerItem.RoomID]
  914. if roomItem.Status != RoomStatusChooseMul {
  915. return errors.New("状态不对")
  916. }
  917. //更新用户
  918. playerItem.Status = PlayerStatusChooseMul
  919. playerItem.Mul = int(mul)
  920. p.PlayerMap[playerID] = playerItem
  921. allChoose := true
  922. for _, chairItem := range roomItem.ChairList {
  923. if chairItem.PlayerID == 0 {
  924. continue
  925. }
  926. chairPlayer := p.PlayerMap[chairItem.PlayerID]
  927. if chairPlayer.Status == PlayerStatusChooseMaster {
  928. allChoose = false
  929. break
  930. }
  931. }
  932. err := db.GetDB().Model(model.GameOrder{}).Where("user_id = ? and issue = ?", playerID, roomItem.Issue).Update("mul", mul).Error
  933. if err != nil {
  934. logrus.Error(err)
  935. return err
  936. }
  937. //通知
  938. userIDList, err := p.getRoomUserIDList(roomItem.ID)
  939. if err != nil {
  940. logrus.Error(err)
  941. return err
  942. }
  943. for _, sendToUserID := range userIDList {
  944. var cardList []uint32
  945. if playerID == sendToUserID {
  946. cardList = GetNNCardList(playerItem.CardList)
  947. }
  948. nxd.SendMsgToUserK(uint32(sendToUserID), gameproto.NotifyTypeEnum_NotifyTypeChooseMul, &gameproto.ChooseMul{
  949. UserID: uint32(playerID),
  950. Mul: uint32(mul),
  951. RoomID: uint32(roomItem.ID),
  952. CardList: cardList,
  953. })
  954. }
  955. //全部选完,就进入下一阶段
  956. if allChoose {
  957. go func() {
  958. defer func() {
  959. recover()
  960. }()
  961. roomItem.ChooseMulCh <- true
  962. }()
  963. }
  964. return nil
  965. }
  966. func (p *Game) OpenCard(playerID int32) error {
  967. p.locker.Lock()
  968. defer p.locker.Unlock()
  969. playerItem := p.PlayerMap[playerID]
  970. if playerItem.RoomID == RoomIDEmpty {
  971. return errors.New("没进入房间")
  972. }
  973. if playerItem.Status != PlayerStatusChooseMul {
  974. return errors.New("状态不对")
  975. }
  976. roomItem := p.RoomMap[playerItem.RoomID]
  977. if roomItem.Status != RoomStatusOpen {
  978. return errors.New("状态不对")
  979. }
  980. userIDList, err := p.getRoomUserIDList(roomItem.ID)
  981. if err != nil {
  982. logrus.Error(err)
  983. return err
  984. }
  985. nxd.SendMsgToUserList(userIDList, gameproto.NotifyTypeEnum_NotifyTypeOpen, &gameproto.Open{
  986. RoomID: uint32(roomItem.ID),
  987. UserID: uint32(playerID),
  988. CardList: GetNNCardList(playerItem.CardList),
  989. })
  990. //更新用户
  991. playerItem.Status = PlayerStatusOpen
  992. p.PlayerMap[playerID] = playerItem
  993. allOpen := true
  994. for _, chairItem := range roomItem.ChairList {
  995. if chairItem.PlayerID == 0 {
  996. continue
  997. }
  998. chairPlayer := p.PlayerMap[chairItem.PlayerID]
  999. if chairPlayer.Status == PlayerStatusChooseMul {
  1000. allOpen = false
  1001. break
  1002. }
  1003. }
  1004. //全部选完,就进入下一阶段
  1005. if allOpen {
  1006. go func() {
  1007. defer func() {
  1008. recover()
  1009. }()
  1010. roomItem.OpenCh <- true
  1011. }()
  1012. }
  1013. return nil
  1014. }
  1015. func (p *Game) getUserRoomID(playerID int32) (*Room, int32, error) {
  1016. for _, roomItem := range p.RoomMap {
  1017. for _, chairItem := range roomItem.ChairList {
  1018. if chairItem.PlayerID != playerID {
  1019. continue
  1020. }
  1021. return &roomItem, chairItem.ID, nil
  1022. }
  1023. }
  1024. return nil, 0, ErrNotFound
  1025. }
  1026. func (p *Game) getChairID(playerID int32, room Room) (int32, error) {
  1027. for i, chairID := range room.ChairList {
  1028. if playerID == chairID.PlayerID {
  1029. return int32(i), nil
  1030. }
  1031. }
  1032. return 0, ErrNotFound
  1033. }
  1034. func (p *Game) GetLogNoLock(playerID int32) ([]Room, []Player, int64) {
  1035. roomList := make([]Room, 0)
  1036. playerList := make([]Player, 0)
  1037. for _, roomItem := range p.RoomMap {
  1038. roomList = append(roomList, roomItem)
  1039. found := false
  1040. for _, chairItem := range roomItem.ChairList {
  1041. if chairItem.PlayerID != playerID {
  1042. continue
  1043. }
  1044. found = true
  1045. break
  1046. }
  1047. if !found {
  1048. continue
  1049. }
  1050. for _, chairItem := range roomItem.ChairList {
  1051. if chairItem.PlayerID == 0 {
  1052. continue
  1053. }
  1054. player := p.PlayerMap[chairItem.PlayerID]
  1055. playerList = append(playerList, player)
  1056. }
  1057. }
  1058. return roomList, playerList, p.LogID
  1059. }
  1060. func genIssue(roomID int32) string {
  1061. return fmt.Sprintf("%d-%d", roomID, time.Now().Unix())
  1062. }
  1063. var cardCache = cache.New(10*time.Minute, 20*time.Minute)
  1064. func getOpenNumList(issue string, roomID, chairID int32) []Card {
  1065. currActiveCard, exists := cardCache.Get(issue)
  1066. var cardMap map[int]int
  1067. if !exists {
  1068. cardMap = map[int]int{}
  1069. for i := 1; i <= 52; i++ {
  1070. cardMap[i] = 1
  1071. }
  1072. cardCache.Set(issue, cardMap, cache.DefaultExpiration)
  1073. } else {
  1074. cardMap = currActiveCard.(map[int]int)
  1075. }
  1076. count := 0
  1077. cardList := make([]Card, 0)
  1078. for {
  1079. key := rand.Intn(52) + 1
  1080. if cardMap[key] == -1 {
  1081. continue
  1082. }
  1083. cardList = append(cardList, Card{
  1084. Suit: (key-1)/13 + 1,
  1085. Num: (key-1)%13 + 1,
  1086. })
  1087. cardMap[key] = -1
  1088. count++
  1089. if count == 5 {
  1090. break
  1091. }
  1092. }
  1093. cardCache.Set(issue, cardMap, cache.DefaultExpiration)
  1094. return cardList
  1095. }