Dateien nach "src/main/java/de/nexuslobby/modules/portal" hochladen

This commit is contained in:
2026-01-22 14:56:58 +00:00
parent 9f1caa71ae
commit cce4339b93
3 changed files with 654 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
package de.nexuslobby.modules.portal;
import org.bukkit.Location;
import org.bukkit.Particle;
public class Portal {
private final String name;
private final String type; // "SERVER" oder "WORLD"
private Location pos1;
private Location pos2;
private String destination; // Server Name oder "World;X;Y;Z;Yaw;Pitch"
private Particle particle;
// NEU: Return Spawn Location, damit Spieler beim Serverwechsel nicht direkt wieder Portal auslösen
private Location returnSpawn;
public Portal(String name, String type) {
this.name = name;
this.type = type;
this.particle = Particle.PORTAL; // Standard Partikel
}
public String getName() { return name; }
public String getType() { return type; }
public Location getPos1() { return pos1; }
public void setPos1(Location pos1) { this.pos1 = pos1; }
public Location getPos2() { return pos2; }
public void setPos2(Location pos2) { this.pos2 = pos2; }
public String getDestination() { return destination; }
public void setDestination(String destination) { this.destination = destination; }
public Particle getParticle() { return particle; }
public void setParticle(Particle particle) { this.particle = particle; }
// --- Getter & Setter für ReturnSpawn ---
public Location getReturnSpawn() { return returnSpawn; }
public void setReturnSpawn(Location returnSpawn) { this.returnSpawn = returnSpawn; }
}

View File

@@ -0,0 +1,154 @@
package de.nexuslobby.modules.portal;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class PortalCommand implements CommandExecutor {
private final PortalManager portalManager;
public PortalCommand(PortalManager portalManager) {
this.portalManager = portalManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Nur Spieler können diesen Befehl nutzen.");
return false;
}
Player p = (Player) sender;
// Wenn keine Argumente da sind, Hilfe zeigen
if (args.length == 0) {
sendHelp(p);
return true;
}
// Switch case für die Unterbefehle
switch (args[0].toLowerCase()) {
case "create":
if (args.length < 3) {
p.sendMessage("§cBenutzung: /portal create <Name> <server|world>");
return true;
}
String type = args[2].toUpperCase();
if (!type.equals("SERVER") && !type.equals("WORLD")) {
p.sendMessage("§cTyp muss 'server' oder 'world' sein!");
return true;
}
portalManager.createPortal(args[1], type, p);
break;
case "setpos1":
if (args.length < 2) { p.sendMessage("§cBenutzung: /portal setpos1 <Name>"); return true; }
if (portalManager.setPortalPos(args[1], 1, p.getLocation())) {
p.sendMessage("§aPosition 1 gesetzt für " + args[1]);
} else {
p.sendMessage("§cPortal nicht gefunden.");
}
break;
case "setpos2":
if (args.length < 2) { p.sendMessage("§cBenutzung: /portal setpos2 <Name>"); return true; }
if (portalManager.setPortalPos(args[1], 2, p.getLocation())) {
p.sendMessage("§aPosition 2 gesetzt für " + args[1]);
} else {
p.sendMessage("§cPortal nicht gefunden.");
}
break;
case "setdest":
if (args.length < 3) {
p.sendMessage("§cBenutzung: /portal setdest <Name> <Ziel>");
p.sendMessage("§7Server: ServerName");
p.sendMessage("§7Welt: Weltname;X;Y;Z;Yaw;Pitch");
return true;
}
String dest = args[2];
// Falls Koordinaten getrennt mit Leerzeichen gegeben werden (z.B. /portal setdest name world 100 64 100)
if (args.length > 3) dest += ";" + args[3];
if (args.length > 4) dest += ";" + args[4];
if (args.length > 5) dest += ";" + args[5];
if (args.length > 6) dest += ";" + args[6];
if (portalManager.setDestination(args[1], dest)) {
p.sendMessage("§aZiel gesetzt für " + args[1] + ": " + dest);
} else {
p.sendMessage("§cPortal nicht gefunden.");
}
break;
case "setparticle":
if (args.length < 3) {
p.sendMessage("§cBenutzung: /portal setparticle <Name> <ParticleType>");
return true;
}
if (portalManager.setParticle(args[1], args[2])) {
p.sendMessage("§aPartikel für " + args[1] + " auf " + args[2].toUpperCase() + " gesetzt.");
} else {
p.sendMessage("§cPortal oder Partikel '" + args[2] + "' nicht gefunden.");
}
break;
case "setspawn":
// Neuer Befehl: /portal setspawn <Name>
if (args.length < 2) {
p.sendMessage("§cBenutzung: /portal setspawn <Name>");
return true;
}
// Optional: Berechtigungscheck (anpassbar)
if (!p.hasPermission("nexuslobby.portal")) {
p.sendMessage("§cKeine Rechte!");
return true;
}
// Wir speichern die aktuelle Position leicht versetzt (2 Blöcke), damit Spieler nicht direkt wieder im Portal landen.
Location spawnLoc = p.getLocation().clone();
spawnLoc.add(0, 0, 2); // einfacher Offset als default
if (portalManager.setPortalReturnSpawn(args[1], spawnLoc)) {
p.sendMessage("§aPortal-Spawnpunkt für '" + args[1] + "' gesetzt!");
} else {
p.sendMessage("§cPortal nicht gefunden.");
}
break;
case "delete":
if (args.length < 2) { p.sendMessage("§cBenutzung: /portal delete <Name>"); return true; }
portalManager.deletePortal(args[1]);
p.sendMessage("§aPortal gelöscht.");
break;
case "list":
p.sendMessage("§eAlle Portale:");
for (String name : portalManager.getPortalNames()) {
p.sendMessage("§7- " + name);
}
break;
default:
p.sendMessage("§cUnbekannter Befehl.");
sendHelp(p);
break;
}
return true;
}
private void sendHelp(Player p) {
p.sendMessage("§6--- Portal Hilfe ---");
p.sendMessage("§e/portal create <Name> <server|world>");
p.sendMessage("§e/portal setpos1 <Name>");
p.sendMessage("§e/portal setpos2 <Name>");
p.sendMessage("§e/portal setdest <Name> <Ziel>");
p.sendMessage("§e/portal setparticle <Name> <Partikel>");
p.sendMessage("§e/portal setspawn <Name>");
p.sendMessage("§e/portal delete <Name>");
p.sendMessage("§e/portal list");
}
}

View File

@@ -0,0 +1,459 @@
package de.nexuslobby.modules.portal;
import de.nexuslobby.api.Module;
import de.nexuslobby.NexusLobby;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitTask;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.Set;
/**
* PortalManager - verwaltet Portale, lädt/speichert sie, spawnt Partikel und teleporiert Spieler.
*/
public class PortalManager implements Module, Listener {
private final NexusLobby plugin;
private final Map<String, Portal> portals = new HashMap<>();
private final Map<UUID, Long> cooldowns = new HashMap<>();
private final Map<UUID, Location[]> selectionMap = new HashMap<>();
private final NamespacedKey wandKey;
private BukkitTask particleTask;
public PortalManager(NexusLobby plugin) {
this.plugin = plugin;
this.wandKey = new NamespacedKey(plugin, "nexuslobby_portal_wand");
}
@Override
public String getName() {
return "PortalManager";
}
@Override
public void onEnable() {
loadPortals();
Bukkit.getPluginManager().registerEvents(this, plugin);
startParticleTask();
plugin.getLogger().info("PortalManager geladen.");
}
@Override
public void onDisable() {
if (particleTask != null) {
particleTask.cancel();
particleTask = null;
}
HandlerList.unregisterAll(this);
plugin.getLogger().info("PortalManager deaktiviert.");
}
/**
* Gibt alle Namen der aktuell geladenen Portale zurück.
* Wird vom LobbyTabCompleter genutzt.
*/
public Set<String> getPortalNames() {
return portals.keySet();
}
// --- Wand / Selection ---
@org.bukkit.event.EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) return;
ItemStack item = event.getItem();
if (item == null || !item.hasItemMeta()) return;
ItemMeta meta = item.getItemMeta();
if (meta == null) return;
if (!meta.getPersistentDataContainer().has(wandKey, PersistentDataType.BYTE)) return;
Player p = event.getPlayer();
if (!p.hasPermission("nexuslobby.portal")) {
p.sendMessage("§cDu hast keine Berechtigung, das Portal-Werkzeug zu benutzen.");
return;
}
event.setCancelled(true);
if (!event.hasBlock()) {
p.sendMessage("§cDu musst auf einen Block klicken!");
return;
}
Block clicked = event.getClickedBlock();
if (clicked == null) return;
Location clickedLoc = clicked.getLocation();
UUID uuid = p.getUniqueId();
selectionMap.putIfAbsent(uuid, new Location[2]);
if (event.getAction() == Action.LEFT_CLICK_BLOCK) {
selectionMap.get(uuid)[0] = clickedLoc;
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 2.0f);
p.sendMessage("§aPosition 1 gesetzt: " + clickedLoc.getBlockX() + ", " + clickedLoc.getBlockY() + ", " + clickedLoc.getBlockZ());
} else if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
selectionMap.get(uuid)[1] = clickedLoc;
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.0f);
p.sendMessage("§bPosition 2 gesetzt: " + clickedLoc.getBlockX() + ", " + clickedLoc.getBlockY() + ", " + clickedLoc.getBlockZ());
if (selectionMap.get(uuid)[0] != null) {
p.sendMessage("§eBenutze jetzt: /portal create <Name> <server|world>");
}
}
}
// --- Load / Save ---
private YamlConfiguration loadPortalConfig() {
java.io.File file = new java.io.File(plugin.getDataFolder(), "portals.yml");
if (!file.exists()) {
try {
plugin.getDataFolder().mkdirs();
file.createNewFile();
} catch (IOException e) {
plugin.getLogger().severe("Konnte portals.yml nicht anlegen: " + e.getMessage());
}
}
return YamlConfiguration.loadConfiguration(file);
}
/**
* Lädt alle Portale aus der Konfiguration.
* PUBLIC für den Zugriff durch NexusLobby.java beim Reload.
*/
public void loadPortals() {
// Liste leeren, um Duplikate beim Reload zu vermeiden
portals.clear();
YamlConfiguration portalConfig = loadPortalConfig();
ConfigurationSection section = portalConfig.getConfigurationSection("portals");
if (section == null) return;
for (String key : section.getKeys(false)) {
String type = portalConfig.getString("portals." + key + ".type", "WORLD");
Portal portal = new Portal(key, type);
if (portalConfig.contains("portals." + key + ".pos1")) {
portal.setPos1(portalConfig.getLocation("portals." + key + ".pos1"));
}
if (portalConfig.contains("portals." + key + ".pos2")) {
portal.setPos2(portalConfig.getLocation("portals." + key + ".pos2"));
}
portal.setDestination(portalConfig.getString("portals." + key + ".destination", ""));
try {
portal.setParticle(Particle.valueOf(portalConfig.getString("portals." + key + ".particle", "PORTAL")));
} catch (IllegalArgumentException ignored) {
portal.setParticle(Particle.PORTAL);
}
if (portalConfig.contains("portals." + key + ".returnSpawn")) {
portal.setReturnSpawn(portalConfig.getLocation("portals." + key + ".returnSpawn"));
}
portals.put(key, portal);
}
}
public void savePortals() {
YamlConfiguration config = loadPortalConfig();
config.set("portals", null);
for (Portal portal : portals.values()) {
String path = "portals." + portal.getName() + ".";
config.set(path + "type", portal.getType());
config.set(path + "pos1", portal.getPos1());
config.set(path + "pos2", portal.getPos2());
config.set(path + "destination", portal.getDestination());
config.set(path + "particle", portal.getParticle() != null ? portal.getParticle().name() : "PORTAL");
config.set(path + "returnSpawn", portal.getReturnSpawn());
}
try {
config.save(new java.io.File(plugin.getDataFolder(), "portals.yml"));
} catch (IOException e) {
plugin.getLogger().severe("Konnte portals.yml nicht speichern!");
e.printStackTrace();
}
}
// --- CRUD ---
public boolean createPortal(String name, String type, Player creator) {
Location[] sel = selectionMap.getOrDefault(creator.getUniqueId(), new Location[2]);
if (sel[0] != null && sel[1] != null) {
Portal portal = new Portal(name, type);
portal.setPos1(sel[0]);
portal.setPos2(sel[1]);
portals.put(name, portal);
savePortals();
selectionMap.remove(creator.getUniqueId());
creator.sendMessage("§aPortal '" + name + "' erstellt!");
return true;
}
creator.sendMessage("§cBitte markiere erst zwei Punkte mit dem Portal-Werkzeug!");
return false;
}
public boolean deletePortal(String name) {
if (portals.remove(name) != null) {
savePortals();
return true;
}
return false;
}
public boolean setPortalPos(String name, int pos, Location loc) {
Portal portal = portals.get(name);
if (portal == null) return false;
if (pos == 1) portal.setPos1(loc);
else portal.setPos2(loc);
savePortals();
return true;
}
public boolean setDestination(String name, String dest) {
Portal portal = portals.get(name);
if (portal == null) return false;
portal.setDestination(dest);
savePortals();
return true;
}
public boolean setParticle(String name, String particleName) {
Portal portal = portals.get(name);
if (portal == null) return false;
try {
portal.setParticle(Particle.valueOf(particleName.toUpperCase()));
savePortals();
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public boolean setPortalReturnSpawn(String name, Location loc) {
Portal portal = portals.get(name);
if (portal == null) return false;
portal.setReturnSpawn(loc);
savePortals();
return true;
}
// --- Particles ---
private void startParticleTask() {
particleTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
for (Portal portal : portals.values()) {
if (portal.getPos1() == null || portal.getPos2() == null) continue;
spawnParticles(portal);
}
}, 0L, 5L);
}
private void spawnParticles(Portal portal) {
Location min = getMinLocation(portal.getPos1(), portal.getPos2());
Location max = getMaxLocation(portal.getPos1(), portal.getPos2());
World world = portal.getPos1().getWorld();
if (world == null) return;
for (int i = 0; i < 30; i++) {
double x = min.getX() + 0.5 + (Math.random() * (max.getX() - min.getX()));
double y = min.getY() + 0.5 + (Math.random() * (max.getY() - min.getY()));
double z = min.getZ() + 0.5 + (Math.random() * (max.getZ() - min.getZ()));
world.spawnParticle(portal.getParticle(), new Location(world, x, y, z), 3, 0.1, 0.1, 0.1, 0);
}
}
// --- Teleport / Movement ---
@org.bukkit.event.EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if (event.getFrom().getX() == event.getTo().getX() &&
event.getFrom().getY() == event.getTo().getY() &&
event.getFrom().getZ() == event.getTo().getZ()) {
return;
}
Player player = event.getPlayer();
Location loc = player.getLocation();
for (Portal portal : portals.values()) {
if (portal.getPos1() == null || portal.getPos2() == null) continue;
if (!isInArea(loc, portal.getPos1(), portal.getPos2())) continue;
if (cooldowns.containsKey(player.getUniqueId()) &&
cooldowns.get(player.getUniqueId()) > System.currentTimeMillis()) {
continue;
}
executeTeleport(player, portal);
cooldowns.put(player.getUniqueId(), System.currentTimeMillis() + 2000);
break;
}
}
private void executeTeleport(Player player, Portal portal) {
if ("SERVER".equalsIgnoreCase(portal.getType())) {
String serverName = portal.getDestination();
player.sendMessage("§eVerbinde zum Server: " + serverName);
plugin.getLogger().info("Verbinde " + player.getName() + " -> " + serverName);
Location loc = portal.getReturnSpawn();
if (loc == null) {
Location pos2 = portal.getPos2();
loc = player.getLocation();
if (pos2 != null) {
double dx = loc.getX() - pos2.getX();
double dz = loc.getZ() - pos2.getZ();
double length = Math.sqrt(dx*dx + dz*dz);
if (length == 0) length = 1;
dx = (dx / length) * 2;
dz = (dz / length) * 2;
loc.add(dx, 0, dz);
} else {
loc.add(0,0,2);
}
}
player.teleport(loc);
connectToServer(player, serverName);
return;
}
String dest = portal.getDestination();
if (dest == null || dest.isEmpty()) {
player.sendMessage("§cDieses Portal hat kein Ziel gesetzt!");
return;
}
if ("SPAWN".equalsIgnoreCase(dest)) {
Location spawnLoc = getMainSpawnLocation();
if (spawnLoc != null) {
player.teleport(spawnLoc);
player.sendMessage("§aDu wurdest zum Spawn teleportiert!");
} else {
player.sendMessage("§cSpawn konnte nicht gefunden werden.");
}
return;
}
String[] parts = dest.split(";");
if (parts.length >= 4) {
World world = Bukkit.getWorld(parts[0]);
if (world == null) {
player.sendMessage("§cZielwelt nicht gefunden: " + parts[0]);
return;
}
try {
double x = Double.parseDouble(parts[1]);
double y = Double.parseDouble(parts[2]);
double z = Double.parseDouble(parts[3]);
float yaw = 0f, pitch = 0f;
if (parts.length >= 6) {
yaw = Float.parseFloat(parts[4]);
pitch = Float.parseFloat(parts[5]);
}
Location target = new Location(world, x, y, z, yaw, pitch);
player.teleport(target);
player.sendMessage("§aDu wurdest teleportiert!");
} catch (NumberFormatException e) {
player.sendMessage("§cUngültige Koordinaten im Portalziel!");
}
} else {
player.sendMessage("§cUngültiges Portalzielformat!");
}
}
private void connectToServer(Player player, String serverName) {
try {
if (!Bukkit.getMessenger().isOutgoingChannelRegistered(plugin, "BungeeCord")) {
plugin.getLogger().warning("BungeeCord outgoing channel not registered; cannot send plugin message.");
player.sendMessage("§cProxy-Verbindung nicht möglich: BungeeCord-Kanal nicht registriert.");
return;
}
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(b);
out.writeUTF("Connect");
out.writeUTF(serverName);
player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray());
} catch (IOException e) {
plugin.getLogger().severe("Fehler beim Senden der BungeeCord-Message: " + e.getMessage());
e.printStackTrace();
player.sendMessage("§cFehler beim Verbinden zum Proxy.");
} catch (RuntimeException e) {
plugin.getLogger().warning("Konnte Plugin-Message nicht senden: " + e.getMessage());
player.sendMessage("§cProxy-Verbindung nicht möglich.");
}
}
// --- Hilfsfunktionen ---
private Location getMainSpawnLocation() {
String worldName = plugin.getConfig().getString("spawn.world", null);
if (worldName != null) {
World w = Bukkit.getWorld(worldName);
if (w != null) {
double x = plugin.getConfig().getDouble("spawn.x", w.getSpawnLocation().getX());
double y = plugin.getConfig().getDouble("spawn.y", w.getSpawnLocation().getY());
double z = plugin.getConfig().getDouble("spawn.z", w.getSpawnLocation().getZ());
float yaw = (float) plugin.getConfig().getDouble("spawn.yaw", w.getSpawnLocation().getYaw());
float pitch = (float) plugin.getConfig().getDouble("spawn.pitch", w.getSpawnLocation().getPitch());
return new Location(w, x, y, z, yaw, pitch);
}
}
if (!Bukkit.getWorlds().isEmpty()) {
return Bukkit.getWorlds().get(0).getSpawnLocation();
}
return null;
}
private boolean isInArea(Location loc, Location loc1, Location loc2) {
if (loc == null || loc1 == null || loc2 == null) return false;
if (!loc.getWorld().equals(loc1.getWorld())) return false;
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
int headY = y + 1;
Location min = getMinLocation(loc1, loc2);
Location max = getMaxLocation(loc1, loc2);
boolean xMatch = (x >= min.getBlockX()) && (x <= max.getBlockX());
boolean zMatch = (z >= min.getBlockZ()) && (z <= max.getBlockZ());
boolean yMatch = (y >= min.getBlockY()) && (headY <= max.getBlockY());
return xMatch && yMatch && zMatch;
}
private Location getMinLocation(Location a, Location b) {
return new Location(a.getWorld(), Math.min(a.getX(), b.getX()),
Math.min(a.getY(), b.getY()), Math.min(a.getZ(), b.getZ()));
}
private Location getMaxLocation(Location a, Location b) {
return new Location(a.getWorld(), Math.max(a.getX(), b.getX()),
Math.max(a.getY(), b.getY()), Math.max(a.getZ(), b.getZ()));
}
}