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 func() { { userIDList, _ := p.getRoomUserIDList(room.ID) for _, userID := range userIDList { playerItem, exists := p.PlayerMap[userID] if !exists { continue } p.EventInfo(userID, "Run", fmt.Sprintf("执行完毕,状态:%d", playerItem.Status)) if playerItem.Status != PlayerStatusWaitReady { logrus.Panicf("完成,但状态不对:%d-%d", userID, playerItem.Status) } } for _, userID := range userIDList { if UserIsOnline(uint(userID)) { continue } p.EventInfo(userID, "Run", "玩家离线,踢走") p.Leave(userID, false) } } 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), }) } 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())) } }() payoutInfoList, err := p.payout(tx, room.BaseAmount, room.ID) if err != nil { return err } for _, payoutInfo := range payoutInfoList { userID := payoutInfo.PlayerID winAmount := payoutInfo.Amount userItem, exists := p.PlayerMap[userID] if !exists { logrus.Fatal("not exist:", userID) continue } beforeUserModel := model.User{} err := tx.Model(model.User{}).Where("id = ?", userID).First(&beforeUserModel).Error if err != nil { return err } if room.RoomType == int32(model.RoomTypeFree) { 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", payoutInfo.Amount, userID, userID, payoutInfo.Amount).Error if err != nil { logrus.Error(err) return err } afterUserModel := model.User{} err = tx.Model(model.User{}).Where("id = ?", userID).First(&afterUserModel).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": payoutInfo.Amount.GreaterThan(decimal.Zero), "win_amount": payoutInfo.Amount, "before_amount": beforeUserModel.Credits.Add(beforeUserModel.CreditsQZNN), "after_amount": afterUserModel.Credits, }).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.Credits = currUserModel.Credits p.PlayerMap[userID] = userItem //设置结算信息 userCredist, _ := userItem.Credits.Round(2).Float64() msg.PayoutInfoList = append(msg.PayoutInfoList, &gameproto.PayoutInfo{ UserID: uint32(userID), WinAmount: winAmount.StringFixed(2), IsMaster: payoutInfo.IsMaster, Credits: userCredist, }) } else { 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", payoutInfo.Amount, userID, userID, payoutInfo.Amount).Error if err != nil { logrus.Error(err) return err } afterUserModel := model.User{} err = tx.Model(model.User{}).Where("id = ?", userID).First(&afterUserModel).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": payoutInfo.Amount.GreaterThan(decimal.Zero), "win_amount": payoutInfo.Amount, "before_amount": beforeUserModel.Balance.Add(beforeUserModel.BalanceQZNN), "after_amount": afterUserModel.Balance, }).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: winAmount.StringFixed(2), IsMaster: payoutInfo.IsMaster, Balance: userBalance, }) } } return nil }) if err != nil { logrus.Error(err, "===============") return err } roomUserIDList, _ = p.getRoomUserIDList(room.ID) //更新一下用户信息 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.Credits = userModel.Credits 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) //判断是否满足准入,不满足,踢走 for _, userID := range roomUserIDList { userItem := p.PlayerMap[userID] if room.RoomType == int32(model.RoomTypeNormal) { if userItem.Balance.LessThan(decimal.NewFromInt(10)) { p.LeaveRoomInner(userID, false) } } else { p.LeaveRoomInner(userID, false) } } 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 }