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

568 lines
12 KiB

package game
import (
"container/list"
"fmt"
"math/rand"
"server/call"
"server/common"
"server/pb"
"server/util"
"strconv"
"sync/atomic"
"time"
"github.com/gogo/protobuf/proto"
"github.com/liangdas/mqant-modules/room"
"github.com/liangdas/mqant/gate"
"github.com/liangdas/mqant/log"
"github.com/liangdas/mqant/module"
timewheel "github.com/liangdas/mqant/module/modules/timer"
)
// 百人游戏主桌子
var (
MainTable *Table
)
type SubTable interface {
Init(t *Table)
Reset()
Enter(p *Player)
StartGame()
Settle()
Destroy()
}
type Table struct {
app module.App
SubTable SubTable
IsDestroy bool
Players map[string]room.BasePlayer
Room *GameRoom
List *TableList
Lists []*TableList
Ele *list.Element
Timer string
RobotTimer string
UUID string
room.QTable
Status pb.GameStatus
OperateTimeout int64
SeatPlayers []*Player // 有座位的玩家
SlicePlayers []*Player // 所有玩家
BetPlayers []*pb.BetPlayers // 本局下注玩家按下注量排序
StartTime int64 // 开局时间
EndTime int64 // 结束时间
ConfigChange bool // 配置修改后,该桌子等玩家打完回收
IsSingle bool // 是否是独立房间
Ran *rand.Rand
Config common.ConfigGameRoom
*MillionSubTable
// *RoomSubTable
}
func (t *Table) Init() {
t.Ran = rand.New(rand.NewSource(time.Now().UnixNano()))
t.SeatPlayers = make([]*Player, t.Config.MaxSeats)
}
func (t *Table) GetSeats() map[string]room.BasePlayer {
return t.Players
}
func (t *Table) GetApp() module.App {
return t.app
}
func (t *Table) OnCreate() {
//可以加载数据
//一定要调用QTable.OnCreate()
t.QTable.OnCreate()
}
func (t *Table) Update(ds time.Duration) {
}
func (t *Table) OnTimeOut() {
if ThisGameType == GameTypeRoom {
t.Debug("OnTimeOut")
t.Finish()
}
}
func (t *Table) Reset() {
t.UUID = ""
t.Status = pb.GameStatus_GameStatusNormal
t.StartTime = 0
t.EndTime = 0
t.BetPlayers = []*pb.BetPlayers{}
t.StopTimer()
// if t.RoomSubTable != nil {
// t.RoomSubTable.Reset()
// }
if t.MillionSubTable != nil {
t.MillionSubTable.Reset()
}
t.SubTable.Reset()
}
func (t *Table) Enter(uid int, s gate.Session, ct common.CurrencyType) {
t.Debug("player %v enter", uid)
// 如果桌子已经销毁,重新分配一张桌子给玩家
if t.IsDestroy {
rid := findRoom(t.Room.RoomId())
if rid == 0 {
rid = findRoom(0)
}
gameRoom := GetRoom(rid)
if gameRoom != nil {
gameRoom.Enter(uid, s, ct)
}
return
}
// 如果玩家已在游戏中,直接返回
p := t.GetPlayer(uid)
if p != nil {
delete(t.Players, p.Session().GetSessionID())
t.Players[s.GetSessionID()] = p
p.Bind(s)
p.IsLeave = false
AllPlayers.Store(uid, p)
util.Go(func() {
p.UpdatePlayerStatus()
})
p.SubPlayer.OnEnter()
return
}
p = NewPlayer(uid, t)
p.GameCurrencyType = ct
p.Bind(s)
t.AddOnePlayer(p)
p.T.SubTable.Enter(p)
p.Enter()
}
func (t *Table) AddOnePlayer(p *Player) {
atomic.AddInt64(t.Room.PlayerCount, 1)
// if !p.IsRobot() {
atomic.AddInt64(PlayerCount, 1)
t.Players[p.Session().GetSessionID()] = p
// } else {
// t.Robots = append(t.Robots, p.Robot)
// t.Players[p.Robot.RobotSessionID] = p
// }
t.SlicePlayers = append(t.SlicePlayers, p)
}
func (t *Table) RemoveOnePlayer(p *Player) {
atomic.AddInt64(t.Room.PlayerCount, -1)
// if !p.IsRobot() {
atomic.AddInt64(PlayerCount, -1)
p.DeleteSeats()
// } else {
// p.Robot.StopTimer()
// if p.Robot.ID > 0 {
// p.Robot.DelRobotPlaying()
// AllRobots.Delete(p.Robot.ID)
// }
// for i := 0; i < len(t.Robots); i++ {
// if t.Robots[i] == p.Robot {
// t.Robots = append(t.Robots[:i], t.Robots[i+1:]...)
// break
// }
// }
// delete(t.GetSeats(), p.Robot.RobotSessionID)
// }
for i := 0; i < len(t.SlicePlayers); i++ {
if t.SlicePlayers[i] == p {
t.SlicePlayers = append(t.SlicePlayers[:i], t.SlicePlayers[i+1:]...)
break
}
}
}
// Broadcast 桌子广播
func (t *Table) Broadcast(pid int, send proto.Message, uid ...int) {
topic := fmt.Sprintf("%v:%v", call.GetTopicName(), pid)
sendP := []string{}
reset := false
for _, v := range t.Players {
p := v.(*Player)
if p.IsLeave || p.IsRobot() {
continue
}
except := false
for _, k := range uid {
if p.UID == k {
except = true
break
}
}
if !except {
reset = true
if p.MillionSubPlayer != nil {
sendP = append(sendP, v.Session().GetSessionID())
} else {
p.Send(pid, send)
}
}
}
if reset {
t.ResetTimeOut()
}
if len(sendP) == 0 {
return
}
body, _ := proto.Marshal(send)
err := t.SendCallBackMsgNR(sendP, topic, body)
if err != nil {
t.Error("err:%v", err)
}
}
func (t *Table) StartGame() {
if t.Status != pb.GameStatus_GameStatusNormal || t.IsDestroy {
return
}
now := time.Now().Unix()
t.StopTimer()
t.Status = pb.GameStatus_GameStatusPlaying
t.StartTime = now
t.UUID = call.SnowNode().Generate().String()
t.Debug("start game")
t.SubTable.StartGame()
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.IsRobot() {
continue
}
p.StartTime = now
p.UUID = t.UUID
}
if len(t.Room.TableList) > 1 {
t.Room.ChangeOne(t)
}
}
func (t *Table) Settle() {
t.Debug("settle,status:%v", t.Status)
if t.Status == pb.GameStatus_GameStatusSettle {
return
}
t.StopTimer()
t.EndTime = time.Now().Unix()
t.Status = pb.GameStatus_GameStatusSettle
t.SubTable.Settle()
if len(t.Room.TableList) > 1 {
t.Room.ChangeOne(t)
}
if t.Room.RoomType == RoomTypePractice {
return
}
if ThisGameType == GameTypeMillion {
t.MillionSubTable.Settle()
}
}
func (t *Table) NF(f func()) {
f()
}
func (t *Table) OnDestroy() {
t.Debug("Destroy")
t.QTable.OnDestroy()
t.IsDestroy = true
t.StopTimer()
for _, v := range t.GetSeats() {
p := v.(*Player)
if !p.IsRobot() && p.TotalBet > 0 && p.Status == pb.PlayerStatus_PlayerStatusPlaying {
p.Debug("destroy return,total:%v", p.TotalBet)
call.UpdateCurrencyPro(&common.UpdateCurrency{
CurrencyBalance: &common.CurrencyBalance{
UID: p.UID,
Event: common.CurrencyEventGameCancelBet,
Type: p.GameCurrencyType,
Value: p.TotalBet,
},
})
}
p.Status = pb.PlayerStatus_PlayerStatusNormal
if p.MillionSubPlayer != nil {
p.TotalBet = 0
}
p.Leave()
}
t.Room.RemoveOne(t)
t.Room.Tables.Delete(t.TableIDInt())
t.SubTable.Destroy()
}
func (t *Table) Leave(session gate.Session) {
player := t.FindPlayer(session)
if player == nil {
return
}
p := player.(*Player)
p.Leave()
}
// 计算当前还在游戏中的玩家
func (t *Table) CountPlayingPlayers() int {
count := 0
for _, v := range t.GetSeats() {
if v.(*Player).Status == pb.PlayerStatus_PlayerStatusPlaying {
count++
}
}
return count
}
func (t *Table) CountRealPlayings() int {
count := 0
for _, v := range t.Players {
if !v.(*Player).IsRobot() && v.(*Player).Status == pb.PlayerStatus_PlayerStatusPlaying {
count++
}
}
return count
}
// 计算参与了游戏的玩家
func (t *Table) CountPlayedPlayers() int {
count := 0
for _, v := range t.GetSeats() {
if v.(*Player).Status != pb.PlayerStatus_PlayerStatusNormal {
count++
}
}
return count
}
func (t *Table) StopTimer() {
t.OperateTimeout = 0
if t.Timer == "" {
return
}
timewheel.GetTimeWheel().RemoveTimer(t.Timer)
t.Timer = ""
}
func (t *Table) GetPlayer(uid int) *Player {
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.UID == uid {
return p
}
}
return nil
}
func (t *Table) TableIDInt() int {
id, _ := strconv.Atoi(t.TableId())
return id
}
// 计算当前还在游戏中的玩家
func (t *Table) GetOnePlaying() *Player {
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.Status == pb.PlayerStatus_PlayerStatusPlaying {
return p
}
}
return nil
}
// 获取一名真实玩家
func (t *Table) GetRealOne() *Player {
for _, v := range t.GetSeats() {
p := v.(*Player)
if !p.IsRobot() {
return p
}
}
return nil
}
// 获取一名玩牌中真实玩家
func (t *Table) GetRealOnePlaying() *Player {
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.Role == common.PlayerRoleNormal && p.Status == pb.PlayerStatus_PlayerStatusPlaying {
return p
}
}
return nil
}
// 获取一名真实玩家
func (t *Table) GetRealPlayings() []*Player {
ret := []*Player{}
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.IsRobot() || p.Status != pb.PlayerStatus_PlayerStatusPlaying {
continue
}
ret = append(ret, p)
}
return ret
}
func (t *Table) CountEmptySeat() int {
count := 0
for i := 0; i < len(t.SeatPlayers); i++ {
if t.SeatPlayers[i] == nil {
count++
}
}
return count
}
func (t *Table) FindEmptySeat() int {
for i := 0; i < len(t.SeatPlayers); i++ {
if t.SeatPlayers[i] == nil {
return i
}
}
return -1
}
func (t *Table) GetLastPlayingPlayer(id int) *Player {
max := len(t.SeatPlayers)
seat := id + max
for i := 0; i < max-1; i++ {
seat--
seatID := seat % max
other := t.SeatPlayers[seatID]
if other != nil && other.Status == pb.PlayerStatus_PlayerStatusPlaying {
return other
}
}
return nil
}
func (t *Table) GetNextPlayingPlayer(seatID int) *Player {
for i := 0; i < len(t.SeatPlayers)-1; i++ {
seatID = (seatID + 1) % len(t.SeatPlayers)
one := t.SeatPlayers[seatID]
if one != nil && one.Status == pb.PlayerStatus_PlayerStatusPlaying {
return one
}
}
return nil
}
// 随机获取一个玩家
func (t *Table) GetRandomPlayer() *Player {
Players := []*Player{}
for _, v := range t.SeatPlayers {
if v == nil || v.Status != pb.PlayerStatus_PlayerStatusPlaying {
continue
}
Players = append(Players, v)
}
return Players[t.Ran.Intn(len(Players))]
}
func (t *Table) GetSeatPlayer(seat int) *Player {
for i, v := range t.SeatPlayers {
if v == nil {
continue
}
if v.SeatID == seat {
return t.SeatPlayers[i]
}
}
return nil
}
func (t *Table) GetOtherPlayer(seat int) *Player {
for i, v := range t.SeatPlayers {
if v == nil || v.SeatID == seat || v.Status != pb.PlayerStatus_PlayerStatusPlaying {
continue
}
return t.SeatPlayers[i]
}
return nil
}
func (t *Table) StartGameTimer(dur time.Duration) {
if t.IsDestroy {
return
}
t.Timer = fmt.Sprintf("startGame_%v", t.TableId())
timewheel.GetTimeWheel().AddTimerCustom(dur, t.Timer, nil, func(arge interface{}) {
t.Debug("startGame timer callback")
t.Put("nf", t.Settle)
})
}
func (t *Table) SettleGameTimer(dur time.Duration) {
if t.IsDestroy {
return
}
t.Timer = fmt.Sprintf("settleGame_%v", t.TableId())
timewheel.GetTimeWheel().AddTimerCustom(dur, t.Timer, nil, func(arge interface{}) {
t.Debug("settleGame timer callback")
t.PutQueue("nf", func() {
t.Reset()
})
})
}
// GetPlayingPlayers 获取本局所有正在游戏中的玩家
func (t *Table) GetPlayingPlayers() []*Player {
ret := []*Player{}
for _, v := range t.GetSeats() {
p := v.(*Player)
if p.Status != pb.PlayerStatus_PlayerStatusPlaying {
continue
}
ret = append(ret, p)
}
return ret
}
// Debug 封装桌子打印日志方法
func (t *Table) Debug(fomat string, a ...interface{}) {
log.Debug("uuid:%v,roomID:%v,tableID:%v,"+fomat, append([]interface{}{t.UUID, t.Room.RoomId(), t.TableId()}, a...)...)
}
// Error 封装桌子打印日志方法
func (t *Table) Error(fomat string, a ...interface{}) {
log.Error("uuid:%v,roomID:%v,tableID:%v,"+fomat, append([]interface{}{t.UUID, t.Room.RoomId(), t.TableId()}, a...)...)
}
func (t *Table) Put(_func string, params ...interface{}) {
for i := 0; i < 3; i++ {
err := t.PutQueue(_func, params...)
if err == nil {
return
}
log.Error("err:%v", err)
}
}
func (t *Table) GetRealBet() int64 {
var realBet int64
for _, v := range t.Players {
p := v.(*Player)
if p.IsRobot() {
continue
}
realBet += p.TotalBet
}
return realBet
}
// ChangeConfig 配置改变
func (t *Table) ChangeConfig() {
t.Debug("config change")
t.PutQueue("nf", func() {
t.ConfigChange = true
})
}