Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 08b05167d8 | |||
| 58927afddc | |||
| 4765f652a8 | |||
| 6fed70c831 | |||
| 97f739a302 | |||
| fef02a2657 | |||
| b06008069a | |||
| c0d2125176 | |||
| 6f7d5c3872 | |||
| 2d4a253d1b | |||
| aaea889832 | |||
| 653abaaac4 | |||
| fd8122beff | |||
| e4ece02a00 | |||
| 21a92bad90 | |||
| 326eed3513 | |||
| 7b1a844234 | |||
| afe6438ec2 | |||
| 484f08c852 | |||
| 9f19a94d27 | |||
| aeac179cec | |||
| f10f6eebc8 | |||
| 5b984d1e7d | |||
| 68eddb1277 | |||
| bf18ab3888 | |||
| 5ffc7a716b | |||
| b8c4ce5dd9 | |||
| f41f935ad3 | |||
| 7521ec5541 | |||
| 919b7a2cf5 | |||
| fb22f49f3d | |||
| 9a654ec6bf | |||
| 810c301daa | |||
| 92b5a3725c | |||
| 3541a7749d | |||
| a02d322201 | |||
| a0d8fc8f6b | |||
| 80a6c0ec14 | |||
| f36e5d8b4e | |||
| e5e661dcac | |||
| c23aedb4e5 | |||
| 08569d98c6 | |||
| 406b28d572 | |||
| 186c9d1841 | |||
| 3b535b15ca | |||
| a8c7892f54 | |||
| 44d0818988 | |||
| c1fd0477b1 | |||
| 531a8d4206 | |||
| 6e544e34e9 | |||
| dfb785cb09 | |||
| 78f4c75c94 | |||
| c10e0a6645 | |||
| 1717a8c84f | |||
| e4b5bc6490 | |||
| bb6e876932 | |||
| f2a401f684 | |||
| d27a4221ef | |||
| 16337cbf18 | |||
| 0b7f32e850 | |||
| 3f5cc88b30 | |||
| 7b7bf9c72e | |||
| 948e018cff | |||
| 54bee6a633 | |||
| 2428a35744 | |||
| b844a7aaea | |||
| aa4360a7cf | |||
| bab76e0a93 | |||
| fa4d08b018 | |||
| 075667a9e3 | |||
| 40ba636c3b | |||
| f15d97e2af | |||
| d81e2c28c9 | |||
| 1c66acbd5c | |||
| 9b50de8f1f | |||
| b2242c49e1 | |||
| 973997cc47 | |||
| eca466ef1a | |||
| d9b23915e8 | |||
| 702b51be1d | |||
| b88d599b3b | |||
| a8c2b58b86 | |||
| 55a54f857a | |||
| 6b0431f230 | |||
| 78b03f743b | |||
| 7b70bdcaef | |||
| 05e9cd1e24 | |||
| 2cf634d7a6 | |||
| d397ae25a8 | |||
| 188b1618da | |||
| 4ba7109e92 | |||
| b7ed8b3515 | |||
| 875f7e1650 | |||
| f3db9b5d8b | |||
| 2179a73329 | |||
| 526d9b00a6 | |||
| 242f54b3dc | |||
| a8c1d2fb10 | |||
| 720b54f4e1 | |||
| 8be068ab72 | |||
| d2ef092625 | |||
| 31b6772807 | |||
| fbd9c65f9f | |||
| 9329f8ec25 | |||
| ebe50e9b07 | |||
| 4e34c30c08 | |||
| 2d088fa663 | |||
| a4927efbd4 | |||
| b8efc67e49 | |||
| 62b7092bcb | |||
| a95145f9fa | |||
| 1b0fc748e5 | |||
| f035d34e2c | |||
| f2938a516e | |||
| 389ad08e69 | |||
| f6d91971f0 | |||
| a0bd8f1606 | |||
| f28adb0be6 | |||
| c593c97c03 | |||
| 66dcd21966 | |||
| a7d4e14c09 | |||
| 9967dc5417 | |||
| dbeb24e676 | |||
| c495513c71 | |||
| 230412e658 | |||
| 8c80824830 | |||
| db7c8eeaa5 | |||
| 53b79311f4 | |||
| 242c91be72 | |||
| fa33cfe1ba | |||
| 1173bfa49d | |||
| 4f9268032d | |||
| 3a03b160ea | |||
| 0a81b07fe6 | |||
| 30d7249c2b | |||
| b10c0a9d40 | |||
| 7e2b4c5f38 | |||
| 9818bc1229 | |||
| e7f4c3ac5d | |||
| 6b6d3bc6b7 | |||
| 222186a83a | |||
| fbf9f10b27 | |||
| 25339444da | |||
| 3f3d1c7d37 | |||
| 4e2e831a1a | |||
| fec84fd8d7 | |||
| 39cf666bf4 | |||
| 24c551fb5c | |||
| 790980a5ac | |||
| 779f031fdc | |||
| 7fb9afa9d3 | |||
| a69200ee17 | |||
| 73fed5acc5 | |||
| a88fef28c3 | |||
| 657a83e182 | |||
| aadc1e75cc | |||
| 121bdcf8b4 | |||
| a625527a1e | |||
| 03dc23cb50 |
BIN
lib/ProtocolLib.jar
Normal file
BIN
lib/ProtocolLib.jar
Normal file
Binary file not shown.
31
pom.xml
31
pom.xml
@@ -1,19 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>de.viper</groupId>
|
<groupId>de.viper</groupId>
|
||||||
<artifactId>SurvivalPlus</artifactId>
|
<artifactId>SurvivalPlus</artifactId>
|
||||||
<version>1.0.5-Beta</version>
|
<version>1.1.1-Beta</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>SurvivalPlus</name>
|
<name>SurvivalPlus</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<!-- Repository für PlaceholderAPI -->
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>codemc-repo</id>
|
<id>codemc-repo</id>
|
||||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||||
@@ -30,12 +29,14 @@
|
|||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Spigot API -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.21-R0.1-SNAPSHOT</version>
|
<version>1.21-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- bStats Bukkit Dependency -->
|
<!-- bStats Bukkit Dependency -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bstats</groupId>
|
<groupId>org.bstats</groupId>
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
<version>3.0.2</version>
|
<version>3.0.2</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- PlaceholderAPI Dependency -->
|
<!-- PlaceholderAPI Dependency -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.clip</groupId>
|
<groupId>me.clip</groupId>
|
||||||
@@ -50,6 +52,7 @@
|
|||||||
<version>2.11.6</version>
|
<version>2.11.6</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- LuckPerms API Dependency -->
|
<!-- LuckPerms API Dependency -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.luckperms</groupId>
|
<groupId>net.luckperms</groupId>
|
||||||
@@ -57,10 +60,19 @@
|
|||||||
<version>5.5.10</version>
|
<version>5.5.10</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ProtocolLib 4.8.0 (für WrapperPlayServerScoreboardTeam) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.comphenix.protocol</groupId>
|
||||||
|
<artifactId>ProtocolLib</artifactId>
|
||||||
|
<version>4.8.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<!-- Compiler Plugin -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
@@ -70,6 +82,8 @@
|
|||||||
<target>17</target>
|
<target>17</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Shade Plugin -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
@@ -111,6 +125,11 @@
|
|||||||
<include>shop.yml</include>
|
<include>shop.yml</include>
|
||||||
<include>warps.yml</include>
|
<include>warps.yml</include>
|
||||||
<include>tablist.yml</include>
|
<include>tablist.yml</include>
|
||||||
|
<include>blockedcommands.yml</include>
|
||||||
|
<include>claims.yml</include>
|
||||||
|
<include>lootchests.yml</include>
|
||||||
|
<include>blocks.yml</include>
|
||||||
|
<include>nicknames.yml</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
274
readme.md
274
readme.md
@@ -1,106 +1,256 @@
|
|||||||
# SurvivalPlus
|
# SurvivalPlus
|
||||||
|
|
||||||
|
**Minecraft Plugin**
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
**SurvivalPlus** ist ein Minecraft-Plugin zur Verbesserung des Survival-Erlebnisses.
|
---
|
||||||
Es bietet Homes, Teleportation, Inventarverwaltung, Freundeslisten, Shops, Loot-Kisten und weitere Komfortbefehle.
|
|
||||||
|
## 📦 Beschreibung
|
||||||
|
|
||||||
|
**SurvivalPlus** ist ein umfangreiches Minecraft-Plugin zur Verbesserung des klassischen Survival-Erlebnisses.
|
||||||
|
Es kombiniert Komfort-Features für Spieler mit leistungsstarken Verwaltungs- und Schutzmechanismen für Serverbetreiber.
|
||||||
|
|
||||||
|
Enthalten sind unter anderem:
|
||||||
|
Homes, Teleports, Inventar- & Enderchest-Verwaltung, Claims (Anti-Grief), Freundeslisten, Shop-System, Loot-Kisten, Tablist-Anpassungen, Player Heads, erweiterte Vanish-Funktionen sowie zahlreiche Server-Utilities.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚡ Features
|
## ⚡ Highlights / Features
|
||||||
|
|
||||||
- **Homes & Warps** – Homepunkte setzen, löschen, Teleportation, persönliche Warps
|
- **Homes & Warps**
|
||||||
- **Teleportation & Spielerinteraktion** – `/tp`, `/tphere`, `/tpa`, `/back`, `/spawn`
|
Persönliche Warps, Home-Management, GUI-Übersichten
|
||||||
- **Inventar & Endertruhe** – Öffnen eigener und fremder Inventare/Endertruhen
|
|
||||||
- **Spielmodus & Zeit** – `/gm`, `/day`, `/night`
|
- **Teleportation & Anfrage-System**
|
||||||
- **Freundes- und Kommunikationssystem** – `/friend`, `/block`, `/blocklist`
|
`/tpa`, `/tpaccept`, `/tpdeny`, `/back`, `/spawn`
|
||||||
- **Koordinaten teilen** – `/sp share`, `/sp shareconfirm`, `/sp sharecancel`
|
|
||||||
- **Items & Werkzeuge** – `/ir`, `/workbench`, `/anvil`, `/kit`
|
- **Claim-System (Anti-Grief)**
|
||||||
- **Server-Management** – `/clearchat`, `/clearitems`, `/closedoors`, `/lock`, `/shop`
|
Land sichern, Trust/Untrust, Ban/Kick, Claim-Infos
|
||||||
- **Statistiken & Reporting** – `/stats`, `/report`, `/showreport`, `/clearreport`
|
|
||||||
- **Fun & Challenges** – `/sit`, `/startchallenge`, `/trade`, `/lootchests`
|
- **Inventar- & Enderchest-Verwaltung**
|
||||||
|
Admin-Zugriff auf Fremd-Inventare
|
||||||
|
|
||||||
|
- **Neu: Player Heads**
|
||||||
|
Köpfe bei Tod oder per `/head` Befehl
|
||||||
|
|
||||||
|
- **Neu: Erweiterte Vanish-Funktionen**
|
||||||
|
Silent Join, keine Item-Aufnahme
|
||||||
|
|
||||||
|
- **Neu: Sign Shops**
|
||||||
|
Schilder-Shops mit Vault-Integration
|
||||||
|
|
||||||
|
- **Shop-System & Lootchests**
|
||||||
|
Verwaltung & Teleport zu Loot-Kisten
|
||||||
|
|
||||||
|
- **CommandBlocker & Server-Utilities**
|
||||||
|
Clearchat, Clearitems, Closedoors, Lock-System
|
||||||
|
|
||||||
|
- **Debug-Logging**
|
||||||
|
Optionales Logging in `debug.log` & `console.log`
|
||||||
|
|
||||||
|
- **Tablist**
|
||||||
|
Animiert & konfigurierbar über `tablist.yml`
|
||||||
|
|
||||||
|
- **bStats Unterstützung**
|
||||||
|
Anonyme Statistiken
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠 Commands Übersicht
|
## 🛠 Komplette Befehlsübersicht
|
||||||
|
|
||||||
|
> **Hinweis:**
|
||||||
|
> Alle Commands sind vollständig in der `plugin.yml` definiert.
|
||||||
|
> Nachfolgend eine Übersicht nach Kategorien.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Allgemein / Haupt
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/sp` | Hauptbefehl (Reload, Info, Help, Share, CommandBlocker u.v.m.) | `survivalplus.sp` |
|
||||||
|
| `/help` | Hilfe / Übersicht (Alias: `/sp help`) | `survivalplus.sp` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Item & Utility
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/ir <name>` | Item umbenennen (Item in Hand) | `survivalplus.itemrename` |
|
||||||
|
| `/workbench` | Öffnet Werkbank-GUI | `survivalplus.workbench` |
|
||||||
|
| `/anvil` | Öffnet Amboss-GUI | `survivalplus.anvil` |
|
||||||
|
| `/trash` | Öffnet Mülleimer | `survivalplus.trash` |
|
||||||
|
| `/showarmorstands` | Debug: ArmorStands sichtbar | `survivalplus.showarmorstands` |
|
||||||
|
| `/cleardebugarmorstands` | Entfernt Debug-ArmorStands | `survivalplus.cleardebugarmorstands` |
|
||||||
|
| `/leashcount` | Zeigt geleinte Tiere | `survivalplus.leashcount` |
|
||||||
|
| `/nick <Name>` | Nickname setzen (Farben/Hex) | `survivalplus.nick` |
|
||||||
|
| `/nick off` | Nickname entfernen | `survivalplus.nick` |
|
||||||
|
| `/head <Spieler>` | Spieler-Kopf erhalten | `survivalplus.head` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Admin & Tools
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/vanish` | Unsichtbar (Silent, No-Pickup optional) | `survivalplus.vanish` |
|
||||||
|
| `/freeze <Spieler>` | Spieler einfrieren | `survivalplus.freeze` |
|
||||||
|
| `/ride [Spieler]` | Reite einen Spieler | `survivalplus.ride` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Teleportation
|
### Teleportation
|
||||||
|
|
||||||
| Befehl | Nutzung | Permission |
|
| Befehl | Nutzung | Permission |
|
||||||
|--------|---------|------------|
|
|------|------|-----------|
|
||||||
| `/tp` | Teleport zu Spieler | `survivalplus.tp` |
|
| `/tp <Spieler>` | Teleport zu Spieler | `survivalplus.tp` |
|
||||||
| `/tphere` | Spieler zu dir teleportieren | `survivalplus.tphere` |
|
| `/tphere <Spieler>` | Spieler zu dir teleportieren | `survivalplus.tphere` |
|
||||||
| `/tpa` | Teleportanfrage senden | `survivalplus.tpa` |
|
| `/tpa <Spieler>` | Teleportanfrage senden | `survivalplus.tpa` |
|
||||||
| `/tpaccept` | Teleportanfrage annehmen | `survivalplus.tpaccept` |
|
| `/tpaccept` | Anfrage akzeptieren | `survivalplus.tpaccept` |
|
||||||
| `/tpdeny` | Teleportanfrage ablehnen | `survivalplus.tpdeny` |
|
| `/tpdeny` | Anfrage ablehnen | `survivalplus.tpdeny` |
|
||||||
| `/back` | Zum letzten Todespunkt | `survivalplus.back` |
|
| `/back` | Zum letzten Todespunkt | `survivalplus.back` |
|
||||||
| `/spawn` | Weltspawn teleport | `survivalplus.spawn` |
|
| `/spawn` | Zum Weltspawn | `survivalplus.spawn` |
|
||||||
|
| `/setspawn` | Server-Spawn setzen | `survivalplus.setspawn` |
|
||||||
|
| `/setworldspawn` | Welt-Spawn setzen | `survivalplus.setworldspawn` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Homes & Warps
|
### Homes & Warps
|
||||||
|
|
||||||
| Befehl | Nutzung | Permission |
|
| Befehl | Nutzung | Permission |
|
||||||
|--------|---------|------------|
|
|------|------|-----------|
|
||||||
| `/sethome <name>` | Home setzen | `survivalplus.homes.set` |
|
| `/sethome <name>` | Home setzen | `survivalplus.homes.set` |
|
||||||
| `/delhome <name>` | Home löschen | `survivalplus.homes.delete` |
|
| `/delhome <name>` | Home löschen | `survivalplus.homes.delete` |
|
||||||
| `/home <name>` | Teleport zu Home | `survivalplus.homes` |
|
| `/home <name>` | Zu Home teleportieren | `survivalplus.homes` |
|
||||||
| `/homelist` | Liste aller Homes | `survivalplus.homes.list` |
|
| `/homelist` | GUI mit allen Homes | `survivalplus.homes.list` |
|
||||||
| `/setwarp <name>` | Persönlichen Warp setzen | `survivalplus.setwarp` |
|
| `/setwarp <name>` | Persönlichen Warp setzen | `survivalplus.setwarp` |
|
||||||
| `/delwarp <name>` | Persönlichen Warp löschen | `survivalplus.delwarp` |
|
| `/delwarp <name>` | Warp löschen | `survivalplus.delwarp` |
|
||||||
| `/warps` | GUI aller Warps öffnen | `survivalplus.warps` |
|
| `/warps` | Warp-GUI öffnen | `survivalplus.warps` |
|
||||||
|
|
||||||
### Spieler & Kommunikation
|
---
|
||||||
| Befehl | Nutzung | Permission |
|
|
||||||
|--------|---------|------------|
|
|
||||||
| `/friend` | Freundesliste verwalten | `survivalplus.friend` |
|
|
||||||
| `/block` | Spieler blockieren | `survivalplus.block` |
|
|
||||||
| `/unblock` | Blockierung aufheben | `survivalplus.unlock` |
|
|
||||||
| `/blocklist` | Liste blockierter Spieler | `survivalplus.blocklist` |
|
|
||||||
|
|
||||||
### Items & Werkzeuge
|
### Claim (Anti-Grief)
|
||||||
| Befehl | Nutzung | Permission |
|
|
||||||
|--------|---------|------------|
|
|
||||||
| `/ir <neuer_name>` | Item umbenennen | `survivalplus.itemrename` |
|
|
||||||
| `/workbench` | Werkbank GUI öffnen | `survivalplus.workbench` |
|
|
||||||
| `/anvil` | Amboss GUI öffnen | `survivalplus.anvil` |
|
|
||||||
| `/kit` | Starterkit erhalten | `survivalplus.kit` |
|
|
||||||
| `/leashcount` | Anzahl geleinter Tiere | `survivalplus.leashcount` |
|
|
||||||
| `/nick <Name>` | Nickname ändern | `survivalplus.nick` |
|
|
||||||
|
|
||||||
### Server-Management
|
|
||||||
| Befehl | Nutzung | Permission |
|
| Befehl | Nutzung | Permission |
|
||||||
|--------|---------|------------|
|
|------|------|-----------|
|
||||||
| `/clearchat` | Chat löschen | `survivalplus.clearchat` |
|
| `/claim mark 1|2` | Auswahlpunkt setzen | — |
|
||||||
|
| `/claim` | Gebiet claimen | `survivalplus.claim.use` |
|
||||||
|
| `/claim unclaim` | Claim löschen | `survivalplus.claim.use` |
|
||||||
|
| `/claim unclaim <Spieler>` | Alle Claims löschen (Admin) | `survivalplus.claim.admin` |
|
||||||
|
| `/claim trust <Spieler>` | Spieler hinzufügen | `survivalplus.claim.trust` |
|
||||||
|
| `/claim untrust <Spieler>` | Spieler entfernen | `survivalplus.claim.trust` |
|
||||||
|
| `/claim ban <Spieler>` | Spieler bannen | `survivalplus.claim.ban` |
|
||||||
|
| `/claim kick <Spieler>` | Spieler kicken | `survivalplus.claim.kick` |
|
||||||
|
| `/claim info` | Claim-Infos anzeigen | `survivalplus.claim.use` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### CommandBlocker / Server-Management
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/sp cb add <cmd>` | Befehl blockieren | `survivalplus.commandblocker.add` |
|
||||||
|
| `/sp cb remove <cmd>` | Blockierung entfernen | `survivalplus.commandblocker.remove` |
|
||||||
|
| `/sp cb list` | Blockierte Befehle | `survivalplus.commandblocker.list` |
|
||||||
|
| `/clearchat` | Chat leeren | `survivalplus.clearchat` |
|
||||||
| `/clearitems` | Items entfernen | `survivalplus.clearitems` |
|
| `/clearitems` | Items entfernen | `survivalplus.clearitems` |
|
||||||
| `/closedoors <radius>` | Türen schließen | `survivalplus.closedoors` |
|
| `/closedoors <radius>` | Türen schließen | `survivalplus.closedoors` |
|
||||||
| `/lock` | Container schützen | `survivalplus.lock` |
|
| `/sp lock` | Kisten/Türen sperren | `survivalplus.lock` |
|
||||||
| `/shop add <item> <preis> <bestand>` | Server-Shop verwalten | `survivalplus.shop` |
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Shop, Loot & Trade
|
||||||
|
|
||||||
### Statistiken & Reporting
|
|
||||||
| Befehl | Nutzung | Permission |
|
| Befehl | Nutzung | Permission |
|
||||||
|--------|---------|------------|
|
|------|------|-----------|
|
||||||
|
| **Sign Shops** | `[Buy] Menge Item Preis` | automatisch |
|
||||||
|
| `/shop add <item> <preis> <bestand>` | Shop verwalten | `survivalplus.shop` |
|
||||||
|
| `/lootchests` | Loot-Kisten auflisten | `survivalplus.lootchests` |
|
||||||
|
| `/tploot <welt> <x> <y> <z>` | Zu Loot-Kiste teleportieren | `survivalplus.lootchests` |
|
||||||
|
| `/trade <Spieler>` | Handel starten | `survivalplus.trade` |
|
||||||
|
| `/tradeaccept <Spieler>` | Handel annehmen | `survivalplus.tradeaccept` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Zeit, Gamemode & Admin
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/day` | Tag setzen | `survivalplus.day` |
|
||||||
|
| `/night` | Nacht setzen | `survivalplus.night` |
|
||||||
|
| `/gm <modus>` | Gamemode ändern | `survivalplus.gamemode` |
|
||||||
|
| `/heal [Spieler]` | Spieler heilen | `survivalplus.heal` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Freundes-, Block- & Report-System
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
|
| `/friend add|accept|deny` | Freundesverwaltung | — |
|
||||||
|
| `/block <Spieler>` | Spieler blockieren | `survivalplus.block` |
|
||||||
|
| `/unblock <Spieler>` | Blockierung aufheben | `survivalplus.unblock` |
|
||||||
|
| `/blocklist` | Blockliste anzeigen | `survivalplus.blocklist` |
|
||||||
|
| `/report <Spieler> [Grund]` | Spieler melden | `survivalplus.report` |
|
||||||
|
| `/showreport <Spieler>` | Reports anzeigen | `survivalplus.report.show` |
|
||||||
|
| `/clearreport <Spieler>` | Reports löschen | `survivalplus.report.clear` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Sonstiges
|
||||||
|
|
||||||
|
| Befehl | Nutzung | Permission |
|
||||||
|
|------|------|-----------|
|
||||||
| `/stats` | Spielerstatistiken | `survivalplus.stats` |
|
| `/stats` | Spielerstatistiken | `survivalplus.stats` |
|
||||||
| `/report <spieler> [grund]` | Spieler melden | `survivalplus.report` |
|
| `/kit` | Starterkit | `survivalplus.kit` |
|
||||||
| `/showreport <spieler>` | Reports anzeigen | `survivalplus.report.show` |
|
| `/startchallenge <name>` | Fun-Challenge starten | `survivalplus.startchallenge` |
|
||||||
| `/clearreport <spieler>` | Reports löschen | `survivalplus.report.clear` |
|
| `/sit` | Hinsetzen | `survivalplus.sit` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Permissions (Kurzüberblick)
|
||||||
|
|
||||||
|
- `survivalplus.*` — Vollzugriff (OP)
|
||||||
|
- `survivalplus.sp` — Zugriff auf Hauptbefehl
|
||||||
|
- `survivalplus.claim.use / trust / admin` — Claim-System
|
||||||
|
- `survivalplus.vanish.silent` — Silent Join
|
||||||
|
- `survivalplus.vanish.no-pickup` — Keine Item-Aufnahme
|
||||||
|
- `survivalplus.head` — `/head` nutzen
|
||||||
|
- `survivalplus.notify` — Admin-Benachrichtigungen
|
||||||
|
|
||||||
|
➡ Vollständige Liste: **plugin.yml**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙ Installation
|
## ⚙ Installation
|
||||||
|
|
||||||
1. Lade die aktuelle `.jar` Datei herunter.
|
1. Aktuelle `.jar` herunterladen
|
||||||
2. Kopiere sie in den `plugins`-Ordner deines Servers.
|
2. In den `plugins/` Ordner legen
|
||||||
3. Starte den Server neu oder nutze `/reload`.
|
3. **LuckPerms** und **Vault** installieren
|
||||||
4. Stelle sicher, dass **LuckPerms** und **PlaceholderAPI** installiert sind.
|
4. Server neu starten oder `/reload`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔐 Permissions
|
## 🐞 Debug & Fehlerberichte
|
||||||
|
|
||||||
- **Vollzugriff:** `survivalplus.*` (OP)
|
- In `config.yml` setzen:
|
||||||
- Alle Befehle können über LuckPerms angepasst werden.
|
```yml
|
||||||
|
debug-logging: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐞 Debug & Logs
|
||||||
|
|
||||||
|
- `Debug/debug.log` — Enthält Plugin-Fehler und Stacktraces (nur bei aktiviertem Debug-Logging)
|
||||||
|
- `Debug/console.log` — Kompletter Konsolenoutput zur Weitergabe an Entwickler
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📜 Lizenz
|
## 📜 Lizenz & Kontakt
|
||||||
|
|
||||||
Dieses Projekt ist frei für den privaten Gebrauch. Kontakt: **M_Viper**
|
Dieses Projekt ist frei für den **privaten Gebrauch**.
|
||||||
|
|
||||||
|
**Kontakt / Support / Feature-Wünsche:**
|
||||||
|
**M_Viper** (Repo-Owner / GitHub)
|
||||||
|
|||||||
@@ -1,30 +1,83 @@
|
|||||||
package de.viper.survivalplus.Manager;
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
|
||||||
public class BlockManager {
|
public class BlockManager {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
private final Map<UUID, Set<UUID>> blockedPlayers = new HashMap<>();
|
private final Map<UUID, Set<UUID>> blockedPlayers = new HashMap<>();
|
||||||
|
private File blocksFile;
|
||||||
|
private FileConfiguration blocksConfig;
|
||||||
|
|
||||||
|
public BlockManager(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.blocksFile = new File(plugin.getDataFolder(), "blocks.yml");
|
||||||
|
if (!blocksFile.exists()) {
|
||||||
|
try {
|
||||||
|
blocksFile.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.blocksConfig = YamlConfiguration.loadConfiguration(blocksFile);
|
||||||
|
loadBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveBlocks() {
|
||||||
|
for (UUID key : blockedPlayers.keySet()) {
|
||||||
|
List<String> uuids = new ArrayList<>();
|
||||||
|
for (UUID uuid : blockedPlayers.get(key)) {
|
||||||
|
uuids.add(uuid.toString());
|
||||||
|
}
|
||||||
|
blocksConfig.set(key.toString(), uuids);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
blocksConfig.save(blocksFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadBlocks() {
|
||||||
|
blockedPlayers.clear();
|
||||||
|
for (String key : blocksConfig.getKeys(false)) {
|
||||||
|
UUID blockerUUID = UUID.fromString(key);
|
||||||
|
List<String> blockedUUIDs = blocksConfig.getStringList(key);
|
||||||
|
Set<UUID> blockedSet = new HashSet<>();
|
||||||
|
for (String uuidStr : blockedUUIDs) {
|
||||||
|
blockedSet.add(UUID.fromString(uuidStr));
|
||||||
|
}
|
||||||
|
blockedPlayers.put(blockerUUID, blockedSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void blockPlayer(Player blocker, Player toBlock) {
|
public void blockPlayer(Player blocker, Player toBlock) {
|
||||||
blockedPlayers.computeIfAbsent(blocker.getUniqueId(), k -> new HashSet<>()).add(toBlock.getUniqueId());
|
blockedPlayers.computeIfAbsent(blocker.getUniqueId(), k -> new HashSet<>()).add(toBlock.getUniqueId());
|
||||||
|
saveBlocks(); // Sofort speichern
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unblockPlayer(Player blocker, Player toUnblock) {
|
public void unblockPlayer(Player blocker, Player toUnblock) {
|
||||||
Set<UUID> blocked = blockedPlayers.get(blocker.getUniqueId());
|
Set<UUID> blocked = blockedPlayers.get(blocker.getUniqueId());
|
||||||
if (blocked != null) {
|
if (blocked != null) {
|
||||||
blocked.remove(toUnblock.getUniqueId());
|
blocked.remove(toUnblock.getUniqueId());
|
||||||
if (blocked.isEmpty()) {
|
if (blocked.isEmpty()) {
|
||||||
blockedPlayers.remove(blocker.getUniqueId());
|
blockedPlayers.remove(blocker.getUniqueId());
|
||||||
|
}
|
||||||
|
saveBlocks(); // Sofort speichern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasBlocked(Player blocker, Player potentialBlocked) {
|
public boolean hasBlocked(Player blocker, Player potentialBlocked) {
|
||||||
return blockedPlayers.getOrDefault(blocker.getUniqueId(), Collections.emptySet())
|
return blockedPlayers.getOrDefault(blocker.getUniqueId(), Collections.emptySet())
|
||||||
.contains(potentialBlocked.getUniqueId());
|
.contains(potentialBlocked.getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<UUID> getBlockedPlayers(Player player) {
|
public Set<UUID> getBlockedPlayers(Player player) {
|
||||||
@@ -33,5 +86,6 @@ public class BlockManager {
|
|||||||
|
|
||||||
public void clear(Player player) {
|
public void clear(Player player) {
|
||||||
blockedPlayers.remove(player.getUniqueId());
|
blockedPlayers.remove(player.getUniqueId());
|
||||||
|
saveBlocks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
193
src/main/java/de/viper/survivalplus/Manager/CommandBlocker.java
Normal file
193
src/main/java/de/viper/survivalplus/Manager/CommandBlocker.java
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CommandBlocker implements Listener, CommandExecutor {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
private FileConfiguration blockedCommandsConfig;
|
||||||
|
private File blockedCommandsFile;
|
||||||
|
private List<String> blockedCommands;
|
||||||
|
|
||||||
|
public CommandBlocker(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
// Lade blockedcommands.yml
|
||||||
|
try {
|
||||||
|
blockedCommandsFile = new File(plugin.getDataFolder(), "blockedcommands.yml");
|
||||||
|
if (!blockedCommandsFile.exists()) {
|
||||||
|
plugin.saveResource("blockedcommands.yml", false);
|
||||||
|
}
|
||||||
|
blockedCommandsConfig = YamlConfiguration.loadConfiguration(blockedCommandsFile);
|
||||||
|
blockedCommands = blockedCommandsConfig.getStringList("blocked-commands");
|
||||||
|
if (blockedCommands == null) {
|
||||||
|
blockedCommands = new ArrayList<>();
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
blockedCommands = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registriere Listener und Command
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
plugin.getCommand("sp").setExecutor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verarbeitet /sp cb Befehle
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (args.length < 2 || !args[0].equalsIgnoreCase("cb")) {
|
||||||
|
return false; // Wird von anderen /sp Subcommands behandelt
|
||||||
|
}
|
||||||
|
|
||||||
|
String subCommand = args[1].toLowerCase();
|
||||||
|
|
||||||
|
switch (subCommand) {
|
||||||
|
case "add":
|
||||||
|
return handleAddCommand(sender, args);
|
||||||
|
case "remove":
|
||||||
|
return handleRemoveCommand(sender, args);
|
||||||
|
case "list":
|
||||||
|
return handleListCommand(sender);
|
||||||
|
default:
|
||||||
|
sender.sendMessage("§cUnbekannter Subcommand! Verfügbare Subcommands: add, remove, list");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /sp cb add <command>
|
||||||
|
*/
|
||||||
|
private boolean handleAddCommand(CommandSender sender, String[] args) {
|
||||||
|
if (!sender.hasPermission("survivalplus.commandblocker.add")) {
|
||||||
|
sender.sendMessage("§cDu hast keine Berechtigung für diesen Befehl!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
sender.sendMessage("§eBenutzung: /sp cb add <command>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandToBlock = args[2].toLowerCase().replaceFirst("^/", "").trim();
|
||||||
|
if (commandToBlock.isEmpty()) {
|
||||||
|
sender.sendMessage("§cBitte gib einen gültigen Befehl an!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (blockedCommands.contains(commandToBlock)) {
|
||||||
|
sender.sendMessage("§cDer Befehl §e/" + commandToBlock + "§c ist bereits blockiert!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockedCommands.add(commandToBlock);
|
||||||
|
blockedCommandsConfig.set("blocked-commands", blockedCommands);
|
||||||
|
blockedCommandsConfig.save(blockedCommandsFile);
|
||||||
|
sender.sendMessage("§aDer Befehl §e/" + commandToBlock + "§a wurde zur Blockierliste hinzugefügt.");
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
sender.sendMessage("§cFehler beim Hinzufügen des Befehls!");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /sp cb remove <command>
|
||||||
|
*/
|
||||||
|
private boolean handleRemoveCommand(CommandSender sender, String[] args) {
|
||||||
|
if (!sender.hasPermission("survivalplus.commandblocker.remove")) {
|
||||||
|
sender.sendMessage("§cDu hast keine Berechtigung für diesen Befehl!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
sender.sendMessage("§eBenutzung: /sp cb remove <command>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandToUnblock = args[2].toLowerCase().replaceFirst("^/", "").trim();
|
||||||
|
if (commandToUnblock.isEmpty()) {
|
||||||
|
sender.sendMessage("§cBitte gib einen gültigen Befehl an!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!blockedCommands.contains(commandToUnblock)) {
|
||||||
|
sender.sendMessage("§cDer Befehl §e/" + commandToUnblock + "§c ist nicht blockiert!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockedCommands.remove(commandToUnblock);
|
||||||
|
blockedCommandsConfig.set("blocked-commands", blockedCommands);
|
||||||
|
blockedCommandsConfig.save(blockedCommandsFile);
|
||||||
|
sender.sendMessage("§aDer Befehl §e/" + commandToUnblock + "§a wurde aus der Blockierliste entfernt.");
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
sender.sendMessage("§cFehler beim Entfernen des Befehls!");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /sp cb list
|
||||||
|
*/
|
||||||
|
private boolean handleListCommand(CommandSender sender) {
|
||||||
|
if (!sender.hasPermission("survivalplus.commandblocker.list")) {
|
||||||
|
sender.sendMessage("§cDu hast keine Berechtigung für diesen Befehl!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (blockedCommands.isEmpty()) {
|
||||||
|
sender.sendMessage("§eEs sind keine Befehle blockiert.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("§6=== Blockierte Befehle ===");
|
||||||
|
for (String cmd : blockedCommands) {
|
||||||
|
sender.sendMessage("§e- /" + cmd);
|
||||||
|
}
|
||||||
|
sender.sendMessage("§6=====================");
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
sender.sendMessage("§cFehler beim Abrufen der Blockierliste!");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blockiere Befehle, wenn sie in der Liste sind
|
||||||
|
*/
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerCommand(PlayerCommandPreprocessEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.hasPermission("survivalplus.commandblocker.bypass")) {
|
||||||
|
return; // Spieler mit Bypass-Berechtigung ignorieren
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String command = event.getMessage().toLowerCase().replaceFirst("^/", "").trim();
|
||||||
|
// Extrahiere den Hauptbefehl (ohne Argumente)
|
||||||
|
String mainCommand = command.split("\\s+")[0];
|
||||||
|
|
||||||
|
if (blockedCommands.contains(mainCommand)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage("§cDieser Befehl ist blockiert!");
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
// Keine Konsolenausgabe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,18 +6,21 @@ import org.bukkit.*;
|
|||||||
import org.bukkit.block.Chest;
|
import org.bukkit.block.Chest;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.command.*;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
@@ -34,9 +37,17 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
private final int maxLootPerPlayer;
|
private final int maxLootPerPlayer;
|
||||||
private final long lootLimitResetMillis;
|
private final long lootLimitResetMillis;
|
||||||
|
|
||||||
|
// Persistence
|
||||||
|
private final File lootChestFile;
|
||||||
|
private FileConfiguration lootChestConfig;
|
||||||
|
|
||||||
public LootChestManager(SurvivalPlus plugin) {
|
public LootChestManager(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.lootChestFile = new File(plugin.getDataFolder(), "lootchests.yml");
|
||||||
|
this.lootChestConfig = YamlConfiguration.loadConfiguration(lootChestFile);
|
||||||
|
|
||||||
loadLootFromConfig();
|
loadLootFromConfig();
|
||||||
|
loadActiveChests(); // Kisten beim Start laden
|
||||||
|
|
||||||
FileConfiguration cfg = plugin.getConfig();
|
FileConfiguration cfg = plugin.getConfig();
|
||||||
this.despawnMillis = cfg.getLong("lootchest.despawn-minutes", 10) * 60 * 1000;
|
this.despawnMillis = cfg.getLong("lootchest.despawn-minutes", 10) * 60 * 1000;
|
||||||
@@ -49,6 +60,102 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
startLootLimitResetTask();
|
startLootLimitResetTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lädt gespeicherte Kisten aus der Datei und prüft, ob sie abgelaufen sind
|
||||||
|
*/
|
||||||
|
private void loadActiveChests() {
|
||||||
|
if (!lootChestFile.exists()) return;
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
List<Location> toRemoveFile = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String key : lootChestConfig.getKeys(false)) {
|
||||||
|
try {
|
||||||
|
long spawnTime = lootChestConfig.getLong(key);
|
||||||
|
|
||||||
|
// Prüfen ob die Zeit abgelaufen ist (inklusive Offline-Zeit)
|
||||||
|
if (now - spawnTime >= despawnMillis) {
|
||||||
|
String[] parts = key.split("_");
|
||||||
|
if (parts.length == 4) {
|
||||||
|
World w = Bukkit.getWorld(parts[0]);
|
||||||
|
if (w != null) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
Location loc = new Location(w, x, y, z);
|
||||||
|
|
||||||
|
// Kiste physikalisch löschen falls noch vorhanden
|
||||||
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
|
loc.getBlock().setType(Material.AIR);
|
||||||
|
}
|
||||||
|
toRemoveFile.add(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Kiste ist noch gültig -> in den Speicher laden
|
||||||
|
String[] parts = key.split("_");
|
||||||
|
if (parts.length == 4) {
|
||||||
|
World w = Bukkit.getWorld(parts[0]);
|
||||||
|
if (w != null) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
Location loc = new Location(w, x, y, z);
|
||||||
|
|
||||||
|
// Integritätsprüfung: Ist da auch wirklich eine Kiste?
|
||||||
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
|
activeChests.add(loc);
|
||||||
|
chestSpawnTimes.put(loc, spawnTime);
|
||||||
|
} else {
|
||||||
|
// Datei sagt ja, Welt sagt nein -> Cleanup in Datei
|
||||||
|
toRemoveFile.add(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Fehler beim Laden einer Lootkiste: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alte Einträge aus der Datei entfernen
|
||||||
|
for (Location loc : toRemoveFile) {
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, null);
|
||||||
|
}
|
||||||
|
saveActiveChests();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert die aktuellen aktiven Kisten in die Datei
|
||||||
|
*/
|
||||||
|
private void saveActiveChests() {
|
||||||
|
lootChestConfig = new YamlConfiguration();
|
||||||
|
for (Map.Entry<Location, Long> entry : chestSpawnTimes.entrySet()) {
|
||||||
|
Location loc = entry.getKey();
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, entry.getValue());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
lootChestConfig.save(lootChestFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().severe("Konnte lootchests.yml nicht speichern!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt eine Kiste komplett aus System und Datei (z.B. beim Looten)
|
||||||
|
*/
|
||||||
|
private void removeChestData(Location loc) {
|
||||||
|
activeChests.remove(loc);
|
||||||
|
chestSpawnTimes.remove(loc);
|
||||||
|
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, null);
|
||||||
|
saveActiveChests();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadLootFromConfig() {
|
private void loadLootFromConfig() {
|
||||||
FileConfiguration cfg = plugin.getConfig();
|
FileConfiguration cfg = plugin.getConfig();
|
||||||
lootItems.clear();
|
lootItems.clear();
|
||||||
@@ -75,7 +182,11 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Falls deaktiviert, nichts tun
|
||||||
|
// Hinweis: Die Logik hier war "!enabled ... return; clearAll".
|
||||||
|
// Das bedeutet: Wenn enabled=true -> !enabled=false -> kein return -> clearAll.
|
||||||
if (!plugin.getConfig().getBoolean("lootchest.enabled", true)) return;
|
if (!plugin.getConfig().getBoolean("lootchest.enabled", true)) return;
|
||||||
|
|
||||||
clearAllActiveChests();
|
clearAllActiveChests();
|
||||||
for (int i = 0; i < spawnCount; i++) {
|
for (int i = 0; i < spawnCount; i++) {
|
||||||
spawnRandomLootChest();
|
spawnRandomLootChest();
|
||||||
@@ -88,26 +199,36 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startChestDespawnTask() {
|
private void startChestDespawnTask() {
|
||||||
|
// Prüft jede Minute (20 Ticks * 60)
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Sicheres Iterieren um ConcurrentModificationException zu vermeiden
|
||||||
Iterator<Location> it = activeChests.iterator();
|
Iterator<Location> it = activeChests.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Location loc = it.next();
|
Location loc = it.next();
|
||||||
Long spawnTime = chestSpawnTimes.get(loc);
|
Long spawnTime = chestSpawnTimes.get(loc);
|
||||||
|
|
||||||
if (spawnTime != null && now - spawnTime >= despawnMillis) {
|
if (spawnTime != null && now - spawnTime >= despawnMillis) {
|
||||||
if (loc.getBlock().getType() == Material.CHEST) {
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
loc.getBlock().setType(Material.AIR);
|
loc.getBlock().setType(Material.AIR);
|
||||||
}
|
}
|
||||||
it.remove();
|
|
||||||
|
// Manuell aus den Datenstrukturen entfernen
|
||||||
chestSpawnTimes.remove(loc);
|
chestSpawnTimes.remove(loc);
|
||||||
|
it.remove(); // Aus der Liste entfernen (Thread-Safe)
|
||||||
|
|
||||||
Bukkit.broadcastMessage(color(
|
Bukkit.broadcastMessage(color(
|
||||||
plugin.getLangConfig().getString("lootchest.despawn-msg",
|
plugin.getLangConfig().getString("lootchest.despawn-msg",
|
||||||
"&eEine Lootkiste ist von selbst verschwunden.")
|
"&eEine Lootkiste ist von selbst verschwunden.")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config einmal speichern (wichtig!)
|
||||||
|
saveActiveChests();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 20L * 60, 20L * 60);
|
}.runTaskTimer(plugin, 20L * 60, 20L * 60);
|
||||||
}
|
}
|
||||||
@@ -117,6 +238,7 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
if (loc.getBlock().getType() == Material.CHEST) {
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
loc.getBlock().setType(Material.AIR);
|
loc.getBlock().setType(Material.AIR);
|
||||||
}
|
}
|
||||||
|
removeChestData(loc);
|
||||||
}
|
}
|
||||||
activeChests.clear();
|
activeChests.clear();
|
||||||
chestSpawnTimes.clear();
|
chestSpawnTimes.clear();
|
||||||
@@ -158,6 +280,8 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
activeChests.add(loc);
|
activeChests.add(loc);
|
||||||
chestSpawnTimes.put(loc, System.currentTimeMillis());
|
chestSpawnTimes.put(loc, System.currentTimeMillis());
|
||||||
|
|
||||||
|
saveActiveChests();
|
||||||
|
|
||||||
world.spawnParticle(Particle.FIREWORK, loc.clone().add(0.5, 1.0, 0.5),
|
world.spawnParticle(Particle.FIREWORK, loc.clone().add(0.5, 1.0, 0.5),
|
||||||
20, 0.3, 0.5, 0.3);
|
20, 0.3, 0.5, 0.3);
|
||||||
world.playSound(loc, Sound.BLOCK_CHEST_OPEN, 1.0f, 1.0f);
|
world.playSound(loc, Sound.BLOCK_CHEST_OPEN, 1.0f, 1.0f);
|
||||||
@@ -265,8 +389,9 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
if (looted >= maxLootPerPlayer) return;
|
if (looted >= maxLootPerPlayer) return;
|
||||||
playerLootCount.put(uuid, looted + 1);
|
playerLootCount.put(uuid, looted + 1);
|
||||||
chestLoc.getBlock().setType(Material.AIR);
|
chestLoc.getBlock().setType(Material.AIR);
|
||||||
activeChests.remove(chestLoc);
|
|
||||||
chestSpawnTimes.remove(chestLoc);
|
removeChestData(chestLoc);
|
||||||
|
|
||||||
Bukkit.broadcastMessage(color(
|
Bukkit.broadcastMessage(color(
|
||||||
plugin.getLangConfig().getString("lootchest.removed-msg", "&aEine Lootkiste wurde geleert und entfernt.")
|
plugin.getLangConfig().getString("lootchest.removed-msg", "&aEine Lootkiste wurde geleert und entfernt.")
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -28,24 +28,51 @@ public class ShopManager {
|
|||||||
return shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
return shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getStock(String itemKey) {
|
||||||
|
return shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spieler kauft Item: Lager sinkt, Preis steigt (Verknappung)
|
||||||
|
*/
|
||||||
public boolean buyItem(String itemKey, int amount) {
|
public boolean buyItem(String itemKey, int amount) {
|
||||||
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
|
||||||
if (stock < amount) {
|
if (stock < amount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
|
|
||||||
|
// Lager aktualisieren
|
||||||
shopConfig.set("items." + itemKey + ".stock", stock - amount);
|
shopConfig.set("items." + itemKey + ".stock", stock - amount);
|
||||||
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
|
|
||||||
|
// Preis erhöhen (Faktor 1.05 = +5%)
|
||||||
|
double newPrice = price * 1.05;
|
||||||
|
shopConfig.set("items." + itemKey + ".current-price", newPrice);
|
||||||
|
|
||||||
saveShop();
|
saveShop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sellItem(String itemKey, int amount) {
|
/**
|
||||||
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
* Spieler verkauft Item: Lager steigt, Preis sinkt (Überfluss)
|
||||||
|
*/
|
||||||
|
public boolean sellItem(String itemKey, int amount) {
|
||||||
|
// Hier könnte man prüfen, ob der Shop genügend Geld hat (falls nötig)
|
||||||
|
|
||||||
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
|
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
|
||||||
|
// Lager aktualisieren
|
||||||
shopConfig.set("items." + itemKey + ".stock", stock + amount);
|
shopConfig.set("items." + itemKey + ".stock", stock + amount);
|
||||||
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
|
|
||||||
|
// Preis senken (Faktor 0.95 = -5%)
|
||||||
|
double newPrice = price * 0.95;
|
||||||
|
shopConfig.set("items." + itemKey + ".current-price", newPrice);
|
||||||
|
|
||||||
saveShop();
|
saveShop();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addOrUpdateItem(String itemKey, double basePrice, int stock) {
|
public void addOrUpdateItem(String itemKey, double basePrice, int stock) {
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
package de.viper.survivalplus.Manager;
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import net.luckperms.api.LuckPerms;
|
import net.luckperms.api.LuckPerms;
|
||||||
import net.luckperms.api.LuckPermsProvider;
|
import net.luckperms.api.LuckPermsProvider;
|
||||||
import net.luckperms.api.model.user.User;
|
import net.luckperms.api.model.user.User;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.bukkit.scoreboard.Scoreboard;
|
||||||
|
import org.bukkit.scoreboard.ScoreboardManager;
|
||||||
|
import org.bukkit.scoreboard.Team;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
import java.util.regex.Matcher;
|
||||||
import java.util.List;
|
import java.util.regex.Pattern;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class TablistManager {
|
public class TablistManager implements Listener {
|
||||||
|
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
private final List<String> headerAnim = new ArrayList<>();
|
private final List<String> headerAnim = new ArrayList<>();
|
||||||
@@ -34,16 +43,34 @@ public class TablistManager {
|
|||||||
private String staffPermission;
|
private String staffPermission;
|
||||||
private String separatorLine;
|
private String separatorLine;
|
||||||
private LuckPerms luckPerms;
|
private LuckPerms luckPerms;
|
||||||
|
private boolean hasPlaceholderAPI;
|
||||||
|
private FileConfiguration nicknameConfig;
|
||||||
|
|
||||||
|
private final Scoreboard scoreboard;
|
||||||
|
private final Map<String, Team> prefixTeams = new HashMap<>();
|
||||||
|
|
||||||
|
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
||||||
|
|
||||||
public TablistManager(SurvivalPlus plugin) {
|
public TablistManager(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
// Resource sicherstellen, Config laden
|
// Scoreboard initialisieren
|
||||||
try { plugin.saveResource("tablist.yml", false); } catch (Exception ignored) {}
|
ScoreboardManager scoreboardManager = Bukkit.getScoreboardManager();
|
||||||
try { plugin.reloadTablistConfig(); } catch (Throwable ignored) {}
|
this.scoreboard = scoreboardManager != null ? scoreboardManager.getMainScoreboard() : null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
File tablistFile = new File(plugin.getDataFolder(), "tablist.yml");
|
||||||
|
if (!tablistFile.exists()) {
|
||||||
|
plugin.saveResource("tablist.yml", false);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
plugin.reloadTablistConfig();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
FileConfiguration config = plugin.getTablistConfig();
|
FileConfiguration config = plugin.getTablistConfig();
|
||||||
|
|
||||||
// Konfigurationswerte laden
|
|
||||||
this.enabled = config.getBoolean("enabled", true);
|
this.enabled = config.getBoolean("enabled", true);
|
||||||
this.serverName = config.getString("server-name", "SurvivalPlus");
|
this.serverName = config.getString("server-name", "SurvivalPlus");
|
||||||
this.website = config.getString("website", "www.example.com");
|
this.website = config.getString("website", "www.example.com");
|
||||||
@@ -54,24 +81,22 @@ public class TablistManager {
|
|||||||
this.staffPermission = config.getString("staff-permission", "survivalplus.staff");
|
this.staffPermission = config.getString("staff-permission", "survivalplus.staff");
|
||||||
this.separatorLine = config.getString("separator-line", "&8&l&m================");
|
this.separatorLine = config.getString("separator-line", "&8&l&m================");
|
||||||
|
|
||||||
// LuckPerms API initialisieren
|
|
||||||
try {
|
try {
|
||||||
this.luckPerms = LuckPermsProvider.get();
|
this.luckPerms = LuckPermsProvider.get();
|
||||||
} catch (IllegalStateException e) {
|
} catch (Throwable e) {
|
||||||
plugin.getLogger().warning("LuckPerms nicht gefunden! Versuche Fallback auf PlaceholderAPI.");
|
luckPerms = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen, ob PlaceholderAPI verfügbar ist
|
this.hasPlaceholderAPI = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
||||||
if (!Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
|
||||||
plugin.getLogger().warning("PlaceholderAPI nicht gefunden! Verwende Standard-Prefix als Fallback.");
|
// Registriere Chat-Listener hier, damit Prefix im Chat gesetzt wird
|
||||||
}
|
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
plugin.getLogger().info("Tablist ist deaktiviert (tablist.yml -> enabled: false)");
|
plugin.getLogger().info("Tablist ist deaktiviert (tablist.yml -> enabled: false)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header- und Footer-Animationen füllen
|
|
||||||
List<String> configHeader = config.getStringList("header-animations");
|
List<String> configHeader = config.getStringList("header-animations");
|
||||||
List<String> configFooter = config.getStringList("footer-animations");
|
List<String> configFooter = config.getStringList("footer-animations");
|
||||||
|
|
||||||
@@ -98,40 +123,59 @@ public class TablistManager {
|
|||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
reloadNicknameConfig();
|
||||||
|
|
||||||
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
||||||
|
|
||||||
// Online-Spieler und Staff zählen
|
|
||||||
int onlinePlayers = Bukkit.getOnlinePlayers().size();
|
int onlinePlayers = Bukkit.getOnlinePlayers().size();
|
||||||
int onlineStaff = (int) Bukkit.getOnlinePlayers().stream()
|
int onlineStaff = (int) Bukkit.getOnlinePlayers().stream()
|
||||||
.filter(p -> p.hasPermission(staffPermission))
|
.filter(p -> p.hasPermission(staffPermission))
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
// Aktuelles Datum und Uhrzeit formatieren
|
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
|
||||||
String currentTime = dateFormat.format(new Date());
|
String currentTime = dateFormat.format(new Date());
|
||||||
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
try {
|
try {
|
||||||
// Spieler-Prefix abrufen (LuckPerms primär, PlaceholderAPI als Fallback)
|
// ------ Name / Nick handling exactly like in your old code ------
|
||||||
String prefix = getPlayerPrefix(player);
|
String displayName = getNickname(player);
|
||||||
int ping = getPlayerPing(player);
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
// Korrigierte Formatierung: Gesamten String durch color-Methode leiten
|
displayName = player.getName();
|
||||||
String prefixedName = color(prefix + player.getName() + "&8 | &e" + ping + "ms");
|
}
|
||||||
player.setPlayerListName(prefixedName);
|
|
||||||
|
|
||||||
// Header mit Spielername und Statistiken
|
String rankPrefix = getPlayerPrefix(player);
|
||||||
|
// Update nametag (prefix above head) as in old code:
|
||||||
|
updateNametag(player, rankPrefix, getNickname(player)); // pass raw nickname (colored) if present
|
||||||
|
|
||||||
|
// PlayerList (TAB)
|
||||||
|
int ping = getPlayerPing(player);
|
||||||
|
String playerListName;
|
||||||
|
if (luckPerms == null && !hasPlaceholderAPI) {
|
||||||
|
playerListName = displayName;
|
||||||
|
} else {
|
||||||
|
playerListName = color(rankPrefix + displayName + (ping >= 0 ? "&8 | &e" + ping + "ms" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
player.setPlayerListName(playerListName);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
// safe fallback: set without prefix
|
||||||
|
try {
|
||||||
|
player.setPlayerListName(color(displayName));
|
||||||
|
} catch (Exception ignored2) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header/Footer build (including TS/Discord/Website and time)
|
||||||
String headerRaw = headerAnim.get(headerIndex)
|
String headerRaw = headerAnim.get(headerIndex)
|
||||||
.replace("{server}", serverName)
|
.replace("{server}", serverName)
|
||||||
.replace("{player}", player.getName())
|
.replace("{player}", displayName)
|
||||||
.replace("{online}", String.valueOf(onlinePlayers))
|
.replace("{online}", String.valueOf(onlinePlayers))
|
||||||
.replace("{staff}", String.valueOf(onlineStaff));
|
.replace("{staff}", String.valueOf(onlineStaff));
|
||||||
String footerRaw = footerAnim.get(footerIndex);
|
String footerRaw = footerAnim.get(footerIndex);
|
||||||
|
|
||||||
// Footer zusammenstellen: TS und Discord nebeneinander, Webseite zentriert
|
|
||||||
StringBuilder footerBuilder = new StringBuilder();
|
StringBuilder footerBuilder = new StringBuilder();
|
||||||
footerBuilder.append("\n"); // Extra Abstand
|
footerBuilder.append("\n");
|
||||||
footerBuilder.append(color(footerRaw)).append("\n");
|
footerBuilder.append(color(footerRaw)).append("\n");
|
||||||
|
|
||||||
footerBuilder.append(color(separatorLine)).append("\n");
|
footerBuilder.append(color(separatorLine)).append("\n");
|
||||||
if (showTeamspeak || showDiscord) {
|
if (showTeamspeak || showDiscord) {
|
||||||
StringBuilder socialLine = new StringBuilder();
|
StringBuilder socialLine = new StringBuilder();
|
||||||
@@ -153,70 +197,145 @@ public class TablistManager {
|
|||||||
String header = color(headerRaw);
|
String header = color(headerRaw);
|
||||||
String footer = color(footerBuilder.toString());
|
String footer = color(footerBuilder.toString());
|
||||||
|
|
||||||
// 1) Adventure (Component) Variante
|
// Try Adventure-based header/footer first, fallback to String reflection
|
||||||
boolean done = tryAdventureComponent(player, headerRaw, footerBuilder.toString());
|
boolean done = tryAdventureComponent(player, headerRaw, footerBuilder.toString());
|
||||||
|
|
||||||
// 2) String-Variante fallback
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = tryStringMethod(player, header, footer);
|
tryStringMethod(player, header, footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Wenn alles fehlschlägt -> Log
|
} catch (Exception ex) {
|
||||||
if (!done) {
|
plugin.getLogger().warning("TablistManager error: " + ex.getMessage());
|
||||||
plugin.getLogger().warning("Tablist: Keine geeignete Methode gefunden für Spieler " + player.getName());
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
plugin.getLogger().log(Level.FINE, "Fehler beim Setzen der Tablist für Spieler " + player.getName(), t);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headerIndex = (headerIndex + 1) % headerAnim.size();
|
headerIndex = (headerIndex + 1) % headerAnim.size();
|
||||||
footerIndex = (footerIndex + 1) % footerAnim.size();
|
footerIndex = (footerIndex + 1) % footerAnim.size();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 0L, interval);
|
}.runTaskTimer(plugin, 40L, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spieler-Prefix abrufen (LuckPerms primär, PlaceholderAPI als Fallback)
|
* Lädt nicknames.yml neu.
|
||||||
*/
|
*/
|
||||||
private String getPlayerPrefix(Player player) {
|
private void reloadNicknameConfig() {
|
||||||
// Versuche LuckPerms-API zuerst
|
|
||||||
if (luckPerms != null) {
|
|
||||||
try {
|
|
||||||
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
|
||||||
String prefix = user.getCachedData().getMetaData().getPrefix();
|
|
||||||
return (prefix == null || prefix.isEmpty()) ? "&7[Spieler] " : prefix + " ";
|
|
||||||
} catch (Exception e) {
|
|
||||||
plugin.getLogger().log(Level.FINE, "Fehler beim Abrufen des Prefix aus LuckPerms für Spieler " + player.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback auf PlaceholderAPI
|
|
||||||
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
|
||||||
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
|
||||||
return (prefix == null || prefix.isEmpty()) ? "&7[Spieler] " : prefix + " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Letzter Fallback: Standard-Prefix
|
|
||||||
return "&7[Spieler] ";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spieler-Ping abrufen
|
|
||||||
*/
|
|
||||||
private int getPlayerPing(Player player) {
|
|
||||||
try {
|
try {
|
||||||
Method getHandle = player.getClass().getMethod("getHandle");
|
File nicknameFile = new File(plugin.getDataFolder(), "nicknames.yml");
|
||||||
Object entityPlayer = getHandle.invoke(player);
|
if (!nicknameFile.exists()) {
|
||||||
return entityPlayer.getClass().getField("ping").getInt(entityPlayer);
|
plugin.saveResource("nicknames.yml", false);
|
||||||
} catch (Exception e) {
|
}
|
||||||
plugin.getLogger().log(Level.FINE, "Fehler beim Abrufen des Pings für Spieler " + player.getName(), e);
|
this.nicknameConfig = YamlConfiguration.loadConfiguration(nicknameFile);
|
||||||
return -1;
|
} catch (Exception ignored) {
|
||||||
|
this.nicknameConfig = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adventure-Variante mit Components
|
* Nickname abrufen und formatieren (farbig + hex)
|
||||||
|
*/
|
||||||
|
private String getNickname(Player player) {
|
||||||
|
if (nicknameConfig == null) return null;
|
||||||
|
try {
|
||||||
|
String uuid = player.getUniqueId().toString();
|
||||||
|
String nickname = nicknameConfig.getString(uuid);
|
||||||
|
if (nickname != null && !nickname.trim().isEmpty()) {
|
||||||
|
return translateNickColors(nickname);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Übersetzt &-Codes und Hex-Farben
|
||||||
|
*/
|
||||||
|
private String translateNickColors(String input) {
|
||||||
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
String hexCode = matcher.group();
|
||||||
|
String replacement = ChatColor.of(hexCode).toString();
|
||||||
|
matcher.appendReplacement(sb, replacement);
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aktualisiert den Nametag über dem Kopf genau wie in deinem alten Code:
|
||||||
|
* - Wenn Nick vorhanden: Nick als Prefix (zeigt [Nick] Spielername)
|
||||||
|
* - Sonst Rang-Prefix (oder [Spieler] wenn kein Rang)
|
||||||
|
* Der Entry ist dabei immer der echte Spielername.
|
||||||
|
*/
|
||||||
|
private void updateNametag(Player player, String rankPrefix, String nickname) {
|
||||||
|
if (scoreboard == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String teamName = generateTeamName(player, rankPrefix);
|
||||||
|
Team team = scoreboard.getTeam(teamName);
|
||||||
|
|
||||||
|
if (team == null) {
|
||||||
|
// register new team if not exists
|
||||||
|
try {
|
||||||
|
team = scoreboard.registerNewTeam(teamName);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
team = scoreboard.getTeam(teamName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (team == null) return;
|
||||||
|
|
||||||
|
String prefix;
|
||||||
|
if (nickname != null && !nickname.trim().isEmpty()) {
|
||||||
|
prefix = nickname;
|
||||||
|
} else {
|
||||||
|
String rp = (rankPrefix != null && !rankPrefix.trim().isEmpty()) ? rankPrefix : "&7[&aSpieler&7]&f ";
|
||||||
|
prefix = color(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
team.setPrefix(prefix);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
// Ensure the genuine player name is used as the team entry
|
||||||
|
String entry = player.getName();
|
||||||
|
|
||||||
|
if (!team.hasEntry(entry)) {
|
||||||
|
// Remove from other teams to avoid duplicates
|
||||||
|
for (Team existingTeam : scoreboard.getTeams()) {
|
||||||
|
if (existingTeam != null && !existingTeam.getName().equals(teamName)) {
|
||||||
|
try {
|
||||||
|
existingTeam.removeEntry(entry);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
team.addEntry(entry);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize scoreboard to online players (use main scoreboard)
|
||||||
|
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||||
|
try {
|
||||||
|
if (onlinePlayer.getScoreboard() != scoreboard) {
|
||||||
|
onlinePlayer.setScoreboard(scoreboard);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eindeutigen Teamnamen generieren
|
||||||
|
*/
|
||||||
|
private String generateTeamName(Player player, String prefix) {
|
||||||
|
if (prefix == null || prefix.trim().isEmpty()) {
|
||||||
|
return "nametag_" + player.getUniqueId().toString().substring(0, 8);
|
||||||
|
}
|
||||||
|
String sanitizedPrefix = prefix.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
|
||||||
|
return "prefix_" + sanitizedPrefix.substring(0, Math.min(sanitizedPrefix.length(), 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Versucht, Adventure Components zu verwenden (falls verfügbar).
|
||||||
*/
|
*/
|
||||||
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
||||||
try {
|
try {
|
||||||
@@ -225,7 +344,9 @@ public class TablistManager {
|
|||||||
try {
|
try {
|
||||||
textMethod = compClass.getMethod("text", CharSequence.class);
|
textMethod = compClass.getMethod("text", CharSequence.class);
|
||||||
} catch (NoSuchMethodException ignored) {
|
} catch (NoSuchMethodException ignored) {
|
||||||
try { textMethod = compClass.getMethod("text", String.class); } catch (NoSuchMethodException ignored2) {}
|
try {
|
||||||
|
textMethod = compClass.getMethod("text", String.class);
|
||||||
|
} catch (NoSuchMethodException ignored2) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object headerComp = null;
|
Object headerComp = null;
|
||||||
@@ -235,7 +356,6 @@ public class TablistManager {
|
|||||||
headerComp = textMethod.invoke(null, color(headerRaw));
|
headerComp = textMethod.invoke(null, color(headerRaw));
|
||||||
footerComp = textMethod.invoke(null, color(footerRaw));
|
footerComp = textMethod.invoke(null, color(footerRaw));
|
||||||
} else {
|
} else {
|
||||||
// Fallback: MiniMessage
|
|
||||||
try {
|
try {
|
||||||
Class<?> miniMsgClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
Class<?> miniMsgClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
||||||
Method miniMsgSingleton = miniMsgClass.getMethod("miniMessage");
|
Method miniMsgSingleton = miniMsgClass.getMethod("miniMessage");
|
||||||
@@ -243,9 +363,7 @@ public class TablistManager {
|
|||||||
Method deserialize = miniMsgClass.getMethod("deserialize", String.class);
|
Method deserialize = miniMsgClass.getMethod("deserialize", String.class);
|
||||||
headerComp = deserialize.invoke(miniMsg, headerRaw);
|
headerComp = deserialize.invoke(miniMsg, headerRaw);
|
||||||
footerComp = deserialize.invoke(miniMsg, footerRaw);
|
footerComp = deserialize.invoke(miniMsg, footerRaw);
|
||||||
} catch (Throwable t) {
|
} catch (Exception ignored) {}
|
||||||
// kein MiniMessage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerComp == null || footerComp == null) return false;
|
if (headerComp == null || footerComp == null) return false;
|
||||||
@@ -265,17 +383,14 @@ public class TablistManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException cnf) {
|
} catch (Exception ignored) {
|
||||||
return false;
|
// fallback to string method
|
||||||
} catch (Throwable t) {
|
|
||||||
plugin.getLogger().log(Level.FINER, "Adventure-Variante fehlgeschlagen: " + t.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String-Variante
|
* Fallback: konventionelle String-Header/Footer mittels Reflection
|
||||||
*/
|
*/
|
||||||
private boolean tryStringMethod(Player player, String header, String footer) {
|
private boolean tryStringMethod(Player player, String header, String footer) {
|
||||||
try {
|
try {
|
||||||
@@ -295,31 +410,84 @@ public class TablistManager {
|
|||||||
mf.invoke(player, footer);
|
mf.invoke(player, footer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Exception ignored) {}
|
||||||
plugin.getLogger().log(Level.FINER, "String-Variante fehlgeschlagen: " + t.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hilfsmethode für Reflection
|
|
||||||
*/
|
|
||||||
private Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
|
private Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
|
||||||
Class<?> current = clazz;
|
Class<?> current = clazz;
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
try {
|
try {
|
||||||
Method m = current.getMethod(name, paramTypes);
|
Method m = current.getMethod(name, paramTypes);
|
||||||
if (m != null) return m;
|
if (m != null) return m;
|
||||||
} catch (NoSuchMethodException ignored) { }
|
} catch (NoSuchMethodException ignored) {}
|
||||||
current = current.getSuperclass();
|
current = current.getSuperclass();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Farbcode-Konvertierung (& -> §)
|
* Holt den Rang-Prefix (LuckPerms -> PlaceholderAPI -> Default [Spieler])
|
||||||
*/
|
*/
|
||||||
|
private String getPlayerPrefix(Player player) {
|
||||||
|
if (luckPerms != null) {
|
||||||
|
try {
|
||||||
|
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
||||||
|
String prefix = user.getCachedData().getMetaData().getPrefix();
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
if (hasPlaceholderAPI) {
|
||||||
|
try {
|
||||||
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
return "&7[&aSpieler&7]&f ";
|
||||||
|
}
|
||||||
|
if (hasPlaceholderAPI) {
|
||||||
|
try {
|
||||||
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
return "&7[&aSpieler&7]&f ";
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPlayerPing(Player player) {
|
||||||
|
try {
|
||||||
|
Method getHandle = player.getClass().getMethod("getHandle");
|
||||||
|
Object entityPlayer = getHandle.invoke(player);
|
||||||
|
return entityPlayer.getClass().getField("ping").getInt(entityPlayer);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat-Format (Nickname wird hier angezeigt). Setzt Prefix + Nick/Name im Chat.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
|
try {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
String displayName = getNickname(player);
|
||||||
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
|
displayName = player.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String prefix = getPlayerPrefix(player);
|
||||||
|
// Format: Rang + Nick + ": " + Nachricht
|
||||||
|
String format = color(prefix + displayName + "&7: &f") + "%2$s";
|
||||||
|
event.setFormat(format);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
private String color(String msg) {
|
private String color(String msg) {
|
||||||
if (msg == null) return "";
|
if (msg == null) return "";
|
||||||
return msg.replace("&", "§");
|
return msg.replace("&", "§");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class BlockCommand implements CommandExecutor {
|
public class BlockCommand implements CommandExecutor {
|
||||||
|
|
||||||
@@ -20,28 +23,40 @@ public class BlockCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cDieser Befehl ist nur für Spieler!")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.block")) {
|
||||||
|
player.sendMessage(color(config.getString("messages.general.no_permission", "§cDu hast keine Berechtigung für diesen Befehl!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
player.sendMessage(config.getString("messages.block.usage"));
|
player.sendMessage(color(config.getString("messages.block.usage", "§cVerwendung: /block <Spieler>")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player target = Bukkit.getPlayerExact(args[0]);
|
Player target = Bukkit.getPlayerExact(args[0]);
|
||||||
if (target == null || target == player) {
|
if (target == null || target == player) {
|
||||||
player.sendMessage(config.getString("messages.block.invalid_player"));
|
player.sendMessage(color(config.getString("messages.block.invalid_player", "§cDieser Spieler konnte nicht gefunden werden oder bist du selbst.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockManager.hasBlocked(player, target)) {
|
if (blockManager.hasBlocked(player, target)) {
|
||||||
player.sendMessage(config.getString("messages.block.already_blocked").replace("%player%", target.getName()));
|
String msg = config.getString("messages.block.already_blocked", "&cDieser Spieler ist bereits blockiert!");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
} else {
|
} else {
|
||||||
blockManager.blockPlayer(player, target);
|
blockManager.blockPlayer(player, target);
|
||||||
player.sendMessage(config.getString("messages.block.blocked").replace("%player%", target.getName()));
|
String msg = config.getString("messages.block.blocked", "&aDu hast %player% blockiert.");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -22,22 +25,30 @@ public class BlockListCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
// Fallback: "Nur Spieler..." falls Key fehlt
|
||||||
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cNur Spieler können diesen Befehl ausführen!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var blocked = blockManager.getBlockedPlayers(player);
|
var blocked = blockManager.getBlockedPlayers(player);
|
||||||
if (blocked.isEmpty()) {
|
if (blocked.isEmpty()) {
|
||||||
player.sendMessage(config.getString("messages.blocklist.no_blocked_players"));
|
player.sendMessage(color(config.getString("messages.blocklist.no_blocked_players", "§cDu hast keine Spieler blockiert.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String list = blocked.stream()
|
String list = blocked.stream()
|
||||||
.map(Bukkit::getOfflinePlayer)
|
.map(Bukkit::getOfflinePlayer)
|
||||||
.map(p -> p.getName() != null ? p.getName() : "Unbekannt")
|
.map(p -> p.getName() != null ? p.getName() : "§eUnbekannt")
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
|
|
||||||
player.sendMessage(config.getString("messages.blocklist.blocked_players").replace("%list%", list));
|
// WICHTIG: Default-String als zweiten Parameter, um NullPointerException zu vermeiden
|
||||||
|
String rawMessage = config.getString("messages.blocklist.blocked_players", "&eBlockierte Spieler: %list%");
|
||||||
|
player.sendMessage(color(rawMessage.replace("%list%", list)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
226
src/main/java/de/viper/survivalplus/commands/ClaimCommand.java
Normal file
226
src/main/java/de/viper/survivalplus/commands/ClaimCommand.java
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
package de.viper.survivalplus.commands;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import de.viper.survivalplus.util.Claim;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ClaimCommand implements CommandExecutor {
|
||||||
|
private SurvivalPlus plugin;
|
||||||
|
private static final int MAX_CLAIMS = 10;
|
||||||
|
private static final int MAX_AREA = 10000; // 100x100 blocks
|
||||||
|
|
||||||
|
public ClaimCommand(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
sender.sendMessage(plugin.getMessage("commands.player-only"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
if (!player.hasPermission("survivalplus.claim.use")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Location point1 = plugin.getPoint1(player);
|
||||||
|
Location point2 = plugin.getPoint2(player);
|
||||||
|
if (point1 == null || point2 == null) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.points-not-set"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!point1.getWorld().equals(point2.getWorld())) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.different-worlds"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int x1 = point1.getBlockX();
|
||||||
|
int z1 = point1.getBlockZ();
|
||||||
|
int x2 = point2.getBlockX();
|
||||||
|
int z2 = point2.getBlockZ();
|
||||||
|
int width = Math.abs(x2 - x1) + 1;
|
||||||
|
int length = Math.abs(z2 - z1) + 1;
|
||||||
|
if (width * length > MAX_AREA) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.too-large").replace("%max%", String.valueOf(MAX_AREA)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Claim newClaim = new Claim(player, point1.getWorld().getName(), x1, z1, x2, z2);
|
||||||
|
if (plugin.hasOverlap(newClaim)) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.overlap"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (plugin.getClaimCount(player) >= MAX_CLAIMS) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.max-reached").replace("%max%", String.valueOf(MAX_CLAIMS)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
plugin.addClaim(newClaim, player);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.success").replace("%count%", String.valueOf(plugin.getClaimCount(player))).replace("%max%", String.valueOf(MAX_CLAIMS)));
|
||||||
|
plugin.clearSelections(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (args[0].toLowerCase()) {
|
||||||
|
case "mark":
|
||||||
|
if (!player.hasPermission("survivalplus.claim.use")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 2 || (!args[1].equals("1") && !args[1].equals("2"))) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.usage-mark"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Location location = player.getLocation();
|
||||||
|
if (args[1].equals("1")) {
|
||||||
|
plugin.setPoint1(player, location);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.point1-set").replace("%x%", String.valueOf(location.getBlockX())).replace("%z%", String.valueOf(location.getBlockZ())));
|
||||||
|
} else {
|
||||||
|
plugin.setPoint2(player, location);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.point2-set").replace("%x%", String.valueOf(location.getBlockX())).replace("%z%", String.valueOf(location.getBlockZ())));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "unclaim":
|
||||||
|
if (args.length == 1) {
|
||||||
|
if (!player.hasPermission("survivalplus.claim.use")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Claim claim = plugin.getClaim(player.getLocation());
|
||||||
|
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.not-owner"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
plugin.removeClaim(player.getLocation(), player);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.unclaimed"));
|
||||||
|
return true;
|
||||||
|
} else if (args.length == 2 && player.isOp()) {
|
||||||
|
Player target = Bukkit.getPlayer(args[1]);
|
||||||
|
UUID targetUUID;
|
||||||
|
if (target != null) {
|
||||||
|
targetUUID = target.getUniqueId();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
targetUUID = UUID.fromString(args[1]);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.player-not-found"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int removedCount = removePlayerClaims(targetUUID);
|
||||||
|
if (removedCount > 0) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.op-unclaimed")
|
||||||
|
.replace("%player%", args[1])
|
||||||
|
.replace("%count%", String.valueOf(removedCount)));
|
||||||
|
} else {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.no-claims-found")
|
||||||
|
.replace("%player%", args[1]));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "trust":
|
||||||
|
if (!player.hasPermission("survivalplus.claim.trust")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.usage-trust"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player target = Bukkit.getPlayer(args[1]);
|
||||||
|
if (target == null) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.player-not-found"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Claim claim = plugin.getClaim(player.getLocation());
|
||||||
|
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.not-owner"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
claim.addTrusted(target.getUniqueId());
|
||||||
|
player.sendMessage(plugin.getMessage("claim.trusted").replace("%player%", args[1]));
|
||||||
|
plugin.saveClaims();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "untrust":
|
||||||
|
if (!player.hasPermission("survivalplus.claim.trust")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.usage-untrust"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
target = Bukkit.getPlayer(args[1]);
|
||||||
|
if (target == null) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.player-not-found"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
claim = plugin.getClaim(player.getLocation());
|
||||||
|
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.not-owner"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
claim.removeTrusted(target.getUniqueId());
|
||||||
|
player.sendMessage(plugin.getMessage("claim.untrusted").replace("%player%", args[1]));
|
||||||
|
plugin.saveClaims();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "info":
|
||||||
|
if (!player.hasPermission("survivalplus.claim.use")) {
|
||||||
|
player.sendMessage(plugin.getMessage("commands.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
claim = plugin.getClaim(player.getLocation());
|
||||||
|
if (claim == null) {
|
||||||
|
player.sendMessage(plugin.getMessage("claim.no-claim-at-location"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String ownerName = Bukkit.getOfflinePlayer(claim.getOwner()).getName();
|
||||||
|
if (ownerName == null) {
|
||||||
|
ownerName = claim.getOwner().toString(); // Fallback to UUID if name not found
|
||||||
|
}
|
||||||
|
player.sendMessage(plugin.getMessage("claim.info")
|
||||||
|
.replace("%owner%", ownerName)
|
||||||
|
.replace("%world%", claim.getWorldName())
|
||||||
|
.replace("%x1%", String.valueOf(claim.getX1()))
|
||||||
|
.replace("%z1%", String.valueOf(claim.getZ1()))
|
||||||
|
.replace("%x2%", String.valueOf(claim.getX2()))
|
||||||
|
.replace("%z2%", String.valueOf(claim.getZ2())));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
player.sendMessage(plugin.getMessage("claim.usage"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int removePlayerClaims(UUID targetUUID) {
|
||||||
|
Map<String, Claim> claims = new HashMap<>(plugin.getClaims());
|
||||||
|
int removedCount = 0;
|
||||||
|
for (Map.Entry<String, Claim> entry : claims.entrySet()) {
|
||||||
|
if (entry.getValue().getOwner().equals(targetUUID)) {
|
||||||
|
plugin.removeClaimByKey(entry.getKey(), targetUUID);
|
||||||
|
removedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (removedCount > 0) {
|
||||||
|
plugin.saveClaims();
|
||||||
|
}
|
||||||
|
return removedCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -116,14 +116,14 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendHelpMessage(Player player) {
|
private void sendHelpMessage(Player player) {
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.header", "&6=== Freundesliste Hilfe ===")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.header", "&6== Freundesliste Hilfe ==")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.add", "&e/friend add <Spielername> &7- Freundschaftsanfrage senden")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.add", "&e/friend add <Spielername> &7- Freundschaftsanfrage senden")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.accept", "&e/friend accept <Spielername> &7- Freundschaftsanfrage akzeptieren")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.accept", "&e/friend accept <Spielername> &7- Freundschaftsanfrage akzeptieren")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.deny", "&e/friend deny <Spielername> &7- Freundschaftsanfrage ablehnen")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.deny", "&e/friend deny <Spielername> &7- Freundschaftsanfrage ablehnen")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.list", "&e/friend list &7- Liste deiner Freunde anzeigen")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.list", "&e/friend list &7- Liste deiner Freunde anzeigen")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.del", "&e/friend del <Spielername> &7- Freund aus der Liste entfernen")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.del", "&e/friend del <Spielername> &7- Freund aus der Liste entfernen")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.tp", "&e/friend tp <Spielername> &7- Zu einem Freund teleportieren")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.tp", "&e/friend tp <Spielername> &7- Zu einem Freund teleportieren")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.footer", "&6=====================")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.footer", "&6=======================")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFriendAdd(Player player, String targetName) {
|
private void handleFriendAdd(Player player, String targetName) {
|
||||||
@@ -155,15 +155,23 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
pendingRequests.add(playerUUID.toString());
|
pendingRequests.add(playerUUID.toString());
|
||||||
friendsConfig.set(targetUUID + ".pending_requests", pendingRequests);
|
friendsConfig.set(targetUUID + ".pending_requests", pendingRequests);
|
||||||
friendsConfig.set(targetUUID + ".name", targetName);
|
friendsConfig.set(targetUUID + ".name", targetName);
|
||||||
|
|
||||||
|
// --- FIX START: Absenderdaten speichern, damit er auch offline gefunden werden kann ---
|
||||||
|
friendsConfig.set(playerUUID + ".name", player.getName());
|
||||||
|
friendsConfig.set(playerUUID + ".last-online", System.currentTimeMillis());
|
||||||
|
// --- FIX END ---
|
||||||
|
|
||||||
saveFriendsConfig();
|
saveFriendsConfig();
|
||||||
|
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.sent", "&aFreundschaftsanfrage an %s gesendet!").replace("%s", targetName)));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.sent", "&aFreundschaftsanfrage an %s gesendet!").replace("%s", targetName)));
|
||||||
|
|
||||||
TextComponent message = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.received", "&aDu hast eine Freundschaftsanfrage von %s erhalten! ").replace("%s", player.getName())));
|
TextComponent message = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.received", "&aDu hast eine Freundschaftsanfrage von %s erhalten! ").replace("%s", player.getName())));
|
||||||
TextComponent accept = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.accept-button", "&a[Accept]")));
|
TextComponent accept = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.accept-button", "&a[Accept]")));
|
||||||
accept.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend accept " + player.getName()));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
accept.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend accept " + player.getName()));
|
||||||
TextComponent deny = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.deny-button", "&c [Deny]")));
|
TextComponent deny = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.deny-button", "&c [Deny]")));
|
||||||
deny.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend deny " + player.getName()));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
deny.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend deny " + player.getName()));
|
||||||
message.addExtra(accept);
|
message.addExtra(accept);
|
||||||
message.addExtra(deny);
|
message.addExtra(deny);
|
||||||
target.spigot().sendMessage(message);
|
target.spigot().sendMessage(message);
|
||||||
@@ -268,7 +276,8 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextComponent removeButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.remove-button", "&c[X]")));
|
TextComponent removeButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.remove-button", "&c[X]")));
|
||||||
removeButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend del " + friendName));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
removeButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend del " + friendName));
|
||||||
entry.addExtra(" ");
|
entry.addExtra(" ");
|
||||||
entry.addExtra(removeButton);
|
entry.addExtra(removeButton);
|
||||||
|
|
||||||
@@ -296,9 +305,11 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
|
|
||||||
TextComponent confirmMessage = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm", "&cMöchtest du %s wirklich aus deiner Freundesliste entfernen? ").replace("%s", friendName)));
|
TextComponent confirmMessage = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm", "&cMöchtest du %s wirklich aus deiner Freundesliste entfernen? ").replace("%s", friendName)));
|
||||||
TextComponent confirmButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm-button", "&a[Confirm]")));
|
TextComponent confirmButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm-button", "&a[Confirm]")));
|
||||||
confirmButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend confirm " + friendName));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
confirmButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend confirm " + friendName));
|
||||||
TextComponent cancelButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.cancel-button", "&c[Cancel]")));
|
TextComponent cancelButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.cancel-button", "&c[Cancel]")));
|
||||||
cancelButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend list"));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
cancelButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend list"));
|
||||||
confirmMessage.addExtra(confirmButton);
|
confirmMessage.addExtra(confirmButton);
|
||||||
confirmMessage.addExtra(" ");
|
confirmMessage.addExtra(" ");
|
||||||
confirmMessage.addExtra(cancelButton);
|
confirmMessage.addExtra(cancelButton);
|
||||||
|
|||||||
@@ -34,10 +34,25 @@ public class NickCommand implements CommandExecutor {
|
|||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
player.sendMessage("§eBenutzung: /nick <Name>");
|
player.sendMessage("§eBenutzung: /nick <Name>");
|
||||||
|
player.sendMessage("§eVerwende /nick off um den Nickname zu entfernen.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name zusammensetzen
|
// Entfernen des Nicks
|
||||||
|
if (args.length == 1 && (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("remove") || args[0].equalsIgnoreCase("reset"))) {
|
||||||
|
String uuid = player.getUniqueId().toString();
|
||||||
|
|
||||||
|
plugin.getNicknamesConfig().set(uuid, null);
|
||||||
|
plugin.saveNicknamesConfig();
|
||||||
|
|
||||||
|
// WICHTIG: Nur DisplayName setzen, TablistManager übernimmt den Rest
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
|
||||||
|
player.sendMessage("§aDein Nickname wurde entfernt.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zusammenbauen des Nicknames
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
sb.append(arg).append(" ");
|
sb.append(arg).append(" ");
|
||||||
@@ -56,28 +71,24 @@ public class NickCommand implements CommandExecutor {
|
|||||||
// Farben anwenden
|
// Farben anwenden
|
||||||
String coloredNick = translateColors(rawNick);
|
String coloredNick = translateColors(rawNick);
|
||||||
|
|
||||||
// Format: [Nickname] (Klammern weiß, Nickname farbig)
|
// Chat/Display: [Nick]
|
||||||
String finalNick = "§f[" + coloredNick + "§f]";
|
String finalNickForDisplay = "§f[" + coloredNick + "§f]";
|
||||||
|
|
||||||
// Anwenden
|
// WICHTIG: Nur DisplayName setzen
|
||||||
player.setDisplayName(finalNick);
|
// playerListName wird vom TablistManager automatisch gesetzt
|
||||||
player.setPlayerListName(finalNick);
|
player.setDisplayName(finalNickForDisplay);
|
||||||
|
|
||||||
// Speichern (ungefärbten Namen)
|
// Speichern (ungefärbten Namen)
|
||||||
plugin.getNicknamesConfig().set(player.getUniqueId().toString(), rawNick);
|
plugin.getNicknamesConfig().set(player.getUniqueId().toString(), rawNick);
|
||||||
plugin.saveNicknamesConfig();
|
plugin.saveNicknamesConfig();
|
||||||
|
|
||||||
player.sendMessage("§aDein Nickname wurde zu " + finalNick + " geändert.");
|
player.sendMessage("§aDein Nickname wurde zu " + finalNickForDisplay + " geändert.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String translateColors(String input) {
|
private String translateColors(String input) {
|
||||||
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
return replaceHexColors(withLegacy);
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceHexColors(String input) {
|
|
||||||
Matcher matcher = HEX_PATTERN.matcher(input);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = matcher.group();
|
String hexCode = matcher.group();
|
||||||
|
|||||||
100
src/main/java/de/viper/survivalplus/commands/RideCommand.java
Normal file
100
src/main/java/de/viper/survivalplus/commands/RideCommand.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package de.viper.survivalplus.commands;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
|
public class RideCommand implements CommandExecutor {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
|
||||||
|
public RideCommand(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
sender.sendMessage("Dieser Befehl ist nur für Spieler!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player) sender;
|
||||||
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.ride")) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du hast keine Berechtigung dafür!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FALL 1: ABSTEIGEN ---
|
||||||
|
if (args.length == 0) {
|
||||||
|
if (player.isInsideVehicle()) {
|
||||||
|
player.leaveVehicle();
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du bist abgestiegen!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FALL 2: AUFSTEIGEN (Via Raycast) ---
|
||||||
|
|
||||||
|
double maxDistance = 5.0;
|
||||||
|
|
||||||
|
// FIX: Wir übergeben einen Filter, der den Spieler selbst ignoriert
|
||||||
|
RayTraceResult rayTrace = player.getWorld().rayTraceEntities(
|
||||||
|
player.getEyeLocation(),
|
||||||
|
player.getEyeLocation().getDirection(),
|
||||||
|
maxDistance,
|
||||||
|
1.0, // Ray Größe (Dicke des Strahls)
|
||||||
|
entity -> !entity.getUniqueId().equals(player.getUniqueId()) // WICHTIG: Ignoriere mich selbst
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rayTrace == null || rayTrace.getHitEntity() == null) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du schaust auf nichts zum Reiten!");
|
||||||
|
player.sendMessage(ChatColor.GRAY + "Schaue einen Spieler oder Mob an.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity target = rayTrace.getHitEntity();
|
||||||
|
|
||||||
|
// Verhindern, dass man aufgesammelte Items reitet
|
||||||
|
if (target instanceof Item) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst keine aufgesammelten Items reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Zielle Logik ---
|
||||||
|
if (target instanceof Player) {
|
||||||
|
Player targetPlayer = (Player) target;
|
||||||
|
|
||||||
|
if (targetPlayer.equals(player)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst dich nicht selbst reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPlayer.hasPermission("survivalplus.ride.exempt")) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst diesen Spieler nicht reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.addPassenger(player);
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du reitest nun " + ChatColor.YELLOW + targetPlayer.getName() + ChatColor.GREEN + "!");
|
||||||
|
targetPlayer.sendMessage(ChatColor.GOLD + player.getName() + ChatColor.GREEN + " reitet dich jetzt!");
|
||||||
|
} else {
|
||||||
|
target.addPassenger(player);
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du reitest nun ein(e) " + target.getName() + "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendMessage(ChatColor.GRAY + "Benutzung: Schaue auf ein Wesen und tippe " + ChatColor.WHITE + "/ride");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.ShopManager;
|
import de.viper.survivalplus.Manager.ShopManager;
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.gui.ShopGui;
|
import de.viper.survivalplus.gui.ShopGui; // <--- WICHTIG: Dieser Import fehlte dir
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -34,7 +34,7 @@ public class ShopCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
|
|
||||||
// Shop-GUI öffnen, wenn kein Argument oder "gui"
|
// Shop-GUI öffnen
|
||||||
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
|
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
|
||||||
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
|
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
|
||||||
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
|
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
|
||||||
@@ -42,41 +42,69 @@ public class ShopCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length < 3) {
|
|
||||||
sender.sendMessage(getMessage("usage-add"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args[0].toLowerCase().equals("add")) {
|
if (!args[0].toLowerCase().equals("add")) {
|
||||||
sender.sendMessage(getMessage("unknown-subcommand"));
|
sender.sendMessage(getMessage("unknown-subcommand"));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack itemInHand = player.getInventory().getItemInMainHand();
|
|
||||||
if (itemInHand == null || itemInHand.getType() == Material.AIR) {
|
|
||||||
sender.sendMessage(ChatColor.RED + "Du musst das Item, das du hinzufügen willst, in der Hand halten!");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String itemKey = itemInHand.getType().name().toLowerCase();
|
// --- Neue Logik für /shop add ---
|
||||||
|
|
||||||
|
String itemKey;
|
||||||
double basePrice;
|
double basePrice;
|
||||||
int stock;
|
int stock;
|
||||||
|
|
||||||
try {
|
// Fall 1: /shop add <Material> <Preis> <Stock> (4 Argumente)
|
||||||
basePrice = Double.parseDouble(args[1]);
|
if (args.length >= 4) {
|
||||||
stock = Integer.parseInt(args[2]);
|
String materialName = args[1];
|
||||||
} catch (NumberFormatException e) {
|
Material mat = Material.matchMaterial(materialName);
|
||||||
sender.sendMessage(getMessage("number-error"));
|
|
||||||
return false;
|
if (mat == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Das Material '" + materialName + "' wurde nicht gefunden!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
itemKey = mat.name().toLowerCase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
basePrice = Double.parseDouble(args[2]);
|
||||||
|
stock = Integer.parseInt(args[3]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Ungültige Preis oder Bestandszahl! Beispiel: /shop add Diamond 20 64");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Fall 2: /shop add <Preis> <Stock> (3 Argumente) -> Nimmt Item in der Hand
|
||||||
|
else if (args.length == 3) {
|
||||||
|
ItemStack itemInHand = player.getInventory().getItemInMainHand();
|
||||||
|
if (itemInHand == null || itemInHand.getType() == Material.AIR) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Du musst das Item, das du hinzufügen willst, in der Hand halten!");
|
||||||
|
sender.sendMessage(ChatColor.GRAY + "Oder benutze: /shop add <Material> <Preis> <Bestand>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
itemKey = itemInHand.getType().name().toLowerCase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
basePrice = Double.parseDouble(args[1]);
|
||||||
|
stock = Integer.parseInt(args[2]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage(getMessage("number-error"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Falsche Anzahl an Argumenten
|
||||||
|
else {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Falsche Benutzung!");
|
||||||
|
sender.sendMessage(ChatColor.GRAY + "Mit Item in Hand: /shop add <Preis> <Bestand>");
|
||||||
|
sender.sendMessage(ChatColor.GRAY + "Mit Namen: /shop add <Material> <Preis> <Bestand>");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
|
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
|
||||||
|
|
||||||
String msg = getMessage("item-added")
|
String msg = getMessage("item-added")
|
||||||
.replace("{item}", itemKey)
|
.replace("{item}", itemKey)
|
||||||
.replace("{price}", args[1])
|
.replace("{price}", String.valueOf(basePrice))
|
||||||
.replace("{stock}", args[2]);
|
.replace("{stock}", String.valueOf(stock));
|
||||||
sender.sendMessage(msg);
|
sender.sendMessage(msg);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.listeners.SitListener;
|
import de.viper.survivalplus.listeners.SitListener;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@@ -38,20 +41,50 @@ public class SitCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe, ob der Spieler bereits sitzt
|
// --- ÄNDERUNG: Wenn man schon sitzt, tue nichts ---
|
||||||
if (sitListener.isSitting(player)) {
|
if (sitListener.isSitting(player)) {
|
||||||
sitListener.standUp(player);
|
player.sendMessage(ChatColor.RED + "Du sitzt bereits!");
|
||||||
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
return true;
|
||||||
|
}
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
if (player.isInsideVehicle()) {
|
||||||
|
player.sendMessage(lang.getString("sit.already-in-vehicle", "§cDu kannst dich nicht setzen, während du in einem Fahrzeug bist!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setze den Spieler mittig auf den Block und leicht oberhalb (Fix)
|
// Prüfe den Boden unter dem Spieler
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
Block blockBelow = loc.clone().subtract(0, 1, 0).getBlock();
|
||||||
|
|
||||||
|
if (blockBelow.getType().isAir() || !blockBelow.getType().isSolid()) {
|
||||||
|
player.sendMessage(plugin.getLangConfig().getString("sit.no-solid-ground", "§cDu kannst dich hier nicht hinsetzen (kein fester Boden)."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position vorbereiten
|
||||||
Location location = player.getLocation();
|
Location location = player.getLocation();
|
||||||
location.setX(location.getBlockX() + 0.5);
|
location.setX(location.getBlockX() + 0.5);
|
||||||
location.setY(location.getBlockY() + 0.25);
|
|
||||||
location.setZ(location.getBlockZ() + 0.5);
|
location.setZ(location.getBlockZ() + 0.5);
|
||||||
|
|
||||||
|
// Höhe dynamisch berechnen
|
||||||
|
double y = location.getBlockY();
|
||||||
|
|
||||||
|
if (isStair(blockBelow.getType()) || isSlab(blockBelow.getType())) {
|
||||||
|
y += 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.setY(y);
|
||||||
|
|
||||||
sitListener.sitPlayer(player, location);
|
sitListener.sitPlayer(player, location);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStair(Material material) {
|
||||||
|
return material.name().endsWith("_STAIRS");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlab(Material material) {
|
||||||
|
return material.name().endsWith("_SLAB") || material.name().endsWith("_STEP") || material.name().equals("PRISMARINE_SLAB");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class UnblockCommand implements CommandExecutor {
|
public class UnblockCommand implements CommandExecutor {
|
||||||
|
|
||||||
@@ -20,29 +23,40 @@ public class UnblockCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cDieser Befehl ist nur für Spieler!")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.unblock")) {
|
||||||
|
player.sendMessage(color(config.getString("messages.general.no_permission", "§cDu hast keine Berechtigung für diesen Befehl!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
player.sendMessage(config.getString("messages.unblock.usage"));
|
player.sendMessage(color(config.getString("messages.block.usage", "§cVerwendung: /unblock <Spieler>")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player target = Bukkit.getPlayerExact(args[0]);
|
Player target = Bukkit.getPlayerExact(args[0]);
|
||||||
if (target == null || target == player) {
|
if (target == null || target == player) {
|
||||||
player.sendMessage(config.getString("messages.unblock.invalid_player"));
|
player.sendMessage(color(config.getString("messages.block.invalid_player", "§cDieser Spieler konnte nicht gefunden werden oder bist du selbst.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockManager.hasBlocked(player, target)) {
|
if (!blockManager.hasBlocked(player, target)) {
|
||||||
blockManager.unblockPlayer(player, target);
|
String msg = config.getString("messages.block.not_blocked", "&cDieser Spieler ist nicht blockiert.");
|
||||||
player.sendMessage(config.getString("messages.unblock.unblocked").replace("%player%", target.getName()));
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
target.sendMessage(config.getString("messages.unblock.unblocked_by").replace("%player%", player.getName()));
|
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(config.getString("messages.unblock.not_blocked").replace("%player%", target.getName()));
|
blockManager.unblockPlayer(player, target);
|
||||||
|
String msg = config.getString("messages.block.unblocked", "&aDu hast %player% entblockt.");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,8 +42,7 @@ public class ShopGui implements Listener {
|
|||||||
for (String itemKey : shopManager.getShopConfig().getConfigurationSection("items").getKeys(false)) {
|
for (String itemKey : shopManager.getShopConfig().getConfigurationSection("items").getKeys(false)) {
|
||||||
Material mat = getMaterialFromKey(itemKey);
|
Material mat = getMaterialFromKey(itemKey);
|
||||||
if (mat == null) {
|
if (mat == null) {
|
||||||
player.sendMessage(ChatColor.RED + "Material für '" + itemKey + "' konnte nicht gefunden werden.");
|
continue; // Unbekannte Materialien einfach überspringen
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addShopItem(itemKey, mat, 64);
|
addShopItem(itemKey, mat, 64);
|
||||||
@@ -64,6 +63,7 @@ public class ShopGui implements Listener {
|
|||||||
|
|
||||||
private void addShopItem(String itemKey, Material material, int amount) {
|
private void addShopItem(String itemKey, Material material, int amount) {
|
||||||
double pricePerUnit = shopManager.getCurrentPrice(itemKey);
|
double pricePerUnit = shopManager.getCurrentPrice(itemKey);
|
||||||
|
int currentStock = shopManager.getStock(itemKey);
|
||||||
double totalPrice = pricePerUnit * amount;
|
double totalPrice = pricePerUnit * amount;
|
||||||
|
|
||||||
ItemStack item = new ItemStack(material, amount);
|
ItemStack item = new ItemStack(material, amount);
|
||||||
@@ -71,9 +71,12 @@ public class ShopGui implements Listener {
|
|||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(ChatColor.GREEN.toString() + amount + "x " + material.name());
|
meta.setDisplayName(ChatColor.GREEN.toString() + amount + "x " + material.name());
|
||||||
meta.setLore(Arrays.asList(
|
meta.setLore(Arrays.asList(
|
||||||
|
ChatColor.GRAY + "Lagerbestand: " + ChatColor.YELLOW + currentStock,
|
||||||
ChatColor.YELLOW + "Preis pro Stück: " + pricePerUnit,
|
ChatColor.YELLOW + "Preis pro Stück: " + pricePerUnit,
|
||||||
ChatColor.YELLOW + "Gesamtpreis: " + totalPrice,
|
ChatColor.YELLOW + "Gesamtpreis: " + totalPrice,
|
||||||
ChatColor.GRAY + "Klicke, um zu kaufen"
|
"",
|
||||||
|
ChatColor.GREEN + "Linksklick zum Kaufen",
|
||||||
|
ChatColor.RED + "Rechtsklick zum Verkaufen"
|
||||||
));
|
));
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
@@ -101,25 +104,54 @@ public class ShopGui implements Listener {
|
|||||||
Material mat = clicked.getType();
|
Material mat = clicked.getType();
|
||||||
String itemKey = mat.name().toLowerCase();
|
String itemKey = mat.name().toLowerCase();
|
||||||
|
|
||||||
if (!shopManager.buyItem(itemKey, amount)) {
|
if (e.isLeftClick()) {
|
||||||
player.sendMessage(ChatColor.RED + "Nicht genügend Bestand im Shop.");
|
// --- KAUFEN ---
|
||||||
return;
|
if (!shopManager.buyItem(itemKey, amount)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Nicht genügend Bestand im Shop.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalPrice = shopManager.getCurrentPrice(itemKey) * amount;
|
||||||
|
|
||||||
|
// TODO: Economy Abzug hier einfügen!
|
||||||
|
// Beispiel: if (!economy.withdrawPlayer(player, totalPrice)) { ... }
|
||||||
|
|
||||||
|
player.getInventory().addItem(new ItemStack(mat, amount));
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + String.format("%.2f", totalPrice) + " gekauft.");
|
||||||
|
|
||||||
|
} else if (e.isRightClick()) {
|
||||||
|
// --- VERKAUFEN ---
|
||||||
|
|
||||||
|
// Prüfen ob Spieler genug Items hat
|
||||||
|
if (!player.getInventory().containsAtLeast(new ItemStack(mat), amount)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du hast nicht genug Items zum Verkaufen.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verkaufslogik
|
||||||
|
shopManager.sellItem(itemKey, amount);
|
||||||
|
|
||||||
|
double sellPrice = shopManager.getCurrentPrice(itemKey) * amount; // Neuer Preis nach dem Verkauf wird genutzt
|
||||||
|
// Hinweis: In echten Systemen bekommt man oft den Preis *vor* dem Preisverfall, hier nehmen wir den neuen für Einfachheit oder den gespeicherten:
|
||||||
|
// Besser wäre: double oldPrice = price * amount; ... player.giveMoney(oldPrice);
|
||||||
|
|
||||||
|
// TODO: Economy Gutschrift hier einfügen!
|
||||||
|
|
||||||
|
player.getInventory().removeItem(new ItemStack(mat, amount));
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + String.format("%.2f", sellPrice) + " verkauft.");
|
||||||
}
|
}
|
||||||
|
|
||||||
double totalPrice = shopManager.getCurrentPrice(itemKey) * amount;
|
// Inventory schließen, um Preise neu zu laden und Bugs zu vermeiden
|
||||||
|
|
||||||
// TODO: Economy Abzug einfügen
|
|
||||||
|
|
||||||
player.getInventory().addItem(new ItemStack(mat, amount));
|
|
||||||
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + totalPrice + " Coins gekauft.");
|
|
||||||
|
|
||||||
player.closeInventory();
|
player.closeInventory();
|
||||||
|
// Optional: direkt neu öffnen mit createInventory() wenn es flüssig sein soll
|
||||||
|
// createInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent e) {
|
public void onInventoryClose(InventoryCloseEvent e) {
|
||||||
if (e.getView().getTitle().equals("Shop") && e.getPlayer().equals(player)) {
|
if (e.getView().getTitle().equals("Shop") && e.getPlayer().equals(player)) {
|
||||||
// Optional: Listener entfernen oder Aufräumarbeiten hier
|
// Listener kann entladen werden, wenn nicht mehr gebraucht
|
||||||
|
// HandlerList.unregisterAll(this); // Vorsicht: falls Singleton, sonst fliegt allen der GUI weg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.*;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDeathEvent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AdaptiveMobListener implements Listener {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
|
||||||
|
// Konfiguration für die Anpassung
|
||||||
|
private final double SCALING_FACTOR = 0.1; // 10% mehr Stärke pro Level
|
||||||
|
private final int KILLS_PER_LEVEL = 5; // Alle 5 Kills steigt das Level
|
||||||
|
private final int MAX_LEVEL = 50; // Maximales Level (Cap)
|
||||||
|
|
||||||
|
public AdaptiveMobListener(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Verhalten tracken: Zählt Kills des Spielers
|
||||||
|
@EventHandler
|
||||||
|
public void onMobDeath(EntityDeathEvent event) {
|
||||||
|
if (event.getEntity().getKiller() instanceof Player) {
|
||||||
|
Player killer = event.getEntity().getKiller();
|
||||||
|
UUID uuid = killer.getUniqueId();
|
||||||
|
|
||||||
|
FileConfiguration mobConfig = plugin.getMobAdaptConfig();
|
||||||
|
String uuidPath = uuid.toString();
|
||||||
|
|
||||||
|
int currentLevel = mobConfig.getInt(uuidPath + ".level", 0);
|
||||||
|
int currentKills = mobConfig.getInt(uuidPath + ".kills", 0);
|
||||||
|
|
||||||
|
currentKills++;
|
||||||
|
|
||||||
|
// Level up wenn genug Kills
|
||||||
|
if (currentKills >= KILLS_PER_LEVEL && currentLevel < MAX_LEVEL) {
|
||||||
|
currentLevel++;
|
||||||
|
currentKills = 0;
|
||||||
|
killer.sendMessage(ChatColor.GREEN + "[SurvivalPlus] " + ChatColor.GRAY + "Die Monster werden aggressiver! (Threat Level: " + currentLevel + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speichern
|
||||||
|
mobConfig.set(uuidPath + ".level", currentLevel);
|
||||||
|
mobConfig.set(uuidPath + ".kills", currentKills);
|
||||||
|
plugin.saveMobAdaptConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Anpassung: Monster werden beim Spawnen angepasst
|
||||||
|
@EventHandler
|
||||||
|
public void onCreatureSpawn(CreatureSpawnEvent event) {
|
||||||
|
// Nur aktivieren, wenn in Config gewünscht
|
||||||
|
if (!plugin.getConfig().getBoolean("adaptive-mobs.enabled", true)) return;
|
||||||
|
|
||||||
|
// Wir greifen nur bei natürlichen Spawns ein (oder Spawn-Eiern), aber nicht bei Spawner-Blöcken (Farmen schützen)
|
||||||
|
if (event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.NATURAL &&
|
||||||
|
event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.SPAWNER_EGG &&
|
||||||
|
event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.DISPENSE_EGG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity entity = event.getEntity();
|
||||||
|
|
||||||
|
// Keine Anpassung für friedliche Tiere
|
||||||
|
if (entity instanceof Animals || entity instanceof Ambient) return;
|
||||||
|
|
||||||
|
// Nächsten Spieler suchen (Radius: 30 Blöcke)
|
||||||
|
Player nearestPlayer = null;
|
||||||
|
double minDistance = 30.0;
|
||||||
|
|
||||||
|
for (Player p : entity.getWorld().getPlayers()) {
|
||||||
|
if (p.getLocation().distance(entity.getLocation()) <= minDistance) {
|
||||||
|
nearestPlayer = p;
|
||||||
|
minDistance = p.getLocation().distance(entity.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestPlayer != null) {
|
||||||
|
applyAttributesBasedOnPlayer(entity, nearestPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyAttributesBasedOnPlayer(LivingEntity entity, Player player) {
|
||||||
|
FileConfiguration mobConfig = plugin.getMobAdaptConfig();
|
||||||
|
int level = mobConfig.getInt(player.getUniqueId().toString() + ".level", 0);
|
||||||
|
|
||||||
|
if (level == 0) return;
|
||||||
|
|
||||||
|
// Multiplikator berechnen (z.B. Level 10 -> 1.0 + (10 * 0.1) = 2.0 = doppelte Stärke)
|
||||||
|
double multiplier = 1.0 + (level * SCALING_FACTOR);
|
||||||
|
|
||||||
|
// Cap bei 5-facher Stärke, damit es nicht unspielbar wird
|
||||||
|
if (multiplier > 5.0) multiplier = 5.0;
|
||||||
|
|
||||||
|
// Lebenspunkte erhöhen
|
||||||
|
if (entity.getAttribute(Attribute.GENERIC_MAX_HEALTH) != null) {
|
||||||
|
double baseHealth = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
|
||||||
|
entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(baseHealth * multiplier);
|
||||||
|
entity.setHealth(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angriffsschaden erhöhen
|
||||||
|
if (entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE) != null) {
|
||||||
|
double baseDamage = entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue();
|
||||||
|
entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(baseDamage * multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Visuelles Indiz (Name über dem Kopf), wenn Monster sehr stark sind
|
||||||
|
if (level >= 10) {
|
||||||
|
entity.setCustomName(ChatColor.RED + "⚠ " + ChatColor.GRAY + "Starkes Monster (Lvl " + level + ")");
|
||||||
|
entity.setCustomNameVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/main/java/de/viper/survivalplus/listeners/ClaimListener.java
Normal file
100
src/main/java/de/viper/survivalplus/listeners/ClaimListener.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import de.viper.survivalplus.util.Claim;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Monster;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ClaimListener implements Listener {
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
private final Map<UUID, Claim> lastClaim = new HashMap<>();
|
||||||
|
|
||||||
|
public ClaimListener(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.isOp()) return;
|
||||||
|
Claim claim = plugin.getClaim(event.getBlock().getLocation());
|
||||||
|
if (claim != null && !claim.getOwner().equals(player.getUniqueId()) && !claim.getTrusted().contains(player.getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.no-break"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.isOp()) return;
|
||||||
|
Claim claim = plugin.getClaim(event.getBlock().getLocation());
|
||||||
|
if (claim != null && !claim.getOwner().equals(player.getUniqueId()) && !claim.getTrusted().contains(player.getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage(plugin.getMessage("claim.no-place"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID playerId = player.getUniqueId();
|
||||||
|
Claim currentClaim = plugin.getClaim(event.getTo());
|
||||||
|
|
||||||
|
// Prüfe, ob sich der Claim-Status geändert hat
|
||||||
|
Claim previousClaim = lastClaim.getOrDefault(playerId, null);
|
||||||
|
if (currentClaim != previousClaim) {
|
||||||
|
if (currentClaim != null) {
|
||||||
|
// Spieler betritt einen Claim
|
||||||
|
String ownerName = plugin.getServer().getOfflinePlayer(currentClaim.getOwner()).getName();
|
||||||
|
if (ownerName == null) {
|
||||||
|
ownerName = currentClaim.getOwner().toString(); // Fallback auf UUID
|
||||||
|
}
|
||||||
|
player.sendMessage(plugin.getMessage("claim.enter").replace("%owner%", ownerName));
|
||||||
|
} else if (previousClaim != null) {
|
||||||
|
// Spieler verlässt einen Claim
|
||||||
|
String ownerName = plugin.getServer().getOfflinePlayer(previousClaim.getOwner()).getName();
|
||||||
|
if (ownerName == null) {
|
||||||
|
ownerName = previousClaim.getOwner().toString(); // Fallback auf UUID
|
||||||
|
}
|
||||||
|
player.sendMessage(plugin.getMessage("claim.leave").replace("%owner%", ownerName));
|
||||||
|
}
|
||||||
|
lastClaim.put(playerId, currentClaim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- NEU: Schutz vor Monstern im Claim ---
|
||||||
|
@EventHandler
|
||||||
|
public void onMobTarget(EntityTargetLivingEntityEvent event) {
|
||||||
|
// 1. Prüfen, ob das Ziel ein Spieler ist
|
||||||
|
if (!(event.getTarget() instanceof Player)) return;
|
||||||
|
|
||||||
|
// 2. Prüfen, ob das Angreifer ein Monster ist (Zombie, Skelett, etc.)
|
||||||
|
if (!(event.getEntity() instanceof Monster)) return;
|
||||||
|
|
||||||
|
Player player = (Player) event.getTarget();
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
|
||||||
|
// 3. Prüfen, ob der Spieler in einem Claim steht
|
||||||
|
Claim claim = plugin.getClaim(loc);
|
||||||
|
|
||||||
|
if (claim != null) {
|
||||||
|
// 4. Prüfen, ob der Spieler dort Rechte hat (Owner oder Trusted)
|
||||||
|
if (claim.getOwner().equals(player.getUniqueId()) || claim.getTrusted().contains(player.getUniqueId())) {
|
||||||
|
// Das Targeting abbrechen -> Monster greift nicht an
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,10 +26,15 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
private final boolean enabled;
|
private final boolean enabled;
|
||||||
private final int durationMinutes;
|
private final int durationMinutes;
|
||||||
|
private final int COOLDOWN_SECONDS = 60; // Abklingzeit für Nachrichten in Sekunden (1 Minute)
|
||||||
|
|
||||||
// Maps für Zeiten und BossBars
|
// Maps für Zeiten, BossBars und Nachrichten-Abklingzeit
|
||||||
private final Map<UUID, Integer> remainingSeconds = new HashMap<>();
|
private final Map<UUID, Integer> remainingSeconds = new HashMap<>();
|
||||||
private final Map<UUID, BossBar> bossBars = new HashMap<>();
|
private final Map<UUID, BossBar> bossBars = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> messageCooldowns = new HashMap<>();
|
||||||
|
|
||||||
|
// NEU: Set um zu speichern, wer schon mal gejoint ist
|
||||||
|
private final Set<UUID> hasJoined = new HashSet<>();
|
||||||
|
|
||||||
// YAML Datei
|
// YAML Datei
|
||||||
private File dataFile;
|
private File dataFile;
|
||||||
@@ -57,17 +62,23 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
|
|
||||||
// Falls nicht gespeichert, neue Zeit einstellen
|
boolean isFirstJoin = !hasJoined.contains(uuid);
|
||||||
remainingSeconds.putIfAbsent(uuid, durationMinutes * 60);
|
|
||||||
|
|
||||||
// Bossbar erstellen/anzeigen
|
if (isFirstJoin) {
|
||||||
BossBar bar = Bukkit.createBossBar(
|
// Erster Join EVER -> Schutz geben und als "gejoint" markieren
|
||||||
ChatColor.GREEN + "Neulingsschutz: " + formatTime(remainingSeconds.get(uuid)),
|
remainingSeconds.put(uuid, durationMinutes * 60);
|
||||||
BarColor.GREEN,
|
hasJoined.add(uuid);
|
||||||
BarStyle.SOLID
|
|
||||||
);
|
createBossBar(player, remainingSeconds.get(uuid));
|
||||||
bar.addPlayer(player);
|
} else {
|
||||||
bossBars.put(uuid, bar);
|
// Spieler war schonmal da -> Prüfen ob noch Schutz übrig ist
|
||||||
|
Integer timeLeft = remainingSeconds.get(uuid);
|
||||||
|
if (timeLeft != null && timeLeft > 0) {
|
||||||
|
// Schutz läuft noch -> Bossbar wiederherstellen
|
||||||
|
createBossBar(player, timeLeft);
|
||||||
|
}
|
||||||
|
// Wenn timeLeft null ist oder 0, passiert nichts -> Kein Schutz für den "alten Hasen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -75,12 +86,13 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
// Bossbar entfernen, aber Zeit bleibt in Map bestehen
|
|
||||||
|
// Bossbar entfernen, aber Status (Zeit & Joined) in Map/Datei behalten
|
||||||
BossBar bar = bossBars.remove(uuid);
|
BossBar bar = bossBars.remove(uuid);
|
||||||
if (bar != null) {
|
if (bar != null) {
|
||||||
bar.removeAll();
|
bar.removeAll();
|
||||||
}
|
}
|
||||||
saveData(); // Beim Verlassen direkt speichern
|
saveData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -89,14 +101,27 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
if (!(event.getEntity() instanceof Player)) return;
|
if (!(event.getEntity() instanceof Player)) return;
|
||||||
|
|
||||||
Player victim = (Player) event.getEntity();
|
Player victim = (Player) event.getEntity();
|
||||||
UUID vid = victim.getUniqueId();
|
UUID victimId = victim.getUniqueId();
|
||||||
Integer timeLeft = remainingSeconds.get(vid);
|
Integer timeLeft = remainingSeconds.get(victimId);
|
||||||
|
|
||||||
if (timeLeft != null && timeLeft > 0) {
|
// Nur schützen, wenn Zeit > 0
|
||||||
event.setCancelled(true);
|
if (timeLeft == null || timeLeft <= 0) return;
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
// Prüfe Cooldown für Nachrichten
|
||||||
|
long currentTime = System.currentTimeMillis() / 1000;
|
||||||
|
if (currentTime >= messageCooldowns.getOrDefault(victimId, 0L) + COOLDOWN_SECONDS) {
|
||||||
victim.sendMessage(ChatColor.GREEN + "Du bist noch im Neulingsschutz!");
|
victim.sendMessage(ChatColor.GREEN + "Du bist noch im Neulingsschutz!");
|
||||||
if (event.getDamager() instanceof Player) {
|
messageCooldowns.put(victimId, currentTime);
|
||||||
((Player) event.getDamager()).sendMessage(ChatColor.RED + victim.getName() + " ist noch geschützt!");
|
}
|
||||||
|
|
||||||
|
if (event.getDamager() instanceof Player) {
|
||||||
|
Player damager = (Player) event.getDamager();
|
||||||
|
UUID damagerId = damager.getUniqueId();
|
||||||
|
if (currentTime >= messageCooldowns.getOrDefault(damagerId, 0L) + COOLDOWN_SECONDS) {
|
||||||
|
damager.sendMessage(ChatColor.RED + victim.getName() + " ist noch geschützt!");
|
||||||
|
messageCooldowns.put(damagerId, currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,16 +134,15 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
Player p = Bukkit.getPlayer(uuid);
|
Player p = Bukkit.getPlayer(uuid);
|
||||||
|
|
||||||
if (p == null || !p.isOnline()) {
|
if (p == null || !p.isOnline()) {
|
||||||
// Spieler offline → Zeit pausiert
|
// Spieler offline -> Zeit pausiert
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timeLeft = remainingSeconds.getOrDefault(uuid, 0);
|
int timeLeft = remainingSeconds.getOrDefault(uuid, 0);
|
||||||
|
|
||||||
if (timeLeft <= 0) {
|
if (timeLeft <= 0) {
|
||||||
// Ablauf: Bossbar weg + Map clean
|
// Zeit abgelaufen -> Bossbar weg, aber aus hasJoined NICHT löschen
|
||||||
BossBar bar = bossBars.remove(uuid);
|
removeProtection(uuid);
|
||||||
if (bar != null) bar.removeAll();
|
|
||||||
remainingSeconds.remove(uuid);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,17 +151,41 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
remainingSeconds.put(uuid, timeLeft);
|
remainingSeconds.put(uuid, timeLeft);
|
||||||
|
|
||||||
// Bossbar updaten
|
// Bossbar updaten
|
||||||
BossBar bar = bossBars.get(uuid);
|
updateBossBar(p, timeLeft);
|
||||||
if (bar != null) {
|
|
||||||
bar.setTitle(ChatColor.GREEN + "Neulingsschutz: " + formatTime(timeLeft));
|
|
||||||
bar.setProgress(Math.max(0, timeLeft / (float) (durationMinutes * 60)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
saveData(); // zyklisch speichern
|
// Jedes Mal zyklisch speichern
|
||||||
|
saveData();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 20L, 20L);
|
}.runTaskTimer(plugin, 20L, 20L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeProtection(UUID uuid) {
|
||||||
|
remainingSeconds.remove(uuid);
|
||||||
|
BossBar bar = bossBars.remove(uuid);
|
||||||
|
if (bar != null) {
|
||||||
|
bar.removeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBossBar(Player player, int seconds) {
|
||||||
|
BossBar bar = Bukkit.createBossBar(
|
||||||
|
ChatColor.GREEN + "Neulingsschutz: " + formatTime(seconds),
|
||||||
|
BarColor.GREEN,
|
||||||
|
BarStyle.SOLID
|
||||||
|
);
|
||||||
|
bar.addPlayer(player);
|
||||||
|
bar.setProgress(Math.max(0, seconds / (float) (durationMinutes * 60)));
|
||||||
|
bossBars.put(player.getUniqueId(), bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBossBar(Player player, int seconds) {
|
||||||
|
BossBar bar = bossBars.get(player.getUniqueId());
|
||||||
|
if (bar != null) {
|
||||||
|
bar.setTitle(ChatColor.GREEN + "Neulingsschutz: " + formatTime(seconds));
|
||||||
|
bar.setProgress(Math.max(0, seconds / (float) (durationMinutes * 60)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- Datei Handling ----------
|
// ---------- Datei Handling ----------
|
||||||
private void loadData() {
|
private void loadData() {
|
||||||
dataFile = new File(plugin.getDataFolder(), "newbieprotection.yml");
|
dataFile = new File(plugin.getDataFolder(), "newbieprotection.yml");
|
||||||
@@ -149,21 +197,47 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
||||||
|
|
||||||
|
hasJoined.clear();
|
||||||
|
remainingSeconds.clear();
|
||||||
|
|
||||||
for (String key : dataConfig.getKeys(false)) {
|
for (String key : dataConfig.getKeys(false)) {
|
||||||
try {
|
try {
|
||||||
UUID uuid = UUID.fromString(key);
|
UUID uuid = UUID.fromString(key);
|
||||||
int sec = dataConfig.getInt(key);
|
|
||||||
remainingSeconds.put(uuid, sec);
|
// Gelesen: 'joined' Status und 'seconds'
|
||||||
|
boolean joined = dataConfig.getBoolean(key + ".joined", false);
|
||||||
|
int sec = dataConfig.getInt(key + ".seconds", 0);
|
||||||
|
|
||||||
|
if (joined) {
|
||||||
|
hasJoined.add(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sec > 0) {
|
||||||
|
remainingSeconds.put(uuid, sec);
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException ignored) {}
|
} catch (IllegalArgumentException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WICHTIG: Public gemacht, damit von SurvivalPlus.java aufrufbar
|
|
||||||
public void saveData() {
|
public void saveData() {
|
||||||
if (dataConfig == null) return;
|
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
||||||
for (Map.Entry<UUID, Integer> entry : remainingSeconds.entrySet()) {
|
|
||||||
dataConfig.set(entry.getKey().toString(), entry.getValue());
|
// Wir speichern ALLE Spieler, die schon mal gejoint sind (hasJoined)
|
||||||
|
// damit wir beim Rejoin wissen, dass sie keinen Neulingsschutz mehr bekommen.
|
||||||
|
for (UUID uuid : hasJoined) {
|
||||||
|
dataConfig.set(uuid + ".joined", true);
|
||||||
|
|
||||||
|
Integer sec = remainingSeconds.get(uuid);
|
||||||
|
if (sec != null && sec > 0) {
|
||||||
|
dataConfig.set(uuid + ".seconds", sec);
|
||||||
|
} else {
|
||||||
|
// Wenn Schutz abgelaufen (0 oder nicht in Map), speichern wir 0 oder löschen wir den Key?
|
||||||
|
// Besser: löschen wir den Key "seconds", aber "joined" bleibt true.
|
||||||
|
dataConfig.set(uuid + ".seconds", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dataConfig.save(dataFile);
|
dataConfig.save(dataFile);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dieser Listener wird nicht mehr benötigt, da NickLoadListener
|
||||||
|
* mit ProtocolLib die Join/Quit Messages direkt auf Packet-Ebene behandelt.
|
||||||
|
*
|
||||||
|
* Diese Klasse kann gelöscht werden oder bleibt als leere Klasse bestehen.
|
||||||
|
*/
|
||||||
|
public class NickJoinMessageListener {
|
||||||
|
// Nicht mehr benötigt - ProtocolLib übernimmt die Arbeit
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@ package de.viper.survivalplus.listeners;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -19,26 +22,78 @@ public class NickLoadListener implements Listener {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
|
||||||
|
|
||||||
|
// Immer die Standard-Join-Message unterdrücken — wir senden eine einzelne kontrollierte Nachricht später
|
||||||
|
event.setJoinMessage(null);
|
||||||
|
|
||||||
|
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
||||||
if (rawNick != null && !rawNick.isEmpty()) {
|
if (rawNick != null && !rawNick.isEmpty()) {
|
||||||
String coloredNick = translateColors(rawNick);
|
String coloredNick = translateColors(rawNick);
|
||||||
String finalNick = "§f[" + coloredNick + "§f]";
|
String plainNick = ChatColor.stripColor(coloredNick);
|
||||||
player.setDisplayName(finalNick);
|
|
||||||
player.setPlayerListName(finalNick);
|
// Kurz: DisplayName jetzt auf echten Namen lassen, damit andere Plugins / Bukkit intern konsistent sind.
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
|
||||||
|
// In 1 Tick: DisplayName für Chat setzen UND die Join-Nachricht EINMAL manuell versenden
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
// Chat-Display: [Nick]
|
||||||
|
player.setDisplayName("§f[" + coloredNick + "§f]");
|
||||||
|
|
||||||
|
// Nachricht an alle Spieler senden (keine Doppelung, weil wir event.setJoinMessage(null) gesetzt haben)
|
||||||
|
String message = coloredNick + " §ejoined the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log in Konsole (sauber, ohne Farb-Codes)
|
||||||
|
plugin.getLogger().info(plainNick + " joined the game");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Kein Nick vorhanden -> benutze Standardverhalten, aber ebenfalls manuell, um Doppelungen zu verhindern
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
String message = player.getName() + " §ejoined the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(message);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(player.getName() + " joined the game");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
// Standard-Quit-Message unterdrücken
|
||||||
|
event.setQuitMessage(null);
|
||||||
|
|
||||||
|
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
||||||
|
if (rawNick != null && !rawNick.isEmpty()) {
|
||||||
|
String coloredNick = translateColors(rawNick);
|
||||||
|
String plainNick = ChatColor.stripColor(coloredNick);
|
||||||
|
|
||||||
|
// Sende Quit-Nachricht einmal manuell
|
||||||
|
String msg = coloredNick + " §eleft the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(msg);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(plainNick + " left the game");
|
||||||
|
} else {
|
||||||
|
String msg = player.getName() + " §eleft the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(msg);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(player.getName() + " left the game");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String translateColors(String input) {
|
private String translateColors(String input) {
|
||||||
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
return replaceHexColors(withLegacy);
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceHexColors(String input) {
|
|
||||||
Matcher matcher = HEX_PATTERN.matcher(input);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = matcher.group();
|
String hexCode = matcher.group();
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
package de.viper.survivalplus.listeners;
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.event.block.Action;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -22,9 +26,12 @@ import java.util.logging.Level;
|
|||||||
public class SitListener implements Listener {
|
public class SitListener implements Listener {
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> sitCooldown = new HashMap<>(); // Neuer Cooldown gegen "Auto-Standup"
|
||||||
|
private static final String SIT_TAG = "SP_SIT_STAND";
|
||||||
|
|
||||||
public SitListener(SurvivalPlus plugin) {
|
public SitListener(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
cleanUpGhostStands();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSitting(Player player) {
|
public boolean isSitting(Player player) {
|
||||||
@@ -42,22 +49,50 @@ public class SitListener implements Listener {
|
|||||||
armorStand.setMarker(true);
|
armorStand.setMarker(true);
|
||||||
armorStand.setInvisible(true);
|
armorStand.setInvisible(true);
|
||||||
armorStand.setInvulnerable(true);
|
armorStand.setInvulnerable(true);
|
||||||
|
armorStand.addScoreboardTag(SIT_TAG);
|
||||||
|
|
||||||
|
// Setze Rotation des Stands auf Rotation des Spielers
|
||||||
|
armorStand.setRotation(player.getLocation().getYaw(), player.getLocation().getPitch());
|
||||||
|
|
||||||
|
// Füge Spieler als Passenger hinzu
|
||||||
armorStand.addPassenger(player);
|
armorStand.addPassenger(player);
|
||||||
|
|
||||||
|
// FIX: KEIN player.teleport() hier ausführen!
|
||||||
|
// In neueren Versionen "bricht" das Teleportieren das Mounten sofort wieder.
|
||||||
|
// Der Spieler wird automatisch durch addPassenger zum Stand teleportiert.
|
||||||
|
|
||||||
|
// Cooldown setzen, damit wir nicht sofort durch "Movement" aufstehen
|
||||||
|
sitCooldown.put(player.getUniqueId(), System.currentTimeMillis() + 500L);
|
||||||
|
|
||||||
sittingPlayers.put(player.getUniqueId(), armorStand);
|
sittingPlayers.put(player.getUniqueId(), armorStand);
|
||||||
|
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
||||||
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " sitzt bei " + locationToString(location));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void standUp(Player player) {
|
public void standUp(Player player) {
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
||||||
|
sitCooldown.remove(playerId); // Cooldown löschen
|
||||||
|
|
||||||
if (armorStand != null) {
|
if (armorStand != null) {
|
||||||
armorStand.remove();
|
if (player.isValid() && armorStand.isValid()) {
|
||||||
|
// Wenn man absteigt, landet man oft leicht daneben. Wir korrigieren das leicht,
|
||||||
|
// aber nicht so aggressiv wie beim Hinsetzen.
|
||||||
|
Location loc = player.getLocation().add(0, 0.2, 0);
|
||||||
|
armorStand.removePassenger(player);
|
||||||
|
armorStand.remove();
|
||||||
|
|
||||||
|
// Kleiner Fix, damit man nicht im Boden klebt
|
||||||
|
player.teleport(loc);
|
||||||
|
} else {
|
||||||
|
armorStand.remove();
|
||||||
|
}
|
||||||
|
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
if (player.isOnline()) {
|
||||||
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " ist aufgestanden");
|
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +106,6 @@ public class SitListener implements Listener {
|
|||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
|
|
||||||
if (!player.hasPermission("survivalplus.sit")) {
|
if (!player.hasPermission("survivalplus.sit")) {
|
||||||
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,35 +114,64 @@ public class SitListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn der Spieler bereits sitzt, stehe auf
|
double distance = player.getLocation().distance(block.getLocation());
|
||||||
|
if (distance > 3.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
||||||
standUp(player);
|
standUp(player);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setze den Spieler genau auf der Treppenstufe
|
if (player.isInsideVehicle()) return;
|
||||||
|
|
||||||
|
// Position berechnen
|
||||||
Location location = block.getLocation();
|
Location location = block.getLocation();
|
||||||
location.setX(location.getX() + 0.5);
|
location.setX(location.getX() + 0.5);
|
||||||
location.setY(location.getY() + 0.5); // Genau auf der Treppenstufe (halbe Blockhöhe)
|
|
||||||
location.setZ(location.getZ() + 0.5);
|
location.setZ(location.getZ() + 0.5);
|
||||||
|
|
||||||
|
// Bei Treppen: Y + 0.5 ist meistens korrekt für die Sitzfläche
|
||||||
|
location.setY(location.getY() + 0.5);
|
||||||
|
|
||||||
|
// Drehung anpassen, damit man nicht auf der Treppe schräg sitzt
|
||||||
|
location.setYaw(player.getLocation().getYaw());
|
||||||
|
location.setPitch(player.getLocation().getPitch());
|
||||||
|
|
||||||
sitPlayer(player, location);
|
sitPlayer(player, location);
|
||||||
event.setCancelled(true); // Verhindere andere Interaktionen mit der Treppe
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerMove(PlayerMoveEvent event) {
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
if (!sittingPlayers.containsKey(playerId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prüfe, ob der Spieler sich bewegt hat (nur Positionsänderung, nicht Kopfbewegung)
|
// Wenn der Spieler sitzt
|
||||||
Location from = event.getFrom();
|
if (sittingPlayers.containsKey(playerId)) {
|
||||||
Location to = event.getTo();
|
|
||||||
if (from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ()) {
|
// FIX: Cooldown prüfen (Verhindert "Auto-Standup" durch Lag beim Hinsetzen)
|
||||||
standUp(player);
|
Long cooldown = sitCooldown.get(playerId);
|
||||||
|
if (cooldown != null && cooldown > System.currentTimeMillis()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location from = event.getFrom();
|
||||||
|
Location to = event.getTo();
|
||||||
|
if (to == null) return;
|
||||||
|
|
||||||
|
// Prüfe signifikante Bewegung
|
||||||
|
if (from.distanceSquared(to) > 0.0025) {
|
||||||
|
standUp(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
|
if (sittingPlayers.containsKey(event.getPlayer().getUniqueId())) {
|
||||||
|
standUp(event.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +185,18 @@ public class SitListener implements Listener {
|
|||||||
return material.name().endsWith("_STAIRS");
|
return material.name().endsWith("_STAIRS");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String locationToString(Location loc) {
|
private void cleanUpGhostStands() {
|
||||||
return String.format("x=%.2f, y=%.2f, z=%.2f, world=%s", loc.getX(), loc.getY(), loc.getZ(), loc.getWorld().getName());
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
for (Entity entity : world.getEntities()) {
|
||||||
|
if (entity instanceof ArmorStand) {
|
||||||
|
if (entity.getScoreboardTags().contains(SIT_TAG)) {
|
||||||
|
entity.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.getLogger().info("Ghost Stands (Sit) bereinigt.");
|
||||||
|
}, 20L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,19 +56,12 @@ public class ToolUpgradeListener implements Listener {
|
|||||||
if (!(event.getInventory() instanceof CraftingInventory)) return;
|
if (!(event.getInventory() instanceof CraftingInventory)) return;
|
||||||
CraftingInventory inv = (CraftingInventory) event.getInventory();
|
CraftingInventory inv = (CraftingInventory) event.getInventory();
|
||||||
ItemStack[] matrix = inv.getMatrix();
|
ItemStack[] matrix = inv.getMatrix();
|
||||||
if (matrix.length < 9) {
|
if (matrix.length < 9) return; // Kein 3x3-Crafting-Tisch
|
||||||
inv.setResult(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack center = matrix[4];
|
ItemStack center = matrix[4];
|
||||||
if (center == null || center.getType() == Material.AIR) {
|
// Nur eingreifen, wenn ein Werkzeug in der Mitte liegt
|
||||||
inv.setResult(null);
|
if (center == null || center.getType() == Material.AIR || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
|
||||||
return;
|
return; // Standard-Rezepte nicht beeinflussen
|
||||||
}
|
|
||||||
if (!isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
|
|
||||||
inv.setResult(null);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentLevel = getToolLevel(center);
|
int currentLevel = getToolLevel(center);
|
||||||
@@ -83,7 +76,7 @@ public class ToolUpgradeListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen ob alle Slots (außer Mitte) mind. 2 Stück vom richtigen Material haben
|
// Prüfen, ob alle Slots (außer Mitte) mind. 2 Stück vom richtigen Material haben
|
||||||
for (int i = 0; i < matrix.length; i++) {
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
if (i == 4) continue;
|
if (i == 4) continue;
|
||||||
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
|
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
|
||||||
@@ -106,20 +99,33 @@ public class ToolUpgradeListener implements Listener {
|
|||||||
|
|
||||||
ItemStack[] matrix = inv.getMatrix();
|
ItemStack[] matrix = inv.getMatrix();
|
||||||
ItemStack center = matrix[4];
|
ItemStack center = matrix[4];
|
||||||
if (center == null || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) return;
|
if (center == null || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
|
||||||
|
plugin.getLogger().fine("Kein Upgrade-Werkzeug in der Mitte: " + (center != null ? center.getType() : "null"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int currentLevel = getToolLevel(center);
|
int currentLevel = getToolLevel(center);
|
||||||
if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) return;
|
if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) {
|
||||||
|
plugin.getLogger().fine("Maximales Level erreicht für Werkzeug: " + center.getType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Material requiredMat = levelMaterials.get(currentLevel + 1);
|
Material requiredMat = levelMaterials.get(currentLevel + 1);
|
||||||
if (requiredMat == null) return;
|
if (requiredMat == null) {
|
||||||
|
plugin.getLogger().fine("Kein Material für Level " + (currentLevel + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < matrix.length; i++) {
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
if (i == 4) continue;
|
if (i == 4) continue;
|
||||||
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) return;
|
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
|
||||||
|
plugin.getLogger().fine("Ungültiges Material in Slot " + i + ": " + (matrix[i] != null ? matrix[i].getType() : "null"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gültig: Event abbrechen, Upgrade geben, Items verbrauchen
|
// Gültig: Event abbrechen, Upgrade geben, Items verbrauchen
|
||||||
|
plugin.getLogger().info("Werkzeug-Upgrade für " + player.getName() + ": " + center.getType() + " auf Level " + (currentLevel + 1));
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
ItemStack result = createUpgradedTool(center, currentLevel + 1);
|
ItemStack result = createUpgradedTool(center, currentLevel + 1);
|
||||||
|
|
||||||
@@ -215,7 +221,9 @@ public class ToolUpgradeListener implements Listener {
|
|||||||
n.endsWith("_SWORD");
|
n.endsWith("_SWORD");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isWoodTool(Material mat) { return mat.name().startsWith("WOODEN"); }
|
private boolean isWoodTool(Material mat) {
|
||||||
|
return mat.name().startsWith("WOODEN");
|
||||||
|
}
|
||||||
|
|
||||||
private int getMaxAllowedLevel(Material mat) {
|
private int getMaxAllowedLevel(Material mat) {
|
||||||
String s = mat.name();
|
String s = mat.name();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.ShapedRecipe;
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
|
import org.bukkit.inventory.RecipeChoice;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
@@ -16,23 +17,34 @@ public class BackpackRecipe {
|
|||||||
ItemStack backpack = new ItemStack(Material.CHEST);
|
ItemStack backpack = new ItemStack(Material.CHEST);
|
||||||
ItemMeta meta = backpack.getItemMeta();
|
ItemMeta meta = backpack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.name", "&eRucksack")));
|
// Fallback falls der Key in der lang.yml fehlt
|
||||||
|
String displayName = langConfig.getString("backpack.name", "&eRucksack");
|
||||||
|
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', displayName));
|
||||||
backpack.setItemMeta(meta);
|
backpack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
NamespacedKey key = new NamespacedKey(plugin, "backpack");
|
NamespacedKey key = new NamespacedKey(plugin, "backpack");
|
||||||
|
|
||||||
|
// Rezept erstellen
|
||||||
ShapedRecipe recipe = new ShapedRecipe(key, backpack);
|
ShapedRecipe recipe = new ShapedRecipe(key, backpack);
|
||||||
|
|
||||||
|
// Form festlegen
|
||||||
recipe.shape(
|
recipe.shape(
|
||||||
"S L", // Faden, leer, Leder
|
"S L",
|
||||||
" C ", // leer, Truhe, leer
|
" C ",
|
||||||
"S L" // Faden, leer, Leder
|
"S L"
|
||||||
);
|
);
|
||||||
recipe.setIngredient('S', Material.STRING); // Faden
|
|
||||||
recipe.setIngredient('L', Material.LEATHER); // Leder
|
// Zutaten festlegen (mit RecipeChoice für bessere Kompatibilität)
|
||||||
recipe.setIngredient('C', Material.CHEST); // Truhe
|
recipe.setIngredient('S', new RecipeChoice.MaterialChoice(Material.STRING));
|
||||||
|
recipe.setIngredient('L', new RecipeChoice.MaterialChoice(Material.LEATHER));
|
||||||
|
recipe.setIngredient('C', new RecipeChoice.MaterialChoice(Material.CHEST));
|
||||||
|
|
||||||
|
// WICHTIG: Setzt eine eigene Gruppe.
|
||||||
|
// Verhindert Konflikte mit Vanilla-Rezepten im Rezeptbuch.
|
||||||
|
recipe.setGroup("survivalplus");
|
||||||
|
|
||||||
Bukkit.addRecipe(recipe);
|
Bukkit.addRecipe(recipe);
|
||||||
plugin.getLogger().info("Backpack Rezept wurde registriert.");
|
plugin.getLogger().info("Backpack Rezept wurde erfolgreich registriert (Gruppe: survivalplus).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,13 +73,14 @@ public class TradeManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TradeSession session = new TradeSession(plugin, sender, receiver);
|
// Neue Session starten
|
||||||
|
TradeSession session = new TradeSession(plugin, sender, receiver, this);
|
||||||
Bukkit.getPluginManager().registerEvents(session, plugin);
|
Bukkit.getPluginManager().registerEvents(session, plugin);
|
||||||
|
|
||||||
activeTrades.put(sender.getUniqueId(), session);
|
activeTrades.put(sender.getUniqueId(), session);
|
||||||
activeTrades.put(receiver.getUniqueId(), session);
|
activeTrades.put(receiver.getUniqueId(), session);
|
||||||
|
|
||||||
session.openInventories();
|
session.openInventory();
|
||||||
|
|
||||||
sender.sendMessage(plugin.getLangConfig().getString("trade.started-sender", "§aTrade gestartet mit %player%").replace("%player%", receiver.getName()));
|
sender.sendMessage(plugin.getLangConfig().getString("trade.started-sender", "§aTrade gestartet mit %player%").replace("%player%", receiver.getName()));
|
||||||
receiver.sendMessage(plugin.getLangConfig().getString("trade.started-receiver", "§a%player% hat dich zu einem Trade eingeladen.").replace("%player%", sender.getName()));
|
receiver.sendMessage(plugin.getLangConfig().getString("trade.started-receiver", "§a%player% hat dich zu einem Trade eingeladen.").replace("%player%", sender.getName()));
|
||||||
@@ -91,7 +92,7 @@ public class TradeManager {
|
|||||||
Player r = session.getReceiver();
|
Player r = session.getReceiver();
|
||||||
if (s != null) activeTrades.remove(s.getUniqueId());
|
if (s != null) activeTrades.remove(s.getUniqueId());
|
||||||
if (r != null) activeTrades.remove(r.getUniqueId());
|
if (r != null) activeTrades.remove(r.getUniqueId());
|
||||||
session.endSession();
|
session.closeInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TradeSession getTrade(Player player) {
|
public TradeSession getTrade(Player player) {
|
||||||
|
|||||||
@@ -16,150 +16,297 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||||||
public class TradeSession implements Listener {
|
public class TradeSession implements Listener {
|
||||||
|
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
|
private final TradeManager tradeManager;
|
||||||
private final Player sender;
|
private final Player sender;
|
||||||
private final Player receiver;
|
private final Player receiver;
|
||||||
|
|
||||||
private final Inventory invSender;
|
// Wir benutzen nur EIN Inventar für beide (Size 54 = Double Chest)
|
||||||
private final Inventory invReceiver;
|
// Slots 0-17: Angebot von Sender (Editierbar für Sender)
|
||||||
|
// Slots 18-35: Angebot von Receiver (Editierbar für Receiver)
|
||||||
|
// Slots 36-44: Trennung / Status
|
||||||
|
// Slot 45: Abbrechen
|
||||||
|
// Slot 53: Bestätigen
|
||||||
|
private final Inventory tradeInv;
|
||||||
|
|
||||||
private boolean senderConfirmed = false;
|
private boolean senderConfirmed = false;
|
||||||
private boolean receiverConfirmed = false;
|
private boolean receiverConfirmed = false;
|
||||||
private boolean ended = false; // Flag gegen Rekursion
|
private boolean active = true;
|
||||||
|
|
||||||
public TradeSession(SurvivalPlus plugin, Player sender, Player receiver) {
|
public TradeSession(SurvivalPlus plugin, Player sender, Player receiver, TradeManager tradeManager) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.tradeManager = tradeManager;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.receiver = receiver;
|
this.receiver = receiver;
|
||||||
|
|
||||||
String titleForSender = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
|
String title = plugin.getLangConfig().getString("trade.inventory-title", "Handel")
|
||||||
.replace("%player%", receiver.getName());
|
.replace("%player%", receiver.getName())
|
||||||
String titleForReceiver = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
|
.replace("%other%", sender.getName());
|
||||||
.replace("%player%", sender.getName());
|
|
||||||
|
|
||||||
this.invSender = Bukkit.createInventory(sender, 27, titleForSender);
|
// Wir nutzen null als Owner, damit es ein gemeinsames Inventar ist
|
||||||
this.invReceiver = Bukkit.createInventory(receiver, 27, titleForReceiver);
|
this.tradeInv = Bukkit.createInventory(null, 54, title);
|
||||||
|
setupLayout();
|
||||||
addConfirmButton(invSender);
|
|
||||||
addConfirmButton(invReceiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addConfirmButton(Inventory inv) {
|
private void setupLayout() {
|
||||||
ItemStack confirm = new ItemStack(Material.LIME_CONCRETE);
|
// Trennung zwischen den beiden Angeboten (Glas)
|
||||||
ItemMeta meta = confirm.getItemMeta();
|
ItemStack glass = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||||
meta.setDisplayName(plugin.getLangConfig().getString("trade.confirm-button", "§aBestätigen"));
|
ItemMeta glassMeta = glass.getItemMeta();
|
||||||
confirm.setItemMeta(meta);
|
glassMeta.setDisplayName(" ");
|
||||||
inv.setItem(26, confirm);
|
glass.setItemMeta(glassMeta);
|
||||||
|
|
||||||
|
for(int i = 36; i < 45; i++) {
|
||||||
|
tradeInv.setItem(i, glass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons initialisieren
|
||||||
|
updateStatusItem();
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButtons() {
|
||||||
|
// Abbrechen Button (Rot)
|
||||||
|
ItemStack cancel = new ItemStack(Material.RED_CONCRETE);
|
||||||
|
ItemMeta cancelMeta = cancel.getItemMeta();
|
||||||
|
cancelMeta.setDisplayName(plugin.getLangConfig().getString("trade.cancel-button", "§cAbbrechen"));
|
||||||
|
cancel.setItemMeta(cancelMeta);
|
||||||
|
tradeInv.setItem(45, cancel);
|
||||||
|
|
||||||
|
// Bestätigen Button
|
||||||
|
Material confirmMat = Material.LIME_CONCRETE;
|
||||||
|
String confirmName = "§aBestätigen";
|
||||||
|
|
||||||
|
// Wenn beide bestätigt haben, ändert sich der Button
|
||||||
|
if (senderConfirmed && receiverConfirmed) {
|
||||||
|
confirmMat = Material.GOLD_BLOCK; // Signalisiert Tauschvorgang
|
||||||
|
confirmName = "§6Handel läuft...";
|
||||||
|
} else if (senderConfirmed) {
|
||||||
|
confirmMat = Material.YELLOW_CONCRETE;
|
||||||
|
confirmName = "§eWarte auf Partner...";
|
||||||
|
} else if (receiverConfirmed) {
|
||||||
|
confirmMat = Material.YELLOW_CONCRETE;
|
||||||
|
confirmName = "§eWarte auf Partner...";
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack confirm = new ItemStack(confirmMat);
|
||||||
|
ItemMeta confirmMeta = confirm.getItemMeta();
|
||||||
|
confirmMeta.setDisplayName(confirmName);
|
||||||
|
confirm.setItemMeta(confirmMeta);
|
||||||
|
tradeInv.setItem(53, confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusItem() {
|
||||||
|
// Slot 40 zeigt den Status an
|
||||||
|
String statusText = "§eWarte auf Bestätigung...";
|
||||||
|
|
||||||
|
if (senderConfirmed && !receiverConfirmed) {
|
||||||
|
statusText = "§a" + sender.getName() + " §7hat bestätigt.";
|
||||||
|
} else if (!senderConfirmed && receiverConfirmed) {
|
||||||
|
statusText = "§a" + receiver.getName() + " §7hat bestätigt.";
|
||||||
|
} else if (senderConfirmed && receiverConfirmed) {
|
||||||
|
statusText = "§6Handel wird ausgeführt...";
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack status = new ItemStack(Material.BOOK);
|
||||||
|
ItemMeta statusMeta = status.getItemMeta();
|
||||||
|
statusMeta.setDisplayName(statusText);
|
||||||
|
status.setItemMeta(statusMeta);
|
||||||
|
tradeInv.setItem(40, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getSender() { return sender; }
|
public Player getSender() { return sender; }
|
||||||
public Player getReceiver() { return receiver; }
|
public Player getReceiver() { return receiver; }
|
||||||
|
|
||||||
public void openInventories() {
|
public void openInventory() {
|
||||||
if (sender.isOnline()) sender.openInventory(invSender);
|
if (sender.isOnline()) sender.openInventory(tradeInv);
|
||||||
if (receiver.isOnline()) receiver.openInventory(invReceiver);
|
if (receiver.isOnline()) receiver.openInventory(tradeInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void returnItems(Player player, Inventory inventory) {
|
public void closeInventory() {
|
||||||
for (int i = 0; i < 26; i++) {
|
active = false;
|
||||||
ItemStack item = inventory.getItem(i);
|
if (sender.isOnline() && sender.getOpenInventory().getTopInventory() == tradeInv) {
|
||||||
if (item != null) player.getInventory().addItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endSession() {
|
|
||||||
if (ended) return; // Rekursion verhindern
|
|
||||||
ended = true;
|
|
||||||
|
|
||||||
// Items zurückgeben
|
|
||||||
if (sender.isOnline()) returnItems(sender, invSender);
|
|
||||||
if (receiver.isOnline()) returnItems(receiver, invReceiver);
|
|
||||||
|
|
||||||
// Inventories schließen
|
|
||||||
if (sender.isOnline() && sender.getOpenInventory().getTopInventory() == invSender) {
|
|
||||||
sender.closeInventory();
|
sender.closeInventory();
|
||||||
}
|
}
|
||||||
if (receiver.isOnline() && receiver.getOpenInventory().getTopInventory() == invReceiver) {
|
if (receiver.isOnline() && receiver.getOpenInventory().getTopInventory() == tradeInv) {
|
||||||
receiver.closeInventory();
|
receiver.closeInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
HandlerList.unregisterAll(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Inventory getOwnInventory(Player p) {
|
private void returnItems() {
|
||||||
return p.getUniqueId().equals(sender.getUniqueId()) ? invSender : invReceiver;
|
// Gibt alle Items zurück, falls der Handel abgebrochen wurde
|
||||||
}
|
for (int i = 0; i < 36; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
private Inventory getOtherInventory(Player p) {
|
if (item != null) {
|
||||||
return p.getUniqueId().equals(sender.getUniqueId()) ? invReceiver : invSender;
|
// Bestimmen, wem das Item gehört
|
||||||
}
|
if (i < 18) {
|
||||||
|
if (sender.isOnline()) sender.getInventory().addItem(item);
|
||||||
private void updateOtherView(Player p) {
|
} else {
|
||||||
Inventory own = getOwnInventory(p);
|
if (receiver.isOnline()) receiver.getInventory().addItem(item);
|
||||||
Inventory other = getOtherInventory(p);
|
}
|
||||||
for (int i = 0; i < 26; i++) {
|
tradeInv.setItem(i, null); // Slot leeren
|
||||||
other.setItem(i, own.getItem(i));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeTrade() {
|
private void executeTrade() {
|
||||||
for (int i = 0; i < 26; i++) {
|
// Tauschvorgang
|
||||||
ItemStack itemFromSender = invSender.getItem(i);
|
// 1. Sender Items zu Receiver
|
||||||
ItemStack itemFromReceiver = invReceiver.getItem(i);
|
for (int i = 0; i < 18; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
|
if (item != null) {
|
||||||
|
if (receiver.isOnline()) receiver.getInventory().addItem(item);
|
||||||
|
tradeInv.setItem(i, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (itemFromSender != null) sender.getInventory().addItem(itemFromSender);
|
// 2. Receiver Items zu Sender
|
||||||
if (itemFromReceiver != null) receiver.getInventory().addItem(itemFromReceiver);
|
for (int i = 18; i < 36; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
|
if (item != null) {
|
||||||
|
if (sender.isOnline()) sender.getInventory().addItem(item);
|
||||||
|
tradeInv.setItem(i, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String success = plugin.getLangConfig().getString("trade.success", "§aHandel erfolgreich abgeschlossen!");
|
String success = plugin.getLangConfig().getString("trade.success", "§aHandel erfolgreich abgeschlossen!");
|
||||||
if (sender.isOnline()) sender.sendMessage(success);
|
if (sender.isOnline()) sender.sendMessage(success);
|
||||||
if (receiver.isOnline()) receiver.sendMessage(success);
|
if (receiver.isOnline()) receiver.sendMessage(success);
|
||||||
|
|
||||||
endSession();
|
closeInventory();
|
||||||
}
|
|
||||||
|
|
||||||
private void resetConfirmations() {
|
|
||||||
senderConfirmed = false;
|
|
||||||
receiverConfirmed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClick(InventoryClickEvent e) {
|
public void onInventoryClick(InventoryClickEvent e) {
|
||||||
|
if (!active) return;
|
||||||
if (!(e.getWhoClicked() instanceof Player p)) return;
|
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||||
if (!p.getUniqueId().equals(sender.getUniqueId()) && !p.getUniqueId().equals(receiver.getUniqueId())) return;
|
if (e.getClickedInventory() == null) return;
|
||||||
|
|
||||||
Inventory top = e.getView().getTopInventory();
|
// Nur Klicks im Trade-Inventar behandeln
|
||||||
Inventory clicked = e.getClickedInventory();
|
if (e.getClickedInventory().getSize() != 54 || !e.getClickedInventory().equals(tradeInv)) return;
|
||||||
|
// Auch Klicks im Bottom Inventory erlauben, aber nicht logisch behandeln (Bukkit regelt das)
|
||||||
|
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId())) {
|
||||||
|
handleSenderClick(e);
|
||||||
|
} else if (p.getUniqueId().equals(receiver.getUniqueId())) {
|
||||||
|
handleReceiverClick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSenderClick(InventoryClickEvent e) {
|
||||||
int slot = e.getSlot();
|
int slot = e.getSlot();
|
||||||
|
|
||||||
if (clicked == null) return;
|
// Abbrechen
|
||||||
|
if (slot == 45) {
|
||||||
// Bestätigen-Button
|
|
||||||
if (slot == 26 && clicked.equals(top)) {
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
if (p.getUniqueId().equals(sender.getUniqueId())) senderConfirmed = true;
|
sender.sendMessage(plugin.getLangConfig().getString("trade.cancelled", "§cHandel abgebrochen."));
|
||||||
if (p.getUniqueId().equals(receiver.getUniqueId())) receiverConfirmed = true;
|
if (receiver.isOnline()) receiver.sendMessage(plugin.getLangConfig().getString("trade.cancelled-partner", "§cHandel wurde abgebrochen."));
|
||||||
|
tradeManager.endTrade(this);
|
||||||
p.sendMessage(plugin.getLangConfig().getString("trade.confirmed", "§aDu hast den Handel bestätigt!"));
|
|
||||||
|
|
||||||
if (senderConfirmed && receiverConfirmed) executeTrade();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nur das eigene Trade-Inventar editierbar
|
// Bestätigen
|
||||||
if (clicked.equals(top)) {
|
if (slot == 53) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
e.setCancelled(true);
|
||||||
updateOtherView(p);
|
if (receiverConfirmed) {
|
||||||
resetConfirmations();
|
executeTrade();
|
||||||
}, 1L);
|
} else {
|
||||||
|
senderConfirmed = !senderConfirmed; // Toggle
|
||||||
|
sender.sendMessage(senderConfirmed ?
|
||||||
|
plugin.getLangConfig().getString("trade.confirmed", "§aBestätigt!") :
|
||||||
|
"§cBestätigung zurückgezogen.");
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Item-Bewegungen nur im eigenen Bereich (0-17) erlauben
|
||||||
|
if (slot >= 0 && slot <= 17) {
|
||||||
|
// Erlaubt
|
||||||
|
// Wenn ein Item bewegt wird, Bestätigungen zurücksetzen
|
||||||
|
if (e.getCurrentItem() != null || e.getCursor() != null) {
|
||||||
|
if (senderConfirmed || receiverConfirmed) {
|
||||||
|
senderConfirmed = false;
|
||||||
|
receiverConfirmed = false;
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle anderen Slots sperren (Partner-Seite, Glas, Status)
|
||||||
|
e.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReceiverClick(InventoryClickEvent e) {
|
||||||
|
int slot = e.getSlot();
|
||||||
|
|
||||||
|
// Abbrechen
|
||||||
|
if (slot == 45) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
receiver.sendMessage(plugin.getLangConfig().getString("trade.cancelled", "§cHandel abgebrochen."));
|
||||||
|
if (sender.isOnline()) sender.sendMessage(plugin.getLangConfig().getString("trade.cancelled-partner", "§cHandel wurde abgebrochen."));
|
||||||
|
tradeManager.endTrade(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bestätigen
|
||||||
|
if (slot == 53) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
if (senderConfirmed) {
|
||||||
|
executeTrade();
|
||||||
|
} else {
|
||||||
|
receiverConfirmed = !receiverConfirmed; // Toggle
|
||||||
|
receiver.sendMessage(receiverConfirmed ?
|
||||||
|
plugin.getLangConfig().getString("trade.confirmed", "§aBestätigt!") :
|
||||||
|
"§cBestätigung zurückgezogen.");
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item-Bewegungen nur im eigenen Bereich (18-35) erlauben
|
||||||
|
if (slot >= 18 && slot <= 35) {
|
||||||
|
// Erlaubt
|
||||||
|
if (e.getCurrentItem() != null || e.getCursor() != null) {
|
||||||
|
if (senderConfirmed || receiverConfirmed) {
|
||||||
|
senderConfirmed = false;
|
||||||
|
receiverConfirmed = false;
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle anderen Slots sperren
|
||||||
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent e) {
|
public void onInventoryClose(InventoryCloseEvent e) {
|
||||||
|
if (!active) return;
|
||||||
if (!(e.getPlayer() instanceof Player p)) return;
|
if (!(e.getPlayer() instanceof Player p)) return;
|
||||||
if (p.getUniqueId().equals(sender.getUniqueId()) || p.getUniqueId().equals(receiver.getUniqueId())) {
|
|
||||||
// Kleine Verzögerung, um StackOverflow zu vermeiden
|
// Wenn ein Spieler das Inventar schließt, wird der Handel abgebrochen
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, this::endSession, 1L);
|
// Wir prüfen, ob noch Items drin sind, um Duplikate zu vermeiden
|
||||||
|
if (e.getInventory().equals(tradeInv)) {
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId()) || p.getUniqueId().equals(receiver.getUniqueId())) {
|
||||||
|
// Verzögern, falls der Server den CloseEvent für beide fast gleichzeitig feuert
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
if (active) { // Nur wenn nicht schon durch executeTrade geschlossen
|
||||||
|
returnItems();
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId())) {
|
||||||
|
if (receiver.isOnline()) receiver.sendMessage("§cDer Partner hat den Handel abgebrochen.");
|
||||||
|
} else {
|
||||||
|
if (sender.isOnline()) sender.sendMessage("§cDer Partner hat den Handel abgebrochen.");
|
||||||
|
}
|
||||||
|
tradeManager.endTrade(this);
|
||||||
|
}
|
||||||
|
}, 1L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
src/main/java/de/viper/survivalplus/util/BannerManager.java
Normal file
28
src/main/java/de/viper/survivalplus/util/BannerManager.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package de.viper.survivalplus.util;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BannerManager {
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
|
||||||
|
public BannerManager(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayConsoleBanner() {
|
||||||
|
String version = plugin.getDescription().getVersion();
|
||||||
|
List<String> banner = Arrays.asList(
|
||||||
|
"******************************",
|
||||||
|
"* SurvivalPlus " + version + " *",
|
||||||
|
"* *",
|
||||||
|
"* M_Viper *",
|
||||||
|
"******************************"
|
||||||
|
);
|
||||||
|
for (String line : banner) {
|
||||||
|
plugin.getLogger().info(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/main/java/de/viper/survivalplus/util/Claim.java
Normal file
91
src/main/java/de/viper/survivalplus/util/Claim.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package de.viper.survivalplus.util;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Claim {
|
||||||
|
private UUID owner;
|
||||||
|
private Set<UUID> trusted = new HashSet<>();
|
||||||
|
private int x1, z1, x2, z2;
|
||||||
|
private String worldName;
|
||||||
|
|
||||||
|
public Claim(Player owner, String worldName, int x1, int z1, int x2, int z2) {
|
||||||
|
this.owner = owner.getUniqueId();
|
||||||
|
this.worldName = worldName;
|
||||||
|
this.x1 = Math.min(x1, x2);
|
||||||
|
this.z1 = Math.min(z1, z2);
|
||||||
|
this.x2 = Math.max(x1, x2);
|
||||||
|
this.z2 = Math.max(z1, z2);
|
||||||
|
trusted.add(owner.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Claim(UUID owner, String worldName, int x1, int z1, int x2, int z2) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.worldName = worldName;
|
||||||
|
this.x1 = Math.min(x1, x2);
|
||||||
|
this.z1 = Math.min(z1, z2);
|
||||||
|
this.x2 = Math.max(x1, x2);
|
||||||
|
this.z2 = Math.max(z1, z2);
|
||||||
|
trusted.add(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canInteract(UUID uuid) {
|
||||||
|
return trusted.contains(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTrusted(UUID uuid) {
|
||||||
|
trusted.add(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTrusted(UUID uuid) {
|
||||||
|
trusted.remove(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<UUID> getTrusted() {
|
||||||
|
return trusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX1() {
|
||||||
|
return x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ1() {
|
||||||
|
return z1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX2() {
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ2() {
|
||||||
|
return z2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWorldName() {
|
||||||
|
return worldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInside(Location location) {
|
||||||
|
if (!location.getWorld().getName().equals(worldName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int x = location.getBlockX();
|
||||||
|
int z = location.getBlockZ();
|
||||||
|
return x >= x1 && x <= x2 && z >= z1 && z <= z2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean overlaps(Claim other) {
|
||||||
|
if (!this.worldName.equals(other.worldName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !(this.x2 < other.x1 || this.x1 > other.x2 || this.z2 < other.z1 || this.z1 > other.z2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,10 @@ package de.viper.survivalplus.util;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.block.data.type.Chest;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@@ -10,9 +13,11 @@ import org.bukkit.configuration.file.FileConfiguration;
|
|||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
@@ -27,6 +32,7 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
private final Map<Location, LockData> lockedBlocks = new HashMap<>();
|
private final Map<Location, LockData> lockedBlocks = new HashMap<>();
|
||||||
private final Set<UUID> lockMode = new HashSet<>();
|
private final Set<UUID> lockMode = new HashSet<>();
|
||||||
private final Map<UUID, BukkitRunnable> lockTimeoutTasks = new HashMap<>();
|
private final Map<UUID, BukkitRunnable> lockTimeoutTasks = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> lastDenyMessage = new HashMap<>();
|
||||||
|
|
||||||
private final File lockFile;
|
private final File lockFile;
|
||||||
private FileConfiguration lockConfig;
|
private FileConfiguration lockConfig;
|
||||||
@@ -139,7 +145,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
if (lockedBlocks.containsKey(loc)) {
|
if (lockedBlocks.containsKey(loc)) {
|
||||||
player.sendMessage(plugin.getMessage("lock.already-locked"));
|
player.sendMessage(plugin.getMessage("lock.already-locked"));
|
||||||
} else {
|
} else {
|
||||||
|
// Lock den Block
|
||||||
lockedBlocks.put(loc, new LockData(uuid.toString()));
|
lockedBlocks.put(loc, new LockData(uuid.toString()));
|
||||||
|
|
||||||
|
// Prüfe auf Doppeltruhe und locke beide Hälften
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
Location otherLoc = otherChest.getLocation();
|
||||||
|
lockedBlocks.put(otherLoc, new LockData(uuid.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.locked"));
|
player.sendMessage(plugin.getMessage("lock.locked"));
|
||||||
}
|
}
|
||||||
@@ -149,7 +164,19 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isLockable) return;
|
if (!isLockable) return;
|
||||||
if (!lockedBlocks.containsKey(loc)) return;
|
|
||||||
|
// Prüfe sowohl den geklickten Block als auch die andere Hälfte bei Doppeltruhen
|
||||||
|
if (!lockedBlocks.containsKey(loc)) {
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
loc = otherChest.getLocation();
|
||||||
|
if (!lockedBlocks.containsKey(loc)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LockData lock = lockedBlocks.get(loc);
|
LockData lock = lockedBlocks.get(loc);
|
||||||
String playerUUID = uuid.toString();
|
String playerUUID = uuid.toString();
|
||||||
@@ -162,6 +189,176 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEU: Verhindert das Öffnen von gelockten Türen durch Redstone (Druckplatten, Knöpfe, etc.)
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onRedstoneChange(BlockRedstoneEvent event) {
|
||||||
|
Block block = event.getBlock();
|
||||||
|
|
||||||
|
// Prüfe, ob der Block eine Tür ist
|
||||||
|
if (!block.getType().name().contains("DOOR")) return;
|
||||||
|
|
||||||
|
Location loc = block.getLocation();
|
||||||
|
LockData lock = null;
|
||||||
|
|
||||||
|
// Prüfe, ob die Tür gelockt ist
|
||||||
|
if (lockedBlocks.containsKey(loc)) {
|
||||||
|
lock = lockedBlocks.get(loc);
|
||||||
|
} else {
|
||||||
|
// Prüfe auch die andere Hälfte der Tür (oben/unten)
|
||||||
|
Location above = loc.clone().add(0, 1, 0);
|
||||||
|
Location below = loc.clone().add(0, -1, 0);
|
||||||
|
|
||||||
|
if (lockedBlocks.containsKey(above)) {
|
||||||
|
lock = lockedBlocks.get(above);
|
||||||
|
} else if (lockedBlocks.containsKey(below)) {
|
||||||
|
lock = lockedBlocks.get(below);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn keine Lock gefunden wurde, erlaube die Änderung
|
||||||
|
if (lock == null) return;
|
||||||
|
|
||||||
|
// Wenn die Tür gelockt ist und Redstone-Signal empfängt, blockiere die Änderung
|
||||||
|
// Es sei denn, das Signal kommt von einem berechtigten Spieler (wird über Druckplatten-Event geprüft)
|
||||||
|
if (event.getNewCurrent() > 0) {
|
||||||
|
event.setNewCurrent(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZUSÄTZLICH: Verhindert Interaktion mit Druckplatten/Knöpfen in der Nähe von gelockten Türen
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onPressurePlateInteract(PlayerInteractEvent event) {
|
||||||
|
if (event.getAction() != Action.PHYSICAL) return;
|
||||||
|
|
||||||
|
Block block = event.getClickedBlock();
|
||||||
|
if (block == null) return;
|
||||||
|
|
||||||
|
// Prüfe, ob es eine Druckplatte ist
|
||||||
|
String typeName = block.getType().name();
|
||||||
|
if (!typeName.contains("PRESSURE_PLATE")) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID playerUUID = player.getUniqueId();
|
||||||
|
|
||||||
|
// Prüfe alle angrenzenden Blöcke auf gelockte Türen
|
||||||
|
for (BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||||
|
Block relative = block.getRelative(face);
|
||||||
|
|
||||||
|
// Prüfe bis zu 2 Blöcke in jede Richtung
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (relative.getType().name().contains("DOOR")) {
|
||||||
|
Location doorLoc = relative.getLocation();
|
||||||
|
|
||||||
|
// Prüfe beide Türhälften
|
||||||
|
LockData lock = getLockData(doorLoc);
|
||||||
|
|
||||||
|
if (lock != null && !hasAccess(player, lock)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
// Anti-Spam: Nur alle 3 Sekunden eine Nachricht senden
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Long lastMessage = lastDenyMessage.get(playerUUID);
|
||||||
|
|
||||||
|
if (lastMessage == null || (currentTime - lastMessage) > 3000) {
|
||||||
|
player.sendMessage(plugin.getMessage("lock.block-denied"));
|
||||||
|
lastDenyMessage.put(playerUUID, currentTime);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relative = relative.getRelative(face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLockedDoor(Location loc) {
|
||||||
|
return lockedBlocks.containsKey(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LockData getLockData(Location loc) {
|
||||||
|
LockData lock = lockedBlocks.get(loc);
|
||||||
|
if (lock == null) {
|
||||||
|
lock = lockedBlocks.get(loc.clone().add(0, 1, 0));
|
||||||
|
}
|
||||||
|
if (lock == null) {
|
||||||
|
lock = lockedBlocks.get(loc.clone().add(0, -1, 0));
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAccess(Player player, LockData lock) {
|
||||||
|
String playerUUID = player.getUniqueId().toString();
|
||||||
|
return lock.getOwnerUUID().equals(playerUUID) ||
|
||||||
|
lock.isFriend(playerUUID) ||
|
||||||
|
player.isOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hilfsmethode: Findet die andere Hälfte einer Doppeltruhe
|
||||||
|
private Block getOtherChestHalf(Block block) {
|
||||||
|
if (block.getType() != Material.CHEST && block.getType() != Material.TRAPPED_CHEST) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Versuche moderne BlockData API (1.13+)
|
||||||
|
if (block.getBlockData() instanceof Chest) {
|
||||||
|
Chest chestData = (Chest) block.getBlockData();
|
||||||
|
|
||||||
|
// Prüfe ob es eine Doppeltruhe ist
|
||||||
|
if (chestData.getType() == Chest.Type.SINGLE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finde die Richtung zur anderen Hälfte
|
||||||
|
BlockFace facing = chestData.getFacing();
|
||||||
|
BlockFace direction;
|
||||||
|
|
||||||
|
if (chestData.getType() == Chest.Type.LEFT) {
|
||||||
|
// Linke Hälfte: Andere Hälfte ist rechts
|
||||||
|
direction = getRight(facing);
|
||||||
|
} else {
|
||||||
|
// Rechte Hälfte: Andere Hälfte ist links
|
||||||
|
direction = getLeft(facing);
|
||||||
|
}
|
||||||
|
|
||||||
|
Block otherBlock = block.getRelative(direction);
|
||||||
|
if (otherBlock.getType() == block.getType()) {
|
||||||
|
return otherBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Fallback für ältere Versionen: Prüfe alle angrenzenden Blöcke
|
||||||
|
for (BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||||
|
Block relative = block.getRelative(face);
|
||||||
|
if (relative.getType() == block.getType()) {
|
||||||
|
return relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockFace getRight(BlockFace face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return BlockFace.EAST;
|
||||||
|
case EAST: return BlockFace.SOUTH;
|
||||||
|
case SOUTH: return BlockFace.WEST;
|
||||||
|
case WEST: return BlockFace.NORTH;
|
||||||
|
default: return face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockFace getLeft(BlockFace face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return BlockFace.WEST;
|
||||||
|
case WEST: return BlockFace.SOUTH;
|
||||||
|
case SOUTH: return BlockFace.EAST;
|
||||||
|
case EAST: return BlockFace.NORTH;
|
||||||
|
default: return face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
@@ -174,6 +371,13 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
String playerUUID = player.getUniqueId().toString();
|
String playerUUID = player.getUniqueId().toString();
|
||||||
|
|
||||||
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
|
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
|
||||||
|
// Erlaube das Brechen und entferne beide Locks bei Doppeltruhen
|
||||||
|
lockedBlocks.remove(loc);
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
lockedBlocks.remove(otherChest.getLocation());
|
||||||
|
}
|
||||||
|
saveLocks();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +437,13 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.no-permission-unlock"));
|
player.sendMessage(plugin.getMessage("lock.no-permission-unlock"));
|
||||||
} else {
|
} else {
|
||||||
lockedBlocks.remove(loc);
|
lockedBlocks.remove(loc);
|
||||||
|
|
||||||
|
// Entferne auch Lock von der anderen Hälfte bei Doppeltruhen
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
lockedBlocks.remove(otherChest.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.unlocked"));
|
player.sendMessage(plugin.getMessage("lock.unlocked"));
|
||||||
}
|
}
|
||||||
@@ -254,6 +465,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.friendadd.not-found"));
|
player.sendMessage(plugin.getMessage("lock.friendadd.not-found"));
|
||||||
} else {
|
} else {
|
||||||
lock.addFriend(friend.getUniqueId().toString());
|
lock.addFriend(friend.getUniqueId().toString());
|
||||||
|
|
||||||
|
// Füge Friend auch zur anderen Hälfte bei Doppeltruhen hinzu
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
LockData otherLock = lockedBlocks.get(otherChest.getLocation());
|
||||||
|
if (otherLock != null) {
|
||||||
|
otherLock.addFriend(friend.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.friendadd.success").replace("{player}", friend.getName()));
|
player.sendMessage(plugin.getMessage("lock.friendadd.success").replace("{player}", friend.getName()));
|
||||||
}
|
}
|
||||||
@@ -276,6 +497,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.friendremove.not-found"));
|
player.sendMessage(plugin.getMessage("lock.friendremove.not-found"));
|
||||||
} else {
|
} else {
|
||||||
lock.removeFriend(friend.getUniqueId().toString());
|
lock.removeFriend(friend.getUniqueId().toString());
|
||||||
|
|
||||||
|
// Entferne Friend auch von der anderen Hälfte bei Doppeltruhen
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
LockData otherLock = lockedBlocks.get(otherChest.getLocation());
|
||||||
|
if (otherLock != null) {
|
||||||
|
otherLock.removeFriend(friend.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.friendremove.success").replace("{player}", friend.getName()));
|
player.sendMessage(plugin.getMessage("lock.friendremove.success").replace("{player}", friend.getName()));
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/main/resources/blockedcommands.yml
Normal file
4
src/main/resources/blockedcommands.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
blocked-commands:
|
||||||
|
- op
|
||||||
|
- ban
|
||||||
|
- kick
|
||||||
0
src/main/resources/claims.yml
Normal file
0
src/main/resources/claims.yml
Normal file
@@ -1,3 +1,9 @@
|
|||||||
|
# Version (Nicht Ändern!)
|
||||||
|
version: 1.1.0
|
||||||
|
|
||||||
|
# Debug-Option
|
||||||
|
debug-logging: false
|
||||||
|
|
||||||
# Neulings Schutz
|
# Neulings Schutz
|
||||||
newbie-protection:
|
newbie-protection:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -3,17 +3,57 @@ footer: "&6==========================="
|
|||||||
|
|
||||||
commands:
|
commands:
|
||||||
gm:
|
gm:
|
||||||
description: "&eWechselt den Spielmodus (survival, creative, adventure, spectator)."
|
description: "&eÄndert den Spielmodus eines Spielers (survival, creative, adventure, spectator)."
|
||||||
usage: "&b/gm [spieler]"
|
usage: "&b/gm <modus> [spieler]"
|
||||||
|
|
||||||
sp:
|
sp:
|
||||||
description: "&eHauptbefehl für SurvivalPlus mit Unterbefehlen."
|
description: "&eHauptbefehl für SurvivalPlus mit Unterbefehlen."
|
||||||
usage: "&b/sp "
|
usage: "&b/sp [reload | help | info | share | lock]"
|
||||||
|
|
||||||
share:
|
sp_reload:
|
||||||
description: "&eTeilt deine aktuellen Koordinaten nach Bestätigung mit allen Spielern."
|
description: "&eLädt das Plugin neu."
|
||||||
|
usage: "&b/sp reload"
|
||||||
|
|
||||||
|
sp_help:
|
||||||
|
description: "&eZeigt die Hilfe für SurvivalPlus-Befehle an."
|
||||||
|
usage: "&b/sp help"
|
||||||
|
|
||||||
|
sp_info:
|
||||||
|
description: "&eZeigt Informationen über das Plugin an."
|
||||||
|
usage: "&b/sp info"
|
||||||
|
|
||||||
|
sp_share:
|
||||||
|
description: "&eTeilt deine Koordinaten nach Bestätigung mit allen Spielern."
|
||||||
usage: "&b/sp share"
|
usage: "&b/sp share"
|
||||||
|
|
||||||
|
sp_cb_add:
|
||||||
|
description: "&eFügt einen Befehl zur Blockierliste hinzu."
|
||||||
|
usage: "&b/sp cb add <befehl>"
|
||||||
|
|
||||||
|
sp_cb_remove:
|
||||||
|
description: "&eEntfernt einen Befehl aus der Blockierliste."
|
||||||
|
usage: "&b/sp cb remove <befehl>"
|
||||||
|
|
||||||
|
sp_cb_list:
|
||||||
|
description: "&eZeigt die Liste der blockierten Befehle an."
|
||||||
|
usage: "&b/sp cb list"
|
||||||
|
|
||||||
|
sp_lock_lock:
|
||||||
|
description: "&eSperrt einen Container (z.B. Kiste oder Tür)."
|
||||||
|
usage: "&b/sp lock "
|
||||||
|
|
||||||
|
sp_lock_unlock:
|
||||||
|
description: "&eEntsperrt einen Container (z.B. Kiste oder Tür)."
|
||||||
|
usage: "&b/sp lock "
|
||||||
|
|
||||||
|
sp_lock_friendadd:
|
||||||
|
description: "&eFügt einen Freund zum Container-Sperrsystem hinzu."
|
||||||
|
usage: "&b/sp lock friendadd <Spieler>"
|
||||||
|
|
||||||
|
sp_lock_friendremove:
|
||||||
|
description: "&eEntfernt einen Freund aus dem Container-Sperrsystem."
|
||||||
|
usage: "&b/sp lock friendremove <Spieler>"
|
||||||
|
|
||||||
shareconfirm:
|
shareconfirm:
|
||||||
description: "&eBestätigt das Teilen deiner Koordinaten mit allen Spielern."
|
description: "&eBestätigt das Teilen deiner Koordinaten mit allen Spielern."
|
||||||
usage: "&b/sp shareconfirm"
|
usage: "&b/sp shareconfirm"
|
||||||
@@ -23,71 +63,90 @@ commands:
|
|||||||
usage: "&b/sp sharecancel"
|
usage: "&b/sp sharecancel"
|
||||||
|
|
||||||
sethome:
|
sethome:
|
||||||
description: "&eSetzt einen neuen Homepunkt."
|
description: "&eSetzt ein Home mit dem angegebenen Namen."
|
||||||
usage: "&b/sethome "
|
usage: "&b/sethome <name>"
|
||||||
|
|
||||||
delhome:
|
delhome:
|
||||||
description: "&eLöscht einen Homepunkt."
|
description: "&eLöscht ein Home mit dem angegebenen Namen."
|
||||||
usage: "&b/delhome "
|
usage: "&b/delhome <name>"
|
||||||
|
|
||||||
homelist:
|
homelist:
|
||||||
description: "&eZeigt alle deine Homes."
|
description: "&eÖffnet eine GUI mit allen Homes."
|
||||||
usage: "&b/homelist"
|
usage: "&b/homelist"
|
||||||
|
|
||||||
home:
|
home:
|
||||||
description: "&eTeleportiert dich zu einem gespeicherten Home."
|
description: "&eTeleportiert zu einem Home."
|
||||||
usage: "&b/home "
|
usage: "&b/home <name>"
|
||||||
|
|
||||||
inv:
|
inv:
|
||||||
description: "&eÖffnet dein Inventar oder das eines anderen Spielers."
|
description: "&eÖffnet das Inventar (eigenes oder das eines anderen Spielers)."
|
||||||
usage: "&b/inv "
|
usage: "&b/inv [spieler]"
|
||||||
|
|
||||||
ec:
|
ec:
|
||||||
description: "&eÖffnet deine Endertruhe oder die eines anderen Spielers."
|
description: "&eÖffnet die Endertruhe (eigene oder die eines anderen Spielers)."
|
||||||
usage: "&b/ec [spieler]"
|
usage: "&b/ec [spieler]"
|
||||||
|
|
||||||
setspawn:
|
|
||||||
description: "&eSetzt den Spawnpunkt der Welt."
|
|
||||||
usage: "&b/setspawn"
|
|
||||||
|
|
||||||
setworldspawn:
|
setworldspawn:
|
||||||
description: "&eSetzt den globalen Weltspawnpunkt."
|
description: "&eSetzt den Weltspawnpunkt auf die Position des Spielers."
|
||||||
usage: "&b/setworldspawn"
|
usage: "&b/setworldspawn"
|
||||||
|
|
||||||
|
setspawn:
|
||||||
|
description: "&eSetzt den Server-Spawnpunkt auf die Position des Spielers."
|
||||||
|
usage: "&b/setspawn"
|
||||||
|
|
||||||
clearchat:
|
clearchat:
|
||||||
description: "&eLöscht den Chat für alle Spieler."
|
description: "&eLöscht den Chat für alle Spieler."
|
||||||
usage: "&b/clearchat"
|
usage: "&b/clearchat"
|
||||||
|
|
||||||
clearitems:
|
clearitems:
|
||||||
description: "&eEntfernt alle Items auf dem Boden."
|
description: "&eLöscht alle herumliegenden Items."
|
||||||
usage: "&b/clearitems"
|
usage: "&b/clearitems"
|
||||||
|
|
||||||
closedoors:
|
closedoors:
|
||||||
description: "&eSchließt alle Türen im angegebenen Radius."
|
description: "&eSchließt alle Türen im angegebenen Radius."
|
||||||
usage: "&b/closedoors "
|
usage: "&b/closedoors <radius>"
|
||||||
|
|
||||||
sit:
|
sit:
|
||||||
description: "&eSetzt dich hin oder steht wieder auf."
|
description: "&eLässt den Spieler sich hinsetzen oder aufstehen."
|
||||||
usage: "&b/sit"
|
usage: "&b/sit"
|
||||||
|
|
||||||
back:
|
back:
|
||||||
description: "&eTeleportiert dich zurück zum letzten Todespunkt."
|
description: "&eTeleportiert zum letzten Todespunkt."
|
||||||
usage: "&b/back"
|
usage: "&b/back"
|
||||||
|
|
||||||
friend:
|
friend:
|
||||||
description: "&eVerwalte deine Freundesliste (hinzufügen, entfernen, anzeigen, teleportieren). Unterstützt anklickbare Anfragen und Bestätigungen."
|
description: "&eVerwaltet die Freundesliste (hinzufügen, entfernen, anzeigen, teleportieren)."
|
||||||
usage: "&b/friend [Spieler]"
|
usage: "&b/friend [add | accept | deny | list | del | tp] [Spieler]"
|
||||||
|
subcommands:
|
||||||
|
add:
|
||||||
|
description: "&eFügt einen Spieler zur Freundesliste hinzu."
|
||||||
|
usage: "&b/friend add <Spieler>"
|
||||||
|
accept:
|
||||||
|
description: "&eAkzeptiert eine Freundschaftsanfrage."
|
||||||
|
usage: "&b/friend accept <Spieler>"
|
||||||
|
deny:
|
||||||
|
description: "&eLehnt eine Freundschaftsanfrage ab."
|
||||||
|
usage: "&b/friend deny <Spieler>"
|
||||||
|
list:
|
||||||
|
description: "&eZeigt die Freundesliste an."
|
||||||
|
usage: "&b/friend list"
|
||||||
|
del:
|
||||||
|
description: "&eEntfernt einen Spieler aus der Freundesliste."
|
||||||
|
usage: "&b/friend del <Spieler>"
|
||||||
|
tp:
|
||||||
|
description: "&eTeleportiert dich zu einem Freund."
|
||||||
|
usage: "&b/friend tp <Spieler>"
|
||||||
|
|
||||||
ir:
|
ir:
|
||||||
description: "&eBenennt Items um."
|
description: "&eBenennt das Item in der Hand um."
|
||||||
usage: "&b/ir "
|
usage: "&b/ir <neuer_name>"
|
||||||
|
|
||||||
showarmorstands:
|
showarmorstands:
|
||||||
description: "&eZeigt unsichtbare ArmorStands an."
|
description: "&eMacht alle unsichtbaren Armor Stands sichtbar."
|
||||||
usage: "&b/showarmorstands"
|
usage: "&b/showarmorstands"
|
||||||
|
|
||||||
cleardebugarmorstands:
|
cleardebugarmorstands:
|
||||||
description: "&eLöscht alle Debug ArmorStands."
|
description: "&eEntfernt alle Debug-ArmorStands."
|
||||||
usage: "&b/cleardebugarmorstands"
|
usage: "&b/cleardebugarmorstands"
|
||||||
|
|
||||||
trash:
|
trash:
|
||||||
@@ -95,76 +154,72 @@ commands:
|
|||||||
usage: "&b/trash"
|
usage: "&b/trash"
|
||||||
|
|
||||||
workbench:
|
workbench:
|
||||||
description: "&eÖffnet eine Werkbank GUI."
|
description: "&eÖffnet eine Werkbank-GUI."
|
||||||
usage: "&b/workbench"
|
usage: "&b/workbench"
|
||||||
|
|
||||||
anvil:
|
anvil:
|
||||||
description: "&eÖffnet eine Amboss GUI."
|
description: "&eÖffnet eine Amboss-GUI."
|
||||||
usage: "&b/anvil"
|
usage: "&b/anvil"
|
||||||
|
|
||||||
stats:
|
stats:
|
||||||
description: "&eZeigt deine persönlichen Statistiken an."
|
description: "&eZeigt deine Statistiken an."
|
||||||
usage: "&b/stats"
|
usage: "&b/stats"
|
||||||
|
|
||||||
spawn:
|
spawn:
|
||||||
description: "&eTeleportiert dich zum Welt-Spawnpunkt."
|
description: "&eTeleportiert dich zum Weltspawnpunkt."
|
||||||
usage: "&b/spawn"
|
usage: "&b/spawn"
|
||||||
|
|
||||||
lock:
|
|
||||||
description: "&eSchützt Container mit dem LockSystem."
|
|
||||||
usage: "&b/lock [Spieler]"
|
|
||||||
|
|
||||||
tp:
|
tp:
|
||||||
description: "&eTeleportiert dich zu einem anderen Spieler."
|
description: "&eTeleportiert dich zu einem Spieler."
|
||||||
usage: "&b/tp "
|
usage: "&b/tp <Spieler>"
|
||||||
|
|
||||||
tphere:
|
tphere:
|
||||||
description: "&eTeleportiert einen Spieler zu dir."
|
description: "&eTeleportiert einen Spieler zu dir."
|
||||||
usage: "&b/tphere "
|
usage: "&b/tphere <Spieler>"
|
||||||
|
|
||||||
tpa:
|
tpa:
|
||||||
description: "&eSendet eine Teleport-Anfrage an einen Spieler."
|
description: "&eSendet eine Teleportanfrage an einen Spieler."
|
||||||
usage: "&b/tpa "
|
usage: "&b/tpa <Spieler>"
|
||||||
|
|
||||||
tpaccept:
|
tpaccept:
|
||||||
description: "&eAkzeptiert eine Teleport-Anfrage."
|
description: "&eAkzeptiert eine Teleportanfrage."
|
||||||
usage: "&b/tpaccept"
|
usage: "&b/tpaccept"
|
||||||
|
|
||||||
tpdeny:
|
tpdeny:
|
||||||
description: "&eLehnt eine Teleport-Anfrage ab."
|
description: "&eLehnt eine Teleportanfrage ab."
|
||||||
usage: "&b/tpdeny"
|
usage: "&b/tpdeny"
|
||||||
|
|
||||||
block:
|
block:
|
||||||
description: "&eBlockiert Nachrichten eines Spielers."
|
description: "&eBlockiert einen Spieler."
|
||||||
usage: "&b/block "
|
usage: "&b/block <Spieler>"
|
||||||
|
|
||||||
unblock:
|
unblock:
|
||||||
description: "&eHebt eine Blockierung auf."
|
description: "&eEntblockt einen Spieler."
|
||||||
usage: "&b/unblock "
|
usage: "&b/unblock <Spieler>"
|
||||||
|
|
||||||
blocklist:
|
blocklist:
|
||||||
description: "&eZeigt eine Liste blockierter Spieler."
|
description: "&eZeigt eine Liste der blockierten Spieler."
|
||||||
usage: "&b/blocklist"
|
usage: "&b/blocklist"
|
||||||
|
|
||||||
kit:
|
kit:
|
||||||
description: "&eErhalte dein Starterkit."
|
description: "&eHolt das Starterkit."
|
||||||
usage: "&b/kit"
|
usage: "&b/kit"
|
||||||
|
|
||||||
leashcount:
|
leashcount:
|
||||||
description: "&eZeigt die Anzahl der angeleinten Tiere an."
|
description: "&eZeigt die Anzahl der geleinten Tiere an."
|
||||||
usage: "&b/leashcount"
|
usage: "&b/leashcount"
|
||||||
|
|
||||||
nick:
|
nick:
|
||||||
description: "&eÄndert deinen angezeigten Namen mit Farben (&) und Hex-Farben (#RRGGBB)."
|
description: "&eÄndert deinen Nicknamen mit Farb- und Hex-Support."
|
||||||
usage: "&b/nick "
|
usage: "&b/nick <Name>"
|
||||||
|
|
||||||
trade:
|
lootchests:
|
||||||
description: "&eStartet einen Handel mit einem Spieler."
|
description: "&eZeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick teleportieren."
|
||||||
usage: "&b/trade "
|
usage: "&b/lootchests"
|
||||||
|
|
||||||
tradeaccept:
|
tploot:
|
||||||
description: "&eAkzeptiert eine Handelsanfrage."
|
description: "&eTeleportiert dich zu einer Loot-Kiste (nur Admins)."
|
||||||
usage: "&b/tradeaccept "
|
usage: "&b/tploot <welt> <x> <y> <z>"
|
||||||
|
|
||||||
day:
|
day:
|
||||||
description: "&eSetzt die Zeit auf Tag."
|
description: "&eSetzt die Zeit auf Tag."
|
||||||
@@ -174,33 +229,78 @@ commands:
|
|||||||
description: "&eSetzt die Zeit auf Nacht."
|
description: "&eSetzt die Zeit auf Nacht."
|
||||||
usage: "&b/night"
|
usage: "&b/night"
|
||||||
|
|
||||||
|
trade:
|
||||||
|
description: "&eStartet einen Handel mit einem Spieler."
|
||||||
|
usage: "&b/trade <Spieler>"
|
||||||
|
|
||||||
|
tradeaccept:
|
||||||
|
description: "&eAkzeptiert eine Handelsanfrage."
|
||||||
|
usage: "&b/tradeaccept <Spieler>"
|
||||||
|
|
||||||
report:
|
report:
|
||||||
description: "&eMeldet einen Spieler an die Admins."
|
description: "&eMeldet einen Spieler an die Admins."
|
||||||
usage: "&b/report [Grund]"
|
usage: "&b/report <Spieler> [Grund]"
|
||||||
|
|
||||||
showreport:
|
showreport:
|
||||||
description: "&eZeigt alle Reports eines Spielers an."
|
description: "&eZeigt alle Reports eines Spielers an."
|
||||||
usage: "&b/showreport "
|
usage: "&b/showreport <Spieler>"
|
||||||
|
|
||||||
clearreport:
|
clearreport:
|
||||||
description: "&eLöscht alle Reports eines Spielers."
|
description: "&eLöscht alle Reports eines Spielers."
|
||||||
usage: "&b/clearreport "
|
usage: "&b/clearreport <Spieler>"
|
||||||
|
|
||||||
shop:
|
shop:
|
||||||
description: "&eVerwaltet den Server-Shop (z.B. Items hinzufügen)."
|
description: "&eVerwaltet den Server-Shop (z.B. Items hinzufügen)."
|
||||||
usage: "&b/shop add "
|
usage: "&b/shop add <item> <basispreis> <lagerbestand>"
|
||||||
|
|
||||||
|
setwarp:
|
||||||
|
description: "&eSetzt einen persönlichen Warp mit dem Item in der Hand."
|
||||||
|
usage: "&b/setwarp <name>"
|
||||||
|
|
||||||
|
delwarp:
|
||||||
|
description: "&eLöscht einen persönlichen Warp."
|
||||||
|
usage: "&b/delwarp <name>"
|
||||||
|
|
||||||
|
warps:
|
||||||
|
description: "&eÖffnet die GUI mit allen Spieler-Warps."
|
||||||
|
usage: "&b/warps"
|
||||||
|
|
||||||
|
startchallenge:
|
||||||
|
description: "&eStartet eine Fun-Challenge."
|
||||||
|
usage: "&b/startchallenge <name>"
|
||||||
|
|
||||||
|
heal:
|
||||||
|
description: "&eHeilt einen Spieler vollständig."
|
||||||
|
usage: "&b/heal [spieler]"
|
||||||
|
|
||||||
|
claim:
|
||||||
|
description: "&eVerwaltet Claims für den Anti-Grief-Schutz."
|
||||||
|
usage: "&b/claim [mark <1|2>| unclaim | trust <spieler> | untrust <spieler>]"
|
||||||
|
subcommands:
|
||||||
|
mark:
|
||||||
|
description: "&eMarkiert die erste oder zweite Ecke eines zu schützenden Bereichs."
|
||||||
|
usage: "&b/claim mark <1|2>"
|
||||||
|
unclaim:
|
||||||
|
description: "&eGibt den geschützten Bereich frei, in dem du stehst."
|
||||||
|
usage: "&b/claim unclaim"
|
||||||
|
trust:
|
||||||
|
description: "&eFügt einen Spieler als vertrauenswürdig hinzu, sodass er im Bereich bauen kann."
|
||||||
|
usage: "&b/claim trust <spieler>"
|
||||||
|
untrust:
|
||||||
|
description: "&eEntfernt die Vertrauensberechtigung eines Spielers für den Bereich."
|
||||||
|
usage: "&b/claim untrust <spieler>"
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
header: "&6=== Befehle ==="
|
header: "&6=== Befehle ==="
|
||||||
footer: "&6================"
|
footer: "&6================"
|
||||||
navigation:
|
navigation:
|
||||||
prev: "&7« Vorherige "
|
prev: "&7« Vorherige Seite"
|
||||||
next: "&7 Nächste »"
|
next: "&7Nächste Seite »"
|
||||||
prev-disabled: "&8« "
|
prev-disabled: "&8« Vorherige Seite"
|
||||||
next-disabled: "&8 »"
|
next-disabled: "&8Nächste Seite »"
|
||||||
page: "&fSeite {current} von {total} "
|
page: "&fSeite {current} von {total}"
|
||||||
sp:
|
sp:
|
||||||
invalid-subcommand: "&cUngültiger Unterbefehl! Verwendung: /sp [reload|help|info|share]"
|
invalid-subcommand: "&cUngültiger Unterbefehl! Verwendung: /sp [reload|help|info|share|lock]"
|
||||||
no-permission: "&cDu hast keine Berechtigung für diesen Befehl!"
|
no-permission: "&cDu hast keine Berechtigung für diesen Befehl!"
|
||||||
plugin:
|
plugin:
|
||||||
reloaded: "&aSurvivalPlus wurde erfolgreich neu geladen!"
|
reloaded: "&aSurvivalPlus wurde erfolgreich neu geladen!"
|
||||||
@@ -215,7 +315,7 @@ messages:
|
|||||||
preview-title: "&aDeine aktuellen Koordinaten wären:"
|
preview-title: "&aDeine aktuellen Koordinaten wären:"
|
||||||
preview-format: "&e%player% &7teilt Koordinaten: &eX: %x%, Y: %y%, Z: %z% &7in Welt &e%world%"
|
preview-format: "&e%player% &7teilt Koordinaten: &eX: %x%, Y: %y%, Z: %z% &7in Welt &e%world%"
|
||||||
send-button: "&a[✅ Senden]"
|
send-button: "&a[✅ Senden]"
|
||||||
cancel-button: "&c [❌ Abbrechen]"
|
cancel-button: "&c[❌ Abbrechen]"
|
||||||
send-hover: "&aKlicke, um deine Koordinaten an alle zu senden."
|
send-hover: "&aKlicke, um deine Koordinaten an alle zu senden."
|
||||||
cancel-hover: "&cKlicke, um das Senden abzubrechen."
|
cancel-hover: "&cKlicke, um das Senden abzubrechen."
|
||||||
sent: "&aKoordinaten gesendet."
|
sent: "&aKoordinaten gesendet."
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ friend:
|
|||||||
notify: "&c%s hat deine Freundschaftsanfrage abgelehnt."
|
notify: "&c%s hat deine Freundschaftsanfrage abgelehnt."
|
||||||
|
|
||||||
list:
|
list:
|
||||||
header: "&6=== Deine Freundesliste ==="
|
header: "&6== Deine Freundesliste =="
|
||||||
entry: "&e%s: %s"
|
entry: "&e%s: %s"
|
||||||
entry-offline: "&e%s: %s &7(Zuletzt online: %s)"
|
entry-offline: "&e%s: %s &7(Zuletzt online: %s)"
|
||||||
online: "&aOnline"
|
online: "&aOnline"
|
||||||
@@ -168,7 +168,7 @@ friend:
|
|||||||
unknown: "&7Unbekannt"
|
unknown: "&7Unbekannt"
|
||||||
date-format: "dd.MM.yyyy HH:mm:ss"
|
date-format: "dd.MM.yyyy HH:mm:ss"
|
||||||
remove-button: "&c[X]"
|
remove-button: "&c[X]"
|
||||||
footer: "&6====================="
|
footer: "&6======================="
|
||||||
|
|
||||||
del:
|
del:
|
||||||
success: "&a%s wurde aus deiner Freundesliste entfernt."
|
success: "&a%s wurde aus deiner Freundesliste entfernt."
|
||||||
@@ -402,5 +402,33 @@ inventory:
|
|||||||
no-permission-others: "§cDu hast keine Berechtigung, das Inventar anderer Spieler anzusehen!"
|
no-permission-others: "§cDu hast keine Berechtigung, das Inventar anderer Spieler anzusehen!"
|
||||||
player-only: "§cDieser Befehl ist nur für Spieler!"
|
player-only: "§cDieser Befehl ist nur für Spieler!"
|
||||||
|
|
||||||
|
claim:
|
||||||
|
usage: "&cVerwendung: /claim mark <1|2> oder /claim"
|
||||||
|
points-not-set: "&cDu musst zuerst zwei Punkte markieren! Verwende /claim mark <1|2>."
|
||||||
|
different-worlds: "&cDie markierten Punkte müssen in derselben Welt liegen!"
|
||||||
|
too-large: "&cDer Bereich ist zu groß! Maximal erlaubt: %max% Blöcke²."
|
||||||
|
overlap: "&cDieser Bereich überschneidet sich mit einem bestehenden Claim!"
|
||||||
|
max-reached: "&cDu hast das Maximum von %max% Claims erreicht!"
|
||||||
|
success: "&aBereich beansprucht! (%count%/%max%)"
|
||||||
|
unclaimed: "&aBereich freigegeben!"
|
||||||
|
not-owner: "&cDies ist nicht dein Claim!"
|
||||||
|
point1-set: "&aPunkt 1 gesetzt bei x=%x%, z=%z%."
|
||||||
|
point2-set: "&aPunkt 2 gesetzt bei x=%x%, z=%z%."
|
||||||
|
trusted: "&a%player% ist jetzt in diesem Claim vertraut!"
|
||||||
|
untrusted: "&a%player% ist in diesem Claim nicht mehr vertraut!"
|
||||||
|
no-break: "&cDu kannst in diesem beanspruchten Bereich keine Blöcke abbauen!"
|
||||||
|
no-place: "&cDu kannst in diesem beanspruchten Bereich keine Blöcke platzieren!"
|
||||||
|
op-unclaimed: "&a%count% Claims von %player% wurden entfernt!"
|
||||||
|
no-claims-found: "&cKeine Claims für %player% gefunden!"
|
||||||
|
no-claim-at-location: "&cKein Claim an dieser Position!"
|
||||||
|
info:
|
||||||
|
- "&eClaim-Info:"
|
||||||
|
- "&7Besitzer: &e%owner%"
|
||||||
|
- "&7Welt: &e%world%"
|
||||||
|
- "&7Koordinaten: &eX1: %x1%, Z1: %z1% bis X2: %x2%, Z2: %z2%"
|
||||||
|
enter: "&aDu hast das Gebiet von %owner% betreten."
|
||||||
|
leave: "&eDu hast das Gebiet von %owner% verlassen."
|
||||||
|
|
||||||
|
|
||||||
force-survival:
|
force-survival:
|
||||||
join-message: "§aDu wurdest in den Survivalmodus gesetzt!"
|
join-message: "§aDu wurdest in den Survivalmodus gesetzt!"
|
||||||
@@ -1,290 +1,288 @@
|
|||||||
name: SurvivalPlus
|
name: SurvivalPlus
|
||||||
version: 1.0.5
|
version: 1.1.1
|
||||||
|
|
||||||
main: de.viper.survivalplus.SurvivalPlus
|
main: de.viper.survivalplus.SurvivalPlus
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
softdepend: [LuckPerms, PlaceholderAPI]
|
softdepend: [LuckPerms, PlaceholderAPI, ProtocolLib]
|
||||||
author: Viper
|
author: Viper
|
||||||
description: A plugin for enhancing survival gameplay in Minecraft.
|
description: A plugin for enhancing survival gameplay in Minecraft.
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
|
sp:
|
||||||
|
description: Hauptbefehl für SurvivalPlus (Command-Blocker, Reload, Info, etc.)
|
||||||
|
usage: /<command> [cb add|cb remove|cb list|reload|help|info|share] [args]
|
||||||
|
permission: survivalplus.sp
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
ir:
|
ir:
|
||||||
description: Benennt das Item in der Hand um.
|
description: Benennt das Item in der Hand um.
|
||||||
usage: /ir <neuer_name>
|
usage: /<command> <neuer_name>
|
||||||
permission: survivalplus.itemrename
|
permission: survivalplus.itemrename
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
gm:
|
gm:
|
||||||
description: Ändert den Spielmodus eines Spielers
|
description: Ändert den Spielmodus eines Spielers
|
||||||
usage: /<command> <modus> [spieler]
|
usage: /<command> <modus> [spieler]
|
||||||
aliases: [gamemode]
|
aliases: [gamemode]
|
||||||
permission: survivalplus.gamemode
|
permission: survivalplus.gamemode
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
sp:
|
|
||||||
description: Zeigt Plugin-Informationen oder führt weitere Befehle aus
|
|
||||||
usage: /<command> [reload|help|info|share] [seite]
|
|
||||||
permission: survivalplus.sp
|
|
||||||
|
|
||||||
sethome:
|
sethome:
|
||||||
description: Setzt ein Home mit dem angegebenen Namen
|
description: Setzt ein Home mit dem angegebenen Namen
|
||||||
usage: /<command> <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.homes.set
|
permission: survivalplus.homes.set
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
delhome:
|
delhome:
|
||||||
description: Löscht ein Home mit dem angegebenen Namen
|
description: Löscht ein Home mit dem angegebenen Namen
|
||||||
usage: /<command> <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.homes.delete
|
permission: survivalplus.homes.delete
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
homelist:
|
homelist:
|
||||||
description: Öffnet eine GUI mit allen Homes
|
description: Öffnet eine GUI mit allen Homes
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.homes.list
|
permission: survivalplus.homes.list
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
home:
|
home:
|
||||||
description: Teleportiert zu einem Home
|
description: Teleportiert zu einem Home
|
||||||
usage: /<command> <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.homes
|
permission: survivalplus.homes
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
inv:
|
inv:
|
||||||
description: Öffnet das Inventar (eigenes oder das eines anderen Spielers)
|
description: Öffnet das Inventar (eigenes oder das eines anderen Spielers)
|
||||||
usage: /<command> [spieler]
|
usage: /<command> [spieler]
|
||||||
permission: survivalplus.inventory.own
|
permission: survivalplus.inventory.own
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
ec:
|
ec:
|
||||||
description: Öffnet die Endertruhe (eigene oder die eines anderen Spielers)
|
description: Öffnet die Endertruhe (eigene oder die eines anderen Spielers)
|
||||||
usage: /<command> [spieler]
|
usage: /<command> [spieler]
|
||||||
permission: survivalplus.enderchest.own
|
permission: survivalplus.enderchest.own
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
setworldspawn:
|
setworldspawn:
|
||||||
description: Setzt den Weltspawnpunkt auf die Position des Spielers
|
description: Setzt den Weltspawnpunkt auf die Position des Spielers
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.setworldspawn
|
permission: survivalplus.setworldspawn
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
setspawn:
|
setspawn:
|
||||||
description: Setzt den Server-Spawnpunkt auf die Position des Spielers
|
description: Setzt den Server-Spawnpunkt auf die Position des Spielers
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.setspawn
|
permission: survivalplus.setspawn
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
clearchat:
|
clearchat:
|
||||||
description: Löscht den Chat für alle Spieler
|
description: Löscht den Chat für alle Spieler
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.clearchat
|
permission: survivalplus.clearchat
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
clearitems:
|
clearitems:
|
||||||
description: Löscht alle herumliegenden Items
|
description: Löscht alle herumliegenden Items
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.clearitems
|
permission: survivalplus.clearitems
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
closedoors:
|
closedoors:
|
||||||
description: Schließt alle Türen im angegebenen Radius
|
description: Schließt alle Türen im angegebenen Radius
|
||||||
usage: /<command> <radius>
|
usage: /<command> <radius>
|
||||||
permission: survivalplus.closedoors
|
permission: survivalplus.closedoors
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
sit:
|
sit:
|
||||||
description: Lässt den Spieler sich hinsetzen
|
description: Lässt den Spieler sich hinsetzen
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.sit
|
permission: survivalplus.sit
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
back:
|
back:
|
||||||
description: Teleportiert zum letzten Todespunkt
|
description: Teleportiert zum letzten Todespunkt
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: survivalplus.back
|
permission: survivalplus.back
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
friend:
|
friend:
|
||||||
description: Verwaltet die Freundesliste
|
description: Verwaltet die Freundesliste
|
||||||
usage: /<command> [add|accept|deny|list|del|tp] [Spielername]
|
usage: /<command> [add|accept|deny|list|del|tp] [Spielername]
|
||||||
permission: survivalplus.friend
|
# FIX: permission und permission-message entfernt um Warnung zu verhindern
|
||||||
|
|
||||||
stats:
|
stats:
|
||||||
description: Zeigt deine Statistiken an
|
description: Zeigt deine Statistiken an
|
||||||
usage: /stats
|
usage: /<command>
|
||||||
permission: survivalplus.stats
|
permission: survivalplus.stats
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
showarmorstands:
|
showarmorstands:
|
||||||
description: Macht alle unsichtbaren Armor Stands sichtbar.
|
description: Macht alle unsichtbaren Armor Stands sichtbar.
|
||||||
usage: /showarmorstands
|
usage: /<command>
|
||||||
permission: survivalplus.showarmorstands
|
permission: survivalplus.showarmorstands
|
||||||
permission-message: "§cDu hast keine Rechte für diesen Befehl."
|
permission-message: "§cDu hast keine Rechte für diesen Befehl."
|
||||||
|
|
||||||
cleardebugarmorstands:
|
cleardebugarmorstands:
|
||||||
description: Entfernt alle Debug-ArmorStands
|
description: Entfernt alle Debug-ArmorStands
|
||||||
usage: /cleardebugarmorstands
|
usage: /<command>
|
||||||
permission: survivalplus.cleardebugarmorstands
|
permission: survivalplus.cleardebugarmorstands
|
||||||
permission-message: "§cDu hast keine Rechte für diesen Befehl."
|
permission-message: "§cDu hast keine Rechte für diesen Befehl."
|
||||||
|
|
||||||
trash:
|
trash:
|
||||||
description: Öffnet den Mülleimer
|
description: Öffnet den Mülleimer
|
||||||
usage: /trash
|
usage: /<command>
|
||||||
permission: survivalplus.trash
|
permission: survivalplus.trash
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
workbench:
|
workbench:
|
||||||
description: Öffnet eine Werkbank GUI
|
description: Öffnet eine Werkbank GUI
|
||||||
usage: /workbench
|
usage: /<command>
|
||||||
permission: survivalplus.workbench
|
permission: survivalplus.workbench
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
anvil:
|
anvil:
|
||||||
description: Öffnet eine Amboss GUI
|
description: Öffnet eine Amboss GUI
|
||||||
usage: /anvil
|
usage: /<command>
|
||||||
permission: survivalplus.anvil
|
permission: survivalplus.anvil
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
leashcount:
|
leashcount:
|
||||||
description: Zeigt die Anzahl der geleinten Tiere an.
|
description: Zeigt die Anzahl der geleinten Tiere an.
|
||||||
usage: /leashcount
|
usage: /<command>
|
||||||
permission: survivalplus.leashcount
|
permission: survivalplus.leashcount
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
splock:
|
splock:
|
||||||
description: Verwaltet das Sperrsystem für Kisten und Türen
|
description: Verwaltet das Sperrsystem für Kisten und Türen
|
||||||
usage: /sp lock|unlock|friendadd|friendremove [Spieler]
|
usage: /<command> lock|unlock|friendadd|friendremove [Spieler]
|
||||||
permission: survivalplus.lock
|
permission: survivalplus.lock
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
tp:
|
tp:
|
||||||
description: Teleportiere dich zu einem Spieler
|
description: Teleportiere dich zu einem Spieler
|
||||||
usage: /tp <Spieler>
|
usage: /<command> <Spieler>
|
||||||
|
permission: survivalplus.tp
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
tphere:
|
tphere:
|
||||||
description: Teleportiere einen Spieler zu dir
|
description: Teleportiere einen Spieler zu dir
|
||||||
usage: /tphere <Spieler>
|
usage: /<command> <Spieler>
|
||||||
|
permission: survivalplus.tphere
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
tpa:
|
tpa:
|
||||||
description: Sende eine Teleportanfrage an einen Spieler
|
description: Sende eine Teleportanfrage an einen Spieler
|
||||||
usage: /tpa <Spieler>
|
usage: /<command> <Spieler>
|
||||||
|
permission: survivalplus.tpa
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
tpaccept:
|
tpaccept:
|
||||||
description: Akzeptiere eine Teleportanfrage
|
description: Akzeptiere eine Teleportanfrage
|
||||||
usage: /tpaccept
|
usage: /<command>
|
||||||
|
permission: survivalplus.tpaccept
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
tpdeny:
|
tpdeny:
|
||||||
description: Lehne eine Teleportanfrage ab
|
description: Lehne eine Teleportanfrage ab
|
||||||
usage: /tpdeny
|
usage: /<command>
|
||||||
|
permission: survivalplus.tpdeny
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
block:
|
block:
|
||||||
description: Blockiere einen Spieler
|
description: Blockiere einen Spieler
|
||||||
usage: /block <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.block
|
permission: survivalplus.block
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
unblock:
|
unblock:
|
||||||
description: Entblocke einen Spieler
|
description: Entblocke einen Spieler
|
||||||
usage: /unblock <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.unlock
|
permission: survivalplus.unblock
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
blocklist:
|
blocklist:
|
||||||
description: Zeige eine Liste der blockierten Spieler
|
description: Zeige eine Liste der blockierten Spieler
|
||||||
usage: /blocklist
|
usage: /<command>
|
||||||
permission: survivalplus.blocklist
|
permission: survivalplus.blocklist
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
kit:
|
kit:
|
||||||
description: Hol dir das Starterkit!
|
description: Hol dir das Starterkit!
|
||||||
usage: /kit
|
usage: /<command>
|
||||||
permission: survivalplus.kit
|
permission: survivalplus.kit
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
nick:
|
nick:
|
||||||
description: Ändert deinen Nicknamen mit Farb- und Hex-Support.
|
description: Ändert deinen Nicknamen mit Farb- und Hex-Support.
|
||||||
usage: /nick <Name>
|
usage: /<command> <Name>
|
||||||
permission: survivalplus.nick
|
permission: survivalplus.nick
|
||||||
permission-message: "§cDu hast keine Berechtigung, deinen Nick zu ändern!"
|
permission-message: "§cDu hast keine Berechtigung, deinen Nick zu ändern!"
|
||||||
|
ride:
|
||||||
|
description: Reite einen Spieler
|
||||||
|
usage: /<command> [spieler]
|
||||||
|
permission: survivalplus.ride
|
||||||
|
permission-message: "§cDu hast keine Berechtigung, Spieler zu reiten!"
|
||||||
lootchests:
|
lootchests:
|
||||||
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
|
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
|
||||||
usage: /lootchests
|
usage: /<command>
|
||||||
permission: survivalplus.lootchests
|
permission: survivalplus.lootchests
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
|
||||||
|
|
||||||
tploot:
|
tploot:
|
||||||
description: Teleportiere dich zu einer Loot-Kiste (nur Admins)
|
description: Teleportiere dich zu einer Loot-Kiste (nur Admins)
|
||||||
usage: /tploot <welt> <x> <y> <z>
|
usage: /<command> <welt> <x> <y> <z>
|
||||||
permission: survivalplus.lootchests
|
permission: survivalplus.lootchests
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
|
||||||
|
|
||||||
day:
|
day:
|
||||||
description: Setzt die Zeit auf Tag
|
description: Setzt die Zeit auf Tag
|
||||||
usage: /day
|
usage: /<command>
|
||||||
permission: survivalplus.day
|
permission: survivalplus.day
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
night:
|
night:
|
||||||
description: Setzt die Zeit auf Nacht
|
description: Setzt die Zeit auf Nacht
|
||||||
usage: /night
|
usage: /<command>
|
||||||
permission: survivalplus.night
|
permission: survivalplus.night
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
trade:
|
trade:
|
||||||
description: Startet einen Handel mit einem Spieler
|
description: Startet einen Handel mit einem Spieler
|
||||||
usage: /trade <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.trade
|
permission: survivalplus.trade
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
tradeaccept:
|
tradeaccept:
|
||||||
description: Akzeptiert eine Handelsanfrage
|
description: Akzeptiert eine Handelsanfrage
|
||||||
usage: /tradeaccept <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.tradeaccept
|
permission: survivalplus.tradeaccept
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
report:
|
report:
|
||||||
description: Meldet einen Spieler an die Admins
|
description: Meldet einen Spieler an die Admins
|
||||||
usage: /report <Spieler> [Grund]
|
usage: /<command> <Spieler> [Grund]
|
||||||
permission: survivalplus.report
|
permission: survivalplus.report
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
showreport:
|
showreport:
|
||||||
description: Zeigt alle Reports eines Spielers an
|
description: Zeigt alle Reports eines Spielers an
|
||||||
usage: /showreport <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.report.show
|
permission: survivalplus.report.show
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
clearreport:
|
clearreport:
|
||||||
description: Löscht alle Reports eines Spielers
|
description: Löscht alle Reports eines Spielers
|
||||||
usage: /clearreport <Spieler>
|
usage: /<command> <Spieler>
|
||||||
permission: survivalplus.report.clear
|
permission: survivalplus.report.clear
|
||||||
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
shop:
|
shop:
|
||||||
description: Verwalten des Server-Shops (z.B. Items hinzufügen)
|
description: Verwalten des Server-Shops (z.B. Items hinzufügen)
|
||||||
usage: /shop add <item> <basispreis> <lagerbestand>
|
usage: /<command> add <item> <basispreis> <lagerbestand>
|
||||||
permission: survivalplus.shop
|
permission: survivalplus.shop
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
spawn:
|
spawn:
|
||||||
description: Teleportiert dich zum Weltspawnpunkt.
|
description: Teleportiert dich zum Weltspawnpunkt.
|
||||||
usage: /spawn
|
usage: /<command>
|
||||||
permission: survivalplus.spawn
|
permission: survivalplus.spawn
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
setwarp:
|
setwarp:
|
||||||
description: Setzt einen persönlichen Warp mit dem Item in der Hand.
|
description: Setzt einen persönlichen Warp mit dem Item in der Hand.
|
||||||
usage: /setwarp <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.setwarp
|
permission: survivalplus.setwarp
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
delwarp:
|
delwarp:
|
||||||
description: Löscht einen persönlichen Warp .
|
description: Löscht einen persönlichen Warp.
|
||||||
usage: /delwarp <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.delwarp
|
permission: survivalplus.delwarp
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
warps:
|
warps:
|
||||||
description: Öffnet die GUI mit allen Spieler-Warps.
|
description: Öffnet die GUI mit allen Spieler-Warps.
|
||||||
usage: /warps
|
usage: /<command>
|
||||||
permission: survivalplus.warps
|
permission: survivalplus.warps
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
startchallenge:
|
startchallenge:
|
||||||
description: Startet eine Fun-Challenge
|
description: Startet eine Fun-Challenge
|
||||||
usage: /startchallenge <name>
|
usage: /<command> <name>
|
||||||
permission: survivalplus.startchallenge
|
permission: survivalplus.startchallenge
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
||||||
|
|
||||||
heal:
|
heal:
|
||||||
description: Heilt einen Spieler vollständig
|
description: Heilt einen Spieler vollständig
|
||||||
usage: /heal [spieler]
|
usage: /<command> [spieler]
|
||||||
permission: survivalplus.heal
|
permission: survivalplus.heal
|
||||||
permission-message: "§cDu hast keine Berechtigung, Spieler zu heilen!"
|
permission-message: "§cDu hast keine Berechtigung, Spieler zu heilen!"
|
||||||
|
|
||||||
survivalplus.notify:
|
claim:
|
||||||
description: Erhält Benachrichtigungen, wenn ein Spieler einen Command- oder Structure-Block besitzt
|
description: Manages claims for anti-griefing
|
||||||
default: op
|
usage: /<command> [unclaim | trust <player> | untrust <player>]
|
||||||
|
aliases: [cl]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
survivalplus.*:
|
survivalplus.*:
|
||||||
description: Gibt Zugriff auf alle SurvivalPlus-Befehle
|
description: Gibt Zugriff auf alle SurvivalPlus-Befehle
|
||||||
default: op
|
default: op
|
||||||
children:
|
children:
|
||||||
|
survivalplus.commandblocker.add: true
|
||||||
|
survivalplus.commandblocker.remove: true
|
||||||
|
survivalplus.commandblocker.list: true
|
||||||
|
survivalplus.commandblocker.bypass: true
|
||||||
survivalplus.gamemode: true
|
survivalplus.gamemode: true
|
||||||
survivalplus.gamemode.others: true
|
survivalplus.gamemode.others: true
|
||||||
survivalplus.sp: true
|
survivalplus.sp: true
|
||||||
@@ -315,194 +313,231 @@ permissions:
|
|||||||
survivalplus.workbench: true
|
survivalplus.workbench: true
|
||||||
survivalplus.anvil: true
|
survivalplus.anvil: true
|
||||||
survivalplus.leashcount: true
|
survivalplus.leashcount: true
|
||||||
|
survivalplus.lock: true
|
||||||
|
survivalplus.tp: true
|
||||||
|
survivalplus.tphere: true
|
||||||
|
survivalplus.tpa: true
|
||||||
|
survivalplus.tpaccept: true
|
||||||
|
survivalplus.tpdeny: true
|
||||||
|
survivalplus.block: true
|
||||||
|
survivalplus.unblock: true
|
||||||
|
survivalplus.blocklist: true
|
||||||
|
survivalplus.kit: true
|
||||||
survivalplus.nick: true
|
survivalplus.nick: true
|
||||||
|
survivalplus.ride: true
|
||||||
|
survivalplus.ride.exempt: true
|
||||||
survivalplus.lootchests: true
|
survivalplus.lootchests: true
|
||||||
|
survivalplus.day: true
|
||||||
|
survivalplus.night: true
|
||||||
|
survivalplus.trade: true
|
||||||
|
survivalplus.tradeaccept: true
|
||||||
|
survivalplus.report: true
|
||||||
|
survivalplus.report.show: true
|
||||||
|
survivalplus.report.clear: true
|
||||||
|
survivalplus.shop: true
|
||||||
|
survivalplus.spawn: true
|
||||||
|
survivalplus.setwarp: true
|
||||||
|
survivalplus.delwarp: true
|
||||||
|
survivalplus.warps: true
|
||||||
survivalplus.startchallenge: true
|
survivalplus.startchallenge: true
|
||||||
survivalplus.heal: true
|
survivalplus.heal: true
|
||||||
survivalplus.heal.others: true
|
survivalplus.heal.others: true
|
||||||
survivalplus.notify: true
|
survivalplus.notify: true
|
||||||
|
survivalplus.chunkanimals: true
|
||||||
survivalplus.lootchests:
|
survivalplus.claim.use: true
|
||||||
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
|
survivalplus.claim.trust: true
|
||||||
|
survivalplus.commandblocker.add:
|
||||||
|
description: Erlaubt das Hinzufügen von Befehlen zur Blockierliste
|
||||||
|
default: op
|
||||||
|
survivalplus.commandblocker.remove:
|
||||||
|
description: Erlaubt das Entfernen von Befehlen aus der Blockierliste
|
||||||
|
default: op
|
||||||
|
survivalplus.commandblocker.list:
|
||||||
|
description: Erlaubt das Anzeigen der Blockierliste
|
||||||
|
default: op
|
||||||
|
survivalplus.commandblocker.bypass:
|
||||||
|
description: Erlaubt das Umgehen blockierter Befehle
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.gamemode:
|
survivalplus.gamemode:
|
||||||
description: Erlaubt das Ändern des eigenen Spielmodus
|
description: Erlaubt das Ändern des eigenen Spielmodus
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.gamemode.others:
|
survivalplus.gamemode.others:
|
||||||
description: Erlaubt das Ändern des Spielmodus anderer Spieler
|
description: Erlaubt das Ändern des Spielmodus anderer Spieler
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.sp:
|
survivalplus.sp:
|
||||||
description: Erlaubt den Zugriff auf den /sp-Befehl
|
description: Erlaubt den Zugriff auf den /sp-Befehl
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.share:
|
survivalplus.share:
|
||||||
description: Erlaubt das Teilen der eigenen Koordinaten mit /sp share
|
description: Erlaubt das Teilen der eigenen Koordinaten mit /sp share
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.homes.set:
|
survivalplus.homes.set:
|
||||||
description: Erlaubt das Setzen von Homes
|
description: Erlaubt das Setzen von Homes
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.homes.delete:
|
survivalplus.homes.delete:
|
||||||
description: Erlaubt das Löschen von Homes
|
description: Erlaubt das Löschen von Homes
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.homes.list:
|
survivalplus.homes.list:
|
||||||
description: Erlaubt das Öffnen der Home-Liste GUI
|
description: Erlaubt das Öffnen der Home-Liste GUI
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.homes:
|
survivalplus.homes:
|
||||||
description: Erlaubt das Teleportieren zu Homes
|
description: Erlaubt das Teleportieren zu Homes
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.homes.unlimited:
|
survivalplus.homes.unlimited:
|
||||||
description: Erlaubt unbegrenzte Homes
|
description: Erlaubt unbegrenzte Homes
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.inventory.own:
|
survivalplus.inventory.own:
|
||||||
description: Erlaubt das Ansehen des eigenen Inventars
|
description: Erlaubt das Ansehen des eigenen Inventars
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.inventory.others:
|
survivalplus.inventory.others:
|
||||||
description: Erlaubt das Ansehen des Inventars anderer Spieler
|
description: Erlaubt das Ansehen des Inventars anderer Spieler
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.enderchest.own:
|
survivalplus.enderchest.own:
|
||||||
description: Erlaubt das Ansehen der eigenen Endertruhe
|
description: Erlaubt das Ansehen der eigenen Endertruhe
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.enderchest.others:
|
survivalplus.enderchest.others:
|
||||||
description: Erlaubt das Ansehen der Endertruhen anderer Spieler
|
description: Erlaubt das Ansehen der Endertruhen anderer Spieler
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.setworldspawn:
|
survivalplus.setworldspawn:
|
||||||
description: Erlaubt das Setzen des Weltspawnpunkts
|
description: Erlaubt das Setzen des Weltspawnpunkts
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.setspawn:
|
survivalplus.setspawn:
|
||||||
description: Erlaubt das Setzen des Server-Spawnpunkts
|
description: Erlaubt das Setzen des Server-Spawnpunkts
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.clearchat:
|
survivalplus.clearchat:
|
||||||
description: Erlaubt das Löschen des Chats
|
description: Erlaubt das Löschen des Chats
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.clearitems:
|
survivalplus.clearitems:
|
||||||
description: Erlaubt das manuelle Löschen der herumliegenden Items
|
description: Erlaubt das manuelle Löschen der herumliegenden Items
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.closedoors:
|
survivalplus.closedoors:
|
||||||
description: Erlaubt das Schließen von Türen mit /closedoors
|
description: Erlaubt das Schließen von Türen mit /closedoors
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.sit:
|
survivalplus.sit:
|
||||||
description: Erlaubt das Sitzen auf Treppen oder mit /sit
|
description: Erlaubt das Sitzen auf Treppen oder mit /sit
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.graves:
|
|
||||||
description: Erlaubt das Erstellen von Gräbern bei Tod
|
|
||||||
default: true
|
|
||||||
|
|
||||||
survivalplus.back:
|
survivalplus.back:
|
||||||
description: Erlaubt das Teleportieren zum letzten Todespunkt
|
description: Erlaubt das Teleportieren zum letzten Todespunkt
|
||||||
default: true
|
default: true
|
||||||
|
survivalplus.graves:
|
||||||
|
description: Erlaubt das Erstellen von Gräbern bei Tod
|
||||||
|
default: true
|
||||||
survivalplus.friend:
|
survivalplus.friend:
|
||||||
description: Erlaubt die Verwaltung der Freundesliste
|
description: Erlaubt die Verwaltung der Freundesliste
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.itemrename:
|
survivalplus.itemrename:
|
||||||
description: Erlaubt das Umbenennen von Items mit /ir
|
description: Erlaubt das Umbenennen von Items mit /ir
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.stats:
|
survivalplus.stats:
|
||||||
description: Erlaubt den Zugriff auf den /stats-Befehl
|
description: Erlaubt den Zugriff auf den /stats-Befehl
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.showarmorstands:
|
survivalplus.showarmorstands:
|
||||||
description: Erlaubt das Sichtbarmachen von Armor Stands mit /showarmorstands
|
description: Erlaubt das Sichtbarmachen von Armor Stands mit /showarmorstands
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.cleardebugarmorstands:
|
survivalplus.cleardebugarmorstands:
|
||||||
description: Erlaubt das Entfernen von Debug-ArmorStands
|
description: Erlaubt das Entfernen von Debug-ArmorStands
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.trash:
|
survivalplus.trash:
|
||||||
description: Erlaubt die Nutzung von /trash
|
description: Erlaubt die Nutzung von /trash
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.workbench:
|
survivalplus.workbench:
|
||||||
description: Erlaubt die Nutzung von /workbench
|
description: Erlaubt die Nutzung von /workbench
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.anvil:
|
survivalplus.anvil:
|
||||||
description: Erlaubt die Nutzung von /anvil
|
description: Erlaubt die Nutzung von /anvil
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.leashcount:
|
survivalplus.leashcount:
|
||||||
description: Erlaubt die Nutzung von /leashcount
|
description: Erlaubt die Nutzung von /leashcount
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.chunkanimals:
|
|
||||||
description: Erlaubt das Anzeigen der Anzahl der Tiere im aktuellen Chunk
|
|
||||||
default: op
|
|
||||||
|
|
||||||
survivalplus.lock:
|
survivalplus.lock:
|
||||||
description: Erlaubt das Verwenden von /lock-Befehlen
|
description: Erlaubt das Verwenden von /lock-Befehlen
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.tp:
|
survivalplus.tp:
|
||||||
description: Erlaube das Teleportieren zu anderen Spielern
|
description: Erlaubt das Teleportieren zu anderen Spielern
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.tphere:
|
survivalplus.tphere:
|
||||||
description: Erlaube das Teleportieren anderer Spieler zu dir
|
description: Erlaubt das Teleportieren anderer Spieler zu dir
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.tpa:
|
survivalplus.tpa:
|
||||||
description: Erlaube das Senden von Teleportanfragen
|
description: Erlaubt das Senden von Teleportanfragen
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.tpaccept:
|
survivalplus.tpaccept:
|
||||||
description: Erlaube das Annehmen von Teleportanfragen
|
description: Erlaubt das Annehmen von Teleportanfragen
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.tpdeny:
|
survivalplus.tpdeny:
|
||||||
description: Erlaube das Ablehnen von Teleportanfragen
|
description: Erlaubt das Ablehnen von Teleportanfragen
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.block:
|
survivalplus.block:
|
||||||
description: Erlaubt das Blockieren anderer Spieler im Chat
|
description: Erlaubt das Blockieren anderer Spieler im Chat
|
||||||
default: true
|
default: true
|
||||||
|
survivalplus.unblock:
|
||||||
survivalplus.info:
|
description: Erlaubt das Entblocken anderer Spieler im Chat
|
||||||
description: Erlaubt den Zugriff auf /sp info
|
default: true
|
||||||
|
survivalplus.blocklist:
|
||||||
|
description: Erlaubt das Anzeigen der blockierten Spieler
|
||||||
|
default: true
|
||||||
|
survivalplus.kit:
|
||||||
|
description: Erlaubt das Abrufen des Starterkits
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.nick:
|
survivalplus.nick:
|
||||||
description: Erlaubt es, den eigenen Nicknamen zu ändern (mit Farben & Hex)
|
description: Erlaubt das Ändern des eigenen Nicknamens (mit Farben & Hex)
|
||||||
|
default: op
|
||||||
|
survivalplus.ride:
|
||||||
|
description: Erlaubt das Reiten von Spielern
|
||||||
|
default: op
|
||||||
|
survivalplus.ride.exempt:
|
||||||
|
description: Spieler mit dieser Permission können nicht geritten werden
|
||||||
|
default: op
|
||||||
|
survivalplus.lootchests:
|
||||||
|
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
|
||||||
|
default: op
|
||||||
|
survivalplus.day:
|
||||||
|
description: Erlaubt das Setzen der Zeit auf Tag
|
||||||
|
default: op
|
||||||
|
survivalplus.night:
|
||||||
|
description: Erlaubt das Setzen der Zeit auf Nacht
|
||||||
|
default: op
|
||||||
|
survivalplus.trade:
|
||||||
|
description: Erlaubt das Starten eines Handels
|
||||||
|
default: true
|
||||||
|
survivalplus.tradeaccept:
|
||||||
|
description: Erlaubt das Akzeptieren eines Handels
|
||||||
|
default: true
|
||||||
|
survivalplus.report:
|
||||||
|
description: Erlaubt das Melden von Spielern
|
||||||
|
default: true
|
||||||
|
survivalplus.report.show:
|
||||||
|
description: Erlaubt das Anzeigen von Spieler-Reports
|
||||||
|
default: op
|
||||||
|
survivalplus.report.clear:
|
||||||
|
description: Erlaubt das Löschen von Spieler-Reports
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.shop:
|
survivalplus.shop:
|
||||||
description: Erlaubt die Nutzung des Shop-Befehls
|
description: Erlaubt die Nutzung des Shop-Befehls
|
||||||
default: op
|
default: op
|
||||||
|
|
||||||
survivalplus.spawn:
|
survivalplus.spawn:
|
||||||
description: Erlaubt die Nutzung des /spawn Befehls
|
description: Erlaubt die Nutzung des /spawn Befehls
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
survivalplus.setwarp:
|
survivalplus.setwarp:
|
||||||
description: Erlaubt das Setzen von persönlichen Warps
|
description: Erlaubt das Setzen von persönlichen Warps
|
||||||
default: true
|
default: true
|
||||||
|
survivalplus.delwarp:
|
||||||
|
description: Erlaubt das Löschen von persönlichen Warps
|
||||||
|
default: true
|
||||||
survivalplus.warps:
|
survivalplus.warps:
|
||||||
description: Erlaubt das Öffnen der Warps-GUI
|
description: Erlaubt das Öffnen der Warps-GUI
|
||||||
default: true
|
default: true
|
||||||
|
survivalplus.startchallenge:
|
||||||
delwarp:
|
description: Erlaubt das Starten von Fun-Challenges
|
||||||
description: Erlaubt das Löschen von persönlichen Warps
|
default: op
|
||||||
default: true
|
survivalplus.heal:
|
||||||
|
description: Erlaubt das Heilen des eigenen Spielers
|
||||||
|
default: op
|
||||||
|
survivalplus.heal.others:
|
||||||
|
description: Erlaubt das Heilen anderer Spieler
|
||||||
|
default: op
|
||||||
|
survivalplus.notify:
|
||||||
|
description: Erhält Benachrichtigungen, wenn ein Spieler einen Command- oder Structure-Block besitzt
|
||||||
|
default: op
|
||||||
|
survivalplus.chunkanimals:
|
||||||
|
description: Erlaubt das Anzeigen der Anzahl der Tiere im aktuellen Chunk
|
||||||
|
default: op
|
||||||
Reference in New Issue
Block a user