From 99d726dc2ab287c0055916bc2f973f8b9aa70bd2 Mon Sep 17 00:00:00 2001 From: liuxiaobo Date: Fri, 13 Jun 2025 14:54:44 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BE=E4=BA=BA=E5=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/baseroom/baseRoom.go | 133 ++++++++++---------- common/baseroom/hundredRoom.go | 180 +++++++++++++++++++++++++++ common/baseroom/interface.go | 3 +- server/colorgame/room/c2s.go | 16 +-- server/colorgame/room/colorPlayer.go | 4 + server/colorgame/room/colorRoom.go | 15 ++- 6 files changed, 260 insertions(+), 91 deletions(-) create mode 100644 common/baseroom/hundredRoom.go diff --git a/common/baseroom/baseRoom.go b/common/baseroom/baseRoom.go index 9920f43..4441c42 100644 --- a/common/baseroom/baseRoom.go +++ b/common/baseroom/baseRoom.go @@ -13,12 +13,21 @@ import ( "time" ) +type PlayerType int + +const ( + PT_User PlayerType = 0 + PT_Robot PlayerType = 1 + PT_All PlayerType = 2 +) + +// 房间基类,不要直接用于业务 type BaseRoom[Seat ISeat] struct { id int roomType int // 房间配置id 初级,中级,高级 playType int // 玩法配置id color玩法id gameNo string - Seats []Seat + seats []Seat processor *processor.Processor timeProcessor *processor.TimerProcessor @@ -26,12 +35,13 @@ type BaseRoom[Seat ISeat] struct { srv service.IService } -func NewBaseRoom[Seat ISeat](id, roomType, playType int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) { +func NewBaseRoom[Seat ISeat](id, roomType, playType, seatNum int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) { room := &BaseRoom[Seat]{ id: id, roomType: roomType, playType: playType, gameNo: "", + seats: make([]Seat, seatNum), timeTypes: make(map[timer.ITimeType]uint32), srv: srv, processor: processor.NewProcessor(), @@ -53,93 +63,86 @@ func (r *BaseRoom[Seat]) PlayType() int { return r.playType } -// 入座玩家数量(包含机器人) -func (r *BaseRoom[Seat]) SeatPlayerNum() int { +// 入座玩家数量 +func (r *BaseRoom[Seat]) SeatPlayerNum(playerType PlayerType) int { num := 0 - for _, seat := range r.Seats { + for _, seat := range r.seats { if !seat.Empty() { - num++ - } - } - return num -} - -// 真实玩家数量 -func (r *BaseRoom[Seat]) RealPlayerNum() int { - num := 0 - for _, seat := range r.Seats { - if !seat.Empty() && seat.Player().Robot() == nil { - num++ - } - } - return num -} - -// 机器人数量 -func (r *BaseRoom[Seat]) RobotPlayerNum() int { - num := 0 - for _, seat := range r.Seats { - if !seat.Empty() && seat.Player().Robot() != nil { - num++ + switch playerType { + case PT_All: + num++ + case PT_User: + if !seat.Player().IsRobot() { + num++ + } + case PT_Robot: + if seat.Player().IsRobot() { + num++ + } + } } } return num } // 返回是否有空座位及空座位编号 -func (r *BaseRoom[Seat]) HasEmptySeat() (bool, int) { - for _, seat := range r.Seats { +func (r *BaseRoom[Seat]) FindEmptySeat() (bool, Seat) { + for _, seat := range r.seats { if seat.Empty() { - return true, seat.No() + return true, seat } } - return false, -1 + return false, utils.TValue[Seat]{}.V } -// 查找玩家及玩家所在的座位 -func (r *BaseRoom[Seat]) FindPlayer(uid int64) (IPlayer, Seat) { - for _, seat := range r.Seats { +// 查找玩家所在的座位 +func (r *BaseRoom[Seat]) FindSeat(uid int64) (bool, Seat) { + for _, seat := range r.seats { if !seat.Empty() && seat.Player().Id() == uid { - return seat.Player(), seat + return true, seat } } - return nil, utils.TValue[Seat]{}.V + return false, utils.TValue[Seat]{}.V } -func (r *BaseRoom[Seat]) AddPlayer(player IPlayer, seat int) { - if seat < 0 || seat >= len(r.Seats) { - log.Error(r.SeatLog(r.Seats[seat], "out of range")) - return +// 查找玩家所在的座位 +func (r *BaseRoom[Seat]) GetSeat(seatNo int) (bool, Seat) { + if seatNo < 0 || seatNo >= len(r.seats) { + return false, utils.TValue[Seat]{}.V } - r.Seats[seat].SetPlayer(player) - return + return true, r.seats[seatNo] } -func (r *BaseRoom[Seat]) RemovePlayer(player IPlayer) { - for _, seat := range r.Seats { - if !seat.Empty() && seat.Player().Id() == player.Id() { - seat.SetPlayer(nil) - break - } +// 站起时player为nil,坐下时player非nil +func (r *BaseRoom[Seat]) SitDownOrStandup(player IPlayer, seat int) bool { + if seat < 0 || seat >= len(r.seats) { + log.Error(r.SeatLog(r.seats[seat], "out of range")) + return false } + if player != nil && r.seats[seat].Player() != nil { + log.Error(r.SeatLog(r.seats[seat], "is already here")) + return false + } + r.seats[seat].SetPlayer(player) + return true } -func (r *BaseRoom[Seat]) RangePlayer(proc func(IPlayer) bool) { - for _, seat := range r.Seats { - if !seat.Empty() && !proc(seat.Player()) { +func (r *BaseRoom[Seat]) RangeSeat(proc func(Seat) bool) { + for _, seat := range r.seats { + if !seat.Empty() && !proc(seat) { return } } } -func (r *BaseRoom[Seat]) FilterPlayer(proc func(IPlayer) bool) []IPlayer { - players := make([]IPlayer, 0) - for _, seat := range r.Seats { - if !seat.Empty() && proc(seat.Player()) { - players = append(players, seat.Player()) +func (r *BaseRoom[Seat]) FilterSeat(proc func(Seat) bool) []Seat { + seats := make([]Seat, 0) + for _, seat := range r.seats { + if !seat.Empty() && proc(seat) { + seats = append(seats, seat) } } - return players + return seats } func (r *BaseRoom[Seat]) DebugSendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) { @@ -151,19 +154,13 @@ func (r *BaseRoom[Seat]) SendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message if user.Robot() != nil { user.Robot().OnMessage(msgId, msg) } else { - for _, seat := range r.Seats { - if !seat.Empty() && seat.Player().Id() == user.Id() { - iMsg := ipb.MakeMsgEx(r.srv.Name(), 0, user.Id(), int32(msgId), msg) - _ = r.srv.Send(user.GateTopicName(), iMsg) - break - } - } + iMsg := ipb.MakeMsgEx(r.srv.Name(), 0, user.Id(), int32(msgId), msg) + _ = r.srv.Send(user.GateTopicName(), iMsg) } - } func (r *BaseRoom[Seat]) Broadcast(msgId pb.MsgId, msg proto.Message, exclude ...IPlayer) { - for _, seat := range r.Seats { + for _, seat := range r.seats { if !seat.Empty() { exist := false for _, excludePlayer := range exclude { @@ -231,7 +228,7 @@ func (r *BaseRoom[Seat]) SeatLog(seat Seat, format string, a ...any) string { func (r *BaseRoom[Seat]) UserLog(uid int64, format string, a ...any) string { var seat Seat exist := false - for _, st := range r.Seats { + for _, st := range r.seats { if !st.Empty() && st.Player().Id() == uid { seat = st exist = true diff --git a/common/baseroom/hundredRoom.go b/common/baseroom/hundredRoom.go new file mode 100644 index 0000000..5e619f1 --- /dev/null +++ b/common/baseroom/hundredRoom.go @@ -0,0 +1,180 @@ +package baseroom + +import ( + "fmt" + "game/common/proto/pb" + "github.com/fox/fox/ipb" + "github.com/fox/fox/log" + "github.com/fox/fox/processor" + "github.com/fox/fox/service" + "github.com/fox/fox/timer" + "github.com/golang/protobuf/proto" + "time" +) + +// 百人场 +type HundredRoom struct { + room *BaseRoom[*BaseSeat] + users map[int64]IPlayer // 所有玩家 +} + +func NewHundredRoom(id, roomType, playType int, srv service.IService) (*HundredRoom, pb.ErrCode) { + baseRoom, code := NewBaseRoom[*BaseSeat](id, roomType, playType, 0, srv) + if code != pb.ErrCode_OK { + return nil, code + } + room := &HundredRoom{ + room: baseRoom, + } + return room, pb.ErrCode_OK +} + +func (r *HundredRoom) Id() int { + return r.room.Id() +} + +func (r *HundredRoom) RoomType() int { + return r.room.RoomType() +} + +func (r *HundredRoom) PlayType() int { + return r.room.PlayType() +} + +// 房间玩家数量 +func (r *HundredRoom) GetPlayerNum(playerType PlayerType) int { + if playerType == PT_All { + return len(r.users) + } + num := 0 + for _, user := range r.users { + switch playerType { + case PT_User: + if !user.IsRobot() { + num++ + } + case PT_Robot: + if user.IsRobot() { + num++ + } + } + } + return num +} + +// 查找玩家所在的座位 +func (r *HundredRoom) FindPlayer(uid int64) (IPlayer, bool) { + u, ok := r.users[uid] + return u, ok +} + +// 站起时player为nil,坐下时player非nil +func (r *HundredRoom) AddPayer(user IPlayer) bool { + if _, ok := r.users[user.Id()]; ok { + return false + } + r.users[user.Id()] = user + return true +} + +func (r *HundredRoom) DelPlayer(uid int64) { + delete(r.users, uid) +} + +func (r *HundredRoom) RangePlayer(proc func(IPlayer) bool) { + for _, seat := range r.users { + if !proc(seat) { + return + } + } +} + +func (r *HundredRoom) FilterPlayer(proc func(IPlayer) bool) []IPlayer { + users := make([]IPlayer, 0) + for _, user := range r.users { + if proc(user) { + users = append(users, user) + } + } + return users +} + +func (r *HundredRoom) DebugSendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) { + log.Debug(r.UserLog(user.Id(), "send msg:%v %v", msgId, msg.String())) +} + +func (r *HundredRoom) SendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) { + r.DebugSendMsg(user, msgId, msg) + if user.Robot() != nil { + user.Robot().OnMessage(msgId, msg) + } else { + iMsg := ipb.MakeMsgEx(r.room.srv.Name(), 0, user.Id(), int32(msgId), msg) + _ = r.room.srv.Send(user.GateTopicName(), iMsg) + } + +} + +func (r *HundredRoom) Broadcast(msgId pb.MsgId, msg proto.Message, exclude ...IPlayer) { + for _, user := range r.users { + exist := false + for _, excludePlayer := range exclude { + if excludePlayer.Id() == user.Id() { + exist = true + break + } + } + if !exist { + r.SendMsg(user, msgId, msg) + } + } +} + +func (r *HundredRoom) NewTimer(timerType timer.ITimeType, duration time.Duration, args ...any) { + r.room.NewTimer(timerType, duration, args...) +} + +func (r *HundredRoom) CancelTimer(timerType timer.ITimeType) { + r.room.CancelTimer(timerType) +} + +func (r *HundredRoom) CancelAllTimer() { + r.room.CancelAllTimer() +} + +func (r *HundredRoom) Log(format string, a ...any) string { + return r.room.Log(format, a...) +} + +func (r *HundredRoom) UserLog(uid int64, format string, a ...any) string { + head := "" + user := r.users[uid] + if user != nil { + head = fmt.Sprintf("room:%v type:%v user:%v robot:%v ", r.Id(), r.RoomType(), uid, user.IsRobot()) + } else { + head = fmt.Sprintf("room:%v type:%v ", r.Id(), r.RoomType()) + } + + return head + fmt.Sprintf(format, a...) +} + +func (r *HundredRoom) Unmarshal(cmd int32, data []byte) (any, error) { + return r.room.Unmarshal(cmd, data) +} + +func (r *HundredRoom) Dispatch(user IPlayer, cmd int32, params ...any) error { + return r.room.Dispatch(user, cmd, params...) +} + +func (r *HundredRoom) RegisterMessages(metas processor.RegisterMetas) { + r.room.RegisterMessages(metas) +} + +// 注册时间事件及处理 +func (r *HundredRoom) RegisterTimerMessages(metas processor.RegisterTimerMetas) { + r.room.RegisterTimerMessages(metas) +} + +// 初始化房间 +func (r *HundredRoom) OnInit() { + +} diff --git a/common/baseroom/interface.go b/common/baseroom/interface.go index ff01bb2..a9a2139 100644 --- a/common/baseroom/interface.go +++ b/common/baseroom/interface.go @@ -11,7 +11,7 @@ type IRoom interface { PlayType() int OnInit() // SeatPlayerNum() int - // HasEmptySeat() bool + // FindEmptySeat() bool // FindPlayer(uid int64) bool Unmarshal(cmd int32, data []byte) (any, error) Dispatch(user IPlayer, cmd int32, params ...any) error @@ -30,6 +30,7 @@ type ISeat interface { type IPlayer interface { Id() int64 Robot() IRobot + IsRobot() bool GateTopicName() string RoomId() int } diff --git a/server/colorgame/room/c2s.go b/server/colorgame/room/c2s.go index 762633a..c8fb28b 100644 --- a/server/colorgame/room/c2s.go +++ b/server/colorgame/room/c2s.go @@ -1,7 +1,6 @@ package room import ( - "game/common/baseroom" "game/common/proto/pb" "github.com/fox/fox/ipb" ) @@ -25,17 +24,7 @@ func (rm *ColorRoom) onMatchRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, req * } func (rm *ColorRoom) enterRoom(user *ColorPlayer) { - // 第一次进房间分配座位 - if u, _ := rm.FindPlayer(user.ID); u == nil { - var seat *baseroom.BaseSeat - if exist, no := rm.HasEmptySeat(); exist { - seat = rm.Seats[no] - } else { - rm.Seats = append(rm.Seats, baseroom.NewBaseSeat(len(rm.Seats))) - seat = rm.Seats[len(rm.Seats)-1] - } - seat.SetPlayer(user) - } + _ = rm.AddPayer(user) rm.notifyColorRoomInfo(user) } @@ -62,8 +51,7 @@ func (rm *ColorRoom) checkLeaveRoom(user *ColorPlayer, iMsg *ipb.InternalMsg, re } func (rm *ColorRoom) leaveRoom(user *ColorPlayer) { - _, st := rm.FindPlayer(user.Id()) - st.SetPlayer(nil) + rm.DelPlayer(user.Id()) rm.userMgr.Del(user.ID) } diff --git a/server/colorgame/room/colorPlayer.go b/server/colorgame/room/colorPlayer.go index ea4450a..73c708c 100644 --- a/server/colorgame/room/colorPlayer.go +++ b/server/colorgame/room/colorPlayer.go @@ -35,6 +35,10 @@ func (p *ColorPlayer) Robot() baseroom.IRobot { return nil } +func (p *ColorPlayer) IsRobot() bool { + return false +} + func (p *ColorPlayer) GateTopicName() string { return p.gateTopicName } diff --git a/server/colorgame/room/colorRoom.go b/server/colorgame/room/colorRoom.go index 7e068a9..5548413 100644 --- a/server/colorgame/room/colorRoom.go +++ b/server/colorgame/room/colorRoom.go @@ -12,7 +12,7 @@ import ( ) type ColorRoom struct { - *baseroom.BaseRoom[*baseroom.BaseSeat] + *baseroom.HundredRoom userMgr *baseroom.PlayerMgr roomCfg *game.ColorRoomConfig @@ -35,7 +35,7 @@ type ColorRoom struct { func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.PlayerMgr) (baseroom.IRoom, pb.ErrCode) { playType := int(pb.ServiceTypeId_STI_ColorGame) rm := &ColorRoom{ - BaseRoom: nil, + HundredRoom: nil, userMgr: userMgr, roomCfg: &game.ColorRoomConfig{}, timingCfg: &game.ColorGameTiming{}, @@ -50,7 +50,7 @@ func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.Play rm.resetGameData() code := pb.ErrCode_OK - rm.BaseRoom, code = baseroom.NewBaseRoom[*baseroom.BaseSeat](id, roomType, playType, srv) + rm.HundredRoom, code = baseroom.NewHundredRoom(id, roomType, playType, srv) if code != pb.ErrCode_OK { log.ErrorF("new color room err code:%v", code) return nil, code @@ -99,11 +99,10 @@ func (rm *ColorRoom) resetGameData() { rm.initPrizeAreaRange() // 清理玩家身上数据 - for _, st := range rm.Seats { - if st.Player() != nil { - GetPlayer(st.Player()).resetData() - } - } + rm.RangePlayer(func(u baseroom.IPlayer) bool { + GetPlayer(u).resetData() + return true + }) // 游戏开始前清理不下注玩家 rm.kickoutUsers()