docs: 增加 space 包 README.md 文档,优化 room 相关内容可读性

This commit is contained in:
kercylan98 2023-12-23 10:59:20 +08:00
parent 05aeed05a1
commit 9d9f7a3854
9 changed files with 356 additions and 241 deletions

54
game/space/README.md Normal file
View File

@ -0,0 +1,54 @@
# Space
[![Go doc](https://img.shields.io/badge/go.dev-reference-brightgreen?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space)
计划提供游戏中常见的空间设计,例如房间、地图等。开发者可以使用它来快速构建游戏中的常见空间,例如多人房间、地图等。
## Room [`房间`]((https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager))
房间在 `Minotaur` 中仅仅只是一个可以为任意可比较类型的 `ID`,当需要将现有或新设计的房间纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,需要实现 [`Room`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,仅需要实现 [`generic.IdR`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/generic#IdR) 接口即可。
该功能由
[`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager)、
[`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)
组成。
当创建一个新的房间并纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理后,将会得到一个 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)。通过 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController) 可以对房间进行管理,例如:获取房间信息、加入房间、退出房间等。
### 使用示例
```go
package main
import (
"fmt"
"github.com/kercylan98/minotaur/game/space"
)
type Room struct {
Id int64
}
func (r *Room) GetId() int64 {
return r.Id
}
type Player struct {
Id string
}
func (p *Player) GetId() string {
return p.Id
}
func main() {
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
var room = &Room{Id: 1}
var controller = rm.AssumeControl(room)
if err := controller.AddEntity(&Player{Id: "1"}); err != nil {
// 房间密码不匹配或者房间已满
panic(err)
}
fmt.Println(controller.GetEntityCount()) // 1
}
```

2
game/space/doc.go Normal file
View File

@ -0,0 +1,2 @@
// Package space 游戏中常见的空间设计,例如房间、地图等
package space

View File

@ -36,59 +36,59 @@ type RoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[E
// JoinSeat 设置特定对象加入座位,当具体的座位不存在的时候,将会自动分配座位 // JoinSeat 设置特定对象加入座位,当具体的座位不存在的时候,将会自动分配座位
// - 当目标座位存在玩家或未添加到房间中的时候,将会返回错误 // - 当目标座位存在玩家或未添加到房间中的时候,将会返回错误
func (slf *RoomController[EntityID, RoomID, Entity, Room]) JoinSeat(entityId EntityID, seat ...int) error { func (rc *RoomController[EntityID, RoomID, Entity, Room]) JoinSeat(entityId EntityID, seat ...int) error {
slf.entitiesRWMutex.Lock() rc.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock() defer rc.entitiesRWMutex.Unlock()
_, exist := slf.entities[entityId] _, exist := rc.entities[entityId]
if !exist { if !exist {
return ErrNotInRoom return ErrNotInRoom
} }
var targetSeat int var targetSeat int
if len(seat) > 0 { if len(seat) > 0 {
targetSeat = seat[0] targetSeat = seat[0]
if targetSeat < len(slf.seat) && slf.seat[targetSeat] != nil { if targetSeat < len(rc.seat) && rc.seat[targetSeat] != nil {
return ErrSeatNotEmpty return ErrSeatNotEmpty
} }
} else { } else {
if len(slf.vacancy) > 0 { if len(rc.vacancy) > 0 {
targetSeat = slf.vacancy[0] targetSeat = rc.vacancy[0]
slf.vacancy = slf.vacancy[1:] rc.vacancy = rc.vacancy[1:]
} else { } else {
targetSeat = len(slf.seat) targetSeat = len(rc.seat)
} }
} }
if targetSeat >= len(slf.seat) { if targetSeat >= len(rc.seat) {
slf.seat = append(slf.seat, make([]*EntityID, targetSeat-len(slf.seat)+1)...) rc.seat = append(rc.seat, make([]*EntityID, targetSeat-len(rc.seat)+1)...)
} }
slf.seat[targetSeat] = &entityId rc.seat[targetSeat] = &entityId
return nil return nil
} }
// LeaveSeat 离开座位 // LeaveSeat 离开座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) LeaveSeat(entityId EntityID) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) LeaveSeat(entityId EntityID) {
slf.entitiesRWMutex.Lock() rc.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock() defer rc.entitiesRWMutex.Unlock()
slf.leaveSeat(entityId) rc.leaveSeat(entityId)
} }
// leaveSeat 离开座位(无锁) // leaveSeat 离开座位(无锁)
func (slf *RoomController[EntityID, RoomID, Entity, Room]) leaveSeat(entityId EntityID) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) leaveSeat(entityId EntityID) {
for i, seat := range slf.seat { for i, seat := range rc.seat {
if seat != nil && *seat == entityId { if seat != nil && *seat == entityId {
slf.seat[i] = nil rc.seat[i] = nil
slf.vacancy = append(slf.vacancy, i) rc.vacancy = append(rc.vacancy, i)
break break
} }
} }
} }
// GetSeat 获取座位 // GetSeat 获取座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeat(entityId EntityID) int { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeat(entityId EntityID) int {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
for i, seat := range slf.seat { for i, seat := range rc.seat {
if seat != nil && *seat == entityId { if seat != nil && *seat == entityId {
return i return i
} }
@ -97,11 +97,11 @@ func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeat(entityId Enti
} }
// GetNotEmptySeat 获取非空座位 // GetNotEmptySeat 获取非空座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetNotEmptySeat() []int { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetNotEmptySeat() []int {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
var seats []int var seats []int
for i, player := range slf.seat { for i, player := range rc.seat {
if player != nil { if player != nil {
seats = append(seats, i) seats = append(seats, i)
} }
@ -111,21 +111,21 @@ func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetNotEmptySeat() []i
// GetEmptySeat 获取空座位 // GetEmptySeat 获取空座位
// - 空座位需要在有对象离开座位后才可能出现 // - 空座位需要在有对象离开座位后才可能出现
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEmptySeat() []int { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEmptySeat() []int {
return slice.Copy(slf.vacancy) return slice.Copy(rc.vacancy)
} }
// HasSeat 判断是否有座位 // HasSeat 判断是否有座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) HasSeat(entityId EntityID) bool { func (rc *RoomController[EntityID, RoomID, Entity, Room]) HasSeat(entityId EntityID) bool {
return slf.GetSeat(entityId) != -1 return rc.GetSeat(entityId) != -1
} }
// GetSeatEntityCount 获取座位上的实体数量 // GetSeatEntityCount 获取座位上的实体数量
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntityCount() int { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntityCount() int {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
var count int var count int
for _, seat := range slf.seat { for _, seat := range rc.seat {
if seat != nil { if seat != nil {
count++ count++
} }
@ -134,213 +134,219 @@ func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntityCount()
} }
// GetSeatEntities 获取座位上的实体 // GetSeatEntities 获取座位上的实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntities() map[EntityID]Entity { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntities() map[EntityID]Entity {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
var entities = make(map[EntityID]Entity) var entities = make(map[EntityID]Entity)
for _, entityId := range slf.seat { for _, entityId := range rc.seat {
if entityId != nil { if entityId != nil {
entities[*entityId] = slf.entities[*entityId] entities[*entityId] = rc.entities[*entityId]
} }
} }
return entities return entities
} }
// GetSeatEntitiesByOrdered 有序的获取座位上的实体 // GetSeatEntitiesByOrdered 有序的获取座位上的实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntitiesByOrdered() []Entity { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntitiesByOrdered() []Entity {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
var entities = make([]Entity, 0, len(slf.seat)) var entities = make([]Entity, 0, len(rc.seat))
for _, entityId := range slf.seat { for _, entityId := range rc.seat {
if entityId != nil { if entityId != nil {
entities = append(entities, slf.entities[*entityId]) entities = append(entities, rc.entities[*entityId])
} }
} }
return entities return entities
} }
// GetSeatEntitiesByOrderedAndContainsEmpty 获取有序的座位上的实体,包含空座位 // GetSeatEntitiesByOrderedAndContainsEmpty 获取有序的座位上的实体,包含空座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntitiesByOrderedAndContainsEmpty() []Entity { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntitiesByOrderedAndContainsEmpty() []Entity {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
var entities = make([]Entity, len(slf.seat)) var entities = make([]Entity, len(rc.seat))
for i, entityId := range slf.seat { for i, entityId := range rc.seat {
if entityId != nil { if entityId != nil {
entities[i] = slf.entities[*entityId] entities[i] = rc.entities[*entityId]
} }
} }
return entities return entities
} }
// GetSeatEntity 获取座位上的实体 // GetSeatEntity 获取座位上的实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntity(seat int) (entity Entity) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntity(seat int) (entity Entity) {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
if seat < len(slf.seat) { if seat < len(rc.seat) {
eid := slf.seat[seat] eid := rc.seat[seat]
if eid != nil { if eid != nil {
return slf.entities[*eid] return rc.entities[*eid]
} }
} }
return entity return entity
} }
// ContainEntity 房间内是否包含实体 // ContainEntity 房间内是否包含实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) ContainEntity(id EntityID) bool { func (rc *RoomController[EntityID, RoomID, Entity, Room]) ContainEntity(id EntityID) bool {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
_, exist := slf.entities[id] _, exist := rc.entities[id]
return exist return exist
} }
// GetRoom 获取原始房间实例 // GetRoom 获取原始房间实例,该实例为被接管的房间的原始实例
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoom() Room { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetRoom() Room {
return slf.room return rc.room
} }
// GetEntities 获取所有实体 // GetEntities 获取所有实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntities() map[EntityID]Entity { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntities() map[EntityID]Entity {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
return hash.Copy(slf.entities) return hash.Copy(rc.entities)
} }
// HasEntity 判断是否有实体 // HasEntity 判断是否有实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) HasEntity(id EntityID) bool { func (rc *RoomController[EntityID, RoomID, Entity, Room]) HasEntity(id EntityID) bool {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
_, exist := slf.entities[id] _, exist := rc.entities[id]
return exist return exist
} }
// GetEntity 获取实体 // GetEntity 获取实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntity(id EntityID) Entity { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntity(id EntityID) Entity {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
return slf.entities[id] return rc.entities[id]
} }
// GetEntityIDs 获取所有实体ID // GetEntityIDs 获取所有实体ID
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntityIDs() []EntityID { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntityIDs() []EntityID {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
return hash.KeyToSlice(slf.entities) return hash.KeyToSlice(rc.entities)
} }
// GetEntityCount 获取实体数量 // GetEntityCount 获取实体数量
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntityCount() int { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntityCount() int {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
return len(slf.entities) return len(rc.entities)
} }
// ChangePassword 修改房间密码 // ChangePassword 修改房间密码
// - 当房间密码为 nil 时,将会取消密码 // - 当房间密码为 nil 时,将会取消密码
func (slf *RoomController[EntityID, RoomID, Entity, Room]) ChangePassword(password *string) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) ChangePassword(password *string) {
old := slf.options.password old := rc.options.password
slf.options.password = password rc.options.password = password
slf.manager.OnRoomChangePasswordEvent(slf, old, slf.options.password) rc.manager.OnRoomChangePasswordEvent(rc, old, rc.options.password)
} }
// AddEntity 添加实体 // AddEntity 添加实体,如果房间存在密码,应使用 AddEntityByPassword 函数进行添加,否则将始终返回 ErrRoomPasswordNotMatch 错误
func (slf *RoomController[EntityID, RoomID, Entity, Room]) AddEntity(entity Entity) error { // - 当房间已满时,将会返回 ErrRoomFull 错误
if slf.options.password != nil { func (rc *RoomController[EntityID, RoomID, Entity, Room]) AddEntity(entity Entity) error {
if rc.options.password != nil {
return ErrRoomPasswordNotMatch return ErrRoomPasswordNotMatch
} }
slf.entitiesRWMutex.Lock() rc.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock() defer rc.entitiesRWMutex.Unlock()
if slf.options.maxEntityCount != nil && len(slf.entities) > *slf.options.maxEntityCount { if rc.options.maxEntityCount != nil && len(rc.entities) > *rc.options.maxEntityCount {
return ErrRoomFull return ErrRoomFull
} }
slf.entities[entity.GetId()] = entity rc.entities[entity.GetId()] = entity
slf.manager.OnRoomAddEntityEvent(slf, entity) rc.manager.OnRoomAddEntityEvent(rc, entity)
return nil return nil
} }
// AddEntityByPassword 通过房间密码添加实体 // AddEntityByPassword 通过房间密码添加实体到该房间中
func (slf *RoomController[EntityID, RoomID, Entity, Room]) AddEntityByPassword(entity Entity, password string) error { // - 当未设置房间密码时password 参数将会被忽略
if slf.options.password == nil || *slf.options.password != password { // - 当房间密码不匹配时,将会返回 ErrRoomPasswordNotMatch 错误
// - 当房间已满时,将会返回 ErrRoomFull 错误
func (rc *RoomController[EntityID, RoomID, Entity, Room]) AddEntityByPassword(entity Entity, password string) error {
if rc.options.password == nil || *rc.options.password != password {
return ErrRoomPasswordNotMatch return ErrRoomPasswordNotMatch
} }
slf.entitiesRWMutex.Lock() rc.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock() defer rc.entitiesRWMutex.Unlock()
if slf.options.maxEntityCount != nil && len(slf.entities) > *slf.options.maxEntityCount { if rc.options.maxEntityCount != nil && len(rc.entities) > *rc.options.maxEntityCount {
return ErrRoomFull return ErrRoomFull
} }
slf.entities[entity.GetId()] = entity rc.entities[entity.GetId()] = entity
slf.manager.OnRoomAddEntityEvent(slf, entity) rc.manager.OnRoomAddEntityEvent(rc, entity)
return nil return nil
} }
// RemoveEntity 移除实体 // RemoveEntity 移除实体
// - 当实体被移除时如果实体在座位上,将会自动离开座位 // - 当实体被移除时如果实体在座位上,将会自动离开座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) RemoveEntity(id EntityID) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) RemoveEntity(id EntityID) {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock() defer rc.entitiesRWMutex.RUnlock()
slf.removeEntity(id) rc.removeEntity(id)
} }
// removeEntity 移除实体(无锁) // removeEntity 移除实体(无锁)
func (slf *RoomController[EntityID, RoomID, Entity, Room]) removeEntity(id EntityID) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) removeEntity(id EntityID) {
slf.leaveSeat(id) rc.leaveSeat(id)
entity, exist := slf.entities[id] entity, exist := rc.entities[id]
delete(slf.entities, id) delete(rc.entities, id)
if !exist { if !exist {
return return
} }
slf.manager.OnRoomRemoveEntityEvent(slf, entity) rc.manager.OnRoomRemoveEntityEvent(rc, entity)
} }
// RemoveAllEntities 移除所有实体 // RemoveAllEntities 移除该房间中的所有实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) RemoveAllEntities() { // - 当实体被移除时如果实体在座位上,将会自动离开座位
slf.entitiesRWMutex.Lock() func (rc *RoomController[EntityID, RoomID, Entity, Room]) RemoveAllEntities() {
defer slf.entitiesRWMutex.Unlock() rc.entitiesRWMutex.Lock()
for id := range slf.entities { defer rc.entitiesRWMutex.Unlock()
slf.removeEntity(id) for id := range rc.entities {
delete(slf.entities, id) rc.removeEntity(id)
delete(rc.entities, id)
} }
} }
// Destroy 销毁房间 // Destroy 销毁房间,房间会从 RoomManager 中移除,同时所有房间的实体、座位等数据都会被清空
func (slf *RoomController[EntityID, RoomID, Entity, Room]) Destroy() { // - 该函数与 RoomManager.DestroyRoom 相同RoomManager.DestroyRoom 函数为该函数的快捷方式
slf.manager.roomsRWMutex.Lock() func (rc *RoomController[EntityID, RoomID, Entity, Room]) Destroy() {
defer slf.manager.roomsRWMutex.Unlock() rc.manager.roomsRWMutex.Lock()
defer rc.manager.roomsRWMutex.Unlock()
delete(slf.manager.rooms, slf.room.GetId()) delete(rc.manager.rooms, rc.room.GetId())
slf.manager.OnRoomDestroyEvent(slf) rc.manager.OnRoomDestroyEvent(rc)
slf.entitiesRWMutex.Lock() rc.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock() defer rc.entitiesRWMutex.Unlock()
for eid := range slf.entities { for eid := range rc.entities {
slf.removeEntity(eid) rc.removeEntity(eid)
delete(slf.entities, eid) delete(rc.entities, eid)
} }
slf.entities = make(map[EntityID]Entity) rc.entities = make(map[EntityID]Entity)
slf.seat = slf.seat[:] rc.seat = rc.seat[:]
slf.vacancy = slf.vacancy[:] rc.vacancy = rc.vacancy[:]
} }
// GetRoomManager 获取房间管理器 // GetRoomManager 获取该房间控制器所属的房间管理器
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoomManager() *RoomManager[EntityID, RoomID, Entity, Room] { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetRoomManager() *RoomManager[EntityID, RoomID, Entity, Room] {
return slf.manager return rc.manager
} }
// GetRoomID 获取房间 ID // GetRoomID 获取房间 ID
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoomID() RoomID { func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetRoomID() RoomID {
return slf.room.GetId() return rc.room.GetId()
} }
// Broadcast 广播消息 // Broadcast 广播,该函数会将所有房间中满足 conditions 的对象传入 handler 中进行处理
func (slf *RoomController[EntityID, RoomID, Entity, Room]) Broadcast(handler func(Entity), conditions ...func(Entity) bool) { func (rc *RoomController[EntityID, RoomID, Entity, Room]) Broadcast(handler func(Entity), conditions ...func(Entity) bool) {
slf.entitiesRWMutex.RLock() rc.entitiesRWMutex.RLock()
entities := hash.Copy(slf.entities) entities := hash.Copy(rc.entities)
slf.entitiesRWMutex.RUnlock() rc.entitiesRWMutex.RUnlock()
for _, entity := range entities { for _, entity := range entities {
for _, condition := range conditions { for _, condition := range conditions {
if !condition(entity) { if !condition(entity) {

View File

@ -6,7 +6,7 @@ import (
"sync" "sync"
) )
// NewRoomManager 创建房间管理器 // NewRoomManager 创建房间管理器 RoomManager 的实例
func NewRoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]]() *RoomManager[EntityID, RoomID, Entity, Room] { func NewRoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]]() *RoomManager[EntityID, RoomID, Entity, Room] {
return &RoomManager[EntityID, RoomID, Entity, Room]{ return &RoomManager[EntityID, RoomID, Entity, Room]{
roomManagerEvents: new(roomManagerEvents[EntityID, RoomID, Entity, Room]), roomManagerEvents: new(roomManagerEvents[EntityID, RoomID, Entity, Room]),
@ -14,64 +14,68 @@ func NewRoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[E
} }
} }
// RoomManager 房间管理器 // RoomManager 房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
// - 该实例是线程安全的
type RoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct { type RoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
*roomManagerEvents[EntityID, RoomID, Entity, Room] *roomManagerEvents[EntityID, RoomID, Entity, Room]
roomsRWMutex sync.RWMutex roomsRWMutex sync.RWMutex
rooms map[RoomID]*RoomController[EntityID, RoomID, Entity, Room] rooms map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
} }
// AssumeControl 将房间控制权交由 RoomManager 接管 // AssumeControl 将房间控制权交由 RoomManager 接管,返回 RoomController 实例
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) AssumeControl(room Room, options ...*RoomControllerOptions) *RoomController[EntityID, RoomID, Entity, Room] { // - 当任何房间需要被 RoomManager 管理时,都应该调用该方法获取到 RoomController 实例后进行操作
controller := newRoomController(slf, room, mergeRoomControllerOptions(options...)) // - 房间被接管后需要在释放房间控制权时调用 RoomController.Destroy 方法,否则将会导致 RoomManager 一直持有房间资源
slf.OnRoomAssumeControlEvent(controller) func (rm *RoomManager[EntityID, RoomID, Entity, Room]) AssumeControl(room Room, options ...*RoomControllerOptions) *RoomController[EntityID, RoomID, Entity, Room] {
controller := newRoomController(rm, room, mergeRoomControllerOptions(options...))
rm.OnRoomAssumeControlEvent(controller)
return controller return controller
} }
// DestroyRoom 销毁房间 // DestroyRoom 销毁房间,该函数为 RoomController.Destroy 的快捷方式
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) DestroyRoom(id RoomID) { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) DestroyRoom(id RoomID) {
slf.roomsRWMutex.Lock() rm.roomsRWMutex.Lock()
room, exist := slf.rooms[id] room, exist := rm.rooms[id]
slf.roomsRWMutex.Unlock() rm.roomsRWMutex.Unlock()
if !exist { if !exist {
return return
} }
room.Destroy() room.Destroy()
} }
// GetRoom 获取房间 // GetRoom 通过房间 ID 获取对应房间的控制器 RoomController当房间不存在时将返回 nil
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRoom(id RoomID) *RoomController[EntityID, RoomID, Entity, Room] { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) GetRoom(id RoomID) *RoomController[EntityID, RoomID, Entity, Room] {
slf.roomsRWMutex.RLock() rm.roomsRWMutex.RLock()
defer slf.roomsRWMutex.RUnlock() defer rm.roomsRWMutex.RUnlock()
return slf.rooms[id] return rm.rooms[id]
} }
// GetRooms 获取所有房间 // GetRooms 获取包含所有房间 ID 到对应控制器 RoomController 的映射
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRooms() map[RoomID]*RoomController[EntityID, RoomID, Entity, Room] { // - 返回值的 map 为拷贝对象,可安全的对其进行增删等操作
slf.roomsRWMutex.RLock() func (rm *RoomManager[EntityID, RoomID, Entity, Room]) GetRooms() map[RoomID]*RoomController[EntityID, RoomID, Entity, Room] {
defer slf.roomsRWMutex.RUnlock() rm.roomsRWMutex.RLock()
return hash.Copy(slf.rooms) defer rm.roomsRWMutex.RUnlock()
return hash.Copy(rm.rooms)
} }
// GetRoomCount 获取房间数量 // GetRoomCount 获取房间管理器接管的房间数量
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomCount() int { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomCount() int {
slf.roomsRWMutex.RLock() rm.roomsRWMutex.RLock()
defer slf.roomsRWMutex.RUnlock() defer rm.roomsRWMutex.RUnlock()
return len(slf.rooms) return len(rm.rooms)
} }
// GetRoomIDs 获取所有房间ID // GetRoomIDs 获取房间管理器接管的所有房间 ID
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomIDs() []RoomID { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomIDs() []RoomID {
slf.roomsRWMutex.RLock() rm.roomsRWMutex.RLock()
defer slf.roomsRWMutex.RUnlock() defer rm.roomsRWMutex.RUnlock()
return hash.KeyToSlice(slf.rooms) return hash.KeyToSlice(rm.rooms)
} }
// HasEntity 判断特定对象是否在任一房间中 // HasEntity 判断特定对象是否在任一房间中,当对象不在任一房间中时将返回 false
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) HasEntity(entityId EntityID) bool { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) HasEntity(entityId EntityID) bool {
slf.roomsRWMutex.RLock() rm.roomsRWMutex.RLock()
rooms := hash.Copy(slf.rooms) rooms := hash.Copy(rm.rooms)
slf.roomsRWMutex.RUnlock() rm.roomsRWMutex.RUnlock()
for _, room := range rooms { for _, room := range rooms {
if room.HasEntity(entityId) { if room.HasEntity(entityId) {
return true return true
@ -80,11 +84,12 @@ func (slf *RoomManager[EntityID, RoomID, Entity, Room]) HasEntity(entityId Entit
return false return false
} }
// GetEntityRooms 获取特定对象所在的房间 // GetEntityRooms 获取特定对象所在的房间,返回值为房间 ID 到对应控制器 RoomController 的映射
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetEntityRooms(entityId EntityID) map[RoomID]*RoomController[EntityID, RoomID, Entity, Room] { // - 由于一个对象可能在多个房间中,因此返回值为 map 类型
slf.roomsRWMutex.RLock() func (rm *RoomManager[EntityID, RoomID, Entity, Room]) GetEntityRooms(entityId EntityID) map[RoomID]*RoomController[EntityID, RoomID, Entity, Room] {
rooms := hash.Copy(slf.rooms) rm.roomsRWMutex.RLock()
slf.roomsRWMutex.RUnlock() rooms := hash.Copy(rm.rooms)
rm.roomsRWMutex.RUnlock()
var result = make(map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]) var result = make(map[RoomID]*RoomController[EntityID, RoomID, Entity, Room])
for id, room := range rooms { for id, room := range rooms {
if room.HasEntity(entityId) { if room.HasEntity(entityId) {
@ -94,11 +99,11 @@ func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetEntityRooms(entityId
return result return result
} }
// Broadcast 向所有房间对象广播消息 // Broadcast 向所有房间对象广播消息,该方法将会遍历所有房间控制器并调用 RoomController.Broadcast 方法
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) Broadcast(handler func(Entity), conditions ...func(Entity) bool) { func (rm *RoomManager[EntityID, RoomID, Entity, Room]) Broadcast(handler func(Entity), conditions ...func(Entity) bool) {
slf.roomsRWMutex.RLock() rm.roomsRWMutex.RLock()
rooms := hash.Copy(slf.rooms) rooms := hash.Copy(rm.rooms)
slf.roomsRWMutex.RUnlock() rm.roomsRWMutex.RUnlock()
for _, room := range rooms { for _, room := range rooms {
room.Broadcast(handler, conditions...) room.Broadcast(handler, conditions...)
} }

View File

@ -19,61 +19,61 @@ type roomManagerEvents[EntityID comparable, RoomID comparable, Entity generic.Id
} }
// RegRoomAssumeControlEvent 注册房间接管事件 // RegRoomAssumeControlEvent 注册房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAssumeControlEvent(handle RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAssumeControlEvent(handle RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAssumeControlEventHandles = append(slf.roomAssumeControlEventHandles, handle) rme.roomAssumeControlEventHandles = append(rme.roomAssumeControlEventHandles, handle)
} }
// OnRoomAssumeControlEvent 房间接管事件 // OnRoomAssumeControlEvent 房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAssumeControlEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAssumeControlEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomAssumeControlEventHandles { for _, handle := range rme.roomAssumeControlEventHandles {
handle(controller) handle(controller)
} }
} }
// RegRoomDestroyEvent 注册房间销毁事件 // RegRoomDestroyEvent 注册房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomDestroyEvent(handle RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomDestroyEvent(handle RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomDestroyEventHandles = append(slf.roomDestroyEventHandles, handle) rme.roomDestroyEventHandles = append(rme.roomDestroyEventHandles, handle)
} }
// OnRoomDestroyEvent 房间销毁事件 // OnRoomDestroyEvent 房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomDestroyEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomDestroyEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomDestroyEventHandles { for _, handle := range rme.roomDestroyEventHandles {
handle(controller) handle(controller)
} }
} }
// RegRoomAddEntityEvent 注册房间添加对象事件 // RegRoomAddEntityEvent 注册房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAddEntityEvent(handle RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAddEntityEvent(handle RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAddEntityEventHandles = append(slf.roomAddEntityEventHandles, handle) rme.roomAddEntityEventHandles = append(rme.roomAddEntityEventHandles, handle)
} }
// OnRoomAddEntityEvent 房间添加对象事件 // OnRoomAddEntityEvent 房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAddEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAddEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.roomAddEntityEventHandles { for _, handle := range rme.roomAddEntityEventHandles {
handle(controller, entity) handle(controller, entity)
} }
} }
// RegRoomRemoveEntityEvent 注册房间移除对象事件 // RegRoomRemoveEntityEvent 注册房间移除对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomRemoveEntityEvent(handle RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomRemoveEntityEvent(handle RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomRemoveEntityEventHandles = append(slf.roomRemoveEntityEventHandles, handle) rme.roomRemoveEntityEventHandles = append(rme.roomRemoveEntityEventHandles, handle)
} }
// OnRoomRemoveEntityEvent 房间移除对象事件 // OnRoomRemoveEntityEvent 房间移除对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomRemoveEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomRemoveEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.roomRemoveEntityEventHandles { for _, handle := range rme.roomRemoveEntityEventHandles {
handle(controller, entity) handle(controller, entity)
} }
} }
// RegRoomChangePasswordEvent 注册房间修改密码事件 // RegRoomChangePasswordEvent 注册房间修改密码事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomChangePasswordEvent(handle RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room]) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomChangePasswordEvent(handle RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomChangePasswordEventHandles = append(slf.roomChangePasswordEventHandles, handle) rme.roomChangePasswordEventHandles = append(rme.roomChangePasswordEventHandles, handle)
} }
// OnRoomChangePasswordEvent 房间修改密码事件 // OnRoomChangePasswordEvent 房间修改密码事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomChangePasswordEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) { func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomChangePasswordEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) {
for _, handle := range slf.roomChangePasswordEventHandles { for _, handle := range rme.roomChangePasswordEventHandles {
handle(controller, oldPassword, password) handle(controller, oldPassword, password)
} }
} }

View File

@ -0,0 +1,46 @@
package space_test
import (
"fmt"
"github.com/kercylan98/minotaur/game/space"
)
type Room struct {
Id int64
}
func (r *Room) GetId() int64 {
return r.Id
}
type Player struct {
Id string
}
func (p *Player) GetId() string {
return p.Id
}
func ExampleNewRoomManager() {
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
fmt.Println(rm == nil)
// Output:
// false
}
func ExampleRoomManager_AssumeControl() {
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
var room = &Room{Id: 1}
var controller = rm.AssumeControl(room)
if err := controller.AddEntity(&Player{Id: "1"}); err != nil {
// 房间密码不匹配或者房间已满
panic(err)
}
fmt.Println(controller.GetEntityCount())
// Output:
// 1
}

View File

@ -22,17 +22,17 @@ type RoomControllerOptions struct {
} }
// WithMaxEntityCount 设置房间最大实体数量 // WithMaxEntityCount 设置房间最大实体数量
func (slf *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions { func (rco *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions {
if maxEntityCount > 0 { if maxEntityCount > 0 {
slf.maxEntityCount = &maxEntityCount rco.maxEntityCount = &maxEntityCount
} }
return slf return rco
} }
// WithPassword 设置房间密码 // WithPassword 设置房间密码
func (slf *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions { func (rco *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions {
if password != "" { if password != "" {
slf.password = &password rco.password = &password
} }
return slf return rco
} }

View File

@ -15,23 +15,25 @@ import (
"time" "time"
) )
type StartBeforeEventHandler func(srv *Server) type (
type StartFinishEventHandler func(srv *Server) StartBeforeEventHandler func(srv *Server)
type StopEventHandler func(srv *Server) StartFinishEventHandler func(srv *Server)
type ConnectionReceivePacketEventHandler func(srv *Server, conn *Conn, packet []byte) StopEventHandler func(srv *Server)
type ConnectionOpenedEventHandler func(srv *Server, conn *Conn) ConnectionReceivePacketEventHandler func(srv *Server, conn *Conn, packet []byte)
type ConnectionClosedEventHandler func(srv *Server, conn *Conn, err any) ConnectionOpenedEventHandler func(srv *Server, conn *Conn)
type MessageErrorEventHandler func(srv *Server, message *Message, err error) ConnectionClosedEventHandler func(srv *Server, conn *Conn, err any)
type MessageLowExecEventHandler func(srv *Server, message *Message, cost time.Duration) MessageErrorEventHandler func(srv *Server, message *Message, err error)
type ConsoleCommandEventHandler func(srv *Server, command string, params ConsoleParams) MessageLowExecEventHandler func(srv *Server, message *Message, cost time.Duration)
type ConnectionOpenedAfterEventHandler func(srv *Server, conn *Conn) ConsoleCommandEventHandler func(srv *Server, command string, params ConsoleParams)
type ConnectionWritePacketBeforeEventHandler func(srv *Server, conn *Conn, packet []byte) []byte ConnectionOpenedAfterEventHandler func(srv *Server, conn *Conn)
type ShuntChannelCreatedEventHandler func(srv *Server, guid int64) ConnectionWritePacketBeforeEventHandler func(srv *Server, conn *Conn, packet []byte) []byte
type ShuntChannelClosedEventHandler func(srv *Server, guid int64) ShuntChannelCreatedEventHandler func(srv *Server, guid int64)
type ConnectionPacketPreprocessEventHandler func(srv *Server, conn *Conn, packet []byte, abort func(), usePacket func(newPacket []byte)) ShuntChannelClosedEventHandler func(srv *Server, guid int64)
type MessageExecBeforeEventHandler func(srv *Server, message *Message) bool ConnectionPacketPreprocessEventHandler func(srv *Server, conn *Conn, packet []byte, abort func(), usePacket func(newPacket []byte))
type MessageReadyEventHandler func(srv *Server) MessageExecBeforeEventHandler func(srv *Server, message *Message) bool
type OnDeadlockDetectEventHandler func(srv *Server, message *Message) MessageReadyEventHandler func(srv *Server)
OnDeadlockDetectEventHandler func(srv *Server, message *Message)
)
func newEvent(srv *Server) *event { func newEvent(srv *Server) *event {
return &event{ return &event{
@ -51,7 +53,7 @@ func newEvent(srv *Server) *event {
connectionPacketPreprocessEventHandlers: slice.NewPriority[ConnectionPacketPreprocessEventHandler](), connectionPacketPreprocessEventHandlers: slice.NewPriority[ConnectionPacketPreprocessEventHandler](),
messageExecBeforeEventHandlers: slice.NewPriority[MessageExecBeforeEventHandler](), messageExecBeforeEventHandlers: slice.NewPriority[MessageExecBeforeEventHandler](),
messageReadyEventHandlers: slice.NewPriority[MessageReadyEventHandler](), messageReadyEventHandlers: slice.NewPriority[MessageReadyEventHandler](),
dedeadlockDetectEventHandlers: slice.NewPriority[OnDeadlockDetectEventHandler](), deadlockDetectEventHandlers: slice.NewPriority[OnDeadlockDetectEventHandler](),
} }
} }
@ -72,7 +74,7 @@ type event struct {
connectionPacketPreprocessEventHandlers *slice.Priority[ConnectionPacketPreprocessEventHandler] connectionPacketPreprocessEventHandlers *slice.Priority[ConnectionPacketPreprocessEventHandler]
messageExecBeforeEventHandlers *slice.Priority[MessageExecBeforeEventHandler] messageExecBeforeEventHandlers *slice.Priority[MessageExecBeforeEventHandler]
messageReadyEventHandlers *slice.Priority[MessageReadyEventHandler] messageReadyEventHandlers *slice.Priority[MessageReadyEventHandler]
dedeadlockDetectEventHandlers *slice.Priority[OnDeadlockDetectEventHandler] deadlockDetectEventHandlers *slice.Priority[OnDeadlockDetectEventHandler]
consoleCommandEventHandlers map[string]*slice.Priority[ConsoleCommandEventHandler] consoleCommandEventHandlers map[string]*slice.Priority[ConsoleCommandEventHandler]
consoleCommandEventHandlerInitOnce sync.Once consoleCommandEventHandlerInitOnce sync.Once
@ -440,11 +442,11 @@ func (slf *event) OnMessageReadyEvent() {
// RegDeadlockDetectEvent 在死锁检测触发时立即执行被注册的事件处理函数 // RegDeadlockDetectEvent 在死锁检测触发时立即执行被注册的事件处理函数
func (slf *event) RegDeadlockDetectEvent(handler OnDeadlockDetectEventHandler, priority ...int) { func (slf *event) RegDeadlockDetectEvent(handler OnDeadlockDetectEventHandler, priority ...int) {
slf.dedeadlockDetectEventHandlers.Append(handler, slice.GetValue(priority, 0)) slf.deadlockDetectEventHandlers.Append(handler, slice.GetValue(priority, 0))
} }
func (slf *event) OnDeadlockDetectEvent(message *Message) { func (slf *event) OnDeadlockDetectEvent(message *Message) {
if slf.dedeadlockDetectEventHandlers.Len() == 0 { if slf.deadlockDetectEventHandlers.Len() == 0 {
return return
} }
defer func() { defer func() {
@ -453,7 +455,7 @@ func (slf *event) OnDeadlockDetectEvent(message *Message) {
debug.PrintStack() debug.PrintStack()
} }
}() }()
slf.dedeadlockDetectEventHandlers.RangeValue(func(index int, value OnDeadlockDetectEventHandler) bool { slf.deadlockDetectEventHandlers.RangeValue(func(index int, value OnDeadlockDetectEventHandler) bool {
value(slf.Server, message) value(slf.Server, message)
return true return true
}) })