2025-06-06 20:02:58 +08:00
|
|
|
|
package baseroom
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"game/common/proto/pb"
|
2025-06-11 23:49:47 +08:00
|
|
|
|
"game/common/utils"
|
2025-06-07 11:57:56 +08:00
|
|
|
|
"github.com/fox/fox/ipb"
|
2025-06-06 20:02:58 +08:00
|
|
|
|
"github.com/fox/fox/log"
|
2025-06-07 11:57:56 +08:00
|
|
|
|
"github.com/fox/fox/processor"
|
|
|
|
|
"github.com/fox/fox/service"
|
2025-06-09 19:10:18 +08:00
|
|
|
|
"github.com/fox/fox/timer"
|
2025-06-06 20:02:58 +08:00
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
type PlayerType int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
PT_User PlayerType = 0
|
|
|
|
|
PT_Robot PlayerType = 1
|
|
|
|
|
PT_All PlayerType = 2
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 房间基类,不要直接用于业务
|
2025-06-06 20:02:58 +08:00
|
|
|
|
type BaseRoom[Seat ISeat] struct {
|
2025-06-07 11:57:56 +08:00
|
|
|
|
id int
|
|
|
|
|
roomType int // 房间配置id 初级,中级,高级
|
2025-06-14 12:31:57 +08:00
|
|
|
|
gameId int // 玩法配置id color玩法id
|
2025-06-07 11:57:56 +08:00
|
|
|
|
gameNo string
|
2025-06-13 14:54:44 +08:00
|
|
|
|
seats []Seat
|
2025-06-07 11:57:56 +08:00
|
|
|
|
processor *processor.Processor
|
2025-06-09 19:10:18 +08:00
|
|
|
|
timeProcessor *processor.TimerProcessor
|
2025-06-06 20:02:58 +08:00
|
|
|
|
|
2025-06-09 19:10:18 +08:00
|
|
|
|
timeTypes map[timer.ITimeType]uint32
|
2025-06-07 11:57:56 +08:00
|
|
|
|
srv service.IService
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 12:31:57 +08:00
|
|
|
|
func NewBaseRoom[Seat ISeat](id, roomType, gameId, seatNum int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
room := &BaseRoom[Seat]{
|
2025-06-07 11:57:56 +08:00
|
|
|
|
id: id,
|
|
|
|
|
roomType: roomType,
|
2025-06-14 12:31:57 +08:00
|
|
|
|
gameId: gameId,
|
2025-06-07 11:57:56 +08:00
|
|
|
|
gameNo: "",
|
2025-06-13 14:54:44 +08:00
|
|
|
|
seats: make([]Seat, seatNum),
|
2025-06-09 19:10:18 +08:00
|
|
|
|
timeTypes: make(map[timer.ITimeType]uint32),
|
2025-06-07 11:57:56 +08:00
|
|
|
|
srv: srv,
|
|
|
|
|
processor: processor.NewProcessor(),
|
2025-06-09 19:10:18 +08:00
|
|
|
|
timeProcessor: processor.NewTimerProcessor(),
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return room, pb.ErrCode_OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) Id() int {
|
|
|
|
|
return r.id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) RoomType() int {
|
|
|
|
|
return r.roomType
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 12:31:57 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) GameId() int {
|
|
|
|
|
return r.gameId
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-15 00:00:24 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) GetService() service.IService {
|
|
|
|
|
return r.srv
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
// 入座玩家数量
|
|
|
|
|
func (r *BaseRoom[Seat]) SeatPlayerNum(playerType PlayerType) int {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
num := 0
|
2025-06-13 14:54:44 +08:00
|
|
|
|
for _, seat := range r.seats {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if !seat.Empty() {
|
2025-06-13 14:54:44 +08:00
|
|
|
|
switch playerType {
|
|
|
|
|
case PT_All:
|
|
|
|
|
num++
|
|
|
|
|
case PT_User:
|
|
|
|
|
if !seat.Player().IsRobot() {
|
|
|
|
|
num++
|
|
|
|
|
}
|
|
|
|
|
case PT_Robot:
|
|
|
|
|
if seat.Player().IsRobot() {
|
|
|
|
|
num++
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return num
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 23:49:47 +08:00
|
|
|
|
// 返回是否有空座位及空座位编号
|
2025-06-13 14:54:44 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) FindEmptySeat() (bool, Seat) {
|
|
|
|
|
for _, seat := range r.seats {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if seat.Empty() {
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return true, seat
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return false, utils.TValue[Seat]{}.V
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
// 查找玩家所在的座位
|
|
|
|
|
func (r *BaseRoom[Seat]) FindSeat(uid int64) (bool, Seat) {
|
|
|
|
|
for _, seat := range r.seats {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if !seat.Empty() && seat.Player().Id() == uid {
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return true, seat
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return false, utils.TValue[Seat]{}.V
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
// 查找玩家所在的座位
|
|
|
|
|
func (r *BaseRoom[Seat]) GetSeat(seatNo int) (bool, Seat) {
|
|
|
|
|
if seatNo < 0 || seatNo >= len(r.seats) {
|
|
|
|
|
return false, utils.TValue[Seat]{}.V
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return true, r.seats[seatNo]
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
// 站起时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
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
2025-06-13 14:54:44 +08:00
|
|
|
|
r.seats[seat].SetPlayer(player)
|
|
|
|
|
return true
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) RangeSeat(proc func(Seat) bool) {
|
|
|
|
|
for _, seat := range r.seats {
|
|
|
|
|
if !seat.Empty() && !proc(seat) {
|
2025-06-10 22:29:29 +08:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 14:54:44 +08:00
|
|
|
|
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)
|
2025-06-10 22:29:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-13 14:54:44 +08:00
|
|
|
|
return seats
|
2025-06-10 22:29:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 20:02:58 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) DebugSendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) {
|
|
|
|
|
log.Debug(r.UserLog(user.Id(), "send msg:%v %v", msgId, msg.String()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) SendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) {
|
|
|
|
|
r.DebugSendMsg(user, msgId, msg)
|
|
|
|
|
if user.Robot() != nil {
|
|
|
|
|
user.Robot().OnMessage(msgId, msg)
|
|
|
|
|
} else {
|
2025-06-13 14:54:44 +08:00
|
|
|
|
iMsg := ipb.MakeMsgEx(r.srv.Name(), 0, user.Id(), int32(msgId), msg)
|
2025-06-17 12:48:14 +08:00
|
|
|
|
_ = r.srv.SendByServiceId(int(pb.ServiceTypeId_STI_Gate), iMsg)
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) Broadcast(msgId pb.MsgId, msg proto.Message, exclude ...IPlayer) {
|
2025-06-13 14:54:44 +08:00
|
|
|
|
for _, seat := range r.seats {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if !seat.Empty() {
|
|
|
|
|
exist := false
|
|
|
|
|
for _, excludePlayer := range exclude {
|
|
|
|
|
if excludePlayer.Id() == seat.Player().Id() {
|
|
|
|
|
exist = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !exist {
|
|
|
|
|
r.SendMsg(seat.Player(), msgId, msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-09 19:10:18 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) NewTimer(timerType timer.ITimeType, duration time.Duration, args ...any) {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if _, ok := r.timeTypes[timerType]; ok {
|
|
|
|
|
log.Error(r.Log("timer type:%v is exist.can not new timer", timerType.String()))
|
|
|
|
|
// if timerType == TtPlayerAct {
|
|
|
|
|
// log.Debug(r.Log(log.StackTrace()))
|
|
|
|
|
// }
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-06-07 11:57:56 +08:00
|
|
|
|
tid := r.srv.NewTimer(duration+time.Duration(10)*time.Millisecond, func() {
|
2025-06-09 19:10:18 +08:00
|
|
|
|
if err := r.timeProcessor.Dispatch(timerType, args...); err != nil {
|
2025-06-07 11:57:56 +08:00
|
|
|
|
log.ErrorF(r.Log("timer dispatch err:%v", err))
|
|
|
|
|
}
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}, true, r.Log("start type:%v timer", timerType.String()))
|
|
|
|
|
r.timeTypes[timerType] = tid
|
|
|
|
|
// log.Debug(r.Log("start type:%v timer", timerType.String()))
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-09 19:10:18 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) CancelTimer(timerType timer.ITimeType) {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if tid, ok := r.timeTypes[timerType]; ok {
|
2025-06-07 11:57:56 +08:00
|
|
|
|
r.srv.CancelTimer(tid)
|
2025-06-06 20:02:58 +08:00
|
|
|
|
delete(r.timeTypes, timerType)
|
|
|
|
|
// log.Debug(r.Log("stop type:%v timer, rest timer:%+v", timerType.String(), r.timeTypes))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) CancelAllTimer() {
|
|
|
|
|
for _, tid := range r.timeTypes {
|
2025-06-07 11:57:56 +08:00
|
|
|
|
r.srv.CancelTimer(tid)
|
2025-06-06 20:02:58 +08:00
|
|
|
|
// log.Debug(r.Log("start type:%v timer", timerType.String()))
|
|
|
|
|
}
|
2025-06-09 19:10:18 +08:00
|
|
|
|
r.timeTypes = make(map[timer.ITimeType]uint32)
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) Log(format string, a ...any) string {
|
|
|
|
|
head := fmt.Sprintf("room:%v type:%v ", r.id, r.roomType)
|
|
|
|
|
return head + fmt.Sprintf(format, a...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) SeatLog(seat Seat, format string, a ...any) string {
|
|
|
|
|
head := ""
|
|
|
|
|
if seat.Player() != nil {
|
|
|
|
|
head = fmt.Sprintf("room:%v type:%v seat:%v user:%v robot:%v ", r.id, r.roomType, seat.No(), seat.Player().Id(), seat.Player().Robot() != nil)
|
|
|
|
|
} else {
|
|
|
|
|
head = fmt.Sprintf("room:%v type:%v seat:%v ", r.id, r.roomType, seat.No())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return head + fmt.Sprintf(format, a...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) UserLog(uid int64, format string, a ...any) string {
|
|
|
|
|
var seat Seat
|
|
|
|
|
exist := false
|
2025-06-13 14:54:44 +08:00
|
|
|
|
for _, st := range r.seats {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
if !st.Empty() && st.Player().Id() == uid {
|
|
|
|
|
seat = st
|
|
|
|
|
exist = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if exist {
|
|
|
|
|
return r.SeatLog(seat, format, a...)
|
|
|
|
|
} else {
|
|
|
|
|
return r.Log(format, a...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 11:57:56 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) Unmarshal(cmd int32, data []byte) (any, error) {
|
|
|
|
|
return r.processor.Unmarshal(cmd, data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) Dispatch(user IPlayer, cmd int32, params ...any) error {
|
2025-06-16 00:50:42 +08:00
|
|
|
|
inp := make([]any, 0, len(params)+1)
|
2025-06-07 11:57:56 +08:00
|
|
|
|
inp = append(inp, user)
|
|
|
|
|
inp = append(inp, params...)
|
|
|
|
|
return r.processor.Dispatch(cmd, inp...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BaseRoom[Seat]) RegisterMessages(metas processor.RegisterMetas) {
|
|
|
|
|
r.processor.RegisterMessages(metas)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 注册时间事件及处理
|
2025-06-09 19:10:18 +08:00
|
|
|
|
func (r *BaseRoom[Seat]) RegisterTimerMessages(metas processor.RegisterTimerMetas) {
|
2025-06-07 11:57:56 +08:00
|
|
|
|
r.timeProcessor.RegisterMessages(metas)
|
2025-06-06 20:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 11:57:56 +08:00
|
|
|
|
// 初始化房间
|
|
|
|
|
func (r *BaseRoom[Seat]) OnInit() {
|
2025-06-06 20:02:58 +08:00
|
|
|
|
|
|
|
|
|
}
|