feat(logic): 添加玩家外观与聊天功能并优化宠物生成逻辑

- 在 `logic/controller/item.go` 中添加了更换玩家服装后广播结果的逻辑
- 在 `logic/controller/user.go` 中新增多个控制器方法:
  - `Aimat`:瞄准操作处理
  - `Chat`:支持消息发送及过滤
  - `ChangePlayerColor`:修改玩家颜色并扣除金币
  - `ChangePlayerDoodle`:更改玩家涂鸦并扣费
  - `ChangeNONOColor`:改变 NONO 颜色
- 移动宠物信息生成函数 `GenPetInfo` 至 `modules/blazing/model/pet.go` 并重构其实现
- 更新 `logic/service/player/pet.go` 和相关引用以适应新结构
-
This commit is contained in:
2025-10-24 00:31:38 +08:00
parent f9dc10e954
commit 18378a3ab6
8 changed files with 254 additions and 125 deletions

View File

@@ -109,7 +109,7 @@ func initfile() {
}
PlayerEffectMAP = make(map[int]NewSeIdx)
for _, v := range EffectMAP1.SeIdxList {
if gconv.Int(v.Stat) == 1 && gconv.Int(v.StarLevel) == 0 {
if gconv.Int(v.Stat) == 1 && gconv.Int(v.StarLevel) == 0 && gconv.Int(v.Idx) > 1000 {
v.ArgsS = ParseSideEffectArgs(v.Args)
PlayerEffectMAP[gconv.Int(v.Idx)] = v

View File

@@ -79,6 +79,7 @@ func (h Controller) ChangePlayerCloth(data *item.ChangePlayerClothInboundInfo, c
c.Info.Clothes = result.ClothList
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, player common.PlayerI) {
// fmt.Println("ChangePlayerCloth", playerID, data.Head.Pack(result))
data.Head.Result = 0
player.SendPack(data.Head.Pack(result))
})

View File

@@ -2,6 +2,7 @@ package controller
import (
"blazing/common/socket/errorcode"
"blazing/cool"
"blazing/logic/service/common"
"blazing/logic/service/player"
"blazing/logic/service/space"
@@ -35,33 +36,80 @@ func (h Controller) UserMoreInfo(data *user.MoreUserInfoInboundInfo, c *player.P
}
func (h Controller) Aimat(data *user.AimatInboundInfo, c *player.Player) (result *user.AimatOutboundInfo, err errorcode.ErrorCode) {
ret := &user.AimatOutboundInfo{
ItemId: data.ItemId,
Point: data.Point,
ShootType: data.ShootType,
UserId: c.Info.UserID,
}
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, player common.PlayerI) {
ret := &user.AimatOutboundInfo{
ItemId: data.ItemId,
Point: data.Point,
ShootType: data.ShootType,
UserId: c.Info.UserID,
}
data.Head.Result = 0
player.SendPack(data.Head.Pack(ret))
})
return ret, -1
return nil, -1
}
func (h Controller) Chat(data *user.ChatInboundInfo, c *player.Player) (result *user.ChatOutboundInfo, err errorcode.ErrorCode) {
result = &user.ChatOutboundInfo{
Message: data.Message,
SenderNickname: c.Info.Nick,
SenderId: c.Info.UserID,
}
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, v common.PlayerI) {
result = &user.ChatOutboundInfo{
Message: string([]byte(data.Message)[:data.MessageLen-1]),
SenderNickname: c.Info.Nick,
SenderId: c.Info.UserID,
}
result.Message = cool.Filter.Replace(result.Message, '*')
data.Head.Result = 0
v.SendPack(data.Head.Pack(result))
})
return nil, -1
}
func (h Controller) ChangePlayerColor(data *user.ChangeColorInboundInfo, c *player.Player) (result *user.ChangeColorOutboundInfo, err errorcode.ErrorCode) {
c.Info.Coins -= 200
c.Info.Color = data.Color
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, v common.PlayerI) {
data.Head.Result = 0
result = &user.ChangeColorOutboundInfo{
UserId: c.Info.UserID,
Color: data.Color,
Coins: c.Info.Coins,
Texture: c.Info.Texture,
}
v.SendPack(data.Head.Pack(result))
})
return nil, -1
}
func (h Controller) ChangePlayerDoodle(data *user.ChangeDoodleInboundInfo, c *player.Player) (result *user.ChangeDoodleOutboundInfo, err errorcode.ErrorCode) {
c.Info.Coins -= 200
c.Info.Texture = data.Id
c.Info.Color = data.Color
defer space.GetSpace(c.Info.MapID).User.IterCb(func(playerID uint32, v common.PlayerI) {
data.Head.Result = 0
result = &user.ChangeDoodleOutboundInfo{
UserId: c.Info.UserID,
Color: c.Info.Color,
Coins: c.Info.Coins,
Texture: c.Info.Texture,
}
v.SendPack(data.Head.Pack(result))
})
return nil, -1
}
func (h Controller) ChangeNONOColor(data *user.ChangeNONOColorInboundInfo, c *player.Player) (result *user.ChangeNONOColorOutboundInfo, err errorcode.ErrorCode) {
//c.Info.Coins -= 200
c.Info.NONO.Color = data.Color
result = &user.ChangeNONOColorOutboundInfo{
Sataus: c.Info.UserID,
Color: c.Info.Color,
}
return result, 0
}

View File

@@ -4,12 +4,9 @@ import (
"blazing/common/data/xmlres"
"blazing/common/utils"
"blazing/logic/service/fight/info"
"math/rand"
"time"
"blazing/modules/blazing/model"
"github.com/gogf/gf/v2/util/gconv"
"github.com/jinzhu/copier"
)
@@ -100,104 +97,19 @@ func LastFourElements[T any](s []T) []T {
return s[n-4:]
}
// -1是随机
// GenPetInfo 生成一个新的精灵实例
// - 参数为 -1 时表示随机生成对应属性
// * @param petTypeId 精灵类型ID
// * @param individualValue 个体值
// * @param natureId 性格ID
// * @param abilityTypeEnum 特性类型
// * @param isShiny 是否为闪光
// * @param level 等级
// * @param individualValue 个体值0-31
// * @param natureId 性格ID0-24
// * @param abilityTypeEnum 特性类型ID0=无, >0=指定, -1=随机)
// * @param shinyid 闪光ID-1=随机)
// * @param level 等级1-100
// * @return 生成的精灵实体
func (player *Player) GenPetInfo(id int, dv, natureId, abilityTypeEnum, shinyid, level int) *model.PetInfo {
// 设置随机数种子,确保每次运行生成不同的随机数序列
rand.Seed(time.Now().UnixNano())
func (player *Player) GenPetInfo(
id int,
dv, natureId, abilityTypeEnum, shinyid, level int,
) *model.PetInfo {
p := &model.PetInfo{ID: uint32(id),
EffectInfo: make([]model.PetEffectInfo, 0),
CatchTime: uint32(time.Now().Unix()),
Level: uint32(level)} //等级
if shinyid != -1 {
p.Shiny = uint32(shinyid)
}
if natureId != -1 {
p.Nature = uint32(natureId)
} else {
p.Nature = uint32(rand.Intn(25))
}
if dv != -1 {
p.Dv = uint32(dv)
} else {
p.Dv = uint32(CalculateIndividualValue(rand.New(rand.NewSource(time.Now().UnixNano()))))
}
if abilityTypeEnum != -1 {
if abilityTypeEnum != 0 {
v := xmlres.PlayerEffectMAP[int(abilityTypeEnum)]
p.EffectInfo = append(p.EffectInfo, model.PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
}
} else {
for i, v := range xmlres.PlayerEffectMAP {
if rand.Intn(len(xmlres.PlayerEffectMAP)) == i {
p.EffectInfo = append(p.EffectInfo, model.PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
}
}
}
tttt := LastFourElements(p.GetLevelRangeCanLearningSkills(0, p.Level)) //获取最后四个技能,如果不足,那就取全部技能
for i := 0; i < len(tttt); i++ {
p.SkillList[i].ID = tttt[i]
p.SkillList[i].PP = uint32(xmlres.SkillMap[int(tttt[i])].MaxPP)
}
p.SkillListLen = uint32(len(tttt))
p.CalculatePetPane()
p.Hp = p.MaxHp
player.AddPetExp(p, 0, true)
return p
}
// 除数数组放大100倍
// 数组按递增顺序排列,用于判断个体值等级
var divisors = []int{
600, 1200, 1900, 2700, 3600, 4600, 5700, 6900, 8200, 9600,
11100, 12700, 14400, 16200, 18100, 20100, 22100, 24000,
25800, 27500, 29100, 30600, 32000, 33300, 34500, 35600,
36600, 37500, 38300, 39000, 39600,
}
// CalculateIndividual 根据给定的a值计算个体值
// 返回值表示a大于等于多少个除数范围0-31
func CalculateIndividual(a int) int {
individual := 0
for _, divisor := range divisors {
if a >= divisor {
individual++
} else {
break // 数组是递增的,可提前跳出循环
}
}
return individual
}
// CalculateIndividualValue 计算个体值0-31
// 接收外部随机数生成器,便于控制随机性和复用
func CalculateIndividualValue(random *rand.Rand) int {
// 生成0-40000的随机数作为个体值计算的输入
a := random.Intn(40001)
return CalculateIndividual(a)
return model.GenPetInfo(id, dv, natureId, abilityTypeEnum, shinyid, level)
}

View File

@@ -15,3 +15,36 @@ type ChatOutboundInfo struct {
MessageLen uint32 `struc:"sizeof=Message"`
Message string `description:"这里的内容没有结束符" codec:"string"` // String -> string
}
type ChangeColorInboundInfo struct {
Head player.TomeeHeader `cmd:"2063" struc:"[0]pad"`
Color uint32 `codec:"color"` // 更改的颜色 rgb (对应Java的@UInt long)
}
type ChangeColorOutboundInfo struct {
UserId uint32 `codec:"userId"` // 更改人的用户id (对应Java的@UInt long)
Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long)
Texture uint32 `codec:"texture"` // 大概是当前的涂装 by 7 (对应Java的@UInt long)
Coins uint32 `codec:"coins"` // 扣除200豆子后返回的剩余豆子 (对应Java的@UInt long)
}
type ChangeDoodleInboundInfo struct {
Head player.TomeeHeader `cmd:"2062" struc:"[0]pad"`
Id uint32 `codec:"id"` // 涂鸦ID (对应Java的@UInt long)
Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long)
}
type ChangeDoodleOutboundInfo struct {
UserId uint32 `codec:"userId"` // 更改人的userid (对应Java的@UInt long)
Color uint32 `codec:"color"` // 使用前端发的id 从itemInfo中获得 (对应Java的@UInt long)
Texture uint32 `codec:"texture"` // 使用前端发的id 从itemInfo中获得 (对应Java的@UInt long)
Coins uint32 `codec:"coins"` // 扣除对应豆子后返回的剩余豆子 (对应Java的@UInt long)
}
type ChangeNONOColorInboundInfo struct {
Head player.TomeeHeader `cmd:"9012" struc:"[0]pad"`
Color uint32 `codec:"color"` // 更改的颜色 rgb (对应Java的@UInt long)
}
type ChangeNONOColorOutboundInfo struct {
Sataus uint32 `codec:"userId"` // 更改人的用户id (对应Java的@UInt long)
Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long)
}

View File

@@ -2,6 +2,7 @@ package admin
import (
"blazing/cool"
"blazing/modules/blazing/model"
"blazing/modules/blazing/service"
"context"
@@ -35,14 +36,13 @@ func init() {
}
func (c *PetBagController) GetSession(ctx context.Context, req *PetGetReq) (res *cool.BaseRes, err error) {
// fmt.Println(req)
// var (
// admin = cool.GetAdmin(ctx)
// //r = g.RequestFromCtx(ctx)
// )
// t := model.GenPetInfo(
// req.PetTypeId, req.IndividualValue, req.NatureId, req.AbilityTypeEnum, req.IsShiny, req.Level)
// service.NewUserService(uint32(admin.UserId)).PetAdd(*t)
var (
admin = cool.GetAdmin(ctx)
//r = g.RequestFromCtx(ctx)
)
t := model.GenPetInfo(
req.PetTypeId, req.IndividualValue, req.NatureId, req.AbilityTypeEnum, req.IsShiny, req.Level)
service.NewUserService(uint32(admin.UserId)).PetAdd(*t)
return
}

View File

@@ -4,6 +4,10 @@ import (
"blazing/common/data/xmlres"
"blazing/cool"
"math"
"math/rand"
"time"
"github.com/gogf/gf/v2/util/gconv"
)
const TableNamePet = "pet"
@@ -210,3 +214,137 @@ func init() {
_ = cool.CreateTable(&Pet{})
// fmt.Println(err)
}
func GenPetInfo(
id int,
dv, natureId, abilityTypeEnum, shinyid, level int,
) *PetInfo {
// 创建随机源
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
// 初始化精灵
p := &PetInfo{
ID: uint32(id),
CatchTime: uint32(time.Now().Unix()),
Level: uint32(level),
EffectInfo: make([]PetEffectInfo, 0),
}
// ---- 处理闪光 ----
if shinyid != -1 {
p.Shiny = uint32(shinyid)
}
// ---- 性格 ----
if natureId == -1 {
p.Nature = uint32(rng.Intn(25))
} else {
p.Nature = uint32(natureId)
}
// ---- 个体值DV----
if dv == -1 {
p.Dv = uint32(CalculateIndividualValue(rng))
} else {
if dv < 0 {
dv = 0
} else if dv > 31 {
dv = 31
}
p.Dv = uint32(dv)
}
// ---- 特性 ----
switch {
case abilityTypeEnum == 0:
// 无特性
case abilityTypeEnum > 0:
// 指定特性
if v, ok := xmlres.PlayerEffectMAP[int(abilityTypeEnum)]; ok {
p.EffectInfo = append(p.EffectInfo, PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
}
case abilityTypeEnum == -1:
// 随机特性
randomIndex := rng.Intn(len(xmlres.PlayerEffectMAP))
var i int
for _, v := range xmlres.PlayerEffectMAP {
if i == randomIndex {
p.EffectInfo = append(p.EffectInfo, PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
break
}
i++
}
}
// ---- 技能学习 ----
skills := LastFourElements(p.GetLevelRangeCanLearningSkills(0, p.Level)) // 最后四个技能
p.SkillListLen = uint32(len(skills))
for i := 0; i < len(skills) && i < len(p.SkillList); i++ {
skillID := skills[i]
if info, ok := xmlres.SkillMap[int(skillID)]; ok {
p.SkillList[i].ID = skillID
p.SkillList[i].PP = uint32(info.MaxPP)
}
}
// ---- 属性计算 ----
p.CalculatePetPane()
p.Hp = p.MaxHp
p.Update()
return p
}
func LastFourElements[T any](s []T) []T {
n := len(s)
if n <= 4 {
// 切片长度小于等于4时返回整个切片
return s
}
// 切片长度大于4时返回最后4个元素从n-4索引到末尾
return s[n-4:]
}
// 除数数组放大100倍
// 数组按递增顺序排列,用于判断个体值等级
var divisors = []int{
600, 1200, 1900, 2700, 3600, 4600, 5700, 6900, 8200, 9600,
11100, 12700, 14400, 16200, 18100, 20100, 22100, 24000,
25800, 27500, 29100, 30600, 32000, 33300, 34500, 35600,
36600, 37500, 38300, 39000, 39600,
}
// CalculateIndividual 根据给定的a值计算个体值
// 返回值表示a大于等于多少个除数范围0-31
func CalculateIndividual(a int) int {
individual := 0
for _, divisor := range divisors {
if a >= divisor {
individual++
} else {
break // 数组是递增的,可提前跳出循环
}
}
return individual
}
// CalculateIndividualValue 计算个体值0-31
// 接收外部随机数生成器,便于控制随机性和复用
func CalculateIndividualValue(random *rand.Rand) int {
// 生成0-40000的随机数作为个体值计算的输入
a := random.Intn(40001)
return CalculateIndividual(a)
}

View File

@@ -4,7 +4,6 @@ import (
"blazing/cool"
"blazing/modules/blazing/model"
"context"
"strings"
"time"
"github.com/gogf/gf/v2/os/glog"
@@ -31,8 +30,6 @@ func (s *UserService) Reg(nick string, color uint32) {
return
}
t := model.NewPlayer()
t.PlayerID = uint64(s.userid)
//设置用户信息