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 } //清理新号,免得卡主 close(room.ReadyCh) close(room.ChooseMasterCh) close(room.ChooseMulCh) close(room.OpenCh) room.ReadyCh = make(chan bool) room.ChooseMasterCh = make(chan bool) room.ChooseMulCh = make(chan bool) room.OpenCh = make(chan bool) 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 }