Het uitbreiden van de Metin2-inventaris is een van de meest gevraagde serverfuncties: zodra de standaardtas vol zit, worden farmen, drops en het beheer van de opslag een pijnpunt. De sleutel is te begrijpen dat de inventaris niet op één plek wordt gedefinieerd — het aantal slots leeft zowel in de server source als aan de client-kant, en deze twee waarden moeten exact overeenkomen. In deze gids loop ik stap voor stap en veilig door hoe je tasvakken en extra pagina's toevoegt.
Hoe de inventaris werkt: slots, pagina's en de gedeelde constante
In Metin2 is de inventaris een array van slots. In de klassieke indeling bestaat elke pagina uit 45 slots (9 kolommen × 5 rijen), en het totale aantal slots moet een veelvoud van de paginagrootte zijn. De standaardwaarde in de meeste sources is 90, dus twee pagina's. Wil je vier pagina's, dan zet je het totaal op 180.
- Totaal aantal slots = aantal pagina's × paginagrootte (45).
- Slotposities (
pos) beginnen bij 0; equipment-slots zitten in een apart blok boven dat bereik. - Als de server en de client niet dezelfde constante delen, verschuiven de itemposities, wat itemverlies en crashes veroorzaakt.
Serverkant: length.h en INVENTORY_MAX_NUM
Het hart van de uitbreiding is de constante in het bestand common/length.h. Daar vind je het totale aantal slots en de paginagrootte:
// common/length.h
enum EInventoryConstants
{
INVENTORY_MAX_NUM = 90, // 2 pagina's × 45 -> zet 180 voor 4 pagina's
INVENTORY_PAGE_SIZE = 45,
};
Wijzig INVENTORY_MAX_NUM en zorg dat de waarde een net veelvoud van 45 blijft. Compileer daarna de game-binary opnieuw:
cd Server/game/src
make clean && make -j$(nproc)
Deze constante wordt op veel plekken gebruikt die items valideren: IsValidItemPosition in char_item.cpp en de functies voor het verplaatsen/plaatsen van items, plus de packetcontroles in input_main.cpp. Omdat ze allemaal op INVENTORY_MAX_NUM werken, is het aanpassen van die ene bron genoeg — je hoeft geen extra if-statements op te sporen.
Database: de item-tabel en positiecontroles
Items worden niet bij de speler opgeslagen, maar in een aparte item-tabel; elke rij wijst zijn plek aan met de kolommen window (inventaris/equipment) en pos. Je hoeft het schema niet te wijzigen voor een uitbreiding, want pos is al een integer-veld dat de nieuwe, grotere waarden aankan. Controleer toch twee dingen:
- Maak eerst een back-up: dump de tabellen
playerenitem. Een positiemismatch kan itemverlies veroorzaken. - Test met een testaccount: plaats items op de nieuwe pagina's en relog het personage; controleer of de nieuwe
pos-waarden (bijv. 90–179) correct in deitem-tabel staan.
Het is ook verstandig de DB-cache opnieuw te compileren, omdat db en game dezelfde protocolheaders delen.
Client source: de constante synchroon houden
De meest kritieke regel: de client moet hetzelfde totale aantal slots kennen. In de client source worden inventaris-arrays en packetstructuren gedimensioneerd door hun eigen constante in het UserInterface-project. Ging je op de server van 90 naar 180, werk dan dezelfde waarde op de client bij en compileer UserInterface opnieuw:
// Client UserInterface (bijv. Packet.h / Locale_inc.h)
#define INVENTORY_MAX_NUM 180
#define INVENTORY_PAGE_SIZE 45
Heb je de client source niet, dan is de UI alleen met python vergroten niet genoeg: de binary is nog gecompileerd met het oude aantal slots, dus items die op de extra pagina's worden geplaatst blijven onzichtbaar of de verbinding wordt verbroken. Daarom is de client source onmisbaar voor een inventaris-uitbreiding.
Client python: extra pagina's met uiInventory.py
Zodra de binary op de juiste grootte is gecompileerd, is de UI aan de beurt. In root/uiInventory.py wordt het inventarisvenster getekend met zijn paginaknoppen en slotgrid. Dit moet je doen:
- Verhoog het aantal pagina's: werk de loop en de
GetInventoryPageCount-logica bij zodat het venster de extra paginaknoppen/tabs toont. - Bereken slotposities op basis van de constante
player.INVENTORY_PAGE_SIZE; ruim hardgecodeerde getallen zoals 90 op. - Is het venster te klein, pas dan de breedte/hoogte in de
.pyaan of bewerk de bijbehorende.sub-afbeeldingen.
De python-kant tekent alleen; de echte slotlimiet wordt door de binary bepaald. Het aantal pagina's dat je in python toont, moet dus overeenkomen met de gecompileerde INVENTORY_MAX_NUM — toon je er meer, dan vallen de kliks in het niets.
Testen en veelgemaakte fouten
Test na de wijziging altijd van begin tot eind:
- Server/client-mismatch: de meest voorkomende fout. Zijn beide kanten met een verschillende
INVENTORY_MAX_NUMgecompileerd, dan verschuiven de itemposities. Werk beide tegelijk bij en compileer ze. - Een waarde die geen veelvoud van 45 is: de pagina blijft half getekend en de laatste rijen zijn niet klikbaar. Houd het totaal altijd deelbaar door 45.
- Exploitcontrole: aparte vensters zoals pet of dragon soul gebruiken ook posities; controleer bij het vergroten van de inventarisconstante of hun pos-bereiken niet botsen.
- Een stabiele back-up: bewaar vóór de livegang een DB-dump en de oude binaries, zodat je rollback-pad open blijft.
Veelgestelde vragen
Kan ik de inventaris uitbreiden zonder de client source?
Nee. Met python vergroot je alleen het visuele deel, maar de binary is gecompileerd met het oude aantal slots; de extra slots werken niet en de mismatch met de server veroorzaakt crashes. Je hebt zowel de server- als de client source nodig.
Verliezen bestaande spelers hun items?
Als je het totale aantal slots verhoogt, blijven de bestaande posities (0–89) op hun plek en worden alleen nieuwe lege slots toegevoegd; geen itemverlies. Maar een verkeerde constante of verkleining kan verlies veroorzaken, dus dump eerst de DB.
Waarom moet het een veelvoud van 45 zijn?
Een inventarispagina is 9×5 = 45 slots. Is het totaal geen veelvoud daarvan, dan wordt de laatste pagina onvolledig getekend en komen de slotindexen tussen de UI en de binary niet overeen.
Wil je een schone, exploit-vrije inventaris-uitbreiding in je serverproject? Ik kan je helpen met systeemontwikkeling aan zowel de Metin2 source als de client — laten we je project bespreken: neem contact met me op.