Jump to content

Reduce server memory usage


Recommended Posts

  • Premium

The problem:
Mobs are using CHARACTER_POINT_INSTANT struct, which contains fixed size arrays for dragon soul, items etc. For every mob these arrays are allocating memory, but mobs obviously don't use items...

The solution:
Replace fixed size arrays with std::map or other data type
From my own testing i saw over 70% memory usage reduction with special inventory system and optimized variables listed below:

bItemGrid
pItems
pDSItems
wDSItemGrid

Below i am sharing example implementation in clean source for bItemGrid variable

Spoiler
//in char.cpp at the end of void CHARACTER::Initialize() function add

#ifdef ENABLE_ITEM_GRID_MAP
m_pointsInstant.pItemsGridMap.clear();
#endif

//in char.h after function LPITEM GetInventoryItem add

#ifdef ENABLE_ITEM_GRID_MAP
	BYTE	ItemGridMapGetConst(BYTE cell_index) const;
#endif

//in char.h replace BYTE bItemGrid[INVENTORY_AND_EQUIP_SLOT_MAX]; with
  
#ifdef ENABLE_ITEM_GRID_MAP
	std::map<BYTE, BYTE> pItemsGridMap;
#else
	BYTE bItemGrid[INVENTORY_AND_EQUIP_SLOT_MAX];
#endif
  
//in char_item.cpp replace function CHARACTER::SetItem with
  
void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
{
	WORD wCell = Cell.cell;
	BYTE window_type = Cell.window_type;
	if ((unsigned long)((CItem*)pItem) == 0xff || (unsigned long)((CItem*)pItem) == 0xffffffff)
	{
		sys_err("!!! FATAL ERROR !!! item == 0xff (char: %s cell: %u)", GetName(), wCell);
		core_dump();
		return;
	}

	if (pItem && pItem->GetOwner())
	{
		assert(!"GetOwner exist");
		return;
	}
  
	switch(window_type)
	{
	case INVENTORY:
	case EQUIPMENT:
		{
			if (wCell >= INVENTORY_AND_EQUIP_SLOT_MAX)
			{
				sys_err("CHARACTER::SetItem: invalid item cell %d", wCell);
				return;
			}

			LPITEM pOld = m_pointsInstant.pItems[wCell];

			if (pOld)
			{
				if (wCell < INVENTORY_MAX_NUM)
				{
					for (int i = 0; i < pOld->GetSize(); ++i)
					{
						int p = wCell + (i * 5);

						if (p >= INVENTORY_MAX_NUM)
							continue;

						if (m_pointsInstant.pItems[p] && m_pointsInstant.pItems[p] != pOld)
							continue;

#ifdef ENABLE_ITEM_GRID_MAP
						m_pointsInstant.pItemsGridMap[p] = 0;
#else
						m_pointsInstant.bItemGrid[p] = 0;
#endif
					}
				}
				else
#ifdef ENABLE_ITEM_GRID_MAP
					m_pointsInstant.pItemsGridMap[wCell] = 0;
#else
					m_pointsInstant.bItemGrid[wCell] = 0;
#endif
			}

			if (pItem)
			{
				if (wCell < INVENTORY_MAX_NUM)
				{
					for (int i = 0; i < pItem->GetSize(); ++i)
					{
						int p = wCell + (i * 5);

						if (p >= INVENTORY_MAX_NUM)
							continue;
                      
#ifdef ENABLE_ITEM_GRID_MAP
						m_pointsInstant.pItemsGridMap[p] = wCell + 1;
#else
						m_pointsInstant.bItemGrid[p] = wCell + 1;
#endif
					}
				}
				else
#ifdef ENABLE_ITEM_GRID_MAP
					m_pointsInstant.pItemsGridMap[wCell] = wCell + 1;
#else
					m_pointsInstant.bItemGrid[wCell] = wCell + 1;
#endif
			}

			m_pointsInstant.pItems[wCell] = pItem;
		}
		break;

	case DRAGON_SOUL_INVENTORY:
		{
			LPITEM pOld = m_pointsInstant.pDSItems[wCell];

			if (pOld)
			{
				if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
				{
					for (int i = 0; i < pOld->GetSize(); ++i)
					{
						int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);

						if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
							continue;

						if (m_pointsInstant.pDSItems[p] && m_pointsInstant.pDSItems[p] != pOld)
							continue;

						m_pointsInstant.wDSItemGrid[p] = 0;
					}
				}
				else
					m_pointsInstant.wDSItemGrid[wCell] = 0;
			}

			if (pItem)
			{
				if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
				{
					sys_err("CHARACTER::SetItem: invalid DS item cell %d", wCell);
					return;
				}

				if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
				{
					for (int i = 0; i < pItem->GetSize(); ++i)
					{
						int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);

						if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
							continue;

						m_pointsInstant.wDSItemGrid[p] = wCell + 1;
					}
				}
				else
					m_pointsInstant.wDSItemGrid[wCell] = wCell + 1;
			}

			m_pointsInstant.pDSItems[wCell] = pItem;
		}
		break;
	default:
		sys_err ("Invalid Inventory type %d", window_type);
		return;
	}

	if (GetDesc())
	{
		if (pItem)
		{
			TPacketGCItemSet pack;
			pack.header = HEADER_GC_ITEM_SET;
			pack.Cell = Cell;

			pack.count = pItem->GetCount();
			pack.vnum = pItem->GetVnum();
			pack.flags = pItem->GetFlag();
			pack.anti_flags	= pItem->GetAntiFlag();
			pack.highlight = (Cell.window_type == DRAGON_SOUL_INVENTORY);


			thecore_memcpy(pack.alSockets, pItem->GetSockets(), sizeof(pack.alSockets));
			thecore_memcpy(pack.aAttr, pItem->GetAttributes(), sizeof(pack.aAttr));

			GetDesc()->Packet(&pack, sizeof(TPacketGCItemSet));
		}
		else
		{
			TPacketGCItemDelDeprecated pack;
			pack.header = HEADER_GC_ITEM_DEL;
			pack.Cell = Cell;
			pack.count = 0;
			pack.vnum = 0;
			memset(pack.alSockets, 0, sizeof(pack.alSockets));
			memset(pack.aAttr, 0, sizeof(pack.aAttr));

			GetDesc()->Packet(&pack, sizeof(TPacketGCItemDelDeprecated));
		}
	}

	if (pItem)
	{
		pItem->SetCell(this, wCell);
		switch (window_type)
		{
		case INVENTORY:
		case EQUIPMENT:
			if ((wCell < INVENTORY_MAX_NUM) || (BELT_INVENTORY_SLOT_START <= wCell && BELT_INVENTORY_SLOT_END > wCell))
				pItem->SetWindow(INVENTORY);
			else
				pItem->SetWindow(EQUIPMENT);
			break;
		case DRAGON_SOUL_INVENTORY:
			pItem->SetWindow(DRAGON_SOUL_INVENTORY);
			break;
		}
	}
}

#ifdef ENABLE_ITEM_GRID_MAP
BYTE CHARACTER::ItemGridMapGetConst(BYTE cell_index) const
{
	auto it = m_pointsInstant.pItemsGridMap.find(cell_index);

	if (it != m_pointsInstant.pItemsGridMap.end())
	{
		return it->second;
	}
	else
	{
		return 0;
	}
}
#endif
  
//in char_item.cpp replace function CHARACTER::IsEmptyItemGrid with

bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) const
{
	switch (Cell.window_type)
	{
	case INVENTORY:
		{
			BYTE bCell = Cell.cell;

			++iExceptionCell;

			if (Cell.IsBeltInventoryPosition())
			{
				LPITEM beltItem = GetWear(WEAR_BELT);

				if (NULL == beltItem)
					return false;

				if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0)))
					return false;

#ifdef ENABLE_ITEM_GRID_MAP
				if (ItemGridMapGetConst(bCell))
				{
					if (ItemGridMapGetConst(bCell) == iExceptionCell)
						return true;

					return false;
				}
#else
				if (m_pointsInstant.bItemGrid[bCell])
				{
					if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
						return true;

					return false;
				}
#endif

				if (bSize == 1)
					return true;

			}
			else if (bCell >= INVENTORY_MAX_NUM)
				return false;
#ifdef ENABLE_ITEM_GRID_MAP
			if (ItemGridMapGetConst(bCell))
			{
				if (ItemGridMapGetConst(bCell) == iExceptionCell)
#else
			if (m_pointsInstant.bItemGrid[bCell])
			{
				if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
#endif
				{
					if (bSize == 1)
						return true;

					int j = 1;
					BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2);

					do
					{
						BYTE p = bCell + (5 * j);

						if (p >= INVENTORY_MAX_NUM)
							return false;

						if (p / (INVENTORY_MAX_NUM / 2) != bPage)
							return false;

#ifdef ENABLE_ITEM_GRID_MAP
						if (ItemGridMapGetConst(p))
							if (ItemGridMapGetConst(p) != iExceptionCell)
								return false;
#else
						if (m_pointsInstant.bItemGrid[p])
							if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
								return false;
#endif	
					}
					while (++j < bSize);

					return true;
				}
				else
					return false;
			}

			if (1 == bSize)
				return true;
			else
			{
				int j = 1;
				BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2);

				do
				{
					BYTE p = bCell + (5 * j);

					if (p >= INVENTORY_MAX_NUM)
						return false;

					if (p / (INVENTORY_MAX_NUM / 2) != bPage)
						return false;

#ifdef ENABLE_ITEM_GRID_MAP
					if (ItemGridMapGetConst(p))
						if (ItemGridMapGetConst(p) != iExceptionCell)
							return false;
#else
					if (m_pointsInstant.bItemGrid[p])
						if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
							return false;
#endif
				}
				while (++j < bSize);

				return true;
			}
		}
		break;
	case DRAGON_SOUL_INVENTORY:
		{
			WORD wCell = Cell.cell;
			if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
				return false;

			iExceptionCell++;

			if (m_pointsInstant.wDSItemGrid[wCell])
			{
				if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell)
				{
					if (bSize == 1)
						return true;

					int j = 1;

					do
					{
						BYTE p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);

						if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
							return false;

						if (m_pointsInstant.wDSItemGrid[p])
							if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
								return false;
					}
					while (++j < bSize);

					return true;
				}
				else
					return false;
			}

			if (1 == bSize)
				return true;
			else
			{
				int j = 1;

				do
				{
					BYTE p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);

					if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
						return false;

#ifdef ENABLE_ITEM_GRID_MAP
					if (ItemGridMapGetConst(p))
#else
					if (m_pointsInstant.bItemGrid[p])
#endif
						if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
							return false;
				}
				while (++j < bSize);

				return true;
			}
		}
	}
}

 

Edited by VegaS™
added spoiler
  • Metin2 Dev 10
  • Good 6
  • Love 9
Link to comment
Share on other sites

  • Forum Moderator
50 minutes ago, Lead0b110010100 said:

I tested it and got like 44% RAM usage reduction. But I had to do some changes in order to not get exceptions when running the server on windows. (Due to unintialized usage of map) + I changed way more lines of code to do that, but the idea is absolutely correct.

 

260105p6Utzb9.gif

 

  • Lmao 4
  • Love 1

Gurgarath
coming soon

Link to comment
Share on other sites

1 hour ago, Lead0b110010100 said:

L'ho testato e ho ottenuto una riduzione dell'utilizzo della RAM del 44%. Ma ho dovuto apportare alcune modifiche per non ottenere eccezioni durante l'esecuzione del server su Windows. (A causa dell'uso non inizializzato della mappa) + Ho cambiato molte più righe di codice per farlo, ma l'idea è assolutamente corretta.

Can you post the changes you made?

Link to comment
Share on other sites

20 hours ago, Hik said:

Can you post the changes you made?

Okay? No problem:

Spoiler
From 00c973263a61583dceede12f790312434ac69fed Mon Sep 17 00:00:00 2001
From: Lead0b110010100 <Lead0b110010100@outlook.com>
Date: Sat, 23 Oct 2021 14:21:15 +0200
Subject: [PATCH] Squashed commit of the following:

commit ba3633233cf2e6bd08664c5cfab93155bc1ce05d
Author: Lead0b110010100 <Lead0b110010100@outlook.com>
Date:   Sat Oct 23 14:18:01 2021 +0200

    Refactoring.

commit 2328c9c4e7336eb2bf6428206ab2aedc2a50f343
Author: Lead0b110010100 <Lead0b110010100@outlook.com>
Date:   Sat Oct 23 14:00:06 2021 +0200

    Improve performants by changing char array with map.

commit cb1c00629cd21f4c0bfb9cc79ca2a322013fce7e
Author: Lead0b110010100 <Lead0b110010100@outlook.com>
Date:   Sat Oct 23 13:28:54 2021 +0200

    Improve performants by changing char array with map.

commit af1e5bee7838815de735e9e280ece47aceb54f8c
Author: Lead0b110010100 <Lead0b110010100@outlook.com>
Date:   Sat Oct 23 13:14:57 2021 +0200

    Improve performants by changing char array with map.

commit 125bc19585cf904e8f40fcb687dbd0b3730ad13a
Author: Lead0b110010100 <Lead0b110010100@outlook.com>
Date:   Sat Oct 23 12:45:01 2021 +0200

    Improve performants by changing char array with map.
---
 Server/game/src/char.cpp      |   6 +-
 Server/game/src/char.h        |  35 ++++++---
 Server/game/src/char_item.cpp | 134 +++++++++++++++++++++++++---------
 3 files changed, 125 insertions(+), 50 deletions(-)

diff --git a/Server/game/src/char.cpp b/Server/game/src/char.cpp
index 246ea710..475888e5 100644
--- a/Server/game/src/char.cpp
+++ b/Server/game/src/char.cpp
@@ -322,7 +322,7 @@ void CHARACTER::Initialize()
 	m_pkChrSyncOwner = NULL;
 
 	memset(&m_points, 0, sizeof(m_points));
-	memset(&m_pointsInstant, 0, sizeof(m_pointsInstant));
+	m_pointsInstant = {};
 	memset(&m_quickslot, 0, sizeof(m_quickslot));
 
 	m_bCharType = CHAR_TYPE_MONSTER;
@@ -9075,12 +9075,12 @@ bool CHARACTER::HasGroupMemberInParty() const
 
 LPITEM CHARACTER::GetSwitchbotItem(uint8_t slot)
 {
-	return m_pointsInstant.pSwitchbotItems[slot];
+	return GetSwitchbotItemFromGrid(slot);
 }
 
 LPITEM CHARACTER::GetSoulshieldItem(uint8_t slot)
 {
-	return m_pointsInstant.pItems[SOULSHIELD_EQUIP_SLOT_START + slot];
+	return GetItemFromGrid(SOULSHIELD_EQUIP_SLOT_START + slot);
 }
 
 LPITEM CHARACTER::GetSafeboxItem(uint16_t slot)
diff --git a/Server/game/src/char.h b/Server/game/src/char.h
index 5a6e0f6a..5c185a2c 100644
--- a/Server/game/src/char.h
+++ b/Server/game/src/char.h
@@ -225,6 +225,15 @@ typedef struct character_point
 /* 저장되지 않는 캐릭터 데이터 */
 typedef struct character_point_instant
 {
+	character_point_instant() : points(), fRot(0.0f), iMaxHP(0), iMaxSP(0), position(0),
+		instant_flag(0), dwAIFlag(0), dwImmuneFlag(0), dwLastShoutPulse(0), parts(),
+		pItems(), pItemGrid(), pExtraItems(), pExtraItemGrid(), pSwitchbotItems(),
+		pCubeNpc(nullptr), battle_victim(nullptr), gm_level(GM_PLAYER),
+		bBasePart(PART_MAIN), iMaxStamina(0), pWardrobeItems(), wardrobeIsLoaded(false),
+		isWardrobeItemUnequiping(0), wardrobeCount(0)
+	{
+	};
+
 	GoldType points[POINT_MAX_NUM];
 
 	float fRot;
@@ -245,20 +254,17 @@ typedef struct character_point_instant
 	// char는 인벤을 uint8_t array로 grid를 관리하고, exchange나 cube는 CGrid로 grid를 관리하고 뭐냐 이거...
 	// grid를 만들어 놨으면 grid를 쓰란 말이야!!!
 	// ㅅㅂ 용혼석 인벤을 똑같이 따라서 만든 나도 잘못했다 ㅠㅠ
-	LPITEM pItems[INVENTORY_AND_EQUIP_SLOT_MAX];
-	uint8_t bItemGrid[INVENTORY_AND_EQUIP_SLOT_MAX];
+	std::map<uint16_t, LPITEM> pItems;
+	std::map<uint8_t, uint8_t> pItemGrid;
 
-	LPITEM pExtraItems[EXTRA_INVENTORY_MAX_NUM];
-	uint16_t wExtraItemGrid[EXTRA_INVENTORY_MAX_NUM];
+	std::map<uint16_t, LPITEM> pExtraItems;
+	std::map<uint16_t, uint16_t> pExtraItemGrid;
 
 #ifdef ENABLE_SWITCHBOT
-	LPITEM pSwitchbotItems[SWITCHBOT_SLOT_COUNT];
+	std::map<uint16_t, LPITEM> pSwitchbotItems;
 #endif
 
-	// by mhh
-	LPITEM pCubeItems[CUBE_MAX_NUM];
 	LPCHARACTER pCubeNpc;
-
 	LPCHARACTER battle_victim;
 
 	uint8_t gm_level;
@@ -268,7 +274,7 @@ typedef struct character_point_instant
 	int32_t iMaxStamina;
 
 #ifdef ENABLE_WARDROBE
-	LPITEM			pWardrobeItems[WARDROBE_SLOT_COUNT];
+	std::map<uint16_t, LPITEM> pWardrobeItems;
 	bool			wardrobeIsLoaded;
 	int32_t				isWardrobeItemUnequiping;
 	int32_t				wardrobeCount;
@@ -1022,6 +1028,15 @@ public:
 	void SetItem(TItemPos Cell, LPITEM item);
 	LPITEM GetItem(TItemPos Cell) const;
 	LPITEM GetInventoryItem(ItemCellType wCell) const;
+
+	ItemCellType GetFromItemGrid(ItemCellType cell) const;
+	ItemCellType GetFromExtraItemGrid(ItemCellType cell) const;
+
+	LPITEM GetItemFromGrid(ItemStackType cell) const;
+	LPITEM GetExtraItemFromGrid(ItemStackType cell) const;
+	LPITEM GetSwitchbotItemFromGrid(ItemStackType cell) const;
+	LPITEM GetWardrobeItemFromGrid(ItemStackType cell) const;
+
 	bool IsEmptyItemGrid(TItemPos Cell, uint8_t size, int32_t iExceptionCell = -1) const;
 
 	LPITEM GetExtraInventoryItem(ItemCellType wCell) const;
@@ -1889,8 +1904,6 @@ public:
 public:
 	bool ItemProcess_Polymorph(LPITEM item);
 
-	// by mhh
-	LPITEM *GetCubeItem() { return m_pointsInstant.pCubeItems; }
 	bool IsCubeOpen() const { return (m_pointsInstant.pCubeNpc ? true : false); }
 	void SetCubeNpc(LPCHARACTER npc) { m_pointsInstant.pCubeNpc = npc; }
 	LPCHARACTER GetCubeNpc() { return m_pointsInstant.pCubeNpc; }
diff --git a/Server/game/src/char_item.cpp b/Server/game/src/char_item.cpp
index 9d92abd5..8a0e5cfe 100644
--- a/Server/game/src/char_item.cpp
+++ b/Server/game/src/char_item.cpp
@@ -248,14 +248,14 @@ LPITEM CHARACTER::GetItem(TItemPos Cell) const
 			sys_err("CHARACTER::GetInventoryItem: invalid item cell %d", wCell);
 			return NULL;
 		}
-		return m_pointsInstant.pItems[wCell];
+		return GetItemFromGrid(wCell);
 	case EXTRA_INVENTORY:
 		if (wCell >= EXTRA_INVENTORY_MAX_NUM)
 		{
 			sys_err("CHARACTER::GetInventoryItem: invalid EXTRA item cell %d", wCell);
 			return NULL;
 		}
-		return m_pointsInstant.pExtraItems[wCell];
+		return GetExtraItemFromGrid(wCell);
 #ifdef ENABLE_SWITCHBOT
 	case SWITCHBOT:
 		if (wCell >= SWITCHBOT_SLOT_COUNT)
@@ -263,7 +263,7 @@ LPITEM CHARACTER::GetItem(TItemPos Cell) const
 			sys_err("CHARACTER::GetInventoryItem: invalid switchbot item cell %d", wCell);
 			return NULL;
 		}
-		return m_pointsInstant.pSwitchbotItems[wCell];
+		return GetSwitchbotItemFromGrid(wCell);
 #endif
 #ifdef ENABLE_WARDROBE
 	case WARDROBE:
@@ -272,7 +272,7 @@ LPITEM CHARACTER::GetItem(TItemPos Cell) const
 			sys_err("CHARACTER::GetInventoryItem: invalid wardrobe item cell %d", wCell);
 			return NULL;
 		}
-		return m_pointsInstant.pWardrobeItems[wCell];
+		return GetWardrobeItemFromGrid(wCell);
 #endif
 
 	default:
@@ -309,7 +309,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 			return;
 		}
 
-		LPITEM pOld = m_pointsInstant.pItems[wCell];
+		LPITEM pOld = GetItemFromGrid(wCell);
 
 		if (pOld)
 		{
@@ -322,14 +322,14 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 					if (p >= INVENTORY_MAX_NUM)
 						continue;
 
-					if (m_pointsInstant.pItems[p] && m_pointsInstant.pItems[p] != pOld)
+					if (GetItemFromGrid(p) && GetItemFromGrid(p) != pOld)
 						continue;
 
-					m_pointsInstant.bItemGrid[p] = 0;
+					m_pointsInstant.pItemGrid[p] = 0;
 				}
 			}
 			else
-				m_pointsInstant.bItemGrid[wCell] = 0;
+				m_pointsInstant.pItemGrid[wCell] = 0;
 		}
 
 		if (pItem)
@@ -345,11 +345,11 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 
 					// wCell + 1 로 하는 것은 빈곳을 체크할 때 같은
 					// 아이템은 예외처리하기 위함
-					m_pointsInstant.bItemGrid[p] = wCell + 1;
+					m_pointsInstant.pItemGrid[p] = wCell + 1;
 				}
 			}
 			else
-				m_pointsInstant.bItemGrid[wCell] = wCell + 1;
+				m_pointsInstant.pItemGrid[wCell] = wCell + 1;
 		}
 
 		m_pointsInstant.pItems[wCell] = pItem;
@@ -364,7 +364,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 			return;
 		}
 
-		LPITEM pOld = m_pointsInstant.pExtraItems[wCell];
+		LPITEM pOld = GetExtraItemFromGrid(wCell);
 
 		if (pOld)
 		{
@@ -375,10 +375,10 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 				if (p >= EXTRA_INVENTORY_MAX_NUM)
 					continue;
 
-				if (m_pointsInstant.pExtraItems[p] && m_pointsInstant.pExtraItems[p] != pOld)
+				if (GetExtraItemFromGrid(p) && GetExtraItemFromGrid(p) != pOld)
 					continue;
 
-				m_pointsInstant.wExtraItemGrid[p] = 0;
+				m_pointsInstant.pExtraItemGrid[p] = 0;
 			}
 		}
 
@@ -391,7 +391,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 				if (p >= EXTRA_INVENTORY_MAX_NUM)
 					continue;
 
-				m_pointsInstant.wExtraItemGrid[p] = wCell + 1;
+				m_pointsInstant.pExtraItemGrid[p] = wCell + 1;
 			}
 		}
 
@@ -402,7 +402,8 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 #ifdef ENABLE_SWITCHBOT
 	case SWITCHBOT:
 	{
-		LPITEM pOld = m_pointsInstant.pSwitchbotItems[wCell];
+		LPITEM pOld = GetSwitchbotItemFromGrid(wCell);
+
 		if (pItem && pOld)
 		{
 			return;
@@ -528,7 +529,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
 		if (m_pointsInstant.isWardrobeItemUnequiping > 0)
 		{
 			int32_t pos = m_pointsInstant.isWardrobeItemUnequiping - 1;
-			LPITEM item = m_pointsInstant.pWardrobeItems[pos];
+			LPITEM item = GetWardrobeItemFromGrid(pos);
 
 			m_pointsInstant.isWardrobeItemUnequiping = -1;
 			pItem->RemoveFromCharacter();
@@ -548,7 +549,7 @@ LPITEM CHARACTER::GetWear(ItemCellType bCell) const
 		return NULL;
 	}
 
-	return m_pointsInstant.pItems[INVENTORY_MAX_NUM + bCell];
+	return GetItemFromGrid(INVENTORY_MAX_NUM + bCell);
 }
 
 void CHARACTER::SetWear(ItemCellType bCell, LPITEM item)
@@ -606,7 +607,7 @@ void CHARACTER::ClearItem()
 #endif
 #ifdef ENABLE_WARDROBE
 	for (i = 0; i < WARDROBE_SLOT_COUNT; i++) {
-		item = m_pointsInstant.pWardrobeItems[i];
+		item = GetWardrobeItemFromGrid(i);
 
 		if (item != nullptr) {
 			item->SetSkipSave(true);
@@ -635,9 +636,9 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 		if (bCell >= INVENTORY_MAX_NUM)
 			return false;
 
-		if (m_pointsInstant.bItemGrid[bCell])
+		if (GetFromItemGrid(bCell))
 		{
-			if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
+			if (GetFromItemGrid(bCell) == iExceptionCell)
 			{
 				if (bSize == 1)
 					return true;
@@ -655,8 +656,8 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 					if (p / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT) != bPage)
 						return false;
 
-					if (m_pointsInstant.bItemGrid[p])
-						if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
+					if (GetFromItemGrid(p))
+						if (GetFromItemGrid(p) != iExceptionCell)
 							return false;
 				} while (++j < bSize);
 
@@ -684,8 +685,8 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 				if (p / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT) != bPage)
 					return false;
 
-				if (m_pointsInstant.bItemGrid[p])
-					if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
+				if (GetFromItemGrid(p))
+					if (GetFromItemGrid(p) != iExceptionCell)
 						return false;
 			} while (++j < bSize);
 
@@ -703,9 +704,9 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 
 		++iExceptionCell;
 
-		if (m_pointsInstant.wExtraItemGrid[bCell])
+		if (GetFromExtraItemGrid(bCell))
 		{
-			if (m_pointsInstant.wExtraItemGrid[bCell] == iExceptionCell)
+			if (GetFromExtraItemGrid(bCell) == iExceptionCell)
 			{
 				if (bSize == 1)
 					return true;
@@ -723,8 +724,8 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 					if (p / (EXTRA_INVENTORY_MAX_NUM / EXTRA_INVENTORY_PAGE_COUNT) != bPage)
 						return false;
 
-					if (m_pointsInstant.wExtraItemGrid[p])
-						if (m_pointsInstant.wExtraItemGrid[p] != iExceptionCell)
+					if (GetFromExtraItemGrid(p))
+						if (GetFromExtraItemGrid(p) != iExceptionCell)
 							return false;
 				} while (++j < bSize);
 
@@ -751,8 +752,8 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 				if (p / (EXTRA_INVENTORY_MAX_NUM / EXTRA_INVENTORY_PAGE_COUNT) != bPage)
 					return false;
 
-				if (m_pointsInstant.wExtraItemGrid[p])
-					if (m_pointsInstant.wExtraItemGrid[p] != iExceptionCell)
+				if (GetFromExtraItemGrid(p))
+					if (GetFromExtraItemGrid(p) != iExceptionCell)
 						return false;
 			} while (++j < bSize);
 
@@ -765,12 +766,13 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 	case SWITCHBOT:
 	{
 		ItemCellType wCell = Cell.cell;
+
 		if (wCell >= SWITCHBOT_SLOT_COUNT)
 		{
 			return false;
 		}
 
-		if (m_pointsInstant.pSwitchbotItems[wCell])
+		if (GetSwitchbotItemFromGrid(wCell))
 		{
 			return false;
 		}
@@ -782,12 +784,12 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, uint8_t bSize, int32_t iException
 #ifdef ENABLE_WARDROBE
 	case WARDROBE:
 	{
-		uint16_t wCell = Cell.cell;
+		ItemStackType wCell = Cell.cell;
 
 		if (wCell >= WARDROBE_SLOT_COUNT)
 			return false;
 
-		return m_pointsInstant.pWardrobeItems[wCell] == nullptr;
+		return !GetWardrobeItemFromGrid(wCell);
 	}
 #endif
 	}
@@ -8718,7 +8720,7 @@ void CHARACTER::CombineShards(LPITEM shard1, LPITEM shard2)
 int32_t CHARACTER::GetEmptyWardrobeSlot() const
 {
 	for (int32_t i = 0; i < WARDROBE_HIDDEN_SLOT_COUNT; i++)
-		if (!m_pointsInstant.pWardrobeItems[i])
+		if (!GetWardrobeItemFromGrid(i))
 			return i;
 
 	return -1;
@@ -8728,7 +8730,7 @@ int32_t CHARACTER::GetWardrobeRewardSlot(uint32_t dwItemVnum) const
 {
 	for (int32_t i = 0; i < WARDROBE_HIDDEN_SLOT_COUNT; i++)
 	{
-		LPITEM item = m_pointsInstant.pWardrobeItems[i];
+		LPITEM item = GetWardrobeItemFromGrid(i);
 
 		if (item && item->GetVnum() == dwItemVnum)
 			return i;
@@ -8743,7 +8745,7 @@ int32_t CHARACTER::GetWardrobeSlot(uint32_t dwItemVnum) const
 
 	for (int32_t i = WARDROBE_HIDDEN_SLOT_COUNT; i < WARDROBE_SLOT_COUNT; i++)
 	{
-		LPITEM item = m_pointsInstant.pWardrobeItems[i];
+		LPITEM item = GetWardrobeItemFromGrid(i);
 
 		if (item == nullptr)
 		{
@@ -8930,3 +8932,63 @@ void CHARACTER::AbsorbAutopotionsInClipping(const TItemPos& pos)
 
 	ChatPacketTrans(CHAT_TYPE_INFO, "Es wurden %d Autopots absorbiert!", count);
 }
+
+ItemCellType CHARACTER::GetFromItemGrid(ItemCellType cell) const
+{
+	const auto& it = m_pointsInstant.pItemGrid.find(cell);
+
+	if (it == m_pointsInstant.pItemGrid.end())
+		return 0;
+
+	return it->second;
+}
+
+ItemCellType CHARACTER::GetFromExtraItemGrid(ItemCellType cell) const
+{
+	const auto& it = m_pointsInstant.pExtraItemGrid.find(cell);
+
+	if (it == m_pointsInstant.pExtraItemGrid.end())
+		return 0;
+
+	return it->second;
+}
+
+LPITEM CHARACTER::GetItemFromGrid(ItemStackType cell) const
+{
+	const auto& it = m_pointsInstant.pItems.find(cell);
+
+	if (it == m_pointsInstant.pItems.end())
+		return nullptr;
+
+	return it->second;
+}
+
+LPITEM CHARACTER::GetExtraItemFromGrid(ItemStackType cell) const
+{
+	const auto& it = m_pointsInstant.pExtraItems.find(cell);
+
+	if (it == m_pointsInstant.pExtraItems.end())
+		return nullptr;
+
+	return it->second;
+}
+
+LPITEM CHARACTER::GetSwitchbotItemFromGrid(ItemStackType cell) const
+{
+	const auto& it = m_pointsInstant.pSwitchbotItems.find(cell);
+
+	if (it == m_pointsInstant.pSwitchbotItems.end())
+		return nullptr;
+
+	return it->second;
+}
+
+LPITEM CHARACTER::GetWardrobeItemFromGrid(ItemStackType cell) const
+{
+	const auto& it = m_pointsInstant.pWardrobeItems.find(cell);
+
+	if (it == m_pointsInstant.pWardrobeItems.end())
+		return nullptr;
+
+	return it->second;
+}
-- 
2.33.1.windows.1

 

Edited by VegaS™
added spoiler
  • Metin2 Dev 1
  • Good 2
  • Love 1
Link to comment
Share on other sites

Did anyone test the impact on cpu usage or the time needed for the execution of the functions? The usage of a ordered std::map should be (in theory) way slower.

ATM I moved the fixed sized arrays into a new struct and added a shared_ptr as member variable to the CHARACTER class. When "SetPlayerProto" gets called I'll create a shared_ptr of the new struct. - Which ofc means I wont save any memory for players which don't use all slots.

In idle (without players) this results in a drop from 1480mb to 540mb ram per channel -> ~64% less ramusage.

Link to comment
Share on other sites

1 hour ago, Cysgod said:

Did anyone test the impact on cpu usage or the time needed for the execution of the functions? The usage of a ordered std::map should be (in theory) way slower.

ATM I moved the fixed sized arrays into a new struct and added a shared_ptr as member variable to the CHARACTER class. When "SetPlayerProto" gets called I'll create a shared_ptr of the new struct. - Which ofc means I wont save any memory for players which don't use all slots.

In idle (without players) this results in a drop from 1480mb to 540mb ram per channel -> ~64% less ramusage.

You ware totally right, I replaced std::map with std::unordered_map here.

Link to comment
Share on other sites

These operations give game.core. Game gives core on loading screen.

No wrong additions. Everything is correct. There was no kernel crash prior to doing this action.

char.h 

#ifdef ENABLE_ITEM_GRID_MAP
    std::unordered_map<BYTE, BYTE> pItemsGridMap;
#else
    BYTE            bItemGrid[INVENTORY_AND_EQUIP_SLOT_MAX];
#endif

and 

    LPITEM            GetInventoryItem(WORD wCell) const;
#ifdef ENABLE_ITEM_GRID_MAP
    BYTE            ItemGridMapGetConst(BYTE cell_index) const;
#endif


char_item.cpp


 

bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) const
{
	switch (Cell.window_type)
	{
	case INVENTORY:
	{
		WORD bCell = Cell.cell;

		++iExceptionCell;

		if (Cell.IsBeltInventoryPosition())
		{
			LPITEM beltItem = GetWear(WEAR_BELT);

			if (NULL == beltItem)
				return false;

			if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0)))
				return false;

#ifdef ENABLE_ITEM_GRID_MAP
			if (ItemGridMapGetConst(bCell))
			{
				if (ItemGridMapGetConst(bCell) == iExceptionCell)
					return true;

				return false;
			}
#else
			if (m_pointsInstant.bItemGrid[bCell])
			{
				if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
					return true;

				return false;
			}
#endif

			if (bSize == 1)
				return true;
		}
		else if (bCell >= INVENTORY_MAX_NUM)
			return false;

#ifdef ENABLE_ITEM_GRID_MAP
		if (ItemGridMapGetConst(bCell))
		{
			if (ItemGridMapGetConst(bCell) == iExceptionCell)
#else
		if (m_pointsInstant.bItemGrid[bCell])
		{
			if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
#endif
			{
				if (bSize == 1)
					return true;

				int j = 1;
				BYTE bPage = bCell / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT);

				do
				{
					BYTE p = bCell + (5 * j);

					if (p >= INVENTORY_MAX_NUM)
						return false;

					if (p / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT) != bPage)
						return false;

#ifdef ENABLE_ITEM_GRID_MAP
					if (ItemGridMapGetConst(p))
						if (ItemGridMapGetConst(p) != iExceptionCell)
							return false;
#else
					if (m_pointsInstant.bItemGrid[p])
						if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
							return false;
#endif
				} while (++j < bSize);

				return true;
			}
			else
				return false;
		}

		if (1 == bSize)
			return true;
		else
		{
			int j = 1;
			BYTE bPage = bCell / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT);

			do
			{
				BYTE p = bCell + (5 * j);

				if (p >= INVENTORY_MAX_NUM)
					return false;

				if (p / (INVENTORY_MAX_NUM / INVENTORY_PAGE_COUNT) != bPage)
					return false;

#ifdef ENABLE_ITEM_GRID_MAP
				if (ItemGridMapGetConst(p))
					if (ItemGridMapGetConst(p) != iExceptionCell)
						return false;
#else
				if (m_pointsInstant.bItemGrid[p])
					if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
						return false;
#endif
			} while (++j < bSize);

			return true;
		}
	}
	break;
	case DRAGON_SOUL_INVENTORY:
	{
		WORD wCell = Cell.cell;
		if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
			return false;

		iExceptionCell++;

		if (m_pointsInstant.wDSItemGrid[wCell])
		{
			if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell)
			{
				if (bSize == 1)
					return true;

				int j = 1;

				do
				{
					int p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);

					if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
						return false;

#ifdef ENABLE_ITEM_GRID_MAP
					if (ItemGridMapGetConst(p))
#else
					if (m_pointsInstant.bItemGrid[p])
#endif
						if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
							return false;
				} while (++j < bSize);

				return true;
			}
			else
				return false;
		}

		if (1 == bSize)
			return true;
		else
		{
			int j = 1;

			do
			{
				int p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);

				if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
					return false;

#ifdef ENABLE_ITEM_GRID_MAP
				if (ItemGridMapGetConst(p))
#else
				if (m_pointsInstant.bItemGrid[p])
#endif
					if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
						return false;
			} while (++j < bSize);

			return true;
		}
	}
	break;
void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
#endif
{
	WORD wCell = Cell.cell;
	BYTE window_type = Cell.window_type;
	if ((unsigned long)((CItem*)pItem) == 0xff || (unsigned long)((CItem*)pItem) == 0xffffffff)
	{
		sys_err("!!! FATAL ERROR !!! item == 0xff (char: %s cell: %u)", GetName(), wCell);
		core_dump();
		return;
	}

	if (pItem && pItem->GetOwner())
	{
		assert(!"GetOwner exist");
		return;
	}

	switch (window_type)
	{
	case INVENTORY:
	case EQUIPMENT:
	{
		if (wCell >= INVENTORY_AND_EQUIP_SLOT_MAX)
		{
			sys_err("CHARACTER::SetItem: invalid item cell %d", wCell);
			return;
		}

		LPITEM pOld = m_pointsInstant.pItems[wCell];

		if (pOld)
		{
			if (wCell < INVENTORY_MAX_NUM)
			{
				for (int i = 0; i < pOld->GetSize(); ++i)
				{
					int p = wCell + (i * 5);

					if (p >= INVENTORY_MAX_NUM)
						continue;

					if (m_pointsInstant.pItems[p] && m_pointsInstant.pItems[p] != pOld)
						continue;

#ifdef ENABLE_ITEM_GRID_MAP
					m_pointsInstant.pItemsGridMap[p] = 0;
#else
					m_pointsInstant.bItemGrid[p] = 0;
#endif
				}
			}
			else
#ifdef ENABLE_ITEM_GRID_MAP
				m_pointsInstant.pItemsGridMap[wCell] = 0;
#else
				m_pointsInstant.bItemGrid[wCell] = 0;
#endif
		}

		if (pItem)
		{
			if (wCell < INVENTORY_MAX_NUM)
			{
				for (int i = 0; i < pItem->GetSize(); ++i)
				{
					int p = wCell + (i * 5);

					if (p >= INVENTORY_MAX_NUM)
						continue;

#ifdef ENABLE_ITEM_GRID_MAP
					m_pointsInstant.pItemsGridMap[p] = wCell + 1;
#else
					m_pointsInstant.bItemGrid[p] = wCell + 1;
#endif
				}
			}
			else
#ifdef ENABLE_ITEM_GRID_MAP
				m_pointsInstant.pItemsGridMap[wCell] = wCell + 1;
#else
				m_pointsInstant.bItemGrid[wCell] = wCell + 1;
#endif
		}

		m_pointsInstant.pItems[wCell] = pItem;
	}
	break;

	case DRAGON_SOUL_INVENTORY:
	{
		LPITEM pOld = m_pointsInstant.pDSItems[wCell];

		if (pOld)
		{
			if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
			{
				for (int i = 0; i < pOld->GetSize(); ++i)
				{
					int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);

					if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
						continue;

					if (m_pointsInstant.pDSItems[p] && m_pointsInstant.pDSItems[p] != pOld)
						continue;

					m_pointsInstant.wDSItemGrid[p] = 0;
				}
			}
			else
				m_pointsInstant.wDSItemGrid[wCell] = 0;
		}

		if (pItem)
		{
			if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
			{
				sys_err("CHARACTER::SetItem: invalid DS item cell %d", wCell);
				return;
			}

			if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
			{
				for (int i = 0; i < pItem->GetSize(); ++i)
				{
					int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);

					if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
						continue;

					m_pointsInstant.wDSItemGrid[p] = wCell + 1;
				}
			}
			else
				m_pointsInstant.wDSItemGrid[wCell] = wCell + 1;
		}

		m_pointsInstant.pDSItems[wCell] = pItem;
	}
	break;
#ifdef ENABLE_ITEM_GRID_MAP
BYTE CHARACTER::ItemGridMapGetConst(BYTE cell_index) const
{
	auto it = m_pointsInstant.pItemsGridMap.find(cell_index);

	if (it != m_pointsInstant.pItemsGridMap.end())
	{
		return it->second;
	}
	else
	{
		return 0;
	}
}
#endif
#ifdef ENABLE_ITEM_GRID_MAP
	m_pointsInstant.pItemsGridMap.clear();
#endif

#ifdef ENABLE_ACCE_SYSTEM
	m_bAcceCombination = false;
	m_bAcceAbsorption = false;
#endif

 

I cleared the codes and the game opened 🙂

Link to comment
Share on other sites

  • Forum Moderator

That is a very brilliant fix! I just finished doing all the changes I could and ended up with pretty good results! I haven't fully finished yet (have to find a way for CopyDragonSoulItemGrid function), but the results so far are good.

I also noticed a bug, it can be from my side but I prefer to report it for anyone, I am sometimes unable to switch an equipment part, on my warrior it was the weapon and the helmet, on my shaman it was only the armor. It doesn't happen when I revert my changes. (Edit : Do not bother trying, it was me. I was tired != != ==)

Spoiler

Before:

unknown.png

After :

unknown.png

 

Edited by Metin2 Dev
Core X - External 2 Internal

Gurgarath
coming soon

Link to comment
Share on other sites

  • Forum Moderator
1 hour ago, Exygo said:

You can't move an item after this 😕

Make sure that all the != are respected, I got this issue at first then after a double check it worked. However it made my special inventory completely messed up, I disabled it for now.

  • Good 2

Gurgarath
coming soon

Link to comment
Share on other sites

  • Honorable Member

There are far better solutions than using std::map or std::unordered_map (which still takes a lot of ram for no reason for each mob):

(I included the most important parts)

You also forgot the CubeItems, and we could probably fit the quickslot too.

Spoiler

u6xpuP5.png

8l52tEd.png

QuAep2f.png

DyiEUfe.png

ls2VRPX.png

Edited by Metin2 Dev
Core X - External 2 Internal
  • Metin2 Dev 2
  • Good 7
  • Love 7
Link to comment
Share on other sites

25 minutes ago, martysama0134 said:

There are far better solutions than using std::map or std::unordered_map (which still takes a lot of ram for no reason for each mob):

 (I included the most important parts)

You also forgot the CubeItems, and we could probably fit the quickslot too.

That's exactly what I did. Running since 24. Oct without any problems.

Spoiler

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

6 hours ago, martysama0134 said:

There are far better solutions than using std::map or std::unordered_map (which still takes a lot of ram for no reason for each mob):

 (I included the most important parts)

You also forgot the CubeItems, and we could probably fit the quickslot too.

 

With your changes -> 430MB

Without your changes -> 775MB

thats impressiv

Spoiler

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

  • Honorable Member
1 hour ago, sxvoyz said:
void CHARACTER::Initialize()
{
	memset(&m_pointsInstant, 0, sizeof(m_pointsInstant));
}

That's why somebody got crash. Try define map/unordered_map outside this structure then everything will be alright.

You probably got a warning in that line, but the solution is even simpler:

	m_pointsInstant = {};

 

  • Good 1
  • Love 1
Link to comment
Share on other sites

Mobs should be their own entity you can reduce memory usage by partly by just allocating specific stuff just for players

but thats an extra allocation for every entity potentially several more allocations for example if you are using maps and not reserving or resizing you will end up with multiple allocations for a single map

  • Good 2
Link to comment
Share on other sites

On 11/5/2021 at 12:20 PM, martysama0134 said:

There are far better solutions than using std::map or std::unordered_map (which still takes a lot of ram for no reason for each mob):

 (I included the most important parts)

You also forgot the CubeItems, and we could probably fit the quickslot too.

Thanks, I followed the code structure you posted ?

I get some sort of warning at this line: do you know how to solve?

m_pointsInstant.playerSlots-> wDSItemGrid [wCell] = 0;

Buffer Overrun: When accessing m_pointsInstant.playerSlots-> wDSItemGrid, the non-write protected size is 1920 bytes, but it is possible to write to wcell.

 

Spoiler

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

  • 7 months later...

Announcements



×
×
  • 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.