You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
512 lines
12 KiB
512 lines
12 KiB
package game |
|
|
|
import ( |
|
"fmt" |
|
"server/call" |
|
"server/common" |
|
"server/config" |
|
"server/db" |
|
"server/natsClient" |
|
"server/pb" |
|
"server/util" |
|
"sync" |
|
"time" |
|
|
|
"github.com/gogo/protobuf/proto" |
|
"github.com/liangdas/mqant-modules/room" |
|
"github.com/liangdas/mqant/gate" |
|
"github.com/liangdas/mqant/log" |
|
timewheel "github.com/liangdas/mqant/module/modules/timer" |
|
"gorm.io/gorm" |
|
) |
|
|
|
var ( |
|
// MatchingPlayers sync.Map |
|
AllPlayers sync.Map |
|
AllRobots sync.Map |
|
PlayerCount *int64 = new(int64) |
|
) |
|
|
|
type SubPlayer interface { |
|
Enter() |
|
OnEnter() |
|
Leave() bool |
|
Reset() |
|
Settle() |
|
TableInfo() |
|
} |
|
|
|
type Player struct { |
|
SubPlayer SubPlayer |
|
T *Table |
|
*room.BasePlayerImp |
|
UID int |
|
SeatID int |
|
Timer string |
|
Role int |
|
*common.PlayerDBInfo |
|
// Currency *common.PlayerCurrency |
|
Balance int64 |
|
Status pb.PlayerStatus |
|
IsLeave bool |
|
StartTime int64 |
|
|
|
GameCurrencyType common.CurrencyType // 本局参与游戏的货币类型 |
|
FinalSettle int64 |
|
TotalBet int64 |
|
UUID string |
|
*MillionSubPlayer |
|
// *RoomSubPlayer |
|
// *SlotPlayer |
|
} |
|
|
|
func GetPlayer(uid int) *Player { |
|
p, ok := AllPlayers.Load(uid) |
|
if !ok { |
|
return nil |
|
} |
|
return p.(*Player) |
|
} |
|
|
|
func NewPlayer(uid int, t *Table) *Player { |
|
p := &Player{UID: uid, T: t, BasePlayerImp: &room.BasePlayerImp{}, SeatID: -1} |
|
p.Status = pb.PlayerStatus_PlayerStatusNormal |
|
return p |
|
} |
|
|
|
func (p *Player) Refresh(session gate.Session) { |
|
p.IsLeave = false |
|
if p.Session().GetSessionID() != session.GetSessionID() { |
|
delete(p.T.Players, p.Session().GetSessionID()) |
|
p.T.Players[session.GetSessionID()] = p |
|
p.Bind(session) |
|
} |
|
} |
|
|
|
func (p *Player) Enter() { |
|
uid := p.UID |
|
AllPlayers.Store(uid, p) |
|
util.Go(func() { |
|
p.PlayerDBInfo, _ = call.GetUserXInfo(uid, "role", "nick", "avatar", "channel_id", "birth", "mobile") |
|
// p.Currency = &common.PlayerCurrency{UID: uid} |
|
// db.Mysql().Get(p.Currency) |
|
p.Balance = call.GetUserCurrencyTotal(p.UID, p.GameCurrencyType) |
|
p.UpdatePlayerStatus() |
|
p.T.PutQueue("nf", func() { |
|
p.Send(int(pb.GameProtocol_EnterGameResp), &pb.GameCommonResp{}) |
|
// 如果是房间模式,玩家进入后自动找位置坐下 |
|
// if p.RoomSubPlayer != nil { |
|
// p.RoomSubPlayer.Enter() |
|
// } |
|
p.SubPlayer.Enter() |
|
}) |
|
}) |
|
} |
|
|
|
// Send 发送消息 |
|
func (p *Player) Send(pid int, send proto.Message) { |
|
if p.IsLeave || p.IsRobot() { |
|
return |
|
} |
|
p.OnResponse(p.Session()) |
|
topic := fmt.Sprintf("%v:%v", call.GetTopicName(), pid) |
|
body, _ := proto.Marshal(send) |
|
if err := p.T.SendCallBackMsgNR([]string{p.Session().GetSessionID()}, topic, body); err != nil { |
|
p.Error("err:%v", err) |
|
} |
|
} |
|
|
|
// SendWithModule 发送消息 |
|
func (p *Player) SendWithModule(module string, pid int, send proto.Message) { |
|
if p.IsLeave || p.IsRobot() { |
|
return |
|
} |
|
p.OnResponse(p.Session()) |
|
topic := fmt.Sprintf("%v:%v", module, pid) |
|
body, _ := proto.Marshal(send) |
|
if err := p.T.SendCallBackMsgNR([]string{p.Session().GetSessionID()}, topic, body); err != nil { |
|
p.Error("err:%v", err) |
|
} |
|
} |
|
|
|
// StopTimer 开始准备倒计时 |
|
func (p *Player) StopTimer() { |
|
if p.Timer != "" { |
|
timewheel.GetTimeWheel().RemoveTimer(p.Timer) |
|
p.Timer = "" |
|
} |
|
} |
|
|
|
func (p *Player) Reset() { |
|
p.StopTimer() |
|
p.Status = pb.PlayerStatus_PlayerStatusNormal |
|
p.FinalSettle = 0 |
|
p.TotalBet = 0 |
|
p.UUID = "" |
|
// if p.RoomSubPlayer != nil { |
|
// p.RoomSubPlayer.Reset() |
|
// } |
|
if p.MillionSubPlayer != nil { |
|
p.MillionSubPlayer.Reset() |
|
} |
|
// if p.SlotPlayer != nil { |
|
// p.SlotPlayer.Reset() |
|
// } |
|
p.SubPlayer.Reset() |
|
} |
|
|
|
func (p *Player) DelAllPlayers() { |
|
player, ok := AllPlayers.Load(p.UID) |
|
if !ok { |
|
return |
|
} |
|
ap := player.(*Player) |
|
if p == ap { |
|
AllPlayers.Delete(p.UID) |
|
} |
|
} |
|
|
|
func (p *Player) IsRobot() bool { |
|
return p.Role == common.PlayerRoleRobot |
|
} |
|
|
|
func (p *Player) Leave() { |
|
t := p.T |
|
if p.Status == pb.PlayerStatus_PlayerStatusLeave { |
|
return |
|
} |
|
p.Debug("leave table") |
|
// p.SettleShouldSend = true |
|
if !p.SubPlayer.Leave() { |
|
return |
|
} |
|
p.DelAllPlayers() |
|
if p.SeatID >= 0 { |
|
t.SeatPlayers[p.SeatID] = nil |
|
} |
|
p.Status = pb.PlayerStatus_PlayerStatusLeave |
|
p.StopTimer() |
|
|
|
t.RemoveOnePlayer(p) |
|
|
|
if len(t.Room.TableList) > 1 { |
|
// 处理一下list |
|
t.Room.MineOne(t) |
|
} |
|
p.Debug("finish leave table") |
|
|
|
// if t.Status == TableStatusPlaying { |
|
// return |
|
// } |
|
|
|
// if !p.IsRobot() && t.IsSingle && t.CountReal() == 0 { |
|
// if ThisGameType == GameTypeMillion { |
|
// t.Finish() |
|
// return |
|
// } |
|
// t.RobotLeave() |
|
// t.StopRobotTimer() |
|
// t.Reset() |
|
// t.Debug("push back to single queue") |
|
// // 该房间空置后,重新丢回队列使用 |
|
// t.Room.Queue.AddQueue(func() { |
|
// t.Ele = t.Room.TableListSingle.PushBack(t) |
|
// t.List = t.Room.TableListSingle |
|
// }) |
|
// } |
|
} |
|
|
|
func (p *Player) SendReal(pid int, resp proto.Message) { |
|
if p.IsRobot() || p.IsLeave { |
|
return |
|
} |
|
p.OnResponse(p.Session()) |
|
body, _ := proto.Marshal(resp) |
|
call.SendSSBytes(p.Session(), pid, body) |
|
} |
|
|
|
func (p *Player) Disconnect() { |
|
p.Debug("disconnect") |
|
// p.IsLeave = true |
|
// if p.MillionSubPlayer != nil { |
|
// p.IsAuto = false |
|
// } |
|
// // slot游戏重连直接退出房间 |
|
// if p.SlotPlayer != nil { |
|
p.Leave() |
|
// } |
|
} |
|
|
|
// PackBalance 统一封装流水记录 |
|
func (p *Player) PackUpdate(data *common.UpdateCurrency) { |
|
t := p.T |
|
uuid := t.UUID |
|
if uuid == "" { |
|
uuid = p.UUID |
|
} |
|
data.UID = p.UID |
|
data.Exi1 = ThisGameID |
|
data.Exi2 = t.Room.RoomId() |
|
data.Exs1 = uuid |
|
data.ChannelID = p.ChannelID |
|
} |
|
|
|
// PackBalance 统一封装流水记录 |
|
func (p *Player) PackBalance(data *common.CurrencyBalance) { |
|
t := p.T |
|
data.UID = p.UID |
|
data.ChannelID = p.ChannelID |
|
data.Exs1 = p.UUID |
|
if data.Exs1 == "" { |
|
data.Exs1 = t.UUID |
|
} |
|
data.Exi1 = ThisGameID |
|
data.Exi2 = t.Room.RoomId() |
|
data.Time = time.Now().Unix() |
|
} |
|
|
|
// Settle 统一结算 |
|
func (p *Player) Settle() { |
|
t := p.T |
|
if p.Status != pb.PlayerStatus_PlayerStatusPlaying { |
|
return |
|
} |
|
p.Debug("settle") |
|
p.StopTimer() |
|
p.SubPlayer.Settle() |
|
p.Status = pb.PlayerStatus_PlayerStatusSettle |
|
if t.Room.RoomType == RoomTypePractice { |
|
return |
|
} |
|
// slot玩法直接reset |
|
// if p.SlotPlayer != nil { |
|
// if p.DBFreeCount == 0 { |
|
// p.AfterSettle() |
|
// } |
|
// p.Reset() |
|
// } else { |
|
p.AfterSettle() |
|
// } |
|
} |
|
|
|
// AfterSettle 结算后检查一些数据 |
|
func (p *Player) AfterSettle() { |
|
if p.IsRobot() { |
|
return |
|
} |
|
// 写入统计 |
|
// p.WriteStats() |
|
// 检查房间水位 |
|
p.CalWater() |
|
|
|
// 结算后,处理活动等逻辑 |
|
if p.UUID == "" { |
|
p.UUID = p.T.UUID |
|
} |
|
now := time.Now().Unix() |
|
if p.StartTime == 0 { |
|
p.StartTime = p.T.StartTime |
|
} |
|
data := &pb.InnerAfterSettle{ |
|
UID: int64(p.UID), |
|
ProviderID: common.ProviderInhouse, |
|
GameID: int64(ThisGameID), |
|
TotalBet: p.TotalBet, |
|
OriginSettle: p.FinalSettle, |
|
FinalSettle: p.FinalSettle, |
|
Phone: p.Mobile, |
|
UUID: p.UUID, |
|
Nick: p.Nick, |
|
MyUUID: p.UUID, |
|
CurrencyType: int64(p.GameCurrencyType), |
|
IsNew: util.IsSameDayTimeStamp(now, p.Birth), |
|
SubID: int64(p.T.Room.RoomId()), |
|
PlayTime: now - p.StartTime, |
|
} |
|
|
|
util.IndexTryS(func() error { |
|
return call.Publish(natsClient.TopicInnerAfterSettle, data) |
|
}) |
|
} |
|
|
|
// CalWater 计算水位 |
|
func (p *Player) CalWater() { |
|
gid := ThisGameID |
|
rid := p.T.Room.RoomId() |
|
conf := call.GetConfigWaterReal(gid, rid) |
|
// 未发生控制,则更新房间水位 |
|
if conf != nil { |
|
add := p.FinalSettle |
|
// if conf.RebatePer != 100 { |
|
// add = add * conf.RebatePer / 100 |
|
// } |
|
// field := "brl" |
|
// if p.GameCurrencyType == common.CurrencyUSDT { |
|
// field = "usdt" |
|
// } |
|
db.Mysql().Update(&common.ConfigWater{GameID: gid, RoomID: rid}, map[string]interface{}{"value": gorm.Expr(fmt.Sprintf("value + %d", add))}) |
|
} |
|
} |
|
|
|
// Debug 封装玩家打印日志方法(机器人也会打印) |
|
func (p *Player) DebugA(fomat string, a ...interface{}) { |
|
t := p.T |
|
log.Debug("uuid:%v,roomID:%v,tableID:%v,player:%v,"+fomat, append([]interface{}{t.UUID, t.Room.RoomId(), t.TableId(), p.UID}, a...)...) |
|
} |
|
|
|
// Debug 封装玩家打印日志方法 |
|
func (p *Player) Debug(fomat string, a ...interface{}) { |
|
if p.IsRobot() { |
|
return |
|
} |
|
t := p.T |
|
log.Debug("uuid:%v,roomID:%v,tableID:%v,player:%v,"+fomat, append([]interface{}{t.UUID, t.Room.RoomId(), t.TableId(), p.UID}, a...)...) |
|
} |
|
|
|
// Error 封装玩家打印日志方法 |
|
func (p *Player) Error(fomat string, a ...interface{}) { |
|
if p.IsRobot() { |
|
return |
|
} |
|
t := p.T |
|
log.Error("uuid:%v,roomID:%v,tableID:%v,player:%v,"+fomat, append([]interface{}{t.UUID, t.Room.RoomId(), t.TableId(), p.UID}, a...)...) |
|
} |
|
|
|
// WriteStats 写入新的统计记录 |
|
func (p *Player) WriteStats() { |
|
t := p.T |
|
now := time.Now().Unix() |
|
if p.StartTime == 0 { |
|
p.StartTime = t.StartTime |
|
} |
|
if p.UUID == "" { |
|
p.UUID = t.UUID |
|
} |
|
pt := now - p.StartTime |
|
st := &common.ESGameData{PlayTime: pt} |
|
st.UID = p.UID |
|
st.Channel = p.ChannelID |
|
st.Provider = common.ProviderInhouse |
|
st.GameID = ThisGameID |
|
st.UUID = p.UUID |
|
st.Type = p.GameCurrencyType |
|
st.BetAmount = p.TotalBet |
|
st.SettleAmount = p.FinalSettle |
|
st.MyUUID = p.UUID |
|
st.Time = now |
|
st.Birth = p.Birth |
|
st.SubID = t.Room.RoomId() |
|
st.IsNew = util.IsSameDayTimeStamp(now, p.Birth) |
|
call.UpdatePlayerProfile(st) |
|
} |
|
|
|
func (p *Player) DeleteSeats() { |
|
t := p.T |
|
if _, ok := t.GetSeats()[p.Session().GetSessionID()]; ok { |
|
delete(t.GetSeats(), p.Session().GetSessionID()) |
|
} else { |
|
for k, v := range t.GetSeats() { |
|
if v.(*Player).UID == p.UID { |
|
delete(t.GetSeats(), k) |
|
break |
|
} |
|
} |
|
} |
|
} |
|
|
|
// 房间控制 |
|
// func (p *Player) CheckWaterControl() (is bool) { |
|
// conf := call.GetConfigWaterReal(ThisGameID, p.T.Room.RoomId()) |
|
// if conf == nil { |
|
// return false |
|
// } |
|
// // 根据触发概率判断是否触发房间控制 |
|
// if conf.RebatePer <= 0 || p.T.Ran.Intn(100)+1 > conf.ControlPer { |
|
// return |
|
// } |
|
|
|
// // 当前水位 |
|
// water := conf.Value |
|
// up := conf.WaterUp * 100 |
|
// down := conf.WaterLower * 100 |
|
|
|
// // 水位大于上限 放 |
|
// if water > up { |
|
// is = true |
|
// } |
|
|
|
// // 水位小于下限 杀 |
|
// if water <= down { |
|
// is = true |
|
// } |
|
// return |
|
// } |
|
|
|
func (p *Player) UpdatePlayerStatus() { |
|
one := common.PlayerStatus{ |
|
GameID: ThisGameID, |
|
ModuleName: call.GetCaller().GetType(), |
|
SubID: p.T.Room.RoomId(), |
|
WorkID: config.GetConfig().WorkID, |
|
TableID: p.T.TableId(), |
|
} |
|
if err := db.Redis().HSet(common.GetRedisKeyPlayerStatus(p.UID), one); err != nil { |
|
p.Error("err:%v", err) |
|
} |
|
} |
|
|
|
func (p *Player) DelPlayerStatus() { |
|
one := new(common.PlayerStatus) |
|
if err := db.Redis().HGetAll(common.GetRedisKeyPlayerStatus(p.UID), one); err != nil { |
|
return |
|
} |
|
if one.TableID == p.T.TableId() && one.GameID == ThisGameID { |
|
db.Redis().Delkey(common.GetRedisKeyPlayerStatus(p.UID)) |
|
} |
|
} |
|
|
|
func (p *Player) PackTableInfo(tableInfo *pb.GameCommonTableInfo) { |
|
tableInfo.User = &pb.GameUser{ |
|
UID: int64(p.UID), |
|
Nick: p.Nick, |
|
Avatar: p.Avatar, |
|
CurrencyType: int64(p.GameCurrencyType), |
|
Balance: p.Balance, |
|
Bet: p.TotalBet, |
|
Status: p.Status, |
|
} |
|
tableInfo.List = p.T.BetPlayers |
|
tableInfo.Status = p.T.Status |
|
tableInfo.TimeLeft = p.T.OperateTimeout - time.Now().UnixMilli() |
|
if tableInfo.TimeLeft < 0 { |
|
tableInfo.TimeLeft = 0 |
|
} |
|
tableInfo.BetLimit = p.T.Config.BetLimit |
|
tableInfo.History = p.T.History |
|
} |
|
|
|
func (p *Player) GetPlayerBetList() { |
|
t := p.T |
|
resp := &pb.GameMsgBetListResp{ |
|
List: t.BetPlayers, |
|
} |
|
p.Send(int(pb.GameProtocol_BetListResp), resp) |
|
} |
|
|
|
func (p *Player) UpdateBetList() { |
|
t := p.T |
|
bet := p.TotalBet |
|
for i := range t.BetPlayers { |
|
if t.BetPlayers[i].UID == int64(p.UID) { |
|
t.BetPlayers[i].BetAmount = bet |
|
return |
|
} |
|
} |
|
t.BetPlayers = append(t.BetPlayers, &pb.BetPlayers{ |
|
UID: int64(p.UID), |
|
Avatar: p.Avatar, |
|
Nick: p.Nick, |
|
CurrencyType: int64(p.GameCurrencyType), |
|
BetAmount: bet, |
|
}) |
|
}
|
|
|