game/common/baseroom/baseRoom.go
2025-06-16 00:50:42 +08:00

273 lines
6.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package baseroom
import (
"fmt"
"game/common/proto/pb"
"game/common/utils"
"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 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 初级,中级,高级
gameId int // 玩法配置id color玩法id
gameNo string
seats []Seat
processor *processor.Processor
timeProcessor *processor.TimerProcessor
timeTypes map[timer.ITimeType]uint32
srv service.IService
}
func NewBaseRoom[Seat ISeat](id, roomType, gameId, seatNum int, srv service.IService) (*BaseRoom[Seat], pb.ErrCode) {
room := &BaseRoom[Seat]{
id: id,
roomType: roomType,
gameId: gameId,
gameNo: "",
seats: make([]Seat, seatNum),
timeTypes: make(map[timer.ITimeType]uint32),
srv: srv,
processor: processor.NewProcessor(),
timeProcessor: processor.NewTimerProcessor(),
}
return room, pb.ErrCode_OK
}
func (r *BaseRoom[Seat]) Id() int {
return r.id
}
func (r *BaseRoom[Seat]) RoomType() int {
return r.roomType
}
func (r *BaseRoom[Seat]) GameId() int {
return r.gameId
}
func (r *BaseRoom[Seat]) GetService() service.IService {
return r.srv
}
// 入座玩家数量
func (r *BaseRoom[Seat]) SeatPlayerNum(playerType PlayerType) int {
num := 0
for _, seat := range r.seats {
if !seat.Empty() {
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]) FindEmptySeat() (bool, Seat) {
for _, seat := range r.seats {
if seat.Empty() {
return true, seat
}
}
return false, utils.TValue[Seat]{}.V
}
// 查找玩家所在的座位
func (r *BaseRoom[Seat]) FindSeat(uid int64) (bool, Seat) {
for _, seat := range r.seats {
if !seat.Empty() && seat.Player().Id() == uid {
return true, seat
}
}
return false, utils.TValue[Seat]{}.V
}
// 查找玩家所在的座位
func (r *BaseRoom[Seat]) GetSeat(seatNo int) (bool, Seat) {
if seatNo < 0 || seatNo >= len(r.seats) {
return false, utils.TValue[Seat]{}.V
}
return true, r.seats[seatNo]
}
// 站起时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]) RangeSeat(proc func(Seat) bool) {
for _, seat := range r.seats {
if !seat.Empty() && !proc(seat) {
return
}
}
}
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 seats
}
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 {
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 {
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)
}
}
}
}
func (r *BaseRoom[Seat]) NewTimer(timerType timer.ITimeType, duration time.Duration, args ...any) {
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
}
tid := r.srv.NewTimer(duration+time.Duration(10)*time.Millisecond, func() {
if err := r.timeProcessor.Dispatch(timerType, args...); err != nil {
log.ErrorF(r.Log("timer dispatch err:%v", err))
}
}, true, r.Log("start type:%v timer", timerType.String()))
r.timeTypes[timerType] = tid
// log.Debug(r.Log("start type:%v timer", timerType.String()))
}
func (r *BaseRoom[Seat]) CancelTimer(timerType timer.ITimeType) {
if tid, ok := r.timeTypes[timerType]; ok {
r.srv.CancelTimer(tid)
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 {
r.srv.CancelTimer(tid)
// log.Debug(r.Log("start type:%v timer", timerType.String()))
}
r.timeTypes = make(map[timer.ITimeType]uint32)
}
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
for _, st := range r.seats {
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...)
}
}
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 {
inp := make([]any, 0, len(params)+1)
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)
}
// 注册时间事件及处理
func (r *BaseRoom[Seat]) RegisterTimerMessages(metas processor.RegisterTimerMetas) {
r.timeProcessor.RegisterMessages(metas)
}
// 初始化房间
func (r *BaseRoom[Seat]) OnInit() {
}