角色创建何时被触发
前面分析过,玩家登录RoomServer,最后会到进入房间流程。这里会通过 Room::Chan_AddPlayer 这个go chan,投递玩家加入。
func (this *Room) Loop() {
// ...(无关代码略)
for {
select {
// ...(无关代码略)
case player := <-this.Chan_AddPlayer:
this.AddPlayer(player)
// ...(无关代码略)
}
}
}
从 Room::AddPlayer() -> Scene::AddPlayer(),细节略
角色离开何时被触发
func (this *Room) Loop() {
// ...(无关代码,略)
for {
select {
// ...(无关代码,略)
case playerId := <-this.chan_RemovePlayerById:
this.RemovePlayerById(playerId)
// ...(无关代码,略)
}
}
}
前面分析过,玩家正常离开、非正常离开,最后会触发 PlayerTask::OnClose()。这里会通过 Room::chan_RemovePlayerById 这个go chan,投递某玩家离开。
协议
玩家创建后,会给自己发送MsgLoginResult协议。至此登录成功!
会广播 MsgAddPlayer 这个消息
玩家离开时,会广播 MsgRemovePlayer 这个消息
角色的持久化数据
前面都没有提到数据库这块。这里详细说明下
加载数据 - 登录RoomServer,验证函数内
func (this *PlayerTask) LoginVerify(cmd usercmd.MsgTypeCmd, data []byte, flag byte) bool { // ...(无关代码,略) // 判断内存中是否有key prevUData := ScenePlayerMgr.GetUDataFromKey(revCmd.Key) if prevUData != nil { //this.OnClose() //老玩家下线 this.udata = prevUData } if this.udata == nil { udata := &common.UserData{} if !redismgr.GetMe().LoadFromRedis(revCmd.Key, udata) { this.RetErrorMsg(int(common.ErrorCodeVerify)) glog.Error("[登录] 验证失败 ", this.Conn.RemoteAddr(), ",", string(nickname), ",", revCmd.Key) return false } this.udata = udata } this.id = this.udata.Id adata, ok := dbclient.GetMe().GetUserById(this.udata.Id) if !ok { glog.Error("[登录] 操作失败 GetAccInfo ") this.RetErrorMsg(int(common.ErrorCodeVerify)) return false } //检查是否重复连接 otask := PlayerTaskMgr_GetMe().GetTask(this.id) if otask != nil { otask.RetErrorMsg(common.ErrorCodeReLogin) otask.Stop() otask.Close() if nil != otask.room { otask.room.ResetPlayerTask(this.id) } PlayerTaskMgr_GetMe().remove(otask) glog.Info("[登录] 发现重复登录 ", otask.id, ",", otask.udata.Account, ",", otask.name, ",", otask.key, ",old:", otask.Conn.RemoteAddr(), " ,new:", this.Conn.RemoteAddr()) otask = nil } this.udata.Icon = adata.Icon this.udata.PassIcon = adata.PassIcon this.udata.PlayNum = adata.PlayNum this.udata.Level = adata.Level this.udata.HideScore = adata.HideScores // ...(无关代码,略) return true }先看看ScenePlayerMgr中是否已经有 (prevUData := ScenePlayerMgr.GetUDataFromKey(revCmd.Key))
没有则缓存中获取 ( redismgr.GetMe().LoadFromRedis(revCmd.Key, udata) )
再获取账号信息,更新一些额外信息 ( adata, ok := dbclient.GetMe().GetUserById(this.udata.Id) )
- 保存数据 - 玩家离开时、房间关闭时
玩家离开时,房间关闭时,最终都调到Room::SaveRoomData() 或 Room::SaveRoomDatas(),来保存玩家数据func (this *Room) Loop() { // ...(无关代码,略) for { select { // ...(无关代码,略) case playerId := <-this.chan_RemovePlayerById: this.RemovePlayerById(playerId) case ctrl := <-this.chan_Control: switch ctrl { case ROOM_CONTROL_END: case ROOM_CONTROL_STOP: glog.Info("[ctrl]", this.name, " ctrl: ", ctrl) this.destory() } return // ...(无关代码,略) } } }