package socket import ( "blazing/common/utils" "blazing/modules/blazing/model" "blazing/modules/blazing/service" "context" "fmt" "sync" "time" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" "github.com/gogf/gf/v2/frame/g" "github.com/panjf2000/gnet/pkg/logging" "github.com/tnnmigga/enum" ) var Mainplayer = &utils.SyncMap[uint32, *Player]{} //玩家数据 func (c *Conn) SendPack(bytes []byte) error { if t, ok := c.MainConn.Context().(*ClientData); ok { if t.Wsmsg.Upgraded { // This is the echo server err := wsutil.WriteServerMessage(c.MainConn, ws.OpBinary, bytes) if err != nil { logging.Infof("conn[%v] [err=%v]", c.MainConn.RemoteAddr().String(), err.Error()) return err } } else { _, err := c.MainConn.Write(bytes) if err != nil { logging.Error(err) } } } return nil } type OgreInfo struct { Data [9]OgrePetInfo } type OgrePetInfo struct { Id uint32 Shiny uint32 Lv uint32 `struc:"skip"` //等级 } type Player struct { MainConn *Conn IsLogin bool //是否登录 mu sync.Mutex loginChan chan struct{} // 登录完成通知通道 Info *model.PlayerInfo StopChan chan struct{} //停止刷怪协程 IsFighting bool context.Context Playerinvite uint32 //当前邀请的玩家ID Onlinetime uint32 //当前登录时间 OgreInfo *OgreInfo FightID string //绑定战斗标识 //FightInfo info.NoteReadyToFightInfo } // PlayerOption 定义配置 Player 的函数类型 type PlayerOption func(*Player) func WithConn(c *Conn) PlayerOption { return func(p *Player) { p.MainConn = c } } // NewPlayer 使用 Options 模式创建 Player 实例 func NewPlayer(opts ...PlayerOption) *Player { p := &Player{ loginChan: make(chan struct{}), } for _, opt := range opts { opt(p) } return p } func (p *Player) SendPack(b []byte) error { // fmt.Println("发送数据包", len(b)) err := p.MainConn.SendPack(b) return err } func (p *Player) Cheak(b error) { if b != nil { g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error()) } } // Save 保存玩家数据 func (p *Player) Save() { p.Info.TimeToday = p.Info.TimeToday + uint32(time.Now().Unix()) - uint32(p.Onlinetime) //保存电池时间 p.Onlinetime = uint32(time.Now().Unix()) service.NewUserService(p.Info.UserID).Save(p.Info) } // IsLoggedIn 检查是否已登录 func (lw *Player) IsLoggedIn() bool { lw.mu.Lock() defer lw.mu.Unlock() return lw.IsLogin } // WaitForLogin 等待登录完成,无超时 func (lw *Player) WaitForLogin() error { if lw.IsLoggedIn() { return nil } // 阻塞等待登录完成 <-lw.loginChan return nil } // WaitForLoginWithTimeout 带超时的登录等待 func (lw *Player) WaitForLoginWithTimeout(timeout time.Duration) error { if lw.IsLoggedIn() { return nil } // 使用定时器实现超时 timer := time.NewTimer(timeout) defer timer.Stop() select { case <-lw.loginChan: return nil case <-timer.C: return fmt.Errorf("登录等待超时: %v", timeout) } } // WaitForLoginWithCtx 带上下文的登录等待 func (lw *Player) WaitForLoginWithCtx(ctx context.Context) error { if lw.IsLoggedIn() { return nil } select { case <-lw.loginChan: return nil case <-ctx.Done(): return ctx.Err() // 上下文取消或超时 } } // CompleteLogin 标记登录完成并通知等待者 func (lw *Player) CompleteLogin() { lw.mu.Lock() defer lw.mu.Unlock() if !lw.IsLogin { lw.IsLogin = true close(lw.loginChan) // 关闭通道以通知所有等待者 } } // 战斗模式 type EnumBattleMode int var BattleMode_PVP = enum.New[struct { PVP_1V1 EnumBattleMode `enum:"1"` PVP_6V6 EnumBattleMode `enum:"2"` }]() var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息 ,比如一个玩家被多人邀请对战 type Playerinvite struct { //挂载到[]Playerinvite上? 被邀请者->邀请者 InviteID uint32 // 邀请者 InviteTime EnumBattleMode //游戏模式 } // 邀请玩家加入战斗 邀请者,被邀请者,邀请模式 func (lw *Player) InvitePlayerToBattle(target int64, mode EnumBattleMode) { t, ok := Playerinvitemap[uint32(target)] //被邀请者是否被邀请过 if ok { //说明存在被邀请 t = append(t, Playerinvite{uint32(lw.Info.UserID), mode}) Playerinvitemap[uint32(target)] = t } else { Playerinvitemap[uint32(target)] = []Playerinvite{{uint32(lw.Info.UserID), mode}} } lw.Playerinvite = uint32(target) } // 取消对战邀请 func (lw *Player) CancelBattle() { if lw.Playerinvite == 0 { return } delete(Playerinvitemap, uint32(lw.Playerinvite)) //删除玩家邀请信息 lw.Playerinvite = 0 }