Esempio n. 1
0
int CWorldCrossserver::OnCrossClientResp(CPluto& u)
{
	CHECK_AND_GET_RPC_FIELD(u, nSeq, uint32_t);

	//检查流水号对应的外系统连接是否还在
	map<uint32_t, _SCrossClientInfo*>::iterator iter1 = m_InRpc.find(nSeq);
	if(iter1 == m_InRpc.end())
	{
		LogWarning("CWorldCrossserver::OnCrossClientResp", "notfound_seq=%d", nSeq);
		return -1;
	}

	_SCrossClientInfo* pInfo = iter1 ->second;
	CMailBox* mb = GetServer()->GetClientMailbox(pInfo->fd);
	if(mb == NULL)
	{
		//外系统已经断开连接了
		LogWarning("CWorldCrossserver::OnCrossClientResp", "notfoundclient_seq=%d", nSeq);
		return -2;
	}

	CPluto* u2 = new CPluto;
	u2->Encode(MSGID_CROSSCLIENT_RESP) << pInfo->sid << pInfo->etype << pInfo->eid;
	//转发包内容
	u2->FillBuff(u.GetBuff()+u.GetLen(), u.GetMaxLen()-u.GetLen());
	u2->endPluto();
	mb->PushPluto(u2);

	//删除数据,即每个流水号只能被回调一次
	delete pInfo;
	m_InRpc.erase(iter1);
	m_lsFreeRpcSeq.push_back(nSeq); //流水号重用

	return 0;
}
Esempio n. 2
0
int CDbMgrServer::HandleSendPluto()
{
    enum { SEND_COUNT = 1000, };
    CPluto* u;
    int i = 0;
	while (!g_pluto_sendlist.Empty())
    {
		u = g_pluto_sendlist.PopPluto();
        CMailBox* mb = u->GetMailbox();
        if(mb)
        {
            LogDebug("CDbMgrServer::HandleSendPluto", "u.GenLen()=%d", u->GetLen());
            mb->PushPluto(u);
        }
        //每次只发送一定条数,主要用在loadAllAvatar处
        if(++i > SEND_COUNT)
        {
            break;
        }
    }

    CEpollServer::HandleSendPluto();

	return 0;
}
Esempio n. 3
0
    //模拟错误的rpc包
    bool err_avatar_rpc()
    {
        //远程方法名
        CDefParser& defp = GetWorld()->GetDefParser();
        const SEntityDef* pDef = defp.GetEntityDefByName("Avatar");
        string strFunc("UseSkillReq");        
        uint16_t nFunc = (uint16_t)pDef->m_baseMethodsMap.GetIntByStr(strFunc);		

        CPluto u;
        u.Encode(MSGID_BASEAPP_CLIENT_RPCALL) << nFunc;

        //其他参数
        u << (uint64_t) 1 << (uint16_t) 2 << (uint16_t)3 << (uint8_t) 4 << (uint16_t) 5 ;
        u << (uint8_t) 6; //error
        u << EndPluto;

        //发送
        printf("send err_cmd: %s \n", strFunc.c_str());
        //print_hex_pluto(u);
        write_some(u.GetBuff(), u.GetLen());

        //收取回应包
        //async_read_some();
        //CPluto* u2 = read_pluto();
        //delete u2;

        return true;
    }
Esempio n. 4
0
	bool login_baseapp(SBaseappLoginData* bd)
	{
		if(bd == NULL)
		{
			return false;
		}

		if(this->connect(bd->m_strBase.c_str(), bd->m_unPort))
		{
			//发送登录包
			CPluto u;
			m_rpc.Encode(u, MSGID_BASEAPP_CLIENT_LOGIN, bd->m_strKey);
			write_some(u.GetBuff(), u.GetLen());
		}
		else
		{
			return false;
		}

		//等待绑定entity(等Account转换为Avatar)
#ifdef _WIN32
		Sleep(100);
#else
        Sleep(1);
#endif

		bool bWait = true;
        int nWaitCount = 0;
		while(bWait)
		{
			CPluto* u = read_pluto();
			if(u)
			{
				//T_VECTOR_OBJECT* p = m_rpc.decode(*u);
				//if(p)
				//{
				//	pluto_msgid_t msgid = u->getMsgId();
				//	if(msgid == MSGID_CLIENT_ENTITY_ATTACHED)
				//	{
				//		bWait = false;
				//		printf("entity attached.\n");
				//	}

				//	clear_T_LIST_OBJECT(p);
				//}
				//delete u;

				bWait = false;
				printf("entity attached.\n");
			}

            if(++nWaitCount > 3)
            {
                bWait = false;
                printf("wait_timeout.\n");
            }
		}

		return true;
	}
Esempio n. 5
0
    int CWorldDbmgr::SelectAccount(T_VECTOR_OBJECT* p, CDbOper& db)
    {
#if __PLAT_PLUG_IN || __PLAT_PLUG_IN_NEW
		if(p->size() != 3)
#else
		if(p->size() != 4)
#endif
        {
            return -1;
        }

        uint16_t nServerId = VOBJECT_GET_U16((*p)[0]);
        int32_t nFd = VOBJECT_GET_I32((*p)[1]);
        const char* s1 = VOBJECT_GET_STR((*p)[2]);
#if __PLAT_PLUG_IN || __PLAT_PLUG_IN_NEW

#else
        const char* s2 = VOBJECT_GET_STR((*p)[3]);
#endif

        CPluto* u = new CPluto;
        string strErr;
#if __PLAT_PLUG_IN || __PLAT_PLUG_IN_NEW
		if(db.SelectAccount(nFd, s1, *u, strErr) != 0)
#else
        if(db.SelectAccount(nFd, s1, s2, *u, strErr) != 0)
#endif
        {
            delete u;
            //cout << strErr << endl;
            LogWarning("SelectAccount_err", "%s", strErr.c_str());
            return -2;
        }

        //通知db结果
        CEpollServer* s = this->GetServer();
        CMailBox* mb = s->GetServerMailbox(nServerId);
        if(mb)
        {
#ifdef _WIN32
            mb->RpcCall(*u);
#else
            u->SetMailbox(mb);

            LogDebug("CWorldDbmgr::SelectAccount", "u.GenLen()=%d", u->GetLen());

            g_pluto_sendlist.PushPluto(u);
#endif
        }
        else
        {
            delete u;
            LogWarning("SelectAccount_err", "no mb!");
            return -3;
        }

        return 0;
    }
Esempio n. 6
0
    //根据dbid查找entity
    int CWorldDbmgr::LookupEntityByDbId(T_VECTOR_OBJECT* p, CDbOper& db)
    {
        if(p->size() != 4)
        {
            return -1;
        }

        uint8_t nServerId = VOBJECT_GET_U8((*p)[0]);
        const char* szEntityName = VOBJECT_GET_STR((*p)[1]);
        TDBID dbid = VOBJECT_GET_U64((*p)[2]);
        int32_t ref = VOBJECT_GET_I32((*p)[3]);

        CPluto* u = new CPluto;
        string strErr;
        if(db.LookupEntityByDbId(szEntityName, dbid, ref, *u, strErr) != 0)
        {
            delete u;
            //cout << strErr << endl;
            LogWarning("LookupEntityByDbId_err", "%s", strErr.c_str());
            return -2;
        }

        //通知db结果
        CEpollServer* s = this->GetServer();
        CMailBox* mb = s->GetServerMailbox(nServerId);
        if(mb)
        {
#ifdef _WIN32
            mb->RpcCall(*u);
#else
            u->SetMailbox(mb);

            LogDebug("CWorldDbmgr::LookupEntityByDbId", "u.GenLen()=%d", u->GetLen());

            g_pluto_sendlist.PushPluto(u);
#endif
        }
        else
        {
            LogWarning("CWorldDbmgr::LookupEntityByDbId", "u.GenLen()=%d", u->GetLen());
            delete u;
        }

        return 0;
    }
Esempio n. 7
0
	//随机走动
	void random_move()
	{
		uint16_t x = 3016 + rand() % 300;
		uint16_t y = 2020 + rand() % 300;
		CPluto u;
		u.Encode(MSGID_BASEAPP_CLIENT_MOVE_REQ) << x << y << EndPluto;
		//u.Cryto();
		write_some(u.GetBuff(), u.GetLen());
	}
Esempio n. 8
0
    int CWorldMgrD::CreateBaseFromDbByName(T_VECTOR_OBJECT* p)
    {
        if(p->size() < 3)
        {
            return -1;
        }

        uint8_t createFlag = VOBJECT_GET_U8((*p)[0]);
        const char* pszEntityType = VOBJECT_GET_STR((*p)[1]);
        const char* pszKey = VOBJECT_GET_STR((*p)[2]);

        uint16_t nBaseappId;
        if(p->size() > 3)
        {
            //指定了baseapp
            nBaseappId = VOBJECT_GET_U16((*p)[3]);
        }
        else
        {
            //未指定baseapp,选择一个
            nBaseappId = ChooseABaseApp(pszEntityType);
        }

#ifdef __TEST_LOGIN
        CEpollServer* s = this->GetServer();
        CMailBox* mb = s->GetServerMailbox(nBaseappId);

        if (mb)
        {
            TENTITYID nOtherEntityId = 0;

            CPluto* u = new CPluto;
            (*u).Encode(MSGID_BASEAPP_LOOKUP_ENTITY_CALLBACK);
            (*u) << (uint64_t)0 << this->GetNextEntityId()<< createFlag << pszKey << nOtherEntityId;
            (*u) << this->GetDefParser().GetTypeId(pszEntityType);

            TDBID dbid2 = 0;

            (*u).ReplaceField(PLUTO_FILED_BEGIN_POS, dbid2);
            (*u) << EndPluto;

            u->SetMailbox(mb);

            LogDebug("CWorldMgrD::CreateBaseFromDbByName", "u.GenLen()=%d", u.GetLen());

            mb->PushPluto(u);
        }

#else
        CMailBox* mb = GetServerMailbox(SERVER_DBMGR);
        if(mb)
        {
            mb->RpcCall(GetRpcUtil(), MSGID_DBMGR_CREATEBASE_FROM_NAME, nBaseappId, createFlag, pszEntityType, pszKey);
        }
#endif
        return 0;
    }
Esempio n. 9
0
    bool avatar_cell_rpc(const char* cmd)
    {
        list<string> ls;
        SplitString(cmd, '|', ls);

        if(ls.empty())
        {
            printf("error rpc, empty string. \n");
            return false;
        }

        //远程方法名
        CDefParser& defp = GetWorld()->GetDefParser();
        const SEntityDef* pDef = defp.GetEntityDefByName("Avatar");
        string strFunc = ls.front();
        ls.pop_front();
        uint16_t nFunc = (uint16_t)pDef->m_cellMethodsMap.GetIntByStr(strFunc);		

        CPluto u;
        u.Encode(MSGID_BASEAPP_CLIENT_RPC2CELL_VIA_BASE) << nFunc;

        //其他参数
        map<string, _SEntityDefMethods*>::const_iterator iter11 = pDef->m_cellMethods.find(strFunc);		
        if(iter11 != pDef->m_cellMethods.end())
        {
            _SEntityDefMethods* pmethod = iter11->second;
            list<VTYPE>::const_iterator iter = pmethod->m_argsType.begin();
            for(; iter != pmethod->m_argsType.end(); ++iter)
            {
                if(ls.empty())
                {
                    printf("error rpc, less params, %s \n", cmd);
                    return false;
                }

                const string& sv = ls.front();
                u.FillPlutoFromStr(*iter, sv.c_str(), (unsigned long)sv.size());
                ls.pop_front();
            }
        }

        u << EndPluto;

        //发送
        printf("send cell cmd: %s \n", cmd);
        //print_hex_pluto(u);
        write_some(u.GetBuff(), u.GetLen());

        //收取回应包
        //async_read_some();
        //CPluto* u2 = read_pluto();
        //delete u2;

        return true;
    }
Esempio n. 10
0
//来自原始服的跨服调用
int CWorldCrossserver::OnCrossServerRpc(CPluto& u)
{
	//printf("CWorldCrossserver::OnCrossServerRpc 111\n");

	CHECK_AND_GET_RPC_FIELD(u, uSrcServerId, uint16_t);
	CHECK_AND_GET_RPC_FIELD(u, etype, TENTITYTYPE);
	CHECK_AND_GET_RPC_FIELD(u, eid, TENTITYID);
	CHECK_AND_GET_RPC_FIELD(u, strGlobal, string);
	//CHECK_AND_GET_RPC_FIELD(u, strFuncId, uint16_t);

	uint32_t nSeq = GetNextRpcSeq(u, uSrcServerId, etype, eid);
	if(nSeq == 0)
	{
		return -1;
	}

	//printf("CWorldCrossserver::OnCrossServerRpc 222, %d - %d - %d - %s - seq =%d \n", uSrcServerId, etype, eid, strGlobal.c_str(), nSeq);

	map<string, CEntityMailbox*>::iterator iter1 = m_globalBases.find(strGlobal);
	if(iter1 == m_globalBases.end())
	{
		return -2;
	}

	CEntityMailbox* emb = iter1->second;
	CMailBox* mb = GetServerMailbox(emb->m_nServerMailboxId);
	if(mb)
	{
		CPluto* u2 = new CPluto;
		u2->Encode(MSGID_BASEAPP_ENTITY_RPC) << (*emb);
		u2->FillBuff(u.GetBuff()+u.GetLen(), 2);        //msg_id
		u2->FillField(nSeq);                            //填充流水号字段
		u2->FillBuff(u.GetBuff()+u.GetLen()+2, u.GetMaxLen()-u.GetLen()-2);//copy其他字段
		u2->endPluto();
		mb->PushPluto(u2);

		return 0;
	}

	return -2;
}
Esempio n. 11
0
    int CWorldDbmgr::InsertDB(T_VECTOR_OBJECT* p, CDbOper& db)
    {
        if(p->size() != 3)
        {
            return -1;
        }

        CEntityMailbox& emb = VOBJECT_GET_EMB((*p)[0]);
        int32_t ref = VOBJECT_GET_I32((*p)[1]);
        SEntityPropFromPluto* p2 = (SEntityPropFromPluto*)((*p)[2]->vv.p);

        const string& strEntityName = GetDefParser().GetTypeName(p2->etype);

        //string strSql;
        //db.make_insert_sql(strEntityName, p2->data, strSql);
        //cout << strSql << endl;

        //string strSql2;
        //db.make_create_sql(strEntityName, strSql2);
        //cout << strSql2 << endl;

        //LogWarning("insert to db", "emb ref strEntityName = %s", strEntityName.c_str());

        string strErr;
        TDBID newid = db.InsertEntity(strEntityName, p2->data, strErr);
        if(newid == 0)
        {
            LogWarning("InsertDB_err", "newid=0;err=%s", strErr.c_str());
            //cout << strErr << endl;
            //return -2;
        }

        //通知db结果
        CEpollServer* s = this->GetServer();
        CMailBox* mb = s->GetServerMailbox(emb.m_nServerMailboxId);
        if(mb)
        {
#ifdef _WIN32
            mb->RpcCall(GetRpcUtil(), MSGID_BASEAPP_INSERT_ENTITY_CALLBACK, emb, newid, ref, strErr.c_str());
#else
            CRpcUtil& rpc = GetRpcUtil();
            CPluto* u = new CPluto;
            rpc.Encode(*u, MSGID_BASEAPP_INSERT_ENTITY_CALLBACK, emb, newid, ref, strErr.c_str());
            u->SetMailbox(mb);

            LogDebug("CDbOper::InsertDB", "u.GenLen()=%d", u->GetLen());

            g_pluto_sendlist.PushPluto(u);
#endif
        }

        return 0;
    }
Esempio n. 12
0
//来自跨服的回调
int CWorldCrossclient::OnCrossClientResp(CPluto& u)
{
    //printf("CWorldCrossclient::onCrossClientResp\n");

    CHECK_AND_GET_RPC_FIELD(u, sid, uint16_t);

    CMailBox* mb = GetServerMailbox(sid);
    //printf("CWorldCrossclient::onCrossClientResp 222, sid=%d;mb=%x\n", sid, mb);
    if(mb)
    {
        //发回给发起调用的那个entity
        CPluto* u2 = new CPluto;
        u2->Encode(MSGID_BASEAPP_ENTITY_RPC) << sid;
        u2->FillBuff(u.GetBuff()+u.GetLen(), u.GetMaxLen()-u.GetLen());
        u2->endPluto();

        mb->PushPluto(u2);
    }

    return 0;
}
Esempio n. 13
0
    //将base/cell共有属性打包
    bool CEntityBase::PickleCellPropsToPluto(CPluto& u1)
    {
        CPluto u;
        const SEntityDef* pDef = this->GetEntityDef();
        if(pDef)
        {
            map<string, _SEntityDefProperties*>::const_iterator iter = pDef->m_properties.begin();
            for(; iter != pDef->m_properties.end(); ++iter)
            {
                _SEntityDefProperties* p = iter->second;
                if(IsCellFlag(p->m_nFlags) && IsBaseFlag(p->m_nFlags))
                {
                    const string& strEntityName = iter->first;
                    map<string, VOBJECT*>::const_iterator iter2 = m_data.find(strEntityName);
                    if(iter2 == m_data.end())
                    {

                        //todo warning...
                        continue;
                    }

                    u << (uint16_t)(pDef->m_propertiesMap.GetIntByStr(iter2->first));
                    u.FillPluto(*(iter2->second));
                }
                else if (IsCellFlag(p->m_nFlags))
                {
                    //如果该属性只有cell才有,则到cellData上查找
                    const string& strEntityName = iter->first;
                    map<string, VOBJECT*>::iterator iter3 = m_cellData.find(strEntityName);

                    if (iter3 != m_cellData.end())
                    {
                        u << (uint16_t)(pDef->m_propertiesMap.GetIntByStr(iter3->first));
                        u.FillPluto(*(iter3->second));
                        m_cellData.erase(iter3);

                        LogDebug("CEntityBase::PickleCellPropsToPluto cellData", "strEntityName=%s", strEntityName.c_str());
                    }
                }
                
            }
            //print_hex_pluto(u);
        }

        charArrayDummy ad;
        ad.m_l = u.GetLen();
        ad.m_s = (char*)u.GetBuff();
        u1 << ad;
        ad.m_l = 0;

        return pDef != NULL;
    }
Esempio n. 14
0
    int CWorldDbmgr::UpdateArrayItemsToDb(T_VECTOR_OBJECT* p, CDbOper& db)
    {
        if( p->size() != 5 )
        {
            return -1;
        }
        const string & itemName = VOBJECT_GET_SSTR((*p)[0]);
        const TDBID dbid = VOBJECT_GET_U64((*p)[1]);
        const uint16_t nBaseappId = VOBJECT_GET_U16((*p)[2]);
        const int32_t ref = VOBJECT_GET_I32((*p)[3]);
        const string& itemsData = VOBJECT_GET_SSTR((*p)[4]);
        //uint32_t l = itemsData.size();

        //LogError("UpdateArrayItemsToDb", "[itemName = %s] [dbid = %d] [nBaseappId = %d] [ref = %d] [itemsData = %d]", 
        //        itemName.c_str(), dbid, nBaseappId, ref, itemsData.size());
        //cout<<itemsData.c_str()<<endl;
        //cout<<itemsData.size()<<endl;
        CPluto* u = new CPluto();
        u->FillBuff(itemsData.c_str(), itemsData.size());
        u->SetMaxLen(u->GetLen());
        string strErr;
        
        //cout<<"world update"<<endl;
        if( !db.UpdateArrayToDb(itemName, dbid, *u, nBaseappId, ref, strErr) )
        {
            LogError("UpdateArrayToDb failure", "[error = %s] [status = %d]", strErr.c_str(), -1);
            CPluto* u1 = new CPluto;
            u1->Encode(MSGID_BASEAPP_UPDATE_ITEMS_CALLBACK);
            *u1 << ref << (uint16_t)1 << strErr<< EndPluto;
            CMailBox* mb = GetServerMailbox(nBaseappId);
            if(mb)
            {
                //cout<<"send pluto"<<endl;
                u1->SetMailbox(mb);

                //LogDebug("CWorldDbmgr::UpdateArrayItemsToDb", "u1.GenLen()=%d", u1->GetLen());

                g_pluto_sendlist.PushPluto(u1);
            }
            else
            {
                delete u1;
                LogWarning("CWorldDbmgr::UpdateArrayItemsToDb", "");
            }
        }

        delete u;

        //cout<<"do success update"<<endl;
        return 0;

    }
Esempio n. 15
0
//转发跨服调用
int CWorldCrossclient::OnCrossServerRpc(CPluto& u)
{
    //跨服服务名
    CHECK_AND_GET_RPC_FIELD(u, strService, string);

    //检查对应的跨服服务器是否已连接
    CMailBox* pmb = ((CCrossclientServer*)GetServer())->GetExternMailbox(strService);
    if(pmb == NULL)
    {
    	//外系统当前不可用,记录日志;返回错误消息也无用
    	LogWarning("CWorldCrossclient::OnCrossServerRpc", "extern error,%s\n", strService.c_str());
    	return 0;
    }

    CPluto* u2 = new CPluto;
    u2->Encode(MSGID_CROSSSERVER_RPC);
    //转发包内容
    u2->FillBuff(u.GetBuff()+u.GetLen(), u.GetMaxLen()-u.GetLen());
    u2->endPluto();
    pmb->PushPluto(u2);

    return 0;
}
Esempio n. 16
0
	int CWorldDbmgr::TableExcute(T_VECTOR_OBJECT* p, CDbOper& db)
	{
		if (p->size() != 3)
		{
			LogError("CWorldDbmgr::TableInsert", "p->size()=%d", p->size());
			return -1;
		}

		uint16_t nBaseappId = VOBJECT_GET_U16((*p)[0]);
		const string& strSql = VOBJECT_GET_SSTR((*p)[1]);
		uint32_t ref = VOBJECT_GET_U32((*p)[2]);

		//LogDebug("CWorldDbmgr::TableExcute", "nBaseappId=%d;ref=%d;strSql=%s",
		//	nBaseappId, ref,  strSql.c_str());

		string strErr;
		uint8_t ret = db.TableExcute(strSql, strErr);

		if(ret != 0)
		{
			LogWarning("ExcuteDB_err", "ret=%d;err=%s", ret, strErr.c_str());
		}
		//ref == 0 无返回
		if (ref == 0)
		{
			return 0;
		}
		
		//通知db结果
		CEpollServer* s = this->GetServer();
		CMailBox* mb = s->GetServerMailbox(nBaseappId);
		if(mb)
		{
#ifdef _WIN32
			mb->RpcCall(GetRpcUtil(), MSGID_BASEAPP_TABLE_EXCUTE_CALLBACK, ref, ret );
#else
			CRpcUtil& rpc = GetRpcUtil();
			CPluto* u = new CPluto;
			rpc.Encode(*u, MSGID_BASEAPP_TABLE_EXCUTE_CALLBACK, ref, ret);
			u->SetMailbox(mb);

			LogDebug("CDbOper::InsertDB", "u.GenLen()=%d", u->GetLen());

			g_pluto_sendlist.PushPluto(u);
#endif
		}
		return 0;
	}
Esempio n. 17
0
	int CWorldDbmgr::TableUpdateBatch(T_VECTOR_OBJECT* p, CDbOper& db)
	{
		LogDebug("CWorldDbmgr::TableUpdateBatch", "");
		if( p->size() != 5 )
		{
			return -1;
		}
		const string & itemName = VOBJECT_GET_SSTR((*p)[0]);
		const string & uniqKey = VOBJECT_GET_SSTR((*p)[1]);
		const uint16_t nBaseappId = VOBJECT_GET_U16((*p)[2]);
		const int32_t ref = VOBJECT_GET_I32((*p)[3]);
		const string& itemsData = VOBJECT_GET_SSTR((*p)[4]);

		//cout<<itemsData.c_str()<<endl;
		//cout<<itemsData.size()<<endl;
		CPluto* u = new CPluto();
		u->FillBuff(itemsData.c_str(), itemsData.size());
		u->SetMaxLen(u->GetLen());
		string strErr;
		int ret = db.UpdateBatch(itemName, uniqKey, *u, nBaseappId, ref, strErr);
		//cout<<"world update"<<endl;
		if( 0 == ret)
		{
			delete u;
            return 0;
		}
		LogError("UpdateArrayToDb failure", "[error = %s] [ret = %d]", strErr.c_str(), ret);
		delete u;
		CPluto* u1 = new CPluto;
		u1->Encode(MSGID_BASEAPP_TABLE_UPDATE_BATCH_CB);
		*u1 << ref << (uint16_t)ret << EndPluto;
		CMailBox* mb = GetServerMailbox(nBaseappId);
		if(mb)
		{
			//cout<<"send pluto"<<endl;
			u1->SetMailbox(mb);

			//LogDebug("CWorldDbmgr::UpdateArrayItemsToDb", "u1.GenLen()=%d", u1->GetLen());

			g_pluto_sendlist.PushPluto(u1);
		}
        else
        {
            delete u1;
            LogWarning("CWorldDbmgr::UpdateArrayItemsToDb", "");
        }
		return -11;
	}
Esempio n. 18
0
    bool random_cell_rpc()
    {
        //远程方法名
        CDefParser& defp = GetWorld()->GetDefParser();
        const SEntityDef* pDef = defp.GetEntityDefByName("Avatar");

        int nMaxFuncId = (int)pDef->m_cellMethods.size();
        int nFunc = rand() % nMaxFuncId;
        const string& strFunc = pDef->m_cellMethodsMap.GetStrByInt(nFunc);

        ostringstream oss;
        oss << strFunc;
        CPluto u;
        u.Encode(MSGID_BASEAPP_CLIENT_RPC2CELL_VIA_BASE) << nFunc;

        //其他参数
        map<string, _SEntityDefMethods*>::const_iterator iter11 = pDef->m_cellMethods.find(strFunc);		
        if(iter11 != pDef->m_cellMethods.end())
        {
            _SEntityDefMethods* pmethod = iter11->second;
            list<VTYPE>::const_iterator iter = pmethod->m_argsType.begin();
            for(; iter != pmethod->m_argsType.end(); ++iter)
            {
                VTYPE vt = *iter;
                string sv;
                switch(vt)
                {
                case V_STR:
                    sv.assign("abcd");
                    break;
                case V_INT8:
                case V_UINT8:
                case V_INT16:
                case V_UINT16:
                case V_INT32:
                case V_UINT32:
                case V_INT64:
                case V_UINT64:
                case V_FLOAT32:
                case V_FLOAT64:
                    sv.assign("14");
                    break;
                case V_BLOB:
                    sv.assign("{}");
                    break;
                default:
                    sv.assign("");
                    break;
                }

                oss << "|" << sv;
                u.FillPlutoFromStr(*iter, sv.c_str(), (unsigned long)sv.size());
            }
        }

        u << EndPluto;

        //发送
        printf("send cell_cmd: %d %s \n", nFunc,  oss.str().c_str());
        //print_hex_pluto(u);
        write_some(u.GetBuff(), u.GetLen());

        //收取回应包
        //async_read_some();
        //CPluto* u2 = read_pluto();
        //delete u2;

        return true;
    }
Esempio n. 19
0
    int CWorldDbmgr::LookupEntityByName(T_VECTOR_OBJECT* p, CDbOper& db)
    {
        if(p->size() != 4)
        {
            return -1;
        }

        uint16_t nBaseappId = VOBJECT_GET_U16((*p)[0]);
        uint8_t nCreateFlag = VOBJECT_GET_U8((*p)[1]);
        const char* pszEntityName = VOBJECT_GET_STR((*p)[2]);
        const char* pszKey = VOBJECT_GET_STR((*p)[3]);

        const string& strKey(pszKey);
        //先查找该key相关的entity是否已经创建出来了
        SEntityLookup* pLookup = LookupEntityInfo(strKey, pszEntityName);
        if(pLookup != NULL)
        {
            //LogInfo("CWorldDbmgr::LookEntityByName", "entity exists;key=%s;eid=%d;baseapp=%d", \
            //        pszKey, pLookup->eid, pLookup->sid);

            CMailBox* mb = GetServerMailbox(pLookup->sid);
            if(mb)
            {
                CPluto* u = new CPluto;
                u->Encode(MSGID_BASEAPP_ENTITY_MULTILOGIN);
                (*u) << pLookup->eid << EndPluto;
                u->SetMailbox(mb);

                //LogDebug("CWorldDbmgr::LookupEntityByName", "u.GenLen()=%d", u->GetLen());

                g_pluto_sendlist.PushPluto(u);
            }

            return 0;
        }

        TENTITYID new_eid = MyGetNextEntityId();
        CPluto* u = new CPluto;
        string strErr;
        if(db.LookupEntityByName(nCreateFlag, pszEntityName, strKey, new_eid, *u, nBaseappId, strErr) != 0)
        {
            delete u;
            //cout << strErr << endl;
            LogWarning("LookEntityByName_err", "%s", strErr.c_str());
            return -2;
        }

        //add for lookup
        CreateNewEntityToLookup(strKey, pszEntityName, new_eid, nBaseappId);

        //通知db结果
        CEpollServer* s = this->GetServer();
        CMailBox* mb = s->GetServerMailbox(nBaseappId);
        if(mb)
        {
#ifdef _WIN32
            mb->RpcCall(*u);
#else
            u->SetMailbox(mb);

            LogDebug("CWorldDbmgr::LookupEntityByName", "u.GenLen()=%d", u->GetLen());

            g_pluto_sendlist.PushPluto(u);
#endif
        }
        else
        {
            LogWarning("CWorldDbmgr::LookupEntityByName", "u.GenLen()=%d", u->GetLen());
            delete u;
        }

        return 0;
    }
Esempio n. 20
0
int lWriteArrayToDb(lua_State* L)
{

    int n  = lua_gettop(L);
    if( n != 4 )
    {
        LogError("lWriteArrayToDb", "Parameters number from lua not enough");
        lua_pop(L, n);
        lua_pushnumber(L, -1);
        return 1;
    }
    if( LUA_TTABLE != lua_type(L, 1) && LUA_TSTRING != lua_type(L, 2) && LUA_TNUMBER != lua_type(L, 3) )
    {
        LogError("Parameters type lua error", "%d", -1);
        lua_pop(L, n);
        lua_pushnumber(L, -1);
        return 1;
    }

    luaL_checkany(L, 4);

    const char* item = lua_tostring(L, 2);
    const string itemName(item);


    const SEntityDef* pDef = GetWorldbase().GetDefParser().GetEntityDefByName(itemName);
    if( !pDef )
    {
        LogError("world:init().error", "%s", "Not the Entitydef");

        lua_pushnumber(L, -1);
        return 1;
    }

    CLuaCallback& cb = GetWorld()->GetCallback();
    int32_t ref = (int32_t)cb.Ref(L);
    TDBID dbid = lua_tonumber(L, 3);

    lua_pop(L, 2);

    uint16_t nBaseappId = GetWorld()->GetMailboxId();
    CPluto *u = new CPluto();
    u->Encode(MSGID_DBMGR_UPDATE_ITEMS);

    *u << itemName << dbid << nBaseappId << ref << (uint16_t)0;


    int i = 1;
    while(true)
    {
        map<string, _SEntityDefProperties*>::const_iterator iter = pDef->m_properties.begin();

        //CPluto *u = new CPluto();
        //cout<<u->GetLen()<<endl;
        //LogDebug("parse table list start", "%d", 1);
        //oss <<"[";
        lua_pushnumber(L, i++);
        lua_gettable(L, -2);
        if( lua_type(L, -1) != LUA_TTABLE )
        {
            break;
        }
        for(; iter != pDef->m_properties.end(); ++iter)
        {

            const _SEntityDefProperties* pProp = iter->second;
            //VOBJECT *v = new VOBJECT();

            if(IsBaseFlag(pProp->m_nFlags) && pProp->m_bSaveDb )
            {
                //cout<<"attribution name = "<<pProp->m_name.c_str()<<endl;
                lua_pushstring(L, pProp->m_name.c_str());

                lua_gettable(L, -2);
                if( lua_type(L, -1) == 0 )
                {
                    LogError("table Item data is not enough", "%s", pProp->m_name.c_str());
                    delete u;
                    u = NULL;

                    cb.Unref(L, ref);

                    lua_pushnumber(L, -1);
                    return 1;
                }
                u->FillPlutoFromLua(pProp->m_nType, L, -1);

                lua_pop(L, 1);
            }
        }
        lua_pop(L, 1);
        //LogDebug("parse table list end", "%d", 1);
    }

    //printf("%d", u->GetLen());

    (*u) << EndPluto;
    // PrintHexPluto(*u);
    //printf("%d, %d", u->GetLen(), itemName.size());
    uint32_t pos = (MSGLEN_TEXT_POS + sizeof(uint16_t) + itemName.size() + 
        sizeof(dbid) + sizeof(nBaseappId) + sizeof(int32_t));
    uint16_t value = (u->GetLen() - pos - sizeof(uint16_t));
    //printf("%d %d", pos, value);
    u->ReplaceField(pos, value);
    //PrintHexPluto(*u);

    CMailBox* mb = GetWorldbase().GetServerMailbox(SERVER_DBMGR);
    if(mb)
    {
        //LogInfo("lWriteArrayToDb", "msg_id = %d, itemName = %s, status = %d", MSGID_DBMGR_UPDATE_ITEMS, itemName.c_str(), 1);
        mb->PushPluto(u);

        lua_pushnumber(L, 0);
        return 1;
    }
    else
    {
        delete u;
        u = NULL;

        cb.Unref(L, ref);

        lua_pushnumber(L, -1);
        return 1;
    }

}
Esempio n. 21
0
int lIncrementalUpdateItems(lua_State* L)
{

    int n  = lua_gettop(L);
    if( n != 4 )
    {
        LogError("lIncrementalUpdateItems", "Parameters number from lua not enough");
        lua_pop(L, n);
        lua_pushnumber(L, -1);
        return 1;
    }
    if( LUA_TTABLE != lua_type(L, 1) && LUA_TSTRING != lua_type(L, 2) && LUA_TSTRING != lua_type(L, 3))
    {
        LogError("Parameters type lua error", "%d", -1);
        lua_pop(L, n);
        lua_pushnumber(L, -1);
        return 1;
    }

    luaL_checkany(L, 4);

    const char* tName = lua_tostring(L, 2);
    const string tblName(tName); //更新的表名字

    const SEntityDef* pDef = GetWorldbase().GetDefParser().GetEntityDefByName(tblName);
    if( !pDef )
    {
        LogError("world:init().error", "%s", "Not the Entitydef");

        lua_pushnumber(L, -1);
        return 1;
    }

    CLuaCallback& cb = GetWorld()->GetCallback();
    int32_t ref = (int32_t)cb.Ref(L);

    const char* oName = lua_tostring(L, 3);
    lua_pop(L, 2);

    const string optName(oName); //操作内型
    uint16_t nBaseappId = GetWorld()->GetMailboxId();

    CPluto *u = new CPluto();
    u->Encode(MSGID_DBMGR_INCREMENTAL_UPDATE_ITEMS);

    *u << tblName << optName << nBaseappId << ref << (uint16_t)0;

    int i = 1;
    while(true)
    {
        map<string, _SEntityDefProperties*>::const_iterator iter = pDef->m_properties.begin();

        lua_pushnumber(L, i++);
        lua_gettable(L, -2);
        if( lua_type(L, -1) != LUA_TTABLE )
        {
            break;
        }

        //独立处理道具的id字段
        lua_pushstring(L, "id");
        lua_gettable(L, -2);
        if( lua_type(L, -1) == LUA_TNIL )
        {
            LogError("table Item data is not enough: ", "%s", "id");
            delete u;
            u = NULL;

            cb.Unref(L, ref);

            lua_pushnumber(L, -1);
            return 1;
        }

        u->FillPlutoFromLua(V_INT64, L, -1);
        lua_pop(L, 1);

        //处理def中存盘字段
        for(; iter != pDef->m_properties.end(); ++iter)
        {
            const _SEntityDefProperties* pProp = iter->second;
            if( IsBaseFlag( pProp->m_nFlags ) && pProp->m_bSaveDb )
            {
                //cout<<"attribution name = "<<pProp->m_name.c_str()<<endl;
                lua_pushstring(L, pProp->m_name.c_str());

                lua_gettable(L, -2);
                if( lua_type(L, -1) == LUA_TNIL )
                {
                    LogError("table Item data is not enough: ", "%s", pProp->m_name.c_str());
                    delete u;
                    u = NULL;

                    cb.Unref(L, ref);

                    lua_pushnumber(L, -1);
                    return 1;
                }
                u->FillPlutoFromLua(pProp->m_nType, L, -1);

                lua_pop(L, 1);
            }
        }
        lua_pop(L, 1);
    }

    (*u) << EndPluto;
    
    uint32_t pos = (MSGLEN_TEXT_POS + sizeof(uint16_t)*2 + tblName.size() + optName.size() + sizeof(nBaseappId) + sizeof(int32_t));
    uint16_t value = (u->GetLen() - pos - sizeof(uint16_t));

    u->ReplaceField(pos, value);
    //PrintHexPluto(*u);

    CMailBox* mb = GetWorldbase().GetServerMailbox(SERVER_DBMGR);
    if(mb)
    {
        mb->PushPluto(u);

        lua_pushnumber(L, 0);
        return 1;
    }
    else
    {
        delete u;
        u = NULL;

        cb.Unref(L, ref);

        lua_pushnumber(L, -1);
        return 1;
    }

}
Esempio n. 22
0
    int CWorldDbmgr::IncremantalUpdateItems(T_VECTOR_OBJECT* p, CDbOper& db)
    {

        if ( p->size() != 5 )
        {
            LogError("CWorldDbmgr::IncremantalUpdateItems", "p->size()=%d", p->size());
            return -1;
        }

        const string & tblName = VOBJECT_GET_SSTR((*p)[0]);
        const string & optName = VOBJECT_GET_SSTR((*p)[1]);
        const uint16_t nBaseappId = VOBJECT_GET_U16((*p)[2]);
        const int32_t  ref = VOBJECT_GET_I32((*p)[3]);
        const string& itemsData = VOBJECT_GET_SSTR((*p)[4]);

        LogDebug("CWorldDbmgr::IncremantalUpdateItems", "tblName=%s;optName=%s;nBaseappId=%d;ref=%d",
            tblName.c_str(), optName.c_str(), nBaseappId, ref);

        CPluto* u = new CPluto();
        u->FillBuff(itemsData.c_str(), itemsData.size());
        u->SetMaxLen(u->GetLen());

        string strErr;
        uint8_t ret = -1;
        if ( optName.compare("update") == 0 )
        {

            ret = db.IncrementalUpdateItems(tblName, nBaseappId, *u, ref, strErr);
            if( ret != 0 )
            {
                CPluto* u1 = new CPluto;
                u1->Encode(MSGID_BASEAPP_UPDATE_ITEMS_CALLBACK);
                *u1 << ref << (uint16_t)1 << strErr<< EndPluto;
                CMailBox* mb = GetServerMailbox(nBaseappId);
                if(mb)
                {
                    u1->SetMailbox(mb);
                    //LogDebug("CWorldDbmgr::IncremantalUpdateItems", "u1.GenLen()=%d", u1->GetLen());
                    g_pluto_sendlist.PushPluto(u1);
                }
                else
                {
                    delete u1;
                    u1 = NULL;
                    LogWarning("CWorldDbmgr::IncremantalUpdateItems", "");
                }
            }
            delete u;
            u = NULL;
            return 0;
        }
        else if( optName.compare("insert") == 0 )
        {

            ret = db.IncremantalInsertItems(tblName, nBaseappId, *u, ref, strErr);
            if( ret != 0 )
            {
                CPluto* u1 = new CPluto;
                u1->Encode(MSGID_BASEAPP_INSERT_ITEMS_CALLBACK);
                *u1 << ref << (uint16_t)1 << strErr<< EndPluto;
                CMailBox* mb = GetServerMailbox(nBaseappId);
                if(mb)
                {
                    u1->SetMailbox(mb);
                    //LogDebug("CWorldDbmgr::IncremantalInsertItems", "u1.GenLen()=%d", u1->GetLen());
                    g_pluto_sendlist.PushPluto(u1);
                }
                else
                {
                    delete u1;
                    u1 = NULL;
                    LogWarning("CWorldDbmgr::IncremantalInsertItems", "");
                }
            }
            delete u;
            u = NULL;
            return 0;
        }
        
    }
Esempio n. 23
0
	SBaseappLoginData* login_account(const char* pszHost, int nPort, const char* pszAccount, const char* pszPasswd)
	{
		printf("try to login account: [ %s : %d ] [ %s ] \n", pszHost, nPort, pszAccount);
		if(this->connect(pszHost, nPort))
		{
			//发送登录包
			CPluto u;
			m_rpc.Encode(u, MSGID_LOGINAPP_LOGIN, pszAccount, pszPasswd);
			write_some(u.GetBuff(), u.GetLen());
		}
		else
		{
			return NULL;
		}

		bool bWait = true;
        int nWaitCount = 0;
		SBaseappLoginData* bd = NULL;
		while(bWait)
		{
			CPluto* u = read_pluto();
			if(u)
			{
				T_VECTOR_OBJECT* p = m_rpc.Decode(*u);
				if(p)
				{
					pluto_msgid_t msgid = u->GetMsgId();
					if(msgid == MSGID_CLIENT_LOGIN_RESP)
					{
						uint8_t nRet = VOBJECT_GET_U8((*p)[0]);
						printf("login ret=%d\n", nRet);
						if(nRet != 0)
						{
							bWait = false;
						}						
					}
					else if(msgid == MSGID_CLIENT_NOTIFY_ATTACH_BASEAPP)
					{
						const char* pszBaseappIp = VOBJECT_GET_STR((*p)[0]);
						uint16_t nBaseappPort = VOBJECT_GET_U16((*p)[1]);
						const char* pszKey = VOBJECT_GET_STR((*p)[2]);

						bd = new SBaseappLoginData;
						bd->m_strBase.assign(pszBaseappIp);
						bd->m_strKey.assign(pszKey);
						bd->m_unPort = nBaseappPort;
						bWait = false;

						printf("redirect to baseapp [ %s : %d ] [ %s ] \n", pszBaseappIp, nBaseappPort, pszKey);

                        //断开到loginapp的连接
                        this->disconnect();
					}
                    else if(msgid == MSGID_CLIENT_NOTIFY_MULTILOGIN)
                    {
                        int a = 0;
                        ++a;
                        printf("mutlilogin, [%s] \n", pszAccount);
                    }
                    else
                    {
                        int a = 0;
                        ++a;
                    }

					ClearTListObject(p);					
				}
				delete u;
			}
            else
            {
                if(++nWaitCount > 3)
                {
                    return NULL;
                }
            }
		}


		return bd;
	}
Esempio n. 24
0
//mogo.UpdateBatchToDb(arrayList, table, uniq, cbF)
int lUpdateBatchToDb(lua_State* L)
{
	int n  = lua_gettop(L);
	if( n != 4 && n != 3)
	{
		LogError("lUpdateBatchToDb", "Parameters number from lua not enough");
		lua_pop(L, n);
		lua_pushnumber(L, 1);
		return 1;
	}
	if( LUA_TTABLE != lua_type(L, 1) || LUA_TSTRING != lua_type(L, 2) || LUA_TSTRING != lua_type(L, 3) )
	{
		LogError("Parameters type lua error", "%d", -1);
		lua_pop(L, n);
		lua_pushnumber(L, 2);
		//lua_pop(L, 2);
		return 1;
	}
	CLuaCallback& cb = GetWorld()->GetCallback();
	int32_t ref = LUA_REFNIL;
	if(n == 4)
	{
		luaL_checkany(L, 4);
		ref = (int32_t)cb.Ref(L);
	}

	//cout<<lua_gettop(L)<<endl;

	const char* pszUniqKey = lua_tostring(L, 3);
	lua_pop(L, 1);
	const string uniqKey(pszUniqKey);

	const char* item = lua_tostring(L, 2);
	lua_pop(L, 1);
	const string itemName(item);
	uint16_t nBaseappId = GetWorld()->GetMailboxId();
	//map<string, map<string, VOBJECT> > items;
	CPluto *u = new CPluto();
	u->Encode(MSGID_DBMGR_UPDATE_BATCH);
	//ostringstream oss;
	*u << itemName << uniqKey << nBaseappId << ref << (uint16_t)0;
	//char str[10240];
	//const string itemName= "Item";
	const SEntityDef* pDef = GetWorldbase().GetDefParser().GetEntityDefByName(itemName);
	if( !pDef )
	{
		LogError("lUpdateBatchToDb", "Not the Entitydef");
		lua_pushnumber(L, 3);
		delete u;
		u = NULL;
		if(LUA_REFNIL != ref)
			cb.Unref(L, ref);

		return 1;
	}

	int i = 1;
	while(true)
	{
		map<string, _SEntityDefProperties*>::const_iterator iter = pDef->m_properties.begin();

		//CPluto *u = new CPluto();
		//cout<<u->GetLen()<<endl;
		//LogDebug("parse table list start", "%d", 1);
		//oss <<"[";
		lua_pushnumber(L, i++);
		lua_gettable(L, -2);
		if( lua_type(L, -1) != LUA_TTABLE )
		{
			break;
		}
		for(; iter != pDef->m_properties.end(); ++iter)
		{

			const _SEntityDefProperties* pProp = iter->second;
			//VOBJECT *v = new VOBJECT();

			if(IsBaseFlag(pProp->m_nFlags))
			{
				//cout<<"attribution name = "<<pProp->m_name.c_str()<<endl;
				lua_pushstring(L, pProp->m_name.c_str());

				lua_gettable(L, -2);
				if( lua_type(L, -1) == LUA_TNIL )
				{
					LogError("lUpdateBatchToDb", "table Item[%s] data is nil. ", pProp->m_name.c_str());
					delete u;
					u = NULL;

					if(LUA_REFNIL != ref)
						cb.Unref(L, ref);

					lua_pushnumber(L, -1);
					return 1;
				}
				u->FillPlutoFromLua(pProp->m_nType, L, -1);

				lua_pop(L, 1);
			}
		}
		lua_pop(L, 1);
		//LogDebug("parse table list end", "%d", 1);

	}

	//printf("%d", u->GetLen());

	(*u) << EndPluto;
	// PrintHexPluto(*u);
	//printf("%d, %d", u->GetLen(), itemName.size());
	//*u << itemName << uniqKey << nBaseappId << ref << (uint16_t)0;
	uint32_t pos = (MSGLEN_TEXT_POS + sizeof(uint16_t) + itemName.size() + sizeof(uint16_t) + uniqKey.size() + sizeof(nBaseappId) + sizeof(int32_t));
	uint16_t value = (u->GetLen() - pos - sizeof(uint16_t));
	//printf("%d %d", pos, value);
	u->ReplaceField(pos, value);
	//PrintHexPluto(*u);

	CMailBox* mb = GetWorldbase().GetServerMailbox(SERVER_DBMGR);
	if(mb)
	{
		//LogInfo("upate items data to db ", "msg_id = %d, itemName = %s, status = %d", MSGID_DBMGR_UPDATE_BATCH, itemName.c_str(), 1);
		mb->PushPluto(u);
		//以下两行为测试数据用
	}
    else
    {
		if(LUA_REFNIL != ref)
			cb.Unref(L, ref);

        delete u;
        u = NULL;
    }
	return 0;
}
Esempio n. 25
0
int BroadcastClientRpc(lua_State* L)
{

    const char* pszEntity = luaL_checkstring(L, 1);
    const char* pszFunc = luaL_checkstring(L, 2);

    world* the_world = GetWorld();
    if (!the_world)
    {
        return 0;
    }

    const SEntityDef* pDef = the_world->GetDefParser().GetEntityDefByName(pszEntity);
    if (!pDef)
    {
        return 0;
    }

    map<string, _SEntityDefMethods*>::const_iterator iter11 = \
        pDef->m_clientMethods.find(pszFunc);
    if(iter11 == pDef->m_clientMethods.end())
    {
        return 0;
    }

    //把pszEntity和pszFunc从堆栈中移除掉
    lua_remove(L, 1);
    lua_remove(L, 1);


    const _SEntityDefMethods* pMethods = iter11->second;
    const list<VTYPE>& args = pMethods->m_argsType;
    int nArgCount = lua_gettop(L);
    if(nArgCount != (int)args.size())
    {
        return 0;
    }

    uint16_t nFuncId = (uint16_t)pDef->m_clientMethodsMap.GetIntByStr(pszFunc);

    CPluto* u = new CPluto;
    u->Encode(MSGID_BASEAPP_BROADCAST_CLIENT_PRC);

    (*u) << the_world->GetDefParser().GetTypeId(pszEntity) << nFuncId;

    //打包rpc的所有参数为一个string
    int idx = 0;
    list<VTYPE>::const_iterator iter = args.begin();
    for(; iter != args.end(); ++iter)
    {
        ++idx;
        VTYPE vt = *iter;
        u->FillPlutoFromLua(vt, L, idx);
    }

    (*u) << EndPluto;

    the_world->GetServer()->AddLocalRpcPluto(u);

    vector<CMailBox*>& mbs = the_world->GetServer()->GetAllServerMbs();
    vector<CMailBox*>::iterator iter2 = mbs.begin();
    for(; iter2 != mbs.end(); ++iter2)
    {
        CMailBox* basemb = *iter2;
        if(basemb && basemb->GetServerMbType() == SERVER_BASEAPP)
        {
            //发给每个其他baseapp的mb的pluto都是发给本地进程的那个pluto的拷贝
            CPluto* u2 = new CPluto(u->GetBuff(), u->GetLen());
            basemb->PushPluto(u2);
        }
    }

    return 0;
}