Update from Git Manager GUI

This commit is contained in:
2026-01-27 20:11:19 +01:00
parent 4f1622f150
commit d6a339b39a
8 changed files with 663 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package de.mviper.elevator;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class DatabaseManager {
private File localFile;
private FileConfiguration localConfig;
public DatabaseManager() { setupLocalFile(); }
private void setupLocalFile() {
localFile = new File(Elevator.getInstance().getDataFolder(), "elevators.yml");
if (!localFile.exists()) {
try {
Elevator.getInstance().getDataFolder().mkdirs();
localFile.createNewFile();
} catch (IOException e) { e.printStackTrace(); }
}
localConfig = YamlConfiguration.loadConfiguration(localFile);
}
public void addElevator(Location loc, UUID owner) {
String key = locToKey(loc);
localConfig.set(key + ".owner", owner.toString());
localConfig.set(key + ".name", "Etage");
localConfig.set(key + ".public", true);
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(); } }
}

View File

@@ -0,0 +1,51 @@
package de.mviper.elevator;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
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;
public class Elevator extends JavaPlugin {
private static Elevator instance;
private DatabaseManager databaseManager;
private HologramManager hologramManager;
@Override
public void onEnable() {
instance = this;
saveDefaultConfig();
this.databaseManager = new DatabaseManager();
this.hologramManager = new HologramManager();
hologramManager.purgeAllHolograms();
getServer().getPluginManager().registerEvents(new ElevatorListener(), this);
getCommand("elevator").setExecutor(new ElevatorCommand());
registerElevatorRecipe();
}
private void registerElevatorRecipe() {
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);
}
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 DatabaseManager getDatabaseManager() { return databaseManager; }
public HologramManager getHologramManager() { return hologramManager; }
}

View File

@@ -0,0 +1,83 @@
package de.mviper.elevator;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class ElevatorCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) return true;
Player p = (Player) sender;
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.
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) {
p.sendMessage("§8[§bElevator§8] §cKein Aufzug-Modul in deiner Nähe gefunden!");
return true;
}
// 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!");
return true;
}
// Befehl: /elevator name <Text>
if (args.length >= 2 && args[0].equalsIgnoreCase("name")) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i < args.length; i++) sb.append(args[i]).append(" ");
String newName = ChatColor.translateAlternateColorCodes('&', sb.toString().trim());
db.setFloorName(moduleBlock.getLocation(), newName);
p.sendMessage("§8[§bElevator§8] §aEtage benannt: " + newName);
return true;
}
// Befehle: /elevator private | public
if (args.length == 1) {
if (args[0].equalsIgnoreCase("private")) {
db.setPublic(moduleBlock.getLocation(), false);
p.sendMessage("§8[§bElevator§8] §7Status: §cPrivat");
return true;
}
if (args[0].equalsIgnoreCase("public")) {
db.setPublic(moduleBlock.getLocation(), true);
p.sendMessage("§8[§bElevator§8] §7Status: §aÖffentlich");
return true;
}
}
// Hilfe-Anzeige
p.sendMessage("§b--- Elevator Hilfe ---");
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");
return true;
}
}

View File

@@ -0,0 +1,337 @@
package de.mviper.elevator;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.*;
public class ElevatorListener implements Listener {
private final String SKULL_URL =
"http://textures.minecraft.net/texture/be8440e9d54ec7630b3e387f84e19e15f0b09d438a6bd784305df5d7608e6903";
private final Map<UUID, Long> cooldowns = new HashMap<>();
@EventHandler
public void onInteract(PlayerInteractEvent e) {
if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getClickedBlock() == null) return;
Block block = e.getClickedBlock();
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
Location elevatorLoc = null;
if (block.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(block.getLocation())) {
elevatorLoc = block.getLocation();
} else if (block.getType().name().contains("SIGN")) {
Sign sign = (Sign) block.getState();
if (sign.getLine(0).equalsIgnoreCase("[Elevator]") || sign.getLine(1).contains("AUFZUG")) {
elevatorLoc = findModuleNearby(block.getLocation(), 3);
}
}
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!");
return;
}
e.setCancelled(true);
openGUI(e.getPlayer(), elevatorLoc.getBlock());
}
}
@EventHandler
public void onSignChange(SignChangeEvent e) {
if (!e.getLine(0).equalsIgnoreCase("[Elevator]")) return;
Location loc = findModuleNearby(e.getBlock().getLocation(), 3);
e.setLine(0, "§7§m--§b §l● §7§m--");
e.setLine(1, "§b§lAUFZUG");
if (loc != null) {
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
String customName = db.getFloorCustomName(loc);
if (customName != null && !customName.isEmpty()) {
e.setLine(2, "§f" + customName);
} else {
List<Block> floors = findFloorsInColumn(loc.getBlock());
floors.sort(Comparator.comparingInt(Block::getY));
int floorIndex = -1;
for (int i = 0; i < floors.size(); i++) {
if (floors.get(i).getY() == loc.getBlockY()) {
floorIndex = i;
break;
}
}
String label = (floorIndex <= 0) ? "Erdgeschoss" : "Etage " + floorIndex;
e.setLine(2, "§f" + label);
}
} else {
e.setLine(2, "§8(Bereit)");
}
e.setLine(3, "§7§m--§b §l● §7§m--");
e.getPlayer().sendMessage("§aAufzug-Schild wurde schick gemacht!");
}
private Location findModuleNearby(Location loc, int radius) {
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
for (int z = -radius; z <= radius; z++) {
Location check = loc.clone().add(x, y, z);
if (check.getBlock().getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(check)) {
return check;
}
}
}
}
return null;
}
private void openGUI(Player p, Block clickedBlock) {
List<Block> floors = findFloorsInColumn(clickedBlock);
floors.sort(Comparator.comparingInt(Block::getY));
Inventory inv = Bukkit.createInventory(null, 27, "§8» §bAufzug-Menü");
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
for (int i = 0; i < floors.size(); i++) {
Block f = floors.get(i);
boolean isCurrent = f.getY() == clickedBlock.getY();
ItemStack item = isCurrent ? new ItemStack(Material.BEACON) : SkullCreator.getCustomSkull(SKULL_URL);
ItemMeta meta = item.getItemMeta();
String floorLabel = (i == 0) ? "Erdgeschoss" : "Etage " + i;
meta.setDisplayName((isCurrent ? "§a● " : "§b○ ") + "§l" + floorLabel);
// Lore ohne sichtbare Koordinaten, aber mit versteckter ID am Ende
String customName = db.getFloorCustomName(f.getLocation());
meta.setLore(Arrays.asList(
"§7Name: §f" + (customName != null ? customName : floorLabel),
"",
isCurrent ? "§7(Diese Etage)" : "§e➤ Klicken zum Reisen",
"§0HIDDEN:" + f.getY() // Versteckte Zeile (Schwarz auf Schwarz/Unsichtbar)
));
item.setItemMeta(meta);
inv.addItem(item);
}
p.openInventory(inv);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent e) {
if (!e.getView().getTitle().equals("§8» §bAufzug-Menü")) return;
e.setCancelled(true);
Player p = (Player) e.getWhoClicked();
if (e.getCurrentItem() == null || !e.getCurrentItem().hasItemMeta()) return;
if (e.getCurrentItem().getType() == Material.BEACON) return;
try {
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:", ""));
p.closeInventory();
// Prüfe grob, ob der Spieler auf dem Modul steht
Block module = findModuleUnderPlayer(p);
if (module != null) {
performTeleport(p, targetY);
} else {
p.sendMessage("§eBitte stelle dich innerhalb von 5 Sekunden auf das Aufzug-Modul...");
new BukkitRunnable() {
int timer = 0;
@Override
public void run() {
if (!p.isOnline()) { cancel(); return; }
Block current = findModuleUnderPlayer(p);
if (current != null) {
performTeleport(p, targetY);
cancel();
return;
}
timer++;
if (timer >= 100) {
p.sendMessage("§cVorgang abgebrochen: Du hast das Modul nicht rechtzeitig betreten.");
cancel();
}
}
}.runTaskTimer(Elevator.getInstance(), 0L, 1L);
}
} catch (Exception ex) {
p.sendMessage("§cFehler beim Verarbeiten der Reisedaten.");
}
}
private void performTeleport(Player p, int targetY) {
Location targetLoc = p.getLocation().clone();
targetLoc.setY(targetY + 1.1);
p.teleport(targetLoc);
p.playSound(p.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 1.2f);
p.sendMessage("§6Abfahrt!");
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();
if (e.getTo().getY() <= e.getFrom().getY()) return;
if (cooldowns.containsKey(p.getUniqueId()) && System.currentTimeMillis() - cooldowns.get(p.getUniqueId()) < 300) return;
Block b = findModuleUnderPlayer(p);
if (b != null) {
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
handleQuickMove(p, 1);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onSneak(PlayerToggleSneakEvent e) {
if (!e.isSneaking()) return;
Player p = e.getPlayer();
if (cooldowns.containsKey(p.getUniqueId()) && System.currentTimeMillis() - cooldowns.get(p.getUniqueId()) < 300) return;
Block b = findModuleUnderPlayer(p);
if (b != null) {
cooldowns.put(p.getUniqueId(), System.currentTimeMillis());
handleQuickMove(p, -1);
}
}
// Hilfsmethode für grobe Erkennung (überall im Listener genutzt)
private Block findModuleUnderPlayer(Player p) {
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
Location l = p.getLocation();
// Check Fußblock und Block darunter
Block feet = l.getBlock();
if (feet.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(feet.getLocation())) return feet;
Block below = feet.getRelative(0, -1, 0);
if (below.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(below.getLocation())) return below;
return null;
}
private boolean isElevatorModule(Block b) {
if (b == null) return false;
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
return b.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(b.getLocation());
}
private void handleQuickMove(Player p, int dir) {
Block b = findModuleUnderPlayer(p);
if (b == null) return;
List<Block> floors = findFloorsInColumn(b);
floors.sort(Comparator.comparingInt(Block::getY));
int currentIdx = -1;
for (int i = 0; i < floors.size(); i++) {
if (floors.get(i).getY() == b.getY()) {
currentIdx = i;
break;
}
}
int nextIdx = currentIdx + dir;
if (nextIdx >= 0 && nextIdx < floors.size()) {
Block targetBlock = floors.get(nextIdx);
Location loc = targetBlock.getLocation().add(0.5, 1.1, 0.5);
loc.setYaw(p.getLocation().getYaw());
loc.setPitch(p.getLocation().getPitch());
p.setVelocity(new Vector(0, 0, 0));
p.teleport(loc);
p.playSound(loc, Sound.BLOCK_IRON_DOOR_OPEN, 0.5f, 1.5f);
showVisualFeedback(p, targetBlock);
}
}
private List<Block> findFloorsInColumn(Block b) {
List<Block> floors = new ArrayList<>();
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
for (int y = b.getWorld().getMinHeight(); y < b.getWorld().getMaxHeight(); y++) {
Block check = b.getWorld().getBlockAt(b.getX(), y, b.getZ());
if (check.getType() == Material.DAYLIGHT_DETECTOR && db.isElevator(check.getLocation())) {
floors.add(check);
}
}
return floors;
}
private void showVisualFeedback(Player p, Block targetBlock) {
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);
}
@EventHandler
public void onPlace(BlockPlaceEvent e) {
if (e.getItemInHand() != null
&& e.getItemInHand().hasItemMeta()
&& e.getItemInHand().getItemMeta().getDisplayName().contains("Aufzug-Modul")) {
Elevator.getInstance().getDatabaseManager()
.addElevator(e.getBlockPlaced().getLocation(), e.getPlayer().getUniqueId());
e.getPlayer().sendMessage("§8[§bElevator§8] §aModul erfolgreich registriert!");
}
}
@EventHandler
public void onBreak(BlockBreakEvent e) {
DatabaseManager db = Elevator.getInstance().getDatabaseManager();
if (!db.isElevator(e.getBlock().getLocation())) return;
if (!e.getPlayer().getUniqueId().equals(db.getOwner(e.getBlock().getLocation()))
&& !e.getPlayer().hasPermission("elevator.admin")) {
e.setCancelled(true);
e.getPlayer().sendMessage("§cDas ist nicht dein Aufzug!");
return;
}
db.removeElevator(e.getBlock().getLocation());
e.getPlayer().sendMessage("§eAufzug-Modul entfernt.");
}
}

View File

@@ -0,0 +1,50 @@
package de.mviper.elevator;
import org.bukkit.*;
import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
import org.bukkit.entity.TextDisplay;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Transformation;
import org.joml.Vector3f;
public class HologramManager {
public void spawnElevatorHolo(Location loc, String floorLabel) {
// Holen des benutzerdefinierten Namens für den Block unter den Füßen
String name = Elevator.getInstance().getDatabaseManager().getFloorCustomName(loc.clone().add(0, -1.1, 0).getBlock().getLocation());
TextDisplay display = loc.getWorld().spawn(loc.clone().add(0, 1.5, 0), TextDisplay.class, d -> {
d.setText("§b" + name + "\n§8» §f" + floorLabel + " §8«");
d.setBillboard(Display.Billboard.CENTER);
d.setShadowed(true);
d.setBackgroundColor(Color.fromARGB(120, 0, 0, 0));
d.addScoreboardTag("ElevatorHolo");
Transformation trans = d.getTransformation();
trans.getScale().set(new Vector3f(1.4f, 1.4f, 1.4f));
d.setTransformation(trans);
});
new BukkitRunnable() {
int ticks = 0;
@Override
public void run() {
if (ticks++ > 40 || !display.isValid()) {
display.remove();
this.cancel();
return;
}
display.teleport(display.getLocation().add(0, 0.015, 0));
}
}.runTaskTimer(Elevator.getInstance(), 0L, 1L);
}
public void purgeAllHolograms() {
for (World w : Bukkit.getWorlds()) {
for (Entity e : w.getEntities()) {
if (e instanceof TextDisplay && e.getScoreboardTags().contains("ElevatorHolo")) e.remove();
}
}
}
}

View File

@@ -0,0 +1,46 @@
package de.mviper.elevator;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.profile.PlayerProfile;
import org.bukkit.profile.PlayerTextures;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
public class SkullCreator {
public static ItemStack getCustomSkull(String urlString) {
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
if (urlString == null || urlString.isEmpty()) return item;
SkullMeta meta = (SkullMeta) item.getItemMeta();
if (meta == null) return item;
try {
// Erstellt ein neues, leeres Profil mit einer zufälligen UUID
PlayerProfile profile = Bukkit.createPlayerProfile(UUID.randomUUID(), "Elevator");
PlayerTextures textures = profile.getTextures();
// Setzt die URL für die Textur
URL url = new URL(urlString);
textures.setSkin(url);
// Wichtig: Texturen zurück ins Profil schreiben
profile.setTextures(textures);
// Profil in die SkullMeta setzen (Offizielle API!)
meta.setOwnerProfile(profile);
} catch (MalformedURLException e) {
Bukkit.getLogger().warning("Ungültige Skull-URL: " + urlString);
} catch (Exception e) {
e.printStackTrace();
}
item.setItemMeta(meta);
return item;
}
}

View File

@@ -0,0 +1,38 @@
# Elevator Config by mviper
mysql:
enable: false
host: "localhost"
port: 3306
database: "minecraft"
user: "root"
password: ""
settings:
max-distance: 64
hologram-duration: 45
cooldown: 500
visuals:
enable-particles: true
particle-type: "FIREWORKS_SPARK"
# Nutze HIER nur das & Zeichen für Farben!
hologram-text: "&8&l» &b&lEtage %floor% &8&l«"
hologram-height-offset: 2.2
hologram-scale: 1.5
actionbar-text: "&fTransport: &b&lEtage %floor%"
hologram-background-color:
alpha: 120
red: 0
green: 0
blue: 0
sounds:
enable: true
type: "BLOCK_NOTE_BLOCK_CHIME"
volume: 1.0
pitch: 1.5
messages:
prefix: "&8[&bElevator&8] "
registered: "&aModul erfolgreich registriert!"
no-target: "&cKeine weitere Etage gefunden."

View File

@@ -0,0 +1,9 @@
name: Elevator
version: 1.0
main: de.mviper.elevator.Elevator
api-version: 1.20
author: mviper
commands:
elevator:
description: Verwalte deinen Aufzug.
permission: elevator.use