印度包网
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

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,
})
}