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项目源码阅读    项目简介和注册登录的主要内容,如果未能解决你的问题,请参考以下文章

KBEngine源码:开始

KBEngine源码:组件方案

KBEngine源码:Space空间

KBEngine源码:EntityCall

KBEngine调研报告

KBEngine+Unity+php做个扑克小游戏-DAY1