Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11576ef695 | |||
| dd8ae45000 | |||
| adeeb88ca5 | |||
| ba7647c732 | |||
| be191df87e | |||
| a884822115 | |||
| 95052e9da4 | |||
| fe7b0fed4b | |||
| 710f8cf4f5 | |||
| 67b06252cb | |||
| 4e8705ba8e |
63
README.md
63
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.
|
||||
* **💎 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.
|
||||
* **🛠 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.
|
||||
* **🛡️ 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 |
|
||||
| :--- | :--- |
|
||||
| **Oben Links** | Tageslichtsensor |
|
||||
| **Oben Rechts** | Tageslichtsensor |
|
||||
| **Mitte** | Eisenblock |
|
||||
| **Unten Links** | Tageslichtsensor |
|
||||
| **Unten Rechts** | Tageslichtsensor |
|
||||
| Slot | Position | Standard-Material |
|
||||
|:-----|:---------|:------------------|
|
||||
| **1, 3, 7, 9** | Ecken | Eisenbarren |
|
||||
| **2, 4, 6, 8** | Seiten | Enderperle |
|
||||
| **5** | Mitte | 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
|
||||
|
||||
| Befehl | Beschreibung | Berechtigung |
|
||||
| :--- | :--- | :--- |
|
||||
|:-------|:-------------|:-------------|
|
||||
| `/elevator name <Text>` | Ändert den Namen der aktuellen Etage. | `elevator.use` |
|
||||
| `/elevator private` | Setzt die Etage auf **Privat**. | `elevator.use` |
|
||||
| `/elevator public` | Setzt die Etage auf **Öffentlich**. | `elevator.use` |
|
||||
@@ -49,40 +50,48 @@ Das **Premium Aufzug-Modul** kann an jeder Werkbank mit folgendem Rezept hergest
|
||||
### Administration
|
||||
|
||||
| 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)
|
||||
|
||||
```yaml
|
||||
settings:
|
||||
max-distance: 64 # Maximale Distanz zwischen Modulen
|
||||
cooldown: 500 # Cooldown in ms zwischen Teleports
|
||||
# Dynamisches Rezept-Beispiel
|
||||
recipe:
|
||||
shape:
|
||||
- "ABA"
|
||||
- "BCB"
|
||||
- "ABA"
|
||||
ingredients:
|
||||
A: "IRON_INGOT"
|
||||
B: "ENDER_PEARL"
|
||||
C: "DAYLIGHT_DETECTOR"
|
||||
|
||||
# Visuelle Einstellungen
|
||||
visuals:
|
||||
enable-particles: true
|
||||
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
|
||||
hologram-scale: 1.5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗 Installation
|
||||
|
||||
1. **Download:** Lade die `Elevator.jar` herunter.
|
||||
2. **Upload:** Verschiebe die Datei in deinen `/plugins` Ordner.
|
||||
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.
|
||||
1. **Download**: Lade die neueste `Elevator.jar` von unserem Repository herunter.
|
||||
2. **Upload**: Verschiebe die Datei in deinen `/plugins` Ordner.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 👤 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:
|
||||
|
||||
[](https://discord.com/invite/FdRs4BRd8D)
|
||||
💡 Entwickelt mit Fokus auf Performance, Design und maximalen Bedienkomfort. Bei Fragen, Fehlern oder Verbesserungsvorschlägen tritt gerne unserem Discord bei.
|
||||
|
||||
---
|
||||
*Viper Plugins © 2026 — Effiziente Systemlösungen für deinen Server.*
|
||||
|
||||
**Viper Plugins** © 2026 — Effiziente Systemlösungen für deinen Server.
|
||||
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.mviper</groupId>
|
||||
<artifactId>Elevator</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.5</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
|
||||
@@ -30,20 +30,89 @@ public class DatabaseManager {
|
||||
localConfig.set(key + ".name", "Etage");
|
||||
localConfig.set(key + ".public", true);
|
||||
saveLocal();
|
||||
|
||||
// Debug-Ausgabe
|
||||
Elevator.getInstance().getLogger().info("Aufzug hinzugefügt: " + key + " | Public: true");
|
||||
}
|
||||
|
||||
public void removeElevator(Location loc) { localConfig.set(locToKey(loc), null); saveLocal(); }
|
||||
public boolean isElevator(Location loc) { return localConfig.contains(locToKey(loc)); }
|
||||
public String getFloorCustomName(Location loc) { return localConfig.getString(locToKey(loc) + ".name", "Etage"); }
|
||||
public void setFloorName(Location loc, String name) { localConfig.set(locToKey(loc) + ".name", name); saveLocal(); }
|
||||
public void removeElevator(Location loc) {
|
||||
localConfig.set(locToKey(loc), null);
|
||||
saveLocal();
|
||||
}
|
||||
|
||||
public boolean isElevator(Location loc) {
|
||||
return localConfig.contains(locToKey(loc));
|
||||
}
|
||||
|
||||
public String getFloorCustomName(Location loc) {
|
||||
return localConfig.getString(locToKey(loc) + ".name", "Etage");
|
||||
}
|
||||
|
||||
public void setFloorName(Location loc, String name) {
|
||||
localConfig.set(locToKey(loc) + ".name", name);
|
||||
saveLocal();
|
||||
}
|
||||
|
||||
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) { 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(); } }
|
||||
public boolean isPublic(Location loc) {
|
||||
String key = locToKey(loc);
|
||||
String fullKey = key + ".public";
|
||||
|
||||
// Prüfe zuerst, ob der Aufzug überhaupt existiert
|
||||
if (!localConfig.contains(key)) {
|
||||
Elevator.getInstance().getLogger().warning("isPublic: Aufzug existiert nicht: " + key);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wenn der public-Schlüssel nicht existiert, setze ihn auf true (Standard)
|
||||
if (!localConfig.contains(fullKey)) {
|
||||
Elevator.getInstance().getLogger().info("isPublic: Schlüssel nicht gefunden, setze auf true: " + fullKey);
|
||||
localConfig.set(fullKey, true);
|
||||
saveLocal();
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean value = localConfig.getBoolean(fullKey, true);
|
||||
Elevator.getInstance().getLogger().info("isPublic: " + fullKey + " = " + value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setPublic(Location loc, boolean status) {
|
||||
String key = locToKey(loc);
|
||||
String fullKey = key + ".public";
|
||||
|
||||
// Prüfe, ob der Aufzug existiert
|
||||
if (!localConfig.contains(key)) {
|
||||
Elevator.getInstance().getLogger().warning("setPublic: Aufzug existiert nicht: " + key);
|
||||
return;
|
||||
}
|
||||
|
||||
localConfig.set(fullKey, status);
|
||||
saveLocal();
|
||||
|
||||
// Sofort nochmal laden um zu verifizieren
|
||||
localConfig = YamlConfiguration.loadConfiguration(localFile);
|
||||
boolean verification = localConfig.getBoolean(fullKey, true);
|
||||
|
||||
Elevator.getInstance().getLogger().info("setPublic: " + fullKey + " auf " + status + " gesetzt (Verifiziert: " + verification + ")");
|
||||
}
|
||||
|
||||
private String locToKey(Location l) {
|
||||
// Wichtig: Nutze getBlockX/Y/Z für konsistente Koordinaten
|
||||
String key = "data." + l.getWorld().getName() + "_" + l.getBlockX() + "_" + l.getBlockY() + "_" + l.getBlockZ();
|
||||
return key;
|
||||
}
|
||||
|
||||
private void saveLocal() {
|
||||
try {
|
||||
localConfig.save(localFile);
|
||||
Elevator.getInstance().getLogger().info("Datenbank gespeichert: " + localFile.getName());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +1,172 @@
|
||||
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.NamespacedKey;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
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.ItemStack;
|
||||
import org.bukkit.inventory.ShapedRecipe;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
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 DatabaseManager databaseManager;
|
||||
private HologramManager hologramManager;
|
||||
private String latestVersionFound;
|
||||
|
||||
private final int RESOURCE_ID = 132220;
|
||||
private final String releaseUrl = "https://www.spigotmc.org/resources/" + RESOURCE_ID;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
saveDefaultConfig();
|
||||
|
||||
this.databaseManager = new DatabaseManager();
|
||||
this.hologramManager = new HologramManager();
|
||||
hologramManager.purgeAllHolograms();
|
||||
|
||||
// Events & Commands registrieren
|
||||
getServer().getPluginManager().registerEvents(new ElevatorListener(), this);
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
getCommand("elevator").setExecutor(new ElevatorCommand());
|
||||
|
||||
// Rezept laden
|
||||
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(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registriert das Elevator-Modul Rezept basierend auf der Config-Einstellung.
|
||||
* Unterstützte Rezept-Typen: "standard", "expensive"
|
||||
*/
|
||||
private void registerElevatorRecipe() {
|
||||
// Erstelle das Elevator-Modul Item
|
||||
ItemStack item = createElevatorModuleItem();
|
||||
|
||||
NamespacedKey key = new NamespacedKey(this, "elevator_module");
|
||||
ShapedRecipe recipe = new ShapedRecipe(key, item);
|
||||
|
||||
List<String> shapeLines = getConfig().getStringList("recipe.shape");
|
||||
if (shapeLines.size() != 3) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
public static Elevator getInstance() { return instance; }
|
||||
public DatabaseManager getDatabaseManager() { return databaseManager; }
|
||||
public HologramManager getHologramManager() { return hologramManager; }
|
||||
|
||||
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"
|
||||
"§7Platziere dies als Etage.",
|
||||
"§eRechtsklick: §fMenü öffnen",
|
||||
"§eSpringen/Sneaken: §fReisen"
|
||||
));
|
||||
meta.addEnchant(Enchantment.LUCK, 1, true);
|
||||
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
// Lese Rezept-Typ aus der Config (Standard: "standard")
|
||||
String recipeType = getConfig().getString("recipe.type", "standard").toLowerCase();
|
||||
|
||||
// Erstelle das ShapedRecipe
|
||||
ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(this, "elevator_module"), item);
|
||||
|
||||
// Wähle das Rezept basierend auf dem Config-Wert
|
||||
switch (recipeType) {
|
||||
case "expensive":
|
||||
// Teures Rezept:
|
||||
// D E D D = DIAMOND
|
||||
// E I E E = ENDER_PEARL
|
||||
// D E D I = IRON_BLOCK
|
||||
recipe.shape("DED", "EIE", "DED");
|
||||
recipe.setIngredient('D', Material.DIAMOND);
|
||||
recipe.setIngredient('E', Material.ENDER_PEARL);
|
||||
recipe.setIngredient('I', Material.IRON_BLOCK);
|
||||
getLogger().info("§aElevator-Rezept aktiviert: §eExpensive (Diamanten + Enderperlen)");
|
||||
break;
|
||||
|
||||
case "standard":
|
||||
default:
|
||||
// Standard-Rezept:
|
||||
// S . S S = DAYLIGHT_DETECTOR
|
||||
// . I . I = IRON_BLOCK
|
||||
// S . S
|
||||
recipe.shape("S.S", ".I.", "S.S");
|
||||
recipe.setIngredient('S', Material.DAYLIGHT_DETECTOR);
|
||||
recipe.setIngredient('I', Material.IRON_BLOCK);
|
||||
getLogger().info("§aElevator-Rezept aktiviert: §eStandard (Daylight Detector + Iron Block)");
|
||||
break;
|
||||
}
|
||||
|
||||
// Rezept zum Server hinzufügen
|
||||
try {
|
||||
getServer().addRecipe(recipe);
|
||||
} catch (Exception e) {
|
||||
getLogger().warning("§cKonnte Elevator-Rezept nicht registrieren: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Elevator getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public DatabaseManager getDatabaseManager() {
|
||||
return databaseManager;
|
||||
}
|
||||
|
||||
public HologramManager getHologramManager() {
|
||||
return hologramManager;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -19,19 +19,26 @@ public class ElevatorCommand implements CommandExecutor {
|
||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||
Block moduleBlock = null;
|
||||
|
||||
// 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.
|
||||
// VERBESSERTE ERKENNUNG: Prüfe direkt unter den Füßen und erweiterten Radius
|
||||
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
|
||||
// Erst direkt unter dem Spieler prüfen (häufigster Fall)
|
||||
Block directBelow = pLoc.clone().subtract(0, 1, 0).getBlock();
|
||||
if (directBelow.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(directBelow.getLocation())) {
|
||||
moduleBlock = directBelow;
|
||||
}
|
||||
|
||||
// Wenn nicht gefunden, erweiterte Suche
|
||||
if (moduleBlock == null) {
|
||||
outerLoop:
|
||||
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())) {
|
||||
moduleBlock = check;
|
||||
break outerLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,9 +46,14 @@ public class ElevatorCommand implements CommandExecutor {
|
||||
|
||||
if (moduleBlock == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
// Debug-Ausgabe
|
||||
Location modLoc = moduleBlock.getLocation();
|
||||
Elevator.getInstance().getLogger().info("Command: Modul gefunden bei X:" + modLoc.getBlockX() + " Y:" + modLoc.getBlockY() + " Z:" + modLoc.getBlockZ());
|
||||
|
||||
// Berechtigungs-Check (Besitzer oder Admin)
|
||||
if (!db.getOwner(moduleBlock.getLocation()).equals(p.getUniqueId()) && !p.hasPermission("elevator.admin")) {
|
||||
p.sendMessage("§8[§bElevator§8] §cDies ist nicht dein Aufzug!");
|
||||
@@ -61,14 +73,33 @@ public class ElevatorCommand implements CommandExecutor {
|
||||
|
||||
// Befehle: /elevator private | public
|
||||
if (args.length == 1) {
|
||||
Location modLocation = moduleBlock.getLocation();
|
||||
|
||||
if (args[0].equalsIgnoreCase("private")) {
|
||||
db.setPublic(moduleBlock.getLocation(), false);
|
||||
db.setPublic(modLocation, false);
|
||||
p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat");
|
||||
p.sendMessage("§7Nur du kannst diesen Aufzug nun benutzen.");
|
||||
|
||||
// Verifizierung
|
||||
boolean currentStatus = db.isPublic(modLocation);
|
||||
p.sendMessage("§8[Debug] Aktueller Status nach Änderung: " + (currentStatus ? "§aÖffentlich" : "§cPrivat"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("public")) {
|
||||
db.setPublic(moduleBlock.getLocation(), true);
|
||||
db.setPublic(modLocation, true);
|
||||
p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich");
|
||||
p.sendMessage("§7Alle Spieler können diesen Aufzug nun benutzen.");
|
||||
|
||||
// Verifizierung
|
||||
boolean currentStatus = db.isPublic(modLocation);
|
||||
p.sendMessage("§8[Debug] Aktueller Status nach Änderung: " + (currentStatus ? "§aÖffentlich" : "§cPrivat"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("status")) {
|
||||
boolean isPublic = db.isPublic(modLocation);
|
||||
p.sendMessage("§8[§bElevator§8] §7Aktueller Status: " + (isPublic ? "§aÖffentlich" : "§cPrivat"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -78,6 +109,7 @@ public class ElevatorCommand implements CommandExecutor {
|
||||
p.sendMessage("§e/elevator name <Text> §7- Namen der Etage ändern");
|
||||
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- Zeigt den aktuellen Status");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ public class ElevatorListener implements Listener {
|
||||
"http://textures.minecraft.net/texture/be8440e9d54ec7630b3e387f84e19e15f0b09d438a6bd784305df5d7608e6903";
|
||||
|
||||
private final Map<UUID, Long> cooldowns = new HashMap<>();
|
||||
private final Map<UUID, Long> deniedMessageCooldown = new HashMap<>(); // NEU: Für "Privat"-Meldungen
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent e) {
|
||||
@@ -48,14 +50,25 @@ public class ElevatorListener implements Listener {
|
||||
}
|
||||
|
||||
if (elevatorLoc != null) {
|
||||
if (!db.isPublic(elevatorLoc)
|
||||
&& !db.getOwner(elevatorLoc).equals(e.getPlayer().getUniqueId())
|
||||
&& !e.getPlayer().hasPermission("elevator.admin")) {
|
||||
e.getPlayer().sendMessage("§cDieser Aufzug ist privat!");
|
||||
Player player = e.getPlayer();
|
||||
boolean isPublic = db.isPublic(elevatorLoc);
|
||||
boolean isOwner = db.getOwner(elevatorLoc).equals(player.getUniqueId());
|
||||
boolean isAdmin = player.hasPermission("elevator.admin");
|
||||
|
||||
// Debug-Ausgabe
|
||||
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;
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
openGUI(e.getPlayer(), elevatorLoc.getBlock());
|
||||
openGUI(player, elevatorLoc.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +215,7 @@ public class ElevatorListener implements Listener {
|
||||
showVisualFeedback(p, p.getWorld().getBlockAt(p.getLocation().getBlockX(), targetY, p.getLocation().getBlockZ()));
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onJump(PlayerMoveEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
@@ -211,6 +225,12 @@ public class ElevatorListener implements Listener {
|
||||
|
||||
Block b = findModuleUnderPlayer(p);
|
||||
if (b != null) {
|
||||
// Prüfe Berechtigung
|
||||
if (!hasPermissionToUse(p, b)) {
|
||||
sendDeniedMessage(p);
|
||||
return;
|
||||
}
|
||||
|
||||
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
||||
handleQuickMove(p, 1);
|
||||
}
|
||||
@@ -225,6 +245,12 @@ public class ElevatorListener implements Listener {
|
||||
|
||||
Block b = findModuleUnderPlayer(p);
|
||||
if (b != null) {
|
||||
// Prüfe Berechtigung
|
||||
if (!hasPermissionToUse(p, b)) {
|
||||
sendDeniedMessage(p);
|
||||
return;
|
||||
}
|
||||
|
||||
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
|
||||
handleQuickMove(p, -1);
|
||||
}
|
||||
@@ -242,6 +268,39 @@ public class ElevatorListener implements Listener {
|
||||
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");
|
||||
|
||||
// Debug
|
||||
Elevator.getInstance().getLogger().info("Permission-Check für " + p.getName() + ": Public=" + isPublic + ", Owner=" + isOwner + ", Admin=" + isAdmin);
|
||||
|
||||
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();
|
||||
|
||||
// Prüfe ob Cooldown aktiv ist (3 Sekunden)
|
||||
if (deniedMessageCooldown.containsKey(playerId)) {
|
||||
long lastMessage = deniedMessageCooldown.get(playerId);
|
||||
if (now - lastMessage < 3000) {
|
||||
return; // Cooldown noch aktiv, keine Nachricht senden
|
||||
}
|
||||
}
|
||||
|
||||
// Sende Nachricht und setze Cooldown
|
||||
p.sendMessage("§8[§bElevator§8] §cDieser Aufzug ist privat!");
|
||||
deniedMessageCooldown.put(playerId, now);
|
||||
}
|
||||
|
||||
private boolean isElevatorModule(Block b) {
|
||||
if (b == null) return false;
|
||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||
@@ -291,19 +350,43 @@ public class ElevatorListener implements Listener {
|
||||
}
|
||||
|
||||
private void showVisualFeedback(Player p, Block targetBlock) {
|
||||
List<Block> floors = findFloorsInColumn(targetBlock);
|
||||
floors.sort(Comparator.comparingInt(Block::getY));
|
||||
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
|
||||
|
||||
int floorIndex = -1;
|
||||
for (int i = 0; i < floors.size(); i++) {
|
||||
if (floors.get(i).getY() == targetBlock.getY()) {
|
||||
floorIndex = i;
|
||||
break;
|
||||
// Hole benutzerdefinierten Namen
|
||||
String customName = db.getFloorCustomName(targetBlock.getLocation());
|
||||
|
||||
// Falls ein Custom Name existiert, benutze diesen, sonst Fallback
|
||||
if (customName != null && !customName.isEmpty() && !customName.equals("Etage")) {
|
||||
// Benutzer hat einen eigenen Namen vergeben
|
||||
p.sendTitle("", "§b" + customName, 5, 25, 5);
|
||||
|
||||
// Optional: Zeige auch ein Hologramm
|
||||
Elevator.getInstance().getHologramManager().spawnElevatorHolo(
|
||||
p.getLocation(),
|
||||
customName
|
||||
);
|
||||
} else {
|
||||
// Standard: Etagen-Nummer anzeigen
|
||||
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;
|
||||
p.sendTitle("", "§b" + label, 5, 25, 5);
|
||||
String label = (floorIndex <= 0) ? "Erdgeschoss" : "Etage " + floorIndex;
|
||||
p.sendTitle("", "§b" + label, 5, 25, 5);
|
||||
|
||||
// Optional: Zeige auch ein Hologramm
|
||||
Elevator.getInstance().getHologramManager().spawnElevatorHolo(
|
||||
p.getLocation(),
|
||||
label
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -331,7 +414,27 @@ public class ElevatorListener implements Listener {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
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,8 @@
|
||||
# Elevator Config by mviper
|
||||
# =============================================================
|
||||
# Elevator Config by M_Viper
|
||||
# =============================================================
|
||||
|
||||
# Datenbank-Einstellungen (SQLite wird standardmäßig genutzt, falls false)
|
||||
mysql:
|
||||
enable: false
|
||||
host: "localhost"
|
||||
@@ -7,51 +11,64 @@ mysql:
|
||||
user: "root"
|
||||
password: ""
|
||||
|
||||
# Allgemeine Aufzug-Logik
|
||||
settings:
|
||||
max-distance: 64
|
||||
hologram-duration: 45
|
||||
cooldown: 500
|
||||
max-distance: 64 # Maximale Reichweite zwischen zwei Modulen
|
||||
hologram-duration: 45 # Wie lange das Hologramm (in Ticks) sichtbar bleibt
|
||||
cooldown: 500 # Wartezeit zwischen Teleports (in Millisekunden)
|
||||
|
||||
# Optische Effekte & Hologramme
|
||||
visuals:
|
||||
enable-particles: true
|
||||
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«"
|
||||
actionbar-text: "&fTransport: &b&lEtage %floor%"
|
||||
|
||||
# Darstellung des Hologramms
|
||||
hologram-height-offset: 2.2
|
||||
hologram-scale: 1.5
|
||||
actionbar-text: "&fTransport: &b&lEtage %floor%"
|
||||
|
||||
# Hintergrund-Box (RGBA Werte)
|
||||
hologram-background-color:
|
||||
alpha: 120
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
# Akustisches Feedback
|
||||
sounds:
|
||||
enable: true
|
||||
type: "BLOCK_NOTE_BLOCK_CHIME"
|
||||
volume: 1.0
|
||||
pitch: 1.5
|
||||
|
||||
# Nachrichten-System
|
||||
messages:
|
||||
prefix: "&8[&bElevator&8] "
|
||||
registered: "&aModul erfolgreich registriert!"
|
||||
no-target: "&cKeine weitere Etage gefunden."
|
||||
|
||||
# ============================================
|
||||
# REZEPT-AUSWAHL
|
||||
# ============================================
|
||||
# Hier kannst du zwischen verschiedenen Crafting-Rezepten wählen.
|
||||
# Mögliche Werte: "standard", "expensive"
|
||||
#
|
||||
Standard-Rezept:
|
||||
S.S S = DAYLIGHT_DETECTOR
|
||||
.I. I = IRON_BLOCK
|
||||
S.S
|
||||
#
|
||||
Teures Rezept (Expensive):
|
||||
DED D = DIAMOND
|
||||
EIE E = ENDER_PEARL
|
||||
DED I = IRON_BLOCK
|
||||
|
||||
# =============================================================
|
||||
# REZEPT-EINSTELLUNGEN
|
||||
# =============================================================
|
||||
# Crafting-Gitter Übersicht:
|
||||
# [ 1 | 2 | 3 ] -> Zeile 1
|
||||
# [ 4 | 5 | 6 ] -> Zeile 2
|
||||
# [ 7 | 8 | 9 ] -> Zeile 3
|
||||
# =============================================================
|
||||
recipe:
|
||||
type: "standard"
|
||||
# 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
|
||||
version: 1.1
|
||||
version: 1.5
|
||||
main: de.mviper.elevator.Elevator
|
||||
api-version: 1.20
|
||||
author: mviper
|
||||
|
||||
Reference in New Issue
Block a user