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.
439 lines
10 KiB
439 lines
10 KiB
|
1 year ago
|
package game
|
||
|
|
|
||
|
|
import (
|
||
|
|
"container/list"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"math"
|
||
|
|
"reflect"
|
||
|
|
"server/call"
|
||
|
|
"server/common"
|
||
|
|
"server/pb"
|
||
|
|
"sync"
|
||
|
|
|
||
|
|
"github.com/liangdas/mqant-modules/room"
|
||
|
|
"github.com/liangdas/mqant/gate"
|
||
|
|
"github.com/liangdas/mqant/log"
|
||
|
|
"github.com/liangdas/mqant/module"
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
RoomMap sync.Map
|
||
|
|
tableIndex uint = 1
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
RoomTypeCash = iota + 1
|
||
|
|
RoomTypePractice
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
GameTypeRoom = iota + 1 // 房间模式
|
||
|
|
GameTypeMillion // 百人场
|
||
|
|
)
|
||
|
|
|
||
|
|
type GameRoom struct {
|
||
|
|
Config *common.ConfigGameRoom
|
||
|
|
NewSubTable func() SubTable
|
||
|
|
Queue *call.ExecQueue
|
||
|
|
SubAdd func(t *Table)
|
||
|
|
SubMine func(t *Table)
|
||
|
|
*room.Room
|
||
|
|
PlayerCount *int64
|
||
|
|
Cards []int
|
||
|
|
TableList []*TableList
|
||
|
|
TableListPlaying []*TableList
|
||
|
|
TableListSingle *TableList // 单独匹配的房间,玩家与机器人游戏
|
||
|
|
RoomType int // 练习场/cash场
|
||
|
|
RoomName string
|
||
|
|
Tables sync.Map
|
||
|
|
}
|
||
|
|
|
||
|
|
type TableList struct {
|
||
|
|
*list.List
|
||
|
|
Index int
|
||
|
|
}
|
||
|
|
|
||
|
|
func GetRoom(id int) *GameRoom {
|
||
|
|
r, ok := RoomMap.Load(id)
|
||
|
|
if !ok {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return r.(*GameRoom)
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRoom(c *common.ConfigGameRoom) *GameRoom {
|
||
|
|
app := call.GetCaller().GetApp()
|
||
|
|
roomID := c.RoomID
|
||
|
|
roomType := c.RoomType
|
||
|
|
roomName := c.RoomName
|
||
|
|
// max := c.MaxPlayer
|
||
|
|
r := &GameRoom{
|
||
|
|
Room: room.NewRoom(app),
|
||
|
|
Config: c,
|
||
|
|
PlayerCount: new(int64),
|
||
|
|
NewSubTable: NewTable,
|
||
|
|
RoomType: roomType,
|
||
|
|
Queue: call.NewQueue(),
|
||
|
|
RoomName: roomName,
|
||
|
|
}
|
||
|
|
r.OnInit(app, roomID)
|
||
|
|
|
||
|
|
// r.GetMatchConfig()
|
||
|
|
// r.GetBroadcastConfig()
|
||
|
|
// r.GetWaterConfig()
|
||
|
|
|
||
|
|
// if ThisGameType == GameTypeRoom {
|
||
|
|
// for i := 0; i < max; i++ {
|
||
|
|
// list := list.New()
|
||
|
|
// r.TableList = append(r.TableList, &TableList{List: list, Index: i})
|
||
|
|
// }
|
||
|
|
// for i := 0; i < max; i++ {
|
||
|
|
// list := list.New()
|
||
|
|
// r.TableListPlaying = append(r.TableListPlaying, &TableList{List: list, Index: i})
|
||
|
|
// }
|
||
|
|
// } else if ThisGameType == GameTypeMillion {
|
||
|
|
r.TableList = append(r.TableList, &TableList{List: list.New(), Index: 0})
|
||
|
|
// }
|
||
|
|
r.TableListSingle = &TableList{List: list.New()}
|
||
|
|
RoomMap.Store(roomID, r)
|
||
|
|
return r
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) Reload(c *common.ConfigGameRoom) {
|
||
|
|
// 标识桌子配置有改动
|
||
|
|
r.Queue.AddQueue(func() {
|
||
|
|
r.Config = c
|
||
|
|
// r.GetMatchConfig()
|
||
|
|
// r.GetBroadcastConfig()
|
||
|
|
// if r.GameType == common.GameTypeRoom {
|
||
|
|
// l := len(r.TableList)
|
||
|
|
// diff := c.MaxPlayer - l
|
||
|
|
// if diff > 0 {
|
||
|
|
// for i := 0; i < diff; i++ {
|
||
|
|
// list := list.New()
|
||
|
|
// r.TableList = append(r.TableList, &TableList{List: list, Index: i + l})
|
||
|
|
// }
|
||
|
|
// for i := 0; i < diff; i++ {
|
||
|
|
// list := list.New()
|
||
|
|
// r.TableListPlaying = append(r.TableListPlaying, &TableList{List: list, Index: i + l})
|
||
|
|
// }
|
||
|
|
// } else if diff < 0 {
|
||
|
|
// if c.MaxPlayer == 0 {
|
||
|
|
// r.TableList = nil
|
||
|
|
// r.TableListPlaying = nil
|
||
|
|
// } else {
|
||
|
|
// r.TableList = r.TableList[:l+diff]
|
||
|
|
// r.TableListPlaying = r.TableListPlaying[:l+diff]
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
r.Tables.Range(func(key, value interface{}) bool {
|
||
|
|
t := value.(*Table)
|
||
|
|
t.ChangeConfig()
|
||
|
|
return true
|
||
|
|
})
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) GetTableID() string {
|
||
|
|
if tableIndex > math.MaxUint32 {
|
||
|
|
tableIndex = 2
|
||
|
|
}
|
||
|
|
t := tableIndex
|
||
|
|
tableIndex++
|
||
|
|
return fmt.Sprintf("%v", t)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) Enter(uid int, session gate.Session, ct common.CurrencyType, tid ...int) {
|
||
|
|
// 顺序进入游戏
|
||
|
|
r.Queue.AddQueue(func() {
|
||
|
|
var err error
|
||
|
|
if ThisGameType == GameTypeMillion {
|
||
|
|
err = r.MatchMillionTable(uid, session, ct)
|
||
|
|
}
|
||
|
|
// else {
|
||
|
|
// err = r.Match(uid, tid...)
|
||
|
|
// }
|
||
|
|
if err != nil {
|
||
|
|
call.SendNR(uid, int(pb.GameProtocol_EnterGameResp), &pb.GameCommonResp{Result: 1})
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) NewTable(module module.App, tableId string) (room.BaseTable, error) {
|
||
|
|
t := &Table{
|
||
|
|
app: module,
|
||
|
|
Room: r,
|
||
|
|
Players: map[string]room.BasePlayer{},
|
||
|
|
Config: *r.Config,
|
||
|
|
}
|
||
|
|
opts := []room.Option{
|
||
|
|
room.TableId(tableId),
|
||
|
|
room.DestroyCallbacks(func(table room.BaseTable) error {
|
||
|
|
log.Info("回收了房间: %v", table.TableId())
|
||
|
|
_ = r.DestroyTable(table.TableId())
|
||
|
|
return nil
|
||
|
|
}),
|
||
|
|
}
|
||
|
|
opts = append(opts, room.TimeOut(1200))
|
||
|
|
if ThisGameType == GameTypeMillion {
|
||
|
|
opts = append(opts, room.Capaciity(2000))
|
||
|
|
opts = append(opts, room.SendMsgCapaciity(2000))
|
||
|
|
}
|
||
|
|
opts = append(opts, room.Update(t.Update))
|
||
|
|
opts = append(opts, room.NoFound(func(msg *room.QueueMsg) (value reflect.Value, e error) {
|
||
|
|
//return reflect.ValueOf(t.doSay), nil
|
||
|
|
return reflect.Zero(reflect.ValueOf("").Type()), errors.New("no found handler")
|
||
|
|
}))
|
||
|
|
opts = append(opts, room.SetRecoverHandle(func(msg *room.QueueMsg, err error) {
|
||
|
|
|
||
|
|
log.Error("Recover %v Error: %v", msg.Func, err.Error())
|
||
|
|
}))
|
||
|
|
opts = append(opts, room.SetErrorHandle(func(msg *room.QueueMsg, err error) {
|
||
|
|
log.Error("Error %v Error: %v", msg.Func, err.Error())
|
||
|
|
}))
|
||
|
|
t.OnInit(t, opts...)
|
||
|
|
t.Register("nf", t.NF) // 下一帧执行
|
||
|
|
return t, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func FindTable(uid int) *Table {
|
||
|
|
data, ok := AllPlayers.Load(uid)
|
||
|
|
if !ok {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
p := data.(*Player)
|
||
|
|
return p.T
|
||
|
|
}
|
||
|
|
|
||
|
|
func FindPlayer(session gate.Session) *Player {
|
||
|
|
uid := int(session.GetUserIdInt64())
|
||
|
|
data, ok := AllPlayers.Load(uid)
|
||
|
|
if !ok {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
p := data.(*Player)
|
||
|
|
p.T.PutQueue("nf", func() {
|
||
|
|
p.Refresh(session)
|
||
|
|
})
|
||
|
|
return p
|
||
|
|
}
|
||
|
|
|
||
|
|
// AddOne 保证在queue中运行
|
||
|
|
func (r *GameRoom) AddOne(t *Table) {
|
||
|
|
if len(t.Lists) == 0 {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if r.SubAdd != nil {
|
||
|
|
r.SubAdd(t)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
log.Debug("table %v add one,list:%+v", t.TableId(), t.List)
|
||
|
|
list := t.List
|
||
|
|
lists := t.Lists
|
||
|
|
// 当前列表已清空
|
||
|
|
if list == nil {
|
||
|
|
list = lists[0]
|
||
|
|
t.List = list
|
||
|
|
t.Ele = list.PushBack(t)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
list.Remove(t.Ele)
|
||
|
|
t.List = nil
|
||
|
|
index := list.Index
|
||
|
|
if index != len(lists)-1 {
|
||
|
|
t.List = lists[index+1]
|
||
|
|
t.Ele = lists[index+1].PushBack(t)
|
||
|
|
}
|
||
|
|
log.Debug("table %v finish add one,list:%+v", t.TableId(), t.List)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) MineOne(t *Table) {
|
||
|
|
if len(t.Lists) == 0 {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
r.Queue.AddQueue(func() {
|
||
|
|
log.Debug("table %v mine one,list:%+v", t.TableId(), t.List)
|
||
|
|
if r.SubMine != nil {
|
||
|
|
r.SubMine(t)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
list := t.List
|
||
|
|
lists := t.Lists
|
||
|
|
// 当前是满人状态
|
||
|
|
if list == nil {
|
||
|
|
newList := lists[len(lists)-1]
|
||
|
|
t.List = newList
|
||
|
|
t.Ele = newList.PushBack(t)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
index := list.Index
|
||
|
|
list.Remove(t.Ele)
|
||
|
|
// 当前已在第一个列表
|
||
|
|
if index > 0 {
|
||
|
|
newList := lists[index-1]
|
||
|
|
t.List = newList
|
||
|
|
t.Ele = newList.PushBack(t)
|
||
|
|
}
|
||
|
|
log.Debug("table %v finish mine one,list:%+v", t.TableId(), t.List)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// ChangeOne 换到另一个list
|
||
|
|
func (r *GameRoom) ChangeOne(t *Table) {
|
||
|
|
if len(t.Lists) == 0 || len(r.TableListPlaying) == 0 {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
r.Queue.AddQueue(func() {
|
||
|
|
target := r.TableList
|
||
|
|
if t.Lists[0] == r.TableList[0] {
|
||
|
|
target = r.TableListPlaying
|
||
|
|
}
|
||
|
|
t.Lists = target
|
||
|
|
list := t.List
|
||
|
|
if list == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
list.Remove(t.Ele)
|
||
|
|
index := list.Index
|
||
|
|
newList := target[index]
|
||
|
|
t.List = newList
|
||
|
|
t.Ele = newList.PushBack(t)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) RemoveOne(table *Table) {
|
||
|
|
r.Queue.AddQueue(func() {
|
||
|
|
list := table.List
|
||
|
|
if list == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
list.Remove(table.Ele)
|
||
|
|
table.List = nil
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// func (r *GameRoom) Match(uid int, tid ...int) error {
|
||
|
|
// log.Debug("GameRoom %v match:%v", r.RoomId(), uid)
|
||
|
|
// find := false
|
||
|
|
// con := r.MatchConfig
|
||
|
|
// // 单人匹配
|
||
|
|
// if con[0].MatchType == common.MatchTypeSingle {
|
||
|
|
// for e := r.TableListSingle.Front(); e != nil; e = e.Next() {
|
||
|
|
// table := e.Value.(*Table)
|
||
|
|
// log.Debug("single player %v checking table %v", uid, table.TableId())
|
||
|
|
// find = true
|
||
|
|
// r.TableListSingle.Remove(e)
|
||
|
|
// table.Run()
|
||
|
|
// table.PutQueue("enter", uid)
|
||
|
|
// break
|
||
|
|
// }
|
||
|
|
// if !find {
|
||
|
|
// r.CreateAndEnterTable(uid, true)
|
||
|
|
// }
|
||
|
|
// return nil
|
||
|
|
// }
|
||
|
|
|
||
|
|
// // 根据匹配策略顺序匹配
|
||
|
|
// for _, v := range con {
|
||
|
|
// // if v.TableState == 0 {
|
||
|
|
// // continue
|
||
|
|
// // }
|
||
|
|
// list := r.TableList
|
||
|
|
// if v.TableState == 2 {
|
||
|
|
// list = r.TableListPlaying
|
||
|
|
// }
|
||
|
|
// empty := v.EmptyPositionNumber[0]
|
||
|
|
// if empty < 1 || empty > len(list) {
|
||
|
|
// continue
|
||
|
|
// }
|
||
|
|
// l := list[len(list)-empty]
|
||
|
|
// // l.Lock()
|
||
|
|
// log.Debug("index:%v,mc:%+v", len(list)-empty, v)
|
||
|
|
// for e := l.Front(); e != nil; e = e.Next() {
|
||
|
|
// table := e.Value.(*Table)
|
||
|
|
// log.Debug("player %v checking table %v", uid, table.TableId())
|
||
|
|
// if tid != nil && table.TableIDInt() == tid[0] {
|
||
|
|
// continue
|
||
|
|
// }
|
||
|
|
// // 屏蔽自己提前离开的房间
|
||
|
|
// if p := table.GetPlayer(uid); p != nil {
|
||
|
|
// continue
|
||
|
|
// }
|
||
|
|
// find = true
|
||
|
|
// // 如果存在队列则处理一下队列
|
||
|
|
// if len(r.TableList) > 1 {
|
||
|
|
// r.AddOne(table)
|
||
|
|
// }
|
||
|
|
// // table.Run()
|
||
|
|
// table.PutQueue("enter", uid)
|
||
|
|
// break
|
||
|
|
// }
|
||
|
|
// if find {
|
||
|
|
// break
|
||
|
|
// }
|
||
|
|
// // l.Unlock()
|
||
|
|
// }
|
||
|
|
|
||
|
|
// // 创建房间
|
||
|
|
// if !find {
|
||
|
|
// r.CreateAndEnterTable(uid, false)
|
||
|
|
// }
|
||
|
|
// return nil
|
||
|
|
// }
|
||
|
|
|
||
|
|
// MatchMillionTable 百人场进场方式
|
||
|
|
func (r *GameRoom) MatchMillionTable(uid int, session gate.Session, ct common.CurrencyType) error {
|
||
|
|
log.Debug("GameRoom %v match:%v,ct:%v", r.RoomId(), uid, ct)
|
||
|
|
find := false
|
||
|
|
for i := 0; i < len(r.TableList); i++ {
|
||
|
|
l := r.TableList[i].List
|
||
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
||
|
|
table := e.Value.(*Table)
|
||
|
|
find = true
|
||
|
|
table.PutQueue("nf", func() {
|
||
|
|
table.Enter(uid, session, ct)
|
||
|
|
})
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建房间
|
||
|
|
if !find {
|
||
|
|
r.CreateAndEnterTable(uid, session, ct, false)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *GameRoom) CreateAndEnterTable(uid int, session gate.Session, ct common.CurrencyType, isSingle bool) {
|
||
|
|
table, err := r.CreateById(call.GetCaller().GetApp(), r.GetTableID(), r.NewTable)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
log.Debug("create table:%v isSingle:%v", table.TableId(), isSingle)
|
||
|
|
t := table.(*Table)
|
||
|
|
sub := r.NewSubTable()
|
||
|
|
sub.Init(t)
|
||
|
|
t.SubTable = sub
|
||
|
|
t.Init()
|
||
|
|
t.IsSingle = isSingle
|
||
|
|
t.Reset()
|
||
|
|
if !isSingle {
|
||
|
|
if ThisGameType == GameTypeMillion {
|
||
|
|
t.List = r.TableList[0]
|
||
|
|
t.Ele = r.TableList[0].PushBack(t)
|
||
|
|
} else {
|
||
|
|
t.List = r.TableList[1]
|
||
|
|
t.Ele = r.TableList[1].PushBack(t)
|
||
|
|
t.Lists = r.TableList
|
||
|
|
}
|
||
|
|
}
|
||
|
|
table.Run()
|
||
|
|
table.PutQueue("nf", func() {
|
||
|
|
t.Enter(uid, session, ct)
|
||
|
|
})
|
||
|
|
r.Tables.Store(t.TableIDInt(), t)
|
||
|
|
}
|