From a269845dbbdc3827bf8626d038f4a9d9b87f786e Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Sat, 23 Dec 2023 11:31:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20space.RoomController=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=AE=BE=E7=BD=AE=E6=88=BF=E4=B8=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/space/room_controller.go | 119 ++++++++++++++++++++++++++++-- game/space/room_manager_events.go | 14 ++++ game/space/room_options.go | 45 ++++++++--- 3 files changed, 164 insertions(+), 14 deletions(-) diff --git a/game/space/room_controller.go b/game/space/room_controller.go index f67f693..e87a3d4 100644 --- a/game/space/room_controller.go +++ b/game/space/room_controller.go @@ -7,7 +7,9 @@ import ( "sync" ) -func newRoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]](manager *RoomManager[EntityID, RoomID, Entity, Room], room Room, options *RoomControllerOptions) *RoomController[EntityID, RoomID, Entity, Room] { +const UnknownSeat = -1 // 未知座位号 + +func newRoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]](manager *RoomManager[EntityID, RoomID, Entity, Room], room Room, options *RoomControllerOptions[EntityID, RoomID, Entity, Room]) *RoomController[EntityID, RoomID, Entity, Room] { controller := &RoomController[EntityID, RoomID, Entity, Room]{ manager: manager, options: options, @@ -25,13 +27,66 @@ func newRoomController[EntityID comparable, RoomID comparable, Entity generic.Id // RoomController 对房间进行操作的控制器,由 RoomManager 接管后返回 type RoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct { manager *RoomManager[EntityID, RoomID, Entity, Room] - options *RoomControllerOptions + options *RoomControllerOptions[EntityID, RoomID, Entity, Room] room Room entities map[EntityID]Entity entitiesRWMutex sync.RWMutex vacancy []int // 空缺的座位 seat []*EntityID // 座位上的玩家 + owner *EntityID // 房主 +} + +// HasOwner 判断是否有房主 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) HasOwner() bool { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + return rc.owner != nil +} + +// IsOwner 判断是否为房主 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) IsOwner(entityId EntityID) bool { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + return rc.owner != nil && *rc.owner == entityId +} + +// GetOwner 获取房主 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetOwner() Entity { + return rc.GetEntity(*rc.owner) +} + +// GetOwnerID 获取房主 ID +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetOwnerID() EntityID { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + return *rc.owner +} + +// GetOwnerExist 获取房间,并返回房主是否存在的状态 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetOwnerExist() (Entity, bool) { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + entity, exist := rc.entities[*rc.owner] + return entity, exist +} + +// SetOwner 设置房主 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) SetOwner(entityId EntityID) { + rc.entitiesRWMutex.Lock() + defer rc.entitiesRWMutex.Unlock() + old := *rc.owner + rc.owner = &entityId + rc.manager.OnRoomOwnerChangeEvent(rc, &old, &entityId) +} + +// DelOwner 删除房主,将房间设置为无主的状态 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) DelOwner() { + rc.entitiesRWMutex.Lock() + defer rc.entitiesRWMutex.Unlock() + old := *rc.owner + rc.owner = nil + rc.manager.OnRoomOwnerChangeEvent(rc, &old, nil) } // JoinSeat 设置特定对象加入座位,当具体的座位不存在的时候,将会自动分配座位 @@ -93,7 +148,41 @@ func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetSeat(entityId Entit return i } } - return -1 + return UnknownSeat +} + +// GetFirstNotEmptySeat 获取第一个非空座位号,如果没有非空座位,将返回 UnknownSeat +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetFirstNotEmptySeat() int { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + for i, seat := range rc.seat { + if seat != nil { + return i + } + } + return UnknownSeat +} + +// GetFirstEmptySeatEntity 获取第一个空座位上的实体,如果没有空座位,将返回空实体 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetFirstEmptySeatEntity() (entity Entity) { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + for _, seat := range rc.seat { + if seat == nil { + return rc.entities[*seat] + } + } + return entity +} + +// GetRandomEntity 获取随机实体,如果房间中没有实体,将返回空实体 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetRandomEntity() (entity Entity) { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + for _, entity = range rc.entities { + return entity + } + return entity } // GetNotEmptySeat 获取非空座位 @@ -117,7 +206,7 @@ func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEmptySeat() []int { // HasSeat 判断是否有座位 func (rc *RoomController[EntityID, RoomID, Entity, Room]) HasSeat(entityId EntityID) bool { - return rc.GetSeat(entityId) != -1 + return rc.GetSeat(entityId) != UnknownSeat } // GetSeatEntityCount 获取座位上的实体数量 @@ -220,6 +309,14 @@ func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntity(id EntityID) return rc.entities[id] } +// GetEntityExist 获取实体,并返回实体是否存在的状态 +func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntityExist(id EntityID) (Entity, bool) { + rc.entitiesRWMutex.RLock() + defer rc.entitiesRWMutex.RUnlock() + entity, exist := rc.entities[id] + return entity, exist +} + // GetEntityIDs 获取所有实体ID func (rc *RoomController[EntityID, RoomID, Entity, Room]) GetEntityIDs() []EntityID { rc.entitiesRWMutex.RLock() @@ -282,6 +379,7 @@ func (rc *RoomController[EntityID, RoomID, Entity, Room]) AddEntityByPassword(en // RemoveEntity 移除实体 // - 当实体被移除时如果实体在座位上,将会自动离开座位 +// - 如果实体为房主,将会根据 RoomControllerOptions.WithOwnerInherit 函数的设置进行继承 func (rc *RoomController[EntityID, RoomID, Entity, Room]) RemoveEntity(id EntityID) { rc.entitiesRWMutex.RLock() defer rc.entitiesRWMutex.RUnlock() @@ -292,15 +390,26 @@ func (rc *RoomController[EntityID, RoomID, Entity, Room]) RemoveEntity(id Entity 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 } + delete(rc.entities, id) + if !rc.options.ownerInherit { + if rc.owner != nil && *rc.owner == id { + rc.owner = nil + } + } else { + if rc.owner != nil && *rc.owner == id { + rc.owner = rc.options.ownerInheritHandler(rc) + defer rc.manager.OnRoomOwnerChangeEvent(rc, &id, rc.owner) + } + } rc.manager.OnRoomRemoveEntityEvent(rc, entity) } // RemoveAllEntities 移除该房间中的所有实体 // - 当实体被移除时如果实体在座位上,将会自动离开座位 +// - 如果实体为房主,将会根据 RoomControllerOptions.WithOwnerInherit 函数的设置进行继承 func (rc *RoomController[EntityID, RoomID, Entity, Room]) RemoveAllEntities() { rc.entitiesRWMutex.Lock() defer rc.entitiesRWMutex.Unlock() diff --git a/game/space/room_manager_events.go b/game/space/room_manager_events.go index cf15f0d..eb58cec 100644 --- a/game/space/room_manager_events.go +++ b/game/space/room_manager_events.go @@ -8,6 +8,7 @@ type ( RoomAddEntityEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) RoomRemoveEntityEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) RoomChangePasswordEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) + RoomOwnerChangeEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room], oldOwner, owner *EntityID) ) type roomManagerEvents[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct { @@ -16,6 +17,19 @@ type roomManagerEvents[EntityID comparable, RoomID comparable, Entity generic.Id roomAddEntityEventHandles []RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room] roomRemoveEntityEventHandles []RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room] roomChangePasswordEventHandles []RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room] + roomOwnerChangeEventHandles []RoomOwnerChangeEventHandle[EntityID, RoomID, Entity, Room] +} + +// RegRoomOwnerChangeEvent 注册房间所有者变更事件,当触发事件时,房间所有者已经被修改 +func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomOwnerChangeEvent(handle RoomOwnerChangeEventHandle[EntityID, RoomID, Entity, Room]) { + rme.roomOwnerChangeEventHandles = append(rme.roomOwnerChangeEventHandles, handle) +} + +// OnRoomOwnerChangeEvent 房间所有者变更事件 +func (rme *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomOwnerChangeEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldOwner, owner *EntityID) { + for _, handle := range rme.roomOwnerChangeEventHandles { + handle(controller, oldOwner, owner) + } } // RegRoomAssumeControlEvent 注册房间接管事件 diff --git a/game/space/room_options.go b/game/space/room_options.go index 33661be..f41a8f3 100644 --- a/game/space/room_options.go +++ b/game/space/room_options.go @@ -1,13 +1,15 @@ package space +import "github.com/kercylan98/minotaur/utils/generic" + // NewRoomControllerOptions 创建房间控制器选项 -func NewRoomControllerOptions() *RoomControllerOptions { - return &RoomControllerOptions{} +func NewRoomControllerOptions[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]]() *RoomControllerOptions[EntityID, RoomID, Entity, Room] { + return &RoomControllerOptions[EntityID, RoomID, Entity, Room]{} } // mergeRoomControllerOptions 合并房间控制器选项 -func mergeRoomControllerOptions(options ...*RoomControllerOptions) *RoomControllerOptions { - result := NewRoomControllerOptions() +func mergeRoomControllerOptions[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]](options ...*RoomControllerOptions[EntityID, RoomID, Entity, Room]) *RoomControllerOptions[EntityID, RoomID, Entity, Room] { + result := NewRoomControllerOptions[EntityID, RoomID, Entity, Room]() for _, option := range options { if option.maxEntityCount != nil { result.maxEntityCount = option.maxEntityCount @@ -16,13 +18,38 @@ func mergeRoomControllerOptions(options ...*RoomControllerOptions) *RoomControll return result } -type RoomControllerOptions struct { - maxEntityCount *int // 房间最大实体数量 - password *string // 房间密码 +type RoomControllerOptions[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct { + maxEntityCount *int // 房间最大实体数量 + password *string // 房间密码 + ownerInherit bool // 房间所有者是否继承 + ownerInheritHandler func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID // 房间所有者继承处理函数 +} + +// WithOwnerInherit 设置房间所有者是否继承,默认为 false +// - inherit: 是否继承,当未设置 inheritHandler 且 inherit 为 true 时,将会按照随机或根据座位号顺序继承房间所有者 +// - inheritHandler: 继承处理函数,当 inherit 为 true 时,该函数将会被调用,传入当前房间中的所有实体,返回值为新的房间所有者 +func (rco *RoomControllerOptions[EntityID, RoomID, Entity, Room]) WithOwnerInherit(inherit bool, inheritHandler ...func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID) *RoomControllerOptions[EntityID, RoomID, Entity, Room] { + rco.ownerInherit = inherit + if len(inheritHandler) > 0 { + rco.ownerInheritHandler = inheritHandler[0] + } else if inherit { + rco.ownerInheritHandler = func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID { + if e := controller.GetFirstEmptySeatEntity(); e != nil { + var id = e.GetId() + return &id + } + if e := controller.GetRandomEntity(); e != nil { + var id = e.GetId() + return &id + } + return nil + } + } + return rco } // WithMaxEntityCount 设置房间最大实体数量 -func (rco *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions { +func (rco *RoomControllerOptions[EntityID, RoomID, Entity, Room]) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions[EntityID, RoomID, Entity, Room] { if maxEntityCount > 0 { rco.maxEntityCount = &maxEntityCount } @@ -30,7 +57,7 @@ func (rco *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomCo } // WithPassword 设置房间密码 -func (rco *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions { +func (rco *RoomControllerOptions[EntityID, RoomID, Entity, Room]) WithPassword(password string) *RoomControllerOptions[EntityID, RoomID, Entity, Room] { if password != "" { rco.password = &password }