Jump to content

Recommended Posts

Hello, does anyone have an auto-pickup system for pets? I used this system, but when I summon the pet, the server crashes.

 

The compilation was successful, but the sysser didn’t clearly show the reason why the server crashed.

I should mention that I have correctly added the code with proper tabbing and well-aligned functions.

 

Edit , in Channel 1 / game2 appear game.core with 302.000 kb when i call pet

 

In service.h add :
				#define __PET_PICKUP
None
In PetSystem.h search :
void			SetSummonItem (LPITEM pItem);
None
Adaugi mai jos :
#ifdef __PET_PICKUP
						void			PickUpItems(int range);
						void			BringItem();
						void			SetPickup(bool is_pickup) { m_is_pickup = is_pickup; }
						bool			IsPickup(){ return m_is_pickup; }
						void			SetPickupItem(LPITEM item) { m_pickup_item = item; }
						LPITEM			GetPickupItem(){ return m_pickup_item; }
				#endif
None
Search :
LPCHARACTER		m_pkOwner;
None
Adaugi mai jos :
#ifdef __PET_PICKUP
			bool			m_is_pickup;
			LPITEM			m_pickup_item;
			#endif
None
In char.h search :
bool			PickupItem(DWORD vid);
None
add under :
#ifdef __PET_PICKUP
						bool			PickupItemByPet(DWORD vid);
						
				#endif
None
In char_item.cpp search :
bool CHARACTER::PickupItem(DWORD dwVID)
None
Adaugi sus :
#ifdef __PET_PICKUP
			bool CHARACTER::PickupItemByPet(DWORD dwVID)
			{
				LPITEM item = ITEM_MANAGER::instance().FindByVID(dwVID);
				if (IsObserverMode())
					return false;
				if (!item || !item->GetSectree())
					return false;
				if (item->IsOwnership(this))
				{
					if (item->GetType() == ITEM_ELK)
					{
						GiveGold(item->GetCount());
						item->RemoveFromGround();

						M2_DESTROY_ITEM(item);
						Save();
					}
					else
					{
						if (item->IsStackable() && !IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
						{
							BYTE bCount = item->GetCount();

							for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
							{
								LPITEM item2 = GetInventoryItem(i);

								if (!item2)
									continue;

								if (item2->GetVnum() == item->GetVnum())
								{
									int j;

									for (j = 0; j < ITEM_SOCKET_MAX_NUM; ++j)
									if (item2->GetSocket(j) != item->GetSocket(j))
										break;

									if (j != ITEM_SOCKET_MAX_NUM)
										continue;

									BYTE bCount2 = MIN(200 - item2->GetCount(), bCount);
									bCount -= bCount2;

									item2->SetCount(item2->GetCount() + bCount2);

									if (bCount == 0)
									{
										ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¾ÆÀÌÅÛ È¹µæ: %s"), item2->GetName());
										M2_DESTROY_ITEM(item);
										if (item2->GetType() == ITEM_QUEST)
											quest::CQuestManager::instance().PickupItem(GetPlayerID(), item2);
										return true;
									}
								}
							}

							item->SetCount(bCount);
						}

						int iEmptyCell;
						if (item->IsDragonSoul())
						{
							if ((iEmptyCell = GetEmptyDragonSoulInventory(item)) == -1)
							{
								sys_log(0, "No empty ds inventory pid %u size 
 itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
								ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¼ÒÁöÇϰí ÀÖ´Â ¾ÆÀÌÅÛÀÌ ³Ê¹« ¸¹½À´Ï´Ù."));
								return false;
							}
						}
						else
						{
							if ((iEmptyCell = GetEmptyInventory(item->GetSize())) == -1)
							{
								sys_log(0, "No empty inventory pid %u size 
 itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
								ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¼ÒÁöÇϰí ÀÖ´Â ¾ÆÀÌÅÛÀÌ ³Ê¹« ¸¹½À´Ï´Ù."));
								return false;
							}
						}

						item->RemoveFromGround();

						if (item->IsDragonSoul())
							item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
						else
							item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));

						char szHint[32 + 1];
						snprintf(szHint, sizeof(szHint), "%s %u %u", item->GetName(), item->GetCount(), item->GetOriginalVnum());
						LogManager::instance().ItemLog(this, item, "GET", szHint);
						ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¾ÆÀÌÅÛ È¹µæ: %s"), item->GetName());

						if (item->GetType() == ITEM_QUEST)
							quest::CQuestManager::instance().PickupItem(GetPlayerID(), item);
					}
					//Motion(MOTION_PICKUP);
					return true;
				}

				return false;
			}
			#endif
None
In PetSystem.cpp cauți :
bool CPetActor::Follow(float fMinDistance)
None
Adaugi sus :
#ifdef __PET_PICKUP
				struct PetPickUpItemStruct
				{
					CPetActor * pet;
					int range;
					PetPickUpItemStruct(CPetActor * p, int r){

						pet = p;
						range = r;
					}
					void operator()(LPENTITY pEnt)
					{
						if (!pet->GetOwner() || !pet->GetCharacter())
							return;
						if (pet->IsPickup())
							return;
						if (pEnt->IsType(ENTITY_ITEM) == true)
						{
							
							LPITEM item = (LPITEM)pEnt;
							LPCHARACTER player = pet->GetOwner();
							if (!item->GetSectree() || !item->IsOwnership(player))
								return;

							int iDist = DISTANCE_APPROX(item->GetX() - player->GetX(), player->GetY() - player->GetY());

							if (iDist > range)
								return;
							pet->SetPickup(true);
							pet->SetPickupItem(item);
						}

					}
				};
				void CPetActor::PickUpItems(int range){
					if (IsPickup())
						return;
					long map = m_pkChar->GetMapIndex();
					PIXEL_POSITION m = m_pkChar->GetXYZ();
					LPSECTREE tree = SECTREE_MANAGER::instance().Get(map, m.x, m.y);
					if (!tree)
					{
						sys_err("cannot find sectree by %dx%d", m.x, m.y);
						return;
					}
					PetPickUpItemStruct f(this, range);
					tree->ForEachAround(f);
				}

				void CPetActor::BringItem(){
					if (!IsPickup())
						return;
					LPITEM item = GetPickupItem();
					if (!m_pkOwner || !m_pkChar || !item || !item->GetSectree())
						return;
					
					float fMinDistance = 20.0;
					float fPetX = m_pkChar->GetX();
					float fPetY = m_pkChar->GetY();

					float itemX = item->GetX();
					float itemY = item->GetY();

					float fDist = DISTANCE_SQRT(itemX - fPetX, itemY - fPetY);
					if (fDist <= 250.0)
					{
						SetPickup(false);
						m_pkOwner->PickupItemByPet(item->GetVID());
						SetPickupItem(NULL);
						m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);
						return;
					}
					m_pkChar->SetRotationToXY(itemX, itemY);
					float fx, fy;

					float fDistToGo = fDist - fMinDistance;
					GetDeltaByDegree(m_pkChar->GetRotation(), fDistToGo, &fx, &fy);

					if (!m_pkChar->Goto((int)(fPetX + fx + 0.5f), (int)(fPetY + fy + 0.5f)))
						return;

					m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);
				}
				#endif
None
Cauta :
if (this->IsSummoned() && HasOption(EPetOption_Followable))
None
Adaugi sus :
#ifdef __PET_PICKUP
				if (this->IsSummoned()){
					this->BringItem();
					this->PickUpItems(900); // 900 = RANGE
				}	
			#endif
None
Cauți :
this->SetSummonItem(NULL);
None
Add below :
#ifdef __PET_PICKUP
				this->SetPickupItem(NULL);
				this->SetPickup(false);
		#endif
None
Cauți :
m_dwSummonItemVID = 0;
		m_dwSummonItemVnum = 0;
None
Adaugi mai jos :
#ifdef __PET_PICKUP
				this->SetPickupItem(NULL);
				this->SetPickup(false);
		#endif

 

Edited by DakaSenpai99
Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/
Share on other sites

  • Replies 9
  • Created
  • Last Reply

Top Posters In This Topic

I got just this

 

Address not mapped to object.
--Type <RET> for more, q to quit, c to continue without paging--bt
#0  0x005956b6 in CPetActor::BringItem (this=0x333b8480) at PetSystem.cpp:397
397     PetSystem.cpp: No such file or directory.
[Current thread is 1 (LWP 100083)]

Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-166473
Share on other sites

On 8/9/2024 at 9:27 PM, DakaSenpai99 said:

I got just this

 

Address not mapped to object.
--Type <RET> for more, q to quit, c to continue without paging--bt
#0  0x005956b6 in CPetActor::BringItem (this=0x333b8480) at PetSystem.cpp:397
397     PetSystem.cpp: No such file or directory.
[Current thread is 1 (LWP 100083)]

And whats on that line? Can you put your petsystem.cpp here or via pastebin?

Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-166498
Share on other sites

Here, i think the he Value 0x4008002 of Item is corupted of invalid:

(gdb) print m_pkOwner
$1 = (LPCHARACTER) 0x39220000
(gdb) print m_pkChar
$2 = (LPCHARACTER) 0x39223000
(gdb) print item
$3 = (LPITEM) 0x4008002
(gdb) print item->GetSectree()
Cannot evaluate function -- may be inlined

 

Here it s Pet System.cpp

 

#include "stdafx.h"
#include "utils.h"
#include "vector.h"
#include "char.h"
#include "sectree_manager.h"
#include "char_manager.h"
#include "mob_manager.h"
#include "PetSystem.h"
#include "../../common/VnumHelper.h"
#include "packet.h"
#include "item_manager.h"
#include "item.h"


extern int passes_per_sec;
EVENTINFO(petsystem_event_info)
{
	CPetSystem* pPetSystem;
};

// PetSystemŔ» update ÇŘÁÖ´Â event.
// PetSystemŔş CHRACTER_MANAGERżˇĽ­ ±âÁ¸ FSMŔ¸·Î update ÇŘÁÖ´Â ±âÁ¸ chractersżÍ ´Ţ¸®,
// OwnerŔÇ STATE¸¦ update ÇŇ ¶§ _UpdateFollowAI ÇÔĽö·Î update ÇŘÁŘ´Ů.
// ±×·±µĄ ownerŔÇ state¸¦ update¸¦ CHRACTER_MANAGERżˇĽ­ ÇŘÁֱ⠶§ą®żˇ,
// petsystemŔ» updateÇϴٰˇ petŔ» unsummonÇĎ´Â şÎşĐżˇĽ­ ą®Á¦°ˇ »ý°ĺ´Ů.
// (CHRACTER_MANAGERżˇĽ­ update Çϸé chracter destroy°ˇ pendingµÇľî, CPetSystemżˇĽ­´Â dangling Ć÷ŔÎĹ͸¦ °ˇÁö°í ŔÖ°Ô µČ´Ů.)
// µű¶óĽ­ PetSystem¸¸ ľ÷µĄŔĚĆ® ÇŘÁÖ´Â event¸¦ ąß»ý˝ĂĹ´.
EVENTFUNC(petsystem_update_event)
{
	petsystem_event_info* info = dynamic_cast<petsystem_event_info*>( event->info );
	if ( info == NULL )
	{
		sys_err( "check_speedhack_event> <Factor> Null pointer" );
		return 0;
	}

	CPetSystem*	pPetSystem = info->pPetSystem;

	if (NULL == pPetSystem)
		return 0;

	
	pPetSystem->Update(0);
	// 0.25Ăʸ¶´Ů °»˝Ĺ.
	return PASSES_PER_SEC(1) / 4;
}

/// NOTE: 1Äł¸ŻĹͰˇ ¸î°łŔÇ ĆęŔ» °ˇÁú Ľö ŔÖ´ÂÁö Á¦ÇŃ... Äł¸ŻĹ͸¶´Ů °łĽö¸¦ ´Ů¸Ł°Ô ÇҰŶó¸é şŻĽö·Î łÖµî°ˇ... Ŕ˝..
/// °ˇÁú Ľö ŔÖ´Â °łĽöżÍ µż˝Ăżˇ ĽŇČŻÇŇ Ľö ŔÖ´Â °łĽö°ˇ Ʋ¸± Ľö ŔִµĄ ŔĚ·±°Ç ±âČą ľřŔ¸´Ď ŔĎ´Ü ą«˝Ă
const float PET_COUNT_LIMIT = 3;

///////////////////////////////////////////////////////////////////////////////////////
//  CPetActor
///////////////////////////////////////////////////////////////////////////////////////

CPetActor::CPetActor(LPCHARACTER owner, DWORD vnum, DWORD options)
{
	m_dwVnum = vnum;
	m_dwVID = 0;
	m_dwOptions = options;
	m_dwLastActionTime = 0;

	m_pkChar = 0;
	m_pkOwner = owner;

	m_originalMoveSpeed = 0;
	
	m_dwSummonItemVID = 0;
	m_dwSummonItemVnum = 0;
}

CPetActor::~CPetActor()
{
	this->Unsummon();

	m_pkOwner = 0;
}

void CPetActor::SetName(const char* name)
{
	std::string petName = m_pkOwner->GetName();

	if (0 != m_pkOwner && 
		0 == name && 
		0 != m_pkOwner->GetName())
	{
		petName += "'s Pet";
	}
	else
		petName += name;

	if (true == IsSummoned())
		m_pkChar->SetName(petName);

	m_name = petName;
}

bool CPetActor::Mount()
{
	if (0 == m_pkOwner)
		return false;

	if (true == HasOption(EPetOption_Mountable))
		m_pkOwner->MountVnum(m_dwVnum);

	return m_pkOwner->GetMountVnum() == m_dwVnum;;
}

void CPetActor::Unmount()
{
	if (0 == m_pkOwner)
		return;

	if (m_pkOwner->IsHorseRiding())
		m_pkOwner->StopRiding();
}

void CPetActor::Unsummon()
{
	if (true == this->IsSummoned())
	{
		// ąöÇÁ »čÁ¦
		this->ClearBuff();
		this->SetSummonItem(NULL);
#ifdef __PET_PICKUP
		this->SetPickupItem(NULL);
		this->SetPickup(false);
#endif
		if (NULL != m_pkOwner)
			m_pkOwner->ComputePoints();

		if (NULL != m_pkChar)
			M2_DESTROY_CHARACTER(m_pkChar);

		m_pkChar = 0;
		m_dwVID = 0;
	}
}

DWORD CPetActor::Summon(const char* petName, LPITEM pSummonItem, bool bSpawnFar)
{
	long x = m_pkOwner->GetX();
	long y = m_pkOwner->GetY();
	long z = m_pkOwner->GetZ();

	if (true == bSpawnFar)
	{
		x += (number(0, 1) * 2 - 1) * number(2000, 2500);
		y += (number(0, 1) * 2 - 1) * number(2000, 2500);
	}
	else
	{
		x += number(-100, 100);
		y += number(-100, 100);
	}

	if (0 != m_pkChar)
	{
		m_pkChar->Show (m_pkOwner->GetMapIndex(), x, y);
		m_dwVID = m_pkChar->GetVID();

		return m_dwVID;
	}
	
	m_pkChar = CHARACTER_MANAGER::instance().SpawnMob(
				m_dwVnum, 
				m_pkOwner->GetMapIndex(), 
				x, y, z,
				false, (int)(m_pkOwner->GetRotation()+180), false);

	if (0 == m_pkChar)
	{
		sys_err("[CPetSystem::Summon] Failed to summon the pet. (vnum: %d)", m_dwVnum);
		return 0;
	}

	m_pkChar->SetPet();

//	m_pkOwner->DetailLog();
//	m_pkChar->DetailLog();

	//ĆęŔÇ ±ą°ˇ¸¦ ÁÖŔÎŔÇ ±ą°ˇ·Î ĽłÁ¤ÇÔ.
	m_pkChar->SetEmpire(m_pkOwner->GetEmpire());

	m_dwVID = m_pkChar->GetVID();

	this->SetName(petName);

	// SetSummonItem(pSummonItem)¸¦ şÎ¸Ą ČÄżˇ ComputePoints¸¦ şÎ¸Ł¸é ąöÇÁ ŔűżëµĘ.
	this->SetSummonItem(pSummonItem);
	m_pkOwner->ComputePoints();
	m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z);

	return m_dwVID;
}

bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
{
	float fDist = number(fMinDist, fMaxDist);
	float r = (float)number (0, 359);
	float dest_x = GetOwner()->GetX() + fDist * cos(r);
	float dest_y = GetOwner()->GetY() + fDist * sin(r);

	//m_pkChar->SetRotation(number(0, 359));        // ąćÇâŔş ·Ł´ýŔ¸·Î ĽłÁ¤

	//GetDeltaByDegree(m_pkChar->GetRotation(), fDist, &fx, &fy);

	// ´Ŕ˝ĽÇŃ ¸ř°¨ ĽÓĽş ĂĽĹ©; ĂÖÁľ Ŕ§ÄˇżÍ Áß°Ł Ŕ§Äˇ°ˇ °ĄĽöľř´Ů¸é °ˇÁö ľĘ´Â´Ů.
	//if (!(SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx, m_pkChar->GetY() + (int) fy) 
	//			&& SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx/2, m_pkChar->GetY() + (int) fy/2)))
	//	return true;

	m_pkChar->SetNowWalking(true);

	//if (m_pkChar->Goto(m_pkChar->GetX() + (int) fx, m_pkChar->GetY() + (int) fy))
	//	m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
	if (!m_pkChar->IsStateMove() && m_pkChar->Goto(dest_x, dest_y))
		m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);

	m_dwLastActionTime = get_dword_time();

	return true;
}

// char_state.cpp StateHorseÇÔĽö ±×łÉ C&P -_-;
bool CPetActor::_UpdateFollowAI()
{
	if (0 == m_pkChar->m_pkMobData)
	{
		//sys_err("[CPetActor::_UpdateFollowAI] m_pkChar->m_pkMobData is NULL");
		return false;
	}
	
	// NOTE: Äł¸ŻĹÍ(Ćę)ŔÇ żř·ˇ Ŕ̵ż ĽÓµµ¸¦ ľËľĆľß ÇϴµĄ, ÇŘ´ç °Ş(m_pkChar->m_pkMobData->m_table.sMovingSpeed)Ŕ» Á÷Á˘ŔűŔ¸·Î Á˘±ŮÇŘĽ­ ľËľĆłľ Ľöµµ ŔÖÁö¸¸
	// m_pkChar->m_pkMobData °ŞŔĚ invalidÇŃ °ćżě°ˇ ŔÚÁÖ ąß»ýÇÔ. ÇöŔç ˝Ă°Ł°ü°č»ó żřŔÎŔş ´ŮŔ˝żˇ ĆÄľÇÇϰí ŔĎ´ÜŔş m_pkChar->m_pkMobData °ŞŔ» ľĆżą »çżëÇĎÁö ľĘµµ·Ď ÇÔ.
	// ż©±âĽ­ ¸Ĺąř °Ë»çÇĎ´Â ŔĚŔŻ´Â ĂÖĂĘ ĂʱâČ­ ÇŇ ¶§ Á¤»ó °ŞŔ» Á¦´ë·Î ¸řľňľîżŔ´Â °ćżěµµ ŔÖŔ˝.. -_-;; ¤Đ¤Đ¤Đ¤Đ¤Đ¤Đ¤Đ¤Đ¤Đ
	if (0 == m_originalMoveSpeed)
	{
		const CMob* mobData = CMobManager::Instance().Get(m_dwVnum);

		if (0 != mobData)
			m_originalMoveSpeed = mobData->m_table.sMovingSpeed;
	}
	float	START_FOLLOW_DISTANCE = 300.0f;		// ŔĚ °Ĺ¸® ŔĚ»ó ¶łľîÁö¸é ÂѾưˇ±â ˝ĂŔŰÇÔ
	float	START_RUN_DISTANCE = 900.0f;		// ŔĚ °Ĺ¸® ŔĚ»ó ¶łľîÁö¸é ¶ŮľîĽ­ ÂѾư¨.

	float	RESPAWN_DISTANCE = 4500.f;			// ŔĚ °Ĺ¸® ŔĚ»ó ¸ÖľîÁö¸é ÁÖŔÎ ż·Ŕ¸·Î ĽŇČŻÇÔ.
	int		APPROACH = 200;						// Á˘±Ů °Ĺ¸®

	bool bDoMoveAlone = true;					// Äł¸ŻĹÍżÍ °ˇ±îŔĚ ŔÖŔ» ¶§ ČĄŔÚ ż©±âŔú±â żňÁ÷ŔϰÇÁö ż©şÎ -_-;
	bool bRun = false;							// ¶Ůľîľß ÇĎłŞ?

	DWORD currentTime = get_dword_time();

	long ownerX = m_pkOwner->GetX();		long ownerY = m_pkOwner->GetY();
	long charX = m_pkChar->GetX();			long charY = m_pkChar->GetY();

	float fDist = DISTANCE_APPROX(charX - ownerX, charY - ownerY);

	if (fDist >= RESPAWN_DISTANCE)
	{
		float fOwnerRot = m_pkOwner->GetRotation() * 3.141592f / 180.f;
		float fx = -APPROACH * cos(fOwnerRot);
		float fy = -APPROACH * sin(fOwnerRot);
		if (m_pkChar->Show(m_pkOwner->GetMapIndex(), ownerX + fx, ownerY + fy))
		{
			return true;
		}
	}
	
	
	if (fDist >= START_FOLLOW_DISTANCE)
	{
		if( fDist >= START_RUN_DISTANCE)
		{
			bRun = true;
		}

		m_pkChar->SetNowWalking(!bRun);		// NOTE: ÇÔĽö Ŕ̸§ş¸°í ¸ŘĂߴ°ÇÁŮ ľËľŇ´ÂµĄ SetNowWalking(false) ÇĎ¸é ¶Ů´Â°ĹŔÓ.. -_-;
		
		Follow(APPROACH);

		m_pkChar->SetLastAttacked(currentTime);
		m_dwLastActionTime = currentTime;
	}
	//else
	//{
	//	if (fabs(m_pkChar->GetRotation() - GetDegreeFromPositionXY(charX, charY, ownerX, ownerX)) > 10.f || fabs(m_pkChar->GetRotation() - GetDegreeFromPositionXY(charX, charY, ownerX, ownerX)) < 350.f)
	//	{
	//		m_pkChar->Follow(m_pkOwner, APPROACH);
	//		m_pkChar->SetLastAttacked(currentTime);
	//		m_dwLastActionTime = currentTime;
	//	}
	//}
	// Follow ÁßŔĚÁö¸¸ ÁÖŔΰú ŔĎÁ¤ °Ĺ¸® ŔĚł»·Î °ˇ±îżöÁł´Ů¸é ¸ŘĂă
	else 
		m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
	//else if (currentTime - m_dwLastActionTime > number(5000, 12000))
	//{
	//	this->_UpdatAloneActionAI(START_FOLLOW_DISTANCE / 2, START_FOLLOW_DISTANCE);
	//}

	return true;
}

bool CPetActor::Update(DWORD deltaTime)
{
	bool bResult = true;

	// Ćę ÁÖŔÎŔĚ Á׾ú°ĹłŞ, ĽŇČŻµČ ĆęŔÇ »óۡ ŔĚ»óÇϴٸé ĆęŔ» ľřľÚ. (NOTE: °ˇ˛ű°ˇ´Ů ŔĚ·± Ŕú·± ŔĚŔŻ·Î ĽŇČŻµČ ĆęŔĚ DEAD »óĹÂżˇ şüÁö´Â °ćżě°ˇ ŔÖŔ˝-_-;)
	// ĆęŔ» ĽŇČŻÇŃ ľĆŔĚĹŰŔĚ ľř°ĹłŞ, ł»°ˇ °ˇÁř »óۡ ľĆ´Ď¶ó¸é ĆęŔ» ľřľÚ.
	if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead()) 
		|| NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())
		|| ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner()
		)
	{
		this->Unsummon();
		return true;
	}
#ifdef __PET_PICKUP
	if (this->IsSummoned()){
		this->BringItem();
		this->PickUpItems(900); // 900 = RANGE
	}	
#endif
	if (this->IsSummoned() && HasOption(EPetOption_Followable))
		bResult = bResult && this->_UpdateFollowAI();

	return bResult;
}

#ifdef __PET_PICKUP
// Structura pentru func?ia de preluare a itemelor de către pet
struct PetPickUpItemStruct
{
    CPetActor* pet;
    int range;

    PetPickUpItemStruct(CPetActor* p, int r) : pet(p), range(r) {}

    void operator()(LPENTITY pEnt)
    {
        if (!pet->GetOwner() || !pet->GetCharacter())
            return;

        if (pet->IsPickup())
            return;

        if (pEnt->IsType(ENTITY_ITEM))
        {
            LPITEM item = dynamic_cast<LPITEM>(pEnt);
            if (!item)
                return;

            LPCHARACTER player = pet->GetOwner();
            if (!item->GetSectree() || !item->IsOwnership(player))
                return;

            int iDist = DISTANCE_APPROX(item->GetX() - player->GetX(), item->GetY() - player->GetY());
            if (iDist > range)
                return;

            pet->SetPickup(true);
            pet->SetPickupItem(item);
        }
    }
};

// Func?ie pentru a căuta ?i a ridica iteme în raza specificată de către pet
void CPetActor::PickUpItems(int range)
{
    if (IsPickup())
        return;

    long map = m_pkChar->GetMapIndex();
    PIXEL_POSITION m = m_pkChar->GetXYZ();
    LPSECTREE tree = SECTREE_MANAGER::instance().Get(map, m.x, m.y);
    if (!tree)
    {
        sys_err("Cannot find sectree at %dx%d", m.x, m.y);
        return;
    }

    PetPickUpItemStruct f(this, range);
    tree->ForEachAround(f);
}

// Func?ie pentru a aduce itemul ridicat de pet la owner
void CPetActor::BringItem()
{
    if (!IsPickup())
        return;

    // Ob?ine item-ul asociat
    LPITEM item = GetPickupItem();

    // Verifică dacă item-ul este nullptr sau al?i pointeri sunt invalizi
    if (!m_pkOwner || !m_pkChar || !item)
    {
        // Dacă item este nullptr, înregistrează o eroare ?i ie?i din func?ie
        sys_err("BringItem() - Invalid pointer detected. Owner: %p, Char: %p, Item: %p", m_pkOwner, m_pkChar, item);
        return;
    }

    // Verifică dacă item-ul are un sectree valid
    if (!item->GetSectree())
    {
        sys_err("BringItem() - Item has no valid sectree. Item: %p", item);
        return;
    }

    // Restul codului tău rămâne neschimbat...
    float fMinDistance = 20.0f;
    float fPetX = m_pkChar->GetX();
    float fPetY = m_pkChar->GetY();
    float itemX = item->GetX();
    float itemY = item->GetY();

    float fDist = DISTANCE_SQRT(itemX - fPetX, itemY - fPetY);
    if (fDist <= 250.0f)
    {
        SetPickup(false);
        m_pkOwner->PickupItemByPet(item->GetVID());
        SetPickupItem(nullptr);
        m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);

        sys_log(0, "Item picked up: %s, Count: %u, Original Vnum: %u", item->GetName(), item->GetCount(), item->GetOriginalVnum());

        return;
    }

    m_pkChar->SetRotationToXY(itemX, itemY);

    float fx, fy;
    float fDistToGo = fDist - fMinDistance;
    GetDeltaByDegree(m_pkChar->GetRotation(), fDistToGo, &fx, &fy);

    if (!m_pkChar->Goto(static_cast<int>(fPetX + fx + 0.5f), static_cast<int>(fPetY + fy + 0.5f)))
        return;

    m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);
}

// Defini?ia func?iei PickupItemByPet din clasa CHARACTER
bool CHARACTER::PickupItemByPet(DWORD dwVID)
{
    LPITEM item = ITEM_MANAGER::instance().FindByVID(dwVID);

    if (!item || !item->GetSectree() || !item->IsOwnership(this))
        return false;

    if (item->GetType() == ITEM_ELK)
    {
        GiveGold(item->GetCount());
        item->RemoveFromGround();
        M2_DESTROY_ITEM(item);
    }
    else
    {
        int iEmptyCell = GetEmptyInventory(item->GetSize());
        if (iEmptyCell == -1)
        {
            sys_log(0, "No empty inventory slot for pet pickup. Owner PID: %d, Item VID: %d", GetPlayerID(), item->GetVID());
            return false;
        }

        item->RemoveFromGround();
        item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));

        // Înlocuirea apelului de log
        sys_log(0, "Item picked up: %s, Count: %u, Original Vnum: %u", item->GetName(), item->GetCount(), item->GetOriginalVnum());

        ChatPacket(CHAT_TYPE_INFO, "Picked up: %s", item->GetName());
    }

    return true;
}

#endif

//NOTE : ÁÖŔÇ!!! MinDistance¸¦ Ĺ©°Ô ŔâŔ¸¸é ±× şŻŔ§¸¸Ĺ­ŔÇ şŻČ­µżľČŔş followÇĎÁö ľĘ´Â´Ů,
bool CPetActor::Follow(float fMinDistance)
{
	// °ˇ·Á´Â Ŕ§Äˇ¸¦ ąŮ¶óşÁľß ÇŃ´Ů.
	if( !m_pkOwner || !m_pkChar) 
		return false;

	float fOwnerX = m_pkOwner->GetX();
	float fOwnerY = m_pkOwner->GetY();

	float fPetX = m_pkChar->GetX();
	float fPetY = m_pkChar->GetY();

	float fDist = DISTANCE_SQRT(fOwnerX - fPetX, fOwnerY - fPetY);
	if (fDist <= fMinDistance)
		return false;

	m_pkChar->SetRotationToXY(fOwnerX, fOwnerY);

	float fx, fy;

	float fDistToGo = fDist - fMinDistance;
	GetDeltaByDegree(m_pkChar->GetRotation(), fDistToGo, &fx, &fy);
	
	if (!m_pkChar->Goto((int)(fPetX+fx+0.5f), (int)(fPetY+fy+0.5f)) )
		return false;

	m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0);

	return true;
}

void CPetActor::SetSummonItem (LPITEM pItem)
{
	if (NULL == pItem)
	{
		m_dwSummonItemVID = 0;
		m_dwSummonItemVnum = 0;
#ifdef __PET_PICKUP
		this->SetPickupItem(NULL);
		this->SetPickup(false);
#endif
		return;
	}

	m_dwSummonItemVID = pItem->GetVID();
	m_dwSummonItemVnum = pItem->GetVnum();
}

void CPetActor::GiveBuff()
{
	// ĆÄȲ Ćę ąöÇÁ´Â ´řŔüżˇĽ­¸¸ ąß»ýÇÔ.
	if (34004 == m_dwVnum || 34009 == m_dwVnum)
	{
		if (NULL == m_pkOwner->GetDungeon())
		{
			return;
		}
	}
	LPITEM item = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID);
	if (NULL != item)
		item->ModifyPoints(true);
	return ;
}

void CPetActor::ClearBuff()
{
    // Verifică dacă proprietarul este valid
    if (m_pkOwner == nullptr) {
        sys_err("CPetActor::ClearBuff() called with a null owner.");
        return;
    }

    // Ob?ine prototipul itemului asociat cu pet-ul
    TItemTable* item_proto = ITEM_MANAGER::instance().GetTable(m_dwSummonItemVnum);
    if (item_proto == nullptr) {
        sys_err("CPetActor::ClearBuff() - Invalid item prototype for summon item vnum: %d", m_dwSummonItemVnum);
        return;
    }

    // Iterează prin toate aplicările de atribute ale itemului
    for (int i = 0; i < ITEM_APPLY_MAX_NUM; i++)
    {
        // Verifică dacă tipul de aplicare este valid
        if (item_proto->aApplies[i].bType == APPLY_NONE)
            continue;

        // Protejează împotriva overflow-urilor/underflow-urilor
        if (item_proto->aApplies[i].lValue != 0) {
            // Aplică modificările asupra punctelor proprietarului
            m_pkOwner->ApplyPoint(item_proto->aApplies[i].bType, -item_proto->aApplies[i].lValue);
        } else {
            sys_err("CPetActor::ClearBuff() - lValue is zero for item apply type %d", item_proto->aApplies[i].bType);
        }
    }

    // Mesaj de log pentru debugging, dacă este nevoie
    sys_log(0, "CPetActor::ClearBuff() - Buff cleared for owner_id=%d, item_vnum=%d", m_pkOwner->GetPlayerID(), m_dwSummonItemVnum);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////
//  CPetSystem
///////////////////////////////////////////////////////////////////////////////////////

CPetSystem::CPetSystem(LPCHARACTER owner)
{
//	assert(0 != owner && "[CPetSystem::CPetSystem] Invalid owner");

	m_pkOwner = owner;
	m_dwUpdatePeriod = 400;

	m_dwLastUpdateTime = 0;
}

CPetSystem::~CPetSystem()
{
	Destroy();
}

void CPetSystem::Destroy()
{
	for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		CPetActor* petActor = iter->second;

		if (0 != petActor)
		{
			delete petActor;
		}
	}
	event_cancel(&m_pkPetSystemUpdateEvent);
	m_petActorMap.clear();
}

/// Ćę ˝Ă˝şĹŰ ľ÷µĄŔĚĆ®. µî·ĎµČ ĆęµéŔÇ AI Ăł¸® µîŔ» ÇÔ.
bool CPetSystem::Update(DWORD deltaTime)
{
	bool bResult = true;

	DWORD currentTime = get_dword_time();

	// CHARACTER_MANAGERżˇĽ­ Äł¸ŻĹÍ·ů UpdateÇŇ ¶§ ¸Ĺ°łşŻĽö·Î ÁÖ´Â (Pulse¶ó°í µÇľîŔÖ´Â)°ŞŔĚ ŔĚŔü ÇÁ·ąŔÓ°úŔÇ ˝Ă°ŁÂ÷ŔĚŔÎÁŮ ľËľŇ´ÂµĄ
	// ŔüÇô ´Ů¸Ą °ŞŔ̶óĽ­-_-; ż©±âżˇ ŔÔ·ÂŔ¸·Î µéľîżŔ´Â deltaTimeŔş Ŕǹ̰ˇ ľřŔ˝¤Đ¤Đ	
	
	if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime)
		return true;
	
	std::vector <CPetActor*> v_garbageActor;

	for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		CPetActor* petActor = iter->second;

		if (0 != petActor && petActor->IsSummoned())
		{
			LPCHARACTER pPet = petActor->GetCharacter();
			
			if (NULL == CHARACTER_MANAGER::instance().Find(pPet->GetVID()))
			{
				v_garbageActor.push_back(petActor);
			}
			else
			{
				bResult = bResult && petActor->Update(deltaTime);
			}
		}
	}
	for (std::vector<CPetActor*>::iterator it = v_garbageActor.begin(); it != v_garbageActor.end(); it++)
		DeletePet(*it);

	m_dwLastUpdateTime = currentTime;

	return bResult;
}

/// °ü¸® ¸ń·ĎżˇĽ­ ĆęŔ» Áöżň
void CPetSystem::DeletePet(DWORD mobVnum)
{
	TPetActorMap::iterator iter = m_petActorMap.find(mobVnum);

	if (m_petActorMap.end() == iter)
	{
		sys_err("[CPetSystem::DeletePet] Can't find pet on my list (VNUM: %d)", mobVnum);
		return;
	}

	CPetActor* petActor = iter->second;

	if (0 == petActor)
		sys_err("[CPetSystem::DeletePet] Null Pointer (petActor)");
	else
		delete petActor;

	m_petActorMap.erase(iter);	
}

/// °ü¸® ¸ń·ĎżˇĽ­ ĆęŔ» Áöżň
void CPetSystem::DeletePet(CPetActor* petActor)
{
	for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		if (iter->second == petActor)
		{
			delete petActor;
			m_petActorMap.erase(iter);

			return;
		}
	}

	sys_err("[CPetSystem::DeletePet] Can't find petActor(0x%x) on my list(size: %d) ", petActor, m_petActorMap.size());
}

void CPetSystem::Unsummon(DWORD vnum, bool bDeleteFromList)
{
	CPetActor* actor = this->GetByVnum(vnum);

	if (0 == actor)
	{
		sys_err("[CPetSystem::GetByVnum(%d)] Null Pointer (petActor)", vnum);
		return;
	}
	actor->Unsummon();

	if (true == bDeleteFromList)
		this->DeletePet(actor);

	bool bActive = false;
	for (TPetActorMap::iterator it = m_petActorMap.begin(); it != m_petActorMap.end(); it++)
	{
		bActive |= it->second->IsSummoned();
	}
	if (false == bActive)
	{
		event_cancel(&m_pkPetSystemUpdateEvent);
		m_pkPetSystemUpdateEvent = NULL;
	}
}


CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* petName, bool bSpawnFar, DWORD options)
{
	CPetActor* petActor = this->GetByVnum(mobVnum);

	// µî·ĎµČ ĆęŔĚ ľĆ´Ď¶ó¸é »ő·Î »ýĽş ČÄ °ü¸® ¸ń·Ďżˇ µî·ĎÇÔ.
	if (0 == petActor)
	{
		petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options);
		m_petActorMap.insert(std::make_pair(mobVnum, petActor));
	}

	DWORD petVID = petActor->Summon(petName, pSummonItem, bSpawnFar);

	if (NULL == m_pkPetSystemUpdateEvent)
	{
		petsystem_event_info* info = AllocEventInfo<petsystem_event_info>();

		info->pPetSystem = this;

		m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4);	// 0.25ĂĘ	
	}

	return petActor;
}


CPetActor* CPetSystem::GetByVID(DWORD vid) const
{
	CPetActor* petActor = 0;

	bool bFound = false;

	for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		petActor = iter->second;

		if (0 == petActor)
		{
			sys_err("[CPetSystem::GetByVID(%d)] Null Pointer (petActor)", vid);
			continue;
		}

		bFound = petActor->GetVID() == vid;

		if (true == bFound)
			break;
	}

	return bFound ? petActor : 0;
}

/// µî·Ď µČ Ćę ÁßżˇĽ­ ÁÖľîÁř ¸÷ VNUMŔ» °ˇÁř ľ×Ĺ͸¦ ąÝČŻÇĎ´Â ÇÔĽö.
CPetActor* CPetSystem::GetByVnum(DWORD vnum) const
{
	CPetActor* petActor = 0;

	TPetActorMap::const_iterator iter = m_petActorMap.find(vnum);

	if (m_petActorMap.end() != iter)
		petActor = iter->second;

	return petActor;
}

size_t CPetSystem::CountSummoned() const
{
	size_t count = 0;

	for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		CPetActor* petActor = iter->second;

		if (0 != petActor)
		{
			if (petActor->IsSummoned())
				++count;
		}
	}

	return count;
}

void CPetSystem::RefreshBuff()
{
	for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
	{
		CPetActor* petActor = iter->second;

		if (0 != petActor)
		{
			if (petActor->IsSummoned())
			{
				petActor->GiveBuff();
			}
		}
	}
}

 

Edited by DakaSenpai99
Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-166499
Share on other sites

bool CPetActor::Update(DWORD deltaTime)
{
	bool bResult = true;

	// Ce ÁÖRÎRE Á×lú°LlS, LNCZµC CeRÇ »óL°? RE»óÇD´U¸é CeR» lrlÚ. (NOTE: °??u°?´U RE·± Rú·± RERZ·Î LNCZµC CeRE DEAD »óLÂz? süÁö´Â °cze°? RÖR?-_-;)
	// CeR» LNCZÇN lCRELURE lr°LlS, l»°? °?Ár »óL°? lC´D¶ó¸é CeR» lrlÚ.
	if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead()) 
		|| NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())
		|| ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner()
		)
	{
		this->Unsummon();
		return true;
	}
#ifdef __PET_PICKUP
	if (this->IsSummoned()){
		this->PickUpItems(900); // 900 = RANGE
		this->BringItem();
	}	
#endif
	if (this->IsSummoned() && HasOption(EPetOption_Followable))
		bResult = bResult && this->_UpdateFollowAI();

	return bResult;
}

Try with this. Before it called BringItem but PickUpItems sets the item pointer you want to use in BringItem, so i changed the lines.

Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-166615
Share on other sites


#0  0x00595b0a in CPetSystem::DeletePet (this=0x33130740, petActor=0x4f60f9ec)
    at PetSystem.cpp:643
643     }
i got this

 

here it's all function

void CPetSystem::DeletePet(CPetActor* petActor)
{
    for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
    {
        if (iter->second == petActor)
        {
            delete petActor;
            m_petActorMap.erase(iter);

            return;
        }
    }

    sys_err("[CPetSystem::DeletePet] Can't find petActor(0x%x) on my list(size: %d) ", petActor, m_petActorMap.size());
}

 

--Type <RET> for more, q to quit, c to continue without paging--bt full #0 0x005955af in CPetActor::BringItem (this=0x22123480) at PetSystem.cpp:395 395 if (!m_pkOwner || !m_pkChar || !item || !item->GetSectree()) [Current thread is 1 (LWP 100095)]

Edited by DakaSenpai99
Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-166621
Share on other sites

  • 7 months later...
On 8/20/2024 at 6:14 PM, DakaSenpai99 said:


#0  0x00595b0a in CPetSystem::DeletePet (this=0x33130740, petActor=0x4f60f9ec)
    at PetSystem.cpp:643
643     }
i got this

 

here it's all function

void CPetSystem::DeletePet(CPetActor* petActor)
{
    for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
    {
        if (iter->second == petActor)
        {
            delete petActor;
            m_petActorMap.erase(iter);

            return;
        }
    }

    sys_err("[CPetSystem::DeletePet] Can't find petActor(0x%x) on my list(size: %d) ", petActor, m_petActorMap.size());
}

 

--Type <RET> for more, q to quit, c to continue without paging--bt full #0 0x005955af in CPetActor::BringItem (this=0x22123480) at PetSystem.cpp:395 395 if (!m_pkOwner || !m_pkChar || !item || !item->GetSectree()) [Current thread is 1 (LWP 100095)]

hi, we haven 't found a solution?

Link to comment
https://metin2.dev/topic/32872-pet-autopickup-problem/#findComment-170002
Share on other sites

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.