Upload folder via GUI - src
This commit is contained in:
@@ -529,6 +529,12 @@ public class NexusLobby extends JavaPlugin implements Listener {
|
||||
if (params.equalsIgnoreCase("parkour_top")) {
|
||||
return parkourManager != null ? parkourManager.getTopTen() : "N/A";
|
||||
}
|
||||
if (params.equalsIgnoreCase("parkour_top_1")) {
|
||||
return parkourManager != null ? parkourManager.getTopTen(1) : "N/A";
|
||||
}
|
||||
if (params.equalsIgnoreCase("parkour_top_2")) {
|
||||
return parkourManager != null ? parkourManager.getTopTen(2) : "N/A";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class LobbyTabCompleter implements TabCompleter {
|
||||
if (sender.hasPermission("nexuslobby.admin")) {
|
||||
suggestions.addAll(Arrays.asList(
|
||||
"setstart", "setfinish", "setcheckpoint",
|
||||
"reset", "clear", "removeall", "info"
|
||||
"holo", "reset", "clear", "removeall", "info"
|
||||
));
|
||||
} else {
|
||||
// Normale Spieler können nur ihren Run abbrechen
|
||||
@@ -77,7 +77,8 @@ public class LobbyTabCompleter implements TabCompleter {
|
||||
String parkSub = args[1].toLowerCase();
|
||||
if (parkSub.equals("setstart")
|
||||
|| parkSub.equals("setfinish")
|
||||
|| parkSub.equals("setcheckpoint")) {
|
||||
|| parkSub.equals("setcheckpoint")
|
||||
|| parkSub.equals("holo")) {
|
||||
suggestions.addAll(Arrays.asList("1", "2"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.nexuslobby.commands;
|
||||
|
||||
import de.nexuslobby.NexusLobby;
|
||||
import de.nexuslobby.modules.ScoreboardModule;
|
||||
import de.nexuslobby.modules.hologram.HologramModule;
|
||||
import de.nexuslobby.modules.parkour.ParkourManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -206,6 +207,25 @@ public class NexusLobbyCommand implements CommandExecutor {
|
||||
player.sendMessage(pm.getTrackInfo());
|
||||
break;
|
||||
|
||||
// /nexus parkour holo <1|2> – Leaderboard-Hologramm an aktueller Position setzen
|
||||
case "holo": {
|
||||
int track = parseTrack(args, 2, player);
|
||||
if (track == -1) return;
|
||||
HologramModule hm = NexusLobby.getInstance().getHologramModule();
|
||||
if (hm == null) {
|
||||
player.sendMessage("§cHologram-Modul nicht verfügbar!");
|
||||
return;
|
||||
}
|
||||
String holoId = "parkour_top_" + track;
|
||||
List<String> pages = new java.util.ArrayList<>();
|
||||
pages.add("%nexuslobby_parkour_top_" + track + "%");
|
||||
hm.createHologram(holoId, player.getLocation(), pages);
|
||||
player.sendMessage("§8[§6Parkour§8] §aLeaderboard-Hologramm für §eStrecke " + track
|
||||
+ " §agesetzt! §8(ID: §7" + holoId + "§8)");
|
||||
player.sendMessage("§8[§6Parkour§8] §7Das Hologramm aktualisiert sich automatisch via PlaceholderAPI.");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
player.sendMessage(de.nexuslobby.utils.LangManager.get("unknown_subcommand"));
|
||||
break;
|
||||
@@ -318,6 +338,7 @@ public class NexusLobbyCommand implements CommandExecutor {
|
||||
player.sendMessage("§e/nexus parkour setstart <1|2> §7- Start setzen");
|
||||
player.sendMessage("§e/nexus parkour setcheckpoint <1|2> §7- Checkpoint setzen");
|
||||
player.sendMessage("§e/nexus parkour setfinish <1|2> §7- Ziel setzen");
|
||||
player.sendMessage("§e/nexus parkour holo <1|2> §7- Top-10 Hologramm setzen");
|
||||
player.sendMessage("§e/nexus parkour reset §7- Eigenen Run abbrechen");
|
||||
player.sendMessage("§e/nexus parkour clear §7- §cTop-10 Liste löschen");
|
||||
player.sendMessage(de.nexuslobby.utils.LangManager.get("info_removeall"));
|
||||
|
||||
@@ -23,6 +23,8 @@ public class ConversationManager {
|
||||
|
||||
// Verhindert Mehrfach-Gespräche und regelt die 60s Pause
|
||||
private final Set<UUID> activeSpeakers = new HashSet<>();
|
||||
// Alle aktiven Bubble-Entities tracken – für zuverlässiges Cleanup bei Reload/Crash
|
||||
private final Set<UUID> activeBubbles = new HashSet<>();
|
||||
|
||||
public ConversationManager(NexusLobby plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -50,6 +52,14 @@ public class ConversationManager {
|
||||
* zu breit und hätte auch legitime Marker-ArmorStands anderer Systeme gelöscht.
|
||||
*/
|
||||
public void clearHangingBubbles() {
|
||||
// Zuerst: Alle getrackte Bubble-Entities direkt entfernen (schnell, kein World-Scan nötig)
|
||||
for (UUID uuid : new HashSet<>(activeBubbles)) {
|
||||
Entity e = Bukkit.getEntity(uuid);
|
||||
if (e != null) e.remove();
|
||||
}
|
||||
activeBubbles.clear();
|
||||
|
||||
// Danach: Vollständiger World-Scan als Fallback (fängt Bubbles nach Crash/Reload ab)
|
||||
int count = 0;
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (ArmorStand as : world.getEntitiesByClass(ArmorStand.class)) {
|
||||
@@ -228,10 +238,15 @@ public class ConversationManager {
|
||||
s.setCustomName(ChatColorTranslate(text));
|
||||
s.setCustomNameVisible(true);
|
||||
s.setInvulnerable(true);
|
||||
s.setPersistent(false); // Überlebt keinen Server-Neustart/-Absturz
|
||||
s.addScoreboardTag("nexus_bubble");
|
||||
});
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(plugin, bubble::remove, 80L); // 4s Sichtbarkeit
|
||||
activeBubbles.add(bubble.getUniqueId());
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
bubble.remove();
|
||||
activeBubbles.remove(bubble.getUniqueId());
|
||||
}, 80L); // 4s Sichtbarkeit
|
||||
}
|
||||
|
||||
// --- Legacy Support & Config Methoden ---
|
||||
@@ -275,8 +290,8 @@ public class ConversationManager {
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
setupFile();
|
||||
clearHangingBubbles(); // Erst aufräumen, dann neu laden
|
||||
activeSpeakers.clear();
|
||||
clearHangingBubbles();
|
||||
setupFile();
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
@@ -47,6 +48,9 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
private static final double VOID_THRESHOLD = -5.0;
|
||||
private static final double CLEANUP_RADIUS = 5.0;
|
||||
|
||||
// Verhindert dass Dribbling einen Kick sofort überschreibt.
|
||||
private static final long KICK_DRIBBLE_LOCK_MS = 300L;
|
||||
|
||||
private static final double PARTICLE_SPEED_HIGH = 0.85;
|
||||
private static final double PARTICLE_SPEED_MEDIUM = 0.45;
|
||||
private static final double PARTICLE_SPEED_MIN = 0.05;
|
||||
@@ -70,6 +74,7 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
private Location spawnLocation;
|
||||
private long lastMoveTime;
|
||||
private long lastGoalTime = 0L;
|
||||
private long lastKickTime = 0L;
|
||||
|
||||
// ── Tor-Erkennung: Position aus dem VORHERIGEN Tick ───────────────────────
|
||||
//
|
||||
@@ -134,12 +139,11 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
handleDribbling();
|
||||
|
||||
// ── SCHRITT 3: Nach Physik die neue Position lesen ─────────────────
|
||||
// Minecraft hat jetzt die Position um vel verschoben.
|
||||
// Da getLocation() einen Tick verzögert ist, lesen wir hier noch
|
||||
// currentPos – aber über den Velocity-Vektor wissen wir die neue Pos.
|
||||
// Wir nutzen deshalb: newPos = currentPos + velocity (vor Drag)
|
||||
// Das ist die tatsächliche neue Ballposition nach diesem Tick.
|
||||
Location newPos = currentPos.clone().add(vel);
|
||||
// Minecraft wendet nach setVelocity noch Drag (0.98 horizontal, Gravity ~0.08
|
||||
// + 0.98 vertikal) an. Wir approximieren: newPos = currentPos + vel * 0.98
|
||||
// Das ist deutlich genauer als currentPos + vel und vermeidet 1-Tick-Versatz
|
||||
// bei der Tor-Erkennung nach schnellen Kicks.
|
||||
Location newPos = currentPos.clone().add(vel.clone().multiply(0.98));
|
||||
|
||||
// ── SCHRITT 4: Segment prüfen ─────────────────────────────────────
|
||||
// Das Segment prevPos → newPos deckt den vollständigen Weg ab den
|
||||
@@ -277,6 +281,7 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
|
||||
private void handleDribbling() {
|
||||
if (ball == null || !ball.isValid()) return;
|
||||
if (System.currentTimeMillis() - lastKickTime < KICK_DRIBBLE_LOCK_MS) return;
|
||||
for (Entity nearby : ball.getNearbyEntities(DRIBBLE_DETECTION_RADIUS, DRIBBLE_HEIGHT, DRIBBLE_DETECTION_RADIUS)) {
|
||||
if (nearby instanceof Player player) {
|
||||
Vector dir = ball.getLocation().toVector().subtract(player.getLocation().toVector());
|
||||
@@ -290,8 +295,16 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
}
|
||||
|
||||
private void handleWallBounce(Vector vel) {
|
||||
if (vel.lengthSquared() < 0.001) return;
|
||||
// Nur prüfen wenn genug horizontale Bewegung vorhanden ist.
|
||||
// Y-Komponente absichtlich ignoriert – der Bounce gilt nur für Wände (X/Z),
|
||||
// nicht für Boden/Decke. So verhindert man dass liegende Boden-Blöcke
|
||||
// fälschlicherweise als Wand erkannt werden und den Ball dauerhaft blockieren.
|
||||
double hSpeed = vel.getX() * vel.getX() + vel.getZ() * vel.getZ();
|
||||
if (hSpeed < 0.001) return;
|
||||
|
||||
Location loc = ball.getLocation();
|
||||
// Y + 0.5 anheben damit wir auf Wand-Höhe prüfen, nicht auf Boden-Ebene.
|
||||
// Ohne den Offset würde loc.getY() (Boden des ArmorStands) den Bodenblock selbst treffen.
|
||||
Block nx = loc.clone().add(vel.getX() * WALL_CHECK_DISTANCE, 0.5, 0).getBlock();
|
||||
Block nz = loc.clone().add(0, 0.5, vel.getZ() * WALL_CHECK_DISTANCE).getBlock();
|
||||
boolean bounced = false;
|
||||
@@ -531,6 +544,7 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
// prevPos auf aktuelle Position setzen bevor der Ball sich bewegt –
|
||||
// so startet das nächste Segment am richtigen Punkt.
|
||||
prevPos = ball.getLocation().clone();
|
||||
lastKickTime = System.currentTimeMillis();
|
||||
ball.setVelocity(dir);
|
||||
|
||||
ball.getWorld().playSound(ball.getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 0.6f, 1.5f);
|
||||
@@ -542,6 +556,45 @@ public class SoccerModule implements Module, Listener, CommandExecutor {
|
||||
if (ball != null && event.getRightClicked().equals(ball)) event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
// Wenn ein Spieler joinт: Ball-State prüfen und ggf. resynchronisieren.
|
||||
// Passiert z.B. nach Server-Wechsel via BungeeCord: der Chunk wird neu geladen,
|
||||
// alte Ball-Entities tauchen wieder auf, die interne Referenz zeigt evtl. auf
|
||||
// die falsche oder eine ungültige Instanz.
|
||||
Bukkit.getScheduler().runTaskLater(NexusLobby.getInstance(), () -> {
|
||||
if (spawnLocation == null || spawnLocation.getWorld() == null) return;
|
||||
|
||||
// Alle alten nexusball-Entities in der Welt suchen
|
||||
boolean foundValid = false;
|
||||
for (Entity e : spawnLocation.getWorld().getEntities()) {
|
||||
if (!(e instanceof ArmorStand as)) continue;
|
||||
if (!isBallEntity(as)) continue;
|
||||
|
||||
if (ball != null && ball.isValid() && as.getUniqueId().equals(ball.getUniqueId())) {
|
||||
// Referenz ist noch korrekt und gültig – alles gut
|
||||
foundValid = true;
|
||||
} else if (ball == null || !ball.isValid()) {
|
||||
// Unsere Referenz ist verloren – die gefundene Entity übernehmen
|
||||
ball = as;
|
||||
prevPos = as.getLocation().clone();
|
||||
lastMoveTime = System.currentTimeMillis();
|
||||
foundValid = true;
|
||||
Bukkit.getLogger().info("[Soccer] Ball-Referenz nach Join wiederhergestellt.");
|
||||
} else {
|
||||
// Duplikat – entfernen
|
||||
as.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundValid) {
|
||||
// Kein Ball in der Welt – neu spawnen
|
||||
respawnBall();
|
||||
Bukkit.getLogger().info("[Soccer] Ball nach Join neu gespawnt.");
|
||||
}
|
||||
}, 20L); // 1s warten damit der Chunk sicher geladen ist
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// COMMANDS
|
||||
// =========================================================================
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerUnleashEntityEvent;
|
||||
import org.bukkit.event.player.PlayerFishEvent.State;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
@@ -764,4 +765,14 @@ public class GadgetModule implements Module, Listener {
|
||||
this.activeShields.clear();
|
||||
GadgetShield.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
removeGadgets(player);
|
||||
UUID uuid = player.getUniqueId();
|
||||
meteorCooldowns.remove(uuid);
|
||||
freezeCooldowns.remove(uuid);
|
||||
grapplingCooldowns.remove(uuid);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,9 @@ public class ParkourListener implements Listener {
|
||||
Location loc = player.getLocation();
|
||||
|
||||
// --- 1. ABSTURZ-CHECK ---
|
||||
if (loc.getY() < 50) {
|
||||
// Absturz-Y aus config lesen (Standard: 50), damit Maps unter Y=50 korrekt funktionieren
|
||||
double fallY = NexusLobby.getInstance().getConfig().getDouble("parkour.fall_y", 50.0);
|
||||
if (loc.getY() < fallY) {
|
||||
Location lastCp = manager.getCheckpoint(player);
|
||||
if (lastCp != null) {
|
||||
player.teleport(lastCp);
|
||||
|
||||
@@ -63,6 +63,7 @@ public class ParkourManager {
|
||||
this.plugin = plugin;
|
||||
this.file = new File(plugin.getDataFolder(), "parkour.yml");
|
||||
loadConfig();
|
||||
migrateLegacyBestTimes();
|
||||
startParticleTask();
|
||||
}
|
||||
|
||||
@@ -82,6 +83,44 @@ public class ParkourManager {
|
||||
config = YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migriert Bestzeiten vom alten Format (besttimes.<uuid>) ins neue Format
|
||||
* (besttimes.<track>.<uuid>). Alte Zeiten werden Track 1 zugeordnet, da vor
|
||||
* dieser Änderung nur ein Track existierte.
|
||||
* Läuft einmalig beim Start; tut nichts wenn keine alten Daten vorhanden sind.
|
||||
*/
|
||||
private void migrateLegacyBestTimes() {
|
||||
if (!config.contains("besttimes")) return;
|
||||
|
||||
// Prüfen ob es direkte UUID-Keys unter besttimes gibt (altes Format)
|
||||
// Im neuen Format wären hier nur "1" und "2" als Keys
|
||||
var section = config.getConfigurationSection("besttimes");
|
||||
if (section == null) return;
|
||||
|
||||
int migrated = 0;
|
||||
for (String key : new java.util.HashSet<>(section.getKeys(false))) {
|
||||
// Neue Keys sind "1" oder "2" – alte Keys sind UUID-Strings (36 Zeichen, enthalten "-")
|
||||
if (!key.equals("1") && !key.equals("2") && key.contains("-")) {
|
||||
double time = config.getDouble("besttimes." + key);
|
||||
// Nur migrieren wenn unter besttimes.1.<uuid> noch kein besserer Wert steht
|
||||
String newPath = "besttimes.1." + key;
|
||||
double existingTime = config.getDouble(newPath, 99999.9);
|
||||
if (time < existingTime) {
|
||||
config.set(newPath, time);
|
||||
}
|
||||
// Alten Key entfernen
|
||||
config.set("besttimes." + key, null);
|
||||
migrated++;
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated > 0) {
|
||||
save();
|
||||
plugin.getLogger().info("[Parkour] Migration: " + migrated
|
||||
+ " Bestzeit(en) von altem Format nach Strecke 1 übertragen.");
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
try {
|
||||
config.save(file);
|
||||
@@ -325,7 +364,8 @@ public class ParkourManager {
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
private void saveBestTime(Player player, double time) {
|
||||
String path = "besttimes." + player.getUniqueId();
|
||||
int track = activeTrack.getOrDefault(player.getUniqueId(), 1);
|
||||
String path = "besttimes." + track + "." + player.getUniqueId();
|
||||
double currentTime = config.getDouble(path, 99999.9);
|
||||
if (time < currentTime) {
|
||||
config.set(path, time);
|
||||
@@ -346,21 +386,51 @@ public class ParkourManager {
|
||||
save();
|
||||
}
|
||||
|
||||
public void clearStats(int track) {
|
||||
config.set("besttimes." + track, null);
|
||||
save();
|
||||
}
|
||||
|
||||
public String getTopTen() {
|
||||
if (!config.contains("besttimes") || config.getConfigurationSection("besttimes") == null)
|
||||
return "§6§l🏆 TOP 10 PARKOUR 🏆\n§7Noch keine Rekorde.";
|
||||
// Fallback: kombiniert beide Tracks (Legacy-Support für %nexuslobby_parkour_top%)
|
||||
return getTopTen(0);
|
||||
}
|
||||
|
||||
public String getTopTen(int track) {
|
||||
String trackLabel = track == 1 ? " §8(Strecke 1)" : track == 2 ? " §8(Strecke 2)" : "";
|
||||
|
||||
Map<String, Double> allTimes = new HashMap<>();
|
||||
for (String uuidStr : config.getConfigurationSection("besttimes").getKeys(false)) {
|
||||
allTimes.put(uuidStr, config.getDouble("besttimes." + uuidStr));
|
||||
|
||||
if (track == 0) {
|
||||
// Alle Tracks kombiniert (nimmt die beste Zeit je Spieler über alle Tracks)
|
||||
for (int t = 1; t <= 2; t++) {
|
||||
String section = "besttimes." + t;
|
||||
if (config.contains(section) && config.getConfigurationSection(section) != null) {
|
||||
for (String uuidStr : config.getConfigurationSection(section).getKeys(false)) {
|
||||
double time = config.getDouble(section + "." + uuidStr);
|
||||
allTimes.merge(uuidStr, time, Math::min);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String section = "besttimes." + track;
|
||||
if (!config.contains(section) || config.getConfigurationSection(section) == null) {
|
||||
return "§6§l🏆 TOP 10 PARKOUR" + trackLabel + "\n§7Noch keine Rekorde.";
|
||||
}
|
||||
for (String uuidStr : config.getConfigurationSection(section).getKeys(false)) {
|
||||
allTimes.put(uuidStr, config.getDouble(section + "." + uuidStr));
|
||||
}
|
||||
}
|
||||
|
||||
if (allTimes.isEmpty())
|
||||
return "§6§l🏆 TOP 10 PARKOUR" + trackLabel + "\n§7Noch keine Rekorde.";
|
||||
|
||||
List<Map.Entry<String, Double>> sortedList = allTimes.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByValue())
|
||||
.limit(10)
|
||||
.toList();
|
||||
|
||||
StringBuilder builder = new StringBuilder("§6§l🏆 TOP 10 PARKOUR 🏆");
|
||||
StringBuilder builder = new StringBuilder("§6§l🏆 TOP 10 PARKOUR" + trackLabel);
|
||||
int rank = 1;
|
||||
for (Map.Entry<String, Double> entry : sortedList) {
|
||||
String name = config.getString("names." + entry.getKey(), "Unbekannt");
|
||||
|
||||
@@ -41,7 +41,7 @@ public class DoubleJump implements Listener {
|
||||
@EventHandler
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (player.getGameMode() != GameMode.CREATIVE && player.getLocation().subtract(0, 0.1, 0).getBlock().getType() != Material.AIR) {
|
||||
if (player.getGameMode() != GameMode.CREATIVE && player.getGameMode() != GameMode.SPECTATOR && player.getLocation().subtract(0, 0.1, 0).getBlock().getType() != Material.AIR) {
|
||||
if (NexusLobby.getInstance().getConfig().getBoolean("doublejump.enabled", true)) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
@@ -84,4 +85,9 @@ public class PlayerHider implements Listener {
|
||||
private String colorize(String s) {
|
||||
return s == null ? "" : s.replace("&", "§");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
hidden.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package de.nexuslobby.utils;
|
||||
import de.nexuslobby.NexusLobby;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -17,7 +19,21 @@ public class VoidProtection implements Listener {
|
||||
Player player = event.getPlayer();
|
||||
if (player.getLocation().getY() < 0) {
|
||||
if (NexusLobby.getInstance().getConfig().getBoolean("void_protection.teleport_to_spawn", true)) {
|
||||
Location spawn = player.getWorld().getSpawnLocation();
|
||||
FileConfiguration config = NexusLobby.getInstance().getConfig();
|
||||
Location spawn;
|
||||
if (config.contains("spawn.world")) {
|
||||
String worldName = config.getString("spawn.world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world != null) {
|
||||
spawn = new Location(world,
|
||||
config.getDouble("spawn.x"), config.getDouble("spawn.y"), config.getDouble("spawn.z"),
|
||||
(float) config.getDouble("spawn.yaw"), (float) config.getDouble("spawn.pitch"));
|
||||
} else {
|
||||
spawn = player.getWorld().getSpawnLocation();
|
||||
}
|
||||
} else {
|
||||
spawn = player.getWorld().getSpawnLocation();
|
||||
}
|
||||
player.teleport(spawn);
|
||||
String msg = de.nexuslobby.utils.LangManager.get("void_protection_message");
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: NexusLobby
|
||||
main: de.nexuslobby.NexusLobby
|
||||
version: "1.8"
|
||||
version: "1.9"
|
||||
api-version: "1.21"
|
||||
author: M_Viper
|
||||
description: Modular Lobby Plugin with an invisible Particle-Parkour system.
|
||||
|
||||
Reference in New Issue
Block a user