package fight import ( "blazing/common/socket/errorcode" "blazing/logic/service/common" "blazing/logic/service/fight/info" "blazing/logic/service/fight/input" "blazing/modules/player/model" "time" ) type FightOption func(*fightBuildOptions) const ( // InputControllerBindingKeep 保持输入中现有的 Player 绑定,不做覆盖。 InputControllerBindingKeep = iota // InputControllerBindingSingle 单侧全部站位由 players[0] 控制(双打单人多站位)。 InputControllerBindingSingle // InputControllerBindingPerSlot 单侧按站位顺序绑定 players[i](组队每人一个站位)。 InputControllerBindingPerSlot ) type fightBuildOptions struct { owner common.PlayerI opponent common.PlayerI ourPlayers []common.PlayerI oppPlayers []common.PlayerI ourInputs []*input.Input oppInputs []*input.Input callback func(model.FightOverInfo) startTime time.Time fightInfo *info.Fightinfo controllerBinding int legacyGroupProtocol bool } // defaultFightBuildOptions 返回建战默认参数。 func defaultFightBuildOptions() *fightBuildOptions { return &fightBuildOptions{ startTime: time.Now(), controllerBinding: InputControllerBindingKeep, } } // WithFightInputs 注入双方站位输入(当前建战主路径)。 func WithFightInputs(ourInputs, oppInputs []*input.Input) FightOption { return func(opts *fightBuildOptions) { opts.ourInputs = ourInputs opts.oppInputs = oppInputs } } // WithFightPlayersOnSide 显式指定双方操作者列表(可选)。 func WithFightPlayersOnSide(ourPlayers, oppPlayers []common.PlayerI) FightOption { return func(opts *fightBuildOptions) { opts.ourPlayers = ourPlayers opts.oppPlayers = oppPlayers } } // WithFightCallback 设置战斗结束回调。 func WithFightCallback(fn func(model.FightOverInfo)) FightOption { return func(opts *fightBuildOptions) { opts.callback = fn } } // WithFightInfo 覆盖战斗信息(模式/状态等)。 func WithFightInfo(fightInfo info.Fightinfo) FightOption { return func(opts *fightBuildOptions) { opts.fightInfo = &fightInfo } } // WithFightStartTime 指定战斗创建时间(测试/回放可用)。 func WithFightStartTime(startTime time.Time) FightOption { return func(opts *fightBuildOptions) { opts.startTime = startTime } } // WithInputControllerBinding 设置站位控制绑定策略。 func WithInputControllerBinding(mode int) FightOption { return func(opts *fightBuildOptions) { opts.controllerBinding = mode } } // WithLegacyGroupProtocol 设置是否使用旧组队协议 CMD。 func WithLegacyGroupProtocol(enabled bool) FightOption { return func(opts *fightBuildOptions) { opts.legacyGroupProtocol = enabled } } func NewFightWithOptions(opts ...FightOption) (*FightC, errorcode.ErrorCode) { buildOpts := defaultFightBuildOptions() for _, opt := range opts { if opt != nil { opt(buildOpts) } } return buildFight(buildOpts) } // uniquePlayersFromInputs 从输入中提取去重后的操作者列表。 func uniquePlayersFromInputs(inputs []*input.Input) []common.PlayerI { if len(inputs) == 0 { return nil } seen := make(map[uint32]struct{}, len(inputs)) players := make([]common.PlayerI, 0, len(inputs)) for _, in := range inputs { if in == nil || in.Player == nil { continue } userID := in.Player.GetInfo().UserID if _, ok := seen[userID]; ok { continue } seen[userID] = struct{}{} players = append(players, in.Player) } return players } // normalizePlayers 归一化 owner/opponent 与双方 players。 // 若未显式传 players,会尝试从 inputs 中自动提取。 func (o *fightBuildOptions) normalizePlayers() { if len(o.ourPlayers) == 0 && len(o.ourInputs) > 0 { o.ourPlayers = uniquePlayersFromInputs(o.ourInputs) } if len(o.oppPlayers) == 0 && len(o.oppInputs) > 0 { o.oppPlayers = uniquePlayersFromInputs(o.oppInputs) } if len(o.ourPlayers) == 0 && o.owner != nil { o.ourPlayers = []common.PlayerI{o.owner} } if len(o.oppPlayers) == 0 && o.opponent != nil { o.oppPlayers = []common.PlayerI{o.opponent} } if o.owner == nil && len(o.ourPlayers) > 0 { o.owner = o.ourPlayers[0] } if o.opponent == nil && len(o.oppPlayers) > 0 { o.opponent = o.oppPlayers[0] } }