123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- package qznn
- import (
- "errors"
- "fmt"
- "math/rand"
- "runtime/debug"
- "time"
- "github.com/shopspring/decimal"
- "github.com/sirupsen/logrus"
- "gogs.daxia.dev/huanan/pkg.daxia.dev/db"
- "gorm.io/gorm"
- "nn.daxia.dev/gameproto"
- "nn.daxia.dev/model"
- "nn.daxia.dev/nxd"
- )
- func (p *Game) WaitReady(room Room) error {
- select {
- case <-room.ReadyCh:
- //
- case <-time.After(5 * time.Second):
- //
- }
- return nil
- }
- func (p *Game) WaitChooseMaster(room Room) error {
- select {
- case <-room.ChooseMasterCh:
- //
- case <-time.After(7 * time.Second):
- //
- }
- p.locker.Lock()
- defer p.locker.Unlock()
- roomUserIDList, err := p.getRoomUserIDList(room.ID)
- if err != nil {
- logrus.Error(err)
- return err
- }
- //设置状态
- userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusReady)
- if err != nil {
- logrus.Error(err)
- return err
- }
- for _, userID := range userIDList {
- userItem := p.PlayerMap[userID]
- userItem.Status = PlayerStatusChooseMaster
- userItem.MasterMul = 0
- p.PlayerMap[userID] = userItem
- p.EventInfo(userID, "选庄", "通知默认不抢")
- nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMaster, &gameproto.ChooseMaster{
- UserID: uint32(userID),
- Mul: uint32(0),
- RoomID: uint32(room.ID),
- })
- }
- //获取修正后的状态用户
- userIDList, err = p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMaster)
- if err != nil {
- logrus.Error(err)
- return err
- }
- maxMasterMul := 0
- for _, userID := range userIDList {
- userItem := p.PlayerMap[userID]
- if userItem.MasterMul > maxMasterMul {
- maxMasterMul = userItem.MasterMul
- }
- }
- masterIDList := make([]int32, 0)
- for _, userID := range userIDList {
- userItem := p.PlayerMap[userID]
- if userItem.MasterMul != maxMasterMul {
- continue
- }
- masterIDList = append(masterIDList, userID)
- }
- //更新用户,选取庄家
- index := rand.Intn(len(masterIDList))
- masterUserID := masterIDList[index]
- p.EventInfo(masterUserID, "选庄", "选为庄家")
- userItem := p.PlayerMap[masterUserID]
- userItem.IsMaster = true
- if userItem.MasterMul == 0 {
- userItem.MasterMul = 1
- }
- p.PlayerMap[masterUserID] = userItem
- //更新
- err = db.GetDB().Model(model.GameOrder{}).Where("user_id = ? and issue = ?", masterUserID, room.Issue).Update("is_master", 1).Error
- if err != nil {
- logrus.Error(err)
- return err
- }
- //通知
- nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMasterFinish, &gameproto.ChooseMasterFinish{
- MasterUserID: uint32(masterUserID),
- MulList: []uint32{1, 4, 8, 11, 15},
- RoomID: uint32(room.ID),
- })
- return nil
- }
- func (p *Game) WaitChooseMul(room Room) error {
- p.locker.Lock()
- {
- room.Status = RoomStatusChooseMul
- room.StatusStartTime = time.Now().Unix()
- p.RoomMap[room.ID] = room
- }
- //master直接发送,跳过开牌流程
- userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMaster)
- if err != nil {
- logrus.Error(err)
- //FOCUS:UnLock
- p.locker.Unlock()
- return err
- }
- //master提前发送
- for _, userID := range userIDList {
- userItem, exists := p.PlayerMap[userID]
- if !exists {
- logrus.Error("not exist:", userID)
- continue
- }
- if !userItem.IsMaster {
- continue
- }
- userItem.Status = PlayerStatusChooseMul
- userItem.Mul = 1
- p.PlayerMap[userID] = userItem
- p.EventInfo(userID, "选倍数", "庄家默认倍数1")
- nxd.SendMsgToUserK(uint32(userID), gameproto.NotifyTypeEnum_NotifyTypeChooseMul, &gameproto.ChooseMul{
- UserID: uint32(userID),
- Mul: uint32(1),
- RoomID: uint32(room.ID),
- CardList: GetNNCardList(userItem.CardList),
- })
- break
- }
- p.locker.Unlock()
- logrus.Infof("等待选择倍数")
- select {
- case <-room.ChooseMulCh:
- //
- case <-time.After(7 * time.Second):
- //
- }
- p.locker.Lock()
- defer p.locker.Unlock()
- roomUserIDList, err := p.getRoomUserIDList(room.ID)
- if err != nil {
- logrus.Error(err)
- return err
- }
- logrus.Infof("未选取的用户,开始自动选取")
- for _, userID := range roomUserIDList {
- userItem, exists := p.PlayerMap[userID]
- if !exists {
- logrus.Error("not exist:", userID)
- continue
- }
- if userItem.Status != PlayerStatusChooseMaster {
- continue
- }
- userItem.Status = PlayerStatusChooseMul
- userItem.Mul = 1
- p.PlayerMap[userID] = userItem
- p.EventInfo(userID, "选倍数", "默认倍数1")
- //通知
- for _, sendToUserID := range roomUserIDList {
- var cardList []uint32
- if userID == sendToUserID {
- cardList = GetNNCardList(userItem.CardList)
- }
- nxd.SendMsgToUserK(uint32(sendToUserID), gameproto.NotifyTypeEnum_NotifyTypeChooseMul, &gameproto.ChooseMul{
- UserID: uint32(userID),
- Mul: uint32(1),
- RoomID: uint32(room.ID),
- CardList: cardList,
- })
- }
- }
- logrus.Infof("通知选择倍数完成, 用户数:%d", len(roomUserIDList))
- //通知
- nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeChooseMulFinish, &gameproto.ChooseMulFinish{
- RoomID: uint32(room.ID),
- })
- return nil
- }
- func (p *Game) WaitOpen(room Room) error {
- p.locker.Lock()
- {
- room.Status = RoomStatusOpen
- room.StatusStartTime = time.Now().Unix()
- p.RoomMap[room.ID] = room
- }
- p.locker.Unlock()
- select {
- case <-room.OpenCh:
- //
- case <-time.After(15 * time.Second):
- //
- }
- p.locker.Lock()
- defer p.locker.Unlock()
- roomUserIDList, err := p.getRoomUserIDList(room.ID)
- if err != nil {
- logrus.Error(err)
- return err
- }
- userIDList, err := p.getRoomUserIDListWithStatus(room.ID, PlayerStatusChooseMul)
- if err != nil {
- logrus.Error(err)
- return err
- }
- for _, userID := range userIDList {
- userItem, exists := p.PlayerMap[userID]
- if !exists {
- logrus.Error("not exist:", userID)
- continue
- }
- userItem.Status = PlayerStatusOpen
- p.PlayerMap[userID] = userItem
- p.EventInfo(userID, "开牌", "默认开牌")
- //通知
- nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpen, &gameproto.Open{
- RoomID: uint32(room.ID),
- UserID: uint32(userID),
- CardList: GetNNCardList(userItem.CardList),
- })
- }
- userIDList, err = p.getRoomUserIDListWithStatus(room.ID, PlayerStatusOpen)
- if err != nil {
- logrus.Error(err)
- return err
- }
- //获取庄家的牌
- var masterPlayerItem Player
- for _, userID := range userIDList {
- playerItem := p.PlayerMap[userID]
- if !playerItem.IsMaster {
- continue
- }
- masterPlayerItem = playerItem
- break
- }
- masterCardList := GetNNCardList(masterPlayerItem.CardList)
- masterTotalWinAmount := decimal.NewFromInt(0)
- timeNow := time.Now()
- msg := &gameproto.OpenFinish{
- RoomID: uint32(room.ID),
- PayoutInfoList: []*gameproto.PayoutInfo{},
- }
- err = db.GetDB().Transaction(func(tx *gorm.DB) error {
- defer func() {
- if err := recover(); err != nil {
- logrus.Error(err)
- fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
- }
- }()
- for _, userID := range userIDList {
- if userID == masterPlayerItem.ID {
- continue
- }
- userItem, exists := p.PlayerMap[userID]
- if !exists {
- logrus.Error("not exist:", userID)
- continue
- }
- var isWin bool
- var winAmount decimal.Decimal
- userCardList := GetNNCardList(userItem.CardList)
- masterWin, isEqual, cardLevel := WinLevel(masterCardList, userCardList)
- if !masterWin {
- _, _, cardLevel = WinLevel(userCardList, masterCardList)
- }
- if isEqual {
- isWin = false
- winAmount = decimal.NewFromInt(0)
- } else {
- if !masterWin {
- isWin = true
- //赢庄家
- winAmount = room.BaseAmount.Mul(decimal.NewFromInt(int64(masterPlayerItem.MasterMul))).Mul(decimal.NewFromInt(int64(userItem.Mul))).Mul(decimal.NewFromInt(int64(cardLevel)))
- } else {
- isWin = false
- //输给庄家
- winAmount = room.BaseAmount.Mul(decimal.NewFromInt(int64(masterPlayerItem.MasterMul))).Mul(decimal.NewFromInt(int64(userItem.Mul))).Mul(decimal.NewFromInt(-1)).Mul(decimal.NewFromInt(int64(cardLevel)))
- }
- }
- err = tx.Model(model.User{}).Where("id = ? and balance + ? > 0", userID, winAmount).
- Update("balance", gorm.Expr("balance + ?", winAmount)).Error
- if err != nil {
- return err
- }
- //设置注单
- err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, userID).Updates(map[string]interface{}{
- "is_draw": 1,
- "draw_time": &timeNow,
- "is_win": isWin,
- "win_amount": winAmount,
- }).Error
- if err != nil {
- return err
- }
- currUserModel := model.User{}
- err = tx.Model(model.User{}).Where("id = ?", userID).First(&currUserModel).Error
- if err != nil {
- return err
- }
- userItem.Balance = currUserModel.Balance
- p.PlayerMap[userID] = userItem
- //设置结算信息
- userBalance, _ := userItem.Balance.Round(2).Float64()
- msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
- UserID: uint32(userID),
- WinAmount: float32(winAmount.Mul(decimal.NewFromInt(100)).IntPart()) / 100,
- IsMaster: false,
- Balance: userBalance,
- })
- masterTotalWinAmount = masterTotalWinAmount.Add(winAmount.Mul(decimal.NewFromInt(-1)))
- }
- err = tx.Model(model.User{}).Where("id = ? and balance + ? > 0", masterPlayerItem.ID, masterTotalWinAmount).
- Update("balance", gorm.Expr("balance + ?", masterTotalWinAmount)).Error
- if err != nil {
- logrus.Error(err)
- return err
- }
- err = tx.Model(model.GameOrder{}).Where("issue = ? and user_id = ?", room.Issue, masterPlayerItem.ID).Updates(map[string]interface{}{
- "is_draw": 1,
- "draw_time": &timeNow,
- "is_win": masterTotalWinAmount.GreaterThan(decimal.Zero),
- "win_amount": masterTotalWinAmount,
- }).Error
- //设置master结算信息,更新余额
- currUserModel := model.User{}
- err = tx.Model(model.User{}).Where("id = ?", masterPlayerItem.ID).First(&currUserModel).Error
- if err != nil {
- logrus.Error(err)
- return err
- }
- masterPlayerItem.Balance = currUserModel.Balance
- p.PlayerMap[masterPlayerItem.ID] = masterPlayerItem
- masterBalance, _ := masterPlayerItem.Balance.Round(2).Float64()
- msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{
- UserID: uint32(masterPlayerItem.ID),
- WinAmount: float32(masterTotalWinAmount.Mul(decimal.NewFromInt(100)).IntPart()) / 100,
- IsMaster: true,
- Balance: masterBalance,
- })
- return nil
- })
- if err != nil {
- logrus.Error(err, "===============")
- return err
- }
- //更新一下用户信息
- userModelList := make([]model.User, 0)
- err = db.GetDB().Model(model.User{}).Where("id in ?", roomUserIDList).Scan(&userModelList).Error
- if err != nil {
- logrus.Error(err)
- return err
- }
- if len(roomUserIDList) != len(userModelList) {
- logrus.Panicf("len(roomUserIDList) != len(userModelList), %d != %d, %v, %v",
- len(roomUserIDList), len(userModelList), roomUserIDList, userModelList)
- }
- for _, userID := range roomUserIDList {
- userItem := p.PlayerMap[userID]
- userItem.IsMaster = false
- userItem.Status = PlayerStatusWaitReady
- p.PlayerMap[userID] = userItem
- }
- for _, userModel := range userModelList {
- userID := int32(userModel.ID)
- userItem := p.PlayerMap[userID]
- userItem.Balance = userModel.Balance
- userItem.HeadImg = userModel.HeadImg
- userItem.Name = userModel.Name
- userItem.IsMaster = false
- userItem.Status = PlayerStatusWaitReady
- p.EventInfo(userID, "开牌", "更新用户状态为等待开牌")
- p.PlayerMap[userID] = userItem
- }
- room.Status = RoomStatusWaitReady
- room.StatusStartTime = time.Now().Unix()
- p.RoomMap[room.ID] = room
- //通知
- roomUserIDList, err = p.getRoomUserIDList(room.ID)
- if err != nil {
- logrus.Error(err)
- return err
- }
- nxd.SendMsgToUserList(roomUserIDList, gameproto.NotifyTypeEnum_NotifyTypeOpenFinish, msg)
- return nil
- }
- func (p *Game) getRoomUserIDListWithStatus(roomID int32, status PlayerStatus) ([]int32, error) {
- roomItem, exists := p.RoomMap[roomID]
- if !exists {
- return nil, errors.New("room not exists")
- }
- userIDList := make([]int32, 0)
- for _, chairItem := range roomItem.ChairList {
- if chairItem.PlayerID == 0 {
- continue
- }
- playerItem, exists := p.PlayerMap[chairItem.PlayerID]
- if !exists {
- continue
- }
- if playerItem.Status != status {
- continue
- }
- userIDList = append(userIDList, chairItem.PlayerID)
- }
- return userIDList, nil
- }
- func (p *Game) getRoomUserIDList(roomID int32) ([]int32, error) {
- roomItem, exists := p.RoomMap[roomID]
- if !exists {
- return nil, errors.New("room not exists")
- }
- userIDList := make([]int32, 0)
- for _, chairItem := range roomItem.ChairList {
- if chairItem.PlayerID == 0 {
- continue
- }
- userIDList = append(userIDList, chairItem.PlayerID)
- }
- return userIDList, nil
- }
|