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