KBEngine warring项目源码阅读 项目简介和注册登录
Posted 李世铭
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KBEngine warring项目源码阅读 项目简介和注册登录相关的知识,希望对你有一定的参考价值。
首先介绍下warring项目,是kbe自带的一个演示示例,大部分人了解kbe引擎也是从warring项目开始的。
项目地址:https://github.com/kbengine/kbengine_unity3d_warring
项目截图:
项目的下载和安装不再多说,现在开始进入代码讲解阶段:
注册:
流程图:
可以看到控件绑定代码为reg_ok,点进去
1 void reg_ok() 2 { 3 log_label.obj.text = "请求连接服务器..."; 4 log_label.obj.color = UnityEngine.Color.green; 5 6 if(reg_username.input.text == "" || reg_username.input.text.Length > 30) 7 { 8 log_label.obj.color = UnityEngine.Color.red; 9 log_label.obj.text = "用户名或者邮箱地址不合法, 最大长度限制30个字符。"; 10 Common.WARNING_MSG("ui::reg_ok: invalid username!"); 11 return; 12 } 13 14 if(reg_password.input.text.Length < 6 || reg_password.input.text.Length > 16) 15 { 16 log_label.obj.color = UnityEngine.Color.red; 17 log_label.obj.text = "密码不合法, 长度限制在6~16位之间。"; 18 Common.WARNING_MSG("ui::reg_ok: invalid reg_password!"); 19 return; 20 } 21 22 if(reg_password.input.text != reg_passwordok.input.text) 23 { 24 log_label.obj.color = UnityEngine.Color.red; 25 log_label.obj.text = "二次输入密码不匹配。"; 26 Common.WARNING_MSG("ui::reg_ok: reg_password != reg_passwordok!"); 27 return; 28 } 29 30 KBEngine.Event.fireIn("createAccount", reg_username.input.text, reg_passwordok.input.text, System.Text.Encoding.UTF8.GetBytes("kbengine_unity_warring")); 31 log_label.obj.text = "连接成功,等待处理请稍后..."; 32 }
可以看到接下来是fireIn("createAccount",xxxx,...)
这里需要讲解一下客户端的fireIn和fireOut是怎么一回事,fireIn是指u3d脚本层触发一个事件给kbe插件执行,fireOut是是插件向u3d脚本层触发的事件,总之是从unity到kbe插件的一个交互过程。既然是插件层层,那么我们打开KBEngine.cs去找对应的registerIn,可以找到下面的代码
1 void installEvents() 2 { 3 Event.registerIn("createAccount", this, "createAccount"); 4 Event.registerIn("login", this, "login"); 5 Event.registerIn("reloginBaseapp", this, "reloginBaseapp"); 6 Event.registerIn("resetPassword", this, "resetPassword"); 7 Event.registerIn("bindAccountEmail", this, "bindAccountEmail"); 8 Event.registerIn("newPassword", this, "newPassword"); 9 10 // 内部事件 11 Event.registerIn("_closeNetwork", this, "_closeNetwork"); 12 }
然后在同一文件的第727行,找到对应的消息,可以看到下一步是调用的createAccount_loginapp(false)函数
点开进去
1 /* 2 创建账号,通过loginapp 3 */ 4 public void createAccount_loginapp(bool noconnect) 5 { 6 if(noconnect) 7 { 8 reset(); 9 _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_createAccount_callback, null); 10 } 11 else 12 { 13 Bundle bundle = Bundle.createObject(); 14 bundle.newMessage(Message.messages["Loginapp_reqCreateAccount"]); 15 bundle.writeString(username); 16 bundle.writeString(password); 17 //string imei = \'AET89766-124\'; 18 //bundle.writeString(imei); 19 bundle.writeBlob(KBEngineApp.app._clientdatas); 20 bundle.send(_networkInterface); 21 } 22 }
可以看到这里开始给后端发了一个消息,消息关键字是Loginapp_reqCreateAccount。我们打开kbe的C++部分源码
在loginapp项目中,找到loginapp.cpp的reqCreateAccount方法,为什么要找这个方法,因为在代码底层识别的时候将关键字变为了前半段代表的节点名,后半段代表消息。
1 //------------------------------------------------------------------------------------- 2 void Loginapp::reqCreateAccount(Network::Channel* pChannel, MemoryStream& s) 3 { 4 std::string accountName, password, datas; 5 6 s >> accountName >> password; 7 s.readBlob(datas); 8 9 if(!_createAccount(pChannel, accountName, password, datas, ACCOUNT_TYPE(g_serverConfig.getLoginApp().account_type))) 10 return; 11 }
点开_createAccount
1 //------------------------------------------------------------------------------------- 2 bool Loginapp::_createAccount(Network::Channel* pChannel, std::string& accountName, 3 std::string& password, std::string& datas, ACCOUNT_TYPE type) 4 { 5 AUTO_SCOPED_PROFILE("createAccount"); 6 7 ACCOUNT_TYPE oldType = type; 8 9 if(!g_kbeSrvConfig.getDBMgr().account_registration_enable) 10 { 11 ERROR_MSG(fmt::format("Loginapp::_createAccount({}): not available! modify kbengine[_defs].xml->dbmgr->account_registration.\\n", 12 accountName)); 13 14 std::string retdatas = ""; 15 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 16 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 17 SERVER_ERROR_CODE retcode = SERVER_ERR_ACCOUNT_REGISTER_NOT_AVAILABLE; 18 (*pBundle) << retcode; 19 (*pBundle).appendBlob(retdatas); 20 pChannel->send(pBundle); 21 return false; 22 } 23 24 accountName = KBEngine::strutil::kbe_trim(accountName); 25 password = KBEngine::strutil::kbe_trim(password); 26 27 if(accountName.size() > ACCOUNT_NAME_MAX_LENGTH) 28 { 29 ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName too big, size={}, limit={}.\\n", 30 accountName.size(), ACCOUNT_NAME_MAX_LENGTH)); 31 32 return false; 33 } 34 35 if(password.size() > ACCOUNT_PASSWD_MAX_LENGTH) 36 { 37 ERROR_MSG(fmt::format("Loginapp::_createAccount: password too big, size={}, limit={}.\\n", 38 password.size(), ACCOUNT_PASSWD_MAX_LENGTH)); 39 40 return false; 41 } 42 43 if(datas.size() > ACCOUNT_DATA_MAX_LENGTH) 44 { 45 ERROR_MSG(fmt::format("Loginapp::_createAccount: bindatas too big, size={}, limit={}.\\n", 46 datas.size(), ACCOUNT_DATA_MAX_LENGTH)); 47 48 return false; 49 } 50 51 std::string retdatas = ""; 52 if(shuttingdown_ != SHUTDOWN_STATE_STOP) 53 { 54 WARNING_MSG(fmt::format("Loginapp::_createAccount: shutting down, create {} failed!\\n", accountName)); 55 56 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 57 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 58 SERVER_ERROR_CODE retcode = SERVER_ERR_IN_SHUTTINGDOWN; 59 (*pBundle) << retcode; 60 (*pBundle).appendBlob(retdatas); 61 pChannel->send(pBundle); 62 return false; 63 } 64 65 PendingLoginMgr::PLInfos* ptinfos = pendingCreateMgr_.find(const_cast<std::string&>(accountName)); 66 if(ptinfos != NULL) 67 { 68 WARNING_MSG(fmt::format("Loginapp::_createAccount: pendingCreateMgr has {}, request create failed!\\n", 69 accountName)); 70 71 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 72 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 73 SERVER_ERROR_CODE retcode = SERVER_ERR_BUSY; 74 (*pBundle) << retcode; 75 (*pBundle).appendBlob(retdatas); 76 pChannel->send(pBundle); 77 return false; 78 } 79 80 { 81 // 把请求交由脚本处理 82 SERVER_ERROR_CODE retcode = SERVER_SUCCESS; 83 SCOPED_PROFILE(SCRIPTCALL_PROFILE); 84 85 PyObject* pyResult = PyObject_CallMethod(getEntryScript().get(), 86 const_cast<char*>("onRequestCreateAccount"), 87 const_cast<char*>("ssy#"), 88 accountName.c_str(), 89 password.c_str(), 90 datas.c_str(), datas.length()); 91 92 if(pyResult != NULL) 93 { 94 if(PySequence_Check(pyResult) && PySequence_Size(pyResult) == 4) 95 { 96 char* sname; 97 char* spassword; 98 char *extraDatas; 99 Py_ssize_t extraDatas_size = 0; 100 101 if(PyArg_ParseTuple(pyResult, "H|s|s|y#", &retcode, &sname, &spassword, &extraDatas, &extraDatas_size) == -1) 102 { 103 ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error! accountName={}\\n", 104 g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName)); 105 106 retcode = SERVER_ERR_OP_FAILED; 107 } 108 else 109 { 110 accountName = sname; 111 password = spassword; 112 113 if (extraDatas && extraDatas_size > 0) 114 datas.assign(extraDatas, extraDatas_size); 115 else 116 SCRIPT_ERROR_CHECK(); 117 } 118 } 119 else 120 { 121 ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error, must be errorcode or tuple! accountName={}\\n", 122 g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName)); 123 124 retcode = SERVER_ERR_OP_FAILED; 125 } 126 127 Py_DECREF(pyResult); 128 } 129 else 130 { 131 SCRIPT_ERROR_CHECK(); 132 retcode = SERVER_ERR_OP_FAILED; 133 } 134 135 if(retcode != SERVER_SUCCESS) 136 { 137 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 138 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 139 (*pBundle) << retcode; 140 (*pBundle).appendBlob(retdatas); 141 pChannel->send(pBundle); 142 return false; 143 } 144 else 145 { 146 if(accountName.size() == 0) 147 { 148 ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName is empty!\\n")); 149 150 retcode = SERVER_ERR_NAME; 151 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 152 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 153 (*pBundle) << retcode; 154 (*pBundle).appendBlob(retdatas); 155 pChannel->send(pBundle); 156 return false; 157 } 158 } 159 } 160 161 if(type == ACCOUNT_TYPE_SMART) 162 { 163 if (email_isvalid(accountName.c_str())) 164 { 165 type = ACCOUNT_TYPE_MAIL; 166 } 167 else 168 { 169 if(!validName(accountName)) 170 { 171 ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})\\n", 172 accountName)); 173 174 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 175 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 176 SERVER_ERROR_CODE retcode = SERVER_ERR_NAME; 177 (*pBundle) << retcode; 178 (*pBundle).appendBlob(retdatas); 179 pChannel->send(pBundle); 180 return false; 181 } 182 183 type = ACCOUNT_TYPE_NORMAL; 184 } 185 } 186 else if(type == ACCOUNT_TYPE_NORMAL) 187 { 188 if(!validName(accountName)) 189 { 190 ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})\\n", 191 accountName)); 192 193 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 194 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 195 SERVER_ERROR_CODE retcode = SERVER_ERR_NAME; 196 (*pBundle) << retcode; 197 (*pBundle).appendBlob(retdatas); 198 pChannel->send(pBundle); 199 return false; 200 } 201 } 202 else if (!email_isvalid(accountName.c_str())) 203 { 204 /* 205 std::string user_name, domain_name; 206 user_name = regex_replace(accountName, _g_mail_pattern, std::string("$1") ); 207 domain_name = regex_replace(accountName, _g_mail_pattern, std::string("$2") ); 208 */ 209 WARNING_MSG(fmt::format("Loginapp::_createAccount: invalid mail={}\\n", 210 accountName)); 211 212 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 213 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 214 SERVER_ERROR_CODE retcode = SERVER_ERR_NAME_MAIL; 215 (*pBundle) << retcode; 216 (*pBundle).appendBlob(retdatas); 217 pChannel->send(pBundle); 218 return false; 219 } 220 221 DEBUG_MSG(fmt::format("Loginapp::_createAccount: accountName={}, passwordsize={}, type={}, oldType={}.\\n", 222 accountName.c_str(), password.size(), type, oldType)); 223 224 ptinfos = new PendingLoginMgr::PLInfos; 225 ptinfos->accountName = accountName; 226 ptinfos->password = password; 227 ptinfos->datas = datas; 228 ptinfos->addr = pChannel->addr(); 229 pendingCreateMgr_.add(ptinfos); 230 231 Components::COMPONENTS& cts = Components::getSingleton().getComponents(DBMGR_TYPE); 232 Components::ComponentInfos* dbmgrinfos = NULL; 233 234 if(cts.size() > 0) 235 dbmgrinfos = &(*cts.begin()); 236 237 if(dbmgrinfos == NULL || dbmgrinfos->pChannel == NULL || dbmgrinfos->cid == 0) 238 { 239 ERROR_MSG(fmt::format("Loginapp::_createAccount: create({}), not found dbmgr!\\n", 240 accountName)); 241 242 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 243 (*pBundle).newMessage(ClientInterface::onCreateAccountResult); 244 SERVER_ERROR_CODE retcode = SERVER_ERR_SRV_NO_READY; 245 (*pBundle) << retcode; 246 (*pBundle).appendBlob(retdatas); 247 pChannel->send(pBundle); 248 return false; 249 } 250 251 pChannel->extra(accountName); 252 253 Network::Bundle* pBundle = Network::Bundle::createPoolObject(); 254 (*pBundle).newMessage(DbmgrInterface::reqCreateAccount); 255 uint8 uatype = uint8(type); 256 (*pBundle) << accountName << password << uatype; 257 (*pBundle).appendBlob(datas); 258 dbmgrinfos->pChannel->send(pBundle); 259 return true; 260 }
可以看到,进行了一堆繁琐的验证以后,最后将解析出来的用户名密码等其他数据
我们打开dbmgr,找到reqCreateAccount函数
1 //------------------------------------------------------------------------------------- 2 void Dbmgr::reqCreateAccount(Network::Channel* pChannel, KBEngine::MemoryStream& s) 3 { 4 std::string registerName, password, datas; 5 uint8 uatype = 0; 6 7 s >> registerName >> password >> uatype; 8 s.readBlob(datas); 9 10 if(registerName.size() == 0) 11 { 12 ERROR_MSG("Dbmgr::reqCreateAccount: registerName is empty.\\n"); 13 return; 14 } 15 16 pInterfacesAccountHandler_->createAccount(pChannel, registerName, password, datas, ACCOUNT_TYPE(uatype)); 17 numCreatedAccount_++; 18 }
然后点开createAccount,因为一般情况下配置文件会填写host和port,所以我们进入InterfacesHandler_Dbmgr::createAccount的方法查看
1 //------------------------------------------------------------------------------------- 2 bool InterfacesHandler_Dbmgr::createAccount(Network::Channel* pChannel, std::string& registerName, 3 std::string& password, std::string& datas, ACCOUNT_TYPE uatype) 4 { 5 std::string dbInterfaceName = Dbmgr::getSingleton().selectAccountDBInterfaceName(registerName); 6 7 thread::ThreadPool* pThreadPool = DBUtil::pThreadPool(dbInterfaceName); 8 if (!pThreadPool) 9 { 10 ERROR_MSG(fmt::format("InterfacesHandler_Dbmgr::createAccount: not found dbInterface({})!\\n", 11 dbInterfaceName)); 12 13 return false; 14 } 15 16 // 如果是email,先查询账号是否存在然后将其登记入库 17 if(uatype == ACCOUNT_TYPE_MAIL) 18 { 19 pThreadPool->addTask(new DBTaskCreateMailAccount(pChannel->addr(), 20 registerName, registerName, password, datas, datas)); 21 22 return true; 23 } 24 25 pThreadPool->addTask(new DBTaskCreateAccount(pChannel->addr(), 26 registerName, registerName, password, datas, datas)); 27 28 return true; 29 }
可以看到,这里是用了一个异步任务队列的形式,进行的数据库写入,点开DBTaskCreateAccount,事实上邮件账号的原理是一样的
我们简单的看下DBTaskCreateAccount这个类,头文件
1 /*以上是关于KBEngine warring项目源码阅读 项目简介和注册登录的主要内容,如果未能解决你的问题,请参考以下文章