• kbengine Unity3d demo 代码执行流程(4)


    1.简单介绍

    2.环境搭建

    3.FQA

    4.代码执行流程

    当服务端成功启动,客户端链接服务端后进入demo中的游戏界面,demo中的功能包括注册、登录、角色管理、战斗、场景等等。

    对于新接触kbengine的人,看见客户端的代码后会觉得很迷茫,有些无从下手。(本人unity和c++都是小白,所以更加难以入手)

    那么如果想使用kbengine框架做游戏业务逻辑上的扩展,就必须先知道代码的运行顺序,都执行了哪些方法,做了什么工作,以方便我们在基础上做更改和添加新的功能。网上很多大牛在介绍kbengine时候都介绍的很详尽,服务端各模块的介绍都很专业,但可惜技术水平原因,大部分都看不懂,有些甚至找不到,所以我的暂时目的是将框架搭建起,并根据官方的api文档在项目的基础上进行新功能的添加,底层的东西暂时不去理会,只关注python和客户端unity c#的部分。

    本人使用的是git上的kbengine_unity3d_demo

    下面简单介绍一下 kbengine中的代码结构。

    客户端

    之前搭建环境时,已经知道这两个文件夹,plugins中是对服务端的对应类(包括网络传输,数据处理,综合逻辑等等),script是自己的逻辑端代码。

    Assets/scripts:

    服务端:

    代码执行流程(以注册为例):

    点击createAccount(注册账号)时,首先执行UI.CS (Assets/scripts/u3d_scripts)中的onLonginUI方法。

    其中首先判断点击的是登录还是注册按钮,当点击注册按钮时将进入第二个if语块判断信息完善程度,然后执行 createAccount方法:

    该方法使用KBEngine.Event.fireIn方法,将触发逻辑端的"createAccount"方法

    这里介绍一下kbengine中使用触发条件的个函数( u3d_scripts表现层 kbe_scripts业务逻辑层 )
    1.KBEngine.Event.fireIn  表现层触发业务逻辑层的方法。
    2.KBEngine.Event.fireOut 逻辑层触发服务端的方法。
    3.Event.registerOut 表现层监听逻辑层的方法。
    4..Event.registerIn  逻辑层监听服务端的方法。

    客户端Kbengine.cs (Assets/Plugins)将接收到前端触发的"createAccount"方法:

    并在类内做方法实现:

    在方法执行过程中,1的部分表示提交服务器的处理路径,2为提交当前的网络请求。

    在1中,Loginapp_resCreateAccount参数,表示,该请求,提交至服务端loginapp,在loginapp.cpp中,有方法reqCreateAccount函数来处理本次请求:

    其中_createAccount方法如下:

    bool Loginapp::_createAccount(Network::Channel* pChannel, std::string& accountName, 
                                     std::string& password, std::string& datas, ACCOUNT_TYPE type)
    {
        AUTO_SCOPED_PROFILE("createAccount");
    
        ACCOUNT_TYPE oldType = type;
    
        if(!g_kbeSrvConfig.getDBMgr().account_registration_enable)
        {
            WARNING_MSG(fmt::format("Loginapp::_createAccount({}): not available!
    ", accountName));
    
            std::string retdatas = "";
            Network::Bundle* pBundle = Network::Bundle::createPoolObject();
            (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
            SERVER_ERROR_CODE retcode = SERVER_ERR_ACCOUNT_REGISTER_NOT_AVAILABLE;
            (*pBundle) << retcode;
            (*pBundle).appendBlob(retdatas);
            pChannel->send(pBundle);
            return false;
        }
    
        accountName = KBEngine::strutil::kbe_trim(accountName);
        password = KBEngine::strutil::kbe_trim(password);
    
        if(accountName.size() > ACCOUNT_NAME_MAX_LENGTH)
        {
            ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName too big, size={}, limit={}.
    ",
                accountName.size(), ACCOUNT_NAME_MAX_LENGTH));
    
            return false;
        }
    
        if(password.size() > ACCOUNT_PASSWD_MAX_LENGTH)
        {
            ERROR_MSG(fmt::format("Loginapp::_createAccount: password too big, size={}, limit={}.
    ",
                password.size(), ACCOUNT_PASSWD_MAX_LENGTH));
    
            return false;
        }
    
        if(datas.size() > ACCOUNT_DATA_MAX_LENGTH)
        {
            ERROR_MSG(fmt::format("Loginapp::_createAccount: bindatas too big, size={}, limit={}.
    ",
                datas.size(), ACCOUNT_DATA_MAX_LENGTH));
    
            return false;
        }
        
        std::string retdatas = "";
        if(shuttingdown_ != SHUTDOWN_STATE_STOP)
        {
            WARNING_MSG(fmt::format("Loginapp::_createAccount: shutting down, create {} failed!
    ", accountName));
    
            Network::Bundle* pBundle = Network::Bundle::createPoolObject();
            (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
            SERVER_ERROR_CODE retcode = SERVER_ERR_IN_SHUTTINGDOWN;
            (*pBundle) << retcode;
            (*pBundle).appendBlob(retdatas);
            pChannel->send(pBundle);
            return false;
        }
    
        PendingLoginMgr::PLInfos* ptinfos = pendingCreateMgr_.find(const_cast<std::string&>(accountName));
        if(ptinfos != NULL)
        {
            WARNING_MSG(fmt::format("Loginapp::_createAccount: pendingCreateMgr has {}, request create failed!
    ", 
                accountName));
    
            Network::Bundle* pBundle = Network::Bundle::createPoolObject();
            (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
            SERVER_ERROR_CODE retcode = SERVER_ERR_BUSY;
            (*pBundle) << retcode;
            (*pBundle).appendBlob(retdatas);
            pChannel->send(pBundle);
            return false;
        }
        
        {
            // 把请求交由脚本处理
            SERVER_ERROR_CODE retcode = SERVER_SUCCESS;
            SCOPED_PROFILE(SCRIPTCALL_PROFILE);
    
            PyObject* pyResult = PyObject_CallMethod(getEntryScript().get(), 
                                                const_cast<char*>("onRequestCreateAccount"), 
                                                const_cast<char*>("ssy#"), 
                                                accountName.c_str(),
                                                password.c_str(),
                                                datas.c_str(), datas.length());
    
            if(pyResult != NULL)
            {
                if(PySequence_Check(pyResult) && PySequence_Size(pyResult) == 4)
                {
                    char* sname;
                    char* spassword;
                    char *extraDatas;
                    Py_ssize_t extraDatas_size = 0;
                    
                    if(PyArg_ParseTuple(pyResult, "H|s|s|y#",  &retcode, &sname, &spassword, &extraDatas, &extraDatas_size) == -1)
                    {
                        ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error! accountName={}
    ", 
                            g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName));
    
                        retcode = SERVER_ERR_OP_FAILED;
                    }
                    else
                    {
                        accountName = sname;
                        password = spassword;
    
                        if (extraDatas && extraDatas_size > 0)
                            datas.assign(extraDatas, extraDatas_size);
                        else
                            SCRIPT_ERROR_CHECK();
                    }
                }
                else
                {
                    ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error, must be errorcode or tuple! accountName={}
    ", 
                        g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName));
    
                    retcode = SERVER_ERR_OP_FAILED;
                }
                
                Py_DECREF(pyResult);
            }
            else
            {
                SCRIPT_ERROR_CHECK();
                retcode = SERVER_ERR_OP_FAILED;
            }
                
            if(retcode != SERVER_SUCCESS)
            {
                Network::Bundle* pBundle = Network::Bundle::createPoolObject();
                (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
                (*pBundle) << retcode;
                (*pBundle).appendBlob(retdatas);
                pChannel->send(pBundle);
                return false;
            }
            else
            {
                if(accountName.size() == 0)
                {
                    ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName is empty!
    "));
    
                    retcode = SERVER_ERR_NAME;
                    Network::Bundle* pBundle = Network::Bundle::createPoolObject();
                    (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
                    (*pBundle) << retcode;
                    (*pBundle).appendBlob(retdatas);
                    pChannel->send(pBundle);
                    return false;
                }
            }
        }
    
        if(type == ACCOUNT_TYPE_SMART)
        {
            if (email_isvalid(accountName.c_str()))
            {
                type = ACCOUNT_TYPE_MAIL;
            }
            else
            {
                if(!validName(accountName))
                {
                    ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})
    ",
                        accountName));
    
                    Network::Bundle* pBundle = Network::Bundle::createPoolObject();
                    (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
                    SERVER_ERROR_CODE retcode = SERVER_ERR_NAME;
                    (*pBundle) << retcode;
                    (*pBundle).appendBlob(retdatas);
                    pChannel->send(pBundle);
                    return false;
                }
    
                type = ACCOUNT_TYPE_NORMAL;
            }
        }
        else if(type == ACCOUNT_TYPE_NORMAL)
        {
            if(!validName(accountName))
            {
                ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})
    ",
                    accountName));
    
                Network::Bundle* pBundle = Network::Bundle::createPoolObject();
                (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
                SERVER_ERROR_CODE retcode = SERVER_ERR_NAME;
                (*pBundle) << retcode;
                (*pBundle).appendBlob(retdatas);
                pChannel->send(pBundle);
                return false;
            }
        }
        else if (!email_isvalid(accountName.c_str()))
        {
            /*
            std::string user_name, domain_name;
            user_name = regex_replace(accountName, _g_mail_pattern, std::string("$1") );
            domain_name = regex_replace(accountName, _g_mail_pattern, std::string("$2") );
            */
            WARNING_MSG(fmt::format("Loginapp::_createAccount: invalid mail={}
    ", 
                accountName));
    
            Network::Bundle* pBundle = Network::Bundle::createPoolObject();
            (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
            SERVER_ERROR_CODE retcode = SERVER_ERR_NAME_MAIL;
            (*pBundle) << retcode;
            (*pBundle).appendBlob(retdatas);
            pChannel->send(pBundle);
            return false;
        }
    
        DEBUG_MSG(fmt::format("Loginapp::_createAccount: accountName={}, passwordsize={}, type={}, oldType={}.
    ",
            accountName.c_str(), password.size(), type, oldType));
    
        ptinfos = new PendingLoginMgr::PLInfos;
        ptinfos->accountName = accountName;
        ptinfos->password = password;
        ptinfos->datas = datas;
        ptinfos->addr = pChannel->addr();
        pendingCreateMgr_.add(ptinfos);
    
        Components::COMPONENTS& cts = Components::getSingleton().getComponents(DBMGR_TYPE);
        Components::ComponentInfos* dbmgrinfos = NULL;
    
        if(cts.size() > 0)
            dbmgrinfos = &(*cts.begin());
    
        if(dbmgrinfos == NULL || dbmgrinfos->pChannel == NULL || dbmgrinfos->cid == 0)
        {
            ERROR_MSG(fmt::format("Loginapp::_createAccount: create({}), not found dbmgr!
    ", 
                accountName));
    
            Network::Bundle* pBundle = Network::Bundle::createPoolObject();
            (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
            SERVER_ERROR_CODE retcode = SERVER_ERR_SRV_NO_READY;
            (*pBundle) << retcode;
            (*pBundle).appendBlob(retdatas);
            pChannel->send(pBundle);
            return false;
        }
    
        pChannel->extra(accountName);
    
        Network::Bundle* pBundle = Network::Bundle::createPoolObject();
        (*pBundle).newMessage(DbmgrInterface::reqCreateAccount);
        uint8 uatype = uint8(type);
        (*pBundle) << accountName << password << uatype;
        (*pBundle).appendBlob(datas);
        dbmgrinfos->pChannel->send(pBundle);
        return true;
    }

    在方法中,将调用python脚本来做服务端的业务处理逻辑,代码位置于 (kbengine_demos_assetsscriptsloginkbmain.py)

    业务逻辑处理完成后,会调用数据库处理的服务端app(dbmgr)来做相应的数据库操作并返回数据。

    至此请求部分执行完成,请求后 服务端会在不同阶段返回相应的状态,在UI.cs中进行返回结果的监听并及时做出处理结果的反应。

  • 相关阅读:
    gsoap、c++。webservice的client。
    2.5给定两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。进阶:假设这些数位是正向存放的。
    c++、webServices、gsoap、tinyxml、iconv
    2.4编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或者等于x的结点之前。
    CMD窗口快捷键
    IE7下position:relative与overflow的问题
    关于ASP.NET下,JQuery+AJAX使用JSON返回对象集合List数据的总结
    找不到可安装的 ISAM(必解决)
    jquery mini ui
    Unity3D
  • 原文地址:https://www.cnblogs.com/z-yue/p/5794000.html
Copyright © 2020-2023  润新知