角色创建何时被触发

前面分析过,玩家登录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) )

  • 保存数据 - 玩家离开时、房间关闭时
    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
        // ...(无关代码,略)
        }
      }
    }
    
    玩家离开时,房间关闭时,最终都调到Room::SaveRoomData() 或 Room::SaveRoomDatas(),来保存玩家数据

results matching ""

    No results matching ""