```
refactor(socket): 更新广播和退出逻辑中的类型引用 更新socket服务器中广播功能和退出功能的代码, 将player.Player类型替换为player.ClientData类型, 并相应调整方法调用以适应新的数据结构。 feat(map): 添加LoadOrStore方法支持 在并发安全的swiss map中新增LoadOrStore方法, 提供原子性的加载或存储功能,增强map的操作能力。 refactor(login): 优化登录逻辑中的玩家获取方式 重构登录控制器中获取玩家对象的方式, 直接从
This commit is contained in:
@@ -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,32 +42,32 @@ 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
|
||||||
})
|
})
|
||||||
} 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)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 的执行,仅解除当前协程的阻塞
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user