|
|
package manager
|
|
|
|
|
|
import (
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"git.noahlan.cn/northlan/ngs/session"
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
"sync"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
RoomKey = "ROOM"
|
|
|
)
|
|
|
|
|
|
type (
|
|
|
// RoomManager 房间管理器
|
|
|
RoomManager struct {
|
|
|
rooms []*Room // 房间列表
|
|
|
|
|
|
mu sync.RWMutex
|
|
|
}
|
|
|
)
|
|
|
|
|
|
func newRoomManager(opts ...RoomManagerOption) *RoomManager {
|
|
|
resp := &RoomManager{
|
|
|
rooms: make([]*Room, 0),
|
|
|
}
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
opt(resp)
|
|
|
}
|
|
|
|
|
|
return resp
|
|
|
}
|
|
|
|
|
|
func (m *RoomManager) CreateRoom(id int64, gameType string, isDefault bool) *Room {
|
|
|
m.mu.Lock()
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
resp := newRoom(id, gameType, isDefault)
|
|
|
m.rooms = append(m.rooms, resp)
|
|
|
|
|
|
return resp
|
|
|
}
|
|
|
|
|
|
// JoinRoom 加入房间
|
|
|
// id 房间ID 零值表示加入默认房间
|
|
|
func (m *RoomManager) JoinRoom(s *session.Session, gameType string, roomId int64) error {
|
|
|
var room *Room
|
|
|
for _, tmp := range m.rooms {
|
|
|
if roomId == 0 {
|
|
|
if tmp.IsDefault && tmp.GameType == gameType {
|
|
|
room = tmp
|
|
|
break
|
|
|
}
|
|
|
} else {
|
|
|
if tmp.ID == roomId {
|
|
|
room = tmp
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if room == nil {
|
|
|
return errors.New("没有房间可供加入")
|
|
|
}
|
|
|
|
|
|
if r, err := m.RoomBySession(s); err == nil {
|
|
|
// 强制离开原房间
|
|
|
s.Remove(RoomKey)
|
|
|
_ = r.Leave(s)
|
|
|
}
|
|
|
|
|
|
s.Set(RoomKey, room)
|
|
|
return room.Add(s)
|
|
|
}
|
|
|
|
|
|
func (m *RoomManager) LeaveRoom(s *session.Session) {
|
|
|
room, err := m.RoomBySession(s)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
s.Remove(RoomKey)
|
|
|
_ = room.Leave(s)
|
|
|
}
|
|
|
|
|
|
func (m *RoomManager) Clean() {
|
|
|
m.mu.Lock()
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
for _, room := range m.rooms {
|
|
|
for _, s := range room.Members() {
|
|
|
s.Remove(RoomKey)
|
|
|
}
|
|
|
_ = room.LeaveAll()
|
|
|
}
|
|
|
m.rooms = m.rooms[:1]
|
|
|
}
|
|
|
|
|
|
func (m *RoomManager) BattleIdBySession(s *session.Session) int64 {
|
|
|
room, err := m.RoomBySession(s)
|
|
|
if err != nil {
|
|
|
return 0
|
|
|
}
|
|
|
return room.BattleId
|
|
|
}
|
|
|
|
|
|
func (m *RoomManager) RoomByBattleId(battleId int64) (*Room, error) {
|
|
|
var resp *Room
|
|
|
m.PeekRoom(func(room *Room) bool {
|
|
|
if room.BattleId == battleId {
|
|
|
resp = room
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
})
|
|
|
if resp == nil {
|
|
|
return nil, errors.New(fmt.Sprintf("未找到战局 [%d] 对应的游戏房间", battleId))
|
|
|
}
|
|
|
return resp, nil
|
|
|
}
|
|
|
|
|
|
// RoomBySession 获取session所在的游戏房间
|
|
|
func (m *RoomManager) RoomBySession(s *session.Session) (*Room, error) {
|
|
|
if !s.HasKey(RoomKey) {
|
|
|
return nil, errors.New(fmt.Sprintf("客户端 [%d] 未加入房间", s.ID()))
|
|
|
}
|
|
|
room := s.Value(RoomKey).(*Room)
|
|
|
return room, nil
|
|
|
}
|
|
|
|
|
|
// PeekRoom 遍历所有房间
|
|
|
// fn filter方法,返回true表示循环继续,false表示循环结束
|
|
|
func (m *RoomManager) PeekRoom(fn func(room *Room) bool) {
|
|
|
m.mu.RLock()
|
|
|
defer m.mu.RUnlock()
|
|
|
|
|
|
for _, room := range m.rooms {
|
|
|
if !fn(room) {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// PeekAllSession 遍历所有session
|
|
|
// fn: returns true继续遍历 false结束
|
|
|
func (m *RoomManager) PeekAllSession(fn func(*Room, *session.Session) bool) {
|
|
|
m.mu.RLock()
|
|
|
defer m.mu.RUnlock()
|
|
|
|
|
|
for _, room := range m.rooms {
|
|
|
room.PeekMembers(func(sId int64, s *session.Session) bool {
|
|
|
return fn(room, s)
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Broadcast 消息全局分发,即所有房间分发
|
|
|
func (m *RoomManager) Broadcast(route string, msg proto.Message) {
|
|
|
m.mu.RLock()
|
|
|
defer m.mu.RUnlock()
|
|
|
|
|
|
for _, room := range m.rooms {
|
|
|
room.Broadcast(route, msg)
|
|
|
}
|
|
|
}
|