# ZalmikStorage Ein mehrseitiges, datenbankgestütztes Lagersystem (ähnlich einer erweiterten Enderchest) für Paper/Spigot-Server ab **Minecraft 1.20**. Spieler öffnen über `/storage` ein 54-Slot-Inventar mit 45 nutzbaren Slots pro Seite und können per Pfeil-Buttons zwischen Seiten blättern. Die Anzahl der verfügbaren Seiten wird über Permissions gesteuert. Items werden serialisiert in einer Datenbank gespeichert. - **Author:** Tronax - **Version:** 1.0 - **API:** Paper 1.20 ## Features - Mehrseitiges Lager mit Navigation (Vorherige / Nächste Seite) - Pro-Spieler-Speicherung anhand der UUID - Seitenlimit konfigurierbar über Permissions - Unterstützt **SQLite**, **MySQL/MariaDB** und **PostgreSQL** (HikariCP Connection-Pool) - Asynchrones Laden/Speichern, um den Main-Thread zu entlasten ## Befehle | Befehl | Beschreibung | Permission | |------------|---------------------------|----------------------| | `/storage` | Öffnet das eigene Lager | `zalmikstorage.use` | ## Permissions | Permission | Beschreibung | Default | |----------------------------------|-----------------------------------------------------|---------| | `zalmikstorage.use` | Erlaubt das Öffnen des Lagers | `false` | | `zalmikstorage.pages.` | Setzt das Seitenlimit auf `` (z. B. `.5` = 5) | – | | `zalmikstorage.pages.unlimited` | Hebt das Seitenlimit komplett auf | – | > Das höchste zutreffende `zalmikstorage.pages.` gewinnt. Ohne eine solche Permission steht **1 Seite** zur Verfügung. ## Konfiguration (`config.yml`) ```yaml database: type: sqlite # sqlite | mysql | mariadb | postgresql host: "127.0.0.1" port: 3306 database: "minecraft" username: "root" password: "password" pool_size: 10 timeout: 30000 ``` Bei `type: sqlite` wird eine lokale Datei `storage.db` im Plugin-Ordner verwendet (Host/Port/Zugangsdaten werden ignoriert). ## Build Voraussetzungen: **JDK 21** und **Maven**. ```bash mvn clean package ``` Das fertige Plugin liegt anschließend unter `target/ZalmikStorage-1.0-SNAPSHOT.jar` und kann in den `plugins/`-Ordner des Servers kopiert werden. ## Datenbank-Schema ```sql CREATE TABLE IF NOT EXISTS zalmik_storage ( uuid VARCHAR(36) NOT NULL, page INT NOT NULL, items TEXT, PRIMARY KEY (uuid, page) ); ``` Items werden als Base64-kodierter `BukkitObjectStream` in der Spalte `items` abgelegt. --- ## Sicherheit & Stabilität Das Plugin wurde einer Code-Prüfung unterzogen. Die dabei gefundenen Logik- und Sicherheitsprobleme sind behoben: ### Kritisch — behoben 1. **Fehlende JDBC-Treiber im Build** — `sqlite-jdbc` und `mariadb-java-client` wurden der `pom.xml` hinzugefügt. Die Standard-Konfiguration (`type: sqlite`) funktioniert jetzt out of the box. 2. **Datenverlust beim Server-Stop** — `onDisable()` speichert alle offenen Lager nun **synchron**, bevor die Datenbankverbindung getrennt und die IO-Queues heruntergefahren werden. 3. **Race-Condition beim schnellen Öffnen/Schließen** — Laden und Speichern laufen pro Spieler über eine **serielle Single-Thread-Queue** (`ExecutorService`). Dadurch ist FIFO-Reihenfolge garantiert: Ein Ladevorgang kann eine noch ausstehende Speicherung nicht mehr überholen. ### Hoch — behoben 4. **Permission-Wert wird ignoriert** — `getMaxPages()` überspringt nun Nodes mit `getValue() == false`. Eine auf `false` gesetzte `zalmikstorage.pages.` gewährt keine Seiten mehr. 5. **Stiller Fehlerzustand bei DB-Verbindungsfehler** — `connect()` wirft jetzt eine Exception statt sie nur zu loggen; `onEnable()` fängt sie ab und **deaktiviert das Plugin**, statt in einem kaputten Zustand weiterzulaufen. ### Mittel / Niedrig — behoben 6. **Unsichere Deserialisierung / DoS** — `ItemSerializer` begrenzt die aus den Daten gelesene Array-Größe (`MAX_ITEMS = 54`) und lehnt ungültige Längen ab, bevor Speicher allokiert wird. 7. **Unbekannter `database.type`** — wird jetzt mit einer klaren `IllegalArgumentException` abgewiesen, statt mit leerer JDBC-URL zu scheitern. 8. **`getCommand("storage")` ohne Null-Check** — wird vor `setExecutor` auf `null` geprüft und sauber geloggt. ### Bereits zuvor solide - **Keine SQL-Injection:** Alle Queries nutzen `PreparedStatement`, das Tabellen-Statement ist statisch. - **Permission-Gate** auf `/storage` (`zalmikstorage.use`, Default `false`). - **Navigations-Slots (45–53) sind klick-geschützt** (`event.setCancelled(true)`), wodurch Item-Klau aus der GUI-Leiste verhindert wird.