aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 Inventory Expansion: Bag Slots and Extra Pages

Metin2 inventory expansion is one of the most requested server features: once the default bag fills up, farming, drops and storage management become painful. The key is to understand that the inventory isn't defined in a single place — the slot count lives both in the server source and on the client side, and these two values must match exactly. In this guide I walk through how to add bag slots and extra pages step by step, safely.

How the inventory works: slots, pages and the shared constant

In Metin2 the inventory is an array of slots. In the classic layout each page is made of 45 slots (9 columns × 5 rows), and the total slot count must be a multiple of the page size. The default value in most sources is 90, i.e. two pages. If you want four pages, you set the total to 180.

  • Total slots = number of pages × page size (45).
  • Slot positions (pos) start at 0; equipment slots sit in a separate block above that range.
  • If the server and client don't share the same constant, item positions shift, causing item loss and crashes.

Server side: length.h and INVENTORY_MAX_NUM

The heart of the expansion is the constant in common/length.h. There you find the total slot count and the page size:

// common/length.h
enum EInventoryConstants
{
    INVENTORY_MAX_NUM   = 90,   // 2 pages × 45  ->  set 180 for 4 pages
    INVENTORY_PAGE_SIZE = 45,
};

Change INVENTORY_MAX_NUM and make sure the value stays a clean multiple of 45. Then recompile the game binary:

cd Server/game/src
make clean && make -j$(nproc)

This constant is used in many places that validate items: IsValidItemPosition in char_item.cpp and the item move/place functions, plus the packet checks in input_main.cpp. Since they all work off INVENTORY_MAX_NUM, changing the single source is enough — you don't have to hunt down extra if statements.

Database: the item table and position checks

Items aren't stored on the player but in a separate item table; each row points to its place with the window (inventory/equipment) and pos columns. You don't need to change the schema for an expansion, because pos is already an integer field that can hold the new, larger values. Still, check two things:

  • Back up first: dump the player and item tables. A position mismatch can cause item loss.
  • Test with a test account: place items on the new pages and relog the character; confirm the new pos values (e.g. 90–179) are written correctly in the item table.

It's also wise to recompile the DB cache, because db and game share the same protocol headers.

Client source: keeping the constant in sync

The most critical rule: the client must know the same total slot count. In the client source, inventory arrays and packet structures are sized by their own constant in the UserInterface project. If you went from 90 to 180 on the server, update the same value on the client and recompile UserInterface:

// Client UserInterface (e.g. Packet.h / Locale_inc.h)
#define INVENTORY_MAX_NUM   180
#define INVENTORY_PAGE_SIZE 45

If you don't have the client source, enlarging the UI with python alone is not enough: the binary is still compiled with the old slot count, so items placed on the extra pages stay invisible or the connection gets dropped. That's why client source is mandatory for inventory expansion.

Client python: extra pages with uiInventory.py

Once the binary is compiled at the right size, it's the UI's turn. In root/uiInventory.py the inventory window is drawn with its page buttons and slot grid. Here's what to do:

  • Increase the page count: update the loop and the GetInventoryPageCount logic so the window shows the extra page buttons/tabs.
  • Compute slot positions from the player.INVENTORY_PAGE_SIZE constant; clean up any hardcoded numbers like 90.
  • If the window is too small, adjust the width/height in the .py or edit the related .sub images.

The python side only draws; the real slot limit is set by the binary. So the page count you display in python must match the compiled INVENTORY_MAX_NUM — show more and the clicks fall through to nothing.

Testing and common mistakes

After the change, always test end to end:

  • Server/client mismatch: the most common error. If the two sides are compiled with a different INVENTORY_MAX_NUM, item positions shift. Update and compile both at the same time.
  • A value that isn't a multiple of 45: the page is left half-drawn and the last rows can't be clicked. Always keep the total divisible by 45.
  • Exploit check: separate windows like pet or dragon soul also use positions; when you grow the inventory constant, verify their pos ranges don't collide.
  • A stable backup: before going live, keep a DB dump and the old binaries so your rollback path stays open.

Frequently Asked Questions

Can I expand the inventory without the client source?

No. With python you only enlarge the visuals, but the binary is compiled with the old slot count; the extra slots won't work and the mismatch with the server causes crashes. You need both the server and client source.

Will existing players lose their items?

If you increase the total slot count, the existing positions (0–89) stay in place and only new empty slots are added; no item loss. But a wrong constant or shrinking can cause loss, so dump the DB first.

Why must it be a multiple of 45?

An inventory page is 9×5 = 45 slots. If the total isn't a multiple of that, the last page is drawn incomplete and the slot indices between the UI and the binary won't match.

Want a clean, exploit-free inventory expansion in your server project? I can help with system development on both the Metin2 source and client — let's talk through your project: get in touch with me.

Bu kategorideki tüm yazılar →

Devamı için