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

Metin2 Gürtelsystem: Belt-Inventar einrichten

Ein metin2 Gürtelsystem fügt dem Ausrüstungsfenster des Spielers einen neuen Ausrüstungsplatz (den Belt-Slot) sowie ein separates kleines Inventar (das Belt-Inventar) hinzu, das sich öffnet, sobald ein Gürtel angelegt ist. Man kann Verbrauchsgegenstände wie Tränke oder Lebensflaschen für schnellen Zugriff während des Spielens hineinlegen, und die Zahl der nutzbaren Zellen wächst, je weiter der Gürtel aufgewertet wird. In diesem Leitfaden zeige ich, wie ich einen Gürtel über drei Schichten zum Laufen bringe — item_proto, die Server-Source und den Client (Python-UI).

Die Architektur des Gürtelsystems

Der Gürtel ist kein einzelnes Skript; er funktioniert nur, wenn die drei Schichten synchron bleiben. Sie müssen alle dieselben Konstanten (den Slot-Bereich) teilen, sonst "verschwinden" Gegenstände oder der Client stürzt ab:

  • item_proto: definiert den Typ des Gürtelgegenstands, den Slot, in den er angelegt wird, und wie viele Zellen er pro Stufe freischaltet.
  • Server-Source: ein eigener Slot-Bereich für das Belt-Inventar, die Validierung der Gegenstandsplatzierung und die Speicherlogik.
  • Client (root/Python): der Belt-Slot im Ausrüstungsfenster und die Grid-UI, die sich öffnet, wenn ein Gürtel getragen wird.

In den meisten Open-Source-Releases steckt das System hinter einem Compile-Flag, z. B. ENABLE_BELT_INVENTORY_SYSTEM. Kompilierst du Server und Client nicht mit dieser aktivierten Definition, passen die Paketstrukturen nicht zusammen und Spieler werden beim Einloggen getrennt.

Einen Gürtelgegenstand zu item_proto hinzufügen

Der Gürtel ist ein eigener Gegenstandstyp und wird in einen speziellen Ausrüstungsplatz angelegt. Drei Felder im item_proto-Eintrag sind entscheidend: der Typ (ITEM_BELT), das Trage-Flag (WEARABLE_BELT) und in welchen Slot er passt (WEAR_BELT). Die Stufe (wie viele Zellen er freischaltet) wird üblicherweise in einem Wertfeld (value0) gespeichert:

-- wenn du das Proto direkt in MySQL bearbeitest, ist die Logik:
-- type      = ITEM_BELT      (Gürteltyp)
-- subtype   = 0
-- wearflags = WEARABLE_BELT  (im Belt-Slot tragbar)
-- value0    = Gürtelstufe     (1,2,3,4 → freigeschaltete Zellenstufe)

UPDATE item_proto
SET    type = 'ITEM_BELT',
       wearflags = 'WEARABLE_BELT',
       value0 = 1            -- Anfangsstufe
WHERE  vnum = 18000;

In türkischen/Multi-Source-Builds lassen sich die Felder auch über item_names.txt und item_proto.txt verwalten. Der Kernpunkt: Der Typ des Gürtels ist weder Waffe noch Rüstung, sondern ein eigener Gürteltyp, damit er in den WEAR_BELT-Slot passt und das normale Inventar nicht belegt. Kompiliere das Proto nach dem Hinzufügen aus item_proto.txt neu (oder aktualisiere die Live-Tabelle) und starte den Game-Core neu.

Server-Source: der Belt-Inventar-Slot-Bereich

Das Belt-Inventar lebt in einem eigenen Adressbereich getrennt vom normalen Inventar und den Ausrüstungsplätzen. In der Source wird dieser Bereich mit Konstanten definiert (Datei und Namen variieren je nach Source, die Logik ist aber gleich):

// in einem Header wie service.h / item_length
#define BELT_INVENTORY_SLOT_START   (INVENTORY_AND_EQUIP_SLOT_END)
#define BELT_INVENTORY_SLOT_COUNT   16
#define BELT_INVENTORY_SLOT_END     (BELT_INVENTORY_SLOT_START + BELT_INVENTORY_SLOT_COUNT)

Eine Hilfsfunktion, die diesen Bereich erkennt, wird bei der Validierung der Platzierung genutzt. Wenn der Game-Core entscheidet, in welche Zelle ein Gegenstand darf, prüft er, ob der Slot in den Gürtelbereich fällt:

bool CHARACTER::IsBeltInventorySlot(WORD wCell) const
{
    return (wCell >= BELT_INVENTORY_SLOT_START &&
            wCell <  BELT_INVENTORY_SLOT_END);
}

// in der Gegenstands-Verschiebevalidierung (char_item.cpp-artig):
if (IsBeltInventorySlot(wDestCell))
{
    // 1) Hat der Spieler einen Gürtel angelegt?
    LPITEM belt = GetWear(WEAR_BELT);
    if (!belt)
        return false;                 // kein Gürtel → Zellen unbenutzbar

    // 2) Ist die Zielzelle durch die Stufe freigeschaltet?
    if (!IsValidBeltCell(belt, wDestCell))
        return false;                 // nicht in eine gesperrte Zelle
}

Beide Prüfungen sind entscheidend: Gegenstände dürfen nicht in Gürtelzellen, wenn kein Gürtel getragen wird, und nur die durch die value0-Stufe des Gürtels freigeschalteten Zellen sind nutzbar. Lässt du diese Logik aus, missbrauchen Spieler gesperrte Zellen für gratis Zusatzinventar. Beim Ablegen des Gürtels muss der Game-Core dessen Gegenstände zurück ins normale Inventar bringen (oder die Aktion ablehnen, wenn kein Platz ist); andernfalls werden die Gegenstände unerreichbar.

Datenbank und Persistenz

Gegenstände im Belt-Inventar werden wie jeder andere Gegenstand in der Tabelle player.item über die Felder window und pos gespeichert; nur der pos-Wert fällt in den Gürtelbereich. Achte hier auf Metin2s klassische Falle: Solange der Spieler online ist, wird das Inventar im Speicher in der DB-Cache-Schicht gehalten. Schreibst du Gürtelgegenstände direkt in MySQL, überschreibt der Spieler sie beim Ausloggen mit seiner Speicherkopie und die Gegenstände gehen verloren. Gegenstandsbewegungen müssen immer über die Game-Core-API laufen, nie über rohes SQL. Das Speicherschema ändert sich nicht; der einzige Unterschied ist, dass Gürtel-Slots in den neuen pos-Bereich geschrieben werden.

Client: der Belt-Slot und die Grid-UI

Auf der Client-Seite gibt es zwei Ergänzungen. Erstens den Belt-Slot im Ausrüstungsfenster; zweitens das Belt-Inventar-Grid, das sich öffnet, wenn ein Gürtel getragen wird. In den Python-UI-Dateien (uiInventory.py und dem zugehörigen Fensterskript) muss der Slot-Bereich identisch zum Server definiert sein:

# in playerSettingModule / player.py
BELT_INVENTORY_SLOT_START = 0
BELT_INVENTORY_SLOT_COUNT = 16
BELT_INVENTORY_SLOT_END   = BELT_INVENTORY_SLOT_START + BELT_INVENTORY_SLOT_COUNT

# Grid ein-/ausblenden, wenn der Gürtel angelegt ist
def OnEquipBelt(self, isEquipped):
    if isEquipped:
        self.beltInventoryGrid.Show()
    else:
        self.beltInventoryGrid.Hide()

Eine sparsame Regel für die Grid-Zellen: Zeige so viele Zellen "aktiv", wie die Stufe des Gürtels (der Wert vom Server) freischaltet, und den Rest "gesperrt". Drag-and-Drop in gesperrte Zellen muss blockiert werden. Vergiss auch nicht, die .tga-Grafiken der UI und die Zellkoordinaten hinzuzufügen; die meisten Sources halten diese in einer Datei belt_inventory_window.py. Schließlich ist die Öffnen/Schließen-Animation des Grids rein kosmetisch — die Gegenstandsvalidierung passiert immer auf dem Server, vertraue nie dem Client.

Den Gürtel aufwerten: Zellen freischalten

Der Reiz des Gürtels ist seine Aufwertbarkeit. Der allgemeine Ansatz ist, die value0-Stufe des Gürtels über einen Aufwertungs-NPC oder eine Quest zu erhöhen. Eine einfache Stufenerhöhung auf der Quest-Seite sieht so aus:

quest belt_upgrade begin
    state start begin
        when 18000.use begin
            local belt = item.get_value(0)   -- aktuelle Stufe
            if belt >= 4 then
                say("Dein Gürtel ist bereits auf der höchsten Stufe.")
                return
            end
            -- Prüfung von Aufwertungsmaterial / Yang hier
            item.set_value(0, belt + 1)
            say("Dein Gürtel wurde auf Stufe "..(belt+1).." aufgewertet!")
        end
    end
end

Steigt die Stufe, zählt der Server anhand des neuen value0 des angelegten Gürtels mehr Gürtelzellen als "freigeschaltet" und aktualisiert den Client. Halte die Stufenobergrenze (4 im Beispiel) sowohl in der Quest als auch in der IsValidBeltCell-Logik der Source konsistent; weichen die beiden ab, lässt du entweder Zellen unnötig gesperrt oder öffnest eine ausnutzbare Lücke.

Häufige Fragen

Das Grid öffnet sich, wenn ich einen Gürtel anlege, aber Gegenstände verschwinden beim Ausloggen — warum?

Die klassische DB-Cache-Falle. Schreibst du Gürtelgegenstände direkt in MySQL, überschreibt der Spieler sie beim Ausloggen mit seiner Speicherkopie. Verschiebe Gegenstände immer über die Game-Core-API und stelle sicher, dass der pos-Wert korrekt in den Gürtelbereich geschrieben wird.

Spieler können Gürtelzellen nutzen, ohne einen Gürtel zu tragen.

Die serverseitige GetWear(WEAR_BELT)-Prüfung fehlt oder ist schwach. Validiere bei jeder Platzierung in den Gürtelbereich zuerst, ob ein Gürtel angelegt ist, dann ob die Zielzelle durch die Stufe freigeschaltet ist. Die Sperre auf der Client-Seite ist rein kosmetisch.

Ich habe das System aktiviert, aber Spieler werden beim Einloggen getrennt.

Fast immer eine Diskrepanz beim ENABLE_BELT_INVENTORY_SYSTEM-Flag oder den Slot-Konstanten zwischen Server und Client. Kompiliere beide mit denselben Definitionen neu; stimmen die Paketgrößen nicht überein, bricht die Sitzung ab.

Möchtest du das Gürtelsystem sauber auf deinem Server installiert haben? Ich richte das Belt-Inventar von Anfang bis Ende ein — von item_proto bis zur Source- und Client-Integration, inklusive stufenweisem Freischalten der Zellen. Lass uns über dein Projekt sprechen — kontaktiere mich.

Bu kategorideki tüm yazılar →

Devamı için