refactor(socket): 更新广播和退出逻辑中的类型引用

更新socket服务器中广播功能和退出功能的代码,
将player.Player类型替换为player.ClientData类型,
并相应调整方法调用以适应新的数据结构。

feat(map): 添加LoadOrStore方法支持

在并发安全的swiss map中新增LoadOrStore方法,
提供原子性的加载或存储功能,增强map的操作能力。

refactor(login): 优化登录逻辑中的玩家获取方式

重构登录控制器中获取玩家对象的方式,
直接从
This commit is contained in:
昔念
2026-03-16 22:30:12 +08:00
parent 30dba8fee3
commit d74652373c
9 changed files with 32 additions and 50 deletions

View File

@@ -13,9 +13,9 @@ type Broadcast struct {
func (s *Server) Broadcast(t string) int { func (s *Server) Broadcast(t string) int {
player.Mainplayer.Range(func(key uint32, value *player.Player) bool { player.Mainplayer.Range(func(key uint32, value *player.ClientData) bool {
value.SendPackCmd(50003, &Broadcast{ value.Player.SendPackCmd(50003, &Broadcast{
Name: t, Name: t,
}) })
return true return true
@@ -42,9 +42,9 @@ func (s *Server) QuitSelf(a int) error {
s.quit = true s.quit = true
if a != 0 { if a != 0 {
player.Mainplayer.Range(func(key uint32, value *player.Player) bool { player.Mainplayer.Range(func(key uint32, value *player.ClientData) bool {
if value != nil { if value != nil {
value.Kick(true) value.Player.Kick(true)
} }
return false return false
@@ -52,22 +52,22 @@ func (s *Server) QuitSelf(a int) error {
} else { } else {
go func() { go func() {
player.Mainplayer.Range(func(key uint32, value *player.Player) bool { player.Mainplayer.Range(func(key uint32, value *player.ClientData) bool {
if value != nil { if value != nil {
value.KickMessage() value.Player.KickMessage()
} }
return false return false
}) })
<-time.After(10 * time.Minute) <-time.After(10 * time.Minute)
player.Mainplayer.Range(func(key uint32, value *player.Player) bool { player.Mainplayer.Range(func(key uint32, value *player.ClientData) bool {
if value != nil { if value != nil {
value.Kick(true) value.Player.Kick(true)
} }
return false return false
}) })
os.Exit(0) os.Exit(0)
}() }()
} }

View File

@@ -43,6 +43,10 @@ func WithSize[K comparable, V any](size uint64) func(csMap *CsMap[K, V]) {
func (m *CsMap[K, V]) Store(key K, value V) { func (m *CsMap[K, V]) Store(key K, value V) {
m.inner.Store(key, value) m.inner.Store(key, value)
} }
func (m *CsMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
T, OK := m.inner.LoadOrStore(key, value)
return T.(V), OK
}
// Delete 删除指定键,返回是否删除成功 // Delete 删除指定键,返回是否删除成功
func (m *CsMap[K, V]) Delete(key K) bool { func (m *CsMap[K, V]) Delete(key K) bool {

View File

@@ -41,7 +41,7 @@ func (h Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.L
} }
} }
currentPlayer := player.GetPlayer(c, data.Head.UserID) currentPlayer := c.Context().(*player.ClientData).GetPlayer(data.Head.UserID)
if currentPlayer == nil { if currentPlayer == nil {
cool.Logger.Error(context.Background(), "获取玩家失败", data.Head.UserID) cool.Logger.Error(context.Background(), "获取玩家失败", data.Head.UserID)

View File

@@ -60,8 +60,8 @@ func PprofWeb() {
func cleanup() { func cleanup() {
fmt.Println("执行优雅清理资源...") fmt.Println("执行优雅清理资源...")
player.Mainplayer.Range(func(key uint32, value *player.Player) bool { player.Mainplayer.Range(func(key uint32, value *player.ClientData) bool {
value.Kick(true) value.Player.Kick(true)
return false return false
}) })

View File

@@ -27,9 +27,7 @@ func NewPlayer(opts gnet.Conn) *Player {
p.monsters = generateThreeUniqueNumbers() p.monsters = generateThreeUniqueNumbers()
p.Done = NewDone(p) //发布订阅事件 p.Done = NewDone(p) //发布订阅事件
p.MapNPC = time.AfterFunc(10*time.Second, func() { p.MapNPC = time.AfterFunc(10*time.Second, p.GenMonster)
p.GenMonster() //生成野怪
})
p.MainConn = opts p.MainConn = opts
return p return p

View File

@@ -219,6 +219,16 @@ type ClientData struct {
//SaveDone chan struct{} //SaveDone chan struct{}
} }
func (p *ClientData) GetPlayer(userid uint32) *Player { //TODO 这里待优化,可能存在内存泄漏问题
_, ok := Mainplayer.LoadOrStore(userid, p)
if !ok {
p.Player = NewPlayer(p.Conn)
}
return p.Player
// return nil
}
func NewClientData(c gnet.Conn) *ClientData { func NewClientData(c gnet.Conn) *ClientData {
// 创建事件处理器 // 创建事件处理器
// 创建消费端串行处理的Lockfree // 创建消费端串行处理的Lockfree

View File

@@ -27,7 +27,7 @@ import (
) )
// Mainplayer 全局玩家数据存储映射 // Mainplayer 全局玩家数据存储映射
var Mainplayer = csmap.New[uint32, *Player]() var Mainplayer = csmap.New[uint32, *ClientData]()
type OgrePetInfo struct { type OgrePetInfo struct {
ID uint32 ID uint32
@@ -284,7 +284,7 @@ func (player1 *Player) Kick(isquit bool) {
case <-CloseChan: case <-CloseChan:
// 正常流程连接关闭回调已执行CloseChan 被关闭 // 正常流程连接关闭回调已执行CloseChan 被关闭
case <-time.After(kickTimeout): case <-time.After(kickTimeout):
player1.Service.Info.Save(*player1.Info) player1.Save()
service.NewBaseSysLogService().RecordKick(uint32(player1.Info.UserID), fmt.Errorf("踢人操作超时(超时时间:%v", kickTimeout).Error()) service.NewBaseSysLogService().RecordKick(uint32(player1.Info.UserID), fmt.Errorf("踢人操作超时(超时时间:%v", kickTimeout).Error())
// 超时处理:避免永久阻塞,可添加日志便于排查问题 // 超时处理:避免永久阻塞,可添加日志便于排查问题
// 注意:这里不会中断 CloseWithCallback 的执行,仅解除当前协程的阻塞 // 注意:这里不会中断 CloseWithCallback 的执行,仅解除当前协程的阻塞

View File

@@ -16,10 +16,7 @@ import (
// Save 保存玩家数据 // Save 保存玩家数据
func (p *Player) Save() { func (p *Player) Save() {
cool.CacheManager.Remove(context.TODO(), fmt.Sprintf("player:%d", p.Info.UserID)) cool.CacheManager.Remove(context.TODO(), fmt.Sprintf("player:%d", p.Info.UserID))
if cool.Config.ServerInfo.IsVip != 0 {
return
}
if p.Info == nil { if p.Info == nil {
return return

View File

@@ -1,37 +1,10 @@
package player package player
import (
"github.com/panjf2000/gnet/v2"
)
func GetPlayer(c gnet.Conn, userid uint32) *Player { //TODO 这里待优化,可能存在内存泄漏问题
//检查player初始化是否为conn初始后取map防止二次连接后存在两个player
clientdata, ok := c.Context().(*ClientData)
if !ok {
return nil
}
if clientdata.Player == nil {
clientdata.Player = NewPlayer(c)
}
// gff := socket.NewClientData()
// gff.Player = clientdata.Player
// c.MainConn.SetContext(gff)
Mainplayer.Store(userid, clientdata.Player)
return clientdata.Player
// return nil
}
func KickPlayer(userid uint32) error { //踢出玩家 func KickPlayer(userid uint32) error { //踢出玩家
//TODO 返回错误码 //TODO 返回错误码
//var player *entity.Player //var player *entity.Player
if player1, ok := Mainplayer.Load(userid); ok { if player1, ok := Mainplayer.Load(userid); ok {
player1.Kick(false) player1.Player.Kick(false)
} }