From 46017d8bc03a2a8cb1464b8e3469d9c6858ce9d6 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 12 May 2023 10:00:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E7=9A=84=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E3=80=81=E8=A1=A5=E4=BD=8D=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/builtin/room_seat.go | 63 ++++++++++++++++++++++++++++++- game/builtin/room_seat_options.go | 14 +++++++ game/room_seat.go | 8 ++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 game/builtin/room_seat_options.go diff --git a/game/builtin/room_seat.go b/game/builtin/room_seat.go index 693c99e..e697ea0 100644 --- a/game/builtin/room_seat.go +++ b/game/builtin/room_seat.go @@ -2,29 +2,38 @@ package builtin import ( "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/hash" + "github.com/kercylan98/minotaur/utils/slice" "github.com/kercylan98/minotaur/utils/synchronization" "sync" ) -func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player]) *RoomSeat[PlayerID, Player] { +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: synchronization.NewMap[PlayerID, int](), } room.RegPlayerJoinRoomEvent(roomSeat.onJoinRoom) room.RegPlayerLeaveRoomEvent(roomSeat.onLeaveRoom) + for _, option := range options { + option(roomSeat) + } return roomSeat } type RoomSeat[PlayerID comparable, Player game.Player[PlayerID]] struct { game.Room[PlayerID, Player] - mutex sync.Mutex + mutex sync.RWMutex vacancy []int seatPS *synchronization.Map[PlayerID, int] seatSP []*PlayerID + + fillIn bool } func (slf *RoomSeat[PlayerID, Player]) SetSeat(id PlayerID, seat int) error { + slf.mutex.Lock() + defer slf.mutex.Unlock() oldSeat, err := slf.GetSeat(id) if err != nil { return err @@ -39,6 +48,15 @@ func (slf *RoomSeat[PlayerID, Player]) SetSeat(id PlayerID, seat int) error { } 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)...) } @@ -58,6 +76,8 @@ func (slf *RoomSeat[PlayerID, Player]) GetSeat(id PlayerID) (int, error) { } func (slf *RoomSeat[PlayerID, Player]) GetPlayerWithSeat(seat int) (player Player, err error) { + slf.mutex.RLock() + defer slf.mutex.RUnlock() if seat > len(slf.seatSP)-1 { return player, ErrRoomNotHasPlayer } @@ -68,6 +88,35 @@ func (slf *RoomSeat[PlayerID, Player]) GetPlayerWithSeat(seat int) (player Playe return slf.GetPlayer(*id), nil } +func (slf *RoomSeat[PlayerID, Player]) GetSeatInfo() []*PlayerID { + slf.mutex.RLock() + defer slf.mutex.RUnlock() + return slf.seatSP +} + +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 +} + +func (slf *RoomSeat[PlayerID, Player]) GetSeatInfoMapVacancy() map[int]*PlayerID { + slf.mutex.RLock() + defer slf.mutex.RUnlock() + return hash.ToMap(slf.seatSP) +} + +func (slf *RoomSeat[PlayerID, Player]) GetSeatInfoWithPlayerIDMap() map[PlayerID]int { + return slf.seatPS.Map() +} + func (slf *RoomSeat[PlayerID, Player]) onJoinRoom(room game.Room[PlayerID, Player], player Player) { slf.mutex.Lock() defer slf.mutex.Unlock() @@ -84,6 +133,16 @@ func (slf *RoomSeat[PlayerID, Player]) onJoinRoom(room game.Room[PlayerID, Playe } func (slf *RoomSeat[PlayerID, Player]) onLeaveRoom(room game.Room[PlayerID, Player], player Player) { + slf.mutex.Lock() + defer slf.mutex.Unlock() seat := slf.seatPS.DeleteGet(player.GetID()) + 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 + } diff --git a/game/builtin/room_seat_options.go b/game/builtin/room_seat_options.go new file mode 100644 index 0000000..5e53026 --- /dev/null +++ b/game/builtin/room_seat_options.go @@ -0,0 +1,14 @@ +package builtin + +import "github.com/kercylan98/minotaur/game" + +type RoomSeatOption[PlayerID comparable, Player game.Player[PlayerID]] func(seat *RoomSeat[PlayerID, Player]) + +// 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_seat.go b/game/room_seat.go index 69f59c8..3b2ccb4 100644 --- a/game/room_seat.go +++ b/game/room_seat.go @@ -9,4 +9,12 @@ type RoomSeat[PlayerID comparable, P Player[PlayerID]] interface { GetSeat(id PlayerID) (int, error) // GetPlayerWithSeat 根据座位号获取玩家 GetPlayerWithSeat(seat int) (P, error) + // GetSeatInfo 获取座位信息,空缺的位置将为空 + GetSeatInfo() []*PlayerID + // GetSeatInfoMap 以map的方式获取座位号 + GetSeatInfoMap() map[int]PlayerID + // GetSeatInfoMapVacancy 以map的方式获取座位号,空缺的位置将被保留为nil + GetSeatInfoMapVacancy() map[int]*PlayerID + // GetSeatInfoWithPlayerIDMap 获取座位信息,将以玩家ID作为key + GetSeatInfoWithPlayerIDMap() map[PlayerID]int }