Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 652372e191 | |||
| 2c8eb8fb70 | |||
| bff9b78408 | |||
| 5f8e0d3c05 | |||
| 201d1855fc | |||
| e19de4b638 | |||
| 90d66b6e96 | |||
| 11576ef695 | |||
| dd8ae45000 | |||
| adeeb88ca5 | |||
| ba7647c732 | |||
| be191df87e | |||
| a884822115 | |||
| 95052e9da4 | |||
| fe7b0fed4b | |||
| 710f8cf4f5 | |||
| 67b06252cb | |||
| 4e8705ba8e | |||
| 4325d54e18 | |||
| 1e083c26b9 | |||
| 5ca80669cf | |||
| 68bc2dd0fa |
65
README.md
65
README.md
@@ -5,6 +5,7 @@
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -14,25 +15,25 @@
|
|||||||
* **📱 Smart-GUI Interface:** Ein Rechtsklick auf das Modul öffnet ein elegantes Menü zur Direktauswahl aller Etagen im Schacht.
|
* **📱 Smart-GUI Interface:** Ein Rechtsklick auf das Modul öffnet ein elegantes Menü zur Direktauswahl aller Etagen im Schacht.
|
||||||
* **💎 Dynamische Hologramme:** Nutzt moderne **Text-Displays** zur Anzeige der Etagen-Namen direkt über dem Modul (ressourcenschonend).
|
* **💎 Dynamische Hologramme:** Nutzt moderne **Text-Displays** zur Anzeige der Etagen-Namen direkt über dem Modul (ressourcenschonend).
|
||||||
* **🔒 Privatsphäre-System:** Schalte Etagen per Befehl zwischen `Public` (öffentlich) und `Private` (nur Besitzer) um.
|
* **🔒 Privatsphäre-System:** Schalte Etagen per Befehl zwischen `Public` (öffentlich) und `Private` (nur Besitzer) um.
|
||||||
|
* **🛠 Voll anpassbares Rezept:** Erstelle dein eigenes Crafting-Layout inklusive frei wählbarer Materialien direkt in der Config.
|
||||||
* **🎨 Customizing:** Volle Unterstützung von **Farbcodes & Hex-Farben** für individuelle Etagennamen.
|
* **🎨 Customizing:** Volle Unterstützung von **Farbcodes & Hex-Farben** für individuelle Etagennamen.
|
||||||
* **🛡️ Grief-Schutz:** Nur Besitzer oder Admins können Module konfigurieren oder entfernen.
|
* **🛡️ Grief-Schutz:** Nur Besitzer oder Admins können Module konfigurieren oder entfernen.
|
||||||
* **📝 Auto-Schilder:** Erstelle stylische Anzeigen automatisch mit `[Elevator]` in der ersten Zeile eines Schildes.
|
* **🔔 Ingame Update-Check:** Admins erhalten beim Joinen eine interaktive Meldung mit direktem Download-Link, sobald eine neue Version auf Git verfügbar ist.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠 Crafting-Rezept
|
## 🛠 Crafting-System
|
||||||
|
|
||||||
Das **Premium Aufzug-Modul** kann an jeder Werkbank mit folgendem Rezept hergestellt werden:
|
Dank des neuen dynamischen Rezept-Systems kannst du das **Aufzug-Modul** in der `config.yml` völlig frei gestalten. Standardmäßig ist folgendes Layout vorkonfiguriert:
|
||||||
|
|
||||||
| Slot | Material |
|
| Slot | Position | Standard-Material |
|
||||||
| :--- | :--- |
|
|:-----|:---------|:------------------|
|
||||||
| **Oben Links** | Tageslichtsensor |
|
| **1, 3, 7, 9** | Ecken | Eisenbarren |
|
||||||
| **Oben Rechts** | Tageslichtsensor |
|
| **2, 4, 6, 8** | Seiten | Enderperle |
|
||||||
| **Mitte** | Eisenblock |
|
| **5** | Mitte | Tageslichtsensor |
|
||||||
| **Unten Links** | Tageslichtsensor |
|
|
||||||
| **Unten Rechts** | Tageslichtsensor |
|
|
||||||
|
|
||||||
**Ergebnis:** `1x Aufzug-Modul`
|
> **Hinweis:** Das Gitter (Shape) und die Zutaten (Ingredients) können jederzeit ohne Code-Änderungen in der Konfiguration angepasst werden.
|
||||||
|
> **Material-Liste:** Alle verfügbaren Materialien findest du in der [Spigot Material Documentation](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ Das **Premium Aufzug-Modul** kann an jeder Werkbank mit folgendem Rezept hergest
|
|||||||
### Befehle
|
### Befehle
|
||||||
|
|
||||||
| Befehl | Beschreibung | Berechtigung |
|
| Befehl | Beschreibung | Berechtigung |
|
||||||
| :--- | :--- | :--- |
|
|:-------|:-------------|:-------------|
|
||||||
| `/elevator name <Text>` | Ändert den Namen der aktuellen Etage. | `elevator.use` |
|
| `/elevator name <Text>` | Ändert den Namen der aktuellen Etage. | `elevator.use` |
|
||||||
| `/elevator private` | Setzt die Etage auf **Privat**. | `elevator.use` |
|
| `/elevator private` | Setzt die Etage auf **Privat**. | `elevator.use` |
|
||||||
| `/elevator public` | Setzt die Etage auf **Öffentlich**. | `elevator.use` |
|
| `/elevator public` | Setzt die Etage auf **Öffentlich**. | `elevator.use` |
|
||||||
@@ -49,40 +50,50 @@ Das **Premium Aufzug-Modul** kann an jeder Werkbank mit folgendem Rezept hergest
|
|||||||
### Administration
|
### Administration
|
||||||
|
|
||||||
| Berechtigung | Beschreibung |
|
| Berechtigung | Beschreibung |
|
||||||
| :--- | :--- |
|
|:-------------|:-------------|
|
||||||
| `elevator.admin` | Verwalten & Abbauen fremder Aufzüge sowie Bypass von Private-Sperren. |
|
| `elevator.admin` | Verwalten & Abbauen fremder Aufzüge sowie Erhalt von Update-Benachrichtigungen. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙️ Konfiguration (Auszug)
|
## ⚙️ Konfiguration (Auszug)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
settings:
|
# Dynamisches Rezept-Beispiel
|
||||||
max-distance: 64 # Maximale Distanz zwischen Modulen
|
recipe:
|
||||||
cooldown: 500 # Cooldown in ms zwischen Teleports
|
shape:
|
||||||
|
- "ABA"
|
||||||
|
- "BCB"
|
||||||
|
- "ABA"
|
||||||
|
ingredients:
|
||||||
|
A: "IRON_INGOT"
|
||||||
|
B: "ENDER_PEARL"
|
||||||
|
C: "DAYLIGHT_DETECTOR"
|
||||||
|
|
||||||
|
# Visuelle Einstellungen
|
||||||
visuals:
|
visuals:
|
||||||
enable-particles: true
|
enable-particles: true
|
||||||
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
|
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
|
||||||
hologram-scale: 1.5
|
hologram-scale: 1.5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🏗 Installation
|
## 🏗 Installation
|
||||||
|
|
||||||
1. **Download:** Lade die `Elevator.jar` herunter.
|
1. **Download**: Lade die neueste `Elevator.jar` von unserem Repository herunter.
|
||||||
2. **Upload:** Verschiebe die Datei in deinen `/plugins` Ordner.
|
2. **Upload**: Verschiebe die Datei in deinen `/plugins` Ordner.
|
||||||
3. **Start:** Starte deinen Server neu, damit das Plugin geladen wird.
|
3. **Start**: Starte deinen Server neu, damit das Plugin geladen wird.
|
||||||
4. **Setup:** Passe die `config.yml` im Ordner `/plugins/Elevator/` nach deinen Wünschen an und lade das Plugin ggf. neu.
|
4. **Setup**: Passe die `config.yml` im Ordner `/plugins/Elevator/` nach deinen Wünschen an.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 👤 Autor & Support
|
## 👤 Autor & Support
|
||||||
|
|
||||||
**Erstellt von: M_Viper**
|
**Erstellt von:** M_Viper
|
||||||
|
|
||||||
💡 Entwickelt mit Fokus auf **Performance**, **Design** und **maximalen Bedienkomfort**. Bei Fragen, Fehlern oder Verbesserungsvorschlägen tritt gerne unserem Discord bei:
|
💡 Entwickelt mit Fokus auf Performance, Design und maximalen Bedienkomfort. Bei Fragen, Fehlern oder Verbesserungsvorschlägen tritt gerne unserem Discord bei.
|
||||||
|
|
||||||
[](https://discord.com/invite/FdRs4BRd8D)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
*Viper Plugins © 2026 — Effiziente Systemlösungen für deinen Server.*
|
|
||||||
|
**Copyright © 2026 - M_Viper - Alle Rechte vorbehalten**
|
||||||
|
|
||||||
|
Die unbefugte Vervielfältigung, Verbreitung oder Weitergabe dieses Plugins ist strafbar und wird rechtlich verfolgt.
|
||||||
104
pom.xml
104
pom.xml
@@ -1,53 +1,53 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" 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.mviper</groupId>
|
<groupId>de.mviper</groupId>
|
||||||
<artifactId>Elevator</artifactId>
|
<artifactId>Elevator</artifactId>
|
||||||
<version>1.0-RELEASE</version>
|
<version>1.8</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<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>
|
<repository>
|
||||||
<id>minecraft-libraries</id>
|
<id>minecraft-libraries</id>
|
||||||
<url>https://libraries.minecraft.net/</url>
|
<url>https://libraries.minecraft.net/</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
<version>1.20.1-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mojang</groupId>
|
<groupId>com.mojang</groupId>
|
||||||
<artifactId>authlib</artifactId>
|
<artifactId>authlib</artifactId>
|
||||||
<version>3.11.50</version> <scope>provided</scope>
|
<version>3.11.50</version> <scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.13.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>17</source>
|
<source>17</source>
|
||||||
<target>17</target>
|
<target>17</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,49 +1,283 @@
|
|||||||
package de.mviper.elevator;
|
package de.mviper.elevator;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class DatabaseManager {
|
public class DatabaseManager {
|
||||||
|
|
||||||
|
// Maximaler Radius (in Blöcken, horizontal, gleiche Y-Ebene) für Auto-Gruppierung
|
||||||
|
private static final int GROUP_SCAN_RADIUS = 4;
|
||||||
|
|
||||||
private File localFile;
|
private File localFile;
|
||||||
private FileConfiguration localConfig;
|
private FileConfiguration localConfig;
|
||||||
|
|
||||||
public DatabaseManager() { setupLocalFile(); }
|
public DatabaseManager() {
|
||||||
|
setupLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
private void setupLocalFile() {
|
private void setupLocalFile() {
|
||||||
localFile = new File(Elevator.getInstance().getDataFolder(), "elevators.yml");
|
localFile = new File(Elevator.getInstance().getDataFolder(), "elevators.yml");
|
||||||
if (!localFile.exists()) {
|
if (!localFile.exists()) {
|
||||||
try {
|
try {
|
||||||
Elevator.getInstance().getDataFolder().mkdirs();
|
Elevator.getInstance().getDataFolder().mkdirs();
|
||||||
localFile.createNewFile();
|
localFile.createNewFile();
|
||||||
} catch (IOException e) { e.printStackTrace(); }
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localConfig = YamlConfiguration.loadConfiguration(localFile);
|
localConfig = YamlConfiguration.loadConfiguration(localFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Basis-Operationen
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
public void addElevator(Location loc, UUID owner) {
|
public void addElevator(Location loc, UUID owner) {
|
||||||
String key = locToKey(loc);
|
String key = locToKey(loc);
|
||||||
localConfig.set(key + ".owner", owner.toString());
|
localConfig.set(key + ".owner", owner.toString());
|
||||||
localConfig.set(key + ".name", "Etage");
|
|
||||||
localConfig.set(key + ".public", true);
|
localConfig.set(key + ".public", true);
|
||||||
saveLocal();
|
saveLocal();
|
||||||
|
|
||||||
|
// Gruppe sofort zuweisen (Auto-Detect angrenzender Module)
|
||||||
|
getOrAssignGroupId(loc);
|
||||||
|
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info(
|
||||||
|
"Aufzug registriert: " + key + " | Gruppe: " + getGroupId(loc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeElevator(Location loc) {
|
||||||
|
String key = locToKey(loc);
|
||||||
|
String groupId = localConfig.getString(key + ".group");
|
||||||
|
|
||||||
|
localConfig.set(key, null);
|
||||||
|
saveLocal();
|
||||||
|
|
||||||
|
// Gruppe aufräumen, wenn keine Mitglieder mehr
|
||||||
|
if (groupId != null && getMembersOfGroup(groupId).isEmpty()) {
|
||||||
|
localConfig.set("groups." + groupId, null);
|
||||||
|
saveLocal();
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info("Gruppe " + groupId + " gelöscht (keine Mitglieder mehr).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isElevator(Location loc) {
|
||||||
|
return localConfig.contains(locToKey(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Gruppen-System
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Gruppen-ID für ein Modul zurück.
|
||||||
|
* Existiert noch keine, wird automatisch eine erstellt oder eine benachbarte übernommen.
|
||||||
|
*/
|
||||||
|
public String getOrAssignGroupId(Location loc) {
|
||||||
|
String key = locToKey(loc);
|
||||||
|
|
||||||
|
// Existiert kein gültiger Aufzug → null
|
||||||
|
if (!localConfig.contains(key)) return null;
|
||||||
|
|
||||||
|
// Gruppe schon gesetzt?
|
||||||
|
if (localConfig.contains(key + ".group")) {
|
||||||
|
return localConfig.getString(key + ".group");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migration: ältere Einträge haben .name direkt gespeichert
|
||||||
|
String oldName = localConfig.getString(key + ".name", null);
|
||||||
|
|
||||||
|
// Benachbartes Modul mit Gruppe suchen (gleiche Y-Ebene)
|
||||||
|
String foundGroup = findAdjacentGroupId(loc);
|
||||||
|
if (foundGroup != null) {
|
||||||
|
localConfig.set(key + ".group", foundGroup);
|
||||||
|
// Alten Namen übernehmen, falls Gruppe noch Default-Name hat
|
||||||
|
if (oldName != null && !oldName.equals("Etage")
|
||||||
|
&& "Etage".equals(localConfig.getString("groups." + foundGroup + ".name", "Etage"))) {
|
||||||
|
localConfig.set("groups." + foundGroup + ".name", oldName);
|
||||||
|
}
|
||||||
|
localConfig.set(key + ".name", null); // Altes Feld entfernen
|
||||||
|
saveLocal();
|
||||||
|
return foundGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neue Gruppe erstellen
|
||||||
|
String newGroupId = UUID.randomUUID().toString().substring(0, 8);
|
||||||
|
String groupName = (oldName != null && !oldName.isEmpty()) ? oldName : "Etage";
|
||||||
|
localConfig.set(key + ".group", newGroupId);
|
||||||
|
localConfig.set("groups." + newGroupId + ".name", groupName);
|
||||||
|
localConfig.set(key + ".name", null); // Altes Feld entfernen
|
||||||
|
saveLocal();
|
||||||
|
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info("Neue Gruppe erstellt: " + newGroupId + " | Name: " + groupName);
|
||||||
|
}
|
||||||
|
return newGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gibt die Gruppen-ID eines Moduls zurück (mit Lazy-Init). */
|
||||||
|
public String getGroupId(Location loc) {
|
||||||
|
return getOrAssignGroupId(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weist einem Modul manuell eine Gruppen-ID zu.
|
||||||
|
* Wird vom /elevator group link Befehl genutzt.
|
||||||
|
*/
|
||||||
|
public void setGroupId(Location loc, String groupId) {
|
||||||
|
String key = locToKey(loc);
|
||||||
|
if (!localConfig.contains(key)) return;
|
||||||
|
|
||||||
|
localConfig.set(key + ".group", groupId);
|
||||||
|
// Gruppe anlegen, falls noch nicht vorhanden
|
||||||
|
if (!localConfig.contains("groups." + groupId + ".name")) {
|
||||||
|
localConfig.set("groups." + groupId + ".name", "Etage");
|
||||||
|
}
|
||||||
|
saveLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeElevator(Location loc) { localConfig.set(locToKey(loc), null); saveLocal(); }
|
/** Gibt den Anzeige-Namen der Gruppe zurück. */
|
||||||
public boolean isElevator(Location loc) { return localConfig.contains(locToKey(loc)); }
|
public String getGroupName(String groupId) {
|
||||||
public String getFloorCustomName(Location loc) { return localConfig.getString(locToKey(loc) + ".name", "Etage"); }
|
return localConfig.getString("groups." + groupId + ".name", "Etage");
|
||||||
public void setFloorName(Location loc, String name) { localConfig.set(locToKey(loc) + ".name", name); saveLocal(); }
|
}
|
||||||
|
|
||||||
public UUID getOwner(Location loc) {
|
/** Setzt den Anzeige-Namen für eine Gruppe (benennt damit alle Mitglieder). */
|
||||||
String s = localConfig.getString(locToKey(loc) + ".owner");
|
public void setGroupNameById(String groupId, String name) {
|
||||||
return s != null ? UUID.fromString(s) : UUID.randomUUID();
|
localConfig.set("groups." + groupId + ".name", name);
|
||||||
|
saveLocal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Alle Modul-Schlüssel (ohne "data." Prefix), die zur Gruppe gehören. */
|
||||||
|
public List<String> getMembersOfGroup(String groupId) {
|
||||||
|
List<String> members = new ArrayList<>();
|
||||||
|
ConfigurationSection data = localConfig.getConfigurationSection("data");
|
||||||
|
if (data == null) return members;
|
||||||
|
for (String locKey : data.getKeys(false)) {
|
||||||
|
if (groupId.equals(data.getString(locKey + ".group"))) {
|
||||||
|
members.add(locKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scannt benachbarte Module (horizontal, gleiche Y-Höhe) auf vorhandene Gruppen-IDs. */
|
||||||
|
private String findAdjacentGroupId(Location loc) {
|
||||||
|
for (int dx = -GROUP_SCAN_RADIUS; dx <= GROUP_SCAN_RADIUS; dx++) {
|
||||||
|
for (int dz = -GROUP_SCAN_RADIUS; dz <= GROUP_SCAN_RADIUS; dz++) {
|
||||||
|
if (dx == 0 && dz == 0) continue;
|
||||||
|
Location adj = loc.clone().add(dx, 0, dz);
|
||||||
|
String adjKey = locToKey(adj);
|
||||||
|
if (localConfig.contains(adjKey) && localConfig.contains(adjKey + ".group")) {
|
||||||
|
return localConfig.getString(adjKey + ".group");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Namen (jetzt Gruppen-basiert)
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Gibt den Etagen-Namen zurück — immer aus der Gruppe. */
|
||||||
|
public String getFloorCustomName(Location loc) {
|
||||||
|
String groupId = getGroupId(loc);
|
||||||
|
if (groupId == null) return "Etage";
|
||||||
|
return getGroupName(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Setzt den Etagen-Namen für die gesamte Gruppe dieses Moduls. */
|
||||||
|
public void setFloorName(Location loc, String name) {
|
||||||
|
String groupId = getGroupId(loc);
|
||||||
|
if (groupId == null) return;
|
||||||
|
setGroupNameById(groupId, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Besitzer & Sichtbarkeit
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
public UUID getOwner(Location loc) {
|
||||||
|
String s = localConfig.getString(locToKey(loc) + ".owner");
|
||||||
|
return s != null ? UUID.fromString(s) : UUID.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic(Location loc) {
|
||||||
|
String key = locToKey(loc);
|
||||||
|
String fullKey = key + ".public";
|
||||||
|
|
||||||
|
if (!localConfig.contains(key)) {
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().warning("isPublic: Aufzug existiert nicht: " + key);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!localConfig.contains(fullKey)) {
|
||||||
|
localConfig.set(fullKey, true);
|
||||||
|
saveLocal();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean value = localConfig.getBoolean(fullKey, true);
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info("isPublic: " + fullKey + " = " + value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPublic(Location loc, boolean status) {
|
||||||
|
String key = locToKey(loc);
|
||||||
|
String fullKey = key + ".public";
|
||||||
|
|
||||||
|
if (!localConfig.contains(key)) {
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().warning("setPublic: Aufzug existiert nicht: " + key);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
localConfig.set(fullKey, status);
|
||||||
|
saveLocal();
|
||||||
|
|
||||||
|
// Neu laden und verifizieren
|
||||||
|
localConfig = YamlConfiguration.loadConfiguration(localFile);
|
||||||
|
boolean verification = localConfig.getBoolean(fullKey, true);
|
||||||
|
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info(
|
||||||
|
"setPublic: " + fullKey + " auf " + status + " gesetzt (Verifiziert: " + verification + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Hilfsmethoden
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
private String locToKey(Location l) {
|
||||||
|
return "data." + l.getWorld().getName()
|
||||||
|
+ "_" + l.getBlockX()
|
||||||
|
+ "_" + l.getBlockY()
|
||||||
|
+ "_" + l.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveLocal() {
|
||||||
|
try {
|
||||||
|
localConfig.save(localFile);
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info("Datenbank gespeichert: " + localFile.getName());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPublic(Location loc) { return localConfig.getBoolean(locToKey(loc) + ".public", true); }
|
|
||||||
public void setPublic(Location loc, boolean status) { localConfig.set(locToKey(loc) + ".public", status); saveLocal(); }
|
|
||||||
private String locToKey(Location l) { return "data." + l.getWorld().getName() + "_" + l.getBlockX() + "_" + l.getBlockY() + "_" + l.getBlockZ(); }
|
|
||||||
private void saveLocal() { try { localConfig.save(localFile); } catch (IOException e) { e.printStackTrace(); } }
|
|
||||||
}
|
}
|
||||||
@@ -1,51 +1,176 @@
|
|||||||
package de.mviper.elevator;
|
package de.mviper.elevator;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.inventory.ItemFlag;
|
import org.bukkit.inventory.ItemFlag;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.ShapedRecipe;
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class Elevator extends JavaPlugin {
|
public class Elevator extends JavaPlugin implements Listener {
|
||||||
private static Elevator instance;
|
private static Elevator instance;
|
||||||
private DatabaseManager databaseManager;
|
private DatabaseManager databaseManager;
|
||||||
private HologramManager hologramManager;
|
private HologramManager hologramManager;
|
||||||
|
private String latestVersionFound;
|
||||||
|
private boolean debugMode;
|
||||||
|
|
||||||
|
private final int RESOURCE_ID = 132220;
|
||||||
|
private final String releaseUrl = "https://www.spigotmc.org/resources/" + RESOURCE_ID;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
|
// Debug-Modus aus config laden
|
||||||
|
this.debugMode = getConfig().getBoolean("settings.debug", false);
|
||||||
this.databaseManager = new DatabaseManager();
|
this.databaseManager = new DatabaseManager();
|
||||||
this.hologramManager = new HologramManager();
|
this.hologramManager = new HologramManager();
|
||||||
hologramManager.purgeAllHolograms();
|
hologramManager.purgeAllHolograms();
|
||||||
|
|
||||||
|
// Events & Commands registrieren
|
||||||
getServer().getPluginManager().registerEvents(new ElevatorListener(), this);
|
getServer().getPluginManager().registerEvents(new ElevatorListener(), this);
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
getCommand("elevator").setExecutor(new ElevatorCommand());
|
getCommand("elevator").setExecutor(new ElevatorCommand());
|
||||||
|
getCommand("elevator").setTabCompleter(new ElevatorTabCompleter());
|
||||||
|
|
||||||
|
// Rezept laden
|
||||||
registerElevatorRecipe();
|
registerElevatorRecipe();
|
||||||
|
|
||||||
|
// Update Check starten (Offizielle Spigot API)
|
||||||
|
checkForUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkForUpdates() {
|
||||||
|
new UpdateChecker(this, RESOURCE_ID).getLatestVersion(version -> {
|
||||||
|
this.latestVersionFound = version;
|
||||||
|
String currentVersion = this.getDescription().getVersion();
|
||||||
|
|
||||||
|
if (!currentVersion.equalsIgnoreCase(version)) {
|
||||||
|
getLogger().info("====================================================");
|
||||||
|
getLogger().info("NEUES UPDATE VERFÜGBAR: v" + version);
|
||||||
|
getLogger().info("Download: " + releaseUrl);
|
||||||
|
getLogger().info("====================================================");
|
||||||
|
} else {
|
||||||
|
getLogger().info("Plugin ist auf dem neuesten Stand (v" + currentVersion + ").");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (player.hasPermission("elevator.admin") || player.isOp()) {
|
||||||
|
if (latestVersionFound != null && !this.getDescription().getVersion().equalsIgnoreCase(latestVersionFound)) {
|
||||||
|
|
||||||
|
player.sendMessage(" ");
|
||||||
|
player.sendMessage("§b§l[Elevator] §eEine neue Version (§b" + latestVersionFound + "§e) ist verfügbar!");
|
||||||
|
|
||||||
|
TextComponent message = new TextComponent("§eDownload: ");
|
||||||
|
TextComponent link = new TextComponent("§6§l[KLICK HIER FÜR UPDATE]");
|
||||||
|
link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, releaseUrl));
|
||||||
|
link.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("§7Öffnet die SpigotMC-Seite")));
|
||||||
|
|
||||||
|
message.addExtra(link);
|
||||||
|
player.spigot().sendMessage(message);
|
||||||
|
player.sendMessage(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerElevatorRecipe() {
|
private void registerElevatorRecipe() {
|
||||||
ItemStack item = new ItemStack(Material.DAYLIGHT_DETECTOR);
|
ItemStack item = createElevatorModuleItem();
|
||||||
ItemMeta meta = item.getItemMeta();
|
|
||||||
if (meta != null) {
|
NamespacedKey key = new NamespacedKey(this, "elevator_module");
|
||||||
meta.setDisplayName("§b§lAufzug-Modul");
|
ShapedRecipe recipe = new ShapedRecipe(key, item);
|
||||||
meta.setLore(Arrays.asList("§7Platziere dies als Etage.", "§eRechtsklick: §fMenü öffnen", "§eSpringen/Sneaken: §fReisen"));
|
|
||||||
meta.addEnchant(Enchantment.LUCK, 1, true);
|
List<String> shapeLines = getConfig().getStringList("recipe.shape");
|
||||||
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
if (shapeLines.size() != 3) {
|
||||||
item.setItemMeta(meta);
|
getLogger().severe("Rezept konnte nicht geladen werden: 'shape' benötigt genau 3 Zeilen!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] cleanedRows = new String[3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
String line = shapeLines.get(i).replace(" ", "");
|
||||||
|
while (line.length() < 3) {
|
||||||
|
line += " ";
|
||||||
|
}
|
||||||
|
if (line.length() > 3) {
|
||||||
|
line = line.substring(0, 3);
|
||||||
|
}
|
||||||
|
cleanedRows[i] = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
recipe.shape(cleanedRows[0], cleanedRows[1], cleanedRows[2]);
|
||||||
|
|
||||||
|
ConfigurationSection section = getConfig().getConfigurationSection("recipe.ingredients");
|
||||||
|
if (section == null) {
|
||||||
|
getLogger().severe("Keine 'recipe.ingredients' in der Config gefunden!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String row : cleanedRows) {
|
||||||
|
for (char c : row.toCharArray()) {
|
||||||
|
if (c == ' ') continue;
|
||||||
|
|
||||||
|
String matName = section.getString(String.valueOf(c));
|
||||||
|
if (matName != null) {
|
||||||
|
Material mat = Material.matchMaterial(matName.toUpperCase());
|
||||||
|
if (mat != null) {
|
||||||
|
recipe.setIngredient(c, mat);
|
||||||
|
} else {
|
||||||
|
getLogger().warning("Ungültiges Material '" + matName + "' für Symbol '" + c + "'!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getLogger().warning("Symbol '" + c + "' im Shape hat keine Zuweisung in ingredients!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
getServer().removeRecipe(key);
|
||||||
|
getServer().addRecipe(recipe);
|
||||||
|
getLogger().info("Elevator: Crafting-Rezept erfolgreich registriert.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().log(Level.WARNING, "Fehler beim Rezept-Setup: {0}", e.getMessage());
|
||||||
}
|
}
|
||||||
ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(this, "elevator_module"), item);
|
|
||||||
recipe.shape("S.S", ".I.", "S.S");
|
|
||||||
recipe.setIngredient('S', Material.DAYLIGHT_DETECTOR);
|
|
||||||
recipe.setIngredient('I', Material.IRON_BLOCK);
|
|
||||||
getServer().addRecipe(recipe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Elevator getInstance() { return instance; }
|
public static Elevator getInstance() { return instance; }
|
||||||
public DatabaseManager getDatabaseManager() { return databaseManager; }
|
public DatabaseManager getDatabaseManager() { return databaseManager; }
|
||||||
public HologramManager getHologramManager() { return hologramManager; }
|
public HologramManager getHologramManager() { return hologramManager; }
|
||||||
|
public boolean isDebugMode() { return debugMode; }
|
||||||
|
|
||||||
|
public ItemStack createElevatorModuleItem() {
|
||||||
|
ItemStack item = new ItemStack(Material.DAYLIGHT_DETECTOR);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
meta.setDisplayName("§b§lAufzug-Modul");
|
||||||
|
meta.setLore(Arrays.asList(
|
||||||
|
"§7Platziere dies als Etage.",
|
||||||
|
"§eRechtsklick: §fMenü öffnen",
|
||||||
|
"§eSpringen/Sneaken: §fReisen"
|
||||||
|
));
|
||||||
|
meta.addEnchant(Enchantment.LUCK, 1, true);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,8 @@ import org.bukkit.command.CommandExecutor;
|
|||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ElevatorCommand implements CommandExecutor {
|
public class ElevatorCommand implements CommandExecutor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -17,67 +19,190 @@ public class ElevatorCommand implements CommandExecutor {
|
|||||||
Player p = (Player) sender;
|
Player p = (Player) sender;
|
||||||
|
|
||||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
Block moduleBlock = null;
|
Block moduleBlock = findNearbyModule(p, db);
|
||||||
|
|
||||||
// GROBE ERKENNUNG:
|
|
||||||
// Wir prüfen einen kleinen Radius (0.5 Blöcke) um den Spieler und 1.2 Blöcke nach unten.
|
|
||||||
// Das stellt sicher, dass man nicht pixelgenau in der Mitte stehen muss.
|
|
||||||
Location pLoc = p.getLocation();
|
|
||||||
|
|
||||||
outerLoop:
|
|
||||||
for (double x = -0.5; x <= 0.5; x += 0.5) {
|
|
||||||
for (double z = -0.5; z <= 0.5; z += 0.5) {
|
|
||||||
for (double y = -1.2; y <= 0.2; y += 0.4) {
|
|
||||||
Block check = pLoc.clone().add(x, y, z).getBlock();
|
|
||||||
if (check.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(check.getLocation())) {
|
|
||||||
moduleBlock = check;
|
|
||||||
break outerLoop; // Modul gefunden, Suche beenden
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleBlock == null) {
|
if (moduleBlock == null) {
|
||||||
p.sendMessage("§8[§bElevator§8] §cKein Aufzug-Modul in deiner Nähe gefunden!");
|
p.sendMessage("§8[§bElevator§8] §cKein Aufzug-Modul in deiner Nähe gefunden!");
|
||||||
|
p.sendMessage("§7Tipp: Stelle dich direkt auf das Daylight-Detector Modul.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Berechtigungs-Check (Besitzer oder Admin)
|
Location modLoc = moduleBlock.getLocation();
|
||||||
if (!db.getOwner(moduleBlock.getLocation()).equals(p.getUniqueId()) && !p.hasPermission("elevator.admin")) {
|
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info(
|
||||||
|
"Command: Modul gefunden bei X:" + modLoc.getBlockX()
|
||||||
|
+ " Y:" + modLoc.getBlockY()
|
||||||
|
+ " Z:" + modLoc.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Besitzer-Check (Besitzer oder Admin)
|
||||||
|
if (!db.getOwner(modLoc).equals(p.getUniqueId()) && !p.hasPermission("elevator.admin")) {
|
||||||
p.sendMessage("§8[§bElevator§8] §cDies ist nicht dein Aufzug!");
|
p.sendMessage("§8[§bElevator§8] §cDies ist nicht dein Aufzug!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Befehl: /elevator name <Text>
|
// ── /elevator name <Text> ──────────────────────────────────────────
|
||||||
if (args.length >= 2 && args[0].equalsIgnoreCase("name")) {
|
if (args.length >= 2 && args[0].equalsIgnoreCase("name")) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 1; i < args.length; i++) sb.append(args[i]).append(" ");
|
for (int i = 1; i < args.length; i++) sb.append(args[i]).append(" ");
|
||||||
String newName = ChatColor.translateAlternateColorCodes('&', sb.toString().trim());
|
String newName = ChatColor.translateAlternateColorCodes('&', sb.toString().trim());
|
||||||
|
|
||||||
db.setFloorName(moduleBlock.getLocation(), newName);
|
db.setFloorName(modLoc, newName);
|
||||||
p.sendMessage("§8[§bElevator§8] §aEtage benannt: " + newName);
|
|
||||||
|
String groupId = db.getGroupId(modLoc);
|
||||||
|
List<String> members = db.getMembersOfGroup(groupId);
|
||||||
|
|
||||||
|
p.sendMessage("§8[§bElevator§8] §aEtage benannt: §f" + newName);
|
||||||
|
if (members.size() > 1) {
|
||||||
|
p.sendMessage("§7(Name für §e" + members.size() + " §7verknüpfte Module gesetzt)");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Befehle: /elevator private | public
|
// ── /elevator group ────────────────────────────────────────────────
|
||||||
if (args.length == 1) {
|
if (args.length >= 1 && args[0].equalsIgnoreCase("group")) {
|
||||||
if (args[0].equalsIgnoreCase("private")) {
|
|
||||||
db.setPublic(moduleBlock.getLocation(), false);
|
// /elevator group info
|
||||||
p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat");
|
if (args.length == 1 || args[1].equalsIgnoreCase("info")) {
|
||||||
|
String groupId = db.getGroupId(modLoc);
|
||||||
|
List<String> members = db.getMembersOfGroup(groupId);
|
||||||
|
p.sendMessage("§b--- Gruppen-Info ---");
|
||||||
|
p.sendMessage("§7Gruppen-ID: §e" + groupId);
|
||||||
|
p.sendMessage("§7Gruppen-Name: §f" + db.getGroupName(groupId));
|
||||||
|
p.sendMessage("§7Module in Gruppe: §e" + members.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (args[0].equalsIgnoreCase("public")) {
|
|
||||||
db.setPublic(moduleBlock.getLocation(), true);
|
// /elevator group scan
|
||||||
p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich");
|
// Scannt benachbarte Module neu und verknüpft sie in eine Gruppe
|
||||||
|
if (args[1].equalsIgnoreCase("scan")) {
|
||||||
|
String myGroup = db.getGroupId(modLoc);
|
||||||
|
int linked = 0;
|
||||||
|
|
||||||
|
// Radius 4 horizontal, gleiche Y-Ebene
|
||||||
|
for (int dx = -4; dx <= 4; dx++) {
|
||||||
|
for (int dz = -4; dz <= 4; dz++) {
|
||||||
|
if (dx == 0 && dz == 0) continue;
|
||||||
|
Location adj = modLoc.clone().add(dx, 0, dz);
|
||||||
|
if (db.isElevator(adj)) {
|
||||||
|
String adjGroup = db.getGroupId(adj);
|
||||||
|
if (!adjGroup.equals(myGroup)) {
|
||||||
|
db.setGroupId(adj, myGroup);
|
||||||
|
linked++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sendMessage("§8[§bElevator§8] §aScan abgeschlossen.");
|
||||||
|
p.sendMessage("§7" + linked + " Modul(e) mit dieser Gruppe verknüpft.");
|
||||||
|
p.sendMessage("§7Gruppe §e" + myGroup + "§7 hat jetzt §e"
|
||||||
|
+ db.getMembersOfGroup(myGroup).size() + "§7 Mitglieder.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /elevator group unlink
|
||||||
|
// Trennt dieses Modul aus der Gruppe heraus (eigene Gruppe)
|
||||||
|
if (args[1].equalsIgnoreCase("unlink")) {
|
||||||
|
String oldGroup = db.getGroupId(modLoc);
|
||||||
|
String oldName = db.getGroupName(oldGroup);
|
||||||
|
|
||||||
|
// Neue solo-Gruppe erstellen
|
||||||
|
String newGroupId = java.util.UUID.randomUUID().toString().substring(0, 8);
|
||||||
|
db.setGroupId(modLoc, newGroupId);
|
||||||
|
db.setGroupNameById(newGroupId, oldName); // Namen behalten
|
||||||
|
|
||||||
|
p.sendMessage("§8[§bElevator§8] §eModul aus Gruppe getrennt.");
|
||||||
|
p.sendMessage("§7Neue Gruppen-ID: §e" + newGroupId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unbekannter Unterbefehl → Hilfe
|
||||||
|
sendGroupHelp(p);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hilfe-Anzeige
|
// ── /elevator private ──────────────────────────────────────────────
|
||||||
p.sendMessage("§b--- Elevator Hilfe ---");
|
if (args.length == 1 && args[0].equalsIgnoreCase("private")) {
|
||||||
p.sendMessage("§e/elevator name <Text> §7- Namen der Etage ändern");
|
db.setPublic(modLoc, false);
|
||||||
p.sendMessage("§e/elevator private §7- Zugriff nur für dich");
|
p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat");
|
||||||
p.sendMessage("§e/elevator public §7- Zugriff für alle");
|
p.sendMessage("§7Nur du kannst diesen Aufzug nun benutzen.");
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
p.sendMessage("§8[Debug] Status nach Änderung: " + (db.isPublic(modLoc) ? "§aÖffentlich" : "§cPrivat"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── /elevator public ───────────────────────────────────────────────
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("public")) {
|
||||||
|
db.setPublic(modLoc, true);
|
||||||
|
p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich");
|
||||||
|
p.sendMessage("§7Alle Spieler können diesen Aufzug nun benutzen.");
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
p.sendMessage("§8[Debug] Status nach Änderung: " + (db.isPublic(modLoc) ? "§aÖffentlich" : "§cPrivat"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── /elevator status ───────────────────────────────────────────────
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("status")) {
|
||||||
|
boolean isPublic = db.isPublic(modLoc);
|
||||||
|
String groupId = db.getGroupId(modLoc);
|
||||||
|
p.sendMessage("§b--- Aufzug-Status ---");
|
||||||
|
p.sendMessage("§7Sichtbarkeit: " + (isPublic ? "§aÖffentlich" : "§cPrivat"));
|
||||||
|
p.sendMessage("§7Etagen-Name: §f" + db.getGroupName(groupId));
|
||||||
|
p.sendMessage("§7Gruppe: §e" + groupId
|
||||||
|
+ " §7(§e" + db.getMembersOfGroup(groupId).size() + " §7Module)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Hilfe-Anzeige ──────────────────────────────────────────────────
|
||||||
|
sendHelp(p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// Modul-Suche (identisch mit alter Logik)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
private Block findNearbyModule(Player p, DatabaseManager db) {
|
||||||
|
Location pLoc = p.getLocation();
|
||||||
|
|
||||||
|
// 1. Direkt unter den Füßen
|
||||||
|
Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock();
|
||||||
|
if (directBelow.getType() == Material.DAYLIGHT_DETECTOR
|
||||||
|
&& db.isElevator(directBelow.getLocation())) {
|
||||||
|
return directBelow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Erweiterter Radius
|
||||||
|
for (double x = -1.0; x <= 1.0; x += 0.5) {
|
||||||
|
for (double z = -1.0; z <= 1.0; z += 0.5) {
|
||||||
|
for (double y = -2.0; y <= 0.5; y += 0.5) {
|
||||||
|
Block check = pLoc.clone().add(x, y, z).getBlock();
|
||||||
|
if (check.getType() == Material.DAYLIGHT_DETECTOR
|
||||||
|
&& db.isElevator(check.getLocation())) {
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHelp(Player p) {
|
||||||
|
p.sendMessage("§b--- Elevator Hilfe ---");
|
||||||
|
p.sendMessage("§e/elevator name <Text> §7- Etagen-Name setzen (für alle Module der Gruppe)");
|
||||||
|
p.sendMessage("§e/elevator private §7- Zugriff nur für dich");
|
||||||
|
p.sendMessage("§e/elevator public §7- Zugriff für alle");
|
||||||
|
p.sendMessage("§e/elevator status §7- Aktuellen Status anzeigen");
|
||||||
|
p.sendMessage("§e/elevator group §7- Gruppen-Info & Verwaltung");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendGroupHelp(Player p) {
|
||||||
|
p.sendMessage("§b--- Gruppen-Befehle ---");
|
||||||
|
p.sendMessage("§e/elevator group §7- Gruppen-Info anzeigen");
|
||||||
|
p.sendMessage("§e/elevator group scan §7- Benachbarte Module automatisch verknüpfen");
|
||||||
|
p.sendMessage("§e/elevator group unlink §7- Dieses Modul aus der Gruppe lösen");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,8 @@ public class ElevatorListener implements Listener {
|
|||||||
"http://textures.minecraft.net/texture/be8440e9d54ec7630b3e387f84e19e15f0b09d438a6bd784305df5d7608e6903";
|
"http://textures.minecraft.net/texture/be8440e9d54ec7630b3e387f84e19e15f0b09d438a6bd784305df5d7608e6903";
|
||||||
|
|
||||||
private final Map<UUID, Long> cooldowns = new HashMap<>();
|
private final Map<UUID, Long> cooldowns = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> deniedMessageCooldown = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInteract(PlayerInteractEvent e) {
|
public void onInteract(PlayerInteractEvent e) {
|
||||||
@@ -48,14 +50,26 @@ public class ElevatorListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (elevatorLoc != null) {
|
if (elevatorLoc != null) {
|
||||||
if (!db.isPublic(elevatorLoc)
|
Player player = e.getPlayer();
|
||||||
&& !db.getOwner(elevatorLoc).equals(e.getPlayer().getUniqueId())
|
boolean isPublic = db.isPublic(elevatorLoc);
|
||||||
&& !e.getPlayer().hasPermission("elevator.admin")) {
|
boolean isOwner = db.getOwner(elevatorLoc).equals(player.getUniqueId());
|
||||||
e.getPlayer().sendMessage("§cDieser Aufzug ist privat!");
|
boolean isAdmin = player.hasPermission("elevator.admin");
|
||||||
|
|
||||||
|
if (Elevator.getInstance().isDebugMode()) {
|
||||||
|
Elevator.getInstance().getLogger().info("Spieler " + player.getName() + " interagiert mit Aufzug:");
|
||||||
|
Elevator.getInstance().getLogger().info(" -> Public: " + isPublic);
|
||||||
|
Elevator.getInstance().getLogger().info(" -> IsOwner: " + isOwner);
|
||||||
|
Elevator.getInstance().getLogger().info(" -> IsAdmin: " + isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPublic && !isOwner && !isAdmin) {
|
||||||
|
player.sendMessage("§8[§bElevator§8] §cDieser Aufzug ist privat!");
|
||||||
|
e.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
openGUI(e.getPlayer(), elevatorLoc.getBlock());
|
openGUI(player, elevatorLoc.getBlock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,13 +143,12 @@ public class ElevatorListener implements Listener {
|
|||||||
String floorLabel = (i == 0) ? "Erdgeschoss" : "Etage " + i;
|
String floorLabel = (i == 0) ? "Erdgeschoss" : "Etage " + i;
|
||||||
meta.setDisplayName((isCurrent ? "§a● " : "§b○ ") + "§l" + floorLabel);
|
meta.setDisplayName((isCurrent ? "§a● " : "§b○ ") + "§l" + floorLabel);
|
||||||
|
|
||||||
// Lore ohne sichtbare Koordinaten, aber mit versteckter ID am Ende
|
|
||||||
String customName = db.getFloorCustomName(f.getLocation());
|
String customName = db.getFloorCustomName(f.getLocation());
|
||||||
meta.setLore(Arrays.asList(
|
meta.setLore(Arrays.asList(
|
||||||
"§7Name: §f" + (customName != null ? customName : floorLabel),
|
"§7Name: §f" + (customName != null ? customName : floorLabel),
|
||||||
"",
|
"",
|
||||||
isCurrent ? "§7(Diese Etage)" : "§e➤ Klicken zum Reisen",
|
isCurrent ? "§7(Diese Etage)" : "§e➤ Klicken zum Reisen",
|
||||||
"§0HIDDEN:" + f.getY() // Versteckte Zeile (Schwarz auf Schwarz/Unsichtbar)
|
"§0HIDDEN:" + f.getY()
|
||||||
));
|
));
|
||||||
|
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
@@ -157,11 +170,9 @@ public class ElevatorListener implements Listener {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
List<String> lore = e.getCurrentItem().getItemMeta().getLore();
|
List<String> lore = e.getCurrentItem().getItemMeta().getLore();
|
||||||
// Die versteckte Koordinate steht in der letzten Zeile (Index 3)
|
|
||||||
int targetY = Integer.parseInt(lore.get(3).replace("§0HIDDEN:", ""));
|
int targetY = Integer.parseInt(lore.get(3).replace("§0HIDDEN:", ""));
|
||||||
p.closeInventory();
|
p.closeInventory();
|
||||||
|
|
||||||
// Prüfe grob, ob der Spieler auf dem Modul steht
|
|
||||||
Block module = findModuleUnderPlayer(p);
|
Block module = findModuleUnderPlayer(p);
|
||||||
|
|
||||||
if (module != null) {
|
if (module != null) {
|
||||||
@@ -202,18 +213,33 @@ public class ElevatorListener implements Listener {
|
|||||||
showVisualFeedback(p, p.getWorld().getBlockAt(p.getLocation().getBlockX(), targetY, p.getLocation().getBlockZ()));
|
showVisualFeedback(p, p.getWorld().getBlockAt(p.getLocation().getBlockX(), targetY, p.getLocation().getBlockZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGH)
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
public void onJump(PlayerMoveEvent e) {
|
public void onJump(PlayerMoveEvent e) {
|
||||||
Player p = e.getPlayer();
|
Player p = e.getPlayer();
|
||||||
|
|
||||||
|
// Nur bei echter Aufwärtsbewegung
|
||||||
if (e.getTo().getY() <= e.getFrom().getY()) return;
|
if (e.getTo().getY() <= e.getFrom().getY()) return;
|
||||||
|
|
||||||
|
// Cooldown prüfen
|
||||||
if (cooldowns.containsKey(p.getUniqueId()) && System.currentTimeMillis() - cooldowns.get(p.getUniqueId()) < 300) return;
|
if (cooldowns.containsKey(p.getUniqueId()) && System.currentTimeMillis() - cooldowns.get(p.getUniqueId()) < 300) return;
|
||||||
|
|
||||||
Block b = findModuleUnderPlayer(p);
|
Block b = findModuleUnderPlayer(p);
|
||||||
if (b != null) {
|
if (b == null) return;
|
||||||
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
|
||||||
handleQuickMove(p, 1);
|
// FIX: Prüfe, ob der Spieler in FROM wirklich AUF dem Elevator stand.
|
||||||
|
// Steht er korrekt drauf: FROM.Y ≈ elevator.getY() + 1.0
|
||||||
|
// Läuft er von einer Halbstufe drüber: FROM.Y ≈ elevator.getY() + 0.5
|
||||||
|
// → Der Schritt von der Halbstufe wird dadurch zuverlässig ignoriert.
|
||||||
|
double expectedStandingY = b.getY() + 1.0;
|
||||||
|
if (e.getFrom().getY() < expectedStandingY - 0.1) return;
|
||||||
|
|
||||||
|
if (!hasPermissionToUse(p, b)) {
|
||||||
|
sendDeniedMessage(p);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
||||||
|
handleQuickMove(p, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
@@ -225,16 +251,28 @@ public class ElevatorListener implements Listener {
|
|||||||
|
|
||||||
Block b = findModuleUnderPlayer(p);
|
Block b = findModuleUnderPlayer(p);
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
|
if (!hasPermissionToUse(p, b)) {
|
||||||
|
sendDeniedMessage(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
||||||
handleQuickMove(p, -1);
|
handleQuickMove(p, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hilfsmethode für grobe Erkennung (überall im Listener genutzt)
|
// Prüft das Modul unter dem Spieler (aktuelle Position)
|
||||||
private Block findModuleUnderPlayer(Player p) {
|
private Block findModuleUnderPlayer(Player p) {
|
||||||
|
return findModuleUnderLocation(p.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIX: Neue Hilfsmethode, die eine beliebige Location prüft.
|
||||||
|
* Wird in onJump für die FROM-Position genutzt, um Halbstufen-Schritte
|
||||||
|
* von echten Sprüngen zu unterscheiden.
|
||||||
|
*/
|
||||||
|
private Block findModuleUnderLocation(Location l) {
|
||||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
Location l = p.getLocation();
|
|
||||||
// Check Fußblock und Block darunter
|
|
||||||
Block feet = l.getBlock();
|
Block feet = l.getBlock();
|
||||||
if (feet.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(feet.getLocation())) return feet;
|
if (feet.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(feet.getLocation())) return feet;
|
||||||
Block below = feet.getRelative(0, -1, 0);
|
Block below = feet.getRelative(0, -1, 0);
|
||||||
@@ -242,6 +280,32 @@ public class ElevatorListener implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prüft, ob der Spieler den Aufzug benutzen darf
|
||||||
|
private boolean hasPermissionToUse(Player p, Block elevatorBlock) {
|
||||||
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
|
Location loc = elevatorBlock.getLocation();
|
||||||
|
|
||||||
|
boolean isPublic = db.isPublic(loc);
|
||||||
|
boolean isOwner = db.getOwner(loc).equals(p.getUniqueId());
|
||||||
|
boolean isAdmin = p.hasPermission("elevator.admin");
|
||||||
|
|
||||||
|
return isPublic || isOwner || isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sendet "Privat"-Meldung nur, wenn Cooldown abgelaufen ist
|
||||||
|
private void sendDeniedMessage(Player p) {
|
||||||
|
UUID playerId = p.getUniqueId();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
if (deniedMessageCooldown.containsKey(playerId)) {
|
||||||
|
long lastMessage = deniedMessageCooldown.get(playerId);
|
||||||
|
if (now - lastMessage < 3000) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sendMessage("§8[§bElevator§8] §cDieser Aufzug ist privat!");
|
||||||
|
deniedMessageCooldown.put(playerId, now);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isElevatorModule(Block b) {
|
private boolean isElevatorModule(Block b) {
|
||||||
if (b == null) return false;
|
if (b == null) return false;
|
||||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
@@ -291,19 +355,29 @@ public class ElevatorListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showVisualFeedback(Player p, Block targetBlock) {
|
private void showVisualFeedback(Player p, Block targetBlock) {
|
||||||
List<Block> floors = findFloorsInColumn(targetBlock);
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
floors.sort(Comparator.comparingInt(Block::getY));
|
|
||||||
|
|
||||||
int floorIndex = -1;
|
String customName = db.getFloorCustomName(targetBlock.getLocation());
|
||||||
for (int i = 0; i < floors.size(); i++) {
|
|
||||||
if (floors.get(i).getY() == targetBlock.getY()) {
|
if (customName != null && !customName.isEmpty() && !customName.equals("Etage")) {
|
||||||
floorIndex = i;
|
p.sendTitle("", "§b" + customName, 5, 25, 5);
|
||||||
break;
|
Elevator.getInstance().getHologramManager().spawnElevatorHolo(p.getLocation(), customName);
|
||||||
|
} else {
|
||||||
|
List<Block> floors = findFloorsInColumn(targetBlock);
|
||||||
|
floors.sort(Comparator.comparingInt(Block::getY));
|
||||||
|
|
||||||
|
int floorIndex = -1;
|
||||||
|
for (int i = 0; i < floors.size(); i++) {
|
||||||
|
if (floors.get(i).getY() == targetBlock.getY()) {
|
||||||
|
floorIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
String label = (floorIndex <= 0) ? "Erdgeschoss" : "Etage " + floorIndex;
|
String label = (floorIndex <= 0) ? "Erdgeschoss" : "Etage " + floorIndex;
|
||||||
p.sendTitle("", "§b" + label, 5, 25, 5);
|
p.sendTitle("", "§b" + label, 5, 25, 5);
|
||||||
|
Elevator.getInstance().getHologramManager().spawnElevatorHolo(p.getLocation(), label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -331,7 +405,27 @@ public class ElevatorListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.removeElevator(e.getBlock().getLocation());
|
e.setDropItems(false);
|
||||||
|
e.setExpToDrop(0);
|
||||||
|
|
||||||
|
Location breakLoc = e.getBlock().getLocation();
|
||||||
|
|
||||||
|
db.removeElevator(breakLoc);
|
||||||
|
e.getBlock().setType(Material.AIR);
|
||||||
|
|
||||||
|
if (e.getPlayer().getGameMode() == GameMode.SURVIVAL) {
|
||||||
|
ItemStack moduleItem = Elevator.getInstance().createElevatorModuleItem();
|
||||||
|
HashMap<Integer, ItemStack> leftover = e.getPlayer().getInventory().addItem(moduleItem);
|
||||||
|
for (ItemStack rest : leftover.values()) {
|
||||||
|
breakLoc.getWorld().dropItemNaturally(breakLoc, rest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakLoc.getWorld() != null) {
|
||||||
|
breakLoc.getWorld().spawnParticle(Particle.CLOUD, breakLoc.add(0.5, 0.5, 0.5), 12, 0.2, 0.2, 0.2, 0.01);
|
||||||
|
breakLoc.getWorld().playSound(breakLoc, Sound.BLOCK_IRON_DOOR_CLOSE, 0.7f, 1.6f);
|
||||||
|
}
|
||||||
|
|
||||||
e.getPlayer().sendMessage("§eAufzug-Modul entfernt.");
|
e.getPlayer().sendMessage("§eAufzug-Modul entfernt.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
129
src/main/java/de/mviper/elevator/ElevatorTabCompleter.java
Normal file
129
src/main/java/de/mviper/elevator/ElevatorTabCompleter.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package de.mviper.elevator;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabCompleter;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ElevatorTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
|
// Alle Top-Level Unterbefehle
|
||||||
|
private static final List<String> SUBCOMMANDS = Arrays.asList(
|
||||||
|
"name", "group", "private", "public", "status"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Unterbefehle von /elevator group
|
||||||
|
private static final List<String> GROUP_SUBCOMMANDS = Arrays.asList(
|
||||||
|
"info", "scan", "unlink"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) return Collections.emptyList();
|
||||||
|
Player p = (Player) sender;
|
||||||
|
|
||||||
|
// args.length == 1 → Hauptbefehl-Vorschläge
|
||||||
|
if (args.length == 1) {
|
||||||
|
return filter(SUBCOMMANDS, args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// args.length == 2 → zweite Ebene
|
||||||
|
if (args.length == 2) {
|
||||||
|
switch (args[0].toLowerCase()) {
|
||||||
|
|
||||||
|
case "group":
|
||||||
|
return filter(GROUP_SUBCOMMANDS, args[1]);
|
||||||
|
|
||||||
|
case "name":
|
||||||
|
// Vorschlag: aktueller Etagen-Name als Platzhalter
|
||||||
|
String currentName = getCurrentFloorName(p);
|
||||||
|
return currentName != null
|
||||||
|
? filter(Collections.singletonList(currentName), args[1])
|
||||||
|
: Collections.emptyList();
|
||||||
|
|
||||||
|
// private / public / status haben keine weiteren Argumente
|
||||||
|
default:
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// args.length >= 3 → drittes+ Argument
|
||||||
|
if (args.length >= 3 && args[0].equalsIgnoreCase("name")) {
|
||||||
|
// Wörter-Eingabe — aktuellen Namen als Gesamtvorschlag anbieten
|
||||||
|
String currentName = getCurrentFloorName(p);
|
||||||
|
if (currentName != null) {
|
||||||
|
// Prüfen ob bisherige Eingabe zum Namen passt
|
||||||
|
String typed = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||||
|
if (currentName.toLowerCase().startsWith(typed.toLowerCase())) {
|
||||||
|
// Nur das nächste fehlende Wort vorschlagen
|
||||||
|
String[] nameParts = currentName.split(" ");
|
||||||
|
int wordIndex = args.length - 1;
|
||||||
|
if (wordIndex < nameParts.length) {
|
||||||
|
return Collections.singletonList(nameParts[wordIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt den aktuellen Etagen-Namen des Moduls zurück, auf dem der Spieler steht.
|
||||||
|
* Null, wenn kein Modul gefunden.
|
||||||
|
*/
|
||||||
|
private String getCurrentFloorName(Player p) {
|
||||||
|
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||||
|
Block module = findModuleUnderPlayer(p, db);
|
||||||
|
if (module == null) return null;
|
||||||
|
|
||||||
|
String groupId = db.getGroupId(module.getLocation());
|
||||||
|
if (groupId == null) return null;
|
||||||
|
|
||||||
|
String name = db.getGroupName(groupId);
|
||||||
|
return (name != null && !name.isEmpty() && !name.equals("Etage")) ? name : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Modul direkt unter dem Spieler suchen (spiegelt Logik aus ElevatorCommand). */
|
||||||
|
private Block findModuleUnderPlayer(Player p, DatabaseManager db) {
|
||||||
|
org.bukkit.Location pLoc = p.getLocation();
|
||||||
|
|
||||||
|
Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock();
|
||||||
|
if (directBelow.getType() == Material.DAYLIGHT_DETECTOR
|
||||||
|
&& db.isElevator(directBelow.getLocation())) {
|
||||||
|
return directBelow;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (double x = -1.0; x <= 1.0; x += 0.5) {
|
||||||
|
for (double z = -1.0; z <= 1.0; z += 0.5) {
|
||||||
|
for (double y = -2.0; y <= 0.5; y += 0.5) {
|
||||||
|
Block check = pLoc.clone().add(x, y, z).getBlock();
|
||||||
|
if (check.getType() == Material.DAYLIGHT_DETECTOR
|
||||||
|
&& db.isElevator(check.getLocation())) {
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Filtert eine Liste nach dem bereits getippten Prefix (case-insensitive). */
|
||||||
|
private List<String> filter(List<String> options, String typed) {
|
||||||
|
if (typed == null || typed.isEmpty()) return new ArrayList<>(options);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
String lower = typed.toLowerCase();
|
||||||
|
for (String s : options) {
|
||||||
|
if (s.toLowerCase().startsWith(lower)) result.add(s);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/de/mviper/elevator/UpdateChecker.java
Normal file
32
src/main/java/de/mviper/elevator/UpdateChecker.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package de.mviper.elevator;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class UpdateChecker {
|
||||||
|
|
||||||
|
private final Elevator plugin;
|
||||||
|
private final int resourceId;
|
||||||
|
|
||||||
|
public UpdateChecker(Elevator plugin, int resourceId) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getLatestVersion(final Consumer<String> consumer) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||||
|
try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream();
|
||||||
|
Scanner scanner = new Scanner(inputStream)) {
|
||||||
|
if (scanner.hasNext()) {
|
||||||
|
consumer.accept(scanner.next());
|
||||||
|
}
|
||||||
|
} catch (IOException exception) {
|
||||||
|
plugin.getLogger().info("Update-Check fehlgeschlagen: " + exception.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
# Elevator Config by mviper
|
# =============================================================
|
||||||
|
# Elevator Config by M_Viper
|
||||||
|
# =============================================================
|
||||||
|
|
||||||
|
debug: false # Debug-Modus (true = Debug-Ausgaben)
|
||||||
|
|
||||||
|
# Datenbank-Einstellungen (SQLite wird standardmäßig genutzt, falls false)
|
||||||
mysql:
|
mysql:
|
||||||
enable: false
|
enable: false
|
||||||
host: "localhost"
|
host: "localhost"
|
||||||
@@ -7,32 +13,65 @@ mysql:
|
|||||||
user: "root"
|
user: "root"
|
||||||
password: ""
|
password: ""
|
||||||
|
|
||||||
|
# Allgemeine Aufzug-Logik
|
||||||
settings:
|
settings:
|
||||||
max-distance: 64
|
max-distance: 64 # Maximale Reichweite zwischen zwei Modulen
|
||||||
hologram-duration: 45
|
hologram-duration: 45 # Wie lange das Hologramm (in Ticks) sichtbar bleibt
|
||||||
cooldown: 500
|
cooldown: 500 # Wartezeit zwischen Teleports (in Millisekunden)
|
||||||
|
|
||||||
|
|
||||||
|
# Optische Effekte & Hologramme
|
||||||
visuals:
|
visuals:
|
||||||
enable-particles: true
|
enable-particles: true
|
||||||
particle-type: "FIREWORKS_SPARK"
|
particle-type: "FIREWORKS_SPARK"
|
||||||
# Nutze HIER nur das & Zeichen für Farben!
|
|
||||||
|
# Texte & Farben (Nutze '&' für Farbcodes)
|
||||||
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
|
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
|
||||||
|
actionbar-text: "&fTransport: &b&lEtage %floor%"
|
||||||
|
|
||||||
|
# Darstellung des Hologramms
|
||||||
hologram-height-offset: 2.2
|
hologram-height-offset: 2.2
|
||||||
hologram-scale: 1.5
|
hologram-scale: 1.5
|
||||||
actionbar-text: "&fTransport: &b&lEtage %floor%"
|
|
||||||
|
# Hintergrund-Box (RGBA Werte)
|
||||||
hologram-background-color:
|
hologram-background-color:
|
||||||
alpha: 120
|
alpha: 120
|
||||||
red: 0
|
red: 0
|
||||||
green: 0
|
green: 0
|
||||||
blue: 0
|
blue: 0
|
||||||
|
|
||||||
|
# Akustisches Feedback
|
||||||
sounds:
|
sounds:
|
||||||
enable: true
|
enable: true
|
||||||
type: "BLOCK_NOTE_BLOCK_CHIME"
|
type: "BLOCK_NOTE_BLOCK_CHIME"
|
||||||
volume: 1.0
|
volume: 1.0
|
||||||
pitch: 1.5
|
pitch: 1.5
|
||||||
|
|
||||||
|
# Nachrichten-System
|
||||||
messages:
|
messages:
|
||||||
prefix: "&8[&bElevator&8] "
|
prefix: "&8[&bElevator&8] "
|
||||||
registered: "&aModul erfolgreich registriert!"
|
registered: "&aModul erfolgreich registriert!"
|
||||||
no-target: "&cKeine weitere Etage gefunden."
|
no-target: "&cKeine weitere Etage gefunden."
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# REZEPT-EINSTELLUNGEN
|
||||||
|
# =============================================================
|
||||||
|
# Crafting-Gitter Übersicht:
|
||||||
|
# [ 1 | 2 | 3 ] -> Zeile 1
|
||||||
|
# [ 4 | 5 | 6 ] -> Zeile 2
|
||||||
|
# [ 7 | 8 | 9 ] -> Zeile 3
|
||||||
|
# =============================================================
|
||||||
|
recipe:
|
||||||
|
# Das 3x3 Layout (Maximal 3 Zeichen pro Zeile!)
|
||||||
|
# Nutze einen Punkt (.) für ein leeres Feld.
|
||||||
|
shape:
|
||||||
|
- "ABA" # Slot 1 2 3
|
||||||
|
- "BCB" # Slot 4 5 6
|
||||||
|
- "ABA" # Slot 7 8 9
|
||||||
|
|
||||||
|
# Material-Zuweisung
|
||||||
|
# Liste aller Materialien: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html
|
||||||
|
ingredients:
|
||||||
|
A: "IRON_INGOT"
|
||||||
|
B: "ENDER_PEARL"
|
||||||
|
C: "DAYLIGHT_DETECTOR"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: Elevator
|
name: Elevator
|
||||||
version: 1.0
|
version: 1.8
|
||||||
main: de.mviper.elevator.Elevator
|
main: de.mviper.elevator.Elevator
|
||||||
api-version: 1.20
|
api-version: 1.20
|
||||||
author: mviper
|
author: mviper
|
||||||
|
|||||||
Reference in New Issue
Block a user