```
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

fix(fight): 修复单输入战斗中效果处理逻辑错误

- 在Effect201的OnSkill方法中调整了多输入战斗检查的位置,
  确保单输入战斗中的单目标效果被正确忽略

- 添加了针对单输入战斗中单目标效果的测试用例

- 移除了重复的多输入战斗检查代码

feat(fight): 添加战斗初始化时捕获标识设置功能

- 在initfightready函数中添加对CanCapture字段的处理
  将玩家的捕获能力信息传递到战斗准备信息中

- 在ReadyFightPetInfo结构体中添加IsCapture字段用于
  标识宠物是否为捕获类型

refactor(fight): 调整战斗初始化顺序确保数据一致性

- 将ReadyInfo初始化移到绑定输入上下文之后执行
  确保团队视图链接完成后再进行准备信息构建

fix(player): 增加宠物血量检查避免无效匹配

- 在玩家匹配检测中增加首只宠物血量检查
  当首只宠物血量为0时不参与匹配以防止异常情况
```
This commit is contained in:
昔念
2026-04-13 10:21:13 +08:00
parent e161e3626f
commit eca7dd86e1
6 changed files with 112 additions and 48 deletions

View File

@@ -485,7 +485,11 @@ func initfightready(in *input.Input) (model.FightUserInfo, []model.ReadyFightPet
panic(err) panic(err)
} }
if i == 0 && in.CanCapture > 0 { if i == 0 && in.CanCapture > 0 {
t[i].IsCapture = uint32(in.CanCapture) if in.CanCapture > 255 {
t[i].IsCapture = 255
} else {
t[i].IsCapture = uint8(in.CanCapture)
}
} }
} }

View File

@@ -10,9 +10,9 @@ const TableNameServerShow = "server_show"
// ServerShow 绑定服务器展示信息(冠名、属主、到期时间)。 // ServerShow 绑定服务器展示信息(冠名、属主、到期时间)。
type ServerShow struct { type ServerShow struct {
*cool.Model *cool.Model
ServerID uint32 `gorm:"column:server_id;comment:'服务器ID';uniqueIndex" json:"server_id"` ServerID uint32 `gorm:"column:server_id;comment:'服务器ID';index:idx_server_show_server_id;uniqueIndex:idx_server_show_server_owner" json:"server_id"`
Name string `gorm:"comment:'服务器展示名'" json:"name"` Name string `gorm:"comment:'服务器展示名'" json:"name"`
Owner uint32 `gorm:"comment:'服务器属主'" json:"owner"` Owner uint32 `gorm:"comment:'服务器属主';uniqueIndex:idx_server_show_server_owner" json:"owner"`
ExpireTime time.Time `gorm:"column:expire_time;default:0;comment:'展示到期时间'" json:"expire_time"` ExpireTime time.Time `gorm:"column:expire_time;default:0;comment:'展示到期时间'" json:"expire_time"`
} }

View File

@@ -196,7 +196,7 @@ func (s *CdkService) UseServerNamingCDK(ctx context.Context, code string, ownerI
} }
var server model.ServerList var server model.ServerList
if err := tx.Model(model.NewServerList()).With(model.ServerShow{}).Where("online_id", serverID).Scan(&server); err != nil { if err := tx.Model(model.NewServerList()).Where("online_id", serverID).Scan(&server); err != nil {
return err return err
} }
if server.OnlineID == 0 { if server.OnlineID == 0 {
@@ -216,8 +216,13 @@ func (s *CdkService) UseServerNamingCDK(ctx context.Context, code string, ownerI
} }
var currentShow model.ServerShow var currentShow model.ServerShow
if server.ServerShow != nil { if err := tx.Model(model.NewServerShow()).
currentShow = *server.ServerShow Where("server_id", serverID).
Where("owner", ownerID).
OrderDesc("id").
Limit(1).
Scan(&currentShow); err != nil {
return err
} }
updated = currentShow updated = currentShow
@@ -225,7 +230,7 @@ func (s *CdkService) UseServerNamingCDK(ctx context.Context, code string, ownerI
updated.Name = serverName updated.Name = serverName
updated.Owner = ownerID updated.Owner = ownerID
if currentShow.ServerID == 0 || !serverService.isActiveServerShow(&currentShow, now) || currentShow.Owner != ownerID { if currentShow.ServerID == 0 || !serverService.isActiveServerShow(&currentShow, now) {
updated.ExpireTime = now.AddDate(0, 1, 0) updated.ExpireTime = now.AddDate(0, 1, 0)
} else { } else {
baseTime := currentShow.ExpireTime baseTime := currentShow.ExpireTime

View File

@@ -55,7 +55,7 @@ func NewServerService() *ServerService {
} }
serverIDs = append(serverIDs, serverID) serverIDs = append(serverIDs, serverID)
} }
showMap := cf.getActiveServerShowMap(serverIDs, now) showMap := cf.getPrimaryActiveServerShowMap(serverIDs, now)
for i := 0; i < len(r); i++ { for i := 0; i < len(r); i++ {
t, ok := cool.GetClient(gconv.Uint32(r[i].Map()["online_id"]), gconv.Uint32(r[i].Map()["port"])) t, ok := cool.GetClient(gconv.Uint32(r[i].Map()["online_id"]), gconv.Uint32(r[i].Map()["port"]))
@@ -93,7 +93,9 @@ func NewServerService() *ServerService {
} }
func (s *ServerService) GetPort(DepartmentID uint) []ServerShowInfo { func (s *ServerService) GetPort(DepartmentID uint) []ServerShowInfo {
servers := s.GetServer() servers := s.getRawServers()
now := time.Now()
showMap := s.getActiveServerShowListMap(s.collectServerIDs(servers), now)
items := make([]ServerShowInfo, 0, len(servers)) items := make([]ServerShowInfo, 0, len(servers))
for _, server := range servers { for _, server := range servers {
if server.IsOpen != 1 { if server.IsOpen != 1 {
@@ -110,17 +112,34 @@ func (s *ServerService) GetPort(DepartmentID uint) []ServerShowInfo {
IsVip: server.IsVip, IsVip: server.IsVip,
IsDebug: server.IsDebug, IsDebug: server.IsDebug,
IsOpen: server.IsOpen, IsOpen: server.IsOpen,
Owner: server.Owner, Owner: 0,
ExpireTime: server.ExpireTime, ExpireTime: time.Time{},
ServerShow: server.ServerShow,
}) })
for i := range showMap[server.OnlineID] {
show := &showMap[server.OnlineID][i]
item := ServerShowInfo{
OnlineID: server.OnlineID,
Name: server.Name,
IP: server.IP,
Port: server.Port,
IsVip: server.IsVip,
IsDebug: server.IsDebug,
IsOpen: server.IsOpen,
Owner: show.Owner,
ExpireTime: show.ExpireTime,
ServerShow: show,
}
if show.Name != "" {
item.Name = show.Name
}
items = append(items, item)
}
} }
return items return items
} }
func (s *ServerService) GetServer() []model.ServerList { func (s *ServerService) GetServer() []model.ServerList {
var item []model.ServerList item := s.getRawServers()
dbm_nocache_noenable(s.Model).With(model.ServerShow{}).Scan(&item)
s.applyServerShowList(item, time.Now()) s.applyServerShowList(item, time.Now())
return item return item
} }
@@ -149,23 +168,20 @@ func (s *ServerService) SetServerID(OnlineID uint32, Port uint32) error {
func (s *ServerService) GetServerID(OnlineID uint32) model.ServerList { func (s *ServerService) GetServerID(OnlineID uint32) model.ServerList {
var tttt model.ServerList var tttt model.ServerList
dbm_nocache_noenable(s.Model).With(model.ServerShow{}).Where("online_id", OnlineID).Scan(&tttt) dbm_nocache_noenable(s.Model).Where("online_id", OnlineID).Scan(&tttt)
s.applyServerShow(&tttt, time.Now()) showMap := s.getPrimaryActiveServerShowMap([]uint32{OnlineID}, time.Now())
s.applyServerShow(&tttt, showMap[OnlineID], time.Now())
return tttt return tttt
} }
// GetDonationAvailableServerIDs 返回当前可被冠名占用的服务器ID列表。 // GetDonationAvailableServerIDs 返回当前可被冠名占用的服务器ID列表。
func (s *ServerService) GetDonationAvailableServerIDs() []uint32 { func (s *ServerService) GetDonationAvailableServerIDs() []uint32 {
servers := s.GetServer() servers := s.getRawServers()
now := time.Now()
ids := make([]uint32, 0, len(servers)) ids := make([]uint32, 0, len(servers))
for _, server := range servers { for _, server := range servers {
if server.OnlineID == 0 { if server.OnlineID == 0 {
continue continue
} }
if s.isActiveServerShow(server.ServerShow, now) {
continue
}
ids = append(ids, server.OnlineID) ids = append(ids, server.OnlineID)
} }
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
@@ -174,13 +190,24 @@ func (s *ServerService) GetDonationAvailableServerIDs() []uint32 {
// CanUseDonationName 校验目标服务器在当前时间点是否允许被冠名。 // CanUseDonationName 校验目标服务器在当前时间点是否允许被冠名。
func (s *ServerService) CanUseDonationName(server model.ServerList, ownerID uint32, now time.Time) bool { func (s *ServerService) CanUseDonationName(server model.ServerList, ownerID uint32, now time.Time) bool {
if server.OnlineID == 0 { return server.OnlineID != 0
return false }
func (s *ServerService) getRawServers() []model.ServerList {
var item []model.ServerList
dbm_nocache_noenable(s.Model).Scan(&item)
return item
}
func (s *ServerService) collectServerIDs(servers []model.ServerList) []uint32 {
serverIDs := make([]uint32, 0, len(servers))
for i := range servers {
if servers[i].OnlineID == 0 {
continue
}
serverIDs = append(serverIDs, servers[i].OnlineID)
} }
if !s.isActiveServerShow(server.ServerShow, now) { return serverIDs
return true
}
return server.ServerShow.Owner == ownerID
} }
// 保存版本号 // 保存版本号
@@ -244,29 +271,32 @@ func (s *ServerService) isActiveServerShow(show *model.ServerShow, now time.Time
} }
func (s *ServerService) applyServerShowList(servers []model.ServerList, now time.Time) { func (s *ServerService) applyServerShowList(servers []model.ServerList, now time.Time) {
showMap := s.getPrimaryActiveServerShowMap(s.collectServerIDs(servers), now)
for i := range servers { for i := range servers {
s.applyServerShow(&servers[i], now) s.applyServerShow(&servers[i], showMap[servers[i].OnlineID], now)
} }
} }
func (s *ServerService) applyServerShow(server *model.ServerList, now time.Time) { func (s *ServerService) applyServerShow(server *model.ServerList, show *model.ServerShow, now time.Time) {
if server == nil { if server == nil {
return return
} }
server.ServerShow = nil
server.Owner = 0 server.Owner = 0
server.ExpireTime = time.Time{} server.ExpireTime = time.Time{}
if !s.isActiveServerShow(server.ServerShow, now) { if !s.isActiveServerShow(show, now) {
return return
} }
if server.ServerShow.Name != "" { server.ServerShow = show
server.Name = server.ServerShow.Name if show.Name != "" {
server.Name = show.Name
} }
server.Owner = server.ServerShow.Owner server.Owner = show.Owner
server.ExpireTime = server.ServerShow.ExpireTime server.ExpireTime = show.ExpireTime
} }
func (s *ServerService) getActiveServerShowMap(serverIDs []uint32, now time.Time) map[uint32]*model.ServerShow { func (s *ServerService) getActiveServerShowListMap(serverIDs []uint32, now time.Time) map[uint32][]model.ServerShow {
showMap := make(map[uint32]*model.ServerShow, len(serverIDs)) showMap := make(map[uint32][]model.ServerShow, len(serverIDs))
if len(serverIDs) == 0 { if len(serverIDs) == 0 {
return showMap return showMap
} }
@@ -277,7 +307,30 @@ func (s *ServerService) getActiveServerShowMap(serverIDs []uint32, now time.Time
if !s.isActiveServerShow(show, now) { if !s.isActiveServerShow(show, now) {
continue continue
} }
showMap[show.ServerID] = show showMap[show.ServerID] = append(showMap[show.ServerID], *show)
}
for serverID := range showMap {
sort.Slice(showMap[serverID], func(i, j int) bool {
left := showMap[serverID][i]
right := showMap[serverID][j]
if !left.ExpireTime.Equal(right.ExpireTime) {
return left.ExpireTime.After(right.ExpireTime)
}
return left.ID > right.ID
})
}
return showMap
}
func (s *ServerService) getPrimaryActiveServerShowMap(serverIDs []uint32, now time.Time) map[uint32]*model.ServerShow {
listMap := s.getActiveServerShowListMap(serverIDs, now)
showMap := make(map[uint32]*model.ServerShow, len(listMap))
for serverID := range listMap {
if len(listMap[serverID]) == 0 {
continue
}
show := listMap[serverID][0]
showMap[serverID] = &show
} }
return showMap return showMap
} }

View File

@@ -199,16 +199,18 @@ type PlayerInfo struct {
Nick string `struc:"[16]byte" default:"nono" json:"nono_nick"` // nono名字16字节 Nick string `struc:"[16]byte" default:"nono" json:"nono_nick"` // nono名字16字节
} }
TeamInfo TeamInfo `struc:"struct" json:"team_info"` // 战队信息24字节 TeamInfo TeamInfo `struc:"struct" json:"team_info"` // 战队信息24字节
TeamPkInfo TeamPKInfo `struc:"struct" json:"team_pk_info"` // 8字节 TeamPkInfo TeamPKInfo `struc:"struct" json:"team_pk_info"` // 8字节
Reserved byte `struc:"byte" json:"reserved"` // 1字节无内容 Reserved byte `struc:"byte" json:"reserved"` // 1字节无内容
Badge uint32 `struc:"uint32" default:"0" json:"badge"` // 默认0 Badge uint32 `struc:"uint32" default:"0" json:"badge"` // 默认0
Reserved1 [27]byte `struc:"[27]byte" default:"3" json:"reserved1"` // 27字节默认3 Reserved1 [27]byte `struc:"[27]byte" default:"3" json:"reserved1"` // 27字节默认3
TaskList [1000]byte `struc:"[1000]byte" default:"0" json:"task_list"` // 任务状态数组500字节默认3 TaskList [1000]byte `struc:"[1000]byte" default:"0" json:"task_list"` // 任务状态数组500字节默认3
PetList []PetInfo `struc:"skip" json:"pet_list"` // 精灵背包内信息(不再走旧登录包体) PetListLen uint32 `struc:"uint32,sizeof=PetList" json:"-"` // 登录包体中的出战精灵数量
BackupPetList []PetInfo `struc:"skip" json:"backup_pet_list"` // 精灵并列备用列表 PetList []PetInfo `json:"pet_list"` // 精灵背包内信息
ClothesCount uint32 `struc:"sizeof=Clothes" json:"clothes_count"` // 穿戴装备数量 BackupPetListLen uint32 `struc:"uint32,sizeof=BackupPetList" json:"-"` // 登录包体中的备用精灵数量
Clothes []PeopleItemInfo ` json:"clothes"` // 穿戴装备 BackupPetList []PetInfo `json:"backup_pet_list"` // 精灵并列备用列表
ClothesCount uint32 `struc:"sizeof=Clothes" json:"clothes_count"` // 穿戴装备数量
Clothes []PeopleItemInfo ` json:"clothes"` // 穿戴装备
} }
// trace("个人装扮是否半价:",MainManager.isClothHalfDay); // trace("个人装扮是否半价:",MainManager.isClothHalfDay);

View File

@@ -119,7 +119,7 @@ type ReadyFightPetInfo struct {
SkinID uint32 `fieldDesc:"精灵皮肤ID" ` SkinID uint32 `fieldDesc:"精灵皮肤ID" `
ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"`
ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"`
IsCapture uint32 `json:"isCapture"` IsCapture uint8 `struc:"uint8" json:"isCapture"`
} }
type FightOverInfo struct { type FightOverInfo struct {
//0 正常结束 //0 正常结束