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" config "blazing/modules/config/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 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() { // 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%,无颜色偏移 // } co := config.NewShinyService().RandShiny(o.Id) if co != nil { o.ShinyInfo = append(o.ShinyInfo, *co) } //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 OgrePet Service *blservice.UserService User *service.BaseSysUserService // PVP被邀请信息 HavePVPinfo []common.PlayerI monsters [3]int // 0 无,1可以刷怪,2是切换过地图 Canmon uint32 // 可以刷怪 } type OgrePet struct { Data [9]OgrePetInfo } // 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()) } }