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.
513 lines
12 KiB
513 lines
12 KiB
|
1 year ago
|
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,
|
||
|
|
})
|
||
|
|
}
|