Files
bl/logic/controller/pet_info.go
昔念 3a13bcc99c ```
feat(game): 实现扭蛋系统批量物品添加功能并优化地图逻辑

- 新增ItemAddBatch方法用于批量添加物品,支持普通道具和特殊道具的分别处理
- 优化扭蛋游戏玩法中的物品添加逻辑,使用新的批量接口提升性能
- 在扭蛋机器人命令中实现完整的物品检查和批量添加流程

refactor(map): 重构地图控制器代码结构并添加注释

- 为EnterMap、LeaveMap、GetMapPlayerList等方法添加中文注释
- 统一地图相关的命名规范,如enter map替换进入地图
- 调整地图玩家列表中BOSS广播命令ID,2021和2022进行对调

refactor(boss): 重构定时BOSS代码并优化注释

- 将原有的中文注释改为英文注释,统一代码风格
- 简化TimeBossRule结构体定义和相关配置
- 优化定时任务注册逻辑,去除冗余的注释和变量

refactor(space): 清理地图空间服务代码注释

- 移除多余的中文注释和说明文字
- 统一代码格式,移除不必要的空行和注释
- 保持原有的天气系统和地图刷怪逻辑不变

fix(role): 修复系统角色权限查询逻辑

- 修改BaseSysRoleService中的查询条件,正确处理管理员权限
- 使用Extend方法替代Where进行复杂的权限判断逻辑
- 确保超级管理员可以访问所有角色,其他用户受限于权限范围

refactor(dict): 添加字典服务批量查询方法

- 新增GetMaxMap方法用于批量获取物品最大持有上限
- 优化数据库查询,减少多次单个查询的开销
- 支持一次请求多个物品的最大数量限制

fix(player): 修复玩家信息保存异常处理

- 将panic方式改为错误日志记录,避免程序崩溃
- 优化Save方法的重试逻辑,统一错误处理方式
- 在本地文件回退时记录详细错误信息

feat(robot): 扩展扭蛋机器人功能

- 添加用户验证和角色创建检查
- 实现批量扭蛋的完整逻辑,支持1-10次抽取
- 集成物品数量检查和批量添加功能
```
2026-04-02 02:33:05 +08:00

317 lines
9.4 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 controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/pet"
"blazing/logic/service/player"
"blazing/modules/player/model"
)
func buildPetShortInfo(info model.PetInfo) pet.PetShortInfo {
return pet.PetShortInfo{
ID: info.ID,
CatchTime: info.CatchTime,
Level: info.Level,
SkinID: info.SkinID,
ShinyLen: info.ShinyLen,
ShinyInfo: info.ShinyInfo,
}
}
func buildPetListOutboundInfo(petList []model.PetInfo) *pet.GetPetListOutboundInfo {
result := &pet.GetPetListOutboundInfo{
ShortInfoList: make([]pet.PetShortInfo, len(petList)),
}
for i := range petList {
result.ShortInfoList[i] = buildPetShortInfo(petList[i])
}
return result
}
func removePetByCatchTime(petList []model.PetInfo, catchTime uint32) []model.PetInfo {
for i := range petList {
if petList[i].CatchTime == catchTime {
return append(petList[:i], petList[i+1:]...)
}
}
return petList
}
func syncBackupPetList(player *player.Player) {
if len(player.Info.BackupPetList) > 0 {
return
}
storagePets := player.Service.Pet.PetInfo(1)
if len(storagePets) == 0 {
player.Info.BackupPetList = make([]model.PetInfo, 0)
return
}
player.Info.BackupPetList = make([]model.PetInfo, len(storagePets))
for i := range storagePets {
player.Info.BackupPetList[i] = storagePets[i].Data
}
}
func buildUserBagPetInfo(player *player.Player) *pet.GetUserBagPetInfoOutboundInfo {
syncBackupPetList(player)
result := &pet.GetUserBagPetInfoOutboundInfo{
PetList: make([]model.PetInfo, len(player.Info.PetList)),
BackupPetList: make([]model.PetInfo, len(player.Info.BackupPetList)),
}
copy(result.PetList, player.Info.PetList)
copy(result.BackupPetList, player.Info.BackupPetList)
return result
}
func buildPetShowOutboundInfo(userID, flag uint32, info *model.PetInfo) *pet.PetShowOutboundInfo {
return &pet.PetShowOutboundInfo{
UserID: userID,
CatchTime: info.CatchTime,
ID: info.ID,
Flag: flag,
Dv: info.Dv,
ShinyLen: info.ShinyLen,
ShinyInfo: info.ShinyInfo,
SkinID: info.SkinID,
}
}
// GetPetInfo 获取精灵信息
// data: 包含精灵捕获时间的输入信息
// player: 当前玩家对象
// 返回: 精灵信息和错误码
func (h Controller) GetPetInfo(
data *pet.InInfo,
player *player.Player) (result *model.PetInfo,
err errorcode.ErrorCode) {
_, petInfo, found := player.FindPet(data.CatchTime)
if found {
result = petInfo
return result, 0
}
ret := player.Service.Pet.PetInfoOneByCatchTime(data.CatchTime)
if ret == nil {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
result = &ret.Data
return result, 0
}
// GetUserBagPetInfo 获取主背包和并列备用精灵列表
func (h Controller) GetUserBagPetInfo(
data *pet.GetUserBagPetInfoInboundEmpty,
player *player.Player) (result *pet.GetUserBagPetInfoOutboundInfo,
err errorcode.ErrorCode) {
return buildUserBagPetInfo(player), 0
}
// GetPetList 获取仓库列表
// data: 空输入结构
// player: 当前玩家对象
// 返回: 精灵列表和错误码
func (h Controller) GetPetList(
data *pet.GetPetListInboundEmpty,
player *player.Player) (result *pet.GetPetListOutboundInfo,
err errorcode.ErrorCode) {
return buildPetListOutboundInfo(player.Info.PetList), 0
}
// GetPetReleaseList 获取放生列表
// data: 空输入结构
// player: 当前玩家对象
// 返回: 放生精灵列表和错误码
func (h Controller) GetPetReleaseList(
data *pet.GetPetListFreeInboundEmpty,
player *player.Player) (result *pet.GetPetListOutboundInfo,
err errorcode.ErrorCode) {
syncBackupPetList(player)
return buildPetListOutboundInfo(player.Info.BackupPetList), 0
}
// PetReleaseToWarehouse 将精灵从仓库包中放生
// data: 包含精灵ID和捕获时间的输入信息
// player: 当前玩家对象
// 返回: 无数据和错误码
func (h Controller) PetReleaseToWarehouse(
data *pet.PET_ROWEI, player *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
_, _, inBag := player.FindPet(data.CatchTime)
freeForbidden := xmlres.PetMAP[int(data.ID)].FreeForbidden
// 如果背包没找到,再放入背包
if inBag || freeForbidden == 1 {
return nil, errorcode.ErrorCodes.ErrCannotReleaseNonWarehouse
}
if !player.Service.Pet.UpdateFree(data.CatchTime, 1) {
return nil, errorcode.ErrorCodes.ErrSystemError
}
return nil, err
}
// PetRetrieveFromWarehouse 领回包
func (h Controller) PetRetrieveFromWarehouse(
data *pet.PET_RETRIEVE, player *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
//如果背包没找到,再放入背包
if _, _, ok := player.FindPet(data.CatchTime); !ok {
if !player.Service.Pet.UpdateFree(data.CatchTime, 0) {
return nil, errorcode.ErrorCodes.ErrSystemError
}
}
return nil, 0
}
// TogglePetBagWarehouse 精灵背包仓库切换
func (h Controller) TogglePetBagWarehouse(
data *pet.PetReleaseInboundInfo,
player *player.Player) (
result *pet.PetReleaseOutboundInfo,
err errorcode.ErrorCode) { //这个时候player应该是空的
//放入背包=数据库置1+添加到背包+pet release发包 仓库=数据库置0+移除背包 设置首发等于取到首发精灵后重新排序
//这里只修改,因为添加和移除背包在宠物获取时已经做了
result = &pet.PetReleaseOutboundInfo{}
result.Flag = uint32(data.Flag)
//擂台住不能换精灵
if player.GetSpace().Owner.UserID == player.Info.UserID {
return result, errorcode.ErrorCodes.ErrChampionCannotSwitch
}
switch data.Flag {
case 0:
index, pet, ok := player.FindPet(data.CatchTime)
if ok {
// ========== 新增index合法性校验 ==========
if index < 0 || index >= len(player.Info.PetList) {
return result, errorcode.ErrorCodes.ErrPokemonIDMismatch
}
if !player.Service.Pet.Update(*pet) {
return result, errorcode.ErrorCodes.ErrSystemError
}
player.Info.BackupPetList = removePetByCatchTime(player.Info.BackupPetList, data.CatchTime)
player.Info.BackupPetList = append(player.Info.BackupPetList, *pet)
player.Info.PetList = append(player.Info.PetList[:index], player.Info.PetList[index+1:]...)
}
// break // 只移除第一个匹配值,若需移除所有,可省略 break 继续循环
case 1:
if len(player.Info.PetList) < 6 {
//todo 背包
_, _, ok := player.FindPet(data.CatchTime)
//如果背包没找到,再放入背包
if !ok {
r := player.Service.Pet.PetInfoOneByCatchTime(data.CatchTime)
if r == nil {
return result, errorcode.ErrorCodes.ErrPokemonNotExists
}
player.Info.PetList = append(player.Info.PetList, r.Data)
player.Info.BackupPetList = removePetByCatchTime(player.Info.BackupPetList, data.CatchTime)
result.PetInfo = r.Data
} else {
player.Info.BackupPetList = removePetByCatchTime(player.Info.BackupPetList, data.CatchTime)
}
}
}
if len(player.Info.PetList) > 0 {
result.FirstPetTime = player.Info.PetList[0].CatchTime //设置首发
}
return result, 0
}
// PlayerShowPet 精灵展示
func (h Controller) PlayerShowPet(
data *pet.PetShowInboundInfo, player *player.Player) (result *pet.PetShowOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
result = &pet.PetShowOutboundInfo{
UserID: data.Head.UserID,
CatchTime: data.CatchTime,
Flag: data.Flag,
}
_, currentPet, ok := player.FindPet(data.CatchTime)
if data.Flag == 0 {
player.SetPetDisplay(0, nil)
player.GetSpace().RefreshUserInfo(player)
defer player.GetSpace().Broadcast(player, data.Head.CMD, result)
return
}
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
player.SetPetDisplay(data.Flag, currentPet)
player.GetSpace().RefreshUserInfo(player)
result = buildPetShowOutboundInfo(data.Head.UserID, data.Flag, currentPet)
defer player.GetSpace().Broadcast(player, data.Head.CMD, result)
return
}
// PetOneCure 单体治疗
func (h Controller) PetOneCure(
data *pet.PetOneCureInboundInfo, player *player.Player) (result *pet.PetOneCureOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
if player.GetSpace().Owner.UserID == player.Info.UserID {
return result, errorcode.ErrorCodes.ErrChampionCannotHeal
}
_, currentPet, ok := player.FindPet(data.CatchTime)
if ok {
defer currentPet.Cure()
}
return &pet.PetOneCureOutboundInfo{
CatchTime: data.CatchTime,
}, 0
}
// PetFirst 精灵首发
func (h Controller) PetFirst(
data *pet.PetDefaultInboundInfo, player *player.Player) (result *pet.PetDefaultOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
//擂台住不能换精灵
if player.GetSpace().Owner.UserID == player.Info.UserID {
return result, errorcode.ErrorCodes.ErrChampionCannotSwitch
}
result = &pet.PetDefaultOutboundInfo{}
index, _, ok := player.FindPet(data.CatchTime)
if ok && index != 0 {
player.Info.PetList[index], player.Info.PetList[0] = player.Info.PetList[0], player.Info.PetList[index]
result.IsDefault = 1
}
return result, 0
}
// SetPetExp 设置宠物经验
func (h Controller) SetPetExp(data *pet.PetSetExpInboundInfo, player *player.Player) (result *pet.PetSetExpOutboundInfo, err errorcode.ErrorCode) {
_, currentPet, found := player.FindPet(data.CatchTime)
if found && currentPet.Level < 100 {
player.AddPetExp(currentPet, data.Exp)
return &pet.PetSetExpOutboundInfo{Exp: player.Info.ExpPool}, 0
}
return &pet.PetSetExpOutboundInfo{Exp: player.Info.ExpPool}, errorcode.ErrorCodes.ErrSystemError
}