Minecraft Storage Plugin for PaperMC (works like a backpack)

This commit is contained in:
Tronax 2026-06-13 10:47:19 +02:00
commit a8524ccc47
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
12 changed files with 743 additions and 0 deletions

106
README.md Normal file
View file

@ -0,0 +1,106 @@
# 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.