package player import ( "blazing/common/data" "blazing/common/socket/errorcode" "blazing/cool" "blazing/logic/service/common" "blazing/logic/service/fight/info" "blazing/logic/service/space" "sync/atomic" "blazing/modules/base/service" config "blazing/modules/config/service" dictrvice "blazing/modules/dict/service" blservice "blazing/modules/player/service" "context" "github.com/antlabs/timer" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" csmap "github.com/mhmtszr/concurrent-swiss-map" "github.com/panjf2000/gnet/v2" ) // Mainplayer 全局玩家数据存储映射 var Mainplayer = csmap.New[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() { var co *data.GlowFilter if o.Ext == 0 { co = config.NewShinyService().RandShiny(o.Id) } if co != nil && len(o.ShinyInfo) == 0 { o.ShinyInfo = append(o.ShinyInfo, *co) } } func (o *OgrePetInfo) FixSHiny() { var co *data.GlowFilter if o.Ext == 0 { co = config.NewShinyService().FixShiny(o.Id) } if co != nil && len(o.ShinyInfo) == 0 { o.ShinyInfo = append(o.ShinyInfo, *co) } } 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 // 可以刷怪 CurDark 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) GetCoins(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 } psocket, ok := p.MainConn.Context().(*ClientData) if ok { return psocket.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: itemmax := dictrvice.NewDictInfoService().GetMax(ItemId) if itemmax == 0 { cool.Logger.Error(context.TODO(), "物品不存在", p.Info.UserID, ItemId) t1 := common.NewTomeeHeader(2601, p.Info.UserID) t1.Result = uint32(errorcode.ErrorCodes.ErrSystemError200007) p.SendPack(t1.Pack(nil)) //准备包由各自发,因为协议不一样 return false } if p.Service.Item.CheakItem(ItemId)+ItemCnt > uint32(itemmax) { 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(qtype int) { //取成功,否则创建 //player1.Save() //先保存数据再返回 head := common.NewTomeeHeader(1001, player1.Info.UserID) head.Result = uint32(errorcode.ErrorCodes.ErrAccountLoggedInElsewhere) if qtype == 1 { head.Result = uint32(errorcode.ErrorCodes.ErrXinPlanSleepMode) } //实际上这里有个问题,会造成重复保存问题 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()) } } func (p *Player) GiveTitle(id uint32) { p.Service.Title.Give(id) p.SendPackCmd(50005, &info.S2C_50005{ Title: id, }) }