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!\n", 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={}.\n",
            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={}.\n",
            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={}.\n",
            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!\n", 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!\n", 
            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={}\n", 
                        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={}\n", 
                    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!\n"));

                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({})\n",
                    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({})\n",
                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={}\n", 
            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={}.\n",
        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!\n", 
            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_assets\scripts\login\kbmain.py)

業務邏輯處理完成后,會調用數據庫處理的服務端app(dbmgr)來做相應的數據庫操作並返回數據。

至此請求部分執行完成,請求后 服務端會在不同階段返回相應的狀態,在UI.cs中進行返回結果的監聽並及時做出處理結果的反應。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM