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

View File

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

View File

@ -19,61 +19,61 @@ type roomManagerEvents[EntityID comparable, RoomID comparable, Entity generic.Id
}
// RegRoomAssumeControlEvent 注册房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAssumeControlEvent(handle RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAssumeControlEventHandles = append(slf.roomAssumeControlEventHandles, handle)
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAssumeControlEvent(handle RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]) {
rme.roomAssumeControlEventHandles = append(rme.roomAssumeControlEventHandles, handle)
}
// OnRoomAssumeControlEvent 房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAssumeControlEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomAssumeControlEventHandles {
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAssumeControlEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range rme.roomAssumeControlEventHandles {
handle(controller)
}
}
// RegRoomDestroyEvent 注册房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomDestroyEvent(handle RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomDestroyEventHandles = append(slf.roomDestroyEventHandles, handle)
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomDestroyEvent(handle RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]) {
rme.roomDestroyEventHandles = append(rme.roomDestroyEventHandles, handle)
}
// OnRoomDestroyEvent 房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomDestroyEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomDestroyEventHandles {
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomDestroyEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range rme.roomDestroyEventHandles {
handle(controller)
}
}
// RegRoomAddEntityEvent 注册房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAddEntityEvent(handle RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAddEntityEventHandles = append(slf.roomAddEntityEventHandles, handle)
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAddEntityEvent(handle RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]) {
rme.roomAddEntityEventHandles = append(rme.roomAddEntityEventHandles, handle)
}
// OnRoomAddEntityEvent 房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAddEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.roomAddEntityEventHandles {
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAddEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range rme.roomAddEntityEventHandles {
handle(controller, entity)
}
}
// RegRoomRemoveEntityEvent 注册房间移除对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomRemoveEntityEvent(handle RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomRemoveEntityEventHandles = append(slf.roomRemoveEntityEventHandles, handle)
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomRemoveEntityEvent(handle RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room]) {
rme.roomRemoveEntityEventHandles = append(rme.roomRemoveEntityEventHandles, handle)
}
// OnRoomRemoveEntityEvent 房间移除对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomRemoveEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.roomRemoveEntityEventHandles {
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomRemoveEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range rme.roomRemoveEntityEventHandles {
handle(controller, entity)
}
}
// RegRoomChangePasswordEvent 注册房间修改密码事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomChangePasswordEvent(handle RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomChangePasswordEventHandles = append(slf.roomChangePasswordEventHandles, handle)
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomChangePasswordEvent(handle RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room]) {
rme.roomChangePasswordEventHandles = append(rme.roomChangePasswordEventHandles, handle)
}
// OnRoomChangePasswordEvent 房间修改密码事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomChangePasswordEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) {
for _, handle := range slf.roomChangePasswordEventHandles {
func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomChangePasswordEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) {
for _, handle := range rme.roomChangePasswordEventHandles {
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 设置房间最大实体数量
func (slf *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions {
func (rco *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions {
if maxEntityCount > 0 {
slf.maxEntityCount = &maxEntityCount
rco.maxEntityCount = &maxEntityCount
}
return slf
return rco
}
// WithPassword 设置房间密码
func (slf *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions {
func (rco *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions {
if password != "" {
slf.password = &password
rco.password = &password
}
return slf
return rco
}

View File

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