106 lines
4.6 KiB
Markdown
106 lines
4.6 KiB
Markdown
# 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 (45–53) sind klick-geschützt** (`event.setCancelled(true)`), wodurch Item-Klau aus der GUI-Leiste verhindert wird.
|