feat: 支持多站位战斗控制绑定模式
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
xinian
2026-04-05 00:03:32 +08:00
committed by cnb
parent 2eba4b7915
commit f473c54880
4 changed files with 491 additions and 52 deletions

View File

@@ -11,6 +11,15 @@ import (
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
@@ -18,37 +27,25 @@ type fightBuildOptions struct {
ourPlayers []common.PlayerI
oppPlayers []common.PlayerI
ourPets []model.PetInfo
oppPets []model.PetInfo
ourInputs []*input.Input
oppInputs []*input.Input
callback func(model.FightOverInfo)
startTime time.Time
fightInfo *info.Fightinfo
controllerBinding int
}
// defaultFightBuildOptions 返回建战默认参数。
func defaultFightBuildOptions() *fightBuildOptions {
return &fightBuildOptions{
startTime: time.Now(),
}
}
func WithFightPlayers(owner, opponent common.PlayerI) FightOption {
return func(opts *fightBuildOptions) {
opts.owner = owner
opts.opponent = opponent
}
}
func WithFightPets(ourPets, oppPets []model.PetInfo) FightOption {
return func(opts *fightBuildOptions) {
opts.ourPets = ourPets
opts.oppPets = oppPets
startTime: time.Now(),
controllerBinding: InputControllerBindingKeep,
}
}
// WithFightInputs 注入双方站位输入(当前建战主路径)。
func WithFightInputs(ourInputs, oppInputs []*input.Input) FightOption {
return func(opts *fightBuildOptions) {
opts.ourInputs = ourInputs
@@ -56,6 +53,7 @@ func WithFightInputs(ourInputs, oppInputs []*input.Input) FightOption {
}
}
// WithFightPlayersOnSide 显式指定双方操作者列表(可选)。
func WithFightPlayersOnSide(ourPlayers, oppPlayers []common.PlayerI) FightOption {
return func(opts *fightBuildOptions) {
opts.ourPlayers = ourPlayers
@@ -63,24 +61,34 @@ func WithFightPlayersOnSide(ourPlayers, oppPlayers []common.PlayerI) FightOption
}
}
// 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
}
}
func NewFightWithOptions(opts ...FightOption) (*FightC, errorcode.ErrorCode) {
buildOpts := defaultFightBuildOptions()
for _, opt := range opts {
@@ -91,11 +99,46 @@ func NewFightWithOptions(opts ...FightOption) (*FightC, errorcode.ErrorCode) {
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]
}
}