You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
3.2 KiB
Go

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