diff --git a/game/builtin/room.go b/game/builtin/room.go index c6ae16d..efe24c0 100644 --- a/game/builtin/room.go +++ b/game/builtin/room.go @@ -16,13 +16,17 @@ func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64) *Roo } type Room[PlayerID comparable, Player game.Player[PlayerID]] struct { - guid int64 - playerLimit int - playersConn *synchronization.Map[string, Player] - players *synchronization.Map[PlayerID, Player] + guid int64 + owner PlayerID + noMaster bool + playerLimit int + playersConn *synchronization.Map[string, Player] + players *synchronization.Map[PlayerID, Player] + kickCheckHandle func(id, target PlayerID) error playerJoinRoomEventHandles []game.PlayerJoinRoomEventHandle[PlayerID, Player] playerLeaveRoomEventHandles []game.PlayerLeaveRoomEventHandle[PlayerID, Player] + playerKickedOutEventHandles []game.PlayerKickedOutEventHandle[PlayerID, Player] } func (slf *Room[PlayerID, Player]) GetGuid() int64 { @@ -49,6 +53,10 @@ func (slf *Room[PlayerID, Player]) IsExistPlayer(id PlayerID) bool { return slf.players.Exist(id) } +func (slf *Room[PlayerID, Player]) IsOwner(id PlayerID) bool { + return !slf.noMaster && slf.owner == id +} + func (slf *Room[PlayerID, Player]) Join(player Player) error { if slf.players.Size() >= slf.playerLimit && slf.playerLimit > 0 { return ErrWorldPlayerLimit @@ -56,6 +64,9 @@ func (slf *Room[PlayerID, Player]) Join(player Player) error { log.Debug("Room.Join", zap.Any("guid", slf.GetGuid()), zap.Any("player", player.GetID()), zap.String("conn", player.GetConnID())) slf.players.Set(player.GetID(), player) slf.playersConn.Set(player.GetConnID(), player) + if slf.players.Size() == 1 && !slf.noMaster { + slf.owner = player.GetID() + } slf.OnPlayerJoinRoomEvent(player) return nil } @@ -71,6 +82,26 @@ func (slf *Room[PlayerID, Player]) Leave(id PlayerID) { slf.playersConn.Delete(player.GetConnID()) } +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(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 +} + func (slf *Room[PlayerID, Player]) RegPlayerJoinRoomEvent(handle game.PlayerJoinRoomEventHandle[PlayerID, Player]) { slf.playerJoinRoomEventHandles = append(slf.playerJoinRoomEventHandles, handle) } @@ -90,3 +121,13 @@ func (slf *Room[PlayerID, Player]) OnPlayerLeaveRoomEvent(player Player) { handle(slf, player) } } + +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 new file mode 100644 index 0000000..17f0d80 --- /dev/null +++ b/game/builtin/room_errors.go @@ -0,0 +1,8 @@ +package builtin + +import "errors" + +var ( + 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_options.go b/game/builtin/room_options.go index 7d5251b..993852c 100644 --- a/game/builtin/room_options.go +++ b/game/builtin/room_options.go @@ -11,3 +11,18 @@ func WithRoomPlayerLimit[PlayerID comparable, Player game.Player[PlayerID]](play 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(id, target PlayerID) error) RoomOption[PlayerID, Player] { + return func(room *Room[PlayerID, Player]) { + room.kickCheckHandle = handle + } +} diff --git a/game/room.go b/game/room.go index 39fcd8b..61cf54c 100644 --- a/game/room.go +++ b/game/room.go @@ -16,11 +16,15 @@ type Room[PlayerID comparable, P Player[PlayerID]] interface { GetPlayers() synchronization.MapReadonly[PlayerID, P] // IsExistPlayer 检查房间中是否存在特定玩家 IsExistPlayer(id PlayerID) bool + // IsOwner 检查玩家是否是房主 + IsOwner(id PlayerID) bool // Join 使特定玩家加入房间 Join(player P) error // Leave 使特定玩家离开房间 Leave(id PlayerID) + // KickOut 将特定玩家踢出房间 + KickOut(id, target PlayerID, reason string) error // RegPlayerJoinRoomEvent 玩家进入房间时将立即执行被注册的事件处理函数 RegPlayerJoinRoomEvent(handle PlayerJoinRoomEventHandle[PlayerID, P]) @@ -28,9 +32,13 @@ type Room[PlayerID comparable, P Player[PlayerID]] interface { // 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) )