From ee18934768507a621406399d9b4c2e4f5d5ccfa7 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Thu, 27 Jul 2023 12:07:17 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=8E=9F?= =?UTF-8?q?=E6=9C=89=E7=9A=84=20builtin=20=E4=B8=AD=E7=9A=84=E5=90=84?= =?UTF-8?q?=E7=B1=BB=20room=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/actor.go | 2 - game/builtin/room.go | 166 ----------------- game/builtin/room_errors.go | 9 - game/builtin/room_manager.go | 34 ---- game/builtin/room_options.go | 38 ---- game/builtin/room_seat.go | 284 ------------------------------ game/builtin/room_seat_errors.go | 7 - game/builtin/room_seat_options.go | 26 --- game/room.go | 44 ----- game/room/events.go | 22 +-- game/room/info.go | 2 +- game/room/manager.go | 15 +- game/room/room.go | 25 +-- game/room/seat.go | 4 +- game/room_seat.go | 47 ----- 15 files changed, 23 insertions(+), 702 deletions(-) delete mode 100644 game/builtin/room.go delete mode 100644 game/builtin/room_errors.go delete mode 100644 game/builtin/room_manager.go delete mode 100644 game/builtin/room_options.go delete mode 100644 game/builtin/room_seat.go delete mode 100644 game/builtin/room_seat_errors.go delete mode 100644 game/builtin/room_seat_options.go delete mode 100644 game/room.go delete mode 100644 game/room_seat.go diff --git a/game/actor.go b/game/actor.go index 2c4ddaa..5b94b3d 100644 --- a/game/actor.go +++ b/game/actor.go @@ -4,8 +4,6 @@ package game // - 需要注意 Actor 不等于 Player // - 在 Minotaur 中,每个网络连接可以表示一个 Player,而每个玩家可以拥有多个 Actor // - Actor 并非 Player 独有,场景中也可包含各类无主的 Actor -// - 内置实现:builtin.Actor -// - 构建函数:builtin.NewActor type Actor interface { // SetGuid 设置对象的唯一标识符 // - 需要注意的是该函数不应该主动执行,否则可能产生意想不到的情况 diff --git a/game/builtin/room.go b/game/builtin/room.go deleted file mode 100644 index 86aabee..0000000 --- a/game/builtin/room.go +++ /dev/null @@ -1,166 +0,0 @@ -package builtin - -import ( - "github.com/kercylan98/minotaur/game" - "github.com/kercylan98/minotaur/utils/concurrent" - "github.com/kercylan98/minotaur/utils/log" -) - -// NewRoom 创建一个默认的内置游戏房间 Room -func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...RoomOption[PlayerID, Player]) *Room[PlayerID, Player] { - room := &Room[PlayerID, Player]{ - guid: guid, - players: concurrent.NewBalanceMap[PlayerID, Player](), - } - for _, option := range options { - option(room) - } - return room -} - -// Room 默认的内置游戏房间实现 -// - 实现了最大人数控制、房主、踢出玩家、玩家维护等功能 -// - 支持并发安全和非并发安全的模式 -type Room[PlayerID comparable, Player game.Player[PlayerID]] struct { - guid int64 - owner PlayerID - noMaster bool - playerLimit int - players *concurrent.BalanceMap[PlayerID, Player] - kickCheckHandle func(room *Room[PlayerID, Player], id, target PlayerID) error - - playerJoinRoomEventHandles []game.PlayerJoinRoomEventHandle[PlayerID, Player] - playerLeaveRoomEventHandles []game.PlayerLeaveRoomEventHandle[PlayerID, Player] - playerKickedOutEventHandles []game.PlayerKickedOutEventHandle[PlayerID, Player] -} - -// GetGuid 获取房间唯一标识 -func (slf *Room[PlayerID, Player]) GetGuid() int64 { - return slf.guid -} - -// GetPlayerLimit 获取最大玩家上限 -func (slf *Room[PlayerID, Player]) GetPlayerLimit() int { - return slf.playerLimit -} - -// GetPlayer 根据玩家id获取玩家 -func (slf *Room[PlayerID, Player]) GetPlayer(id PlayerID) Player { - return slf.players.Get(id) -} - -// GetPlayers 获取所有玩家 -func (slf *Room[PlayerID, Player]) GetPlayers() map[PlayerID]Player { - return slf.players.Map() -} - -// GetPlayerCount 获取玩家数量 -func (slf *Room[PlayerID, Player]) GetPlayerCount() int { - return slf.players.Size() -} - -// IsExistPlayer 房间内是否存在某玩家 -func (slf *Room[PlayerID, Player]) IsExistPlayer(id PlayerID) bool { - return slf.players.Exist(id) -} - -// IsOwner 检查特定玩家是否是房主 -// - 当房间为无主模式(WithRoomNoMaster)时,将会始终返回false -func (slf *Room[PlayerID, Player]) IsOwner(id PlayerID) bool { - return !slf.noMaster && slf.owner == id -} - -// ChangeOwner 改变房主 -// - 当房间为无主模式(WithRoomNoMaster)时,将不会发生任何变化 -func (slf *Room[PlayerID, Player]) ChangeOwner(id PlayerID) { - if slf.noMaster || slf.owner == id { - return - } - slf.owner = id -} - -// Join 控制玩家加入到该房间 -func (slf *Room[PlayerID, Player]) Join(player Player) error { - playerId := player.GetID() - exist := slf.players.Exist(playerId) - if !exist && slf.players.Size() >= slf.playerLimit && slf.playerLimit > 0 { - return ErrRoomPlayerLimit - } - slf.players.Set(playerId, player) - if !exist { - log.Debug("Room.Join", log.Any("guid", slf.GetGuid()), log.Any("player", playerId)) - if slf.players.Size() == 1 && !slf.noMaster { - slf.owner = playerId - } - slf.OnPlayerJoinRoomEvent(player) - } - return nil -} - -// Leave 控制玩家离开房间 -func (slf *Room[PlayerID, Player]) Leave(id PlayerID) { - player, exist := slf.players.GetExist(id) - if !exist { - return - } - log.Debug("Room.Leave", log.Any("guid", slf.GetGuid()), log.Any("player", id)) - slf.OnPlayerLeaveRoomEvent(player) - slf.players.Delete(id) -} - -// KickOut 以某种原因踢出特定玩家 -// - 当设置了房间踢出玩家的检查处理函数(WithRoomKickPlayerCheckHandle)时,将会根据检查结果进行处理,即便是无主模式。其他情况如下 -// - 如果是无主模式(WithRoomNoMaster),将会返回错误 -// - 如果不是房主发起的踢出玩家,将会返回错误 -func (slf *Room[PlayerID, Player]) KickOut(id, target PlayerID, reason string) error { - player, exist := slf.players.GetExist(target) - if !exist { - return nil - } - if slf.kickCheckHandle != nil { - if err := slf.kickCheckHandle(slf, id, target); err != nil { - return err - } - } else if slf.noMaster { - return ErrRoomNoHasMaster - } else if slf.owner != id { - return ErrRoomNotIsOwner - } - - slf.OnPlayerKickedOutEvent(id, target, reason) - slf.Leave(player.GetID()) - return nil -} - -// RegPlayerJoinRoomEvent 玩家进入房间时将立即执行被注册的事件处理函数 -func (slf *Room[PlayerID, Player]) RegPlayerJoinRoomEvent(handle game.PlayerJoinRoomEventHandle[PlayerID, Player]) { - slf.playerJoinRoomEventHandles = append(slf.playerJoinRoomEventHandles, handle) -} - -func (slf *Room[PlayerID, Player]) OnPlayerJoinRoomEvent(player Player) { - for _, handle := range slf.playerJoinRoomEventHandles { - handle(slf, player) - } -} - -// RegPlayerLeaveRoomEvent 玩家离开房间时将立即执行被注册的事件处理函数 -func (slf *Room[PlayerID, Player]) RegPlayerLeaveRoomEvent(handle game.PlayerLeaveRoomEventHandle[PlayerID, Player]) { - slf.playerLeaveRoomEventHandles = append(slf.playerLeaveRoomEventHandles, handle) -} - -func (slf *Room[PlayerID, Player]) OnPlayerLeaveRoomEvent(player Player) { - for _, handle := range slf.playerLeaveRoomEventHandles { - handle(slf, player) - } -} - -// RegPlayerKickedOutEvent 当玩家被踢出游戏时将立即执行被注册的事件处理函数 -func (slf *Room[PlayerID, Player]) RegPlayerKickedOutEvent(handle game.PlayerKickedOutEventHandle[PlayerID, Player]) { - slf.playerKickedOutEventHandles = append(slf.playerKickedOutEventHandles, handle) -} - -func (slf *Room[PlayerID, Player]) OnPlayerKickedOutEvent(executor, kicked PlayerID, reason string) { - for _, handle := range slf.playerKickedOutEventHandles { - handle(slf, executor, kicked, reason) - } -} diff --git a/game/builtin/room_errors.go b/game/builtin/room_errors.go deleted file mode 100644 index a8e8e41..0000000 --- a/game/builtin/room_errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package builtin - -import "errors" - -var ( - ErrRoomPlayerLimit = errors.New("the number of players in the room has reached the upper limit") // 玩家数量达到上限 - ErrRoomNoHasMaster = errors.New("room not has master, can't kick player") - ErrRoomNotIsOwner = errors.New("not is room owner, can't kick player") -) diff --git a/game/builtin/room_manager.go b/game/builtin/room_manager.go deleted file mode 100644 index 86f17c3..0000000 --- a/game/builtin/room_manager.go +++ /dev/null @@ -1,34 +0,0 @@ -package builtin - -import ( - "github.com/kercylan98/minotaur/game" - "github.com/kercylan98/minotaur/utils/concurrent" - "sync/atomic" -) - -func NewRoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]]() *RoomManager[PlayerID, Room] { - return &RoomManager[PlayerID, Room]{ - rooms: concurrent.NewBalanceMap[int64, Room](), - } -} - -// RoomManager 房间管理器 -type RoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]] struct { - guid atomic.Int64 - rooms *concurrent.BalanceMap[int64, Room] -} - -// GenGuid 生成一个新的房间guid -func (slf *RoomManager[PlayerID, Room]) GenGuid() int64 { - return slf.guid.Add(1) -} - -// AddRoom 添加房间到房间管理器中 -func (slf *RoomManager[PlayerID, Room]) AddRoom(room Room) { - slf.rooms.Set(room.GetGuid(), room) -} - -// CloseRoom 关闭特定guid的房间 -func (slf *RoomManager[PlayerID, Room]) CloseRoom(guid int64) { - slf.rooms.Delete(guid) -} diff --git a/game/builtin/room_options.go b/game/builtin/room_options.go deleted file mode 100644 index b67a6ec..0000000 --- a/game/builtin/room_options.go +++ /dev/null @@ -1,38 +0,0 @@ -package builtin - -import ( - "github.com/kercylan98/minotaur/game" - "github.com/kercylan98/minotaur/utils/concurrent" -) - -// RoomOption 房间构建可选项 -type RoomOption[PlayerID comparable, Player game.Player[PlayerID]] func(room *Room[PlayerID, Player]) - -// WithRoomSync 通过线程安全的方式创建房间 -func WithRoomSync[PlayerID comparable, Player game.Player[PlayerID]]() RoomOption[PlayerID, Player] { - return func(room *Room[PlayerID, Player]) { - room.players = concurrent.NewBalanceMap[PlayerID, Player]() - } -} - -// WithRoomPlayerLimit 限制房间的玩家数量上限 -func WithRoomPlayerLimit[PlayerID comparable, Player game.Player[PlayerID]](playerLimit int) RoomOption[PlayerID, Player] { - return func(room *Room[PlayerID, Player]) { - room.playerLimit = playerLimit - } -} - -// WithRoomNoMaster 设置房间为无主的 -func WithRoomNoMaster[PlayerID comparable, Player game.Player[PlayerID]]() RoomOption[PlayerID, Player] { - return func(room *Room[PlayerID, Player]) { - room.noMaster = true - } -} - -// WithRoomKickPlayerCheckHandle 设置房间踢出玩家的检查处理函数 -// - 当没有设置该函数时,如果不是房主,将无法进行踢出 -func WithRoomKickPlayerCheckHandle[PlayerID comparable, Player game.Player[PlayerID]](handle func(room *Room[PlayerID, Player], id, target PlayerID) error) RoomOption[PlayerID, Player] { - return func(room *Room[PlayerID, Player]) { - room.kickCheckHandle = handle - } -} diff --git a/game/builtin/room_seat.go b/game/builtin/room_seat.go deleted file mode 100644 index 55ad7f7..0000000 --- a/game/builtin/room_seat.go +++ /dev/null @@ -1,284 +0,0 @@ -package builtin - -import ( - "github.com/kercylan98/minotaur/game" - "github.com/kercylan98/minotaur/utils/concurrent" - "github.com/kercylan98/minotaur/utils/hash" - "github.com/kercylan98/minotaur/utils/slice" - "sync" -) - -// NewRoomSeat 基于特定游戏房间(game.Room)的实现创建一个支持座位号管理的房间实现(RoomSeat) -func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player], options ...RoomSeatOption[PlayerID, Player]) *RoomSeat[PlayerID, Player] { - roomSeat := &RoomSeat[PlayerID, Player]{ - Room: room, - seatPS: concurrent.NewBalanceMap[PlayerID, int](), - } - for _, option := range options { - option(roomSeat) - } - return roomSeat -} - -// RoomSeat 包含座位号的默认内置房间实现,依赖于游戏房间(game.Room)实现 -// - 实现了对玩家座位号的管理,分别为自动管理(WithRoomSeatAutoManage)及手工管理,默认清空下为手工管理 -type RoomSeat[PlayerID comparable, Player game.Player[PlayerID]] struct { - game.Room[PlayerID, Player] - mutex sync.RWMutex - vacancy []int - seatPS *concurrent.BalanceMap[PlayerID, int] - seatSP []*PlayerID - duplicateLock bool - fillIn bool - autoMode sync.Once -} - -// AddSeat 为特定玩家添加座位 -// - 当座位存在空缺的时候,玩家将会优先在空缺位置坐下,否则将会在末位追加 -func (slf *RoomSeat[PlayerID, Player]) AddSeat(id PlayerID) { - if slf.seatPS.Exist(id) { - return - } - slf.mutex.Lock() - defer slf.mutex.Unlock() - if len(slf.vacancy) > 0 { - seat := slf.vacancy[0] - slf.vacancy = slf.vacancy[1:] - slf.seatPS.Set(id, seat) - slf.seatSP[seat] = &id - } else { - slf.seatPS.Set(id, len(slf.seatSP)) - slf.seatSP = append(slf.seatSP, &id) - } -} - -// AddSeatWithAssign 将玩家添加到特定的座位 -// - 如果位置已经有玩家,将会与其进行更换 -func (slf *RoomSeat[PlayerID, Player]) AddSeatWithAssign(id PlayerID, seat int) { - slf.AddSeat(id) - _ = slf.SetSeat(id, seat) -} - -// RemovePlayerSeat 删除玩家座位 -// - 受补位模式(WithRoomSeatFillIn)影响 -func (slf *RoomSeat[PlayerID, Player]) RemovePlayerSeat(id PlayerID) { - if !slf.seatPS.Exist(id) { - return - } - slf.mutex.Lock() - defer slf.mutex.Unlock() - seat := slf.seatPS.DeleteGet(id) - if slf.fillIn { - slice.Del(&slf.seatSP, seat) - for i := seat; i < len(slf.seatSP); i++ { - slf.seatPS.Set(*slf.seatSP[i], i) - } - return - } - slf.seatSP[seat] = nil -} - -// RemoveSeat 删除特定座位的玩家 -// - 受补位模式(WithRoomSeatFillIn)影响 -func (slf *RoomSeat[PlayerID, Player]) RemoveSeat(seat int) { - if seat >= len(slf.seatSP) { - return - } - playerId := slf.seatSP[seat] - if playerId == nil { - return - } - slf.RemovePlayerSeat(*playerId) -} - -// SetSeat 设置玩家的座位号 -// - 如果玩家没有预先添加过座位将会返回错误 -// - 如果位置已经有玩家,将会与其进行更换 -func (slf *RoomSeat[PlayerID, Player]) SetSeat(id PlayerID, seat int) error { - slf.mutex.Lock() - slf.duplicateLock = true - defer func() { - slf.mutex.Unlock() - slf.duplicateLock = false - }() - oldSeat, err := slf.GetSeat(id) - if err != nil { - return err - } - playerId, err := slf.GetPlayerIDWithSeat(seat) - if err != nil { - ov := slf.seatSP[oldSeat] - slf.seatSP[oldSeat] = slf.seatSP[seat] - slf.seatSP[seat] = ov - slf.seatPS.Set(id, seat) - slf.seatPS.Set(playerId, oldSeat) - } else { - maxSeat := len(slf.seatSP) - 1 - if seat > maxSeat { - if slf.fillIn { - seat = maxSeat + 1 - defer func() { - slice.Del(&slf.seatSP, oldSeat) - for i := oldSeat; i < len(slf.seatSP); i++ { - slf.seatPS.Set(*slf.seatSP[i], i) - } - }() - } - count := seat - maxSeat - slf.seatSP = append(slf.seatSP, make([]*PlayerID, count)...) - } - slf.seatSP[seat] = slf.seatSP[oldSeat] - slf.seatSP[oldSeat] = nil - slf.seatPS.Set(id, seat) - } - return nil -} - -// GetSeat 获取玩家座位号 -func (slf *RoomSeat[PlayerID, Player]) GetSeat(id PlayerID) (int, error) { - seat, exist := slf.seatPS.GetExist(id) - if !exist { - return 0, ErrRoomNotHasPlayer - } - return seat, nil -} - -// GetPlayerIDWithSeat 获取特定座位号的玩家 -func (slf *RoomSeat[PlayerID, Player]) GetPlayerIDWithSeat(seat int) (playerId PlayerID, err error) { - if !slf.duplicateLock { - slf.mutex.RLock() - defer slf.mutex.RUnlock() - } - if seat > len(slf.seatSP)-1 { - return playerId, ErrRoomNotHasPlayer - } - id := slf.seatSP[seat] - if id == nil { - return playerId, ErrRoomNotHasPlayer - } - return *id, nil -} - -// GetSeatInfo 获取所有座位号 -// - 在非补位模式(WithRoomSeatFillIn)下由于座位号可能存在缺席的情况,所以需要根据是否为空指针进行判断 -func (slf *RoomSeat[PlayerID, Player]) GetSeatInfo() []*PlayerID { - slf.mutex.RLock() - defer slf.mutex.RUnlock() - return slf.seatSP -} - -// GetSeatInfoMap 获取座位号及其对应的玩家信息 -// - 缺席情况将被忽略 -func (slf *RoomSeat[PlayerID, Player]) GetSeatInfoMap() map[int]PlayerID { - var seatInfo = make(map[int]PlayerID) - slf.mutex.RLock() - defer slf.mutex.RUnlock() - for seat, playerId := range slf.seatSP { - if playerId == nil { - continue - } - seatInfo[seat] = *playerId - } - return seatInfo -} - -// GetSeatInfoMapVacancy 获取座位号及其对应的玩家信息 -// - 缺席情况将不会被忽略 -func (slf *RoomSeat[PlayerID, Player]) GetSeatInfoMapVacancy() map[int]*PlayerID { - slf.mutex.RLock() - defer slf.mutex.RUnlock() - return hash.ToMap(slf.seatSP) -} - -// GetSeatInfoWithPlayerIDMap 获取玩家及其座位号信息 -func (slf *RoomSeat[PlayerID, Player]) GetSeatInfoWithPlayerIDMap() map[PlayerID]int { - return slf.seatPS.Map() -} - -// GetFirstSeat 获取第一个未缺席的座位号 -func (slf *RoomSeat[PlayerID, Player]) GetFirstSeat() int { - for seat, playerId := range slf.seatSP { - if playerId != nil { - return seat - } - } - return -1 -} - -// GetNextSeat 获取特定座位号下一个未缺席的座位号 -func (slf *RoomSeat[PlayerID, Player]) GetNextSeat(seat int) int { - l := len(slf.seatSP) - if l == 0 || seat >= l || seat < 0 { - return -1 - } - var target = seat - for { - target++ - if target >= l { - target = 0 - } - if target == seat { - return seat - } - if slf.seatSP[target] != nil { - return target - } - } -} - -// GetNextSeatVacancy 获取特定座位号下一个座位号 -// - 缺席将不会被忽略 -func (slf *RoomSeat[PlayerID, Player]) GetNextSeatVacancy(seat int) int { - l := len(slf.seatSP) - if l == 0 || seat >= l || seat < 0 { - return -1 - } - seat++ - if seat >= l { - seat = 0 - } - return seat -} - -// GetPrevSeat 获取特定座位号上一个未缺席的座位号 -func (slf *RoomSeat[PlayerID, Player]) GetPrevSeat(seat int) int { - l := len(slf.seatSP) - if l == 0 || seat >= l || seat < 0 { - return -1 - } - var target = seat - for { - target-- - if target < 0 { - target = l - 1 - } - if target == seat { - return seat - } - if slf.seatSP[target] != nil { - return target - } - } -} - -// GetPrevSeatVacancy 获取特定座位号上一个座位号 -// - 缺席将不会被忽略 -func (slf *RoomSeat[PlayerID, Player]) GetPrevSeatVacancy(seat int) int { - l := len(slf.seatSP) - if l == 0 || seat >= l || seat < 0 { - return -1 - } - seat-- - if seat < 0 { - seat = l - 1 - } - return seat -} - -func (slf *RoomSeat[PlayerID, Player]) onJoinRoom(room game.Room[PlayerID, Player], player Player) { - slf.AddSeat(player.GetID()) -} - -func (slf *RoomSeat[PlayerID, Player]) onLeaveRoom(room game.Room[PlayerID, Player], player Player) { - slf.RemovePlayerSeat(player.GetID()) -} diff --git a/game/builtin/room_seat_errors.go b/game/builtin/room_seat_errors.go deleted file mode 100644 index fd69597..0000000 --- a/game/builtin/room_seat_errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package builtin - -import "errors" - -var ( - ErrRoomNotHasPlayer = errors.New("player not exist") -) diff --git a/game/builtin/room_seat_options.go b/game/builtin/room_seat_options.go deleted file mode 100644 index e8a3766..0000000 --- a/game/builtin/room_seat_options.go +++ /dev/null @@ -1,26 +0,0 @@ -package builtin - -import "github.com/kercylan98/minotaur/game" - -type RoomSeatOption[PlayerID comparable, Player game.Player[PlayerID]] func(seat *RoomSeat[PlayerID, Player]) - -// WithRoomSeatAutoManage 通过自动管理的方式创建带有座位号的房间 -// - 默认情况下需要自行维护房间用户的座位号信息 -// - 自动管理模式下,将注册房间的 Room.RegPlayerJoinRoomEvent 和 Room.RegPlayerLeaveRoomEvent 事件以便玩家在加入或者离开时维护座位信息 -func WithRoomSeatAutoManage[PlayerID comparable, Player game.Player[PlayerID]]() RoomSeatOption[PlayerID, Player] { - return func(seatRoom *RoomSeat[PlayerID, Player]) { - seatRoom.autoMode.Do(func() { - seatRoom.RegPlayerJoinRoomEvent(seatRoom.onJoinRoom) - seatRoom.RegPlayerLeaveRoomEvent(seatRoom.onLeaveRoom) - }) - } -} - -// WithRoomSeatFillIn 通过补位的方式创建带有座位号的房间 -// - 默认情况下玩家离开座位不会影响其他玩家 -// - 补位情况下,靠前的玩家离开座位将有后方玩家向前补位 -func WithRoomSeatFillIn[PlayerID comparable, Player game.Player[PlayerID]]() RoomSeatOption[PlayerID, Player] { - return func(seatRoom *RoomSeat[PlayerID, Player]) { - seatRoom.fillIn = true - } -} diff --git a/game/room.go b/game/room.go deleted file mode 100644 index ed3bb3d..0000000 --- a/game/room.go +++ /dev/null @@ -1,44 +0,0 @@ -package game - -// Room 房间类似于简版的游戏世界(World),不过没有游戏实体 -type Room[PlayerID comparable, P Player[PlayerID]] interface { - // GetGuid 获取房间的唯一标识符 - GetGuid() int64 - // GetPlayerLimit 获取玩家人数上限 - GetPlayerLimit() int - // GetPlayer 根据玩家id获取玩家 - GetPlayer(id PlayerID) P - // GetPlayers 获取房间中的所有玩家 - GetPlayers() map[PlayerID]P - // GetPlayerCount 获取玩家数量 - GetPlayerCount() int - // IsExistPlayer 检查房间中是否存在特定玩家 - IsExistPlayer(id PlayerID) bool - // IsOwner 检查玩家是否是房主 - IsOwner(id PlayerID) bool - // ChangeOwner 设置玩家为房主 - ChangeOwner(id PlayerID) - - // Join 使特定玩家加入房间 - Join(player P) error - // Leave 使特定玩家离开房间 - Leave(id PlayerID) - // KickOut 将特定玩家踢出房间 - KickOut(id, target PlayerID, reason string) error - - // RegPlayerJoinRoomEvent 玩家进入房间时将立即执行被注册的事件处理函数 - RegPlayerJoinRoomEvent(handle PlayerJoinRoomEventHandle[PlayerID, P]) - OnPlayerJoinRoomEvent(player P) - // RegPlayerLeaveRoomEvent 玩家离开房间时将立即执行被注册的事件处理函数 - RegPlayerLeaveRoomEvent(handle PlayerLeaveRoomEventHandle[PlayerID, P]) - OnPlayerLeaveRoomEvent(player P) - // RegPlayerKickedOutEvent 当玩家被踢出游戏时将立即执行被注册的事件处理函数 - RegPlayerKickedOutEvent(handle PlayerKickedOutEventHandle[PlayerID, P]) - OnPlayerKickedOutEvent(executor, kicked PlayerID, reason string) -} - -type ( - PlayerJoinRoomEventHandle[ID comparable, P Player[ID]] func(room Room[ID, P], player P) - PlayerLeaveRoomEventHandle[ID comparable, P Player[ID]] func(room Room[ID, P], player P) - PlayerKickedOutEventHandle[ID comparable, P Player[ID]] func(room Room[ID, P], executor, kicked ID, reason string) -) diff --git a/game/room/events.go b/game/room/events.go index 7f3fe33..c394b56 100644 --- a/game/room/events.go +++ b/game/room/events.go @@ -4,26 +4,26 @@ import "github.com/kercylan98/minotaur/game" type ( // PlayerJoinRoomEventHandle 玩家加入房间事件处理函数 - PlayerJoinRoomEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, player P) + PlayerJoinRoomEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, player P) // PlayerLeaveRoomEventHandle 玩家离开房间事件处理函数 - PlayerLeaveRoomEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, player P) + PlayerLeaveRoomEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, player P) // PlayerKickedOutEventHandle 玩家被踢出房间事件处理函数 - PlayerKickedOutEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, executor, kicked P, reason string) + PlayerKickedOutEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, executor, kicked P, reason string) // PlayerUpgradeOwnerEventHandle 玩家成为房主事件处理函数 - PlayerUpgradeOwnerEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, oldOwner, newOwner P) + PlayerUpgradeOwnerEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, oldOwner, newOwner P) // CancelOwnerEventHandle 取消房主事件处理函数 - CancelOwnerEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, oldOwner P) + CancelOwnerEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, oldOwner P) // ChangePlayerLimitEventHandle 改变房间人数上限事件处理函数 - ChangePlayerLimitEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, oldLimit, newLimit int) + ChangePlayerLimitEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, oldLimit, newLimit int) // PlayerSeatChangeEventHandle 玩家座位改变事件处理函数 - PlayerSeatChangeEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, player P, oldSeat, newSeat int) + PlayerSeatChangeEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, player P, oldSeat, newSeat int) // PlayerSeatSetEventHandle 玩家座位设置事件处理函数 - PlayerSeatSetEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, player P, seat int) + PlayerSeatSetEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, player P, seat int) // PlayerSeatCancelEventHandle 玩家座位取消事件处理函数 - PlayerSeatCancelEventHandle[PID comparable, P game.Player[PID], R Room[PID, P]] func(room R, player P, seat int) + PlayerSeatCancelEventHandle[PID comparable, P game.Player[PID], R Room] func(room R, player P, seat int) ) -func newEvent[PID comparable, P game.Player[PID], R Room[PID, P]]() *event[PID, P, R] { +func newEvent[PID comparable, P game.Player[PID], R Room]() *event[PID, P, R] { return &event[PID, P, R]{ playerJoinRoomEventRoomHandles: make(map[int64][]PlayerJoinRoomEventHandle[PID, P, R]), playerLeaveRoomEventRoomHandles: make(map[int64][]PlayerLeaveRoomEventHandle[PID, P, R]), @@ -36,7 +36,7 @@ func newEvent[PID comparable, P game.Player[PID], R Room[PID, P]]() *event[PID, } } -type event[PID comparable, P game.Player[PID], R Room[PID, P]] struct { +type event[PID comparable, P game.Player[PID], R Room] struct { playerJoinRoomEventHandles []PlayerJoinRoomEventHandle[PID, P, R] playerJoinRoomEventRoomHandles map[int64][]PlayerJoinRoomEventHandle[PID, P, R] playerLeaveRoomEventHandles []PlayerLeaveRoomEventHandle[PID, P, R] diff --git a/game/room/info.go b/game/room/info.go index a546fac..93cea46 100644 --- a/game/room/info.go +++ b/game/room/info.go @@ -2,7 +2,7 @@ package room import "github.com/kercylan98/minotaur/game" -type info[PlayerID comparable, P game.Player[PlayerID], R Room[PlayerID, P]] struct { +type info[PlayerID comparable, P game.Player[PlayerID], R Room] struct { room R playerLimit int // 玩家人数上限, <= 0 表示无限制 owner *PlayerID // 房主 diff --git a/game/room/manager.go b/game/room/manager.go index 8ad06da..a74cd29 100644 --- a/game/room/manager.go +++ b/game/room/manager.go @@ -3,10 +3,11 @@ package room import ( "github.com/kercylan98/minotaur/game" "github.com/kercylan98/minotaur/utils/concurrent" + "github.com/kercylan98/minotaur/utils/generic" ) // NewManager 创建房间管理器 -func NewManager[PID comparable, P game.Player[PID], R Room[PID, P]]() *Manager[PID, P, R] { +func NewManager[PID comparable, P game.Player[PID], R Room]() *Manager[PID, P, R] { manager := &Manager[PID, P, R]{ event: newEvent[PID, P, R](), rooms: concurrent.NewBalanceMap[int64, *info[PID, P, R]](), @@ -18,7 +19,7 @@ func NewManager[PID comparable, P game.Player[PID], R Room[PID, P]]() *Manager[P } // Manager 房间管理器 -type Manager[PID comparable, P game.Player[PID], R Room[PID, P]] struct { +type Manager[PID comparable, P game.Player[PID], R Room] struct { *event[PID, P, R] rooms *concurrent.BalanceMap[int64, *info[PID, P, R]] // 所有房间 players *concurrent.BalanceMap[PID, P] // 所有加入房间的玩家 @@ -78,7 +79,7 @@ func (slf *Manager[PID, P, R]) CancelOwner(roomId int64) { info.owner = nil } }) - if oldOwner != nil { + if !generic.IsNil(oldOwner) { slf.OnCancelOwnerEvent(room, oldOwner) } } @@ -99,7 +100,7 @@ func (slf *Manager[PID, P, R]) SetOwner(roomId int64, owner PID) error { oldOwner = slf.GetRoomPlayer(roomId, *info.owner) } newOwner = slf.GetRoomPlayer(roomId, owner) - if newOwner == nil { + if generic.IsNil(newOwner) { err = ErrRoomOrPlayerNotExist return } @@ -270,7 +271,7 @@ func (slf *Manager[PID, P, R]) Leave(roomId int64, player P) { } // Join 使玩家加入房间 -func (slf *Manager[PID, P, R]) Join(player P, roomId int64) error { +func (slf *Manager[PID, P, R]) Join(roomId int64, player P) error { var err error var roomInfo *info[PID, P, R] slf.rooms.Atom(func(m map[int64]*info[PID, P, R]) { @@ -315,12 +316,12 @@ func (slf *Manager[PID, P, R]) KickOut(roomId int64, executor, kicked PID, reaso var executorPlayer, kickedPlayer P slf.rp.Atom(func(m map[int64]map[PID]struct{}) { executorPlayer, kickedPlayer = slf.GetRoomPlayer(roomId, executor), slf.GetRoomPlayer(roomId, kicked) - if executorPlayer == nil || kickedPlayer == nil { + if generic.IsHasNil(executorPlayer, kickedPlayer) { err = ErrRoomOrPlayerNotExist return } room = slf.rooms.Get(roomId).room - if room == nil { + if generic.IsNil(room) { err = ErrRoomNotExist return } diff --git a/game/room/room.go b/game/room/room.go index a4d2633..a52a0f7 100644 --- a/game/room/room.go +++ b/game/room/room.go @@ -1,30 +1,7 @@ package room -import "github.com/kercylan98/minotaur/game" - // Room 房间类似于简版的游戏世界(World),不过没有游戏实体 -type Room[PlayerID comparable, P game.Player[PlayerID]] interface { +type Room interface { // GetGuid 获取房间的唯一标识符 GetGuid() int64 - // GetPlayerLimit 获取玩家人数上限 - GetPlayerLimit() int - // GetPlayer 根据玩家id获取玩家 - GetPlayer(id PlayerID) P - // GetPlayers 获取房间中的所有玩家 - GetPlayers() map[PlayerID]P - // GetPlayerCount 获取玩家数量 - GetPlayerCount() int - // IsExistPlayer 检查房间中是否存在特定玩家 - IsExistPlayer(id PlayerID) bool - // IsOwner 检查玩家是否是房主 - IsOwner(id PlayerID) bool - // ChangeOwner 设置玩家为房主 - ChangeOwner(id PlayerID) - - // Join 使特定玩家加入房间 - Join(player P) error - // Leave 使特定玩家离开房间 - Leave(id PlayerID) - // KickOut 将特定玩家踢出房间 - KickOut(id, target PlayerID, reason string) error } diff --git a/game/room/seat.go b/game/room/seat.go index e96197b..e7143c6 100644 --- a/game/room/seat.go +++ b/game/room/seat.go @@ -7,7 +7,7 @@ import ( "sync" ) -func newSeat[PlayerID comparable, P game.Player[PlayerID], R Room[PlayerID, P]](manager *Manager[PlayerID, P, R], room R, event *event[PlayerID, P, R]) *Seat[PlayerID, P, R] { +func newSeat[PlayerID comparable, P game.Player[PlayerID], R Room](manager *Manager[PlayerID, P, R], room R, event *event[PlayerID, P, R]) *Seat[PlayerID, P, R] { roomSeat := &Seat[PlayerID, P, R]{ manager: manager, room: room, @@ -18,7 +18,7 @@ func newSeat[PlayerID comparable, P game.Player[PlayerID], R Room[PlayerID, P]]( } // Seat 房间座位信息 -type Seat[PlayerID comparable, P game.Player[PlayerID], R Room[PlayerID, P]] struct { +type Seat[PlayerID comparable, P game.Player[PlayerID], R Room] struct { manager *Manager[PlayerID, P, R] room R event *event[PlayerID, P, R] diff --git a/game/room_seat.go b/game/room_seat.go deleted file mode 100644 index 8814417..0000000 --- a/game/room_seat.go +++ /dev/null @@ -1,47 +0,0 @@ -package game - -// RoomSeat 带有座位号的房间实现 -type RoomSeat[PlayerID comparable, P Player[PlayerID]] interface { - Room[PlayerID, P] - // AddSeat 将玩家添加到座位号中 - AddSeat(id PlayerID) - // AddSeatWithAssign 将玩家添加到座位号中,并分配特定的座位号 - AddSeatWithAssign(id PlayerID, seat int) - // RemovePlayerSeat 移除玩家的座位号 - RemovePlayerSeat(id PlayerID) - // RemoveSeat 移除特定座位号 - RemoveSeat(seat int) - // SetSeat 设置玩家座位号,当玩家没有座位号时,将会返回错误信息 - // - 如果座位号有其他玩家,他们的位置将互换 - SetSeat(id PlayerID, seat int) error - // GetSeat 获取玩家座位号 - GetSeat(id PlayerID) (int, error) - // GetPlayerIDWithSeat 根据座位号获取玩家ID - GetPlayerIDWithSeat(seat int) (PlayerID, error) - // GetSeatInfo 获取座位信息,空缺的位置将为空 - GetSeatInfo() []*PlayerID - // GetSeatInfoMap 以map的方式获取座位号 - GetSeatInfoMap() map[int]PlayerID - // GetSeatInfoMapVacancy 以map的方式获取座位号,空缺的位置将被保留为nil - GetSeatInfoMapVacancy() map[int]*PlayerID - // GetSeatInfoWithPlayerIDMap 获取座位信息,将以玩家ID作为key - GetSeatInfoWithPlayerIDMap() map[PlayerID]int - // GetFirstSeat 获取第一个非空缺座位号,不存在时将返回-1 - GetFirstSeat() int - // GetNextSeat 获取下一个座位号,空缺的位置将会被跳过 - // - 超出范围将返回-1 - // - 当没有下一个座位号时将始终返回本身 - GetNextSeat(seat int) int - // GetNextSeatVacancy 获取下一个座位号,空缺的位置将被保留 - // - 超出范围将返回-1 - // - 当没有下一个座位号时将始终返回本身 - GetNextSeatVacancy(seat int) int - // GetPrevSeat 获取上一个座位号,空缺的位置将会被跳过 - // - 超出范围将返回-1 - // - 当没有上一个座位号时将始终返回本身 - GetPrevSeat(seat int) int - // GetPrevSeatVacancy 获取上一个座位号,空缺的位置将被保留 - // - 超出范围将返回-1 - // - 当没有上一个座位号时将始终返回本身 - GetPrevSeatVacancy(seat int) int -}