生撸一个多人在线游戏 (2

a.实现基本服务器连接管理,数据协议通讯.建立一个简单的服务器框架.


客户端和 gate连接, gate 负责 转发客户端的请求 给其他服务器。 这个游戏做来耍的就不做复杂了。

login 负责处理账户数据、

game 负责基本游戏逻辑。


通许协议直接用C++结构体了,懒的去弄其他协议了。

玩家登录:

协议定义:

JMSG_PROTOCOL_(verify_login_account,jdot_string, username, jdot_string, password, anubis_net::net_ident_t, custom_key);

verify_login_account : 协议名称

username: 用户名

password: 密码

custom_key:附加数据,服务器原样返回。

登录流程:

客户端 发起 登录请求:

  bool LoginModule::VerifyLoginAccount(const jdot_string&username, const jdot_string&password)
  {
    anubis::login_proto::verify_login_account msg;
    msg.username = username;
    msg.password = password;
    return GetClient()->SendNetMsg(msg);

  }

gate 转发登录请求:

    void LoginProxy::OnNetMessage(anubis::login_proto::verify_login_account&msg, Agent*agent, NetConnection*session)
    {
      //--
      if (m_state != kIdle) {
        //++
        anubis::login_proto::verify_login_account_ack ack;
        ack.result_code = proto::kBusy;
        session->SendMsg(ack);
        return;
      }

      m_reqClientCustomKey = msg.custom_key;
      m_username = msg.username;
      m_custom_params = msg.password;

      if (GetLoginStub()->VerifyLoginAccount(agent, msg)) {
        m_state = kVerifing;
      }
    }

    bool LoginStub::VerifyLoginAccount(Agent*agent, anubis::login_proto::verify_login_account&msg)
    {
      if (!m_session || m_session->IsClosed()) {
        anubis::login_proto::verify_login_account_ack ack;
        ack.username = msg.username;
        ack.custom_key = msg.custom_key;
        ack.result_code = proto::kInternalError;
        agent->SendMsg(ack);
        return false;
      }
      msg.custom_key.ident = agent->GetGateSaveKey();
      m_session->SendMsg(msg);
      return true;
    }

login server 注册消息:

  void LoginServer::DispatchMessage(NetConnection*session, const net::msg_header&header, net::unique_buffer_t::unpacker_t&unpacker, const net::unique_buffer_t&msg_buf)
  {
    bool is_handled = false;
    bool unpack_success = true;

    if (header.msg_type != anubis::basic_proto::set_svr_component::PROTOCOL_ID
      &&session->GetTag() != 1) {
      JDOT_DEBUG("session not verify,<%s,%d>", session->GetRemoteAddress().c_str(), session->GetRemotePort());
      session->KickSession();
      return;
    }

    ANUBIS_NET_MSG_SWITCH_BEGIN(is_handled, unpack_success, unpacker, header.msg_type)
      ANUBIS_CASE_ON_NET_MESSAGE(anubis::basic_proto::set_svr_component, session);
      ANUBIS_CASE_ON_NET_MESSAGE(anubis::login_proto::create_login_account, session);
      ANUBIS_CASE_ON_NET_MESSAGE(anubis::login_proto::verify_login_account, session);
      ANUBIS_CASE_ON_NET_MESSAGE(anubis::login_proto::create_role, session);
    ANUBIS_NET_MSG_SWITCH_END();

    if (!unpack_success) {
      JDOT_ERROR("unpack message error--%d", (int)header.msg_type);
    }

    if (!is_handled) {
      JDOT_ERROR("unhandle message --%d", (int)header.msg_type);
    }
    //++
  }

login server 转发 到 数据库服务器:

  void LoginServer::OnNetMessage(anubis::login_proto::verify_login_account&msg, NetConnection*session)
  {
    m_accountdb.VerifyAccount(session, msg);
  }

数据库,就用 sqlite了,反正是 做来玩的:

数据库验证帐号:

  void AccountDB::VerifyAccount(NetConnection*session, db_proto::verify_login_account&msg)
  {
    // 暂时同步处理.
    jdot_nodes::login_account_nodes_v1::LoginAccount node;


    node.SetUserName(msg.username);


    auto ret_code = m_accountTable->ReadDB(&node, decltype(node)::FLD_UserNameName);


    anubis::db_proto::verify_login_account_ack ack;
    ack.username = msg.username;
    ack.userid = node.GetDBID();
    ack.custom_key = msg.custom_key;


    if (ret_code == jdot_nodes::SqliteTable::kSuccess) {
      ack.result_code =node.GetDBID()!=0 && node.GetUserPassword() == msg.password ? proto::result_code::kSuccess : proto::result_code::kFail;
    }
    else if(ret_code==jdot_nodes::SqliteTable::kNotExists) {
      ack.result_code = proto::result_code::kFail;
    }
    else {
      ack.result_code = proto::result_code::kInternalError;
    }


    if (ret_code == jdot_nodes::SqliteTable::kSuccess && node.GetDBID() != 0 && node.GetUserPassword() == msg.password) {
      if (!m_dbServer->GetBaseDB()->LoginQueryRole(ack)) {
        ack.result_code = proto::result_code::kInternalError;// 读数据库出错.
      }
    }
    else {
      ack.roleid = 0;
    }


    session->SendMsg(ack);


    NET_DEBUG("check account:<%s,%s,%d>", msg.username.c_str(), msg.password.c_str(), ack.result_code);
  }

数据库验证后在一路返回到客户端:

客户端消息注册:

  void LoginModule::SetupHandlers()
  {
    ANUBIS_BEGIN_PROTO_HANDLER_MAP(GetClient()->NetDispatcher.GetMapping())
      ANUBIS_USER_PROTO_HANDLER(anubis::login_proto::verify_login_account_ack, OnNetMessage);
    ANUBIS_USER_PROTO_HANDLER(anubis::login_proto::create_login_account_ack, OnNetMessage);
    ANUBIS_USER_PROTO_HANDLER(anubis::login_proto::create_role_ack, OnNetMessage);
    ANUBIS_USER_PROTO_HANDLER(anubis::game_proto::game_load_role, OnNetMessage);
    ANUBIS_USER_PROTO_HANDLER(anubis::game_proto::game_load_role_failed, OnNetMessage);
   
    ANUBIS_END_PROTO_HANDLER_MAP();
  }

客户端用的cocos开发,简单分为逻辑层,和显示控制层 2层。逻辑层不知道 显示层的存在。显示层可以直接调用逻辑层。

客户端收到验证回调后,把消息转化为事件 发出去,感兴趣的ui层 会做相应展示:

  void LoginModule::OnNetMessage(ClientApp*client, anubis::login_proto::verify_login_account_ack&msg)
  {
    if (msg.result_code != anubis::proto::kSuccess) {
      client->Publish<EVT_NetAccountLogined>(client,false);
      return;
    }
    m_userid = msg.userid;
    m_roleid = msg.roleid;
    m_rolename = msg.rolename;
    //++
    client->Publish<EVT_NetAccountLogined>(client,true);
    //++ net message .measure time|-_-!! this need connect to the lobby to do ?
    if (msg.roleid != 0) {

      JDOT_INFO("verify success:<%d,%s>", (int)msg.roleid, (const char*)msg.rolename.c_str());


      client->MeasuredTime();
    }
  }
服务器基本框架就这样了,接着搞 游戏服务器逻辑。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值