519 lines
17 KiB
Go
Raw Normal View History

2025-06-08 00:52:17 +08:00
package room
import (
"encoding/json"
"game/common/proto/pb"
"github.com/fox/fox/log"
)
// const (
// LiveProcessInit = iota
// LiveProcessStart
// LiveProcessWait
// LiveProcessWaitDone
// LiveProcessFuncStart
// LiveProcessFuncDone
// )
//
// var LiveProcessStatusName = map[int]string{
// LiveProcessInit: "LiveProcessInit",
// LiveProcessStart: "LiveProcessStart",
// LiveProcessWait: "LiveProcessWait",
// LiveProcessWaitDone: "LiveProcessWaitDone",
// LiveProcessFuncStart: "LiveProcessFuncStart",
// LiveProcessFuncDone: "LiveProcessFuncDone",
// }
type LiveMgr struct {
// LiveWg *sync.WaitGroup
// Count int // 当前数量
// Mu *sync.Mutex
MaintenanceStatus int32 // 维护状态 0 正常 1 维护
// ProcessStatus int // 进程状态
Restting bool // 重置状态
MainteMsg string
DiscardMsg string
DiscardStatus int
DiscardRestting bool // 重置状态
RankList *pb.ColorPinoyLiveRankList
HasMainte bool
}
func NewLiveMgr() *LiveMgr {
return &LiveMgr{
// LiveWg: new(sync.WaitGroup),
// Mu: new(sync.Mutex),
RankList: new(pb.ColorPinoyLiveRankList),
}
}
func (lm *LiveMgr) Reset() {
lm.Restting = false
lm.DiscardRestting = false
lm.DiscardStatus = 0
}
// func (lm *LiveMgr) IsAdd() bool {
// lm.Mu.Lock()
// defer lm.Mu.Unlock()
// return lm.Count > 0
// }
//
// func (lm *LiveMgr) Add() {
// log.Debug("LiveMgr add")
// lm.Mu.Lock()
// defer lm.Mu.Unlock()
// lm.LiveWg.Add(1)
// lm.Count++
// }
//
// func (lm *LiveMgr) Done() {
// log.Debug("LiveMgr Done")
// lm.Mu.Lock()
// defer lm.Mu.Unlock()
// if lm.Count == 0 {
// return
// }
// lm.LiveWg.Done()
// lm.Count--
// }
//
// func (lm *LiveMgr) Wait() {
// log.Debug("LiveMgr Wait")
// lm.LiveWg.Wait()
// }
func (lm *LiveMgr) NeedMaintenance() bool {
return !lm.HasMainte && (lm.MaintenanceStatus == 1 || lm.DiscardStatus == 1)
}
func (rm *ColorRoom) LiveDelayUpdate() error {
event := &events.ServCmdKafka{
ServCmd: common.ServCmd_sc_live_delay_update,
}
data := &common.ServLiveDelayUpdate{
GameId: gconfig.GConfig.GRoomConfig.GameId,
MainteStatus: rm.LiveMgr.MaintenanceStatus,
MainteMsg: rm.LiveMgr.MainteMsg,
}
event.Data, _ = proto.Marshal(data)
err := gconfig.Produce(context.Background(), define.TopicSysServerCmd, event)
if err != nil {
log.Error(rm.Log("fail to Produce Event(%+v), err: %v", event, err))
return err
}
return nil
}
func (rm *ColorRoom) NotifyLiveDelayUpdate() {
if !gconfig.DelayUpdateServer {
return
}
if rm.LiveDelayUpdate() != nil {
return
}
gconfig.DelayUpdateServer = false
}
func (rm *ColorRoom) ServerMaintenanceKickPlayer() {
rm.Traverse(func(u *model.User) bool {
kMsg := new(pb.ColorPinoyLiveKickOutUserMsg)
kMsg.Reason = int32(pb.ColorPinoyLiveLeaveReason_ColorPinoyLiveLeaveReason_Server_Update)
u.SendMsg(int32(pb.ColorPinoyLiveSendToClientMessageType_ColorPinoyLiveNoticeKickOutUser), kMsg)
rm.KickOutUser(u)
return true
})
}
func (rm *ColorRoom) SyncServerMaintenance(st int32, ss string) {
_ = st
_ = ss
rm.LoadDealerNames()
// 可能即将变为 normal
if gconfig.GConfig.GServConfig.Status != define.GameStatusNoraml {
rm.LiveMgr.MaintenanceStatus = 0
rm.LiveMgr.MainteMsg = ""
return
}
ssv := redisf.RSC.LiveMainteGet(gconfig.GConfig.GDataConfig.VersionMode, gconfig.GConfig.GRoomConfig.GameId)
resp := new(pb.ColorPinoyLiveCommResp)
_ = json.Unmarshal([]byte(ssv), resp)
rm.LiveMgr.MaintenanceStatus = resp.MaintainStatus
rm.LiveMgr.MainteMsg = resp.MaintainMsg
}
func (rm *ColorRoom) OnLiveGameMessage(subCmd int32, buffer []byte) ([]byte, error) {
// log.Debug("收到后台消息:", subCmd)
var result proto.Message
_, err := rm.Table.RunAndWait(func() any {
switch subCmd {
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGGameGetStatus):
result = rm.LiveGetGameStatus(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGReady):
result = rm.LiveGameReady(buffer) // 点击finish
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGBetting):
result = rm.LiveGameBetting(buffer) // 点击start
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGMStartDice):
result = rm.LiveGameStartDice(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGMResultImg):
result = rm.LiveGameResultImg(buffer)
// case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGLucky):
// result = rm.LiveGameLucky(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGResult):
result = rm.LiveGameResult(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGMMainteSet):
result = rm.LiveGameMainte(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGMDiscard):
result = rm.LiveGameDiscard(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGMRankList):
result = rm.LiveGameRankList(buffer)
case int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGSetDealer):
result = rm.LiveGameSetDealerName(buffer)
default:
log.Error(rm.Log("no protocol"))
return nil
}
return result
})
if err == nil && result != nil {
b, _ := proto.Marshal(result)
canLog := true
if subCmd == int32(pb.ColorPinoyLiveProcessCmd_ColorPinoyLiveMSGGameGetStatus) {
if rd := rand.RandInt(0, 100); rd < 90 {
canLog = false
}
}
if canLog {
j, _ := json.Marshal(result)
log.Debug(rm.Log("返回后台消息 subCmd:%d, msg:%s", subCmd, string(j)))
}
return b, nil
}
return nil, err
}
func (rm *ColorRoom) getStatus() (int32, int64) {
switch rm.Status {
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveStartUnReady:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Readymove)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveStartReady:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Startmove)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveStartMovie:
return int32(pb.ColorPinoyLiveGameStatus_ColorPinoyLiveBetStatus), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Startbet)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveBetStatus:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Startbet)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveEndBetMovie:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Endmove)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveOpenThreeDice:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.OpenThreeDice)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Endpay)
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveRankStatus:
return int32(rm.Status), rm.StatusTime + int64(rm.RoomCfg.TimeConf.Rank)
default:
return int32(rm.Status), rm.StatusTime
}
}
func (rm *ColorRoom) LiveStatus() *pb.ColorPinoyLiveCommResp {
resp := &pb.ColorPinoyLiveCommResp{
GameId: gconfig.GConfig.GRoomConfig.GameId,
MaintainStatus: rm.LiveMgr.MaintenanceStatus,
MaintainMsg: rm.LiveMgr.MainteMsg,
Times: rm.RoomCfg.TimeConf.Get(),
GameNo: rm.Table.GetGameRoundId(),
DealerName: rm.dealerName,
Jackpot: rm.jackpotMgr.GetJackpotCopy(),
}
resp.GameStatus, resp.Countdown = rm.getStatus()
resp.BetAreaMul = rm.betEndBetAreasOdds
for _, dice := range rm.StartDices {
resp.StartDice = append(resp.StartDice, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
}
resp.ResultImg = rm.ResultImgs
switch rm.Status {
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveOpenThreeDice:
resp.LuckyStar = pb.ColorPinoyLiveDiceColorType(model.GetColor(rm.LuckyDice))
for _, dice := range rm.NormalDices {
resp.DrawResult = append(resp.DrawResult, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
}
case pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus, pb.ColorPinoyLiveGameStatus_ColorPinoyLiveRankStatus:
resp.LuckyStar = pb.ColorPinoyLiveDiceColorType(model.GetColor(rm.LuckyDice))
for _, dice := range rm.NormalDices {
resp.DrawResult = append(resp.DrawResult, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
}
resp.RankList = rm.LiveMgr.RankList
default:
}
// 结束下注后,后台可看到更新爆奖后的投注面板
if rm.Status > pb.ColorPinoyLiveGameStatus_ColorPinoyLiveBetStatus {
resp.BetAreaMul = rm.betEndBetAreasOdds
}
return resp
}
func (rm *ColorRoom) LiveGetGameStatus(buffer []byte) proto.Message {
_ = buffer
return rm.LiveStatus()
}
func (rm *ColorRoom) LiveGameReady(buffer []byte) proto.Message {
_ = buffer
log.Debug(rm.Log("LiveGameReady"))
// rm.MutexStatus.Lock()
// defer rm.MutexStatus.Unlock()
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
if rm.Status != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveRankStatus {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
return resp
}
rm.Ready()
resp.GameStatus, resp.Countdown = rm.getStatus()
return resp
}
func (rm *ColorRoom) LiveGameBetting(buffer []byte) proto.Message {
_ = buffer
log.Debug(rm.Log("LiveGameBetting"))
// rm.MutexStatus.Lock()
// defer rm.MutexStatus.Unlock()
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
if rm.Status != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveStartReady {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
return resp
}
rm.StartBet()
return resp
}
func (rm *ColorRoom) LiveGameStartDice(buffer []byte) proto.Message {
log.Debug(rm.Log("LiveGameStartDice"))
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
if rm.Status != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveEndBetMovie {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
return resp
}
req := new(pb.ColorPinoyLiveStartDice)
_ = proto.Unmarshal(buffer, req)
if len(req.GetStartDice()) != 3 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorDice)
return resp
}
for i := 0; i < len(req.GetStartDice()); i++ {
rm.StartDices[i] = byte(req.GetStartDice()[i])
}
log.Debug(rm.Log("req:", req.GetStartDice(), ",StartDice:", rm.StartDices))
resp.StartDice = make([]pb.ColorPinoyLiveDiceColorType, 0)
for _, dice := range rm.StartDices {
resp.StartDice = append(resp.StartDice, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
}
resp.ResultImg = rm.ResultImgs
return resp
}
func (rm *ColorRoom) LiveGameResultImg(buffer []byte) proto.Message {
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
req := new(pb.ColorPinoyLiveResultImg)
_ = proto.Unmarshal(buffer, req)
rm.ResultImgs = append(rm.ResultImgs, req.GetResultImg()...)
log.Debug(rm.Log("req:", req.GetResultImg(), ",ResultImg:", rm.ResultImgs))
resp.StartDice = make([]pb.ColorPinoyLiveDiceColorType, 0)
for _, dice := range rm.StartDices {
resp.StartDice = append(resp.StartDice, pb.ColorPinoyLiveDiceColorType(model.GetColor(dice)))
}
resp.ResultImg = rm.ResultImgs
return resp
}
func (rm *ColorRoom) LiveGameResult(buffer []byte) proto.Message {
// rm.MutexStatus.Lock()
// defer rm.MutexStatus.Unlock()
log.Debug(rm.Log("LiveGameResult"))
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
log.Debug(rm.Log("LiveGameResult status:%v ", rm.Status))
if rm.Status != pb.ColorPinoyLiveGameStatus_ColorPinoyLiveEndBetMovie {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
return resp
}
req := new(pb.ColorPinoyLiveResult)
_ = proto.Unmarshal(buffer, req)
if len(req.GetColor()) != 3 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorDice)
return resp
} else {
for i := 0; i < len(req.GetColor()); i++ {
if !model.IsLogic(int32(req.GetColor()[i])) {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorDice)
return resp
}
rm.NormalDices[i] = byte(req.GetColor()[i])
}
}
log.Debug(rm.Log("LiveGameResult req:%v NormalDices:%v", req.GetColor(), rm.NormalDices))
rm.Table.Run(rm.openThreeDice)
return resp
}
func (rm *ColorRoom) LiveGameMainte(buffer []byte) proto.Message {
req := new(pb.ColorPinoyLiveMaintain)
_ = proto.Unmarshal(buffer, req)
b, _ := json.Marshal(req)
log.Debug(rm.Log("LiveGameMainte:%v", string(b)))
resp := rm.LiveStatus()
if rm.LiveMgr.Restting {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
resp.Msg = "Restting"
return resp
}
if req.TargetStatus == rm.LiveMgr.MaintenanceStatus {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
if rm.GetGameStatus() == pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
resp.Msg = "SettleStatus"
return resp
}
defer func() {
_ = pushGate.NotifyConfigUpdated(msg.ConfigUpdateType_ConfigUpdateTypeLiveConfig)
rm.SetLiveGameStatus()
}()
if req.TargetStatus == 0 {
rm.LiveMgr.MaintenanceStatus = 0
rm.LiveMgr.MainteMsg = ""
rm.LiveMgr.HasMainte = false
} else {
rm.LiveMgr.MaintenanceStatus = req.TargetStatus
rm.LiveMgr.MainteMsg = req.GetMsg()
rm.LiveMainteCnt()
}
resp.MaintainStatus = rm.LiveMgr.MaintenanceStatus
resp.MaintainMsg = rm.LiveMgr.MainteMsg
resp.GameStatus, resp.Countdown = rm.getStatus()
br, _ := json.Marshal(resp)
redisf.RSC.LiveMainteSet(gconfig.GConfig.GDataConfig.VersionMode, gconfig.GConfig.GRoomConfig.GameId, string(br))
redisf.RSC.LiveMainteLobbySet(gconfig.GConfig.GDataConfig.VersionMode, gconfig.GConfig.GRoomConfig.GameId, rm.LiveMgr.MaintenanceStatus, rm.LiveMgr.MainteMsg)
return resp
}
func (rm *ColorRoom) LiveMainteCnt() {
rm.LiveMainte()
}
func (rm *ColorRoom) LiveMainte() {
if rm.LiveMgr.MaintenanceStatus == 1 {
rm.LiveMgr.HasMainte = true
rm.LiveMgr.Restting = true
}
if rm.LiveMgr.DiscardStatus == 1 {
rm.LiveMgr.DiscardRestting = true
}
rm.GameDiscard()
// rm.LiveMgr.SetProcessStatus(LiveProcessInit)
if rm.LiveMgr.MaintenanceStatus == 1 {
rm.LiveMgr.Restting = false
}
if rm.LiveMgr.DiscardStatus == 1 {
rm.LiveMgr.DiscardRestting = false
rm.LiveMgr.DiscardStatus = 0
}
}
func (rm *ColorRoom) LiveGameDiscard(_ []byte) proto.Message {
log.Debug(rm.Log("LiveGameDiscard"))
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
log.Error(rm.Log("rm.LiveMgr.MaintenanceStatus"))
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
if rm.LiveMgr.DiscardRestting {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
resp.Msg = "DiscardRestting"
return resp
}
// if rm.GetGameStatus() == pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus {
// resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorGameSatus)
// resp.Msg = "SettleStatus"
// return resp
// }
rm.LiveMgr.DiscardStatus = 1
rm.LiveMgr.DiscardMsg = ""
rm.LiveMainteCnt()
resp.GameStatus, resp.Countdown = rm.getStatus()
return resp
}
func (rm *ColorRoom) LiveGameRankList(buffer []byte) proto.Message {
_ = buffer
return rm.LiveMgr.RankList
}
func (rm *ColorRoom) LiveGameSetDealerName(buffer []byte) proto.Message {
resp := rm.LiveStatus()
if rm.LiveMgr.MaintenanceStatus == 1 {
resp.Code = int32(pb.ColorPinoyLiveProcessError_ColorPinoyLiveProcessErrorMainteStatus)
return resp
}
req := new(pb.ColorPinoyLiveSetDealer)
_ = proto.Unmarshal(buffer, req)
rm.UpdateDealerName(req.DealerName)
log.Debug(rm.Log("set dealer:", req.DealerName))
resp.DealerName = rm.dealerName
return resp
}
// 长度0 维护, 长度1 设置状态 , 长度2 设置排行榜
func (rm *ColorRoom) SetLiveGameStatus(pushRank ...int) {
lScene := &lws.CPLScene{
Status: int32(rm.Status),
RankList: nil,
MaintainStatus: rm.LiveMgr.MaintenanceStatus,
}
if rm.LiveMgr.RankList != nil &&
(rm.Status == pb.ColorPinoyLiveGameStatus_ColorPinoyLiveSettleStatus || rm.Status == pb.ColorPinoyLiveGameStatus_ColorPinoyLiveRankStatus) {
lScene.RankList = &lws.CPLRankList{
PlayerData: nil,
GameNo: rm.LiveMgr.RankList.GameNo,
}
for _, dd := range rm.LiveMgr.RankList.PlayerData {
lScene.RankList.PlayerData = append(lScene.RankList.PlayerData, &lws.CPLPlayerData{
Uid: dd.Uid,
Profit: dd.Profit,
Nickname: dd.Nickname,
Avatar: dd.Avatar,
})
}
}
if len(pushRank) == 0 {
live.PushScene(lScene)
} else if len(pushRank) == 1 {
live.PushStatus(&lws.CPLStatus{Status: lScene.Status})
} else if len(pushRank) == 2 {
live.PushColorRank(lScene.RankList)
}
go redisf.RSC.SetLiveGameStatus(lScene, gconfig.GConfig.GRoomConfig.GameId, gconfig.GConfig.GDataConfig.VersionMode)
}