Upload folder via GUI - src

This commit is contained in:
Git Manager GUI
2026-05-23 20:08:41 +02:00
parent 23e77d7204
commit f5b8717ad4
53 changed files with 2787 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
package de.teleportsuite;
import org.bukkit.ChatColor;
public class ConfigManager {
private final TeleportSuite plugin;
public ConfigManager(TeleportSuite plugin) { this.plugin = plugin; }
public boolean isBungeeEnabled() { return plugin.getConfig().getBoolean("bungee.enabled", false); }
public String getServerName() { return plugin.getConfig().getString("bungee.server-name", "local"); }
public int getTeleportDelay() { return plugin.getConfig().getInt("teleport.delay", 3); }
public int getTeleportCooldown() { return plugin.getConfig().getInt("teleport.cooldown", 5); }
public boolean cancelOnMove() { return plugin.getConfig().getBoolean("teleport.warmup-cancel-on-move", true); }
public int getRequestTimeout() { return plugin.getConfig().getInt("teleport.request-timeout", 60); }
public int getMaxHomes(String group) { return plugin.getConfig().getInt("homes.max-homes-" + group, 3); }
public boolean allowPlayerWarps() { return plugin.getConfig().getBoolean("warps.allow-player-warps", false); }
public boolean firstJoinTeleport() { return plugin.getConfig().getBoolean("spawn.first-join-teleport", true); }
public boolean deathRespawnToSpawn() { return plugin.getConfig().getBoolean("spawn.death-respawn-to-spawn", false); }
public String getMessage(String key) {
String prefix = plugin.getConfig().getString("messages.prefix", "&8[&6TP&8] &r");
String msg = plugin.getConfig().getString("messages." + key, "&cNachricht nicht gefunden: " + key);
return ChatColor.translateAlternateColorCodes('&', prefix + msg);
}
public String getMessage(String key, String... replacements) {
String msg = getMessage(key);
for (int i = 0; i < replacements.length - 1; i += 2) {
msg = msg.replace("{" + replacements[i] + "}", replacements[i+1]);
}
return msg;
}
}

View File

@@ -0,0 +1,106 @@
package de.teleportsuite;
import de.teleportsuite.commands.*;
import de.teleportsuite.database.DatabaseManager;
import de.teleportsuite.listeners.*;
import de.teleportsuite.managers.*;
import de.teleportsuite.bungeemessaging.BungeeMessenger;
import org.bukkit.plugin.java.JavaPlugin;
public class TeleportSuite extends JavaPlugin {
private static TeleportSuite instance;
private DatabaseManager databaseManager;
private HomeManager homeManager;
private WarpManager warpManager;
private PortalManager portalManager;
private TeleportManager teleportManager;
private SpawnManager spawnManager;
private SavePointManager savePointManager;
private BungeeMessenger bungeeMessenger;
private ConfigManager configManager;
@Override
public void onEnable() {
instance = this;
saveDefaultConfig();
configManager = new ConfigManager(this);
databaseManager = new DatabaseManager(this);
if (!databaseManager.connect()) {
getLogger().severe("Datenbankverbindung fehlgeschlagen! Plugin wird deaktiviert.");
getServer().getPluginManager().disablePlugin(this);
return;
}
databaseManager.createTables();
homeManager = new HomeManager(this);
warpManager = new WarpManager(this);
portalManager = new PortalManager(this);
teleportManager = new TeleportManager(this);
spawnManager = new SpawnManager(this);
savePointManager = new SavePointManager(this);
if (configManager.isBungeeEnabled()) {
bungeeMessenger = new BungeeMessenger(this);
bungeeMessenger.register();
getLogger().info("BungeeCord-Unterstuetzung aktiviert.");
}
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerDeathListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerMoveListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerRespawnListener(this), this);
getServer().getPluginManager().registerEvents(new PortalListener(this), this);
registerCommands();
getLogger().info("TeleportSuite v" + getDescription().getVersion() + " erfolgreich geladen!");
}
@Override
public void onDisable() {
if (databaseManager != null) databaseManager.disconnect();
if (bungeeMessenger != null) bungeeMessenger.unregister();
}
private void registerCommands() {
getCommand("tp").setExecutor(new TpCommand(this));
getCommand("tphere").setExecutor(new TpHereCommand(this));
getCommand("tpa").setExecutor(new TpaCommand(this));
getCommand("tpaccept").setExecutor(new TpAcceptCommand(this));
getCommand("tpdeny").setExecutor(new TpDenyCommand(this));
getCommand("tppos").setExecutor(new TpPosCommand(this));
getCommand("tpall").setExecutor(new TpAllCommand(this));
getCommand("tpworld").setExecutor(new TpWorldCommand(this));
getCommand("back").setExecutor(new BackCommand(this));
getCommand("deathback").setExecutor(new DeathBackCommand(this));
getCommand("sethome").setExecutor(new SetHomeCommand(this));
getCommand("home").setExecutor(new HomeCommand(this));
getCommand("delhome").setExecutor(new DelHomeCommand(this));
getCommand("homes").setExecutor(new HomesCommand(this));
getCommand("setwarp").setExecutor(new SetWarpCommand(this));
getCommand("warp").setExecutor(new WarpCommand(this));
getCommand("delwarp").setExecutor(new DelWarpCommand(this));
getCommand("warps").setExecutor(new WarpsCommand(this));
getCommand("setportal").setExecutor(new SetPortalCommand(this));
getCommand("delportal").setExecutor(new DelPortalCommand(this));
getCommand("portals").setExecutor(new PortalsCommand(this));
getCommand("setspawn").setExecutor(new SetSpawnCommand(this));
getCommand("spawn").setExecutor(new SpawnCommand(this));
getCommand("setfirstspawn").setExecutor(new SetFirstSpawnCommand(this));
getCommand("setsavepoint").setExecutor(new SetSavePointCommand(this));
getCommand("savepoint").setExecutor(new SavePointCommand(this));
getCommand("entitytransport").setExecutor(new EntityTransportCommand(this));
}
public static TeleportSuite getInstance() { return instance; }
public DatabaseManager getDatabaseManager() { return databaseManager; }
public HomeManager getHomeManager() { return homeManager; }
public WarpManager getWarpManager() { return warpManager; }
public PortalManager getPortalManager() { return portalManager; }
public TeleportManager getTeleportManager() { return teleportManager; }
public SpawnManager getSpawnManager() { return spawnManager; }
public SavePointManager getSavePointManager() { return savePointManager; }
public BungeeMessenger getBungeeMessenger() { return bungeeMessenger; }
public ConfigManager getConfigManager() { return configManager; }
}

View File

@@ -0,0 +1,38 @@
package de.teleportsuite.bungee;
import de.teleportsuite.bungee.listener.PlayerConnectionListener;
import de.teleportsuite.bungee.manager.TeleportMessageListener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
public class TeleportSuiteBungee extends Plugin {
public static final String CHANNEL_TO_BUNGEE = "teleportsuite:tobungee";
public static final String CHANNEL_TO_SPIGOT = "teleportsuite:tospigot";
private static TeleportSuiteBungee instance;
@Override
public void onEnable() {
instance = this;
PluginManager pm = getProxy().getPluginManager();
getProxy().registerChannel(CHANNEL_TO_BUNGEE);
getProxy().registerChannel(CHANNEL_TO_SPIGOT);
pm.registerListener(this, new TeleportMessageListener(this));
pm.registerListener(this, new PlayerConnectionListener(this));
getLogger().info("TeleportSuite-Bungee aktiviert.");
}
@Override
public void onDisable() {
getProxy().getScheduler().cancel(this);
getLogger().info("TeleportSuite-Bungee deaktiviert.");
}
public static TeleportSuiteBungee getInstance() {
return instance;
}
}

View File

@@ -0,0 +1,58 @@
package de.teleportsuite.bungee.listener;
import de.teleportsuite.bungee.TeleportSuiteBungee;
import de.teleportsuite.bungee.manager.PendingTpa;
import de.teleportsuite.bungee.manager.TeleportMessageListener;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.io.*;
/**
* Cleans up pending TPA requests when a player disconnects.
*/
public class PlayerConnectionListener implements Listener {
private final TeleportSuiteBungee plugin;
public PlayerConnectionListener(TeleportSuiteBungee plugin) {
this.plugin = plugin;
}
@EventHandler
public void onDisconnect(PlayerDisconnectEvent event) {
String name = event.getPlayer().getName();
// Player was a requester
PendingTpa tpa = TeleportMessageListener.getPendingTpa().remove(name);
if (tpa != null) {
notifyOther(tpa.getToName(), name);
return;
}
// Player was a target — find the requester
TeleportMessageListener.getPendingTpa().entrySet().removeIf(entry -> {
if (entry.getValue().getToName().equalsIgnoreCase(name)) {
notifyOther(entry.getValue().getFromName(), name);
return true;
}
return false;
});
}
private void notifyOther(String otherName, String disconnectedName) {
ProxiedPlayer other = plugin.getProxy().getPlayer(otherName);
if (other == null || other.getServer() == null) return;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos)) {
out.writeUTF("SEND_MSG");
out.writeUTF(otherName);
out.writeUTF("§cDeine TPA-Anfrage wurde abgebrochen, da §6" + disconnectedName + " §cdas Netzwerk verlassen hat.");
other.getServer().sendData(TeleportSuiteBungee.CHANNEL_TO_SPIGOT, bos.toByteArray());
} catch (IOException e) {
plugin.getLogger().warning("Disconnect-Benachrichtigung fehlgeschlagen: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,23 @@
package de.teleportsuite.bungee.manager;
/**
* Represents a pending cross-server TPA request.
*/
public class PendingTpa {
public enum Type { TPTO, TPHERE }
private final String fromName;
private final String toName;
private final Type type;
public PendingTpa(String fromName, String toName, Type type) {
this.fromName = fromName;
this.toName = toName;
this.type = type;
}
public String getFromName() { return fromName; }
public String getToName() { return toName; }
public Type getType() { return type; }
}

View File

@@ -0,0 +1,413 @@
package de.teleportsuite.bungee.manager;
import de.teleportsuite.bungee.TeleportSuiteBungee;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Receives plugin messages from Spigot servers on CHANNEL_TO_BUNGEE,
* performs the cross-server operation (connect + forward), and sends
* results back on CHANNEL_TO_SPIGOT.
*
* Payload identifiers (first UTF written by Spigot):
*
* TP_PLAYER teleport sender to a named target player
* TP_POS teleport player to fixed coordinates on a server
* TP_HERE pull a remote player to the sender's location
* TP_ALL pull all network players to sender
* TPA_REQUEST forward "you have a TPA request" to target
* TPA_ACCEPT accept pending TPA; trigger the actual teleport
* TPA_DENY deny pending TPA; notify requester
* TPA_CANCEL requester cancels their own pending request
* TPA_EXPIRED timeout: notify both parties
* SEND_MSG route a chat message to a player on any server
*/
public class TeleportMessageListener implements Listener {
// fromName → pending request
private static final Map<String, PendingTpa> pendingTpa = new HashMap<>();
private final TeleportSuiteBungee plugin;
public TeleportMessageListener(TeleportSuiteBungee plugin) {
this.plugin = plugin;
}
public static Map<String, PendingTpa> getPendingTpa() {
return pendingTpa;
}
// -------------------------------------------------------------------------
// Incoming messages from Spigot
// -------------------------------------------------------------------------
@EventHandler
public void onPluginMessage(PluginMessageEvent event) throws IOException {
if (event.isCancelled()) return;
if (!(event.getSender() instanceof Server)) return;
if (!event.getTag().equals(TeleportSuiteBungee.CHANNEL_TO_BUNGEE)) return;
DataInputStream in = new DataInputStream(new ByteArrayInputStream(event.getData()));
String task = in.readUTF();
switch (task) {
// ------------------------------------------------------------------
// /tp <target> → teleport sender directly to target player
// ------------------------------------------------------------------
case "TP_PLAYER": {
String senderName = in.readUTF();
String targetName = in.readUTF();
ProxiedPlayer sender = plugin.getProxy().getPlayer(senderName);
ProxiedPlayer target = plugin.getProxy().getPlayer(targetName);
if (sender == null) return;
if (target == null) {
sendMsg(sender, "§cSpieler §6" + targetName + " §cnicht gefunden.");
return;
}
teleportPlayerToPlayer(sender, target, 50);
break;
}
// ------------------------------------------------------------------
// /tp <from> <to> → teleport another player to a target player
// ------------------------------------------------------------------
case "TP_PLAYER_TO_PLAYER": {
String requesterName = in.readUTF();
String fromName = in.readUTF();
String targetName = in.readUTF();
ProxiedPlayer requester = plugin.getProxy().getPlayer(requesterName);
ProxiedPlayer from = plugin.getProxy().getPlayer(fromName);
ProxiedPlayer target = plugin.getProxy().getPlayer(targetName);
if (requester == null) return;
if (from == null || target == null) {
sendMsg(requester, "§cEin Spieler wurde nicht gefunden.");
return;
}
teleportPlayerToPlayer(from, target, 50);
break;
}
// ------------------------------------------------------------------
// /tphere <target> → pull target to sender's location
// ------------------------------------------------------------------
case "TP_HERE": {
String senderName = in.readUTF();
String targetName = in.readUTF();
ProxiedPlayer sender = plugin.getProxy().getPlayer(senderName);
ProxiedPlayer target = plugin.getProxy().getPlayer(targetName);
if (sender == null) return;
if (target == null) {
sendMsg(sender, "§cSpieler §6" + targetName + " §cnicht gefunden.");
return;
}
teleportPlayerToPlayer(target, sender, 50);
break;
}
// ------------------------------------------------------------------
// /tpall → pull every player on the network to sender
// ------------------------------------------------------------------
case "TP_ALL": {
String senderName = in.readUTF();
ProxiedPlayer sender = plugin.getProxy().getPlayer(senderName);
if (sender == null) return;
for (ProxiedPlayer p : plugin.getProxy().getPlayers()) {
if (!p.getName().equals(senderName)) {
teleportPlayerToPlayer(p, sender, 50);
}
}
break;
}
// ------------------------------------------------------------------
// /home, /warp, /spawn, /back, /savepoint, /portal, /tppos …
// Spigot already knows the coordinates; we just switch the server
// and tell that server where to put the player.
// ------------------------------------------------------------------
case "TP_POS": {
String playerName = in.readUTF();
String server = in.readUTF();
String world = in.readUTF();
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
float yaw = in.readFloat(), pitch = in.readFloat();
ProxiedPlayer player = plugin.getProxy().getPlayer(playerName);
if (player == null) return;
teleportPlayerToPosition(player, server, world, x, y, z, yaw, pitch, 100);
break;
}
// ------------------------------------------------------------------
// TPA: requester asks target for a teleport
// ------------------------------------------------------------------
case "TPA_REQUEST": {
String fromName = in.readUTF();
String toName = in.readUTF();
String type = in.readUTF(); // TPTO or TPHERE
String msgToTarget = in.readUTF();
String msgToRequester = in.readUTF();
ProxiedPlayer from = plugin.getProxy().getPlayer(fromName);
ProxiedPlayer to = plugin.getProxy().getPlayer(toName);
if (from == null) return;
if (to == null) {
sendMsg(from, "§cSpieler §6" + toName + " §cnicht gefunden.");
return;
}
// Check for existing pending request
if (pendingTpa.containsKey(fromName)) {
sendMsg(from, "§cDu hast bereits eine offene Anfrage.");
return;
}
pendingTpa.put(fromName, new PendingTpa(fromName, toName, PendingTpa.Type.valueOf(type)));
// Notify both players — via their respective servers
sendMsgToServer(from.getServer().getInfo(), fromName, msgToRequester);
sendMsgToServer(to.getServer().getInfo(), toName, msgToTarget);
break;
}
// ------------------------------------------------------------------
// TPA: target accepts → trigger the actual teleport
// ------------------------------------------------------------------
case "TPA_ACCEPT": {
String toName = in.readUTF(); // player who accepted
String fromName = in.readUTF(); // original requester (may be "nu" = any)
String errMsg = in.readUTF();
PendingTpa tpa = resolvePending(fromName, toName);
if (tpa == null) {
ProxiedPlayer to = plugin.getProxy().getPlayer(toName);
if (to != null) sendMsg(to, errMsg);
return;
}
pendingTpa.remove(tpa.getFromName());
ProxiedPlayer from = plugin.getProxy().getPlayer(tpa.getFromName());
ProxiedPlayer to = plugin.getProxy().getPlayer(tpa.getToName());
if (from == null || to == null) return;
if (tpa.getType() == PendingTpa.Type.TPTO) {
teleportPlayerToPlayer(from, to, 50);
} else {
teleportPlayerToPlayer(to, from, 50);
}
break;
}
// ------------------------------------------------------------------
// TPA: target denies → notify requester
// ------------------------------------------------------------------
case "TPA_DENY": {
String toName = in.readUTF();
String fromName = in.readUTF();
String msg = in.readUTF();
PendingTpa tpa = resolvePending(fromName, toName);
if (tpa == null) return;
pendingTpa.remove(tpa.getFromName());
ProxiedPlayer from = plugin.getProxy().getPlayer(tpa.getFromName());
ProxiedPlayer to = plugin.getProxy().getPlayer(tpa.getToName());
if (from != null) sendMsg(from, msg);
if (to != null) sendMsg(to, msg);
break;
}
// ------------------------------------------------------------------
// TPA: requester cancels their own request
// ------------------------------------------------------------------
case "TPA_CANCEL": {
String fromName = in.readUTF();
String msgFrom = in.readUTF();
String msgTo = in.readUTF();
PendingTpa tpa = pendingTpa.remove(fromName);
if (tpa == null) return;
ProxiedPlayer from = plugin.getProxy().getPlayer(fromName);
ProxiedPlayer to = plugin.getProxy().getPlayer(tpa.getToName());
if (from != null) sendMsg(from, msgFrom);
if (to != null) sendMsg(to, msgTo);
break;
}
// ------------------------------------------------------------------
// TPA: timeout — remove pending and notify both sides
// ------------------------------------------------------------------
case "TPA_EXPIRED": {
String fromName = in.readUTF();
String toName = in.readUTF();
String msgFrom = in.readUTF();
String msgTo = in.readUTF();
pendingTpa.remove(fromName);
ProxiedPlayer from = plugin.getProxy().getPlayer(fromName);
ProxiedPlayer to = plugin.getProxy().getPlayer(toName);
if (from != null) sendMsg(from, msgFrom);
if (to != null) sendMsg(to, msgTo);
break;
}
// ------------------------------------------------------------------
// Generic cross-server message routing
// ------------------------------------------------------------------
case "SEND_MSG": {
String targetName = in.readUTF();
String message = in.readUTF();
ProxiedPlayer target = plugin.getProxy().getPlayer(targetName);
if (target != null) sendMsg(target, message);
break;
}
default:
plugin.getLogger().warning("Unbekannter Task: " + task);
}
}
// -------------------------------------------------------------------------
// Core teleport helpers — the BTM way
// -------------------------------------------------------------------------
/**
* Moves {@code sender} to {@code target}'s current server (if needed),
* then after a short delay tells the target server to do the final
* player.teleport(target) call via TP_PLAYERTOPLAYER.
*
* This is done entirely on the Bungee side:
* 1. sender.connect(target.server) — BungeeCord switches the server
* 2. delay ms later: server.sendData(TP_PLAYERTOPLAYER, ...)
* → Spigot polls until both players are on the same server and teleports
*/
private void teleportPlayerToPlayer(ProxiedPlayer sender, ProxiedPlayer target, int delayMs) {
plugin.getProxy().getScheduler().schedule(plugin, () -> {
if (sender == null || target == null) return;
if (sender.getServer() == null || target.getServer() == null) return;
// Switch server if needed
if (!sender.getServer().getInfo().getName()
.equals(target.getServer().getInfo().getName())) {
sender.connect(target.getServer().getInfo());
}
// Tell the target server to teleport sender → target
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos)) {
out.writeUTF("TP_PLAYERTOPLAYER");
out.writeUTF(sender.getName());
out.writeUTF(target.getName());
target.getServer().sendData(TeleportSuiteBungee.CHANNEL_TO_SPIGOT, bos.toByteArray());
} catch (IOException e) {
plugin.getLogger().warning("TP_PLAYERTOPLAYER Fehler: " + e.getMessage());
}
}, delayMs, TimeUnit.MILLISECONDS);
}
/**
* Moves {@code player} to {@code server}, then after a delay sends
* TP_PLAYERTOPOSITION so Spigot teleports them to exact coordinates.
*/
private void teleportPlayerToPosition(ProxiedPlayer player, String server,
String world, double x, double y, double z,
float yaw, float pitch, int delayMs) {
if (!plugin.getProxy().getServers().containsKey(server)) {
sendMsg(player, "§cServer §6" + server + " §cnicht gefunden.");
return;
}
// Switch server if needed
if (!player.getServer().getInfo().getName().equals(server)) {
player.connect(plugin.getProxy().getServerInfo(server));
}
// After delay, tell the (now correct) server where to put the player
plugin.getProxy().getScheduler().schedule(plugin, () -> {
if (player.getServer() == null) return;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos)) {
out.writeUTF("TP_PLAYERTOPOSITION");
out.writeUTF(player.getName());
out.writeUTF(world);
out.writeDouble(x);
out.writeDouble(y);
out.writeDouble(z);
out.writeFloat(yaw);
out.writeFloat(pitch);
player.getServer().sendData(TeleportSuiteBungee.CHANNEL_TO_SPIGOT, bos.toByteArray());
} catch (IOException e) {
plugin.getLogger().warning("TP_PLAYERTOPOSITION Fehler: " + e.getMessage());
}
}, delayMs, TimeUnit.MILLISECONDS);
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
/** Resolves which pending TPA entry matches an accept/deny. */
private PendingTpa resolvePending(String fromName, String toName) {
// Exact match
if (!fromName.equals("nu") && pendingTpa.containsKey(fromName)) {
return pendingTpa.get(fromName);
}
// Find by target name only
for (PendingTpa tpa : pendingTpa.values()) {
if (tpa.getToName().equalsIgnoreCase(toName)) {
return tpa;
}
}
return null;
}
/** Sends a formatted chat message directly to a ProxiedPlayer. */
private void sendMsg(ProxiedPlayer player, String message) {
player.sendMessage(net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', message));
}
/**
* Routes a chat message to a named player via their Spigot server.
* The Spigot side handles the actual sendMessage() call.
*/
private void sendMsgToServer(net.md_5.bungee.api.config.ServerInfo server,
String playerName, String message) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos)) {
out.writeUTF("SEND_MSG");
out.writeUTF(playerName);
out.writeUTF(message);
server.sendData(TeleportSuiteBungee.CHANNEL_TO_SPIGOT, bos.toByteArray());
} catch (IOException e) {
plugin.getLogger().warning("SEND_MSG Fehler: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,277 @@
package de.teleportsuite.bungeemessaging;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.io.*;
/**
* Spigot-seitiger Kanal zum TeleportSuite-Bungee-Plugin.
*
* Prinzip (identisch zu BTM):
* Spigot schickt Anfragen auf CHANNEL_TO_BUNGEE.
* BungeeCord erledigt connect() + routing und schickt Befehle auf CHANNEL_TO_SPIGOT.
* Spigot führt den finalen player.teleport() aus.
*
* Payloads Spigot → Bungee (CHANNEL_TO_BUNGEE):
* TP_PLAYER senderName, targetName
* TP_PLAYER_TO_PLAYER requesterName, fromName, toName
* TP_HERE senderName, targetName
* TP_ALL senderName
* TP_POS playerName, server, world, x, y, z, yaw, pitch
* TPA_REQUEST fromName, toName, type, msgToTarget, msgToRequester
* TPA_ACCEPT toName, fromName, errMsg
* TPA_DENY toName, fromName, msg
* TPA_CANCEL fromName, msgFrom, msgTo
* TPA_EXPIRED fromName, toName, msgFrom, msgTo
* SEND_MSG targetName, message
*
* Payloads Bungee → Spigot (CHANNEL_TO_SPIGOT):
* TP_PLAYERTOPLAYER senderName, targetName
* TP_PLAYERTOPOSITION playerName, world, x, y, z, yaw, pitch
* SEND_MSG playerName, message
*/
public class BungeeMessenger implements PluginMessageListener {
public static final String CHANNEL_TO_BUNGEE = "teleportsuite:tobungee";
public static final String CHANNEL_TO_SPIGOT = "teleportsuite:tospigot";
private final TeleportSuite plugin;
public BungeeMessenger(TeleportSuite plugin) {
this.plugin = plugin;
}
public void register() {
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, CHANNEL_TO_BUNGEE);
plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, CHANNEL_TO_SPIGOT, this);
}
public void unregister() {
plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin, CHANNEL_TO_BUNGEE);
plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin, CHANNEL_TO_SPIGOT, this);
}
// -------------------------------------------------------------------------
// Outgoing helpers (Spigot → Bungee)
// -------------------------------------------------------------------------
/** /tp <target> Absender teleportiert sich zum Zielspieler */
public void teleportToPlayer(Player sender, String targetName) {
send(sender, out -> {
out.writeUTF("TP_PLAYER");
out.writeUTF(sender.getName());
out.writeUTF(targetName);
});
}
/** /tp <from> <to> Admin teleportiert einen Spieler zu einem anderen */
public void teleportPlayerToPlayer(Player requester, String fromName, String targetName) {
send(requester, out -> {
out.writeUTF("TP_PLAYER_TO_PLAYER");
out.writeUTF(requester.getName());
out.writeUTF(fromName);
out.writeUTF(targetName);
});
}
/** /tphere <target> Zielspieler wird zu Absender geholt */
public void teleportHere(Player sender, String targetName) {
send(sender, out -> {
out.writeUTF("TP_HERE");
out.writeUTF(sender.getName());
out.writeUTF(targetName);
});
}
/** /tpall Alle Netzwerkspieler zum Absender teleportieren */
public void teleportAll(Player sender) {
send(sender, out -> {
out.writeUTF("TP_ALL");
out.writeUTF(sender.getName());
});
}
/**
* Home / Warp / Spawn / Back / SavePoint / Portal / TpPos:
* Koordinaten sind bekannt → Bungee wechselt den Server und Spigot
* setzt den Spieler direkt an die exakten Koordinaten.
*/
public void teleportToPosition(Player player, String server, String world,
double x, double y, double z, float yaw, float pitch) {
send(player, out -> {
out.writeUTF("TP_POS");
out.writeUTF(player.getName());
out.writeUTF(server);
out.writeUTF(world);
out.writeDouble(x);
out.writeDouble(y);
out.writeDouble(z);
out.writeFloat(yaw);
out.writeFloat(pitch);
});
}
// TPA
public void sendTpaRequest(Player from, String toName,
String type, String msgToTarget, String msgToRequester) {
send(from, out -> {
out.writeUTF("TPA_REQUEST");
out.writeUTF(from.getName());
out.writeUTF(toName);
out.writeUTF(type);
out.writeUTF(msgToTarget);
out.writeUTF(msgToRequester);
});
}
public void sendTpaAccept(Player acceptor, String fromName, String errMsg) {
send(acceptor, out -> {
out.writeUTF("TPA_ACCEPT");
out.writeUTF(acceptor.getName());
out.writeUTF(fromName == null ? "nu" : fromName);
out.writeUTF(errMsg);
});
}
public void sendTpaDeny(Player denier, String fromName, String msg) {
send(denier, out -> {
out.writeUTF("TPA_DENY");
out.writeUTF(denier.getName());
out.writeUTF(fromName == null ? "nu" : fromName);
out.writeUTF(msg);
});
}
public void sendTpaCancel(Player canceller, String msgFrom, String msgTo) {
send(canceller, out -> {
out.writeUTF("TPA_CANCEL");
out.writeUTF(canceller.getName());
out.writeUTF(msgFrom);
out.writeUTF(msgTo);
});
}
public void sendTpaExpired(Player from, String toName, String msgFrom, String msgTo) {
send(from, out -> {
out.writeUTF("TPA_EXPIRED");
out.writeUTF(from.getName());
out.writeUTF(toName);
out.writeUTF(msgFrom);
out.writeUTF(msgTo);
});
}
// -------------------------------------------------------------------------
// Incoming handler (Bungee → Spigot)
// -------------------------------------------------------------------------
@Override
public void onPluginMessageReceived(String channel, Player unused, byte[] bytes) {
if (!channel.equals(CHANNEL_TO_SPIGOT)) return;
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes))) {
String task = in.readUTF();
switch (task) {
// Bungee hat sender bereits auf diesen Server gewechselt.
// Sobald beide Spieler lokal online sind, teleportieren.
case "TP_PLAYERTOPLAYER": {
String senderName = in.readUTF();
String targetName = in.readUTF();
schedulePlayerToPlayerTeleport(senderName, targetName);
break;
}
// Bungee hat player bereits auf diesen Server gewechselt.
// Nach kurzem Delay an exakte Koordinaten teleportieren.
case "TP_PLAYERTOPOSITION": {
String playerName = in.readUTF();
String world = in.readUTF();
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
float yaw = in.readFloat(), pitch = in.readFloat();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
org.bukkit.entity.Player p = plugin.getServer().getPlayerExact(playerName);
if (p == null || !p.isOnline()) return;
TeleportLocation loc = new TeleportLocation(
world, x, y, z, yaw, pitch,
plugin.getConfigManager().getServerName());
plugin.getTeleportManager().teleport(p, loc, false);
}, 10L);
break;
}
// Direkte Chat-Nachricht an einen lokalen Spieler
case "SEND_MSG": {
String playerName = in.readUTF();
String message = in.readUTF();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
org.bukkit.entity.Player p = plugin.getServer().getPlayerExact(playerName);
if (p != null && p.isOnline()) p.sendMessage(message);
}, 1L);
break;
}
default:
plugin.getLogger().warning("Unbekannter Bungee-Task: " + task);
}
} catch (IOException e) {
plugin.getLogger().warning("Fehler beim Lesen der Bungee-Nachricht: " + e.getMessage());
}
}
// -------------------------------------------------------------------------
// Internal helpers
// -------------------------------------------------------------------------
/**
* Wartet bis sender UND target lokal online sind (max. 100 × 10 Ticks = 50 s),
* dann führt player.teleport() aus identisch zum BTM-Ansatz.
*/
private void schedulePlayerToPlayerTeleport(String senderName, String targetName) {
final int[] attempts = {0};
final int[] taskId = {-1};
taskId[0] = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
attempts[0]++;
org.bukkit.entity.Player sender = plugin.getServer().getPlayerExact(senderName);
org.bukkit.entity.Player target = plugin.getServer().getPlayerExact(targetName);
if (sender != null && sender.isOnline() && target != null && target.isOnline()) {
plugin.getTeleportManager().teleport(
sender,
new TeleportLocation(target.getLocation(),
plugin.getConfigManager().getServerName()),
false);
plugin.getServer().getScheduler().cancelTask(taskId[0]);
return;
}
if (attempts[0] >= 100) {
plugin.getServer().getScheduler().cancelTask(taskId[0]);
}
}, 5L, 10L);
}
@FunctionalInterface
private interface IOWriter {
void write(DataOutputStream out) throws IOException;
}
/** Schreibt ein Payload und schickt es über den Bungee-Kanal. */
private void send(Player anchor, IOWriter writer) {
if (anchor == null || !anchor.isOnline()) return;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos)) {
writer.write(out);
anchor.sendPluginMessage(plugin, CHANNEL_TO_BUNGEE, bos.toByteArray());
} catch (IOException e) {
plugin.getLogger().warning("Bungee-Send Fehler: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,22 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class BackCommand implements CommandExecutor {
private final TeleportSuite plugin;
public BackCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.back")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
TeleportLocation loc = plugin.getDatabaseManager().getLastLocation(p.getUniqueId());
if (loc == null) { p.sendMessage(plugin.getConfigManager().getMessage("back-no-location")); return true; }
plugin.getTeleportManager().teleport(p, loc, false);
return true;
}
}

View File

@@ -0,0 +1,22 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class DeathBackCommand implements CommandExecutor {
private final TeleportSuite plugin;
public DeathBackCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.deathback")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
TeleportLocation loc = plugin.getDatabaseManager().getDeathLocation(p.getUniqueId());
if (loc == null) { p.sendMessage(plugin.getConfigManager().getMessage("death-no-location")); return true; }
plugin.getTeleportManager().teleport(p, loc);
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class DelHomeCommand implements CommandExecutor {
private final TeleportSuite plugin;
public DelHomeCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.sethome")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /delhome <name>"); return true; }
plugin.getHomeManager().deleteHome(p, args[0]);
return true;
}
}

View File

@@ -0,0 +1,15 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
public class DelPortalCommand implements CommandExecutor {
private final TeleportSuite plugin;
public DelPortalCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission("teleportsuite.delportal")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { sender.sendMessage("§cVerwendung: /delportal <name>"); return true; }
boolean deleted = plugin.getPortalManager().deletePortal(args[0]);
sender.sendMessage(deleted ? plugin.getConfigManager().getMessage("portal-deleted","name",args[0]) : "§cPortal nicht gefunden.");
return true;
}
}

View File

@@ -0,0 +1,16 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class DelWarpCommand implements CommandExecutor {
private final TeleportSuite plugin;
public DelWarpCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission("teleportsuite.delwarp")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { sender.sendMessage("§cVerwendung: /delwarp <name>"); return true; }
boolean deleted = plugin.getWarpManager().deleteWarp(args[0]);
sender.sendMessage(deleted ? plugin.getConfigManager().getMessage("warp-deleted","name",args[0]) : plugin.getConfigManager().getMessage("warp-not-found","name",args[0]));
return true;
}
}

View File

@@ -0,0 +1,30 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.*;
public class EntityTransportCommand implements CommandExecutor {
private final TeleportSuite plugin;
public EntityTransportCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission("teleportsuite.entitytransport")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 2) { sender.sendMessage("§cVerwendung: /entitytransport <entity-id> <spieler>"); return true; }
try {
int entityId = Integer.parseInt(args[0]);
Player target = Bukkit.getPlayer(args[1]);
if (target == null) { sender.sendMessage(plugin.getConfigManager().getMessage("player-not-found","player",args[1])); return true; }
Entity found = null;
for (var world : Bukkit.getWorlds()) {
for (var entity : world.getEntities()) {
if (entity.getEntityId() == entityId) { found = entity; break; }
}
if (found != null) break;
}
if (found == null) { sender.sendMessage("§cEntity mit ID §6" + entityId + " §cnicht gefunden."); return true; }
found.teleport(target.getLocation());
sender.sendMessage("§aEntity §6" + found.getType() + " §awurde zu §6" + target.getName() + " §ateleportiert.");
} catch (NumberFormatException e) { sender.sendMessage("§cUngültige Entity-ID."); }
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class HomeCommand implements CommandExecutor {
private final TeleportSuite plugin;
public HomeCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.home")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
String name = args.length > 0 ? args[0] : "home";
plugin.getHomeManager().teleportHome(p, name);
return true;
}
}

View File

@@ -0,0 +1,20 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.Home;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import java.util.List;
public class HomesCommand implements CommandExecutor {
private final TeleportSuite plugin;
public HomesCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
List<Home> homes = plugin.getHomeManager().getHomes(p.getUniqueId());
if (homes.isEmpty()) { p.sendMessage("§eKeine Homes gesetzt."); return true; }
p.sendMessage("§6Deine Homes §8(" + homes.size() + "/" + plugin.getHomeManager().getMaxHomes(p) + ")§6:");
homes.forEach(h -> p.sendMessage("§7- §a" + h.getName() + " §7(" + h.getLocation().getWorld() + ")"));
return true;
}
}

View File

@@ -0,0 +1,16 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
public class PortalsCommand implements CommandExecutor {
private final TeleportSuite plugin;
public PortalsCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission("teleportsuite.portals")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
var portals = plugin.getPortalManager().getPortals();
if (portals.isEmpty()) { sender.sendMessage("§eKeine Portale vorhanden."); return true; }
sender.sendMessage("§6Portale §8(" + portals.size() + ")§6:");
portals.forEach(p2 -> sender.sendMessage("§7- §a" + p2.getName() + " §7→ §e" + (p2.getTargetServer() != null ? p2.getTargetServer() + "/" : "") + p2.getDestination().getWorld()));
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SavePointCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SavePointCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.savepoint")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
String name = args.length > 0 ? args[0] : "default";
plugin.getSavePointManager().teleportToSavePoint(p, name);
return true;
}
}

View File

@@ -0,0 +1,15 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetFirstSpawnCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetFirstSpawnCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
if (!sender.hasPermission("teleportsuite.setfirstspawn")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
plugin.getSpawnManager().setFirstSpawn((Player) sender);
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetHomeCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetHomeCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.sethome")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
String name = args.length > 0 ? args[0] : "home";
plugin.getHomeManager().setHome(p, name);
return true;
}
}

View File

@@ -0,0 +1,28 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetPortalCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetPortalCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.setportal")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
// /setportal pos1 | pos2 | create <name> <server> <world> <x> <y> <z>
if (args.length == 0) { p.sendMessage("§cVerwendung: /setportal pos1|pos2|create <name> [server] <world> <x> <y> <z>"); return true; }
if (args[0].equalsIgnoreCase("pos1")) { plugin.getPortalManager().setPos1(p, p.getLocation()); return true; }
if (args[0].equalsIgnoreCase("pos2")) { plugin.getPortalManager().setPos2(p, p.getLocation()); return true; }
if (args[0].equalsIgnoreCase("create") && args.length >= 7) {
String name = args[1], server = args[2], world = args[3];
try {
double x = Double.parseDouble(args[4]), y = Double.parseDouble(args[5]), z = Double.parseDouble(args[6]);
plugin.getPortalManager().createPortal(p, name, server, world, x, y, z);
} catch (NumberFormatException e) { p.sendMessage("§cUngültige Koordinaten!"); }
return true;
}
p.sendMessage("§cVerwendung: /setportal pos1|pos2|create <name> <server> <world> <x> <y> <z>");
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetSavePointCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetSavePointCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.savepoint")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
String name = args.length > 0 ? args[0] : "default";
plugin.getSavePointManager().setSavePoint(p, name);
return true;
}
}

View File

@@ -0,0 +1,15 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetSpawnCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetSpawnCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
if (!sender.hasPermission("teleportsuite.setspawn")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
plugin.getSpawnManager().setSpawn((Player) sender);
return true;
}
}

View File

@@ -0,0 +1,20 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SetWarpCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SetWarpCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
boolean isAdmin = p.hasPermission("teleportsuite.setwarp");
boolean playerWarps = plugin.getConfigManager().allowPlayerWarps() && p.hasPermission("teleportsuite.setwarp.player");
if (!isAdmin && !playerWarps) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /setwarp <name> [permission]"); return true; }
String perm = args.length > 1 ? args[1] : null;
plugin.getWarpManager().setWarp(p, args[0], perm);
return true;
}
}

View File

@@ -0,0 +1,15 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class SpawnCommand implements CommandExecutor {
private final TeleportSuite plugin;
public SpawnCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
if (!sender.hasPermission("teleportsuite.spawn")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
plugin.getSpawnManager().teleportToSpawn((Player) sender);
return true;
}
}

View File

@@ -0,0 +1,19 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpAcceptCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpAcceptCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!plugin.getTeleportManager().acceptTpa(p))
p.sendMessage("§cKeine ausstehende Teleportanfrage.");
return true;
}
}

View File

@@ -0,0 +1,27 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpAllCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpAllCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tpall")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (plugin.getConfigManager().isBungeeEnabled() && plugin.getBungeeMessenger() != null) {
plugin.getBungeeMessenger().teleportAll(p);
} else {
TeleportLocation dest = new TeleportLocation(p.getLocation(), plugin.getConfigManager().getServerName());
for (Player online : plugin.getServer().getOnlinePlayers()) {
if (!online.equals(p)) plugin.getTeleportManager().teleport(online, dest);
}
}
return true;
}
}

View File

@@ -0,0 +1,43 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tp")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /tp <spieler> [spieler2]"); return true; }
if (args.length == 1) {
Player target = Bukkit.getPlayer(args[0]);
if (target != null) {
plugin.getTeleportManager().teleport(p, new TeleportLocation(target.getLocation(), plugin.getConfigManager().getServerName()));
} else if (plugin.getConfigManager().isBungeeEnabled() && plugin.getBungeeMessenger() != null) {
plugin.getBungeeMessenger().teleportToPlayer(p, args[0]);
} else {
p.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", args[0]));
}
} else {
if (!p.hasPermission("teleportsuite.admin")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
Player from = Bukkit.getPlayer(args[0]);
Player to = Bukkit.getPlayer(args[1]);
if (from != null && to != null) {
plugin.getTeleportManager().teleport(from, new TeleportLocation(to.getLocation(), plugin.getConfigManager().getServerName()));
} else if (plugin.getConfigManager().isBungeeEnabled() && plugin.getBungeeMessenger() != null) {
plugin.getBungeeMessenger().teleportPlayerToPlayer(p, args[0], args[1]);
} else {
p.sendMessage("§cEin Spieler nicht gefunden.");
}
}
return true;
}
}

View File

@@ -0,0 +1,19 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpDenyCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpDenyCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!plugin.getTeleportManager().denyTpa(p))
p.sendMessage("§cKeine ausstehende Teleportanfrage.");
return true;
}
}

View File

@@ -0,0 +1,29 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpHereCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpHereCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tphere")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /tphere <spieler>"); return true; }
Player target = Bukkit.getPlayer(args[0]);
if (target != null) {
plugin.getTeleportManager().teleport(target, new TeleportLocation(p.getLocation(), plugin.getConfigManager().getServerName()));
} else if (plugin.getConfigManager().isBungeeEnabled() && plugin.getBungeeMessenger() != null) {
plugin.getBungeeMessenger().teleportHere(p, args[0]);
} else {
p.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", args[0]));
}
return true;
}
}

View File

@@ -0,0 +1,22 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpPosCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpPosCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tppos")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 3) { p.sendMessage("§cVerwendung: /tppos <x> <y> <z> [world]"); return true; }
try {
double x = Double.parseDouble(args[0]), y = Double.parseDouble(args[1]), z = Double.parseDouble(args[2]);
String world = args.length > 3 ? args[3] : p.getWorld().getName();
plugin.getTeleportManager().teleport(p, new TeleportLocation(world, x, y, z, p.getLocation().getYaw(), p.getLocation().getPitch(), plugin.getConfigManager().getServerName()));
} catch (NumberFormatException e) { p.sendMessage("§cUngültige Koordinaten!"); }
return true;
}
}

View File

@@ -0,0 +1,23 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpWorldCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpWorldCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tpworld")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /tpworld <welt>"); return true; }
World world = Bukkit.getWorld(args[0]);
if (world == null) { p.sendMessage("§cWelt §6" + args[0] + " §cnicht gefunden."); return true; }
var spawn = world.getSpawnLocation();
plugin.getTeleportManager().teleport(p, new TeleportLocation(world.getName(), spawn.getX(), spawn.getY(), spawn.getZ(), 0, 0, plugin.getConfigManager().getServerName()));
return true;
}
}

View File

@@ -0,0 +1,32 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class TpaCommand implements CommandExecutor {
private final TeleportSuite plugin;
public TpaCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.tpa")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /tpa <spieler>"); return true; }
if (p.getName().equalsIgnoreCase(args[0])) { p.sendMessage("§cDu kannst dir nicht selbst eine Anfrage senden."); return true; }
Player target = Bukkit.getPlayer(args[0]);
if (target != null) {
// Same server
plugin.getTeleportManager().sendTpaRequest(p, target);
} else if (plugin.getConfigManager().isBungeeEnabled() && plugin.getBungeeMessenger() != null) {
// Cross-server — Bungee manages the pending state
plugin.getTeleportManager().sendCrossServerTpaRequest(p, args[0]);
} else {
p.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", args[0]));
}
return true;
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public class WarpCommand implements CommandExecutor {
private final TeleportSuite plugin;
public WarpCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) { sender.sendMessage("§cNur für Spieler!"); return true; }
Player p = (Player) sender;
if (!p.hasPermission("teleportsuite.warp")) { p.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
if (args.length < 1) { p.sendMessage("§cVerwendung: /warp <name>"); return true; }
plugin.getWarpManager().teleportWarp(p, args[0]);
return true;
}
}

View File

@@ -0,0 +1,21 @@
package de.teleportsuite.commands;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.Warp;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import java.util.List;
public class WarpsCommand implements CommandExecutor {
private final TeleportSuite plugin;
public WarpsCommand(TeleportSuite p) { this.plugin = p; }
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission("teleportsuite.warp")) { sender.sendMessage(plugin.getConfigManager().getMessage("no-permission")); return true; }
List<Warp> warps = plugin.getWarpManager().getAllWarps();
if (warps.isEmpty()) { sender.sendMessage("§eKeine Warps vorhanden."); return true; }
sender.sendMessage("§6Verfügbare Warps §8(" + warps.size() + ")§6:");
warps.stream()
.filter(w -> w.getPermission() == null || sender.hasPermission(w.getPermission()))
.forEach(w -> sender.sendMessage("§7- §a" + w.getName() + " §7(" + w.getLocation().getWorld() + ")"));
return true;
}
}

View File

@@ -0,0 +1,374 @@
package de.teleportsuite.database;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.*;
import java.sql.*;
import java.util.*;
public class DatabaseManager {
private final TeleportSuite plugin;
private HikariDataSource dataSource;
private boolean isMySQL;
public DatabaseManager(TeleportSuite plugin) { this.plugin = plugin; }
public boolean connect() {
String type = plugin.getConfig().getString("database.type", "sqlite").toLowerCase();
isMySQL = type.equals("mysql");
try {
HikariConfig config = new HikariConfig();
if (isMySQL) {
String host = plugin.getConfig().getString("database.mysql.host", "localhost");
int port = plugin.getConfig().getInt("database.mysql.port", 3306);
String db = plugin.getConfig().getString("database.mysql.database", "teleportsuite");
String user = plugin.getConfig().getString("database.mysql.username", "root");
String pass = plugin.getConfig().getString("database.mysql.password", "");
config.setJdbcUrl("jdbc:mysql://"+host+":"+port+"/"+db+"?useSSL=false&autoReconnect=true&characterEncoding=UTF-8");
config.setUsername(user);
config.setPassword(pass);
config.setMaximumPoolSize(plugin.getConfig().getInt("database.mysql.pool-size", 10));
} else {
String file = plugin.getDataFolder().getAbsolutePath() + "/" +
plugin.getConfig().getString("database.sqlite.file", "teleportsuite.db");
config.setJdbcUrl("jdbc:sqlite:" + file);
config.setMaximumPoolSize(1);
}
config.setPoolName("TeleportSuite-Pool");
dataSource = new HikariDataSource(config);
plugin.getLogger().info("Datenbankverbindung hergestellt (" + (isMySQL ? "MySQL" : "SQLite") + ")");
return true;
} catch (Exception e) {
plugin.getLogger().severe("Datenbankfehler: " + e.getMessage());
return false;
}
}
public void createTables() {
String ai = isMySQL ? "AUTO_INCREMENT" : "AUTOINCREMENT";
String bool = isMySQL ? "TINYINT(1)" : "INTEGER";
String[] tables = {
"CREATE TABLE IF NOT EXISTS ts_homes (id INTEGER PRIMARY KEY "+ai+",uuid VARCHAR(36) NOT NULL,name VARCHAR(64) NOT NULL,world VARCHAR(64) NOT NULL,x DOUBLE NOT NULL,y DOUBLE NOT NULL,z DOUBLE NOT NULL,yaw FLOAT NOT NULL,pitch FLOAT NOT NULL,server VARCHAR(64) DEFAULT 'local',UNIQUE(uuid,name))",
"CREATE TABLE IF NOT EXISTS ts_warps (id INTEGER PRIMARY KEY "+ai+",name VARCHAR(64) NOT NULL UNIQUE,world VARCHAR(64) NOT NULL,x DOUBLE NOT NULL,y DOUBLE NOT NULL,z DOUBLE NOT NULL,yaw FLOAT NOT NULL,pitch FLOAT NOT NULL,server VARCHAR(64) DEFAULT 'local',creator VARCHAR(36),permission VARCHAR(128) DEFAULT NULL)",
"CREATE TABLE IF NOT EXISTS ts_portals (id INTEGER PRIMARY KEY "+ai+",name VARCHAR(64) NOT NULL UNIQUE,world VARCHAR(64) NOT NULL,x1 INT NOT NULL,y1 INT NOT NULL,z1 INT NOT NULL,x2 INT NOT NULL,y2 INT NOT NULL,z2 INT NOT NULL,target_server VARCHAR(64),target_world VARCHAR(64),target_x DOUBLE,target_y DOUBLE,target_z DOUBLE,target_yaw FLOAT DEFAULT 0,target_pitch FLOAT DEFAULT 0)",
"CREATE TABLE IF NOT EXISTS ts_spawns (id INTEGER PRIMARY KEY "+ai+",type VARCHAR(32) NOT NULL UNIQUE,world VARCHAR(64) NOT NULL,x DOUBLE NOT NULL,y DOUBLE NOT NULL,z DOUBLE NOT NULL,yaw FLOAT NOT NULL,pitch FLOAT NOT NULL,server VARCHAR(64) DEFAULT 'local')",
"CREATE TABLE IF NOT EXISTS ts_savepoints (id INTEGER PRIMARY KEY "+ai+",uuid VARCHAR(36) NOT NULL,name VARCHAR(64) NOT NULL,world VARCHAR(64) NOT NULL,x DOUBLE NOT NULL,y DOUBLE NOT NULL,z DOUBLE NOT NULL,yaw FLOAT NOT NULL,pitch FLOAT NOT NULL,server VARCHAR(64) DEFAULT 'local',UNIQUE(uuid,name))",
"CREATE TABLE IF NOT EXISTS ts_player_data (uuid VARCHAR(36) PRIMARY KEY,last_world VARCHAR(64),last_x DOUBLE,last_y DOUBLE,last_z DOUBLE,last_yaw FLOAT,last_pitch FLOAT,last_server VARCHAR(64) DEFAULT 'local',death_world VARCHAR(64),death_x DOUBLE,death_y DOUBLE,death_z DOUBLE,death_yaw FLOAT,death_pitch FLOAT,death_server VARCHAR(64) DEFAULT 'local',first_join "+bool+" DEFAULT 1)"
};
try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) {
for (String sql : tables) stmt.execute(sql);
plugin.getLogger().info("Datenbanktabellen erstellt/verifiziert.");
} catch (SQLException e) {
plugin.getLogger().severe("Fehler beim Erstellen der Tabellen: " + e.getMessage());
}
}
// ===== HOMES =====
public void saveHome(UUID uuid, String name, TeleportLocation loc) {
String sql = isMySQL
? "INSERT INTO ts_homes (uuid,name,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE world=?,x=?,y=?,z=?,yaw=?,pitch=?,server=?"
: "INSERT OR REPLACE INTO ts_homes (uuid,name,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, uuid.toString()); ps.setString(2, name);
ps.setString(3, loc.getWorld()); ps.setDouble(4, loc.getX()); ps.setDouble(5, loc.getY());
ps.setDouble(6, loc.getZ()); ps.setFloat(7, loc.getYaw()); ps.setFloat(8, loc.getPitch());
ps.setString(9, loc.getServer());
if (isMySQL) {
ps.setString(10, loc.getWorld()); ps.setDouble(11, loc.getX()); ps.setDouble(12, loc.getY());
ps.setDouble(13, loc.getZ()); ps.setFloat(14, loc.getYaw()); ps.setFloat(15, loc.getPitch());
ps.setString(16, loc.getServer());
}
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("saveHome: " + e.getMessage()); }
}
public List<Home> getHomes(UUID uuid) {
List<Home> list = new ArrayList<>();
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM ts_homes WHERE uuid=?")) {
ps.setString(1, uuid.toString());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
TeleportLocation loc = new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
list.add(new Home(uuid, rs.getString("name"), loc));
}
} catch (SQLException e) { plugin.getLogger().warning("getHomes: " + e.getMessage()); }
return list;
}
public Home getHome(UUID uuid, String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM ts_homes WHERE uuid=? AND name=?")) {
ps.setString(1, uuid.toString()); ps.setString(2, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
TeleportLocation loc = new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
return new Home(uuid, name, loc);
}
} catch (SQLException e) { plugin.getLogger().warning("getHome: " + e.getMessage()); }
return null;
}
public boolean deleteHome(UUID uuid, String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("DELETE FROM ts_homes WHERE uuid=? AND name=?")) {
ps.setString(1, uuid.toString()); ps.setString(2, name);
return ps.executeUpdate() > 0;
} catch (SQLException e) { plugin.getLogger().warning("deleteHome: " + e.getMessage()); return false; }
}
public int countHomes(UUID uuid) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT COUNT(*) FROM ts_homes WHERE uuid=?")) {
ps.setString(1, uuid.toString());
ResultSet rs = ps.executeQuery();
if (rs.next()) return rs.getInt(1);
} catch (SQLException e) { plugin.getLogger().warning("countHomes: " + e.getMessage()); }
return 0;
}
// ===== WARPS =====
public void saveWarp(String name, TeleportLocation loc, UUID creator, String permission) {
String sql = isMySQL
? "INSERT INTO ts_warps (name,world,x,y,z,yaw,pitch,server,creator,permission) VALUES(?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE world=?,x=?,y=?,z=?,yaw=?,pitch=?,server=?"
: "INSERT OR REPLACE INTO ts_warps (name,world,x,y,z,yaw,pitch,server,creator,permission) VALUES(?,?,?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, name); ps.setString(2, loc.getWorld());
ps.setDouble(3, loc.getX()); ps.setDouble(4, loc.getY()); ps.setDouble(5, loc.getZ());
ps.setFloat(6, loc.getYaw()); ps.setFloat(7, loc.getPitch()); ps.setString(8, loc.getServer());
ps.setString(9, creator != null ? creator.toString() : null); ps.setString(10, permission);
if (isMySQL) {
ps.setString(11, loc.getWorld()); ps.setDouble(12, loc.getX()); ps.setDouble(13, loc.getY());
ps.setDouble(14, loc.getZ()); ps.setFloat(15, loc.getYaw()); ps.setFloat(16, loc.getPitch());
ps.setString(17, loc.getServer());
}
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("saveWarp: " + e.getMessage()); }
}
public Warp getWarp(String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM ts_warps WHERE name=?")) {
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
TeleportLocation loc = new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
String creatorStr = rs.getString("creator");
UUID creator = creatorStr != null ? UUID.fromString(creatorStr) : null;
return new Warp(name, loc, creator, rs.getString("permission"));
}
} catch (SQLException e) { plugin.getLogger().warning("getWarp: " + e.getMessage()); }
return null;
}
public List<Warp> getAllWarps() {
List<Warp> list = new ArrayList<>();
try (Connection c = getConnection();
Statement stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM ts_warps ORDER BY name")) {
while (rs.next()) {
TeleportLocation loc = new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
String creatorStr = rs.getString("creator");
UUID creator = creatorStr != null ? UUID.fromString(creatorStr) : null;
list.add(new Warp(rs.getString("name"), loc, creator, rs.getString("permission")));
}
} catch (SQLException e) { plugin.getLogger().warning("getAllWarps: " + e.getMessage()); }
return list;
}
public boolean deleteWarp(String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("DELETE FROM ts_warps WHERE name=?")) {
ps.setString(1, name);
return ps.executeUpdate() > 0;
} catch (SQLException e) { plugin.getLogger().warning("deleteWarp: " + e.getMessage()); return false; }
}
// ===== PORTALS =====
public void savePortal(Portal portal) {
String sql = isMySQL
? "INSERT INTO ts_portals (name,world,x1,y1,z1,x2,y2,z2,target_server,target_world,target_x,target_y,target_z,target_yaw,target_pitch) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE world=VALUES(world),x1=VALUES(x1),y1=VALUES(y1),z1=VALUES(z1),x2=VALUES(x2),y2=VALUES(y2),z2=VALUES(z2),target_server=VALUES(target_server),target_world=VALUES(target_world),target_x=VALUES(target_x),target_y=VALUES(target_y),target_z=VALUES(target_z),target_yaw=VALUES(target_yaw),target_pitch=VALUES(target_pitch)"
: "INSERT OR REPLACE INTO ts_portals (name,world,x1,y1,z1,x2,y2,z2,target_server,target_world,target_x,target_y,target_z,target_yaw,target_pitch) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
TeleportLocation dest = portal.getDestination();
ps.setString(1, portal.getName()); ps.setString(2, portal.getWorld());
// We need full portal data - for simplicity storing via Portal model fields
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("savePortal: " + e.getMessage()); }
}
public List<Portal> getAllPortals() {
List<Portal> list = new ArrayList<>();
try (Connection c = getConnection();
Statement stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM ts_portals")) {
while (rs.next()) {
TeleportLocation dest = new TeleportLocation(rs.getString("target_world"),rs.getDouble("target_x"),rs.getDouble("target_y"),rs.getDouble("target_z"),rs.getFloat("target_yaw"),rs.getFloat("target_pitch"),rs.getString("target_server"));
list.add(new Portal(rs.getString("name"),rs.getString("world"),rs.getInt("x1"),rs.getInt("y1"),rs.getInt("z1"),rs.getInt("x2"),rs.getInt("y2"),rs.getInt("z2"),rs.getString("target_server"),dest));
}
} catch (SQLException e) { plugin.getLogger().warning("getAllPortals: " + e.getMessage()); }
return list;
}
public boolean deletePortal(String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("DELETE FROM ts_portals WHERE name=?")) {
ps.setString(1, name);
return ps.executeUpdate() > 0;
} catch (SQLException e) { plugin.getLogger().warning("deletePortal: " + e.getMessage()); return false; }
}
// ===== SPAWNS =====
public void saveSpawn(String type, TeleportLocation loc) {
String sql = isMySQL
? "INSERT INTO ts_spawns (type,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE world=?,x=?,y=?,z=?,yaw=?,pitch=?,server=?"
: "INSERT OR REPLACE INTO ts_spawns (type,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, type); ps.setString(2, loc.getWorld());
ps.setDouble(3, loc.getX()); ps.setDouble(4, loc.getY()); ps.setDouble(5, loc.getZ());
ps.setFloat(6, loc.getYaw()); ps.setFloat(7, loc.getPitch()); ps.setString(8, loc.getServer());
if (isMySQL) {
ps.setString(9, loc.getWorld()); ps.setDouble(10, loc.getX()); ps.setDouble(11, loc.getY());
ps.setDouble(12, loc.getZ()); ps.setFloat(13, loc.getYaw()); ps.setFloat(14, loc.getPitch());
ps.setString(15, loc.getServer());
}
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("saveSpawn: " + e.getMessage()); }
}
public TeleportLocation getSpawn(String type) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM ts_spawns WHERE type=?")) {
ps.setString(1, type);
ResultSet rs = ps.executeQuery();
if (rs.next()) return new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
} catch (SQLException e) { plugin.getLogger().warning("getSpawn: " + e.getMessage()); }
return null;
}
// ===== PLAYER DATA =====
public void saveLastLocation(UUID uuid, TeleportLocation loc) {
String sql = isMySQL
? "INSERT INTO ts_player_data (uuid,last_world,last_x,last_y,last_z,last_yaw,last_pitch,last_server) VALUES(?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE last_world=?,last_x=?,last_y=?,last_z=?,last_yaw=?,last_pitch=?,last_server=?"
: "INSERT OR REPLACE INTO ts_player_data (uuid,last_world,last_x,last_y,last_z,last_yaw,last_pitch,last_server) VALUES(?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, uuid.toString()); ps.setString(2, loc.getWorld());
ps.setDouble(3, loc.getX()); ps.setDouble(4, loc.getY()); ps.setDouble(5, loc.getZ());
ps.setFloat(6, loc.getYaw()); ps.setFloat(7, loc.getPitch()); ps.setString(8, loc.getServer());
if (isMySQL) {
ps.setString(9, loc.getWorld()); ps.setDouble(10, loc.getX()); ps.setDouble(11, loc.getY());
ps.setDouble(12, loc.getZ()); ps.setFloat(13, loc.getYaw()); ps.setFloat(14, loc.getPitch());
ps.setString(15, loc.getServer());
}
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("saveLastLocation: " + e.getMessage()); }
}
public void saveDeathLocation(UUID uuid, TeleportLocation loc) {
try (Connection c = getConnection()) {
PreparedStatement check = c.prepareStatement("SELECT uuid FROM ts_player_data WHERE uuid=?");
check.setString(1, uuid.toString());
ResultSet rs = check.executeQuery();
String sql;
if (rs.next()) {
sql = "UPDATE ts_player_data SET death_world=?,death_x=?,death_y=?,death_z=?,death_yaw=?,death_pitch=?,death_server=? WHERE uuid=?";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, loc.getWorld()); ps.setDouble(2, loc.getX()); ps.setDouble(3, loc.getY());
ps.setDouble(4, loc.getZ()); ps.setFloat(5, loc.getYaw()); ps.setFloat(6, loc.getPitch());
ps.setString(7, loc.getServer()); ps.setString(8, uuid.toString());
ps.executeUpdate();
}
} else {
sql = "INSERT INTO ts_player_data (uuid,death_world,death_x,death_y,death_z,death_yaw,death_pitch,death_server) VALUES(?,?,?,?,?,?,?,?)";
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, uuid.toString()); ps.setString(2, loc.getWorld());
ps.setDouble(3, loc.getX()); ps.setDouble(4, loc.getY()); ps.setDouble(5, loc.getZ());
ps.setFloat(6, loc.getYaw()); ps.setFloat(7, loc.getPitch()); ps.setString(8, loc.getServer());
ps.executeUpdate();
}
}
} catch (SQLException e) { plugin.getLogger().warning("saveDeathLocation: " + e.getMessage()); }
}
public TeleportLocation getLastLocation(UUID uuid) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT last_world,last_x,last_y,last_z,last_yaw,last_pitch,last_server FROM ts_player_data WHERE uuid=?")) {
ps.setString(1, uuid.toString());
ResultSet rs = ps.executeQuery();
if (rs.next() && rs.getString("last_world") != null)
return new TeleportLocation(rs.getString("last_world"),rs.getDouble("last_x"),rs.getDouble("last_y"),rs.getDouble("last_z"),rs.getFloat("last_yaw"),rs.getFloat("last_pitch"),rs.getString("last_server"));
} catch (SQLException e) { plugin.getLogger().warning("getLastLocation: " + e.getMessage()); }
return null;
}
public TeleportLocation getDeathLocation(UUID uuid) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT death_world,death_x,death_y,death_z,death_yaw,death_pitch,death_server FROM ts_player_data WHERE uuid=?")) {
ps.setString(1, uuid.toString());
ResultSet rs = ps.executeQuery();
if (rs.next() && rs.getString("death_world") != null)
return new TeleportLocation(rs.getString("death_world"),rs.getDouble("death_x"),rs.getDouble("death_y"),rs.getDouble("death_z"),rs.getFloat("death_yaw"),rs.getFloat("death_pitch"),rs.getString("death_server"));
} catch (SQLException e) { plugin.getLogger().warning("getDeathLocation: " + e.getMessage()); }
return null;
}
public boolean isFirstJoin(UUID uuid) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT first_join FROM ts_player_data WHERE uuid=?")) {
ps.setString(1, uuid.toString());
ResultSet rs = ps.executeQuery();
if (rs.next()) return rs.getInt("first_join") == 1;
} catch (SQLException e) { plugin.getLogger().warning("isFirstJoin: " + e.getMessage()); }
return true;
}
public void setFirstJoinDone(UUID uuid) {
try (Connection c = getConnection()) {
PreparedStatement check = c.prepareStatement("SELECT uuid FROM ts_player_data WHERE uuid=?");
check.setString(1, uuid.toString());
ResultSet rs = check.executeQuery();
if (rs.next()) {
PreparedStatement ps = c.prepareStatement("UPDATE ts_player_data SET first_join=0 WHERE uuid=?");
ps.setString(1, uuid.toString()); ps.executeUpdate();
} else {
PreparedStatement ps = c.prepareStatement("INSERT INTO ts_player_data (uuid,first_join) VALUES(?,0)");
ps.setString(1, uuid.toString()); ps.executeUpdate();
}
} catch (SQLException e) { plugin.getLogger().warning("setFirstJoinDone: " + e.getMessage()); }
}
// ===== SAVEPOINTS =====
public void saveSavePoint(UUID uuid, String name, TeleportLocation loc) {
String sql = isMySQL
? "INSERT INTO ts_savepoints (uuid,name,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE world=?,x=?,y=?,z=?,yaw=?,pitch=?,server=?"
: "INSERT OR REPLACE INTO ts_savepoints (uuid,name,world,x,y,z,yaw,pitch,server) VALUES(?,?,?,?,?,?,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, uuid.toString()); ps.setString(2, name);
ps.setString(3, loc.getWorld()); ps.setDouble(4, loc.getX()); ps.setDouble(5, loc.getY());
ps.setDouble(6, loc.getZ()); ps.setFloat(7, loc.getYaw()); ps.setFloat(8, loc.getPitch());
ps.setString(9, loc.getServer());
if (isMySQL) {
ps.setString(10, loc.getWorld()); ps.setDouble(11, loc.getX()); ps.setDouble(12, loc.getY());
ps.setDouble(13, loc.getZ()); ps.setFloat(14, loc.getYaw()); ps.setFloat(15, loc.getPitch());
ps.setString(16, loc.getServer());
}
ps.executeUpdate();
} catch (SQLException e) { plugin.getLogger().warning("saveSavePoint: " + e.getMessage()); }
}
public TeleportLocation getSavePoint(UUID uuid, String name) {
try (Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM ts_savepoints WHERE uuid=? AND name=?")) {
ps.setString(1, uuid.toString()); ps.setString(2, name);
ResultSet rs = ps.executeQuery();
if (rs.next()) return new TeleportLocation(rs.getString("world"),rs.getDouble("x"),rs.getDouble("y"),rs.getDouble("z"),rs.getFloat("yaw"),rs.getFloat("pitch"),rs.getString("server"));
} catch (SQLException e) { plugin.getLogger().warning("getSavePoint: " + e.getMessage()); }
return null;
}
public Connection getConnection() throws SQLException { return dataSource.getConnection(); }
public void disconnect() { if (dataSource != null && !dataSource.isClosed()) dataSource.close(); }
public boolean isMySQL() { return isMySQL; }
}

View File

@@ -0,0 +1,19 @@
package de.teleportsuite.listeners;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
public class PlayerDeathListener implements Listener {
private final TeleportSuite plugin;
public PlayerDeathListener(TeleportSuite plugin) { this.plugin = plugin; }
@EventHandler
public void onDeath(PlayerDeathEvent event) {
var player = event.getEntity();
TeleportLocation deathLoc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveDeathLocation(player.getUniqueId(), deathLoc);
}
}

View File

@@ -0,0 +1,22 @@
package de.teleportsuite.listeners;
import de.teleportsuite.TeleportSuite;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class PlayerJoinListener implements Listener {
private final TeleportSuite plugin;
public PlayerJoinListener(TeleportSuite plugin) { this.plugin = plugin; }
@EventHandler
public void onJoin(PlayerJoinEvent event) {
if (!plugin.getConfigManager().firstJoinTeleport()) return;
var player = event.getPlayer();
if (plugin.getDatabaseManager().isFirstJoin(player.getUniqueId())) {
plugin.getDatabaseManager().setFirstJoinDone(player.getUniqueId());
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin,
() -> plugin.getSpawnManager().teleportToFirstSpawn(player), 20L);
}
}
}

View File

@@ -0,0 +1,24 @@
package de.teleportsuite.listeners;
import de.teleportsuite.TeleportSuite;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class PlayerMoveListener implements Listener {
private final TeleportSuite plugin;
public PlayerMoveListener(TeleportSuite plugin) { this.plugin = plugin; }
@EventHandler
public void onMove(PlayerMoveEvent event) {
if (!plugin.getConfigManager().cancelOnMove()) return;
var from = event.getFrom();
var to = event.getTo();
if (to == null) return;
if (from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ()) {
plugin.getTeleportManager().cancelWarmup(event.getPlayer().getUniqueId());
}
// Portal check
plugin.getPortalManager().checkPortal(event.getPlayer(), to);
}
}

View File

@@ -0,0 +1,21 @@
package de.teleportsuite.listeners;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerRespawnEvent;
public class PlayerRespawnListener implements Listener {
private final TeleportSuite plugin;
public PlayerRespawnListener(TeleportSuite plugin) { this.plugin = plugin; }
@EventHandler
public void onRespawn(PlayerRespawnEvent event) {
if (!plugin.getConfigManager().deathRespawnToSpawn()) return;
TeleportLocation spawn = plugin.getDatabaseManager().getSpawn("spawn");
if (spawn == null) return;
var loc = spawn.toBukkitLocation();
if (loc != null) event.setRespawnLocation(loc);
}
}

View File

@@ -0,0 +1,13 @@
package de.teleportsuite.listeners;
import de.teleportsuite.TeleportSuite;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
// Portal checks are handled in PlayerMoveListener via PortalManager
// This listener exists for future portal-block-specific events (nether portals etc.)
public class PortalListener implements Listener {
private final TeleportSuite plugin;
public PortalListener(TeleportSuite plugin) { this.plugin = plugin; }
}

View File

@@ -0,0 +1,53 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.Home;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.UUID;
public class HomeManager {
private final TeleportSuite plugin;
public HomeManager(TeleportSuite plugin) { this.plugin = plugin; }
public int getMaxHomes(Player player) {
if (player.hasPermission("teleportsuite.home.unlimited")) return Integer.MAX_VALUE;
if (player.hasPermission("teleportsuite.home.premium")) return plugin.getConfigManager().getMaxHomes("premium");
if (player.hasPermission("teleportsuite.home.vip")) return plugin.getConfigManager().getMaxHomes("vip");
return plugin.getConfigManager().getMaxHomes("default");
}
public boolean setHome(Player player, String name) {
int current = plugin.getDatabaseManager().countHomes(player.getUniqueId());
int max = getMaxHomes(player);
if (current >= max) {
player.sendMessage(plugin.getConfigManager().getMessage("home-limit", "max", String.valueOf(max)));
return false;
}
TeleportLocation loc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveHome(player.getUniqueId(), name, loc);
player.sendMessage(plugin.getConfigManager().getMessage("home-set", "name", name));
return true;
}
public void teleportHome(Player player, String name) {
Home home = plugin.getDatabaseManager().getHome(player.getUniqueId(), name);
if (home == null) {
player.sendMessage(plugin.getConfigManager().getMessage("home-not-found", "name", name));
return;
}
plugin.getTeleportManager().teleport(player, home.getLocation());
}
public boolean deleteHome(Player player, String name) {
boolean deleted = plugin.getDatabaseManager().deleteHome(player.getUniqueId(), name);
if (deleted) player.sendMessage(plugin.getConfigManager().getMessage("home-deleted", "name", name));
else player.sendMessage(plugin.getConfigManager().getMessage("home-not-found", "name", name));
return deleted;
}
public List<Home> getHomes(UUID uuid) {
return plugin.getDatabaseManager().getHomes(uuid);
}
}

View File

@@ -0,0 +1,81 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.Portal;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.*;
public class PortalManager {
private final TeleportSuite plugin;
private List<Portal> portals = new ArrayList<>();
// Selection for portal creation: player -> pos1, pos2
private final Map<UUID, Location> pos1 = new HashMap<>();
private final Map<UUID, Location> pos2 = new HashMap<>();
// Cooldown to prevent multiple triggers
private final Map<UUID, Long> cooldown = new HashMap<>();
public PortalManager(TeleportSuite plugin) {
this.plugin = plugin;
loadPortals();
}
public void loadPortals() {
portals = plugin.getDatabaseManager().getAllPortals();
}
public void setPos1(Player player, Location loc) {
pos1.put(player.getUniqueId(), loc);
player.sendMessage("§aPos1 gesetzt: §f" + formatLoc(loc));
}
public void setPos2(Player player, Location loc) {
pos2.put(player.getUniqueId(), loc);
player.sendMessage("§aPos2 gesetzt: §f" + formatLoc(loc));
}
public boolean createPortal(Player player, String name, String targetServer, String targetWorld, double tx, double ty, double tz) {
Location l1 = pos1.get(player.getUniqueId());
Location l2 = pos2.get(player.getUniqueId());
if (l1 == null || l2 == null) {
player.sendMessage("§cBitte setze erst Pos1 und Pos2 mit §e/setportal pos1 §cund §e/setportal pos2");
return false;
}
TeleportLocation dest = new TeleportLocation(targetWorld, tx, ty, tz, 0, 0, targetServer);
Portal portal = new Portal(name, l1.getWorld().getName(),
l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(),
l2.getBlockX(), l2.getBlockY(), l2.getBlockZ(),
targetServer, dest);
plugin.getDatabaseManager().savePortal(portal);
portals.add(portal);
pos1.remove(player.getUniqueId());
pos2.remove(player.getUniqueId());
player.sendMessage(plugin.getConfigManager().getMessage("portal-created", "name", name));
return true;
}
public boolean deletePortal(String name) {
portals.removeIf(p -> p.getName().equalsIgnoreCase(name));
return plugin.getDatabaseManager().deletePortal(name);
}
public void checkPortal(Player player, Location loc) {
long now = System.currentTimeMillis();
if (now - cooldown.getOrDefault(player.getUniqueId(), 0L) < 2000) return;
for (Portal portal : portals) {
if (portal.contains(loc)) {
cooldown.put(player.getUniqueId(), now);
plugin.getTeleportManager().teleport(player, portal.getDestination(), true);
break;
}
}
}
public List<Portal> getPortals() { return portals; }
private String formatLoc(Location loc) {
return loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ() + " in " + loc.getWorld().getName();
}
}

View File

@@ -0,0 +1,22 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.entity.Player;
public class SavePointManager {
private final TeleportSuite plugin;
public SavePointManager(TeleportSuite plugin) { this.plugin = plugin; }
public void setSavePoint(Player player, String name) {
TeleportLocation loc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveSavePoint(player.getUniqueId(), name, loc);
player.sendMessage(plugin.getConfigManager().getMessage("savepoint-set", "name", name));
}
public void teleportToSavePoint(Player player, String name) {
TeleportLocation loc = plugin.getDatabaseManager().getSavePoint(player.getUniqueId(), name);
if (loc == null) { player.sendMessage("§cSavepoint §6" + name + " §cnicht gefunden."); return; }
plugin.getTeleportManager().teleport(player, loc);
}
}

View File

@@ -0,0 +1,41 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.entity.Player;
public class SpawnManager {
private final TeleportSuite plugin;
public SpawnManager(TeleportSuite plugin) { this.plugin = plugin; }
public void setSpawn(Player player) {
TeleportLocation loc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveSpawn("spawn", loc);
player.sendMessage(plugin.getConfigManager().getMessage("spawn-set"));
}
public void setFirstSpawn(Player player) {
TeleportLocation loc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveSpawn("firstspawn", loc);
player.sendMessage(plugin.getConfigManager().getMessage("firstspawn-set"));
}
public void teleportToSpawn(Player player) {
TeleportLocation spawn = plugin.getDatabaseManager().getSpawn("spawn");
if (spawn == null) { player.sendMessage("§cKein Spawn gesetzt!"); return; }
plugin.getTeleportManager().teleport(player, spawn);
}
public void teleportToFirstSpawn(Player player) {
TeleportLocation firstSpawn = plugin.getDatabaseManager().getSpawn("firstspawn");
if (firstSpawn == null) {
teleportToSpawn(player);
return;
}
plugin.getTeleportManager().teleport(player, firstSpawn);
}
public TeleportLocation getRespawnLocation() {
return plugin.getDatabaseManager().getSpawn("spawn");
}
}

View File

@@ -0,0 +1,220 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.bungeemessaging.BungeeMessenger;
import de.teleportsuite.models.TeleportLocation;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.*;
public class TeleportManager {
private final TeleportSuite plugin;
// Same-server pending TPA: requesterUUID → targetUUID
private final Map<UUID, UUID> tpaRequests = new HashMap<>();
private final Map<UUID, Long> requestTimestamps = new HashMap<>();
// Cooldowns
private final Map<UUID, Long> cooldowns = new HashMap<>();
// Warmup tasks
private final Map<UUID, Integer> warmupTasks = new HashMap<>();
// Back-locations (saved before every teleport)
private final Map<UUID, TeleportLocation> pendingBackLocations = new HashMap<>();
public TeleportManager(TeleportSuite plugin) { this.plugin = plugin; }
// -------------------------------------------------------------------------
// Main teleport entry point
// -------------------------------------------------------------------------
public void teleport(Player player, TeleportLocation destination) {
teleport(player, destination, true);
}
public void teleport(Player player, TeleportLocation destination, boolean saveBack) {
int delay = plugin.getConfigManager().getTeleportDelay();
if (player.hasPermission("teleportsuite.nodelay")) delay = 0;
if (!player.hasPermission("teleportsuite.nocooldown")) {
long cooldownMs = plugin.getConfigManager().getTeleportCooldown() * 1000L;
long lastTp = cooldowns.getOrDefault(player.getUniqueId(), 0L);
if (System.currentTimeMillis() - lastTp < cooldownMs) {
long remaining = (cooldownMs - (System.currentTimeMillis() - lastTp)) / 1000;
player.sendMessage(plugin.getConfigManager().getMessage(
"teleport-cooldown", "seconds", String.valueOf(remaining)));
return;
}
}
if (saveBack) {
pendingBackLocations.put(player.getUniqueId(),
new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName()));
}
if (delay <= 0) {
executeTeleport(player, destination);
return;
}
player.sendMessage(plugin.getConfigManager().getMessage(
"teleport-warmup", "seconds", String.valueOf(delay)));
Location startLoc = player.getLocation().clone();
int taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (plugin.getConfigManager().cancelOnMove()) {
Location now = player.getLocation();
if (Math.abs(now.getX() - startLoc.getX()) > 0.5
|| Math.abs(now.getZ() - startLoc.getZ()) > 0.5) {
player.sendMessage(plugin.getConfigManager().getMessage("teleport-cancelled"));
warmupTasks.remove(player.getUniqueId());
return;
}
}
executeTeleport(player, destination);
warmupTasks.remove(player.getUniqueId());
}, delay * 20L);
warmupTasks.put(player.getUniqueId(), taskId);
}
private void executeTeleport(Player player, TeleportLocation dest) {
String localServer = plugin.getConfigManager().getServerName();
// Save last location + apply cooldown always (also for cross-server)
plugin.getDatabaseManager().saveLastLocation(player.getUniqueId(),
new TeleportLocation(player.getLocation(), localServer));
cooldowns.put(player.getUniqueId(), System.currentTimeMillis());
if (!dest.isLocalServer(localServer)) {
// Cross-server: delegate completely to the Bungee plugin.
// It will call sender.connect() and then send TP_PLAYERTOPOSITION.
BungeeMessenger bm = plugin.getBungeeMessenger();
if (bm != null) {
bm.teleportToPosition(player, dest.getServer(), dest.getWorld(),
dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch());
player.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
}
return;
}
Location loc = dest.toBukkitLocation();
if (loc == null || loc.getWorld() == null) {
player.sendMessage("§cZielwelt nicht gefunden!");
return;
}
player.teleport(loc);
player.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
}
public void cancelWarmup(UUID uuid) {
Integer taskId = warmupTasks.remove(uuid);
if (taskId != null) Bukkit.getScheduler().cancelTask(taskId);
}
public TeleportLocation getBackLocation(UUID uuid) {
return pendingBackLocations.get(uuid);
}
// -------------------------------------------------------------------------
// Same-server TPA
// -------------------------------------------------------------------------
public void sendTpaRequest(Player from, Player to) {
tpaRequests.put(from.getUniqueId(), to.getUniqueId());
requestTimestamps.put(from.getUniqueId(), System.currentTimeMillis());
to.sendMessage(plugin.getConfigManager().getMessage("tpa-received", "player", from.getName()));
from.sendMessage(plugin.getConfigManager().getMessage("tpa-sent", "player", to.getName()));
int timeout = plugin.getConfigManager().getRequestTimeout();
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (tpaRequests.containsKey(from.getUniqueId())) {
tpaRequests.remove(from.getUniqueId());
requestTimestamps.remove(from.getUniqueId());
if (from.isOnline()) {
from.sendMessage(plugin.getConfigManager().getMessage("tpa-expired"));
}
}
}, timeout * 20L);
}
// -------------------------------------------------------------------------
// Cross-server TPA — all state lives on the Bungee plugin now;
// Spigot just sends the right payload and handles local accept/deny.
// -------------------------------------------------------------------------
/**
* Called by TpaCommand when the target player is NOT on this server.
* Bungee will manage the pending state and route all messages.
*/
public void sendCrossServerTpaRequest(Player from, String targetName) {
BungeeMessenger bm = plugin.getBungeeMessenger();
if (bm == null) {
from.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetName));
return;
}
bm.sendTpaRequest(
from, targetName, "TPTO",
plugin.getConfigManager().getMessage("tpa-received", "player", from.getName()),
plugin.getConfigManager().getMessage("tpa-sent", "player", targetName));
}
/** Called by TpAcceptCommand — handles both same-server and cross-server. */
public boolean acceptTpa(Player target) {
// Same-server accept
UUID requesterUUID = null;
for (Map.Entry<UUID, UUID> entry : tpaRequests.entrySet()) {
if (entry.getValue().equals(target.getUniqueId())) {
requesterUUID = entry.getKey();
break;
}
}
if (requesterUUID != null) {
Player from = Bukkit.getPlayer(requesterUUID);
tpaRequests.remove(requesterUUID);
requestTimestamps.remove(requesterUUID);
if (from != null && from.isOnline()) {
from.sendMessage(plugin.getConfigManager().getMessage("tpa-accepted", "player", target.getName()));
teleport(from, new TeleportLocation(target.getLocation(),
plugin.getConfigManager().getServerName()));
}
return true;
}
// Cross-server accept — tell Bungee, it has the pending state
BungeeMessenger bm = plugin.getBungeeMessenger();
if (bm == null) return false;
bm.sendTpaAccept(target, null,
plugin.getConfigManager().getMessage("tpa-request-not-found"));
return true;
}
/** Called by TpDenyCommand — handles both same-server and cross-server. */
public boolean denyTpa(Player target) {
// Same-server deny
UUID requesterUUID = null;
for (Map.Entry<UUID, UUID> entry : tpaRequests.entrySet()) {
if (entry.getValue().equals(target.getUniqueId())) {
requesterUUID = entry.getKey();
break;
}
}
if (requesterUUID != null) {
Player from = Bukkit.getPlayer(requesterUUID);
tpaRequests.remove(requesterUUID);
requestTimestamps.remove(requesterUUID);
if (from != null && from.isOnline()) {
from.sendMessage(plugin.getConfigManager().getMessage("tpa-denied", "player", target.getName()));
}
return true;
}
// Cross-server deny
BungeeMessenger bm = plugin.getBungeeMessenger();
if (bm == null) return false;
bm.sendTpaDeny(target, null,
plugin.getConfigManager().getMessage("tpa-denied", "player", target.getName()));
return true;
}
}

View File

@@ -0,0 +1,39 @@
package de.teleportsuite.managers;
import de.teleportsuite.TeleportSuite;
import de.teleportsuite.models.TeleportLocation;
import de.teleportsuite.models.Warp;
import org.bukkit.entity.Player;
import java.util.List;
public class WarpManager {
private final TeleportSuite plugin;
public WarpManager(TeleportSuite plugin) { this.plugin = plugin; }
public void setWarp(Player player, String name, String permission) {
TeleportLocation loc = new TeleportLocation(player.getLocation(), plugin.getConfigManager().getServerName());
plugin.getDatabaseManager().saveWarp(name, loc, player.getUniqueId(), permission);
player.sendMessage(plugin.getConfigManager().getMessage("warp-set", "name", name));
}
public void teleportWarp(Player player, String name) {
Warp warp = plugin.getDatabaseManager().getWarp(name);
if (warp == null) {
player.sendMessage(plugin.getConfigManager().getMessage("warp-not-found", "name", name));
return;
}
if (warp.getPermission() != null && !player.hasPermission(warp.getPermission())) {
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
return;
}
plugin.getTeleportManager().teleport(player, warp.getLocation());
}
public boolean deleteWarp(String name) {
return plugin.getDatabaseManager().deleteWarp(name);
}
public List<Warp> getAllWarps() {
return plugin.getDatabaseManager().getAllWarps();
}
}

View File

@@ -0,0 +1,17 @@
package de.teleportsuite.models;
import java.util.UUID;
public class Home {
private final UUID uuid;
private final String name;
private final TeleportLocation location;
public Home(UUID uuid, String name, TeleportLocation location) {
this.uuid = uuid; this.name = name; this.location = location;
}
public UUID getUuid() { return uuid; }
public String getName() { return name; }
public TeleportLocation getLocation() { return location; }
}

View File

@@ -0,0 +1,33 @@
package de.teleportsuite.models;
import org.bukkit.Location;
import org.bukkit.World;
public class Portal {
private final String name;
private final String world;
private final int x1, y1, z1, x2, y2, z2;
private final String targetServer;
private final TeleportLocation destination;
public Portal(String name, String world, int x1, int y1, int z1, int x2, int y2, int z2,
String targetServer, TeleportLocation destination) {
this.name = name; this.world = world;
this.x1 = x1; this.y1 = y1; this.z1 = z1;
this.x2 = x2; this.y2 = y2; this.z2 = z2;
this.targetServer = targetServer; this.destination = destination;
}
public boolean contains(Location loc) {
if (!loc.getWorld().getName().equals(world)) return false;
int bx = loc.getBlockX(), by = loc.getBlockY(), bz = loc.getBlockZ();
return bx >= Math.min(x1,x2) && bx <= Math.max(x1,x2) &&
by >= Math.min(y1,y2) && by <= Math.max(y1,y2) &&
bz >= Math.min(z1,z2) && bz <= Math.max(z1,z2);
}
public String getName() { return name; }
public String getWorld() { return world; }
public String getTargetServer() { return targetServer; }
public TeleportLocation getDestination() { return destination; }
}

View File

@@ -0,0 +1,38 @@
package de.teleportsuite.models;
import org.bukkit.Bukkit;
import org.bukkit.Location;
public class TeleportLocation {
private String world;
private double x, y, z;
private float yaw, pitch;
private String server;
public TeleportLocation(String world, double x, double y, double z, float yaw, float pitch, String server) {
this.world = world; this.x = x; this.y = y; this.z = z;
this.yaw = yaw; this.pitch = pitch; this.server = server;
}
public TeleportLocation(Location loc, String server) {
this.world = loc.getWorld().getName();
this.x = loc.getX(); this.y = loc.getY(); this.z = loc.getZ();
this.yaw = loc.getYaw(); this.pitch = loc.getPitch();
this.server = server;
}
public Location toBukkitLocation() {
return new Location(Bukkit.getWorld(world), x, y, z, yaw, pitch);
}
public String getWorld() { return world; }
public double getX() { return x; }
public double getY() { return y; }
public double getZ() { return z; }
public float getYaw() { return yaw; }
public float getPitch() { return pitch; }
public String getServer() { return server; }
public boolean isLocalServer(String localServer) {
return server == null || server.equals("local") || server.equals(localServer);
}
}

View File

@@ -0,0 +1,20 @@
package de.teleportsuite.models;
import java.util.UUID;
public class Warp {
private final String name;
private final TeleportLocation location;
private final UUID creator;
private final String permission;
public Warp(String name, TeleportLocation location, UUID creator, String permission) {
this.name = name; this.location = location;
this.creator = creator; this.permission = permission;
}
public String getName() { return name; }
public TeleportLocation getLocation() { return location; }
public UUID getCreator() { return creator; }
public String getPermission() { return permission; }
}

View File

@@ -0,0 +1,5 @@
name: TeleportSuite-Bungee
main: de.teleportsuite.bungee.TeleportSuiteBungee
version: 1.0
author: TeleportSuite
description: BungeeCord-Companion fuer TeleportSuite

View File

@@ -0,0 +1,77 @@
# TeleportSuite Configuration
version: "1.0.0"
# Datenbank-Einstellungen
database:
type: sqlite # sqlite oder mysql
mysql:
host: localhost
port: 3306
database: teleportsuite
username: root
password: password
pool-size: 10
sqlite:
file: teleportsuite.db
# BungeeCord Einstellungen
bungee:
enabled: false
server-name: "survival" # Name dieses Servers im BungeeCord-Netz
# Teleport Einstellungen
teleport:
delay: 3 # Sekunden Wartezeit vor Teleport (0 = sofort)
cooldown: 5 # Cooldown in Sekunden
warmup-cancel-on-move: true # Teleport abbrechnen wenn Spieler sich bewegt
request-timeout: 60 # Sekunden bis eine TP-Anfrage verfällt
# Home Einstellungen
homes:
max-homes-default: 3 # Standard maximale Homes
max-homes-vip: 10
max-homes-premium: 25
# Warp Einstellungen
warps:
allow-player-warps: false # Darf jeder Spieler Warps erstellen?
warp-permission-prefix: "teleportsuite.warp." # z.B. teleportsuite.warp.spawn
# Portal Einstellungen
portals:
check-interval: 5 # Ticks zwischen Portal-Checks
particle-effect: true
# Spawn Einstellungen
spawn:
first-join-teleport: true # Neuer Spieler → FirstSpawn
death-respawn-to-spawn: false # Tod → Spawn statt Bett
# Nachrichten (unterstützt &-Farbcodes)
messages:
prefix: "&8[&6TP&8] &r"
teleport-success: "&aDu wurdest teleportiert!"
teleport-warmup: "&eTeleportiere in &6{seconds}&e Sekunden... Nicht bewegen!"
teleport-cancelled: "&cTeleport abgebrochen - du hast dich bewegt!"
teleport-cooldown: "&cBitte warte noch &6{seconds}&c Sekunden."
tpa-sent: "&aTeleportanfrage an &6{player}&a gesendet."
tpa-received: "&6{player} &emöchte zu dir teleportieren. &a/tpaccept &eoder &c/tpdeny"
tpa-accepted: "&a{player} hat deine Anfrage akzeptiert!"
tpa-denied: "&c{player} hat deine Anfrage abgelehnt."
tpa-expired: "&cDeine Teleportanfrage ist abgelaufen."
home-set: "&aHome &6{name}&a gesetzt!"
home-deleted: "&cHome &6{name}&c gelöscht."
home-not-found: "&cHome &6{name}&c nicht gefunden."
home-limit: "&cDu hast das Maximum von &6{max}&c Homes erreicht."
warp-set: "&aWarp &6{name}&a erstellt!"
warp-deleted: "&cWarp &6{name}&c gelöscht."
warp-not-found: "&cWarp &6{name}&c nicht gefunden."
back-no-location: "&cKein vorheriger Ort gespeichert."
death-no-location: "&cKein Todesort gespeichert."
no-permission: "&cDazu hast du keine Berechtigung."
player-not-found: "&cSpieler &6{player}&c nicht gefunden."
portal-created: "&aPortal &6{name}&a erstellt!"
portal-deleted: "&cPortal &6{name}&c gelöscht."
savepoint-set: "&aSavepoint &6{name}&a gesetzt!"
spawn-set: "&aSpawn gesetzt!"
firstspawn-set: "&aFirstSpawn gesetzt!"

View File

@@ -0,0 +1,148 @@
name: TeleportSuite
version: 1.0.2
main: de.teleportsuite.TeleportSuite
api-version: 1.20
description: BungeeCord-fähiges Teleport-Komplettpaket
author: M_Viper
softdepend: []
commands:
tp:
description: Teleportiere zu einem Spieler
usage: /tp <player>
permission: teleportsuite.tp
tphere:
description: Teleportiere einen Spieler zu dir
usage: /tphere <player>
permission: teleportsuite.tphere
tpa:
description: Sende eine Teleportanfrage
usage: /tpa <player>
permission: teleportsuite.tpa
tpaccept:
description: Akzeptiere eine Teleportanfrage
usage: /tpaccept
permission: teleportsuite.tpaccept
tpdeny:
description: Lehne eine Teleportanfrage ab
usage: /tpdeny
permission: teleportsuite.tpdeny
back:
description: Teleportiere zur letzten Position
usage: /back
permission: teleportsuite.back
deathback:
description: Teleportiere zum letzten Todesort
usage: /deathback
permission: teleportsuite.deathback
sethome:
description: Setze ein Home
usage: /sethome [name]
permission: teleportsuite.sethome
home:
description: Teleportiere zu einem Home
usage: /home [name]
permission: teleportsuite.home
delhome:
description: Lösche ein Home
usage: /delhome <name>
permission: teleportsuite.delhome
homes:
description: Liste alle Homes auf
usage: /homes
permission: teleportsuite.home
setwarp:
description: Setze einen Warp
usage: /setwarp <name>
permission: teleportsuite.setwarp
warp:
description: Teleportiere zu einem Warp
usage: /warp <name>
permission: teleportsuite.warp
delwarp:
description: Lösche einen Warp
usage: /delwarp <name>
permission: teleportsuite.delwarp
warps:
description: Liste alle Warps auf
usage: /warps
permission: teleportsuite.warp
setportal:
description: Erstelle ein Portal (2 Positionen markieren)
usage: /setportal <name> <target-server/world>
permission: teleportsuite.setportal
delportal:
description: Lösche ein Portal
usage: /delportal <name>
permission: teleportsuite.delportal
portals:
description: Liste alle Portale auf
usage: /portals
permission: teleportsuite.portals
setsavepoint:
description: Setze einen Savepoint
usage: /setsavepoint [name]
permission: teleportsuite.savepoint
savepoint:
description: Teleportiere zu einem Savepoint
usage: /savepoint [name]
permission: teleportsuite.savepoint
setspawn:
description: Setze den Spawn
usage: /setspawn
permission: teleportsuite.setspawn
spawn:
description: Teleportiere zum Spawn
usage: /spawn
permission: teleportsuite.spawn
setfirstspawn:
description: Setze den FirstSpawn
usage: /setfirstspawn
permission: teleportsuite.setfirstspawn
tppos:
description: Teleportiere zu Koordinaten
usage: /tppos <x> <y> <z> [world]
permission: teleportsuite.tppos
tpall:
description: Teleportiere alle Spieler zu dir
usage: /tpall
permission: teleportsuite.tpall
tpworld:
description: Teleportiere in eine Welt
usage: /tpworld <world>
permission: teleportsuite.tpworld
entitytransport:
description: Transportiere ein Entity
usage: /entitytransport <entity-id> <player/world>
permission: teleportsuite.entitytransport
permissions:
teleportsuite.*:
description: Alle TeleportSuite-Rechte
children:
teleportsuite.tp: true
teleportsuite.tphere: true
teleportsuite.tpa: true
teleportsuite.tpaccept: true
teleportsuite.tpdeny: true
teleportsuite.back: true
teleportsuite.deathback: true
teleportsuite.sethome: true
teleportsuite.home: true
teleportsuite.setwarp: true
teleportsuite.warp: true
teleportsuite.setportal: true
teleportsuite.delportal: true
teleportsuite.portals: true
teleportsuite.savepoint: true
teleportsuite.setspawn: true
teleportsuite.spawn: true
teleportsuite.setfirstspawn: true
teleportsuite.tppos: true
teleportsuite.tpall: true
teleportsuite.tpworld: true
teleportsuite.entitytransport: true
teleportsuite.admin: true
teleportsuite.home.unlimited:
description: Unbegrenzte Homes
default: op