Jump to content

Recommended Posts

  • Active+ Member

Hi all, I am using Mali's Official Transmutation and Official Private Shop Search systems. They work great. But I realized that I have a little bug. Until I close and open the shop window, a transmutation icon appears on the slot that an item is sold. I believe it's a bug on the pack side. Which file may be causing it? 

 

Video:

 

  • 1 year later...
  • 9 months later...
  • Premium

Hello, I have the same issue did someone manage to fix it ? 

 

EDIT:

I reload a saved version of my file without Private shop Search and this happen anyway for me anytime an item is sold,

a transmutation icon is shown before reload.

 

Could this be from transmutation system then ? 

may it come from this in uiShop.py ? 

Spoiler
if app.BL_TRANSMUTATION_SYSTEM:
	changelookvnum = shop.GetItemChangeLookVnum(idx)
	if not changelookvnum == 0:
		self.itemSlotWindow.SetSlotCoverImage(i,"icon/item/ingame_convert_Mark.tga")
	else:
		self.itemSlotWindow.EnableSlotCoverImage(i,False)

 

If i just let:

self.itemSlotWindow.EnableSlotCoverImage(i,False)

The bug does not appear but i guess transmuted item in shops does not have the transmutation icons anymore.

Edited by ARiver
some leads
  • 1 year later...

Problem The bug is on the server side in CShop::BroadcastUpdateItem (source/server/game/src/shop.cpp): TPacketGCShopUpdateItem pack2; // <- not initialized!

When an item is purchased from a private shop (including the search glass), the server first sets r_item.pkItem = NULL and then calls BroadcastUpdateItem(pos). The first branch of this function is: if (m_pkPC && !m_itemVector[pos].pkItem) pack2.item.vnum = 0; // only vnum is zeroed out

Because the pack2 structure on the stack is not zeroed out, other fields including dwTransmutationVnum retain garbage memory values. The client copies this packet via SetItemData, and when shop.GetItemChangeLookVnum(idx) != 0 in uishop.py, it renders the ingame_convert_Mark.tga icon. Closing and reopening the window sends the SHOP_SUBHEADER_GC_START packet with the correct value (0), causing the icon to disappear—exactly matching the described behavior.

Solution Zero out pack2 in shop.cpp:

TPacketGCShopUpdateItem pack2;
memset(&pack2, 0, sizeof(pack2));

The Start() function in the same file already uses this exact approach. This clears dwTransmutationVnum and all other uninitialized fields in the sold item's slot. Since both regular shop purchases and search glass purchases route through this function, both are resolved. Recompiling the game project is all that is required.

example:

void CShop::BroadcastUpdateItem(BYTE pos)
{
	TPacketGCShop pack;
	TPacketGCShopUpdateItem pack2;
#if defined(ENABLE_TRANSMUTATION)
	memset(&pack2, 0, sizeof(pack2));
#endif

	TEMP_BUFFER	buf;

	pack.header		= HEADER_GC_SHOP;
	pack.subheader	= SHOP_SUBHEADER_GC_UPDATE_ITEM;
	pack.size		= sizeof(pack) + sizeof(pack2);

	pack2.pos		= pos;

	if (m_pkPC && !m_itemVector[pos].pkItem)
		pack2.item.vnum = 0;
	else
	{
		pack2.item.vnum	= m_itemVector[pos].vnum;
		if (m_itemVector[pos].pkItem)
		{
			thecore_memcpy(pack2.item.alSockets, m_itemVector[pos].pkItem->GetSockets(), sizeof(pack2.item.alSockets));
			thecore_memcpy(pack2.item.aAttr, m_itemVector[pos].pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = m_itemVector[pos].pkItem->GetTransmutationVnum();
#endif
		}
		else
		{
			memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
			memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = 0;
#endif
		}
	}

	pack2.item.price	= m_itemVector[pos].price;
#ifdef ENABLE_CHEQUE_SYSTEM
    pack2.item.cheque = m_itemVector[pos].cheque;
#endif
	pack2.item.count	= m_itemVector[pos].count;

	buf.write(&pack, sizeof(pack));
	buf.write(&pack2, sizeof(pack2));

	Broadcast(buf.read_peek(), buf.size());
}

 

  • Love 1
  • Active+ Member
19 hours ago, caelnarae said:

Problem The bug is on the server side in CShop::BroadcastUpdateItem (source/server/game/src/shop.cpp): TPacketGCShopUpdateItem pack2; // <- not initialized!

When an item is purchased from a private shop (including the search glass), the server first sets r_item.pkItem = NULL and then calls BroadcastUpdateItem(pos). The first branch of this function is: if (m_pkPC && !m_itemVector[pos].pkItem) pack2.item.vnum = 0; // only vnum is zeroed out

Because the pack2 structure on the stack is not zeroed out, other fields including dwTransmutationVnum retain garbage memory values. The client copies this packet via SetItemData, and when shop.GetItemChangeLookVnum(idx) != 0 in uishop.py, it renders the ingame_convert_Mark.tga icon. Closing and reopening the window sends the SHOP_SUBHEADER_GC_START packet with the correct value (0), causing the icon to disappear—exactly matching the described behavior.

Solution Zero out pack2 in shop.cpp:

TPacketGCShopUpdateItem pack2;
memset(&pack2, 0, sizeof(pack2));

The Start() function in the same file already uses this exact approach. This clears dwTransmutationVnum and all other uninitialized fields in the sold item's slot. Since both regular shop purchases and search glass purchases route through this function, both are resolved. Recompiling the game project is all that is required.

example:

void CShop::BroadcastUpdateItem(BYTE pos)
{
	TPacketGCShop pack;
	TPacketGCShopUpdateItem pack2;
#if defined(ENABLE_TRANSMUTATION)
	memset(&pack2, 0, sizeof(pack2));
#endif

	TEMP_BUFFER	buf;

	pack.header		= HEADER_GC_SHOP;
	pack.subheader	= SHOP_SUBHEADER_GC_UPDATE_ITEM;
	pack.size		= sizeof(pack) + sizeof(pack2);

	pack2.pos		= pos;

	if (m_pkPC && !m_itemVector[pos].pkItem)
		pack2.item.vnum = 0;
	else
	{
		pack2.item.vnum	= m_itemVector[pos].vnum;
		if (m_itemVector[pos].pkItem)
		{
			thecore_memcpy(pack2.item.alSockets, m_itemVector[pos].pkItem->GetSockets(), sizeof(pack2.item.alSockets));
			thecore_memcpy(pack2.item.aAttr, m_itemVector[pos].pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = m_itemVector[pos].pkItem->GetTransmutationVnum();
#endif
		}
		else
		{
			memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
			memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
            pack2.item.dwTransmutationVnum = 0;
#endif
		}
	}

	pack2.item.price	= m_itemVector[pos].price;
#ifdef ENABLE_CHEQUE_SYSTEM
    pack2.item.cheque = m_itemVector[pos].cheque;
#endif
	pack2.item.count	= m_itemVector[pos].count;

	buf.write(&pack, sizeof(pack));
	buf.write(&pack2, sizeof(pack2));

	Broadcast(buf.read_peek(), buf.size());
}

 

There's a problem here; if the ENABLE_TRANSMUTATION definition doesn't exist, there won't be a memset call for pack2.

Btw, you don't need that many memset calls. Use brace initialization. "T x{};" is value-initialization and since structs in Metin2 provide the POD and aggregate definition, the object will be zero-initialized. The result will look something like this:

 

void CShop::BroadcastUpdateItem(BYTE pos)
{
	if (pos >= m_itemVector.size()) // why haven't they added this check? comments are really important.
	{
		sys_err("CShop::BroadcastUpdateItem: invalid pos %u (size %u)", pos, m_itemVector.size());
		return;
	}

	TPacketGCShop pack{};
	TPacketGCShopUpdateItem pack2{};
	TEMP_BUFFER buf;

	pack.header    = HEADER_GC_SHOP;
	pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM;
	pack.size      = sizeof(pack) + sizeof(pack2);

	pack2.pos = pos;

	const SHOP_ITEM& item = m_itemVector[pos];

	if (!(m_pkPC && !item.pkItem))
	{
		pack2.item.vnum = item.vnum;

		if (item.pkItem)
		{
			thecore_memcpy(pack2.item.alSockets, item.pkItem->GetSockets(), sizeof(pack2.item.alSockets));
			thecore_memcpy(pack2.item.aAttr, item.pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
#if defined(ENABLE_TRANSMUTATION)
			pack2.item.dwTransmutationVnum = item.pkItem->GetTransmutationVnum();
#endif
		}
	}

	pack2.item.price = item.price;
#if defined(ENABLE_CHEQUE_SYSTEM)
	pack2.item.cheque = item.cheque;
#endif
	pack2.item.count = item.count;

	buf.write(&pack, sizeof(pack));
	buf.write(&pack2, sizeof(pack2));

	Broadcast(buf.read_peek(), buf.size());
}

 

  • Metin2 Dev 1
  • Love 1

Software Engineer | Low-Latency C++

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.