1.离线玩家数据加分布式锁操作

2.修复聊天记录错乱
3.修复重启服务器后无法登录
This commit is contained in:
flswld
2023-02-12 23:47:44 +08:00
parent 0b3c075402
commit ddecfdea12
11 changed files with 108 additions and 35 deletions

View File

@@ -263,10 +263,18 @@ func (g *GameManager) Close() {
Msg: saveUserIdList,
}
<-EXIT_SAVE_FIN_CHAN
// 单纯的告诉网关下线玩家
// 告诉网关下线玩家并全服广播玩家离线
userList := USER_MANAGER.GetAllOnlineUserList()
for _, player := range userList {
g.KickPlayer(player.PlayerID, kcp.EnetServerShutdown)
MESSAGE_QUEUE.SendToAll(&mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserOnlineStateChangeNotify,
ServerMsg: &mq.ServerMsg{
UserId: player.PlayerID,
IsOnline: false,
},
})
}
time.Sleep(time.Second)
}

View File

@@ -269,7 +269,7 @@ func (g *GameManager) AskAddFriendReq(player *model.Player, payloadMsg pb.Messag
})
} else {
// 全服离线玩家
targetPlayer, _, _ := USER_MANAGER.LoadGlobalPlayer(targetUid)
targetPlayer := USER_MANAGER.LoadTempOfflineUser(targetUid, true)
if targetPlayer == nil {
logger.Error("apply add friend target player is nil, uid: %v", targetUid)
return
@@ -362,7 +362,7 @@ func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Messa
})
} else {
// 全服离线玩家
targetPlayer, _, _ := USER_MANAGER.LoadGlobalPlayer(targetUid)
targetPlayer := USER_MANAGER.LoadTempOfflineUser(targetUid, true)
if targetPlayer == nil {
logger.Error("apply add friend target player is nil, uid: %v", targetUid)
return

View File

@@ -268,7 +268,7 @@ func (u *UserManager) SetRemoteUserOnlineState(userId uint32, isOnline bool, app
}
}
// GetRemoteOnlineUserList 获取指定数量的远程在线玩家
// GetRemoteOnlineUserList 获取指定数量的远程在线玩家 玩家数据只读禁止修改
func (u *UserManager) GetRemoteOnlineUserList(total int) map[uint32]*model.Player {
if total > 50 {
return nil
@@ -276,7 +276,7 @@ func (u *UserManager) GetRemoteOnlineUserList(total int) map[uint32]*model.Playe
onlinePlayerMap := make(map[uint32]*model.Player)
count := 0
for userId := range u.remotePlayerMap {
player := u.LoadTempOfflineUser(userId)
player := u.LoadTempOfflineUser(userId, false)
if player == nil {
continue
}
@@ -289,7 +289,7 @@ func (u *UserManager) GetRemoteOnlineUserList(total int) map[uint32]*model.Playe
return onlinePlayerMap
}
// LoadGlobalPlayer 加载并返回一个全服玩家及其在线状态
// LoadGlobalPlayer 加载并返回一个全服玩家及其在线状态 玩家数据只读禁止修改
// 参见LoadTempOfflineUser说明
func (u *UserManager) LoadGlobalPlayer(userId uint32) (player *model.Player, online bool, remote bool) {
online = u.GetUserOnlineState(userId)
@@ -304,14 +304,14 @@ func (u *UserManager) LoadGlobalPlayer(userId uint32) (player *model.Player, onl
if online {
if remote {
// 远程在线玩家 为了简化实现流程 直接加载数据库临时档
player = u.LoadTempOfflineUser(userId)
player = u.LoadTempOfflineUser(userId, false)
} else {
// 本地在线玩家
player = u.GetOnlineUser(userId)
}
} else {
// 全服离线玩家
player = u.LoadTempOfflineUser(userId)
player = u.LoadTempOfflineUser(userId, false)
}
return player, online, remote
}
@@ -320,12 +320,20 @@ func (u *UserManager) LoadGlobalPlayer(userId uint32) (player *model.Player, onl
// LoadTempOfflineUser 加载临时离线玩家
// 正常情况速度较快可以同步阻塞调用
func (u *UserManager) LoadTempOfflineUser(userId uint32) *model.Player {
func (u *UserManager) LoadTempOfflineUser(userId uint32, lock bool) *model.Player {
player := u.GetOnlineUser(userId)
if player != nil && player.Online {
logger.Error("not allow get a online player as offline player, uid: %v", userId)
return nil
}
if lock {
// 加离线玩家数据分布式锁
ok := u.dao.DistLockSync(userId)
if !ok {
logger.Error("lock redis offline player data error, uid: %v", userId)
return nil
}
}
player = u.LoadUserFromRedisSync(userId)
if player == nil {
// 玩家可能不存在于redis 尝试从db查询出来然后写入redis
@@ -349,10 +357,12 @@ func (u *UserManager) LoadTempOfflineUser(userId uint32) *model.Player {
}
// SaveTempOfflineUser 保存临时离线玩家
// 如果调用LoadTempOfflineUser后修改了离线玩家数据 则必须立即调用此函数回写
// 如果调用LoadTempOfflineUser获取了离线玩家数据 则必须在逻辑完成后立即调用此函数回写并解锁
func (u *UserManager) SaveTempOfflineUser(player *model.Player) {
// 主协程同步写入redis
u.SaveUserToRedisSync(player)
// 解离线玩家数据分布式锁
u.dao.DistUnlock(player.PlayerID)
// 另一个协程异步的写回db
playerData, err := msgpack.Marshal(player)
if err != nil {

View File

@@ -15,8 +15,8 @@ import (
const (
ENTITY_NUM_UNLIMIT = false // 是否不限制场景内实体数量
ENTITY_MAX_SEND_NUM = 200 // 场景内最大实体数量
MAX_MULTIPLAYER_WORLD_NUM = 2 // 本服务器最大多人世界数量
ENTITY_MAX_SEND_NUM = 300 // 场景内最大实体数量
MAX_MULTIPLAYER_WORLD_NUM = 10 // 本服务器最大多人世界数量
)
type WorldManager struct {