Jump to content

Recommended Posts

  • Management

Hello,

I've found a bug on the mount system, since I use it as "horse", when you unmount, it follows you.

It happens when unmounting, with the command /ride (CTRL+G).

It crashes here (do_ride):

	if(ch->GetMountingVnumM() != 0)
	{
		CMountSystem* MountSystem = ch->GetMountSystem();
		if(MountSystem != NULL)
		{
			bool MState = MountSystem->IsMounting(ch->GetMountingVnumM());
			if(MState == true)
			{
				MountSystem->Unmount(ch->GetMountingVnumM());
				return;
			}
			else
			{
				do_unmount(ch, NULL, 0, 0);
				if (ch->IsHorseRiding())
				    ch->StopRiding(); 
				MountSystem->Mount(ch->GetMountingVnumM());
				return;
			}
		} 
	}

gdb:

(gdb) bt full
#0  0x082adc1e in boost::unordered_detail::hash_table<boost::unordered_detail::map<unsigned int, boost::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, CMountActor*> > > >::find (
    k=<synthetic pointer>: 1291250540, this=0x4c6a45d4) at ../../../Extern/include/boost/unordered/detail/table.hpp:580
No locals.
#1  boost::unordered_map<unsigned int, CMountActor*, boost::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, CMountActor*> > >::find (k=<synthetic pointer>: 1291250540, this=0x4c6a45d4)
    at ../../../Extern/include/boost/unordered/unordered_map.hpp:428
No locals.
#2  CMountSystem::GetByVnum (vnum=1291250540, this=0x4c6a45d0) at MountSystem.cpp:515
        MountActor = 0x0
        iter = <optimized out>
#3  CMountSystem::IsMounting (this=this@entry=0x4c6a45d0, mobVnum=1291250540) at MountSystem.cpp:447
        MountActor = 0x0
#4  0x080f3295 in do_ride (ch=0x4cf6abc0, argument=0xffff8e5f "", cmd=228, subcmd=0) at cmd_general.cpp:4626
        MState = <optimized out>
        __FUNCTION__ = "do_ride"
#5  0x080e99b2 in interpret_command (ch=ch@entry=0x4cf6abc0, argument=argument@entry=0xffff980f "ride", len=len@entry=4) at cmd.cpp:930
        __FUNCTION__ = "interpret_command"
        cmd = "ride\000\000\001\000\000\000\001\000\000\000(\216\377\377N:9\bD!]L\250\r\234L\000\000\000\000\370\r\234L\000\000\000\000\021\000\000\000\344\027J\b\b\000\000\000\000\000\000\000\a\000\000\000\b\000\000\000\b\000\000\000\340\226\373L\030!]L\270\216\377\377\n\n&\b\000!]L\004\000\000\000\370\r\234L\000\000\000\000\001\000\000\000\021\000\000\000H!]Lx\216\377\377t\216\377\377H!]Lt\216\377"
        new_line = "ride\000\374\r\234Lp\216\377\377\004\000\000\000\000\000\000\000\227\310PKT)V\356KP\310\227\370\r\234L\b\000\000\000\260\r\234L\310\216\377\377i\325\063\b@!]L\250\r\234L\000\000\000\000\370\r\234L\364\226\373L\000\000\000\000\000\000\000\000\b\000\000\000\001\000\000\000\370\377\377\377\000\000\000\000\350\000\000\000\001\000\000\000\001\000\000\000\b\217\377\377N:9\bD!]L\250\r\234L\000\000\000\000\370\r\234L\000\000\000\000\021\000\000\000\344\027J\b\b\000\000\000\000\000\000\000\a\000\000\000\b\000\000\000\b\000\000\000\370\226\373L\030!]L\230\217\377\377\n\n&\b\000!]L\004\000\000\000\343\251\223(\000\000\000\000\001\000\000\000"...
        icmd = 228
        cmdlen = 4
#6  0x081799cb in CInputMain::Chat (this=0x4c998e9c, ch=ch@entry=0x4cf6abc0, data=data@entry=0x4cfd9680 "\003\n", uiBytes=11) at input_main.cpp:830
        pinfo = 0x4cfd9680
        buf = "/ride\000\260\231\377\377\334h\225(\002\000\000\000x\231\377\377\322\033\224(\002\000\000\000\334h\225(x\232\377\377\343\311\215(\220\232\377\377|\231\377\377\334h\225(\377\377\377\377\002\000\000\000v\231\377\377\000\000\000\000\377\377\377\377\000\000\000\000\002\000\000\000\001\000\000\000\000\000\000\000\022\000\000\000\001\000\000\000\001\000\000\000\002\000\000\000\200\000\000\000\001\000\000\000\002\000\000\000\001\000\000\000\000\000\000\000\001\000\000\000\001\000\000\000\002\000\000\000\001\000\000\000\260\310\224(\001\000\000\000\002\000\000\000\001\000\000\000\001\000\000\000\000\000\000\000\200*j\b\350\233\377\377\000\000\000\000\001\000\000\000\002\000\000\000\001\000\000\000\372\326\377N\000\000\000\000\200*"...
        chatbuf = "\000\000\001\000\000\000\001\000\000\000\030\000\000\000\001\000\000\000\260\310\224(\001\000\000\000\004\000\000\000\001", '\000' <repeats 11 times>, "\200*j\b(\235\377\377\000\000\000\000\000\000\000\000\200*j\bH\235\377\377\000\000\000\000\000\000\000\000\200*j\bH\235\377\377\000\000\000\000\000\000\000\000\200*j\000D\235\377\377\000\000\000\000\367\000\277\374\024\216\376\000L\235\377\377<\302\257\304\310\000]L@\000\000\000\346\307W\202\205\311-\352q\000\334\027&\315\263\000\064\236\377\377\200*j\b\220\232\377\377\334h\225(\250\233\377\377\030i\222(\220\232\377\377\274\211\225(\316\033\224(\350\233\377\377\372\233\377\377\000\000\000\000\375\377\377\177\b\002\377\377\370\233"...
        iExtraLen = 6
        __FUNCTION__ = "Chat"
        pAffect = <optimized out>
        nNome = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x38 <error: Cannot access memory at address 0x38>}}
        buflen = 5
        len = <optimized out>
        pack_chat = {header = 0 '\000', size = 0, type = 0 '\000', id = 256, bEmpire = 0 '\000'}
#7  0x0817ae85 in CInputMain::Analyze (this=0x4c998e9c, d=0x4c998e00, bHeader=3 '\003', c_pData=0x4cfd9680 "\003\n") at input_main.cpp:3840
        __FUNCTION__ = "Analyze"
        iExtraLen = 0
#8  0x0815f09a in CInputProcessor::Process (this=0x4c998e9c, lpDesc=0x4c998e00, c_pvOrig=<optimized out>, r_iBytesProceed=@0xffffa3f8: 0, iBytes=<optimized out>) at input.cpp:114
        iExtraPacketSize = <optimized out>
        bHeader = 3 '\003'
        c_pszName = 0x4cfaa10c "Chat"
        bLastHeader = <optimized out>
        iLastPacketLen = <optimized out>
        iPacketLen = 5
        c_pData = 0x4cfd9680 "\003\n"
#9  0x081247e9 in DESC::ProcessInput (this=this@entry=0x4c998e00) at desc.cpp:313
        iBytesProceed = 0
        bytes_read = 11
        __FUNCTION__ = "ProcessInput"
#10 0x082c52d4 in io_loop (fdw=0x28cf62e0) at main.cpp:1185
        iRet = <optimized out>
        d = 0x4c998e00
        num_events = 4
        event_idx = 3
        __FUNCTION__ = "io_loop"
#11 0x082c5557 in idle () at main.cpp:1062
        pta = {tv_sec = 1532296067, tv_usec = 21324}
---Type <return> to continue, or q <return> to quit---

This is the system (in case anyone need it): 

This is the hidden content, please

Thank you all

  • Metin2 Dev 7
  • Smile Tear 1
  • Good 2
  • Love 1

raw

raw

Link to comment
https://metin2.dev/topic/19079-mount-system-like-horse-crashes-core/
Share on other sites

  • Management
12 minutes ago, WeedHex said:

        MountActor = 0x0

It's the reason of the crash.

Ok, but what does that mean?

How can I solve it?

Thanks for your answer.

raw

raw

  • Premium
void CMountSystem::Unmount(DWORD mobVnum)
void CMountSystem::Mount(DWORD mobVnum, LPITEM mountItem)

Under

CMountActor* mountActor = this->GetByVnum(mobVnum);

You should have something like

if (mountActor == NULL)
	return;

 

  • Management
3 hours ago, Dobrescu Sebastian said:

void CMountSystem::Unmount(DWORD mobVnum)
void CMountSystem::Mount(DWORD mobVnum, LPITEM mountItem)

Under


CMountActor* mountActor = this->GetByVnum(mobVnum);

You should have something like


if (mountActor == NULL)
	return;

 

I don't have such functions...

Here my MountSystem.h:

#ifndef	__HEADER_MOUNT_SYSTEM__
#define	__HEADER_MOUNT_SYSTEM__
       
#include <boost/unordered_map.hpp>
#include <algorithm>
  
class CHARACTER;

 
class CMountActor
{
	protected:
		friend class CMountSystem;
		CMountActor(LPCHARACTER owner, DWORD vnum);
		
		virtual ~CMountActor();
		virtual bool	Update(DWORD deltaTime);
		
	protected:
		virtual bool	_UpdateFollowAI();
		virtual bool	_UpdatAloneActionAI(float fMinDist, float fMaxDist);
		
	private:
		bool Follow(float fMinDistance = 50.f);
		
	public:
		LPCHARACTER		GetCharacter()	const					{ return m_pkCharacter; }
		LPCHARACTER		GetOwner()	const						{ return m_pkOwner; }
		DWORD			GetVnum() const							{ return m_dwVnum; }
		DWORD			GetVID() const							{ return m_dwVID; }
		
		void			SetName(const char* MountName);
		DWORD			Mount();
		DWORD			Unmount();

		DWORD			Summon(const char* MounName, DWORD mobVnum);
		void			Unsummon();

		bool			IsSummoned() const { return 0 != m_pkCharacter; }
		bool			IsMounting() const { return m_dwMounted; }
	
		void			UpdateTime();

	private:
		DWORD			m_dwVnum;
		DWORD			m_dwVID;
		DWORD			m_dwLastActionTime;
		DWORD			m_dwUpdatePeriod;
		DWORD			m_dwLastUpdateTime;
		short			m_OMoveSpeed;
		bool			m_dwMounted;
		std::string		m_Name;

		LPCHARACTER		m_pkCharacter;
		LPCHARACTER		m_pkOwner;
};

class CMountSystem
{
	public:
		typedef	boost::unordered_map<DWORD,	CMountActor*>		TMountActorMap;
		

	public:
		CMountSystem(LPCHARACTER owner);
		virtual ~CMountSystem();

		CMountActor*	GetByVID(DWORD vid) const;
		CMountActor*	GetByVnum(DWORD vnum) const;

		bool		Update(DWORD deltaTime);
		void		Destroy();

		size_t		CountSummoned() const;

	public:
		void		SetUpdatePeriod(DWORD ms);

		CMountActor*	Summon(DWORD mobVnum, const char* MountName);
		CMountActor*	Mount(DWORD mobVnum);
		CMountActor*	Unmount(DWORD mobVnum);
		
		void		Unsummon(DWORD mobVnum, bool bDeleteFromList = false);
		void		Unsummon(CMountActor* MountActor, bool bDeleteFromList = false);

		CMountActor* 	Mount(DWORD mobVnum, const char* MountName);
		
		void		DeleteMount(DWORD mobVnum);
		void		DeleteMount(CMountActor* MountActor);
		bool		IsActiveMount();
		bool		IsMounting(DWORD mobVnum);
		void		UpdateTime();
	
	private:
		TMountActorMap	m_MountActorMap;
		LPCHARACTER		m_pkOwner;	
		
		DWORD			m_dwUpdatePeriod;
		DWORD			m_dwLastUpdateTime;
		LPEVENT			m_pkMountSystemUpdateEvent;
};

#endif

On the debug is mentioned this function:

CMountActor* CMountSystem::GetByVnum(DWORD vnum) const
{
	CMountActor* MountActor = 0;

	TMountActorMap::const_iterator iter = m_MountActorMap.find(vnum);

	if (m_MountActorMap.end() != iter)
		MountActor = iter->second;

	return MountActor;
}

This is only breaking on non-MountSystem mounts, on the mounts configured on the mounting system quest for this system it works fine.

Thanks for your answer

raw

raw

  • Management
3 hours ago, Chyu ^^ said:

What about this?
image.png.19a81f698266958535f2585e080cebfa.png
 

I didn't understand it was to change to void, I thought he had those functions, and I didn't saw them...

 

But, anyway, I believe I solved it...

The command do_ride:

ACMD(do_ride)
{
    dev_log(LOG_DEB0, "[DO_RIDE] start");
    if (ch->IsDead() || ch->IsStun())
		return;

#ifdef DEATHMATCH_MODE
	if (ch->GetMapIndex() == DEATMATCH_MAP_INDEX)
		return;
#endif

	if(ch->GetMountingVnumM() != 0)
	{
		CMountSystem* MountSystem = ch->GetMountSystem();
		if(MountSystem != NULL)
		{
			bool MState = MountSystem->IsMounting(ch->GetMountingVnumM());
			if(MState == true)
			{
				MountSystem->Unmount(ch->GetMountingVnumM());
				return;
			}
			else
			{
				do_unmount(ch, NULL, 0, 0);
				if (ch->IsHorseRiding())
				    ch->StopRiding(); 
				MountSystem->Mount(ch->GetMountingVnumM());
				return;
			}
		} 
	}

    // ³»¸®±â
    {
	if (ch->IsHorseRiding())
	{
	    dev_log(LOG_DEB0, "[DO_RIDE] stop riding");
	    ch->StopRiding(); 
	    return;
	}

	if (ch->GetMountVnum())
	{
	    dev_log(LOG_DEB0, "[DO_RIDE] unmount");
	    do_unmount(ch, NULL, 0, 0);
	    return;
	}
    }

    // Ÿ±â
    {
		if (ch->GetHorse() != NULL)
		{
			dev_log(LOG_DEB0, "[DO_RIDE] start riding");
			ch->StartRiding();
			return;
		}
#ifdef ENABLE_INVENTORY_12_PAGES
		for (UINT i=0; i<INVENTORY_MAX_NUM; ++i)  	
#else
		for (BYTE i=0; i<INVENTORY_MAX_NUM; ++i)
#endif
		{
			LPITEM item = ch->GetInventoryItem(i);
			if (NULL == item)
			continue;

			// À¯´ÏÅ© Å»°Í ¾ÆÀÌÅÛ
			if (item->IsRideItem())
			{
				if (NULL==ch->GetWear(WEAR_UNIQUE1) || NULL==ch->GetWear(WEAR_UNIQUE2) || NULL==ch->GetWear(WEAR_COSTUME_MOUNT))
				{
					dev_log(LOG_DEB0, "[DO_RIDE] USE UNIQUE ITEM");
					//ch->EquipItem(item);
					ch->UseItem(TItemPos (INVENTORY, i));
					return;
				}
			}

			// ÀÏ¹Ý Å»°Í ¾ÆÀÌÅÛ
			// TODO : Å»°Í¿ë SubType Ãß°¡
			switch (item->GetVnum())
			{
			case 71114:	// Àú½ÅÀÌ¿ë±Ç
			case 71116:	// »ê°ß½ÅÀÌ¿ë±Ç
			case 71118:	// ÅõÁö¹üÀÌ¿ë±Ç
			case 71120:	// »çÀÚ¿ÕÀÌ¿ë±Ç
				dev_log(LOG_DEB0, "[DO_RIDE] USE QUEST ITEM");
				ch->UseItem(TItemPos (INVENTORY, i));
				return;
			}

			// GF mantis #113524, 52001~52090 ¹ø Å»°Í
			if( (item->GetVnum() > 52000) && (item->GetVnum() < 52091) )	{
				dev_log(LOG_DEB0, "[DO_RIDE] USE QUEST ITEM");
				ch->UseItem(TItemPos (INVENTORY, i));
				return;
			}
		}
    }


    // Ÿ°Å³ª ³»¸± ¼ö ¾øÀ»¶§
    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¸»À» ¸ÕÀú ¼ÒÈ¯ÇØÁÖ¼¼¿ä."));
}

The function 

if(ch->GetMountingVnumM() != 0)

Was always getting passed by, it was never 0, I don't know why, maybe some garbage in memory, I don't know...

There's this code in char.h

#ifdef ENABLE_MOUNT_SYSTEM
		////////////////////////////////
		// Mount system
	public:
		void SetMountingM(bool bValue) { bMounting = bValue; }
		bool GetMountVnumM() { return bMounting; }
		DWORD GetMountingVnumM() const { return bMountVnumM; }
		void SetMountVnumM(DWORD bVnum) { bMountVnumM = bVnum; }
		
	private:
		bool bMounting;
		DWORD bMountVnumM;
	
#endif

I just set the return value to 0 by default

DWORD bMountVnumM = 0;

With this, I can use the CTRL+G shortcut to unmount in every mount, since the variable is 0, it won't enter the if statement...

In the other hand, the mount system with the quest function Mount.summon the variable will be programmatically filled with the mount vnum, and be set to 0 with unsummon.

 

With this the server didn't crash, but I'll ask my team to test it better, but so far there's no problem...

raw

raw

  • Management
48 minutes ago, Dobrescu Sebastian said:

God! You have to search what i told you in MountSystem.cpp

I did that, but the functions you mentioned aren't void, so only using the return wouldn't help... That's why I supposed I had to changed them to void, but didn't help...

raw

raw

  • Premium

syncIsg.jpg

If yours its DWORD and not a void make yourself just a chek for nullpointer.

Instead a return you can make something like

CMountActor* mountActor = this->GetByVnum(mobVnum);

if (mountActor)
{
	you put here all the code line.
}

@Chyu ^^ The point it's not to change to void it's to check if the function blocks the nullpointers.  You genius. My source code is different than his, I have void. What a big deal. Got it ?

First of all it matters also the rest of the functions and the quest to be written in the correct way, because first of all it doesn't have to reach to a null pointer situation, but even with all possible checks, a null pointer will appear and he must have check for them.

 

Edited by Metin2 Dev
Core X - External 2 Internal
  • Management
47 minutes ago, Dobrescu Sebastian said:

syncIsg.jpg

If yours its DWORD and not a void make yourself just a chek for nullpointer.

Instead a return you can make something like


CMountActor* mountActor = this->GetByVnum(mobVnum);

if (mountActor)
{
	you put here all the code line.
}

@Chyu ^^ The point it's not to change to void it's to check if the function blocks the nullpointers.  You genius. My source code is different than his, I have void. What a big deal. Got it ?

First of all it matters also the rest of the functions and the quest to be written in the correct way, because first of all it doesn't have to reach to a null pointer situation, but even with all possible checks, a null pointer will appear and he must have check for them.

 

It was getting to a nullpointer because it wasn't detecting other mounts besides the ones being summoned by the Mount System (like horse, to follow you), the function was always returning something else different from 0, so it was always getting inside the if statement, but there was no actor defined by the quest function, so it would crash on null actor...

Edited by Metin2 Dev
Core X - External 2 Internal

raw

raw

  • Premium
Acum 19 minute, charparodar a spus:

It was getting to a nullpointer because it wasn't detecting other mounts besides the ones being summoned by the Mount System (like horse, to follow you), the function was always returning something else different from 0, so it was always getting inside the if statement, but there was no actor defined by the quest function, so it would crash on null actor...

Yes, but do a check to not do anything if there is a nullpointer, because it can happen accidentally when you have many players on. (from my experience) I gave you a model.

  • Management
Just now, Dobrescu Sebastian said:

Yes, but do a check to not do anything if there is a nullpointer, because it can happen accidentally when you have many players on. (from my experience) I gave you a model.

Yes, but how can I return a nullpointer when the function has CMountActor* type? I have to return a CMountActor*, but how do I return null?

raw

raw

  • Premium
Acum 1 minut, charparodar a spus:

Yes, but how can I return a nullpointer when the function has CMountActor* type? I have to return a CMountActor*, but how do I return null?

You just put a condition like

if (mountActor)
{
	you put here all the code line.
}

So this way the code will be executed only if mountActor exists.

if (mountActor) its the same as if (mountActor !=null) or if (mountActor != 0)

  • Love 1
  • Management
Just now, Dobrescu Sebastian said:

You just put a condition like


if (mountActor)
{
	you put here all the code line.
}

So this way the code will be executed only if mountActor exists.

But if I put everything inside that code I'll get an error that not every code returns a value, right?

The function is like this, at the moment:

CMountActor* CMountSystem::Mount(DWORD mobVnum)
{
	CMountActor* MountActor = this->GetByVnum(mobVnum);
	DWORD MountVID = MountActor->Mount();
	return MountActor;
}

CMountActor* CMountSystem::Unmount(DWORD mobVnum)
{
	CMountActor* MountActor = this->GetByVnum(mobVnum);
	DWORD MountVID = MountActor->Unmount();
	return MountActor;
}

If I put it like this will it do the same?

CMountActor* CMountSystem::Mount(DWORD mobVnum)
{
	CMountActor* MountActor = this->GetByVnum(mobVnum);
	
	if(MountActor)
		DWORD MountVID = MountActor->Mount();
	
	return MountActor;
}

CMountActor* CMountSystem::Unmount(DWORD mobVnum)
{
	CMountActor* MountActor = this->GetByVnum(mobVnum);
	
	if(MountActor)
		DWORD MountVID = MountActor->Unmount();
	
	return MountActor;
}

 

raw

raw

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.