Merge branch 'develop'

This commit is contained in:
kercylan98 2023-10-16 12:44:50 +08:00
commit 2d35b283b8
12 changed files with 756 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/kercylan98/minotaur/utils/random"
"github.com/kercylan98/minotaur/utils/slice"
"github.com/kercylan98/minotaur/utils/timer"
"sync"
"time"
)
@ -65,6 +66,8 @@ type Round[Data RoundData] struct {
changeEventHandles []RoundChangeEvent[Data] // 游戏回合变更事件
actionTimeoutEventHandles []RoundActionTimeoutEvent[Data] // 行动超时事件
actionRefreshEventHandles []RoundActionRefreshEvent[Data] // 行动刷新事件
actionMutex sync.Mutex
}
// GetData 获取游戏数据
@ -77,6 +80,8 @@ func (slf *Round[Data]) GetData() Data {
func (slf *Round[Data]) Start() {
slf.currentEntity = -1
slf.round = 1
slf.actionMutex.Lock()
defer slf.actionMutex.Unlock()
slf.loop(false)
}
@ -157,7 +162,11 @@ func (slf *Round[Data]) SkipCamp() {
// ActionRefresh 刷新行动超时时间
func (slf *Round[Data]) ActionRefresh() {
slf.actionTimeoutTime = time.Now().Add(slf.actionTimeout).Unix()
slf.ticker.After(slf.actionTimeoutTickerName, slf.actionTimeout, slf.loop, true)
slf.ticker.After(slf.actionTimeoutTickerName, slf.actionTimeout, func(timeout bool) {
slf.actionMutex.Lock()
defer slf.actionMutex.Unlock()
slf.loop(timeout)
}, true)
}
// ActionFinish 结束行动
@ -166,6 +175,8 @@ func (slf *Round[Data]) ActionFinish() {
if slf.shareAction {
slf.currentEntity = -1
}
slf.actionMutex.Lock()
defer slf.actionMutex.Unlock()
slf.loop(false)
}

View File

@ -67,6 +67,9 @@ func (slf *Manager[PID, P, R]) ReleaseRoom(guid int64) {
slf.pr.Atom(func(m map[PID]map[int64]struct{}) {
for playerId := range players {
delete(m[playerId], guid)
if len(m[playerId]) == 0 {
slf.players.Delete(playerId)
}
}
})
})
@ -364,6 +367,9 @@ func (slf *Manager[PID, P, R]) Leave(roomId int64, player P) {
return
}
delete(rooms, roomId)
if len(rooms) == 0 {
slf.players.Delete(player.GetID())
}
})
slf.rp.Atom(func(m map[int64]map[PID]struct{}) {
players, exist := m[roomId]

26
game/room/manager_test.go Normal file
View File

@ -0,0 +1,26 @@
package room_test
import (
"fmt"
"github.com/kercylan98/minotaur/game/room"
"testing"
)
func TestNewManager(t *testing.T) {
m := room.NewManager[string, *Player, *Room]()
r := &Room{}
m.CreateRoom(r)
helper := m.GetHelper(r)
helper.Join(&Player{ID: "player_01"})
helper.Join(&Player{ID: "player_02"})
helper.Join(&Player{ID: "player_03"})
helper.Leave(helper.GetPlayer("player_02"))
helper.Join(&Player{ID: "player_02"})
helper.BroadcastExcept(func(player *Player) {
fmt.Println(player.GetID())
}, func(player *Player) bool {
return false
})
}

View File

@ -8,10 +8,11 @@ import (
)
type Player struct {
ID string
}
func (slf *Player) GetID() string {
return ""
return slf.ID
}
func (slf *Player) GetConn() *server.Conn {

View File

@ -0,0 +1,352 @@
package space
import (
"github.com/kercylan98/minotaur/utils/generic"
"github.com/kercylan98/minotaur/utils/hash"
"github.com/kercylan98/minotaur/utils/slice"
"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] {
controller := &RoomController[EntityID, RoomID, Entity, Room]{
manager: manager,
options: options,
entities: make(map[EntityID]Entity),
room: room,
}
manager.roomsRWMutex.Lock()
defer manager.roomsRWMutex.Unlock()
manager.rooms[room.GetId()] = controller
return controller
}
// 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
room Room
entities map[EntityID]Entity
entitiesRWMutex sync.RWMutex
vacancy []int // 空缺的座位
seat []*EntityID // 座位上的玩家
}
// 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]
if !exist {
return ErrNotInRoom
}
var targetSeat int
if len(seat) > 0 {
targetSeat = seat[0]
if targetSeat < len(slf.seat) && slf.seat[targetSeat] != nil {
return ErrSeatNotEmpty
}
} else {
if len(slf.vacancy) > 0 {
targetSeat = slf.vacancy[0]
slf.vacancy = slf.vacancy[1:]
} else {
targetSeat = len(slf.seat)
}
}
if targetSeat >= len(slf.seat) {
slf.seat = append(slf.seat, make([]*EntityID, targetSeat-len(slf.seat)+1)...)
}
slf.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)
}
// leaveSeat 离开座位(无锁)
func (slf *RoomController[EntityID, RoomID, Entity, Room]) leaveSeat(entityId EntityID) {
for i, seat := range slf.seat {
if seat != nil && *seat == entityId {
slf.seat[i] = nil
slf.vacancy = append(slf.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 {
if seat != nil && *seat == entityId {
return i
}
}
return -1
}
// GetNotEmptySeat 获取非空座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetNotEmptySeat() []int {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
var seats []int
for i, player := range slf.seat {
if player != nil {
seats = append(seats, i)
}
}
return seats
}
// GetEmptySeat 获取空座位
// - 空座位需要在有对象离开座位后才可能出现
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEmptySeat() []int {
return slice.Copy(slf.vacancy)
}
// HasSeat 判断是否有座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) HasSeat(entityId EntityID) bool {
return slf.GetSeat(entityId) != -1
}
// GetSeatEntityCount 获取座位上的实体数量
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntityCount() int {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
var count int
for _, seat := range slf.seat {
if seat != nil {
count++
}
}
return count
}
// GetSeatEntities 获取座位上的实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetSeatEntities() map[EntityID]Entity {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
var entities = make(map[EntityID]Entity)
for _, entityId := range slf.seat {
if entityId != nil {
entities[*entityId] = slf.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 {
if entityId != nil {
entities = append(entities, slf.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 {
if entityId != nil {
entities[i] = slf.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]
if eid != nil {
return slf.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]
return exist
}
// GetRoom 获取原始房间实例
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoom() Room {
return slf.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)
}
// HasEntity 判断是否有实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) HasEntity(id EntityID) bool {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
_, exist := slf.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]
}
// GetEntityIDs 获取所有实体ID
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntityIDs() []EntityID {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
return hash.KeyToSlice(slf.entities)
}
// GetEntityCount 获取实体数量
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetEntityCount() int {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
return len(slf.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)
}
// AddEntity 添加实体
func (slf *RoomController[EntityID, RoomID, Entity, Room]) AddEntity(entity Entity) error {
if slf.options.password != nil {
return ErrRoomPasswordNotMatch
}
slf.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock()
if slf.options.maxEntityCount != nil && len(slf.entities) > *slf.options.maxEntityCount {
return ErrRoomFull
}
slf.entities[entity.GetId()] = entity
slf.manager.OnRoomAddEntityEvent(slf, 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 {
return ErrRoomPasswordNotMatch
}
slf.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock()
if slf.options.maxEntityCount != nil && len(slf.entities) > *slf.options.maxEntityCount {
return ErrRoomFull
}
slf.entities[entity.GetId()] = entity
slf.manager.OnRoomAddEntityEvent(slf, entity)
return nil
}
// RemoveEntity 移除实体
// - 当实体被移除时如果实体在座位上,将会自动离开座位
func (slf *RoomController[EntityID, RoomID, Entity, Room]) RemoveEntity(id EntityID) {
slf.entitiesRWMutex.RLock()
defer slf.entitiesRWMutex.RUnlock()
slf.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)
if !exist {
return
}
slf.manager.OnRoomRemoveEntityEvent(slf, 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)
}
}
// Destroy 销毁房间
func (slf *RoomController[EntityID, RoomID, Entity, Room]) Destroy() {
slf.manager.roomsRWMutex.Lock()
defer slf.manager.roomsRWMutex.Unlock()
delete(slf.manager.rooms, slf.room.GetId())
slf.manager.OnRoomDestroyEvent(slf)
slf.entitiesRWMutex.Lock()
defer slf.entitiesRWMutex.Unlock()
for eid := range slf.entities {
slf.removeEntity(eid)
delete(slf.entities, eid)
}
slf.entities = make(map[EntityID]Entity)
slf.seat = slf.seat[:]
slf.vacancy = slf.vacancy[:]
}
// GetRoomManager 获取房间管理器
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoomManager() *RoomManager[EntityID, RoomID, Entity, Room] {
return slf.manager
}
// GetRoomID 获取房间ID
func (slf *RoomController[EntityID, RoomID, Entity, Room]) GetRoomID() RoomID {
return slf.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()
for _, entity := range entities {
for _, condition := range conditions {
if !condition(entity) {
continue
}
}
handler(entity)
}
}

16
game/space/room_errors.go Normal file
View File

@ -0,0 +1,16 @@
package space
import "errors"
var (
// ErrRoomFull 房间已满
ErrRoomFull = errors.New("room is full")
// ErrSeatNotEmpty 座位上已经有实体
ErrSeatNotEmpty = errors.New("seat is not empty")
// ErrNotInRoom 实体不在房间中
ErrNotInRoom = errors.New("not in room")
// ErrRoomPasswordNotMatch 房间密码不匹配
ErrRoomPasswordNotMatch = errors.New("room password not match")
// ErrPermissionDenied 权限不足
ErrPermissionDenied = errors.New("permission denied")
)

105
game/space/room_manager.go Normal file
View File

@ -0,0 +1,105 @@
package space
import (
"github.com/kercylan98/minotaur/utils/generic"
"github.com/kercylan98/minotaur/utils/hash"
"sync"
)
// NewRoomManager 创建房间管理器
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]),
rooms: make(map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]),
}
}
// 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)
return controller
}
// DestroyRoom 销毁房间
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) DestroyRoom(id RoomID) {
slf.roomsRWMutex.Lock()
room, exist := slf.rooms[id]
slf.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]
}
// 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)
}
// GetRoomCount 获取房间数量
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomCount() int {
slf.roomsRWMutex.RLock()
defer slf.roomsRWMutex.RUnlock()
return len(slf.rooms)
}
// GetRoomIDs 获取所有房间ID
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) GetRoomIDs() []RoomID {
slf.roomsRWMutex.RLock()
defer slf.roomsRWMutex.RUnlock()
return hash.KeyToSlice(slf.rooms)
}
// HasEntity 判断特定对象是否在任一房间中
func (slf *RoomManager[EntityID, RoomID, Entity, Room]) HasEntity(entityId EntityID) bool {
slf.roomsRWMutex.RLock()
rooms := hash.Copy(slf.rooms)
slf.roomsRWMutex.RUnlock()
for _, room := range rooms {
if room.HasEntity(entityId) {
return true
}
}
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()
var result = make(map[RoomID]*RoomController[EntityID, RoomID, Entity, Room])
for id, room := range rooms {
if room.HasEntity(entityId) {
result[id] = room
}
}
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()
for _, room := range rooms {
room.Broadcast(handler, conditions...)
}
}

View File

@ -0,0 +1,79 @@
package space
import "github.com/kercylan98/minotaur/utils/generic"
type (
RoomAssumeControlEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room])
RoomDestroyEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room])
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)
)
type roomManagerEvents[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
roomAssumeControlEventHandles []RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]
roomDestroyEventHandles []RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]
roomAddEntityEventHandles []RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]
roomRemoveEntityEventHandles []RoomRemoveEntityEventHandle[EntityID, RoomID, Entity, Room]
roomChangePasswordEventHandles []RoomChangePasswordEventHandle[EntityID, RoomID, Entity, Room]
}
// RegRoomAssumeControlEvent 注册房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAssumeControlEvent(handle RoomAssumeControlEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAssumeControlEventHandles = append(slf.roomAssumeControlEventHandles, handle)
}
// OnRoomAssumeControlEvent 房间接管事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAssumeControlEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomAssumeControlEventHandles {
handle(controller)
}
}
// RegRoomDestroyEvent 注册房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomDestroyEvent(handle RoomDestroyEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomDestroyEventHandles = append(slf.roomDestroyEventHandles, handle)
}
// OnRoomDestroyEvent 房间销毁事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomDestroyEvent(controller *RoomController[EntityID, RoomID, Entity, Room]) {
for _, handle := range slf.roomDestroyEventHandles {
handle(controller)
}
}
// RegRoomAddEntityEvent 注册房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) RegRoomAddEntityEvent(handle RoomAddEntityEventHandle[EntityID, RoomID, Entity, Room]) {
slf.roomAddEntityEventHandles = append(slf.roomAddEntityEventHandles, handle)
}
// OnRoomAddEntityEvent 房间添加对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomAddEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.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)
}
// OnRoomRemoveEntityEvent 房间移除对象事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomRemoveEntityEvent(controller *RoomController[EntityID, RoomID, Entity, Room], entity Entity) {
for _, handle := range slf.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)
}
// OnRoomChangePasswordEvent 房间修改密码事件
func (slf *roomManagerEvents[EntityID, RoomID, Entity, Room]) OnRoomChangePasswordEvent(controller *RoomController[EntityID, RoomID, Entity, Room], oldPassword, password *string) {
for _, handle := range slf.roomChangePasswordEventHandles {
handle(controller, oldPassword, password)
}
}

View File

@ -0,0 +1,38 @@
package space
// NewRoomControllerOptions 创建房间控制器选项
func NewRoomControllerOptions() *RoomControllerOptions {
return &RoomControllerOptions{}
}
// mergeRoomControllerOptions 合并房间控制器选项
func mergeRoomControllerOptions(options ...*RoomControllerOptions) *RoomControllerOptions {
result := NewRoomControllerOptions()
for _, option := range options {
if option.maxEntityCount != nil {
result.maxEntityCount = option.maxEntityCount
}
}
return result
}
type RoomControllerOptions struct {
maxEntityCount *int // 房间最大实体数量
password *string // 房间密码
}
// WithMaxEntityCount 设置房间最大实体数量
func (slf *RoomControllerOptions) WithMaxEntityCount(maxEntityCount int) *RoomControllerOptions {
if maxEntityCount > 0 {
slf.maxEntityCount = &maxEntityCount
}
return slf
}
// WithPassword 设置房间密码
func (slf *RoomControllerOptions) WithPassword(password string) *RoomControllerOptions {
if password != "" {
slf.password = &password
}
return slf
}

14
utils/generic/id.go Normal file
View File

@ -0,0 +1,14 @@
package generic
type IdR[ID comparable] interface {
GetId() ID
}
type IdW[ID comparable] interface {
SetId(id ID)
}
type IdRW[ID comparable] interface {
IdR[ID]
IdW[ID]
}

78
utils/super/permission.go Normal file
View File

@ -0,0 +1,78 @@
package super
import (
"github.com/kercylan98/minotaur/utils/generic"
"sync"
)
// NewPermission 创建权限
func NewPermission[Code generic.Integer, EntityID comparable]() *Permission[Code, EntityID] {
return &Permission[Code, EntityID]{
permissions: make(map[EntityID]Code),
}
}
type Permission[Code generic.Integer, EntityID comparable] struct {
permissions map[EntityID]Code
l sync.RWMutex
}
// HasPermission 是否有权限
func (slf *Permission[Code, EntityID]) HasPermission(entityId EntityID, permission Code) bool {
slf.l.RLock()
c, exist := slf.permissions[entityId]
slf.l.RUnlock()
if !exist {
return false
}
return c&permission != 0
}
// AddPermission 添加权限
func (slf *Permission[Code, EntityID]) AddPermission(entityId EntityID, permission ...Code) {
slf.l.Lock()
defer slf.l.Unlock()
userPermission, exist := slf.permissions[entityId]
if !exist {
userPermission = 0
slf.permissions[entityId] = userPermission
}
for _, p := range permission {
userPermission |= p
}
slf.permissions[entityId] = userPermission
}
// RemovePermission 移除权限
func (slf *Permission[Code, EntityID]) RemovePermission(entityId EntityID, permission ...Code) {
slf.l.Lock()
defer slf.l.Unlock()
userPermission, exist := slf.permissions[entityId]
if !exist {
return
}
for _, p := range permission {
userPermission &= ^p
}
slf.permissions[entityId] = userPermission
}
// SetPermission 设置权限
func (slf *Permission[Code, EntityID]) SetPermission(entityId EntityID, permission ...Code) {
slf.l.Lock()
defer slf.l.Unlock()
var userPermission Code
for _, p := range permission {
userPermission |= p
}
slf.permissions[entityId] = userPermission
}

View File

@ -0,0 +1,28 @@
package super_test
import (
"github.com/kercylan98/minotaur/utils/super"
"testing"
)
func TestNewPermission(t *testing.T) {
const (
Read = 1 << iota
Write
Execute
)
p := super.NewPermission[int, int]()
p.AddPermission(1, Read, Write)
t.Log(p.HasPermission(1, Read))
t.Log(p.HasPermission(1, Write))
p.SetPermission(2, Read|Write)
t.Log(p.HasPermission(2, Read))
t.Log(p.HasPermission(2, Execute))
p.SetPermission(2, Execute)
t.Log(p.HasPermission(2, Execute))
t.Log(p.HasPermission(2, Read))
t.Log(p.HasPermission(2, Write))
p.RemovePermission(2, Execute)
t.Log(p.HasPermission(2, Execute))
}