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