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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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