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.
438 lines
10 KiB
438 lines
10 KiB
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) |
|
}
|
|
|