1634 lines
55 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package room
import (
"game/common/baseroom"
"game/common/config/game"
"game/common/proto/pb"
"game/server/colorgame/config"
"game/server/colorgame/model"
"github.com/fox/fox/ksync"
"github.com/fox/fox/log"
"github.com/fox/fox/xrand"
"github.com/fox/fox/xtime"
"sort"
"sync"
)
func (rm *ColorRoom) setStatus(status pb.ColorGameStatus) {
rm.status = status
rm.statusTime = xtime.Now().TimestampMilli()
}
// 状态结束时间点,毫秒
func (rm *ColorRoom) endTimeStatus() int64 {
duration := int64(0)
switch rm.status {
case pb.ColorGameStatus_CGS_Start:
duration = rm.timingCfg.Start
case pb.ColorGameStatus_CGS_Betting:
duration = rm.timingCfg.Betting
case pb.ColorGameStatus_CGS_BetEnd:
duration = rm.timingCfg.EndBetting
case pb.ColorGameStatus_CGS_OpenThreeDice:
duration = rm.timingCfg.OpenThreeDice
case pb.ColorGameStatus_CGS_Settle:
duration = rm.timingCfg.Settle
}
return rm.statusTime + duration
}
// 游戏开始前更新配置
func (rm *ColorRoom) updateConfig() {
colorConfig := config.GetColorConfig()
rm.timingCfg = colorConfig.GameTiming
for _, cfg := range colorConfig.Rooms {
if rm.RoomType() == cfg.RoomType {
rm.roomCfg = cfg
break
}
}
}
// 游戏开始时展示每个区域的默认赔率
func (rm *ColorRoom) initEndBetAreaMul() {
rm.endBetAreaMul = rm.endBetAreaMul[0:0]
for pos := 0; pos < len(pb.ColorBetArea_name); pos++ {
prizeArea := pb.ColorPrizeArea_CPA_Single_0
var mul = rm.roomCfg.WinSingleColorMul[0]
switch pos / 6 {
case 1:
prizeArea = pb.ColorPrizeArea_CPA_Double
mul = rm.roomCfg.WinDoubleColorMul
case 2:
prizeArea = pb.ColorPrizeArea_CPA_Three
mul = rm.roomCfg.WinThreeColorMul
}
rm.endBetAreaMul = append(rm.endBetAreaMul, &pb.ColorBetAreaMul{
Area: pb.ColorBetArea(pos),
PrizeArea: prizeArea,
PrizeType: pb.ColorPrizeType_CPT_Normal,
Mul: mul[0].Mul / config.Hundred,
})
}
}
// 随机出某个奖励档位下的赔率数组,档位,赔率数组概率之和
func (rm *ColorRoom) randArrMul(area pb.ColorBetArea) (arrMul []*game.ColorMulRate, prizeArea pb.ColorPrizeArea, sumRate int) {
switch area / 6 {
case 0:
maxWeight := 0
for _, w := range rm.roomCfg.WinSingleColorWeight {
maxWeight += w
}
weight := xrand.RandRange[int](0, maxWeight)
for pos, w := range rm.roomCfg.WinSingleColorWeight {
if weight < w {
prizeArea = pb.ColorPrizeArea(pos)
arrMul = rm.roomCfg.WinSingleColorMul[pos]
break
}
weight -= w
}
case 1:
prizeArea = pb.ColorPrizeArea_CPA_Double
arrMul = rm.roomCfg.WinDoubleColorMul
case 2:
prizeArea = pb.ColorPrizeArea_CPA_Three
arrMul = rm.roomCfg.WinThreeColorMul
default:
log.Error("area:%v is not exist")
return
}
for _, mr := range arrMul {
sumRate += mr.Rate
}
return
}
// 下注结束后,更新每个区域的实际赔率
func (rm *ColorRoom) updateEndBetAreaMul() {
jackpotExist := false
for pos := range pb.ColorBetArea_name {
bam := rm.endBetAreaMul[pos]
arrMul, prizeArea, sumRate := rm.randArrMul(pb.ColorBetArea(pos))
bam.PrizeArea = prizeArea
bam.PrizeType = pb.ColorPrizeType_CPT_Normal
if prizeArea == pb.ColorPrizeArea_CPA_Single_2 {
// 在单色区域 命中三同色爆奖之后 再随jackpot概率
// 只会有一个区域有jackpot标签
if !jackpotExist && xrand.RandRange(0, config.RateBase) < rm.roomCfg.JackpotRate {
bam.Mul = 0
bam.PrizeType = pb.ColorPrizeType_CPT_Jackpot
jackpotExist = true
continue
}
}
mulPos := 0
rd := xrand.RandRange[int](0, sumRate)
for i, mr := range arrMul {
if rd < mr.Rate {
mulPos = i
}
rd -= mr.Rate
}
// 赔率数组里第一个是基础赔率,后面的都是爆奖赔率
if mulPos > 0 {
bam.PrizeType = pb.ColorPrizeType_CPT_Big
}
bam.Mul = arrMul[mulPos].Mul / config.Hundred
log.Debug(rm.Log("区域:%v 显示赔率:%v 奖励类型:%v 奖励档位:%v", bam.Area, bam.Mul, bam.PrizeType, bam.PrizeArea))
}
}
// 获取三个骰子指定颜色中了几个
func (rm *ColorRoom) getDiceColorCount(color []pb.ColorType, c pb.ColorType) (count int) {
for _, colorType := range color {
if colorType == c {
count++
}
}
return
}
// 获取投注区域的颜色
func (rm *ColorRoom) getAreaColor(area pb.ColorBetArea) (color pb.ColorType) {
switch area {
case pb.ColorBetArea_CBA_Yellow, pb.ColorBetArea_CBA_Yellow2, pb.ColorBetArea_CBA_Yellow3:
return pb.ColorType_CT_Yellow
case pb.ColorBetArea_CBA_White, pb.ColorBetArea_CBA_White2, pb.ColorBetArea_CBA_White3:
return pb.ColorType_CT_White
case pb.ColorBetArea_CBA_Pink, pb.ColorBetArea_CBA_Pink2, pb.ColorBetArea_CBA_Pink3:
return pb.ColorType_CT_Pink
case pb.ColorBetArea_CBA_Blue, pb.ColorBetArea_CBA_Blue2, pb.ColorBetArea_CBA_Blue3:
return pb.ColorType_CT_Blue
case pb.ColorBetArea_CBA_Red, pb.ColorBetArea_CBA_Red2, pb.ColorBetArea_CBA_Red3:
return pb.ColorType_CT_Red
case pb.ColorBetArea_CBA_Green, pb.ColorBetArea_CBA_Green2, pb.ColorBetArea_CBA_Green3:
return pb.ColorType_CT_Green
}
return
}
// 获取某个区域的实际中奖赔率
func (rm *ColorRoom) getAreaMul(area pb.ColorBetArea, prizeArea pb.ColorPrizeArea) (mul int64, prizeType pb.ColorPrizeType) {
bam := rm.endBetAreaMul[area]
// 奖励档位一样比如单黄投注区域显示双色爆奖赔率为9。此时开出双黄色则该投注区域赔率为9。
// 如果开出三黄色则赔率为CPA_Single_2的赔率组里的第1个赔率(基础赔率)
// 如果开出单黄色则赔率为CPA_Single_0的赔率组里的第1个赔率(基础赔率)
if bam.PrizeArea == prizeArea {
mul = bam.Mul
prizeType = bam.PrizeType
} else {
arr2Mul := make([][]*game.ColorMulRate, 0)
arr2Mul = append(arr2Mul, rm.roomCfg.WinSingleColorMul...)
arr2Mul = append(arr2Mul, rm.roomCfg.WinDoubleColorMul)
arr2Mul = append(arr2Mul, rm.roomCfg.WinThreeColorMul)
mul = arr2Mul[prizeArea][0].Mul
prizeType = pb.ColorPrizeType_CPT_Normal
}
return
}
// 检查投掷结果是否匹配某个下注区域
func (rm *ColorRoom) isWinInArea(color []pb.ColorType, area pb.ColorBetArea) (win bool, prizeArea pb.ColorPrizeArea) {
colorCount := rm.getDiceColorCount(color, rm.getAreaColor(area))
if colorCount == 0 {
return false, 0
}
// 单色投注区,查看开出几个该颜色
if area < pb.ColorBetArea_CBA_Yellow2 {
if colorCount == 1 {
return true, pb.ColorPrizeArea_CPA_Single_0
} else if colorCount == 2 {
return true, pb.ColorPrizeArea_CPA_Single_1
} else {
return true, pb.ColorPrizeArea_CPA_Single_2
}
} else if area < pb.ColorBetArea_CBA_Yellow3 {
if colorCount > 1 {
return true, pb.ColorPrizeArea_CPA_Double
}
} else {
if colorCount > 2 {
return true, pb.ColorPrizeArea_CPA_Three
}
}
return false, 0
}
// 开3个骰子并计算出赢钱区域及实际赔率
func (rm *ColorRoom) openDices() {
for i := 0; i < 3; i++ {
c := xrand.RandRange(int(pb.ColorType_CT_Yellow), int(pb.ColorType_CT_Green))
rm.ntfOpenThreeDice.Color = append(rm.ntfOpenThreeDice.Color, pb.ColorType(c))
}
rm.ntfOpenThreeDice.AniRouteIndex = 0
for _, area := range rm.endBetAreaMul {
isWin, prizeArea := rm.isWinInArea(rm.ntfOpenThreeDice.Color, area.Area)
mul, prizeType := rm.getAreaMul(area.Area, prizeArea)
if !isWin {
continue
}
rm.winBetAreaMul = append(rm.winBetAreaMul, &pb.ColorBetAreaMul{
Area: area.Area,
PrizeArea: prizeArea,
PrizeType: prizeType,
Mul: mul,
})
rm.ntfOpenThreeDice.WinArea = append(rm.ntfOpenThreeDice.WinArea, area.Area)
}
}
// 计算 下注区域中奖得分返回是否有jp奖jp奖位置中奖人数
func (rm *ColorRoom) CalculateJackpotScore() (pb.ColorBetArea, map[int64]int64) {
jackpotArea := pb.ColorBetArea(-1)
for _, winArea := range rm.winBetAreaMul {
if winArea.PrizeType != pb.ColorPrizeType_CPT_Jackpot {
continue
}
rm.RangePlayer(func(u baseroom.IPlayer) bool {
user := GetPlayer(u)
if user.totalBets[winArea.Area] > 0 {
rm.jackpotMgr.AddJpUser(user.ID, user.totalBets[winArea.Area])
}
return true
})
}
rm.jackpotUser, rm.jackpotValue = rm.jackpotMgr.WinJackpot()
log.Debug(rm.Log("本局是否中jackpot奖:%v, 玩家一起分走jackpot:%v, 当前jackpot值:%v", rm.jackpotValue > 0, rm.jackpotValue, rm.jackpotMgr.GetJackpot()))
return jackpotArea, rm.jackpotUser
}
// 计算 所有玩家的下注区域中奖得分
func (rm *ColorRoom) CalculateAllUserScore() {
// 赢钱会清空jackpot池
jpArea, userJackPot := rm.CalculateJackpotScore()
var jackpotUserName []string
rm.RangePlayer(func(u baseroom.IPlayer) bool {
user := GetPlayer(u)
if user.totalBet > 0 {
// 算分
jpScore := userJackPot[user.ID]
rm.CalculateUserScore(user, jpArea, jpScore)
if jpScore > 0 {
jackpotUserName = append(jackpotUserName, user.Nickname)
//rm.BroadHitJackpot(user, jpScore)
}
}
return true
})
}
// 计算 下注区域中奖得分
func (rm *ColorRoom) CalculateUserScore(user *ColorPlayer, jpArea pb.ColorBetArea, jpScore int64) {
msg := user.settleMsg
for _, winArea := range rm.winBetAreaMul {
win2 := int64(0) // 税前
gold := int64(0) // 税后
if user.totalBets[winArea.Area] <= 0 {
continue
}
if jpArea != winArea.Area {
odds := winArea.Mul
// 奖金计算公式 Payouts =( Odds * Bet ) * ( 1 + Bonus) + Bet odds 是倍率 Bonus是猜中幸运骰子 的加成
// 本区域赢未扣税 倍率是百分值所以计算时要除以100
win2 = (odds * user.totalBets[winArea.Area]) / 100
// 本区域赢扣税
gold = win2 * (100 - rm.roomCfg.Rate) / 100
// 算税()
msg.Tax += win2 - gold
// 加回投注本金
gold += user.totalBets[winArea.Area]
msg.TotalWin += gold
// 统计赢区的下注总额
msg.TotalWinBaseBet += user.totalBets[winArea.Area]
log.Debug(rm.UserLog(user.ID, "算分 odds:%v 投注区:%v 税前:%v 税后+本金:%v", odds, winArea.Area, win2, gold))
} else {
win2 = jpScore
// 本区域赢扣税
gold = jpScore * (100 - rm.roomCfg.Rate) / 100
// 算税()
msg.Tax += win2 - gold
// 加回投注本金
gold += user.totalBets[winArea.Area]
msg.TotalWin += gold
// 统计赢区的下注总额
msg.TotalWinBaseBet += user.totalBets[winArea.Area]
log.Debug(rm.UserLog(user.ID, "算分 jackpotValue 投注区:%v win2:%v Gold:%v", winArea.Area, win2, gold))
}
msg.UserAreaWin = append(msg.UserAreaWin, &pb.NtfColorSettle_UserBetAreaMul{
AreaMul: &pb.ColorBetAreaMul{
Area: winArea.Area,
PrizeType: winArea.PrizeType,
PrizeArea: winArea.PrizeArea,
Mul: winArea.Mul,
},
Bet: user.totalBets[winArea.Area],
Win: win2,
RealWin: gold,
})
}
}
// 和平台做结算
func (rm *ColorRoom) settle() {
//var allWinner []*pb.ColorPinoyLiveBigWinner
rm.CalculateAllUserScore()
wg := new(sync.WaitGroup)
rm.RangePlayer(func(u baseroom.IPlayer) bool {
wg.Add(1)
user := GetPlayer(u)
ksync.GoSafe(func() {
defer wg.Done()
if user.totalBet > 0 {
// 和平台做赢钱结算
//_, err := rm.TransInoutGameEnd(u, 0, u.SettleMsg.TotalWin, u.SettleMsg.Tax)
//if err != nil {
// log.Error(rm.Log(err.Error()))
//}
}
}, nil)
return true
})
wg.Wait()
//// 异步加钱完成后再执行后续的结算操作
//rm.Traverse(func(u *model.User) bool {
// msg := u.SettleMsg
// if msg == nil || msg.TotalWin < 1 {
// return true
// }
// winner := &pb.ColorPinoyLiveBigWinner{
// NickName: u.UserInetr.GetNike(),
// Avatar: u.UserInetr.GetHead(),
// WinChips: msg.TotalWin,
// AreaId: msg.UserRealWins,
// }
// allWinner = append(allWinner, winner)
// log.Debug(rm.LogEx(u, "赢钱:%v", winner.WinChips))
// return true
//})
//// 更新大客户
//rm.updateBigWinner(allWinner)
//// 更新路途
//rm.SetGameTrend()
}
// 更新大客户
func (rm *ColorRoom) updateBigUsers() {
if rm.status > pb.ColorGameStatus_CGS_Betting && rm.status < pb.ColorGameStatus_CGS_Settle {
rm.RangePlayer(func(u baseroom.IPlayer) bool {
user := GetPlayer(u)
rm.bigUsers = append(rm.bigUsers, &pb.ColorBigUser{
NickName: user.Nickname,
Avatar: user.AvatarUrl,
WinChips: user.totalBet,
AreaId: user.totalBets,
})
return true
})
} else if rm.status >= pb.ColorGameStatus_CGS_Settle {
rm.RangePlayer(func(u baseroom.IPlayer) bool {
user := GetPlayer(u)
bigUser := &pb.ColorBigUser{
NickName: user.Nickname,
Avatar: user.AvatarUrl,
WinChips: user.settleMsg.TotalWin,
}
for _, area := range user.settleMsg.UserAreaWin {
bigUser.AreaId = append(bigUser.AreaId, area.Win)
}
return true
})
}
sort.Slice(rm.bigUsers, func(i, j int) bool {
return rm.bigUsers[i].WinChips > rm.bigUsers[j].WinChips
})
if len(rm.bigUsers) > 6 {
rm.bigUsers = rm.bigUsers[0:6]
}
}
func (rm *ColorRoom) initGameTrend() [][]pb.ColorType {
return model.GetTrend()
}
// 更新路途 最多保存100局
func (rm *ColorRoom) updateGameTrend() {
rm.trend = append(rm.trend, []pb.ColorType{rm.ntfOpenThreeDice.Color[0], rm.ntfOpenThreeDice.Color[1], rm.ntfOpenThreeDice.Color[2]})
if len(rm.trend) > 100 {
rm.trend = rm.trend[len(rm.trend)-100 : len(rm.trend)]
}
model.SetTrend(rm.trend)
}
// 更新路途 最多保存100局
func (rm *ColorRoom) getNotifyTrend() *pb.NtfColorTrend {
ntf := &pb.NtfColorTrend{}
// 只计算30局的概率
maxCount := 30
partTrend := rm.trend
if len(rm.trend) > maxCount {
partTrend = rm.trend[len(rm.trend)-maxCount : len(rm.trend)]
}
for c := pb.ColorType_CT_Yellow; c <= pb.ColorType_CT_Green; c++ {
cnt := int32(0)
for _, colors := range partTrend {
for _, color := range colors {
if color == c {
cnt++
}
}
}
ntf.ColorRate = append(ntf.ColorRate, &pb.NtfColorTrend_ColorRate{
Color: c,
Rate: cnt * 10000 / 100,
})
}
return ntf
}
//
// import (
// "encoding/json"
// "fmt"
// "game/common/proto/pb"
// "github.com/fox/fox/ipb"
// "github.com/fox/fox/log"
// "sort"
// "sync"
// "time"
// )
//
// func (rm *ColorRoom) SceneUserSitDown(user *model.User) {
// _ = user
// rm.SendOnlinePlayerNum()
// }
//
// // CheckAndBet 检查并下注
// func (rm *ColorRoom) CheckAndBet(user *model.User, bets []*pb.ColorPinoyLiveBetReq) {
// if len(bets) == 0 {
// log.Error(rm.Log("玩家(%d) bets data err :%v ", bets))
// model.SendBetFailMessage(model.DataErr, user)
// return
// }
//
// betInfos := [config.BET_TYPE_NUM]int64{}
// betCountInfos := [config.BET_TYPE_NUM]int64{}
// totalBetAmount := int64(0)
// oneBetMessage := &pb.ColorPinoyLiveS2CRepetBet{}
// oneBetMessage.Uid = user.UserID
// oneBetMessage.BetInfo = []*pb.ColorPinoyLiveBetSuccessMessage{}
//
// if rm.GetGameStatus() != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveBetStatus {
// log.Error(rm.Log("玩家(%d) UndoBet data err GetGameStatus:%v,LastTimeBet:%v ", user.UserID, rm.GetGameStatus(), user.LastTimeBet))
// model.SendBetFailMessage(model.StatusError, user)
// return
// }
//
// for _, bet := range bets {
// // 判断下注下标和下注区域下标是否超出列表
// if _, ok := pb.ColorPinoyLiveBetTypeJP_name[int32(bet.BetType)]; !ok ||
// bet.BetLevel < 0 || bet.BetLevel >= int32(len(rm.RoomCfg.ColorPinoyLiveConfig.BetList)) ||
// bet.BetIndex < 0 || bet.BetIndex >= int32(len(rm.RoomCfg.ColorPinoyLiveConfig.BetList[bet.BetLevel])) {
// log.Error(rm.Log("玩家(%d) bets data err BetLevel:%d BetIndex:%d ", bet.BetLevel, bet.BetIndex))
// model.SendBetFailMessage(model.DataErr, user)
// return
// }
// // 下注总金额
// betAmountCount := rm.RoomCfg.ColorPinoyLiveConfig.BetList[bet.BetLevel][bet.BetIndex]
// bet.BetAmount = betAmountCount
//
// if betAmountCount > user.Balance-totalBetAmount {
// log.Debug(rm.Log("用户余额为:%v 总押注%d 押注%d", user.Balance, totalBetAmount, betAmountCount))
// model.SendBetFailMessage(model.ScoreLess, user)
// return
// } else {
// totalBetAmount += betAmountCount
// betInfos[bet.BetType%config.BET_TYPE_NUM] += betAmountCount
// betCountInfos[bet.BetType%config.BET_TYPE_NUM] += 1
// }
// }
//
// if totalBetAmount <= 0 || totalBetAmount+user.totalBet > rm.RoomCfg.ColorPinoyLiveConfig.TotalBetLimit {
// log.Error(rm.Log("DataErr totalBetAmount:%d err ", totalBetAmount))
// model.SendBetFailMessage(model.PlayerEarTopScore, user)
// return
// }
// log.Debug(rm.LogEx(user, "下注区域最大金额:%v", rm.Cfg.AreaBetLimit))
// for i, num := range betInfos {
// // 投注大于下注区域限制
// if (user.totalBets[i] + num) > rm.Cfg.AreaBetLimit {
// // log.Debug("PlayerEarTopScore totalBetAmount:%d err ", totalBetAmount)
// model.SendBetFailMessage(model.PlayerEarTopScore, user)
// return
// }
// }
//
// user.AddBalance(-totalBetAmount)
//
// if user.LastTimeBet == nil {
// user.LastTimeBet = make([][]*pb.ColorPinoyLiveBetReq, 0)
// }
// user.LastTimeBet = append(user.LastTimeBet, bets)
// user.totalBet += totalBetAmount
// // log.Debug("上次下注:", user.LastTimeBet)
// rm.MutexData.Lock()
// for i, num := range betInfos {
// if num > 0 {
// user.totalBets[i] += num
// rm.totalBets[i] += num
//
// SendSuccessMessage := new(pb.ColorPinoyLiveBetSuccessMessage)
// SendSuccessMessage.BetType = pb.ColorPinoyLiveBetTypeJP(i)
// SendSuccessMessage.UserBet = num
// SendSuccessMessage.UserBets = user.totalBets[i] + num
// SendSuccessMessage.totalBets = rm.totalBets[i] + num
// oneBetMessage.BetInfo = append(oneBetMessage.BetInfo, SendSuccessMessage)
// }
// }
// // 统计个区域投注次数
// // user.TotalBetsCount = make([]int64, config.BET_TYPE_NUM)
// for i, count := range betCountInfos {
// if count > 0 {
// user.TotalBetsCount[i] += count
// }
// }
// user.AllBet += totalBetAmount
// user.NoBetCount = 0
// oneBetMessage.UserScore = user.Balance
// // oneBetMessage.UserBets = user.totalBets[:]
//
// rm.totalBet += totalBetAmount
// rm.MutexData.Unlock()
//
// rm.Table.Broadcast(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeGameSeatUserBet), oneBetMessage)
// live.PushColorBet(&lws.CPLBet{
// Uid: user.UserID,
// Nickname: user.UserInetr.GetNike(),
// Bet: totalBetAmount,
// Avatar: user.UserInetr.GetHead(),
// })
// }
//
// func (rm *ColorRoom) UndoBet(user *model.User, undoType pb.ColorPinoyLiveUndoType) {
//
// betInfos := [config.BET_TYPE_NUM]int64{}
// betCountInfos := [config.BET_TYPE_NUM]int64{}
// totalBetAmount := int64(0)
// undoBetMessage := &pb.S2CUndoBet{}
// undoBetMessage.Uid = user.UserID
// undoBetMessage.BetInfo = []*pb.ColorPinoyLiveBetSuccessMessage{}
// undoBetMessage.UndoType = undoType
//
// if rm.GetGameStatus() != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveBetStatus {
// log.Error(rm.Log("玩家(%d) UndoBet data err GetGameStatus:%v,LastTimeBet:%v ", user.UserID, rm.GetGameStatus(), user.LastTimeBet))
// model.SendBetFailMessage(model.StatusError, user)
// return
// }
// if len(user.LastTimeBet) == 0 {
// log.Error(rm.Log("玩家(%d) LastTimeBet null err:%v ", user.UserID, user.LastTimeBet))
// model.SendBetFailMessage(model.LastBetNull, user)
// return
// }
// var bets []*pb.ColorPinoyLiveBetReq
// if undoType == pb.ColorPinoyLiveUndoType_ColorPinoyLiveUndoOne {
// bets = user.LastTimeBet[len(user.LastTimeBet)-1]
// } else if undoType == pb.ColorPinoyLiveUndoType_ColorPinoyLiveUndoAll {
// for _, bet := range user.LastTimeBet {
// bets = append(bets, bet...)
// }
// } else {
// log.Error(rm.Log("玩家(%d) undoType err %v,", user.UserID, undoType))
// model.SendBetFailMessage(model.DataErr, user)
// return
// }
// if len(bets) == 0 {
// log.Error(rm.Log("玩家(%d) bets err %v,", user.UserID, bets))
// model.SendBetFailMessage(model.LastBetNull, user)
// return
// }
// for _, bet := range bets {
// // 判断下注下标和下注区域下标是否超出列表
// if _, ok := pb.ColorPinoyLiveBetTypeJP_name[int32(bet.BetType)]; !ok {
// log.Error(rm.Log("玩家(%d) bet err %v,", bet))
// model.SendBetFailMessage(model.DataErr, user)
// return
// }
// totalBetAmount += bet.BetAmount
// betInfos[bet.BetType%config.BET_TYPE_NUM] += bet.BetAmount
// betCountInfos[bet.BetType%config.BET_TYPE_NUM] += 1
// }
//
// if totalBetAmount > 0 {
// user.AddBalance(totalBetAmount)
// }
//
// if user.LastTimeBet != nil && len(user.LastTimeBet) > 0 {
// if undoType == pb.ColorPinoyLiveUndoType_ColorPinoyLiveUndoOne {
// user.LastTimeBet = user.LastTimeBet[:len(user.LastTimeBet)-1]
// } else {
// user.LastTimeBet = nil
// }
// }
//
// rm.MutexData.Lock()
// for i, num := range betInfos {
// user.totalBets[i] -= num
// rm.totalBets[i] -= num
// }
// // 统计个区域投注次数
// for i, count := range betCountInfos {
// if count > 0 {
// user.TotalBetsCount[i] -= count
// }
// if user.TotalBetsCount[i] < 0 {
// user.TotalBetsCount[i] = 0
// }
// }
// rm.totalBet -= totalBetAmount
//
// user.totalBet -= totalBetAmount
// user.AllBet -= totalBetAmount
// user.NoBetCount = 0
//
// for i, num := range betInfos {
//
// SendSuccessMessage := new(pb.ColorPinoyLiveBetSuccessMessage)
// SendSuccessMessage.SeatId = int32(user.SceneChairId)
// SendSuccessMessage.BetType = pb.ColorPinoyLiveBetTypeJP(i)
// SendSuccessMessage.UserBet = num
// SendSuccessMessage.UserBets = user.totalBets[i]
// SendSuccessMessage.totalBets = rm.totalBets[i]
//
// undoBetMessage.BetInfo = append(undoBetMessage.BetInfo, SendSuccessMessage)
// }
// rm.MutexData.Unlock()
// // 玩家当前分数
// undoBetMessage.UserScore = user.Balance
//
// // log.Debug("undoBetMessage %v", undoBetMessage)
// rm.Table.Broadcast(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeUndoBet), undoBetMessage)
//
// }
// func (rm *ColorRoom) KickOutUser(u *model.User) {
// // delete(rm.AllUserList, k)
// rm.DeletePlayer(u.UserID)
// if u.SceneChairId != 0 {
// rm.OnUserStanUp(u)
// }
// role := "机器人"
// // rm.DeleteExitUserFromOnlineUserListSlice(u)
// if !u.IsRobot {
// rm.Table.KickOut(u.UserInetr)
// role = "玩家"
// }
// log.Debug(rm.Log("删除(%s(%d) 金额:%d 输赢:%d", role, u.UserID, u.Balance, u.Balance-u.UserInetr.GetScore()))
// rm.SendOnlinePlayerNum()
// }
// func (rm *ColorRoom) TransInoutGameBet(user *model.User, bet int64) error {
// if config.CHIPS_DEBUG {
// user.Balance -= bet
// return nil
// }
// user.Mn.Lock()
// defer user.Mn.Unlock()
// transferInOutResp, err := rm.Table.TransInoutGameCarryAdd(user.UserInetr, rm.Table.GetLevel(), bet, "")
// if err != nil {
// return err
// }
// user.Balance = transferInOutResp.Balance
// user.Carry = transferInOutResp.Carry
// user.UserInetr.SetPreserve(transferInOutResp.Preserve)
// // time.Sleep(10 * time.Second)
// return nil
// }
// func (rm *ColorRoom) TransInoutGameEnd(user *model.User, bet int64, amountWin int64, tax int64) (int64, error) {
// if config.CHIPS_DEBUG || user.IsRobot {
// user.Balance += amountWin
// return amountWin, nil
// }
// transferInOutResp, err := rm.Table.TransInoutGameEnd(user.UserInetr, rm.Table.GetLevel(), bet+tax, amountWin+tax, "")
// if err != nil {
// return 0, err
// }
// user.Balance = transferInOutResp.GetBalance()
// if transferInOutResp.GetRealTransfer() == 0 {
// return 0, errors.New("error")
// }
// user.TransBet += bet
// user.TransWin += amountWin
// // time.Sleep(10 * time.Second)
// return transferInOutResp.RealTransfer, nil
// }
//
// func (rm *ColorRoom) ResetUserBet(user *model.User) {
// rm.MutexData.Lock()
// for i, bet := range user.totalBets {
// rm.totalBets[i] -= bet
// // rm.BetNumber[i] -= user.BetNumber[i]
// }
// rm.totalBet -= user.totalBet
// rm.MutexData.Unlock()
// user.totalBet = 0
// user.totalBets = [config.BET_TYPE_NUM]int64{}
// // user.BetNumber = [config.BET_TYPE_NUM]int64{}
//
// }
//
// func (rm *ColorRoom) StartTransInoutBet() {
// wg := new(sync.WaitGroup)
// var failUser []*model.User
// failMutx := &sync.Mutex{}
// rm.Traverse(func(u *model.User) bool {
// wg.Add(1)
// go func(user *model.User) {
// defer wg.Done()
// user.Mn.Lock()
// defer user.Mn.Unlock()
// if user.totalBet > 0 {
// _, err := rm.TransInoutGameEnd(user, user.totalBet, 0, 0)
// if err != nil {
// func() {
// failMutx.Lock()
// defer failMutx.Unlock()
// failUser = append(failUser, user)
// }()
// }
// }
// }(u)
// return true
// })
// wg.Wait()
// // 异步扣款完成后,处理部分扣款失败回滚操作
// if len(failUser) > 0 {
// pbMsg := &pb.ColorPinoyLiveS2CBetEndFailResult{
// Code: 1,
// }
// for _, user := range failUser {
// rm.ResetUserBet(user)
// player := &pb.ColorPinoyLiveS2CRepetBet{}
// player.UserScore = user.Balance
// player.Uid = user.UserID
//
// var bets []*pb.ColorPinoyLiveBetReq
// for _, bet := range user.LastTimeBet {
// bets = append(bets, bet...)
// }
// for _, bet := range bets {
// // 判断下注下标和下注区域下标是否超出列表
// if _, ok := pb.ColorPinoyLiveBetTypeJP_name[int32(bet.BetType)]; !ok {
// log.Error(rm.Log("玩家(%d) bet err %v,", bet))
// model.SendBetFailMessage(model.DataErr, user)
// return
// }
// SendSuccessMessage := new(pb.ColorPinoyLiveBetSuccessMessage)
// SendSuccessMessage.BetIndex = bet.BetIndex
// SendSuccessMessage.BetLevel = bet.BetLevel
// SendSuccessMessage.BetType = bet.BetType
// SendSuccessMessage.SeatId = int32(user.SceneChairId)
// SendSuccessMessage.UserBet = bet.BetAmount
// SendSuccessMessage.totalBets = rm.totalBets[bet.BetType]
//
// player.BetInfo = append(player.BetInfo, SendSuccessMessage)
// }
// pbMsg.Players = append(pbMsg.Players, player)
// }
// // log.Debug("玩家停止下注后 扣钱失败: %v", pbMsg)
// rm.Table.Broadcast(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticePlayerBetEndResultFailed), pbMsg)
// }
// // 大客投注
// var allWinner []*pb.ColorPinoyLiveBigWinner
// rm.Traverse(func(user *model.User) bool {
// if user.totalBet > 0 {
// allWinner = append(allWinner, &pb.ColorPinoyLiveBigWinner{NickName: user.UserInetr.GetNike(), Avatar: user.UserInetr.GetHead(), WinChips: user.totalBet, AreaId: user.totalBets[:]})
// }
// return true
// })
// rm.updateBigWinner(allWinner)
// bigMsg := &pb.ColorPinoyLivePlayerBigWinner{BigBet: allWinner, Jackpot: rm.jackpotMgr.GetJackpot()}
// rm.Table.Broadcast(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeGameBigWinner), bigMsg)
//
// rm.TimerJob, _ = rm.Table.AddTimer(time.Duration(rm.RoomCfg.TimeConf.Endmove), func() {
// rm.NotifyBigBetAreaMul()
// })
// allUserTotalBet := int64(0) // 所有玩家投注未中奖的总金额用于计算jackpot池
// rm.Traverse(func(user *model.User) bool {
// if user.totalBet < 1 {
// return true
// }
// allUserTotalBet += user.totalBet
// return true
// })
// log.Debug(rm.Log("本局总投注金额为:%v 赎回比例:%v 追加比例:%v 满额追加比例:%v", allUserTotalBet, rm.Cfg.JpXRate, rm.Cfg.JpYRate, rm.Cfg.JpXYRate))
// rm.jackpotX, rm.jackpotY = rm.jackpotMgr.AddJp(allUserTotalBet, int64(rm.Cfg.JpXRate), int64(rm.Cfg.JpYRate), int64(rm.Cfg.JpXYRate))
// if rm.jackpotX > 0 || rm.jackpotY > 0 {
// rm.kafkaJackpotUserRepaid(rm.jackpotX, rm.jackpotY)
// }
// }
//
// // 计算 下注区域中奖得分返回是否有jp奖jp奖位置中奖人数
// func (rm *ColorRoom) CalculateJackpotScore() (pb.ColorPinoyLiveBetTypeJP, map[int64]int64) {
// jackpotArea := pb.ColorPinoyLiveBetTypeJP(-1)
// for _, winArea := range rm.PokerMsg.WinBetArea {
// if !winArea.IsJackpot || !winArea.IsWin {
// continue
// }
// color := getColorByBetArea(winArea.BetArea)
// colorCount := getColorCount(rm.NormalDices, color)
// if colorCount != 3 {
// continue
// }
// jackpotArea = winArea.BetArea
// rm.Traverse(func(user *model.User) bool {
// if user.totalBets[winArea.BetArea] <= 0 {
// return true
// }
// rm.jackpotMgr.AddJpUser(user.UserID, user.totalBets[winArea.BetArea])
// return true
// })
// }
// rm.jackpotUser, rm.costJackpot = rm.jackpotMgr.WinJackpot()
// if rm.costJackpot > 0 {
// rm.kafkaHitJackpot(rm.costJackpot, rm.jackpotUser)
// }
// log.Debug(rm.Log("本局是否中jackpot奖:%v, 玩家一起分走jackpot:%v, 当前jackpot值:%v", rm.costJackpot > 0, rm.costJackpot, rm.jackpotMgr.GetJackpot()))
// return jackpotArea, rm.jackpotUser
// }
//
// // 计算 所有玩家的下注区域中奖得分
// func (rm *ColorRoom) CalculateAllUserScore() {
// // 赢钱会清空jackpot池
// jpArea, userJackPot := rm.CalculateJackpotScore()
// var jackpotUserName []string
// rm.Traverse(func(user *model.User) bool {
// msg := new(pb.ColorPinoyLiveUserSettleMsg)
// msg.WinAreaOdd = rm.PokerMsg.WinBetArea
// msg.UserBets = rm.CopyArr(user.totalBets)
// msg.UserRealWins = make([]int64, config.BET_TYPE_NUM)
// msg.UserWins = make([]int64, config.BET_TYPE_NUM)
//
// if user.totalBet > 0 {
// // 算分
// jpScore := userJackPot[user.UserID]
// rm.CalculateUserScore(user, jpArea, jpScore, msg)
// if jpScore > 0 {
// jackpotUserName = append(jackpotUserName, user.UserInetr.GetNike())
// rm.BroadHitJackpot(user, jpScore)
// }
// }
// // 统计玩家信息
// if msg.TotalWin > user.totalBet {
// user.UserCount(true, msg.TotalWin)
// } else {
// user.UserCount(false, 0)
// }
// user.Balance += msg.TotalWin
// msg.UserScore = user.Balance
// user.SettleMsg = msg
// return true
// })
// rm.Traverse(func(user *model.User) bool {
// user.SettleMsg.JackpotUserName = jackpotUserName
// return true
// })
// }
//
// // 计算 下注区域中奖得分
// func (rm *ColorRoom) CalculateUserScore(user *model.User, jpArea pb.ColorPinoyLiveBetTypeJP, jpScore int64, msg *pb.ColorPinoyLiveUserSettleMsg) {
// for _, winArea := range msg.WinAreaOdd {
// if msg.UserBets[winArea.BetArea] <= 0 {
// continue
// }
// if jpArea != winArea.BetArea {
// odds := winArea.Odd
// // 奖金计算公式 Payouts =( Odds * Bet ) * ( 1 + Bonus) + Bet odds 是倍率 Bonus是猜中幸运骰子 的加成
// // 本区域赢未扣税 倍率是百分值所以计算时要除以100
// win2 := (odds * msg.UserBets[winArea.BetArea]) / 100
// // 本区域赢扣税
// Gold := win2 * (100 - rm.RoomCfg.Rate) / 100
// // 算税()
// msg.Tax += win2 - Gold
// // 加回投注本金
// Gold += msg.UserBets[winArea.BetArea]
// msg.TotalWin += Gold
// // 统计赢区的下注总额
// msg.TotalWinBaseBet += msg.UserBets[winArea.BetArea]
//
// msg.UserWins[winArea.BetArea] += win2
// msg.UserRealWins[winArea.BetArea] += Gold
// log.Debug(rm.LogEx(user, "算分 odds:%v 投注区:%v win2:%v Gold:%v", odds, winArea.BetArea, win2, Gold))
// } else {
// win2 := jpScore
// // 本区域赢扣税
// Gold := jpScore * (100 - rm.RoomCfg.Rate) / 100
// // 算税()
// msg.Tax += win2 - Gold
// // 加回投注本金
// Gold += msg.UserBets[winArea.BetArea]
// msg.TotalWin += Gold
// // 统计赢区的下注总额
// msg.TotalWinBaseBet += msg.UserBets[winArea.BetArea]
//
// msg.UserWins[winArea.BetArea] += win2
// msg.UserRealWins[winArea.BetArea] += Gold
// msg.JackpotWin = Gold
// log.Debug(rm.LogEx(user, "算分 jackpotValue 投注区:%v win2:%v Gold:%v", winArea.BetArea, win2, Gold))
// }
// }
//
// }
//
// type areaWin struct {
// areaId int64
// win int64
// }
//
// // 更新大赢家
// func (rm *ColorRoom) updateBigWinner(allWinner []*pb.ColorPinoyLiveBigWinner) {
// // log.Debug(fmt.Sprintf("allWinner:%+v", allWinner))
// rm.BigWinner = rm.BigWinner[:0]
// sort.Slice(allWinner, func(i, j int) bool {
// return allWinner[i].WinChips > allWinner[j].WinChips
// })
// if len(allWinner) > BigWinnerCount {
// allWinner = allWinner[:BigWinnerCount]
// }
// for _, winner := range allWinner {
// var areaWins []*areaWin
// for areaId, win := range winner.AreaId {
// if win > 0 {
// areaWins = append(areaWins, &areaWin{areaId: int64(areaId), win: win})
// }
// }
// sort.Slice(areaWins, func(i, j int) bool {
// return areaWins[i].win > areaWins[j].win
// })
// if len(areaWins) > BigWinnerCount {
// areaWins = areaWins[:BigWinnerCount]
// }
// winner.AreaId = make([]int64, 0, BigWinnerCount)
// for _, area := range areaWins {
// winner.AreaId = append(winner.AreaId, area.areaId)
// }
// }
// rm.BigWinner = allWinner
// }
//
// // 和平台做结算
// func (rm *ColorRoom) SetUserSettleMsg() {
// var allWinner []*pb.ColorPinoyLiveBigWinner
// rm.CalculateAllUserScore()
// wg := new(sync.WaitGroup)
// rm.Traverse(func(uu *model.User) bool {
// wg.Add(1)
// go func(u *model.User) {
// defer wg.Done()
// if u.totalBet > 0 {
// // 和平台做赢钱结算
// // if msg.TotalWin > 0 {
// _, err := rm.TransInoutGameEnd(u, 0, u.SettleMsg.TotalWin, u.SettleMsg.Tax)
// if err != nil {
// log.Error(rm.Log(err.Error()))
// // model.SendBetFailMessage(model.BalanceError, u)
// }
// // }
// }
// }(uu)
// return true
// })
// wg.Wait()
// // 异步加钱完成后再执行后续的结算操作
// rm.Traverse(func(u *model.User) bool {
// msg := u.SettleMsg
// if msg == nil || msg.TotalWin < 1 {
// return true
// }
// winner := &pb.ColorPinoyLiveBigWinner{
// NickName: u.UserInetr.GetNike(),
// Avatar: u.UserInetr.GetHead(),
// WinChips: msg.TotalWin,
// AreaId: msg.UserRealWins,
// }
// allWinner = append(allWinner, winner)
// log.Debug(rm.LogEx(u, "赢钱:%v", winner.WinChips))
// return true
// })
// rm.updateBigWinner(allWinner)
//
// rm.SetGameTrend()
// rm.sendSettleMsg2Client()
// // log.Debug(time.Now().Unix() - rm.endAt)
// rm.Table.EndGame()
// rm.NotifyLiveDelayUpdate() // 通知延迟更新服务器配置,切换维护状态
// rm.TimerJob, _ = rm.Table.AddTimer(time.Duration(rm.RoomCfg.TimeConf.Endpay), func() {
// rm.Rank()
// })
// }
//
// func (rm *ColorRoom) CountUser(u *model.User) {
// u.Icon = 0
// // rm.OnlineUserList = append(rm.OnlineUserList, u)
// }
// func (rm *ColorRoom) ResetData(all bool) {
// rm.totalBets = [config.BET_TYPE_NUM]int64{}
// rm.totalBet = 0
// rm.LuckyDice = 0
// rm.NormalDices = make([]byte, 3)
// rm.StartDices = make([]byte, 3)
// rm.ResultImgs = make([]string, 0)
// rm.InitBigOddsBetAreas()
//
// if all {
// rm.LiveMgr.Reset()
// rm.Traverse(func(u *model.User) bool {
// u.ResetUserData()
// u.RetrunGold = 0
// return true
// })
// }
// }
// func (rm *ColorRoom) GetPairDice(count int, startIndex int, endIndex int) []byte {
// if gconfig.GConfig.IsProd() {
// return nil
// }
// // PokerCard 表示一张扑克牌
// type Dice struct {
// Color int // 花色
// Point int // 点数
// }
// type PairDice struct {
// Cards []Dice
// }
// key := fmt.Sprintf("preset-cards:0:color:%d", rm.Table.GetId())
// log.Debug(rm.Log("获取配牌配置 key:", key))
// str := redisf.RSC.GetPairCard(key)
// if str == "" {
// return nil
// }
// pairCard := new(PairDice)
// err := json.Unmarshal([]byte(str), pairCard)
// if err != nil {
// log.Debug(rm.Log("getPairCard:%v", err))
// return nil
// }
// if len(pairCard.Cards) < 2 {
// log.Error(rm.Log("getPairCard ", pairCard))
// return nil
// }
// log.Debug(rm.Log("getPairCard pairCard:%v", pairCard))
// var res []byte
// for index, card := range pairCard.Cards {
// if index >= startIndex && index < endIndex {
// res = append(res, byte(card.Point))
// if (len(res)) == count {
// break
// }
// }
// }
// return res
// }
//
// func (rm *ColorRoom) GetGameTrend() (luckyRates []int32) {
// // var mapLuckyRate = map[pb.ColorPinoyLiveDiceColorType]int32{}
// // for _, trend := range rm.GameTrend.ListTrendGroup {
// // mapLuckyRate[trend.LuckyDice]++
// // }
// // for i := pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_YELLOW; i <= pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_GREEN; i++ {
// // luckyRates = append(luckyRates, 0)
// // }
// // if len(mapLuckyRate) > 0 {
// // for k, v := range mapLuckyRate {
// // // log.Debug(fmt.Sprintf("颜色:%v 数量:%v 总数量:%v 配置:%v", k, v, len(rm.GameTrend.ListTrendGroup), config.WinTrendNum))
// // if int(k-1) < len(luckyRates) {
// // luckyRates[k-1] = v * 10000 / int32(len(rm.GameTrend.ListTrendGroup))
// // }
// // }
// // }
//
// return luckyRates
//
// }
//
// func (rm *ColorRoom) SetGameTrend() {
//
// trendGroup := new(pb.ColorPinoyLiveTrendGroup)
// trendGroup.LuckyDice = pb.ColorPinoyLiveDiceColorType(model.GetColor(rm.LuckyDice))
// for _, dice := range rm.NormalDices {
// trendGroup.ThreeDice = append(trendGroup.ThreeDice, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
// }
//
// rm.GameTrend.ListTrendGroup = append(rm.GameTrend.ListTrendGroup, trendGroup)
//
// // log.Debug("走势图 rm.GameTrend.ListTrendGroup: ", rm.GameTrend.ListTrendGroup)
// winlen := len(rm.GameTrend.ListTrendGroup)
// if winlen > config.WinTrendNum {
// rm.GameTrend.ListTrendGroup = rm.GameTrend.ListTrendGroup[(winlen - config.WinTrendNum):]
// }
//
// if rm.ServerStatus == define.GameStatusNoraml {
// str, err := json.Marshal(rm.GameTrend.ListTrendGroup)
// if err != nil {
// return
// }
// redisf.RSC.SetColorGameTrend(rm.TrendRedisKey, str)
// // log.Debug("SetGameTrend 保存走势图到redis :", str)
//
// }
// }
//
// // 获取投注区域的颜色
// func getColorByBetArea(area pb.ColorPinoyLiveBetTypeJP) pb.ColorPinoyLiveDiceColorType {
// switch area {
// case pb.ColorPinoyLiveBetTypeJP_CLJ_Yellow, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Yellow, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Yellow:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_YELLOW
// case pb.ColorPinoyLiveBetTypeJP_CLJ_White, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_White, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_White:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_WHITE
// case pb.ColorPinoyLiveBetTypeJP_CLJ_Pink, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Pink, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Pink:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_PINK
// case pb.ColorPinoyLiveBetTypeJP_CLJ_Blue, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Blue, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Blue:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_BLUE
// case pb.ColorPinoyLiveBetTypeJP_CLJ_Red, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Red, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Red:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_RED
// case pb.ColorPinoyLiveBetTypeJP_CLJ_Green, pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Green, pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Green:
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_GREEN
// }
// return pb.ColorPinoyLiveDiceColorType_ColorPinoyLiveType_Void
// }
//
// func getColorCount(result []byte, color pb.ColorPinoyLiveDiceColorType) int {
// count := 0
// for _, c := range result {
// if model.GetColor(c) == int32(color) {
// count++
// }
// }
// return count
// }
//
// func stringDices(result []byte) string {
// s := ""
// for _, c := range result {
// s += fmt.Sprintf("%v", pb.ColorPinoyLiveDiceColorType(model.GetColor(c)))
// }
// return s
// }
//
// // 检查投掷结果是否匹配某个下注区域
// func isWinningArea(result []byte, area pb.ColorPinoyLiveBetTypeJP) (win bool, bigPos pb.ColorPinoyLiveBigBetAreaPos, colorCount int) {
// color := getColorByBetArea(area)
// colorCount = getColorCount(result, color)
// if colorCount == 0 {
// return false, 0, colorCount
// }
// // 单色投注区,查看开出几个该颜色
// if area < pb.ColorPinoyLiveBetTypeJP_CLJ_Double_Yellow {
// if colorCount == 1 {
// return true, pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_0, colorCount
// } else if colorCount == 2 {
// return true, pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_1, colorCount
// } else {
// return true, pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_2, colorCount
// }
// } else if area < pb.ColorPinoyLiveBetTypeJP_CLJ_Three_Yellow {
// if colorCount > 1 {
// return true, pb.ColorPinoyLiveBigBetAreaPos_BBA_Double, colorCount
// }
// } else {
// if colorCount > 2 {
// return true, pb.ColorPinoyLiveBigBetAreaPos_BBA_Three, colorCount
// }
// }
// return false, 0, colorCount
// }
//
// // 计算开奖结果
// func (rm *ColorRoom) CompareDiceResult() {
// var wins []*pb.ColorPinoyLiveBetAreaOdd
// // // 存储中奖区域
// result := rm.NormalDices
// log.Debug(rm.Log("开奖结果:%v", stringDices(result)))
// rm.afterBetAreaOdds = rm.afterBetAreaOdds[0:0]
// // 检查所有下注区域是否中奖
// for pos, area := range rm.betEndBetAreasOdds {
// betAreaOdd := &pb.ColorPinoyLiveBetAreaOdd{
// BetArea: area.BetType,
// Odd: area.Odd[0],
// ViewOdd: 0,
// IsBigOdd: area.IsBigOdd,
// BigSingleColorOddPos: area.BigSingleColorOddPos,
// IsWin: false,
// IsJackpot: area.IsJackpot,
// }
// if pos/6 == 0 {
// // 第一行投注区域,赔率是多个赔率中的一个
// betAreaOdd.Odd = area.Odd[area.BigSingleColorOddPos]
// } else {
// betAreaOdd.Odd = area.Odd[0]
// }
// betAreaOdd.ViewOdd = betAreaOdd.Odd
// // 更新实际赔率
// isWin, winOddPos, colorCount := isWinningArea(result, area.BetType)
// betAreaOdd.IsWin = isWin
// if betAreaOdd.IsWin {
// if betAreaOdd.IsJackpot && colorCount == 3 {
// betAreaOdd.Odd = 0
// } else {
// if winOddPos == pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_0 {
// betAreaOdd.Odd = area.Odd[0]
// } else if winOddPos == pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_1 {
// betAreaOdd.Odd = area.Odd[1]
// } else if winOddPos == pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_2 {
// betAreaOdd.Odd = area.Odd[2]
// }
// // 爆奖需要修正
// if betAreaOdd.IsBigOdd && winOddPos > betAreaOdd.BigSingleColorOddPos {
// betAreaOdd.Odd = area.Odd[area.BigSingleColorOddPos]
// }
// }
// wins = append(wins, betAreaOdd)
// }
//
// // 修正牌局记录倍率
// tmpAreaOdd := &pb.ColorPinoyLiveBetAreaOdd{
// BetArea: betAreaOdd.BetArea,
// Odd: betAreaOdd.Odd,
// ViewOdd: betAreaOdd.ViewOdd,
// IsBigOdd: betAreaOdd.IsBigOdd,
// BigSingleColorOddPos: betAreaOdd.BigSingleColorOddPos,
// IsWin: betAreaOdd.IsWin,
// IsJackpot: betAreaOdd.IsJackpot,
// }
// if !tmpAreaOdd.IsWin && pos/6 == 0 &&
// (betAreaOdd.BigSingleColorOddPos == pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_1 ||
// betAreaOdd.BigSingleColorOddPos == pb.ColorPinoyLiveBigBetAreaPos_BBA_Single_2) {
// tmpAreaOdd.Odd = area.Odd[0]
// if !tmpAreaOdd.IsBigOdd {
// tmpAreaOdd.ViewOdd = tmpAreaOdd.Odd
// }
// }
// if !tmpAreaOdd.IsWin && pos/6 == 1 && tmpAreaOdd.IsBigOdd {
// tmpAreaOdd.Odd = rm.RoomCfg.ColorPinoyLiveConfig.WinDoubleColorMul[0].Mul
// }
// if !tmpAreaOdd.IsWin && pos/6 == 2 && tmpAreaOdd.IsBigOdd {
// tmpAreaOdd.Odd = rm.RoomCfg.ColorPinoyLiveConfig.WinThreeColorMul[0].Mul
// }
//
// rm.afterBetAreaOdds = append(rm.afterBetAreaOdds, tmpAreaOdd)
// log.Debug(rm.Log("开奖,区域:%v 是否中奖:%v 实际赔率:%v 显示赔率:%v 是否爆奖:%v 爆奖位置:%v", betAreaOdd.BetArea, betAreaOdd.IsWin, betAreaOdd.Odd,
// betAreaOdd.ViewOdd, betAreaOdd.IsBigOdd, betAreaOdd.BigSingleColorOddPos))
// }
// rm.PokerMsg.WinBetArea = wins
// }
//
// // 检查用户是否被踢掉
// func (rm *ColorRoom) checkUserBet() {
// kickMsg, isKick := redisf.RSC.IsGameMaintenance(gconfig.GConfig.GRoomConfig.ChannelId, gconfig.GConfig.GServConfig.GameId)
// rm.Traverse(func(u *model.User) bool {
// u.NoBetCount++
// if isKick {
// msg := new(pb.ColorPinoyLiveKickOutUserMsg)
// // msg.KickOutReason = fmt.Sprintf("you did not bet %d games", rm.RoomCfg.LongHuConfig.NoBetCountMax)
// msg.Reason = int32(pb.ColorPinoyLiveLeaveReason_ColorPinoyLiveLeaveReason_Maintaince)
// msg.KickOutReason = kickMsg
// u.SendMsg(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeKickOutUser), msg)
// u.NoBetCount = 0
// rm.KickOutUser(u)
// return true
// }
// if rm.ServerStatus != define.GameStatusNoraml || u.UserInetr.NeedKickout() {
// msg := new(pb.ColorPinoyLiveKickOutUserMsg)
// // msg.KickOutReason = fmt.Sprintf("game server maintenance ")
// msg.Reason = int32(pb.ColorPinoyLiveLeaveReason_ColorPinoyLiveLeaveReason_PLAYER_QUIT_ROOM)
// u.SendMsg(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeKickOutUser), msg)
// rm.KickOutUser(u)
// return true
// }
// if redisf.RSC.IsUserLiveBan(u.UserInetr.GetOpToken(), int64(gconfig.GConfig.GRoomConfig.GameId), u.UserID) {
// msg := new(pb.ColorPinoyLiveKickOutUserMsg)
// msg.Reason = int32(pb.ColorPinoyLiveLeaveReason_ColorPinoyLiveLeaveReason_Ban)
// u.SendMsg(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeKickOutUser), msg)
// rm.KickOutUser(u)
// return true
// }
// // if u.NoBetCount >= (rm.RoomCfg.ColorPinoyLiveConfig.NoBetCountMax + 1) {
// // msg := new(pb.ColorPinoyLiveKickOutUserMsg)
// // // msg.KickOutReason = fmt.Sprintf("you did not bet %d games", rm.RoomCfg.LongHuConfig.NoBetCountMax)
// // msg.Reason = 1
// // u.SendMsg(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeKickOutUser), msg)
// // // 踢掉用户
// // u.NoBetCount = 0
// // rm.KickOutUser(u)
// // return true
// // }
//
// return true
// })
// }
//
// // 初始走势图
// func (rm *ColorRoom) InitWinTrend() {
// rm.TrendRedisKey = fmt.Sprintf("pb.:%d:%d:trend", gconfig.GConfig.GDataConfig.VersionMode, rm.RoomCfg.Level)
// if rm.ServerStatus == define.GameStatusNoraml {
// winTrend := redisf.RSC.GetColorGameTrend(rm.TrendRedisKey)
// if winTrend != "" {
// rm.GameTrend = new(pb.ColorPinoyLiveTrend)
// rm.GameTrend.ListTrendGroup = []*pb.ColorPinoyLiveTrendGroup{}
// err := json.Unmarshal([]byte(winTrend), &rm.GameTrend.ListTrendGroup)
// winlen := len(rm.GameTrend.ListTrendGroup)
// // log.Debug("初始化走势图1:", len(rm.GameTrend.ListTrendGroup))
// if winlen > config.WinTrendNum {
// rm.GameTrend.ListTrendGroup = rm.GameTrend.ListTrendGroup[(winlen - config.WinTrendNum):]
// // log.Debug("初始化走势图2:", len(rm.GameTrend.ListTrendGroup))
// }
// // log.Debug("初始化走势图:", rm.GameTrend.ListTrendGroup)
// if err != nil {
// log.Error(rm.Log("初始化走势图:%v", err))
// }
// }
//
// }
//
// }
//
// func (rm *ColorRoom) DeleteExitUserFromOnlineUserListSlice(user *model.User) {
// rm.MutexUserList.Lock()
// defer rm.MutexUserList.Unlock()
// for k, v := range rm.OnlineUserList {
// if user == v {
// rm.OnlineUserList = append(rm.OnlineUserList[:k], rm.OnlineUserList[k+1:]...)
// break
// }
// }
// }
//
// func (rm *ColorRoom) SelectUserListBalanceTopSitDownChair() {
// rm.MutexUserList.Lock()
// rm.SceneInfo.ClearSceneChairId()
// rm.SceneInfo.Init()
// index := len(rm.OnlineUserList)
// if index >= config.SEAT_NUM {
// index = config.SEAT_NUM
// }
// cou := model.Usercount{}
// cou = rm.OnlineUserList
// sort.Sort(cou)
// for i := 0; i < index; i++ {
// u := rm.OnlineUserList[i]
// ChairId := i + 1
// if rm.SceneInfo.SitScene(u, ChairId) {
// u.SceneChairId = ChairId
// }
// }
// rm.MutexUserList.Unlock()
//
// }
//
// func (rm *ColorRoom) CopyArr(arr [config.BET_TYPE_NUM]int64) []int64 {
// slice := make([]int64, len(arr))
// copy(slice, arr[:])
// return slice
// }
//
// func (rm *ColorRoom) GameDiscard() {
// rm.TimerJob.Cancel()
// rm.GameUserDiscard()
// // rm.TimerJob, _ = rm.Table.AddTimer(1000, func() {
// // rm.LiveCnt(rm.Ready, false, true, []bool{true}...)
// // })
// rm.ResetData(false)
// rm.Traverse(func(user *model.User) bool {
// if rm.LiveMgr.MaintenanceStatus == 1 {
// rm.sendUserMainte(user, int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeGameMainte))
// }
// if rm.LiveMgr.DiscardStatus == 1 {
// rm.sendUserMainte(user, int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeDiscard))
// }
// return true
// })
// rm.Ready()
// }
//
// func (rm *ColorRoom) sendUserMainte(user *model.User, cmd int32) {
// userinfo := new(pb.ColorPinoyLiveUserInfo)
// userinfo.NikeName = user.UserInetr.GetNike()
// userinfo.UserGlod = user.Balance
// userinfo.Head = user.UserInetr.GetHead()
// userinfo.UserID = user.UserID
// _ = user.UserInetr.SendMsg(cmd, &pb.ColorPinoyLiveMainteNtf{
// UserInfo: userinfo,
// MaintMsg: rm.LiveMgr.MainteMsg,
// ReturnGold: user.RetrunGold,
// })
// }
//
// func (rm *ColorRoom) GameUserDiscard() {
// rm.MutexStatus.RLock()
// defer rm.MutexStatus.RUnlock()
// log.Debug(rm.Log("流局,状态:%v,分出去的jackpot:%v", rm.GetGameStatus(), rm.costJackpot))
// // 回退
// if rm.GetGameStatus() >= pb.ColorPinoyLiveGameStatus_ColorPinoyLiveEndBetMovie && rm.GetGameStatus() < pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus {
// rm.jackpotMgr.RollBackJpXAndJpY(0, 0, rm.jackpotX, rm.jackpotY)
// rm.kafkaBackJackpot(0, rm.jackpotX, rm.jackpotY, rm.jackpotUser)
// } else if rm.GetGameStatus() >= pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus {
// rm.jackpotMgr.RollBackJpXAndJpY(rm.costJackpot, rm.jackpotFunding, rm.jackpotX, rm.jackpotY)
// rm.kafkaBackJackpot(rm.costJackpot, rm.jackpotX, rm.jackpotY, rm.jackpotUser)
// }
//
// var betCount int64
// GameTotalBets := make([]int64, config.BET_TYPE_NUM)
// var PlayerData []*pb.ColorPinoyLivePlayerData
// copyBetAreaMul := rm.copyBetAreaOdds()
// wg := new(sync.WaitGroup)
// playerDataMu := new(sync.Mutex)
// rm.Traverse(func(v *model.User) bool {
// wg.Add(1)
// monitor.GoSafe(func(u *model.User) {
// defer wg.Done()
// u.RetrunGold = u.totalBet
// msg := new(pb.ColorPinoyLiveUserSettleMsg)
// msg.UserBets = rm.CopyArr(u.totalBets)
// msg.UserRealWins = make([]int64, config.BET_TYPE_NUM)
// msg.UserWins = make([]int64, config.BET_TYPE_NUM)
// msg.WinAreaOdd = rm.PokerMsg.WinBetArea
// msg.UserScore = u.Balance
// u.SettleMsg = msg
// // 写入数据库统计信息
// if u.totalBet > 0 {
// for i, bet := range u.totalBets {
// betCount += bet
// GameTotalBets[i] += bet
// }
// // 玩家下注区域统计
// u.SettleMsg.UserBetsCount = make([]int64, config.BET_TYPE_NUM)
// for i, count := range u.TotalBetsCount {
// u.SettleMsg.UserBetsCount[i] = count
// }
// if rm.GetGameStatus() < pb.ColorPinoyLiveGameStatus_ColorPinoyLiveEndBetMovie {
// u.AddBalance(u.totalBet)
// } else if rm.GetGameStatus() < pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus {
// _, err := rm.TransInoutGameEnd(u, u.TransWin, u.TransBet, 0)
// if err != nil {
// log.Error(rm.Log("discard error:%v, game_no:%s, uid:%d, TransWin:%d, TransBet:%d", err, rm.Table.GetGameRoundId(), u.UserID, u.TransWin, u.TransBet))
// }
// } else {
// if rm.LiveMgr.DiscardStatus == 1 {
// _, err := rm.TransInoutGameEnd(u, u.TransWin, u.TransBet, 0)
// if err != nil {
// log.Error(rm.Log("discard error:%v, game_no:%s, uid:%d, TransWin:%d, TransBet:%d", err, rm.Table.GetGameRoundId(), u.UserID, u.TransWin, u.TransBet))
// }
// } else {
// return
// }
// }
// func() {
// playerDataMu.Lock()
// defer playerDataMu.Unlock()
// PlayerData = append(PlayerData, &pb.ColorPinoyLivePlayerData{
// Uid: u.UserID,
// totalBets: u.SettleMsg.UserBets, // 玩家各个区域的总下注额
// totalBet: u.totalBet,
// Profit: u.SettleMsg.TotalWin,
// Tax: u.SettleMsg.Tax,
// Balance: u.Balance,
// PreBalance: u.PreBalance,
// UserWins: u.SettleMsg.UserWins, // 玩家赢取的下注区域总下注额
// UserRealWins: u.SettleMsg.UserRealWins, // 玩家赢取的下注区域总下注额 扣税后
// AreaOdds: copyBetAreaMul, // 投注区域倍率
// StartTime: u.StartAt,
// TransBet: u.TransBet,
// TransWin: u.TransWin,
// DevMode: u.UserInetr.GetDevMode(),
// UserBetsCount: u.SettleMsg.UserBetsCount,
// IsDiscard: 1,
// })
// }()
// }
// u.ResetUserData()
// }, v)
// return true
// })
// wg.Wait()
// // 发布事件
// if PlayerData == nil || len(PlayerData) == 0 {
// return
// }
// // 开奖结果
// gameDetail := &pb.ColorPinoyLiveDetail{DealerName: rm.dealerName, ResultImg: rm.ResultImgs}
// gameDetail.BetAreaMul = copyBetAreaMul
// gameRecordData := &pb.ColorPinoyLiveEnd{
// GameNo: fmt.Sprintf("%d|%d|%d", gconfig.GConfig.GRoomConfig.GameId, rm.Table.GetId(), time.Now().UnixMilli()),
// StartTime: rm.startAt,
// EndTime: rm.endAt,
// Level: gconfig.GConfig.GRoomConfig.Level,
// BaseBet: rm.RoomCfg.BaseBet,
// PlayerData: PlayerData,
// TaxRate: rm.RoomCfg.Rate,
// totalBet: betCount,
// totalBets: GameTotalBets[:],
// OpToken: gconfig.GConfig.GServConfig.ChannelId,
// Detail: gameDetail,
// IsDiscard: 1,
// }
// log.Debug("GameUserDiscard")
// go func() {
// err := gconfig.Produce(context.Background(), define.TopicColoLiveGameGameEnd, gameRecordData)
// if err != nil {
// log.Error(rm.Log("[%s] fail to Produce TongitsGameEndEvent(%+v), err: %v", gameRecordData.GameNo, gameRecordData, err))
// }
// }()
// }
//
// func (rm *ColorRoom) LoadDealerNames() {
// ssv := redisf.RSC.DealerNameGet(gconfig.GConfig.GDataConfig.VersionMode, gconfig.GConfig.GRoomConfig.GameId, GameName)
// var dealerNames []string
// _ = json.Unmarshal([]byte(ssv), &dealerNames)
// rm.dealerName = dealerNames
// log.Debug(rm.Log("dealerNames:%v", rm.dealerName))
// }
//
// // 发送垫资kafka
// func (rm *ColorRoom) kafkaJackpotFunding(funding int64) {
// msg := &events.JackpotEvent{
// EventType: events.JackpotEvent_et_funding,
// GameId: rm.RoomCfg.GameId,
// Time: time.Now().UnixMilli(),
// Funding: &events.JackpotEvent_Funding{Funding: funding},
// GameNo: rm.Table.GetGameRoundId(),
// }
// go func() {
// err := gconfig.Produce(context.Background(), define.TopicJackpot, msg)
// if err != nil {
// log.Error(rm.Log("kafka JackpotEvent_et_funding err: %v", err))
// }
// }()
// log.Debug(rm.Log("kafka 垫资:%v", funding))
// }
//
// // 发送赎回及追加kafka
// func (rm *ColorRoom) kafkaJackpotUserRepaid(jpx, jpy int64) {
// msg := &events.JackpotEvent{
// EventType: events.JackpotEvent_et_user_repaid,
// GameId: rm.RoomCfg.GameId,
// Time: time.Now().UnixMilli(),
// UserRepaid: &events.JackpotEvent_UserRepaid{JackpotX: jpx, JackpotY: jpy},
// GameNo: rm.Table.GetGameRoundId(),
// }
// go func() {
// err := gconfig.Produce(context.Background(), define.TopicJackpot, msg)
// if err != nil {
// log.Error(rm.Log("kafka JackpotEvent_et_user_repaid err: %v", err))
// }
// }()
// log.Debug(rm.Log("kafka 赎回jpx:%v 追加jpy:%v", jpx, jpy))
// }
//
// // 中jackpot分奖
// func (rm *ColorRoom) kafkaHitJackpot(jackpotValue int64, userJp map[int64]int64) {
// msg := &events.JackpotEvent{
// EventType: events.JackpotEvent_et_hit_jackpot,
// GameId: rm.RoomCfg.GameId,
// Time: time.Now().UnixMilli(),
// HitJackpot: &events.JackpotEvent_HitJackpot{SumJackpot: jackpotValue, UserJackpot: userJp},
// GameNo: rm.Table.GetGameRoundId(),
// }
// go func() {
// err := gconfig.Produce(context.Background(), define.TopicJackpot, msg)
// if err != nil {
// log.Error(rm.Log("kafka JackpotEvent_HitJackpot err: %v", err))
// }
// }()
// log.Debug(rm.Log("kafka 中jackpot:%v", jackpotValue))
// }
//
// func (rm *ColorRoom) kafkaBackJackpot(jackpotValue, jpx, jpy int64, userJp map[int64]int64) {
// userJp2 := make(map[int64]int64)
// for k, v := range userJp {
// userJp2[k] = -v
// }
// msg := &events.JackpotEvent{
// EventType: events.JackpotEvent_et_game_discard,
// GameId: rm.RoomCfg.GameId,
// Time: time.Now().UnixMilli(),
// GameDiscard: &events.JackpotEvent_GameDiscard{
// Jackpot: -jackpotValue,
// JackpotX: -jpx,
// JackpotY: -jpy,
// UserJackpot: userJp2,
// },
// GameNo: rm.Table.GetGameRoundId(),
// }
// go func() {
// err := gconfig.Produce(context.Background(), define.TopicJackpot, msg)
// if err != nil {
// log.Error(rm.Log("kafka JackpotEvent_HitJackpot err: %v", err))
// }
// }()
// log.Debug(rm.Log("kafka 回退jackpot:%v jpx:%v jpy:%v", -jackpotValue, -jpx, -jpy))
// }