ZalmikStorage/README.md

106 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.<n>` | Setzt das Seitenlimit auf `<n>` (z. B. `.5` = 5) | |
| `zalmikstorage.pages.unlimited` | Hebt das Seitenlimit komplett auf | |
> Das höchste zutreffende `zalmikstorage.pages.<n>` 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.<n>` 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 (4553) sind klick-geschützt** (`event.setCancelled(true)`), wodurch Item-Klau aus der GUI-Leiste verhindert wird.