feat: 添加ItemInfo结构体并重构抽蛋和任务系统 - 在common/data/color.go中添加ItemInfo结构体用于表示发放物品的信息 - 在common/utils/tomap.go中添加RandomSlice泛型函数用于从切片中随机选取元素 - 重构action_egg.go中的EggGamePlay功能,实现抽蛋逻辑和物品发放 - 更新fight_boss.go中使用新的ItemInfo结构体替换旧的model.ItemInfo - 修改user_talk.go中获取物品数量的逻辑 - 更新user_task.go中任务完成逻辑使用新的ItemInfo结构体 - 在egg.go中更新抽蛋结果结构体使用ItemInfo - 更新战斗奖励结构体使用ItemInfo - 在player.go中添加学习力道具处理逻辑 - 重构任务系统使用新的ItemInfo结构体 - 移除旧的model.ItemInfo定义 - 更新宠物奖励配置模型添加成长值等字段 - 实现GetEgg方法用于获取扭蛋奖励 - 修复宠物融合材料服务中的道具验证逻辑 ```
268 lines
6.6 KiB
Go
268 lines
6.6 KiB
Go
package player
|
||
|
||
import (
|
||
"blazing/common/data"
|
||
"blazing/common/data/xmlres"
|
||
"blazing/common/socket/errorcode"
|
||
"blazing/common/utils"
|
||
"blazing/cool"
|
||
"blazing/logic/service/common"
|
||
"blazing/logic/service/fight/info"
|
||
"blazing/logic/service/space"
|
||
"sync/atomic"
|
||
|
||
"blazing/modules/base/service"
|
||
|
||
blservice "blazing/modules/blazing/service"
|
||
"context"
|
||
|
||
"github.com/antlabs/timer"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
"github.com/panjf2000/gnet/v2"
|
||
)
|
||
|
||
// CountPlayer 统计在线玩家数量
|
||
func CountPlayer() int {
|
||
count := 0
|
||
Mainplayer.Range(func(uint32, *Player) bool {
|
||
count++
|
||
return true // 继续遍历
|
||
})
|
||
return count
|
||
}
|
||
|
||
// Mainplayer 全局玩家数据存储映射
|
||
var Mainplayer = &utils.SyncMap[uint32, *Player]{}
|
||
|
||
type OgreInfo struct {
|
||
Data [9]OgrePetInfo
|
||
}
|
||
|
||
type OgrePetInfo struct {
|
||
Id uint32
|
||
ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"`
|
||
ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"`
|
||
Lv uint32 `struc:"skip"` //等级
|
||
Item uint32 `struc:"skip"` //奖励,如果有的话
|
||
Ext uint32 `struc:"skip"` //是否变尼尔尼奥
|
||
}
|
||
|
||
func (o *OgrePetInfo) RandSHiny(t int64) {
|
||
o.ShinyInfo = make([]data.GlowFilter, 1)
|
||
// 假设 t 是包含 ShinyInfo 字段的结构体,ShinyInfo 是 GlowFilter 类型的切片
|
||
o.ShinyInfo[0] = data.GlowFilter{
|
||
// 光晕颜色:白色(十六进制 0xFFFFFF),符合 uint32 类型
|
||
Color: 65535,
|
||
// 透明度:0.8(0.0~1.0 范围内的合理值,float64 类型)
|
||
Alpha: 0.3,
|
||
// 水平模糊量:10(0~255 范围内,uint8 类型,略高于默认值6)
|
||
BlurX: 20,
|
||
// 垂直模糊量:10(与 BlurX 对称,uint8 类型)
|
||
BlurY: 20,
|
||
// 发光强度:8(0~255 范围内,uint8 类型,略高于默认值2)
|
||
Strength: 1,
|
||
// 滤镜应用次数:2(1~3 范围内,int 类型,非默认值1)
|
||
Quality: 2,
|
||
// 内侧发光:true(bool 类型,模拟开启内侧发光)
|
||
Inner: true,
|
||
// 挖空:false(bool 类型,保持默认逻辑)
|
||
Knockout: false,
|
||
// 颜色矩阵:标准 RGBA 矩阵(20个uint8,符合 [20]uint8 数组类型)
|
||
// 矩阵含义:R=100%、G=100%、B=100%、A=100%,无颜色偏移
|
||
|
||
}
|
||
|
||
o.ShinyInfo[0].ColorMatrixFilter = GenerateRandomOffspringMatrix().Get()
|
||
//g.Dump(ttt.ShinyInfo)
|
||
// ttt.Shiny = 0 //待确认是否刷新异色
|
||
}
|
||
|
||
type Player struct {
|
||
MainConn gnet.Conn
|
||
baseplayer
|
||
IsLogin bool //是否登录
|
||
Done
|
||
|
||
MapNPC timer.TimeNoder
|
||
|
||
context.Context
|
||
Fightinfo info.Fightinfo // 当前邀请的玩家ID
|
||
|
||
Logintime uint32 // 当前登录时间
|
||
OgreInfo OgreInfo
|
||
|
||
Service *blservice.UserService
|
||
User *service.BaseSysUserService
|
||
// PVP被邀请信息
|
||
HavePVPinfo []common.PlayerI
|
||
monsters [3]int
|
||
// 0 无,1可以刷怪,2是切换过地图
|
||
Canmon uint32 // 可以刷怪
|
||
}
|
||
|
||
// PlayerOption 定义配置 Player 的函数类型
|
||
type PlayerOption func(*Player)
|
||
|
||
// WithConn 设置玩家连接的配置选项
|
||
func WithConn(c gnet.Conn) PlayerOption {
|
||
return func(p *Player) {
|
||
p.MainConn = c
|
||
}
|
||
}
|
||
|
||
func (p *Player) UseCoins(amount uint32) bool {
|
||
if p.Info.Coins < amount {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
func (p *Player) UseGold(amount uint32) bool {
|
||
if p.User.GetGold(uint(p.Info.UserID)) < amount {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
func (p *Player) GetAction() {
|
||
|
||
}
|
||
|
||
// InvitePlayer 邀请玩家进行对战
|
||
func (f *Player) InvitePlayer(ff common.PlayerI) {
|
||
f.HavePVPinfo = append(f.HavePVPinfo, ff)
|
||
tt := common.NewTomeeHeader(2501, f.GetInfo().UserID)
|
||
f.SendPack(tt.Pack(&info.NoteInviteToFightOutboundInfo{
|
||
UserID: ff.GetInfo().UserID,
|
||
Nick: ff.GetInfo().Nick,
|
||
Mode: ff.Getfightinfo().Mode,
|
||
}))
|
||
}
|
||
|
||
// Getfightinfo 获取玩家的战斗信息
|
||
func (p *Player) Getfightinfo() info.Fightinfo {
|
||
return p.Fightinfo
|
||
}
|
||
|
||
// QuitFight 退出战斗
|
||
func (p *Player) QuitFight() {
|
||
p.FightC = nil
|
||
atomic.StoreUint32(&p.Fightinfo.Mode, 0)
|
||
}
|
||
|
||
// GetSpace 获取玩家所在的空间
|
||
func (p *Player) GetSpace() *space.Space {
|
||
return space.GetSpace(p.Info.MapID)
|
||
}
|
||
|
||
// CanFight 检查玩家是否可以进行战斗
|
||
// 0无战斗,1PVP,2,BOOS,3PVE
|
||
func (p *Player) CanFight() bool {
|
||
if len(p.Info.PetList) == 0 {
|
||
atomic.StoreUint32(&p.Fightinfo.Mode, 0)
|
||
return false
|
||
}
|
||
|
||
if p.FightC != nil {
|
||
atomic.StoreUint32(&p.Fightinfo.Mode, 0)
|
||
return false
|
||
}
|
||
|
||
for _, pet := range p.Info.PetList {
|
||
if pet.Hp > 0 { // 只要找到一个血量大于0的宠物,就可以战斗
|
||
return true
|
||
}
|
||
}
|
||
|
||
// 遍历完所有宠物,都没有血量大于0的,才不能战斗
|
||
atomic.StoreUint32(&p.Fightinfo.Mode, 0)
|
||
return false
|
||
}
|
||
|
||
func (p *Player) SendPack(b []byte) error {
|
||
if p.MainConn == nil {
|
||
return nil
|
||
}
|
||
_, ok := p.MainConn.Context().(*ClientData)
|
||
if ok {
|
||
return p.MainConn.Context().(*ClientData).SendPack(b)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 添加物品 返回成功添加的物品
|
||
func (p *Player) ItemAdd(ItemId, ItemCnt uint32) (result bool) {
|
||
switch ItemId {
|
||
case 1: //塞尔豆
|
||
p.Info.Coins = p.Info.Coins + ItemCnt
|
||
return true
|
||
case 3: //累计经验
|
||
p.Info.ExpPool = p.Info.ExpPool + ItemCnt
|
||
return true
|
||
|
||
case 5: //金豆ItemAdd
|
||
p.User.UpdateGold(p.Info.UserID, int64(ItemCnt*100))
|
||
return true
|
||
case 9: //学习力
|
||
p.Info.EVPool = p.Info.EVPool + ItemCnt
|
||
|
||
default:
|
||
itemx, ok := xmlres.ItemsMAP[int(ItemId)]
|
||
if !ok {
|
||
cool.Logger.Error(context.TODO(), "物品不存在", ItemId)
|
||
|
||
t1 := common.NewTomeeHeader(2601, p.Info.UserID)
|
||
t1.Result = uint32(errorcode.ErrorCodes.ErrSystemError200007)
|
||
|
||
p.SendPack(t1.Pack(nil)) //准备包由各自发,因为协议不一样
|
||
return false
|
||
|
||
}
|
||
if itemx.Max == 0 {
|
||
itemx.Max = 1
|
||
}
|
||
|
||
if p.Service.Item.CheakItem(ItemId)+ItemCnt > uint32(itemx.Max) {
|
||
|
||
println(p.Info.UserID, "物品超过拥有最大限制", ItemId)
|
||
t1 := common.NewTomeeHeader(2601, p.Info.UserID)
|
||
t1.Result = uint32(errorcode.ErrorCodes.ErrTooManyOfItem)
|
||
|
||
p.SendPack(t1.Pack(nil)) //准备包由各自发,因为协议不一样
|
||
return false
|
||
}
|
||
p.Service.Item.UPDATE(ItemId, gconv.Int(ItemCnt))
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
func (player1 *Player) Kick() {
|
||
if player1.IsLogin {
|
||
//取成功,否则创建
|
||
//player1.Save() //先保存数据再返回
|
||
head := common.NewTomeeHeader(1001, player1.Info.UserID)
|
||
head.Result = uint32(errorcode.ErrorCodes.ErrAccountLoggedInElsewhere)
|
||
//实际上这里有个问题,会造成重复保存问题
|
||
|
||
player1.SendPack(head.Pack(nil))
|
||
CloseChan := make(chan struct{})
|
||
|
||
player1.MainConn.CloseWithCallback(func(c gnet.Conn, err error) error {
|
||
|
||
close(CloseChan)
|
||
return nil
|
||
})
|
||
<-CloseChan
|
||
}
|
||
}
|
||
|
||
func (p *Player) Cheak(b error) {
|
||
if b != nil {
|
||
g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error())
|
||
}
|
||
|
||
}
|