Update from Git Manager GUI
This commit is contained in:
@@ -1,30 +1,83 @@
|
|||||||
package de.viper.survivalplus.Manager;
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
|
||||||
public class BlockManager {
|
public class BlockManager {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
private final Map<UUID, Set<UUID>> blockedPlayers = new HashMap<>();
|
private final Map<UUID, Set<UUID>> blockedPlayers = new HashMap<>();
|
||||||
|
private File blocksFile;
|
||||||
|
private FileConfiguration blocksConfig;
|
||||||
|
|
||||||
|
public BlockManager(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.blocksFile = new File(plugin.getDataFolder(), "blocks.yml");
|
||||||
|
if (!blocksFile.exists()) {
|
||||||
|
try {
|
||||||
|
blocksFile.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.blocksConfig = YamlConfiguration.loadConfiguration(blocksFile);
|
||||||
|
loadBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveBlocks() {
|
||||||
|
for (UUID key : blockedPlayers.keySet()) {
|
||||||
|
List<String> uuids = new ArrayList<>();
|
||||||
|
for (UUID uuid : blockedPlayers.get(key)) {
|
||||||
|
uuids.add(uuid.toString());
|
||||||
|
}
|
||||||
|
blocksConfig.set(key.toString(), uuids);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
blocksConfig.save(blocksFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadBlocks() {
|
||||||
|
blockedPlayers.clear();
|
||||||
|
for (String key : blocksConfig.getKeys(false)) {
|
||||||
|
UUID blockerUUID = UUID.fromString(key);
|
||||||
|
List<String> blockedUUIDs = blocksConfig.getStringList(key);
|
||||||
|
Set<UUID> blockedSet = new HashSet<>();
|
||||||
|
for (String uuidStr : blockedUUIDs) {
|
||||||
|
blockedSet.add(UUID.fromString(uuidStr));
|
||||||
|
}
|
||||||
|
blockedPlayers.put(blockerUUID, blockedSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void blockPlayer(Player blocker, Player toBlock) {
|
public void blockPlayer(Player blocker, Player toBlock) {
|
||||||
blockedPlayers.computeIfAbsent(blocker.getUniqueId(), k -> new HashSet<>()).add(toBlock.getUniqueId());
|
blockedPlayers.computeIfAbsent(blocker.getUniqueId(), k -> new HashSet<>()).add(toBlock.getUniqueId());
|
||||||
|
saveBlocks(); // Sofort speichern
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unblockPlayer(Player blocker, Player toUnblock) {
|
public void unblockPlayer(Player blocker, Player toUnblock) {
|
||||||
Set<UUID> blocked = blockedPlayers.get(blocker.getUniqueId());
|
Set<UUID> blocked = blockedPlayers.get(blocker.getUniqueId());
|
||||||
if (blocked != null) {
|
if (blocked != null) {
|
||||||
blocked.remove(toUnblock.getUniqueId());
|
blocked.remove(toUnblock.getUniqueId());
|
||||||
if (blocked.isEmpty()) {
|
if (blocked.isEmpty()) {
|
||||||
blockedPlayers.remove(blocker.getUniqueId());
|
blockedPlayers.remove(blocker.getUniqueId());
|
||||||
|
}
|
||||||
|
saveBlocks(); // Sofort speichern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasBlocked(Player blocker, Player potentialBlocked) {
|
public boolean hasBlocked(Player blocker, Player potentialBlocked) {
|
||||||
return blockedPlayers.getOrDefault(blocker.getUniqueId(), Collections.emptySet())
|
return blockedPlayers.getOrDefault(blocker.getUniqueId(), Collections.emptySet())
|
||||||
.contains(potentialBlocked.getUniqueId());
|
.contains(potentialBlocked.getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<UUID> getBlockedPlayers(Player player) {
|
public Set<UUID> getBlockedPlayers(Player player) {
|
||||||
@@ -33,5 +86,6 @@ public class BlockManager {
|
|||||||
|
|
||||||
public void clear(Player player) {
|
public void clear(Player player) {
|
||||||
blockedPlayers.remove(player.getUniqueId());
|
blockedPlayers.remove(player.getUniqueId());
|
||||||
|
saveBlocks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,18 +6,21 @@ import org.bukkit.*;
|
|||||||
import org.bukkit.block.Chest;
|
import org.bukkit.block.Chest;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.command.*;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
@@ -34,9 +37,17 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
private final int maxLootPerPlayer;
|
private final int maxLootPerPlayer;
|
||||||
private final long lootLimitResetMillis;
|
private final long lootLimitResetMillis;
|
||||||
|
|
||||||
|
// Persistence
|
||||||
|
private final File lootChestFile;
|
||||||
|
private FileConfiguration lootChestConfig;
|
||||||
|
|
||||||
public LootChestManager(SurvivalPlus plugin) {
|
public LootChestManager(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.lootChestFile = new File(plugin.getDataFolder(), "lootchests.yml");
|
||||||
|
this.lootChestConfig = YamlConfiguration.loadConfiguration(lootChestFile);
|
||||||
|
|
||||||
loadLootFromConfig();
|
loadLootFromConfig();
|
||||||
|
loadActiveChests(); // Kisten beim Start laden
|
||||||
|
|
||||||
FileConfiguration cfg = plugin.getConfig();
|
FileConfiguration cfg = plugin.getConfig();
|
||||||
this.despawnMillis = cfg.getLong("lootchest.despawn-minutes", 10) * 60 * 1000;
|
this.despawnMillis = cfg.getLong("lootchest.despawn-minutes", 10) * 60 * 1000;
|
||||||
@@ -49,6 +60,102 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
startLootLimitResetTask();
|
startLootLimitResetTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lädt gespeicherte Kisten aus der Datei und prüft, ob sie abgelaufen sind
|
||||||
|
*/
|
||||||
|
private void loadActiveChests() {
|
||||||
|
if (!lootChestFile.exists()) return;
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
List<Location> toRemoveFile = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String key : lootChestConfig.getKeys(false)) {
|
||||||
|
try {
|
||||||
|
long spawnTime = lootChestConfig.getLong(key);
|
||||||
|
|
||||||
|
// Prüfen ob die Zeit abgelaufen ist (inklusive Offline-Zeit)
|
||||||
|
if (now - spawnTime >= despawnMillis) {
|
||||||
|
String[] parts = key.split("_");
|
||||||
|
if (parts.length == 4) {
|
||||||
|
World w = Bukkit.getWorld(parts[0]);
|
||||||
|
if (w != null) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
Location loc = new Location(w, x, y, z);
|
||||||
|
|
||||||
|
// Kiste physikalisch löschen falls noch vorhanden
|
||||||
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
|
loc.getBlock().setType(Material.AIR);
|
||||||
|
}
|
||||||
|
toRemoveFile.add(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Kiste ist noch gültig -> in den Speicher laden
|
||||||
|
String[] parts = key.split("_");
|
||||||
|
if (parts.length == 4) {
|
||||||
|
World w = Bukkit.getWorld(parts[0]);
|
||||||
|
if (w != null) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
Location loc = new Location(w, x, y, z);
|
||||||
|
|
||||||
|
// Integritätsprüfung: Ist da auch wirklich eine Kiste?
|
||||||
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
|
activeChests.add(loc);
|
||||||
|
chestSpawnTimes.put(loc, spawnTime);
|
||||||
|
} else {
|
||||||
|
// Datei sagt ja, Welt sagt nein -> Cleanup in Datei
|
||||||
|
toRemoveFile.add(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("Fehler beim Laden einer Lootkiste: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alte Einträge aus der Datei entfernen
|
||||||
|
for (Location loc : toRemoveFile) {
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, null);
|
||||||
|
}
|
||||||
|
saveActiveChests();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert die aktuellen aktiven Kisten in die Datei
|
||||||
|
*/
|
||||||
|
private void saveActiveChests() {
|
||||||
|
lootChestConfig = new YamlConfiguration();
|
||||||
|
for (Map.Entry<Location, Long> entry : chestSpawnTimes.entrySet()) {
|
||||||
|
Location loc = entry.getKey();
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, entry.getValue());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
lootChestConfig.save(lootChestFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().severe("Konnte lootchests.yml nicht speichern!");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt eine Kiste komplett aus System und Datei (z.B. beim Looten)
|
||||||
|
*/
|
||||||
|
private void removeChestData(Location loc) {
|
||||||
|
activeChests.remove(loc);
|
||||||
|
chestSpawnTimes.remove(loc);
|
||||||
|
|
||||||
|
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
lootChestConfig.set(key, null);
|
||||||
|
saveActiveChests();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadLootFromConfig() {
|
private void loadLootFromConfig() {
|
||||||
FileConfiguration cfg = plugin.getConfig();
|
FileConfiguration cfg = plugin.getConfig();
|
||||||
lootItems.clear();
|
lootItems.clear();
|
||||||
@@ -75,7 +182,11 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Falls deaktiviert, nichts tun
|
||||||
|
// Hinweis: Die Logik hier war "!enabled ... return; clearAll".
|
||||||
|
// Das bedeutet: Wenn enabled=true -> !enabled=false -> kein return -> clearAll.
|
||||||
if (!plugin.getConfig().getBoolean("lootchest.enabled", true)) return;
|
if (!plugin.getConfig().getBoolean("lootchest.enabled", true)) return;
|
||||||
|
|
||||||
clearAllActiveChests();
|
clearAllActiveChests();
|
||||||
for (int i = 0; i < spawnCount; i++) {
|
for (int i = 0; i < spawnCount; i++) {
|
||||||
spawnRandomLootChest();
|
spawnRandomLootChest();
|
||||||
@@ -88,26 +199,36 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startChestDespawnTask() {
|
private void startChestDespawnTask() {
|
||||||
|
// Prüft jede Minute (20 Ticks * 60)
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Sicheres Iterieren um ConcurrentModificationException zu vermeiden
|
||||||
Iterator<Location> it = activeChests.iterator();
|
Iterator<Location> it = activeChests.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Location loc = it.next();
|
Location loc = it.next();
|
||||||
Long spawnTime = chestSpawnTimes.get(loc);
|
Long spawnTime = chestSpawnTimes.get(loc);
|
||||||
|
|
||||||
if (spawnTime != null && now - spawnTime >= despawnMillis) {
|
if (spawnTime != null && now - spawnTime >= despawnMillis) {
|
||||||
if (loc.getBlock().getType() == Material.CHEST) {
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
loc.getBlock().setType(Material.AIR);
|
loc.getBlock().setType(Material.AIR);
|
||||||
}
|
}
|
||||||
it.remove();
|
|
||||||
|
// Manuell aus den Datenstrukturen entfernen
|
||||||
chestSpawnTimes.remove(loc);
|
chestSpawnTimes.remove(loc);
|
||||||
|
it.remove(); // Aus der Liste entfernen (Thread-Safe)
|
||||||
|
|
||||||
Bukkit.broadcastMessage(color(
|
Bukkit.broadcastMessage(color(
|
||||||
plugin.getLangConfig().getString("lootchest.despawn-msg",
|
plugin.getLangConfig().getString("lootchest.despawn-msg",
|
||||||
"&eEine Lootkiste ist von selbst verschwunden.")
|
"&eEine Lootkiste ist von selbst verschwunden.")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config einmal speichern (wichtig!)
|
||||||
|
saveActiveChests();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 20L * 60, 20L * 60);
|
}.runTaskTimer(plugin, 20L * 60, 20L * 60);
|
||||||
}
|
}
|
||||||
@@ -117,6 +238,7 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
if (loc.getBlock().getType() == Material.CHEST) {
|
if (loc.getBlock().getType() == Material.CHEST) {
|
||||||
loc.getBlock().setType(Material.AIR);
|
loc.getBlock().setType(Material.AIR);
|
||||||
}
|
}
|
||||||
|
removeChestData(loc);
|
||||||
}
|
}
|
||||||
activeChests.clear();
|
activeChests.clear();
|
||||||
chestSpawnTimes.clear();
|
chestSpawnTimes.clear();
|
||||||
@@ -158,6 +280,8 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
activeChests.add(loc);
|
activeChests.add(loc);
|
||||||
chestSpawnTimes.put(loc, System.currentTimeMillis());
|
chestSpawnTimes.put(loc, System.currentTimeMillis());
|
||||||
|
|
||||||
|
saveActiveChests();
|
||||||
|
|
||||||
world.spawnParticle(Particle.FIREWORK, loc.clone().add(0.5, 1.0, 0.5),
|
world.spawnParticle(Particle.FIREWORK, loc.clone().add(0.5, 1.0, 0.5),
|
||||||
20, 0.3, 0.5, 0.3);
|
20, 0.3, 0.5, 0.3);
|
||||||
world.playSound(loc, Sound.BLOCK_CHEST_OPEN, 1.0f, 1.0f);
|
world.playSound(loc, Sound.BLOCK_CHEST_OPEN, 1.0f, 1.0f);
|
||||||
@@ -265,8 +389,9 @@ public class LootChestManager implements Listener, CommandExecutor {
|
|||||||
if (looted >= maxLootPerPlayer) return;
|
if (looted >= maxLootPerPlayer) return;
|
||||||
playerLootCount.put(uuid, looted + 1);
|
playerLootCount.put(uuid, looted + 1);
|
||||||
chestLoc.getBlock().setType(Material.AIR);
|
chestLoc.getBlock().setType(Material.AIR);
|
||||||
activeChests.remove(chestLoc);
|
|
||||||
chestSpawnTimes.remove(chestLoc);
|
removeChestData(chestLoc);
|
||||||
|
|
||||||
Bukkit.broadcastMessage(color(
|
Bukkit.broadcastMessage(color(
|
||||||
plugin.getLangConfig().getString("lootchest.removed-msg", "&aEine Lootkiste wurde geleert und entfernt.")
|
plugin.getLangConfig().getString("lootchest.removed-msg", "&aEine Lootkiste wurde geleert und entfernt.")
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.viper.survivalplus.Manager;
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -25,6 +26,8 @@ import java.util.Date;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class TablistManager implements Listener {
|
public class TablistManager implements Listener {
|
||||||
|
|
||||||
@@ -70,18 +73,6 @@ public class TablistManager implements Listener {
|
|||||||
|
|
||||||
FileConfiguration config = plugin.getTablistConfig();
|
FileConfiguration config = plugin.getTablistConfig();
|
||||||
|
|
||||||
|
|
||||||
// Nicknames.yml laden
|
|
||||||
try {
|
|
||||||
File nicknameFile = new File(plugin.getDataFolder(), "nicknames.yml");
|
|
||||||
if (!nicknameFile.exists()) {
|
|
||||||
plugin.saveResource("nicknames.yml", false);
|
|
||||||
}
|
|
||||||
this.nicknameConfig = YamlConfiguration.loadConfiguration(nicknameFile);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
this.nicknameConfig = null; // Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
|
|
||||||
// Konfigurationswerte laden
|
// Konfigurationswerte laden
|
||||||
this.enabled = config.getBoolean("enabled", true);
|
this.enabled = config.getBoolean("enabled", true);
|
||||||
this.serverName = config.getString("server-name", "SurvivalPlus");
|
this.serverName = config.getString("server-name", "SurvivalPlus");
|
||||||
@@ -97,7 +88,7 @@ public class TablistManager implements Listener {
|
|||||||
try {
|
try {
|
||||||
this.luckPerms = LuckPermsProvider.get();
|
this.luckPerms = LuckPermsProvider.get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
luckPerms = null; // Keine Konsolenausgabe
|
luckPerms = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen, ob PlaceholderAPI verfügbar ist
|
// Prüfen, ob PlaceholderAPI verfügbar ist
|
||||||
@@ -140,6 +131,9 @@ public class TablistManager implements Listener {
|
|||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Nickname Config neu laden
|
||||||
|
reloadNicknameConfig();
|
||||||
|
|
||||||
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
||||||
|
|
||||||
// Online-Spieler und Staff zählen
|
// Online-Spieler und Staff zählen
|
||||||
@@ -154,22 +148,24 @@ public class TablistManager implements Listener {
|
|||||||
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
try {
|
try {
|
||||||
// Nickname oder Spielername verwenden
|
// Nickname abrufen (farbig)
|
||||||
String displayName = getNickname(player);
|
String displayName = getNickname(player);
|
||||||
|
// Falls kein Nickname, Name nehmen
|
||||||
if (displayName == null || displayName.trim().isEmpty()) {
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
displayName = player.getName();
|
displayName = player.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spielername für die Tablist setzen
|
// Spielername für die Tablist setzen (Spielerliste auf der rechten Seite)
|
||||||
String playerListName;
|
String playerListName;
|
||||||
String prefix = getPlayerPrefix(player);
|
String rankPrefix = getPlayerPrefix(player);
|
||||||
|
|
||||||
if (luckPerms == null && !hasPlaceholderAPI) {
|
if (luckPerms == null && !hasPlaceholderAPI) {
|
||||||
playerListName = displayName;
|
playerListName = displayName;
|
||||||
updateNametag(player, "", displayName);
|
updateNametag(player, rankPrefix, displayName);
|
||||||
} else {
|
} else {
|
||||||
int ping = getPlayerPing(player);
|
int ping = getPlayerPing(player);
|
||||||
playerListName = color(prefix + displayName + (ping >= 0 ? "&8 | &e" + ping + "ms" : ""));
|
playerListName = color(rankPrefix + displayName + (ping >= 0 ? "&8 | &e" + ping + "ms" : ""));
|
||||||
updateNametag(player, prefix, displayName);
|
updateNametag(player, rankPrefix, displayName);
|
||||||
}
|
}
|
||||||
player.setPlayerListName(playerListName);
|
player.setPlayerListName(playerListName);
|
||||||
|
|
||||||
@@ -215,7 +211,7 @@ public class TablistManager implements Listener {
|
|||||||
done = tryStringMethod(player, header, footer);
|
done = tryStringMethod(player, header, footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Keine Warnung bei Fehlschlag, da dies normal sein kann
|
// 3) Keine Warnung bei Fehlschlag
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
// Keine Konsolenausgabe für Fehler bei der Tablist
|
// Keine Konsolenausgabe für Fehler bei der Tablist
|
||||||
}
|
}
|
||||||
@@ -228,7 +224,22 @@ public class TablistManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nickname aus nicknames.yml abrufen
|
* Lädt die nicknames.yml neu
|
||||||
|
*/
|
||||||
|
private void reloadNicknameConfig() {
|
||||||
|
try {
|
||||||
|
File nicknameFile = new File(plugin.getDataFolder(), "nicknames.yml");
|
||||||
|
if (!nicknameFile.exists()) {
|
||||||
|
plugin.saveResource("nicknames.yml", false);
|
||||||
|
}
|
||||||
|
this.nicknameConfig = YamlConfiguration.loadConfiguration(nicknameFile);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
this.nicknameConfig = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nickname abrufen und formatieren
|
||||||
*/
|
*/
|
||||||
private String getNickname(Player player) {
|
private String getNickname(Player player) {
|
||||||
if (nicknameConfig == null) return null;
|
if (nicknameConfig == null) return null;
|
||||||
@@ -236,161 +247,130 @@ public class TablistManager implements Listener {
|
|||||||
String uuid = player.getUniqueId().toString();
|
String uuid = player.getUniqueId().toString();
|
||||||
String nickname = nicknameConfig.getString(uuid);
|
String nickname = nicknameConfig.getString(uuid);
|
||||||
if (nickname != null && !nickname.trim().isEmpty()) {
|
if (nickname != null && !nickname.trim().isEmpty()) {
|
||||||
try {
|
return translateNickColors(nickname);
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".nickname", nickname);
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return nickname;
|
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nametag über dem Kopf aktualisieren
|
* Nametag über dem Kopf aktualisieren
|
||||||
*/
|
*/
|
||||||
private void updateNametag(Player player, String prefix, String displayName) {
|
private void updateNametag(Player player, String rankPrefix, String nickname) {
|
||||||
if (scoreboard == null) return;
|
if (scoreboard == null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String teamName = generateTeamName(player, prefix);
|
String teamName = generateTeamName(player, rankPrefix);
|
||||||
Team team = scoreboard.getTeam(teamName);
|
Team team = scoreboard.getTeam(teamName);
|
||||||
|
|
||||||
// Team erstellen oder aktualisieren
|
|
||||||
if (team == null) {
|
if (team == null) {
|
||||||
team = scoreboard.registerNewTeam(teamName);
|
team = scoreboard.registerNewTeam(teamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix zwingend setzen, wenn LuckPerms installiert ist
|
// WICHTIG:
|
||||||
String coloredPrefix = color(prefix != null && !prefix.trim().isEmpty() ? prefix : (luckPerms != null ? "&7[Spieler] " : ""));
|
// Wir nutzen den Rang-Prefix ODER den Nickname als Team-Prefix.
|
||||||
team.setPrefix(coloredPrefix);
|
// Da wir den Namen über dem Kopf nicht komplett ersetzen können (ohne ProtocolLib),
|
||||||
|
// zeigen wir den Nickname als Prefix an.
|
||||||
|
// Ergebnis über Kopf: [Nick] Spielername
|
||||||
|
|
||||||
|
String prefix;
|
||||||
|
|
||||||
|
// Wenn ein Nickname existiert, hat er Vorrang über den Rang-Prefix (damit man ihn sieht)
|
||||||
|
if (nickname != null && !nickname.trim().isEmpty()) {
|
||||||
|
prefix = nickname;
|
||||||
|
} else {
|
||||||
|
prefix = color(rankPrefix != null && !rankPrefix.trim().isEmpty() ? rankPrefix : (luckPerms != null ? "&7[Spieler] " : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
team.setPrefix(prefix);
|
||||||
|
|
||||||
|
// WICHTIG: Der Entry MUSS der echte Spielername sein.
|
||||||
|
// Wir nutzen hier den echten Namen, nicht den Nicknamen, da Nicks zu lang sein können oder Sonderzeichen enthalten.
|
||||||
|
String entry = player.getName();
|
||||||
|
|
||||||
// Spieler dem Team hinzufügen
|
|
||||||
String entry = displayName != null && !displayName.trim().isEmpty() ? displayName : player.getName();
|
|
||||||
if (!team.hasEntry(entry)) {
|
if (!team.hasEntry(entry)) {
|
||||||
// Spieler aus anderen Teams entfernen, um Konflikte zu vermeiden
|
// Spieler aus anderen Teams entfernen
|
||||||
for (Team existingTeam : scoreboard.getTeams()) {
|
for (Team existingTeam : scoreboard.getTeams()) {
|
||||||
if (!existingTeam.getName().equals(teamName)) {
|
if (!existingTeam.getName().equals(teamName)) {
|
||||||
existingTeam.removeEntry(entry);
|
existingTeam.removeEntry(entry);
|
||||||
existingTeam.removeEntry(player.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
team.addEntry(entry);
|
team.addEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Team für alle Spieler sichtbar machen
|
// Scoreboard für alle Spieler synchronisieren
|
||||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||||
if (onlinePlayer.getScoreboard() != scoreboard) {
|
if (onlinePlayer.getScoreboard() != scoreboard) {
|
||||||
onlinePlayer.setScoreboard(scoreboard);
|
onlinePlayer.setScoreboard(scoreboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug-Ausgabe für Nametag
|
} catch (Exception ignored) {}
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".nametag_prefix", coloredPrefix);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".nametag_entry", entry);
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Farben übersetzen
|
||||||
|
*/
|
||||||
|
private String translateNickColors(String input) {
|
||||||
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
|
return replaceHexColors(withLegacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replaceHexColors(String input) {
|
||||||
|
Matcher matcher = HEX_PATTERN.matcher(input);
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
String hexCode = matcher.group();
|
||||||
|
String replacement = ChatColor.of(hexCode).toString();
|
||||||
|
matcher.appendReplacement(sb, replacement);
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Eindeutigen Teamnamen generieren
|
* Eindeutigen Teamnamen generieren
|
||||||
*/
|
*/
|
||||||
private String generateTeamName(Player player, String prefix) {
|
private String generateTeamName(Player player, String prefix) {
|
||||||
// Verwende UUID für eindeutige Teamnamen, falls kein Prefix vorhanden
|
|
||||||
if (prefix == null || prefix.trim().isEmpty()) {
|
if (prefix == null || prefix.trim().isEmpty()) {
|
||||||
return "nametag_" + player.getUniqueId().toString().substring(0, 8);
|
return "nametag_" + player.getUniqueId().toString().substring(0, 8);
|
||||||
}
|
}
|
||||||
// Verwende Prefix für Teamnamen, max 16 Zeichen (Bukkit-Beschränkung)
|
|
||||||
String sanitizedPrefix = prefix.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
|
String sanitizedPrefix = prefix.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
|
||||||
return "prefix_" + sanitizedPrefix.substring(0, Math.min(sanitizedPrefix.length(), 12));
|
return "prefix_" + sanitizedPrefix.substring(0, Math.min(sanitizedPrefix.length(), 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spieler-Prefix abrufen (LuckPerms primär, PlaceholderAPI als Fallback)
|
* Rang-Prefix abrufen
|
||||||
*/
|
*/
|
||||||
private String getPlayerPrefix(Player player) {
|
private String getPlayerPrefix(Player player) {
|
||||||
// Wenn LuckPerms installiert ist, Prefix zwingend abrufen
|
|
||||||
if (luckPerms != null) {
|
if (luckPerms != null) {
|
||||||
// Versuche LuckPerms-API zuerst
|
|
||||||
try {
|
try {
|
||||||
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
||||||
String prefix = user.getCachedData().getMetaData().getPrefix();
|
String prefix = user.getCachedData().getMetaData().getPrefix();
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".prefix", prefix);
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return prefix + " ";
|
return prefix + " ";
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback auf PlaceholderAPI, wenn LuckPerms installiert ist
|
|
||||||
if (hasPlaceholderAPI) {
|
if (hasPlaceholderAPI) {
|
||||||
try {
|
try {
|
||||||
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".prefix", prefix);
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return prefix + " ";
|
return prefix + " ";
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard-Prefix, wenn LuckPerms installiert ist, aber kein Prefix definiert
|
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".prefix", "&7[Spieler]");
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return "&7[Spieler] ";
|
return "&7[Spieler] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn LuckPerms nicht installiert ist, aber PlaceholderAPI vorhanden ist
|
|
||||||
if (hasPlaceholderAPI) {
|
if (hasPlaceholderAPI) {
|
||||||
try {
|
try {
|
||||||
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".prefix", prefix);
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return prefix + " ";
|
return prefix + " ";
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard-Prefix, wenn weder LuckPerms noch PlaceholderAPI einen Prefix liefern
|
|
||||||
try {
|
|
||||||
File debugFile = new File(plugin.getDataFolder(), "debug.yml");
|
|
||||||
FileConfiguration debugConfig = YamlConfiguration.loadConfiguration(debugFile);
|
|
||||||
debugConfig.set(player.getUniqueId().toString() + ".prefix", "&7[Spieler]");
|
|
||||||
debugConfig.save(debugFile);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return "&7[Spieler] ";
|
return "&7[Spieler] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,32 +383,33 @@ public class TablistManager implements Listener {
|
|||||||
Object entityPlayer = getHandle.invoke(player);
|
Object entityPlayer = getHandle.invoke(player);
|
||||||
return entityPlayer.getClass().getField("ping").getInt(entityPlayer);
|
return entityPlayer.getClass().getField("ping").getInt(entityPlayer);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return -1; // Keine Konsolenausgabe
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chat-Format modifizieren
|
* Chat-Format (Nickname wird hier angezeigt)
|
||||||
*/
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
try {
|
try {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
|
// Nickname abrufen (wichtig: hier neu abrufen, da es asynchron ist und sich geändert haben könnte)
|
||||||
|
// Da Config-Lesezugriffe meist Thread-Safe sind, ist das hier okay.
|
||||||
String displayName = getNickname(player);
|
String displayName = getNickname(player);
|
||||||
if (displayName == null || displayName.trim().isEmpty()) {
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
displayName = player.getName();
|
displayName = player.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
String prefix = getPlayerPrefix(player);
|
String prefix = getPlayerPrefix(player);
|
||||||
|
// Format: Rang + Nick + ": " + Nachricht
|
||||||
String format = color(prefix + displayName + "&7: &f") + "%2$s";
|
String format = color(prefix + displayName + "&7: &f") + "%2$s";
|
||||||
event.setFormat(format);
|
event.setFormat(format);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Keine Konsolenausgabe
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adventure-Variante mit Components
|
* Adventure-Variante
|
||||||
*/
|
*/
|
||||||
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
||||||
try {
|
try {
|
||||||
@@ -449,7 +430,6 @@ public class TablistManager implements Listener {
|
|||||||
headerComp = textMethod.invoke(null, color(headerRaw));
|
headerComp = textMethod.invoke(null, color(headerRaw));
|
||||||
footerComp = textMethod.invoke(null, color(footerRaw));
|
footerComp = textMethod.invoke(null, color(footerRaw));
|
||||||
} else {
|
} else {
|
||||||
// Fallback: MiniMessage
|
|
||||||
try {
|
try {
|
||||||
Class<?> miniMsgClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
Class<?> miniMsgClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
||||||
Method miniMsgSingleton = miniMsgClass.getMethod("miniMessage");
|
Method miniMsgSingleton = miniMsgClass.getMethod("miniMessage");
|
||||||
@@ -457,9 +437,7 @@ public class TablistManager implements Listener {
|
|||||||
Method deserialize = miniMsgClass.getMethod("deserialize", String.class);
|
Method deserialize = miniMsgClass.getMethod("deserialize", String.class);
|
||||||
headerComp = deserialize.invoke(miniMsg, headerRaw);
|
headerComp = deserialize.invoke(miniMsg, headerRaw);
|
||||||
footerComp = deserialize.invoke(miniMsg, footerRaw);
|
footerComp = deserialize.invoke(miniMsg, footerRaw);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
// Kein MiniMessage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerComp == null || footerComp == null) return false;
|
if (headerComp == null || footerComp == null) return false;
|
||||||
@@ -512,9 +490,6 @@ public class TablistManager implements Listener {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hilfsmethode für Reflection
|
|
||||||
*/
|
|
||||||
private Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
|
private Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
|
||||||
Class<?> current = clazz;
|
Class<?> current = clazz;
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
@@ -527,9 +502,6 @@ public class TablistManager implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Farbcode-Konvertierung (& -> §)
|
|
||||||
*/
|
|
||||||
private String color(String msg) {
|
private String color(String msg) {
|
||||||
if (msg == null) return "";
|
if (msg == null) return "";
|
||||||
return msg.replace("&", "§");
|
return msg.replace("&", "§");
|
||||||
|
|||||||
@@ -335,9 +335,16 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
getCommand("lootchests").setExecutor(lootChestManager);
|
getCommand("lootchests").setExecutor(lootChestManager);
|
||||||
getCommand("tploot").setExecutor(lootChestManager);
|
getCommand("tploot").setExecutor(lootChestManager);
|
||||||
getCommand("claim").setExecutor(new ClaimCommand(this));
|
getCommand("claim").setExecutor(new ClaimCommand(this));
|
||||||
BlockManager blockManager = new BlockManager();
|
// HIER: (this) hinzugefügt, damit der BlockManager die Datei speichern kann
|
||||||
|
BlockManager blockManager = new BlockManager(this);
|
||||||
FileConfiguration config = getConfig();
|
FileConfiguration config = getConfig();
|
||||||
BackpackRecipe.register(this, langConfig);
|
BackpackRecipe.register(this, langConfig);
|
||||||
|
|
||||||
|
// NEU: Befehle registrieren
|
||||||
|
getCommand("block").setExecutor(new BlockCommand(blockManager, getConfig()));
|
||||||
|
getCommand("unblock").setExecutor(new UnblockCommand(blockManager, getConfig()));
|
||||||
|
getCommand("blocklist").setExecutor(new BlockListCommand(blockManager, getConfig()));
|
||||||
|
|
||||||
pluginManager.registerEvents(new ChatBlockListener(blockManager), this);
|
pluginManager.registerEvents(new ChatBlockListener(blockManager), this);
|
||||||
pluginManager.registerEvents(new InventoryClickListener(this), this);
|
pluginManager.registerEvents(new InventoryClickListener(this), this);
|
||||||
pluginManager.registerEvents(sitListener, this);
|
pluginManager.registerEvents(sitListener, this);
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class BlockCommand implements CommandExecutor {
|
public class BlockCommand implements CommandExecutor {
|
||||||
|
|
||||||
@@ -20,28 +23,40 @@ public class BlockCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cDieser Befehl ist nur für Spieler!")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.block")) {
|
||||||
|
player.sendMessage(color(config.getString("messages.general.no_permission", "§cDu hast keine Berechtigung für diesen Befehl!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
player.sendMessage(config.getString("messages.block.usage"));
|
player.sendMessage(color(config.getString("messages.block.usage", "§cVerwendung: /block <Spieler>")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player target = Bukkit.getPlayerExact(args[0]);
|
Player target = Bukkit.getPlayerExact(args[0]);
|
||||||
if (target == null || target == player) {
|
if (target == null || target == player) {
|
||||||
player.sendMessage(config.getString("messages.block.invalid_player"));
|
player.sendMessage(color(config.getString("messages.block.invalid_player", "§cDieser Spieler konnte nicht gefunden werden oder bist du selbst.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockManager.hasBlocked(player, target)) {
|
if (blockManager.hasBlocked(player, target)) {
|
||||||
player.sendMessage(config.getString("messages.block.already_blocked").replace("%player%", target.getName()));
|
String msg = config.getString("messages.block.already_blocked", "&cDieser Spieler ist bereits blockiert!");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
} else {
|
} else {
|
||||||
blockManager.blockPlayer(player, target);
|
blockManager.blockPlayer(player, target);
|
||||||
player.sendMessage(config.getString("messages.block.blocked").replace("%player%", target.getName()));
|
String msg = config.getString("messages.block.blocked", "&aDu hast %player% blockiert.");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -22,22 +25,30 @@ public class BlockListCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
// Fallback: "Nur Spieler..." falls Key fehlt
|
||||||
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cNur Spieler können diesen Befehl ausführen!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var blocked = blockManager.getBlockedPlayers(player);
|
var blocked = blockManager.getBlockedPlayers(player);
|
||||||
if (blocked.isEmpty()) {
|
if (blocked.isEmpty()) {
|
||||||
player.sendMessage(config.getString("messages.blocklist.no_blocked_players"));
|
player.sendMessage(color(config.getString("messages.blocklist.no_blocked_players", "§cDu hast keine Spieler blockiert.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String list = blocked.stream()
|
String list = blocked.stream()
|
||||||
.map(Bukkit::getOfflinePlayer)
|
.map(Bukkit::getOfflinePlayer)
|
||||||
.map(p -> p.getName() != null ? p.getName() : "Unbekannt")
|
.map(p -> p.getName() != null ? p.getName() : "§eUnbekannt")
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
|
|
||||||
player.sendMessage(config.getString("messages.blocklist.blocked_players").replace("%list%", list));
|
// WICHTIG: Default-String als zweiten Parameter, um NullPointerException zu vermeiden
|
||||||
|
String rawMessage = config.getString("messages.blocklist.blocked_players", "&eBlockierte Spieler: %list%");
|
||||||
|
player.sendMessage(color(rawMessage.replace("%list%", list)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -34,6 +34,23 @@ public class NickCommand implements CommandExecutor {
|
|||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
player.sendMessage("§eBenutzung: /nick <Name>");
|
player.sendMessage("§eBenutzung: /nick <Name>");
|
||||||
|
player.sendMessage("§eVerwende /nick off um den Nickname zu entfernen.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Befehl zum Entfernen des Nicks
|
||||||
|
if (args.length == 1 && (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("remove") || args[0].equalsIgnoreCase("reset"))) {
|
||||||
|
String uuid = player.getUniqueId().toString();
|
||||||
|
|
||||||
|
// Aus Config entfernen
|
||||||
|
plugin.getNicknamesConfig().set(uuid, null);
|
||||||
|
plugin.saveNicknamesConfig();
|
||||||
|
|
||||||
|
// Visuell sofort zurücksetzen
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
player.setPlayerListName(player.getName());
|
||||||
|
|
||||||
|
player.sendMessage("§aDein Nickname wurde entfernt.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package de.viper.survivalplus.commands;
|
|||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.listeners.SitListener;
|
import de.viper.survivalplus.listeners.SitListener;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@@ -45,11 +47,27 @@ public class SitCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setze den Spieler mittig auf den Block und leicht oberhalb (Fix)
|
// Prüfe ob Spieler bereits in einem Fahrzeug ist
|
||||||
|
if (player.isInsideVehicle()) {
|
||||||
|
player.sendMessage(lang.getString("sit.already-in-vehicle", "§cDu kannst dich nicht setzen, während du in einem Fahrzeug bist!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob unter dem Spieler Luft ist (Verhindert Sitzen beim Bauen in der Luft)
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
Block blockBelow = loc.clone().subtract(0, 1, 0).getBlock();
|
||||||
|
|
||||||
|
// Wir erlauben das Sitzen nur, wenn der Block unter einem nicht Luft ist und kein Flüssigkeitsblock ist
|
||||||
|
if (blockBelow.getType().isAir() || !blockBelow.getType().isSolid()) {
|
||||||
|
player.sendMessage(plugin.getLangConfig().getString("sit.no-solid-ground", "§cDu kannst dich hier nicht hinsetzen (kein fester Boden)."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setze den Spieler mittig auf den Block
|
||||||
Location location = player.getLocation();
|
Location location = player.getLocation();
|
||||||
location.setX(location.getBlockX() + 0.5);
|
location.setX(location.getBlockX() + 0.5);
|
||||||
location.setY(location.getBlockY() + 0.25);
|
|
||||||
location.setZ(location.getBlockZ() + 0.5);
|
location.setZ(location.getBlockZ() + 0.5);
|
||||||
|
location.setY(location.getBlockY());
|
||||||
|
|
||||||
sitListener.sitPlayer(player, location);
|
sitListener.sitPlayer(player, location);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.BlockManager;
|
import de.viper.survivalplus.Manager.BlockManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.*;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class UnblockCommand implements CommandExecutor {
|
public class UnblockCommand implements CommandExecutor {
|
||||||
|
|
||||||
@@ -20,29 +23,40 @@ public class UnblockCommand implements CommandExecutor {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage(config.getString("messages.general.only_players"));
|
sender.sendMessage(color(config.getString("messages.general.only_players", "§cDieser Befehl ist nur für Spieler!")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.unblock")) {
|
||||||
|
player.sendMessage(color(config.getString("messages.general.no_permission", "§cDu hast keine Berechtigung für diesen Befehl!")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
player.sendMessage(config.getString("messages.unblock.usage"));
|
player.sendMessage(color(config.getString("messages.block.usage", "§cVerwendung: /unblock <Spieler>")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player target = Bukkit.getPlayerExact(args[0]);
|
Player target = Bukkit.getPlayerExact(args[0]);
|
||||||
if (target == null || target == player) {
|
if (target == null || target == player) {
|
||||||
player.sendMessage(config.getString("messages.unblock.invalid_player"));
|
player.sendMessage(color(config.getString("messages.block.invalid_player", "§cDieser Spieler konnte nicht gefunden werden oder bist du selbst.")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockManager.hasBlocked(player, target)) {
|
if (!blockManager.hasBlocked(player, target)) {
|
||||||
blockManager.unblockPlayer(player, target);
|
String msg = config.getString("messages.block.not_blocked", "&cDieser Spieler ist nicht blockiert.");
|
||||||
player.sendMessage(config.getString("messages.unblock.unblocked").replace("%player%", target.getName()));
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
target.sendMessage(config.getString("messages.unblock.unblocked_by").replace("%player%", player.getName()));
|
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(config.getString("messages.unblock.not_blocked").replace("%player%", target.getName()));
|
blockManager.unblockPlayer(player, target);
|
||||||
|
String msg = config.getString("messages.block.unblocked", "&aDu hast %player% entblockt.");
|
||||||
|
player.sendMessage(color(msg.replace("%player%", target.getName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String color(String msg) {
|
||||||
|
if (msg == null) return "";
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
package de.viper.survivalplus.listeners;
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.event.block.Action;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -22,9 +26,11 @@ import java.util.logging.Level;
|
|||||||
public class SitListener implements Listener {
|
public class SitListener implements Listener {
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
||||||
|
private static final String SIT_TAG = "SP_SIT_STAND"; // Tag zum Identifizieren
|
||||||
|
|
||||||
public SitListener(SurvivalPlus plugin) {
|
public SitListener(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
cleanUpGhostStands(); // Entferne alte Stands beim Laden
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSitting(Player player) {
|
public boolean isSitting(Player player) {
|
||||||
@@ -39,11 +45,17 @@ public class SitListener implements Listener {
|
|||||||
// Erstelle einen unsichtbaren ArmorStand als Sitz
|
// Erstelle einen unsichtbaren ArmorStand als Sitz
|
||||||
ArmorStand armorStand = player.getWorld().spawn(location, ArmorStand.class);
|
ArmorStand armorStand = player.getWorld().spawn(location, ArmorStand.class);
|
||||||
armorStand.setGravity(false);
|
armorStand.setGravity(false);
|
||||||
armorStand.setMarker(true);
|
armorStand.setMarker(true); // Keine Hitbox
|
||||||
armorStand.setInvisible(true);
|
armorStand.setInvisible(true);
|
||||||
armorStand.setInvulnerable(true);
|
armorStand.setInvulnerable(true);
|
||||||
|
armorStand.addScoreboardTag(SIT_TAG); // Tag für Cleanup
|
||||||
|
|
||||||
|
// Füge Spieler als Passenger hinzu
|
||||||
armorStand.addPassenger(player);
|
armorStand.addPassenger(player);
|
||||||
|
|
||||||
|
// Teleportiere den Spieler nochmals zur Sicherheit (Anti-Slide)
|
||||||
|
player.teleport(location);
|
||||||
|
|
||||||
sittingPlayers.put(player.getUniqueId(), armorStand);
|
sittingPlayers.put(player.getUniqueId(), armorStand);
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
||||||
@@ -54,9 +66,15 @@ public class SitListener implements Listener {
|
|||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
||||||
if (armorStand != null) {
|
if (armorStand != null) {
|
||||||
|
if (player.isValid()) {
|
||||||
|
armorStand.removePassenger(player);
|
||||||
|
}
|
||||||
armorStand.remove();
|
armorStand.remove();
|
||||||
|
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
if (player.isOnline()) {
|
||||||
|
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
||||||
|
}
|
||||||
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " ist aufgestanden");
|
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " ist aufgestanden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +89,7 @@ public class SitListener implements Listener {
|
|||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
|
|
||||||
if (!player.hasPermission("survivalplus.sit")) {
|
if (!player.hasPermission("survivalplus.sit")) {
|
||||||
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
|
// Kein Feedback nötig, wenn keine Permission, um nicht zu spammen
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +98,13 @@ public class SitListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEU: Prüfen ob der Spieler nah genug dran ist (max 2 Blöcke Entfernung)
|
||||||
|
// Dies verhindert das versehentliche Sitzen beim Bauen in der Ferne.
|
||||||
|
double distance = player.getLocation().distance(block.getLocation());
|
||||||
|
if (distance > 3.0) {
|
||||||
|
return; // Spieler ist zu weit weg -> Ignorieren (normales Bauen möglich)
|
||||||
|
}
|
||||||
|
|
||||||
// Wenn der Spieler bereits sitzt, stehe auf
|
// Wenn der Spieler bereits sitzt, stehe auf
|
||||||
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
||||||
standUp(player);
|
standUp(player);
|
||||||
@@ -87,11 +112,17 @@ public class SitListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prüfe ob in Fahrzeug
|
||||||
|
if (player.isInsideVehicle()) return;
|
||||||
|
|
||||||
// Setze den Spieler genau auf der Treppenstufe
|
// Setze den Spieler genau auf der Treppenstufe
|
||||||
Location location = block.getLocation();
|
Location location = block.getLocation();
|
||||||
location.setX(location.getX() + 0.5);
|
location.setX(location.getX() + 0.5);
|
||||||
location.setY(location.getY() + 0.5); // Genau auf der Treppenstufe (halbe Blockhöhe)
|
|
||||||
location.setZ(location.getZ() + 0.5);
|
location.setZ(location.getZ() + 0.5);
|
||||||
|
|
||||||
|
// Bei Treppen die Höhe anpassen (Y + 0.5 ist meist genau die "Sitzfläche")
|
||||||
|
location.setY(location.getY() + 0.5);
|
||||||
|
|
||||||
sitPlayer(player, location);
|
sitPlayer(player, location);
|
||||||
event.setCancelled(true); // Verhindere andere Interaktionen mit der Treppe
|
event.setCancelled(true); // Verhindere andere Interaktionen mit der Treppe
|
||||||
}
|
}
|
||||||
@@ -104,14 +135,25 @@ public class SitListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe, ob der Spieler sich bewegt hat (nur Positionsänderung, nicht Kopfbewegung)
|
// Prüfe, ob der Spieler sich wirklich bewegt hat (Distanz > 0.05)
|
||||||
|
// Das verhindert, dass minimale "Wackler" durch Lag den Spieler abwerfen
|
||||||
Location from = event.getFrom();
|
Location from = event.getFrom();
|
||||||
Location to = event.getTo();
|
Location to = event.getTo();
|
||||||
if (from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ()) {
|
if (to == null) return;
|
||||||
|
|
||||||
|
if (from.distanceSquared(to) > 0.0025) { // ca 0.05 Blöcke Abstand
|
||||||
standUp(player);
|
standUp(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
|
// Wenn teleportiert, absteigen
|
||||||
|
if (sittingPlayers.containsKey(event.getPlayer().getUniqueId())) {
|
||||||
|
standUp(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
@@ -125,4 +167,20 @@ public class SitListener implements Listener {
|
|||||||
private String locationToString(Location loc) {
|
private String locationToString(Location loc) {
|
||||||
return String.format("x=%.2f, y=%.2f, z=%.2f, world=%s", loc.getX(), loc.getY(), loc.getZ(), loc.getWorld().getName());
|
return String.format("x=%.2f, y=%.2f, z=%.2f, world=%s", loc.getX(), loc.getY(), loc.getZ(), loc.getWorld().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entfernt verbliebene ArmorStands von vorherigen Läufen (z.B. nach /reload)
|
||||||
|
private void cleanUpGhostStands() {
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
for (Entity entity : world.getEntities()) {
|
||||||
|
if (entity instanceof ArmorStand) {
|
||||||
|
if (entity.getScoreboardTags().contains(SIT_TAG)) {
|
||||||
|
entity.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.getLogger().info("Ghost Stands (Sit) bereinigt.");
|
||||||
|
}, 20L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.ShapedRecipe;
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
|
import org.bukkit.inventory.RecipeChoice;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
@@ -16,23 +17,34 @@ public class BackpackRecipe {
|
|||||||
ItemStack backpack = new ItemStack(Material.CHEST);
|
ItemStack backpack = new ItemStack(Material.CHEST);
|
||||||
ItemMeta meta = backpack.getItemMeta();
|
ItemMeta meta = backpack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.name", "&eRucksack")));
|
// Fallback falls der Key in der lang.yml fehlt
|
||||||
|
String displayName = langConfig.getString("backpack.name", "&eRucksack");
|
||||||
|
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', displayName));
|
||||||
backpack.setItemMeta(meta);
|
backpack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
NamespacedKey key = new NamespacedKey(plugin, "backpack");
|
NamespacedKey key = new NamespacedKey(plugin, "backpack");
|
||||||
|
|
||||||
|
// Rezept erstellen
|
||||||
ShapedRecipe recipe = new ShapedRecipe(key, backpack);
|
ShapedRecipe recipe = new ShapedRecipe(key, backpack);
|
||||||
|
|
||||||
|
// Form festlegen
|
||||||
recipe.shape(
|
recipe.shape(
|
||||||
"S L", // Faden, leer, Leder
|
"S L",
|
||||||
" C ", // leer, Truhe, leer
|
" C ",
|
||||||
"S L" // Faden, leer, Leder
|
"S L"
|
||||||
);
|
);
|
||||||
recipe.setIngredient('S', Material.STRING); // Faden
|
|
||||||
recipe.setIngredient('L', Material.LEATHER); // Leder
|
// Zutaten festlegen (mit RecipeChoice für bessere Kompatibilität)
|
||||||
recipe.setIngredient('C', Material.CHEST); // Truhe
|
recipe.setIngredient('S', new RecipeChoice.MaterialChoice(Material.STRING));
|
||||||
|
recipe.setIngredient('L', new RecipeChoice.MaterialChoice(Material.LEATHER));
|
||||||
|
recipe.setIngredient('C', new RecipeChoice.MaterialChoice(Material.CHEST));
|
||||||
|
|
||||||
|
// WICHTIG: Setzt eine eigene Gruppe.
|
||||||
|
// Verhindert Konflikte mit Vanilla-Rezepten im Rezeptbuch.
|
||||||
|
recipe.setGroup("survivalplus");
|
||||||
|
|
||||||
Bukkit.addRecipe(recipe);
|
Bukkit.addRecipe(recipe);
|
||||||
plugin.getLogger().info("Backpack Rezept wurde registriert.");
|
plugin.getLogger().info("Backpack Rezept wurde erfolgreich registriert (Gruppe: survivalplus).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,13 +73,14 @@ public class TradeManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TradeSession session = new TradeSession(plugin, sender, receiver);
|
// Neue Session starten
|
||||||
|
TradeSession session = new TradeSession(plugin, sender, receiver, this);
|
||||||
Bukkit.getPluginManager().registerEvents(session, plugin);
|
Bukkit.getPluginManager().registerEvents(session, plugin);
|
||||||
|
|
||||||
activeTrades.put(sender.getUniqueId(), session);
|
activeTrades.put(sender.getUniqueId(), session);
|
||||||
activeTrades.put(receiver.getUniqueId(), session);
|
activeTrades.put(receiver.getUniqueId(), session);
|
||||||
|
|
||||||
session.openInventories();
|
session.openInventory();
|
||||||
|
|
||||||
sender.sendMessage(plugin.getLangConfig().getString("trade.started-sender", "§aTrade gestartet mit %player%").replace("%player%", receiver.getName()));
|
sender.sendMessage(plugin.getLangConfig().getString("trade.started-sender", "§aTrade gestartet mit %player%").replace("%player%", receiver.getName()));
|
||||||
receiver.sendMessage(plugin.getLangConfig().getString("trade.started-receiver", "§a%player% hat dich zu einem Trade eingeladen.").replace("%player%", sender.getName()));
|
receiver.sendMessage(plugin.getLangConfig().getString("trade.started-receiver", "§a%player% hat dich zu einem Trade eingeladen.").replace("%player%", sender.getName()));
|
||||||
@@ -91,7 +92,7 @@ public class TradeManager {
|
|||||||
Player r = session.getReceiver();
|
Player r = session.getReceiver();
|
||||||
if (s != null) activeTrades.remove(s.getUniqueId());
|
if (s != null) activeTrades.remove(s.getUniqueId());
|
||||||
if (r != null) activeTrades.remove(r.getUniqueId());
|
if (r != null) activeTrades.remove(r.getUniqueId());
|
||||||
session.endSession();
|
session.closeInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TradeSession getTrade(Player player) {
|
public TradeSession getTrade(Player player) {
|
||||||
|
|||||||
@@ -16,150 +16,297 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||||||
public class TradeSession implements Listener {
|
public class TradeSession implements Listener {
|
||||||
|
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
|
private final TradeManager tradeManager;
|
||||||
private final Player sender;
|
private final Player sender;
|
||||||
private final Player receiver;
|
private final Player receiver;
|
||||||
|
|
||||||
private final Inventory invSender;
|
// Wir benutzen nur EIN Inventar für beide (Size 54 = Double Chest)
|
||||||
private final Inventory invReceiver;
|
// Slots 0-17: Angebot von Sender (Editierbar für Sender)
|
||||||
|
// Slots 18-35: Angebot von Receiver (Editierbar für Receiver)
|
||||||
|
// Slots 36-44: Trennung / Status
|
||||||
|
// Slot 45: Abbrechen
|
||||||
|
// Slot 53: Bestätigen
|
||||||
|
private final Inventory tradeInv;
|
||||||
|
|
||||||
private boolean senderConfirmed = false;
|
private boolean senderConfirmed = false;
|
||||||
private boolean receiverConfirmed = false;
|
private boolean receiverConfirmed = false;
|
||||||
private boolean ended = false; // Flag gegen Rekursion
|
private boolean active = true;
|
||||||
|
|
||||||
public TradeSession(SurvivalPlus plugin, Player sender, Player receiver) {
|
public TradeSession(SurvivalPlus plugin, Player sender, Player receiver, TradeManager tradeManager) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.tradeManager = tradeManager;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.receiver = receiver;
|
this.receiver = receiver;
|
||||||
|
|
||||||
String titleForSender = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
|
String title = plugin.getLangConfig().getString("trade.inventory-title", "Handel")
|
||||||
.replace("%player%", receiver.getName());
|
.replace("%player%", receiver.getName())
|
||||||
String titleForReceiver = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
|
.replace("%other%", sender.getName());
|
||||||
.replace("%player%", sender.getName());
|
|
||||||
|
|
||||||
this.invSender = Bukkit.createInventory(sender, 27, titleForSender);
|
// Wir nutzen null als Owner, damit es ein gemeinsames Inventar ist
|
||||||
this.invReceiver = Bukkit.createInventory(receiver, 27, titleForReceiver);
|
this.tradeInv = Bukkit.createInventory(null, 54, title);
|
||||||
|
setupLayout();
|
||||||
addConfirmButton(invSender);
|
|
||||||
addConfirmButton(invReceiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addConfirmButton(Inventory inv) {
|
private void setupLayout() {
|
||||||
ItemStack confirm = new ItemStack(Material.LIME_CONCRETE);
|
// Trennung zwischen den beiden Angeboten (Glas)
|
||||||
ItemMeta meta = confirm.getItemMeta();
|
ItemStack glass = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||||
meta.setDisplayName(plugin.getLangConfig().getString("trade.confirm-button", "§aBestätigen"));
|
ItemMeta glassMeta = glass.getItemMeta();
|
||||||
confirm.setItemMeta(meta);
|
glassMeta.setDisplayName(" ");
|
||||||
inv.setItem(26, confirm);
|
glass.setItemMeta(glassMeta);
|
||||||
|
|
||||||
|
for(int i = 36; i < 45; i++) {
|
||||||
|
tradeInv.setItem(i, glass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons initialisieren
|
||||||
|
updateStatusItem();
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButtons() {
|
||||||
|
// Abbrechen Button (Rot)
|
||||||
|
ItemStack cancel = new ItemStack(Material.RED_CONCRETE);
|
||||||
|
ItemMeta cancelMeta = cancel.getItemMeta();
|
||||||
|
cancelMeta.setDisplayName(plugin.getLangConfig().getString("trade.cancel-button", "§cAbbrechen"));
|
||||||
|
cancel.setItemMeta(cancelMeta);
|
||||||
|
tradeInv.setItem(45, cancel);
|
||||||
|
|
||||||
|
// Bestätigen Button
|
||||||
|
Material confirmMat = Material.LIME_CONCRETE;
|
||||||
|
String confirmName = "§aBestätigen";
|
||||||
|
|
||||||
|
// Wenn beide bestätigt haben, ändert sich der Button
|
||||||
|
if (senderConfirmed && receiverConfirmed) {
|
||||||
|
confirmMat = Material.GOLD_BLOCK; // Signalisiert Tauschvorgang
|
||||||
|
confirmName = "§6Handel läuft...";
|
||||||
|
} else if (senderConfirmed) {
|
||||||
|
confirmMat = Material.YELLOW_CONCRETE;
|
||||||
|
confirmName = "§eWarte auf Partner...";
|
||||||
|
} else if (receiverConfirmed) {
|
||||||
|
confirmMat = Material.YELLOW_CONCRETE;
|
||||||
|
confirmName = "§eWarte auf Partner...";
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack confirm = new ItemStack(confirmMat);
|
||||||
|
ItemMeta confirmMeta = confirm.getItemMeta();
|
||||||
|
confirmMeta.setDisplayName(confirmName);
|
||||||
|
confirm.setItemMeta(confirmMeta);
|
||||||
|
tradeInv.setItem(53, confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusItem() {
|
||||||
|
// Slot 40 zeigt den Status an
|
||||||
|
String statusText = "§eWarte auf Bestätigung...";
|
||||||
|
|
||||||
|
if (senderConfirmed && !receiverConfirmed) {
|
||||||
|
statusText = "§a" + sender.getName() + " §7hat bestätigt.";
|
||||||
|
} else if (!senderConfirmed && receiverConfirmed) {
|
||||||
|
statusText = "§a" + receiver.getName() + " §7hat bestätigt.";
|
||||||
|
} else if (senderConfirmed && receiverConfirmed) {
|
||||||
|
statusText = "§6Handel wird ausgeführt...";
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack status = new ItemStack(Material.BOOK);
|
||||||
|
ItemMeta statusMeta = status.getItemMeta();
|
||||||
|
statusMeta.setDisplayName(statusText);
|
||||||
|
status.setItemMeta(statusMeta);
|
||||||
|
tradeInv.setItem(40, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getSender() { return sender; }
|
public Player getSender() { return sender; }
|
||||||
public Player getReceiver() { return receiver; }
|
public Player getReceiver() { return receiver; }
|
||||||
|
|
||||||
public void openInventories() {
|
public void openInventory() {
|
||||||
if (sender.isOnline()) sender.openInventory(invSender);
|
if (sender.isOnline()) sender.openInventory(tradeInv);
|
||||||
if (receiver.isOnline()) receiver.openInventory(invReceiver);
|
if (receiver.isOnline()) receiver.openInventory(tradeInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void returnItems(Player player, Inventory inventory) {
|
public void closeInventory() {
|
||||||
for (int i = 0; i < 26; i++) {
|
active = false;
|
||||||
ItemStack item = inventory.getItem(i);
|
if (sender.isOnline() && sender.getOpenInventory().getTopInventory() == tradeInv) {
|
||||||
if (item != null) player.getInventory().addItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endSession() {
|
|
||||||
if (ended) return; // Rekursion verhindern
|
|
||||||
ended = true;
|
|
||||||
|
|
||||||
// Items zurückgeben
|
|
||||||
if (sender.isOnline()) returnItems(sender, invSender);
|
|
||||||
if (receiver.isOnline()) returnItems(receiver, invReceiver);
|
|
||||||
|
|
||||||
// Inventories schließen
|
|
||||||
if (sender.isOnline() && sender.getOpenInventory().getTopInventory() == invSender) {
|
|
||||||
sender.closeInventory();
|
sender.closeInventory();
|
||||||
}
|
}
|
||||||
if (receiver.isOnline() && receiver.getOpenInventory().getTopInventory() == invReceiver) {
|
if (receiver.isOnline() && receiver.getOpenInventory().getTopInventory() == tradeInv) {
|
||||||
receiver.closeInventory();
|
receiver.closeInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
HandlerList.unregisterAll(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Inventory getOwnInventory(Player p) {
|
private void returnItems() {
|
||||||
return p.getUniqueId().equals(sender.getUniqueId()) ? invSender : invReceiver;
|
// Gibt alle Items zurück, falls der Handel abgebrochen wurde
|
||||||
}
|
for (int i = 0; i < 36; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
private Inventory getOtherInventory(Player p) {
|
if (item != null) {
|
||||||
return p.getUniqueId().equals(sender.getUniqueId()) ? invReceiver : invSender;
|
// Bestimmen, wem das Item gehört
|
||||||
}
|
if (i < 18) {
|
||||||
|
if (sender.isOnline()) sender.getInventory().addItem(item);
|
||||||
private void updateOtherView(Player p) {
|
} else {
|
||||||
Inventory own = getOwnInventory(p);
|
if (receiver.isOnline()) receiver.getInventory().addItem(item);
|
||||||
Inventory other = getOtherInventory(p);
|
}
|
||||||
for (int i = 0; i < 26; i++) {
|
tradeInv.setItem(i, null); // Slot leeren
|
||||||
other.setItem(i, own.getItem(i));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeTrade() {
|
private void executeTrade() {
|
||||||
for (int i = 0; i < 26; i++) {
|
// Tauschvorgang
|
||||||
ItemStack itemFromSender = invSender.getItem(i);
|
// 1. Sender Items zu Receiver
|
||||||
ItemStack itemFromReceiver = invReceiver.getItem(i);
|
for (int i = 0; i < 18; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
|
if (item != null) {
|
||||||
|
if (receiver.isOnline()) receiver.getInventory().addItem(item);
|
||||||
|
tradeInv.setItem(i, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (itemFromSender != null) sender.getInventory().addItem(itemFromSender);
|
// 2. Receiver Items zu Sender
|
||||||
if (itemFromReceiver != null) receiver.getInventory().addItem(itemFromReceiver);
|
for (int i = 18; i < 36; i++) {
|
||||||
|
ItemStack item = tradeInv.getItem(i);
|
||||||
|
if (item != null) {
|
||||||
|
if (sender.isOnline()) sender.getInventory().addItem(item);
|
||||||
|
tradeInv.setItem(i, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String success = plugin.getLangConfig().getString("trade.success", "§aHandel erfolgreich abgeschlossen!");
|
String success = plugin.getLangConfig().getString("trade.success", "§aHandel erfolgreich abgeschlossen!");
|
||||||
if (sender.isOnline()) sender.sendMessage(success);
|
if (sender.isOnline()) sender.sendMessage(success);
|
||||||
if (receiver.isOnline()) receiver.sendMessage(success);
|
if (receiver.isOnline()) receiver.sendMessage(success);
|
||||||
|
|
||||||
endSession();
|
closeInventory();
|
||||||
}
|
|
||||||
|
|
||||||
private void resetConfirmations() {
|
|
||||||
senderConfirmed = false;
|
|
||||||
receiverConfirmed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClick(InventoryClickEvent e) {
|
public void onInventoryClick(InventoryClickEvent e) {
|
||||||
|
if (!active) return;
|
||||||
if (!(e.getWhoClicked() instanceof Player p)) return;
|
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||||
if (!p.getUniqueId().equals(sender.getUniqueId()) && !p.getUniqueId().equals(receiver.getUniqueId())) return;
|
if (e.getClickedInventory() == null) return;
|
||||||
|
|
||||||
Inventory top = e.getView().getTopInventory();
|
// Nur Klicks im Trade-Inventar behandeln
|
||||||
Inventory clicked = e.getClickedInventory();
|
if (e.getClickedInventory().getSize() != 54 || !e.getClickedInventory().equals(tradeInv)) return;
|
||||||
|
// Auch Klicks im Bottom Inventory erlauben, aber nicht logisch behandeln (Bukkit regelt das)
|
||||||
|
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId())) {
|
||||||
|
handleSenderClick(e);
|
||||||
|
} else if (p.getUniqueId().equals(receiver.getUniqueId())) {
|
||||||
|
handleReceiverClick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSenderClick(InventoryClickEvent e) {
|
||||||
int slot = e.getSlot();
|
int slot = e.getSlot();
|
||||||
|
|
||||||
if (clicked == null) return;
|
// Abbrechen
|
||||||
|
if (slot == 45) {
|
||||||
// Bestätigen-Button
|
|
||||||
if (slot == 26 && clicked.equals(top)) {
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
if (p.getUniqueId().equals(sender.getUniqueId())) senderConfirmed = true;
|
sender.sendMessage(plugin.getLangConfig().getString("trade.cancelled", "§cHandel abgebrochen."));
|
||||||
if (p.getUniqueId().equals(receiver.getUniqueId())) receiverConfirmed = true;
|
if (receiver.isOnline()) receiver.sendMessage(plugin.getLangConfig().getString("trade.cancelled-partner", "§cHandel wurde abgebrochen."));
|
||||||
|
tradeManager.endTrade(this);
|
||||||
p.sendMessage(plugin.getLangConfig().getString("trade.confirmed", "§aDu hast den Handel bestätigt!"));
|
|
||||||
|
|
||||||
if (senderConfirmed && receiverConfirmed) executeTrade();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nur das eigene Trade-Inventar editierbar
|
// Bestätigen
|
||||||
if (clicked.equals(top)) {
|
if (slot == 53) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
e.setCancelled(true);
|
||||||
updateOtherView(p);
|
if (receiverConfirmed) {
|
||||||
resetConfirmations();
|
executeTrade();
|
||||||
}, 1L);
|
} else {
|
||||||
|
senderConfirmed = !senderConfirmed; // Toggle
|
||||||
|
sender.sendMessage(senderConfirmed ?
|
||||||
|
plugin.getLangConfig().getString("trade.confirmed", "§aBestätigt!") :
|
||||||
|
"§cBestätigung zurückgezogen.");
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Item-Bewegungen nur im eigenen Bereich (0-17) erlauben
|
||||||
|
if (slot >= 0 && slot <= 17) {
|
||||||
|
// Erlaubt
|
||||||
|
// Wenn ein Item bewegt wird, Bestätigungen zurücksetzen
|
||||||
|
if (e.getCurrentItem() != null || e.getCursor() != null) {
|
||||||
|
if (senderConfirmed || receiverConfirmed) {
|
||||||
|
senderConfirmed = false;
|
||||||
|
receiverConfirmed = false;
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle anderen Slots sperren (Partner-Seite, Glas, Status)
|
||||||
|
e.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReceiverClick(InventoryClickEvent e) {
|
||||||
|
int slot = e.getSlot();
|
||||||
|
|
||||||
|
// Abbrechen
|
||||||
|
if (slot == 45) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
receiver.sendMessage(plugin.getLangConfig().getString("trade.cancelled", "§cHandel abgebrochen."));
|
||||||
|
if (sender.isOnline()) sender.sendMessage(plugin.getLangConfig().getString("trade.cancelled-partner", "§cHandel wurde abgebrochen."));
|
||||||
|
tradeManager.endTrade(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bestätigen
|
||||||
|
if (slot == 53) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
if (senderConfirmed) {
|
||||||
|
executeTrade();
|
||||||
|
} else {
|
||||||
|
receiverConfirmed = !receiverConfirmed; // Toggle
|
||||||
|
receiver.sendMessage(receiverConfirmed ?
|
||||||
|
plugin.getLangConfig().getString("trade.confirmed", "§aBestätigt!") :
|
||||||
|
"§cBestätigung zurückgezogen.");
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item-Bewegungen nur im eigenen Bereich (18-35) erlauben
|
||||||
|
if (slot >= 18 && slot <= 35) {
|
||||||
|
// Erlaubt
|
||||||
|
if (e.getCurrentItem() != null || e.getCursor() != null) {
|
||||||
|
if (senderConfirmed || receiverConfirmed) {
|
||||||
|
senderConfirmed = false;
|
||||||
|
receiverConfirmed = false;
|
||||||
|
updateButtons();
|
||||||
|
updateStatusItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle anderen Slots sperren
|
||||||
|
e.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent e) {
|
public void onInventoryClose(InventoryCloseEvent e) {
|
||||||
|
if (!active) return;
|
||||||
if (!(e.getPlayer() instanceof Player p)) return;
|
if (!(e.getPlayer() instanceof Player p)) return;
|
||||||
if (p.getUniqueId().equals(sender.getUniqueId()) || p.getUniqueId().equals(receiver.getUniqueId())) {
|
|
||||||
// Kleine Verzögerung, um StackOverflow zu vermeiden
|
// Wenn ein Spieler das Inventar schließt, wird der Handel abgebrochen
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, this::endSession, 1L);
|
// Wir prüfen, ob noch Items drin sind, um Duplikate zu vermeiden
|
||||||
|
if (e.getInventory().equals(tradeInv)) {
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId()) || p.getUniqueId().equals(receiver.getUniqueId())) {
|
||||||
|
// Verzögern, falls der Server den CloseEvent für beide fast gleichzeitig feuert
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
if (active) { // Nur wenn nicht schon durch executeTrade geschlossen
|
||||||
|
returnItems();
|
||||||
|
if (p.getUniqueId().equals(sender.getUniqueId())) {
|
||||||
|
if (receiver.isOnline()) receiver.sendMessage("§cDer Partner hat den Handel abgebrochen.");
|
||||||
|
} else {
|
||||||
|
if (sender.isOnline()) sender.sendMessage("§cDer Partner hat den Handel abgebrochen.");
|
||||||
|
}
|
||||||
|
tradeManager.endTrade(this);
|
||||||
|
}
|
||||||
|
}, 1L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,10 @@ package de.viper.survivalplus.util;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.block.data.type.Chest;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@@ -10,9 +13,11 @@ import org.bukkit.configuration.file.FileConfiguration;
|
|||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
@@ -27,6 +32,7 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
private final Map<Location, LockData> lockedBlocks = new HashMap<>();
|
private final Map<Location, LockData> lockedBlocks = new HashMap<>();
|
||||||
private final Set<UUID> lockMode = new HashSet<>();
|
private final Set<UUID> lockMode = new HashSet<>();
|
||||||
private final Map<UUID, BukkitRunnable> lockTimeoutTasks = new HashMap<>();
|
private final Map<UUID, BukkitRunnable> lockTimeoutTasks = new HashMap<>();
|
||||||
|
private final Map<UUID, Long> lastDenyMessage = new HashMap<>();
|
||||||
|
|
||||||
private final File lockFile;
|
private final File lockFile;
|
||||||
private FileConfiguration lockConfig;
|
private FileConfiguration lockConfig;
|
||||||
@@ -139,7 +145,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
if (lockedBlocks.containsKey(loc)) {
|
if (lockedBlocks.containsKey(loc)) {
|
||||||
player.sendMessage(plugin.getMessage("lock.already-locked"));
|
player.sendMessage(plugin.getMessage("lock.already-locked"));
|
||||||
} else {
|
} else {
|
||||||
|
// Lock den Block
|
||||||
lockedBlocks.put(loc, new LockData(uuid.toString()));
|
lockedBlocks.put(loc, new LockData(uuid.toString()));
|
||||||
|
|
||||||
|
// Prüfe auf Doppeltruhe und locke beide Hälften
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
Location otherLoc = otherChest.getLocation();
|
||||||
|
lockedBlocks.put(otherLoc, new LockData(uuid.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.locked"));
|
player.sendMessage(plugin.getMessage("lock.locked"));
|
||||||
}
|
}
|
||||||
@@ -149,7 +164,19 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isLockable) return;
|
if (!isLockable) return;
|
||||||
if (!lockedBlocks.containsKey(loc)) return;
|
|
||||||
|
// Prüfe sowohl den geklickten Block als auch die andere Hälfte bei Doppeltruhen
|
||||||
|
if (!lockedBlocks.containsKey(loc)) {
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
loc = otherChest.getLocation();
|
||||||
|
if (!lockedBlocks.containsKey(loc)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LockData lock = lockedBlocks.get(loc);
|
LockData lock = lockedBlocks.get(loc);
|
||||||
String playerUUID = uuid.toString();
|
String playerUUID = uuid.toString();
|
||||||
@@ -162,6 +189,176 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEU: Verhindert das Öffnen von gelockten Türen durch Redstone (Druckplatten, Knöpfe, etc.)
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onRedstoneChange(BlockRedstoneEvent event) {
|
||||||
|
Block block = event.getBlock();
|
||||||
|
|
||||||
|
// Prüfe, ob der Block eine Tür ist
|
||||||
|
if (!block.getType().name().contains("DOOR")) return;
|
||||||
|
|
||||||
|
Location loc = block.getLocation();
|
||||||
|
LockData lock = null;
|
||||||
|
|
||||||
|
// Prüfe, ob die Tür gelockt ist
|
||||||
|
if (lockedBlocks.containsKey(loc)) {
|
||||||
|
lock = lockedBlocks.get(loc);
|
||||||
|
} else {
|
||||||
|
// Prüfe auch die andere Hälfte der Tür (oben/unten)
|
||||||
|
Location above = loc.clone().add(0, 1, 0);
|
||||||
|
Location below = loc.clone().add(0, -1, 0);
|
||||||
|
|
||||||
|
if (lockedBlocks.containsKey(above)) {
|
||||||
|
lock = lockedBlocks.get(above);
|
||||||
|
} else if (lockedBlocks.containsKey(below)) {
|
||||||
|
lock = lockedBlocks.get(below);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn keine Lock gefunden wurde, erlaube die Änderung
|
||||||
|
if (lock == null) return;
|
||||||
|
|
||||||
|
// Wenn die Tür gelockt ist und Redstone-Signal empfängt, blockiere die Änderung
|
||||||
|
// Es sei denn, das Signal kommt von einem berechtigten Spieler (wird über Druckplatten-Event geprüft)
|
||||||
|
if (event.getNewCurrent() > 0) {
|
||||||
|
event.setNewCurrent(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZUSÄTZLICH: Verhindert Interaktion mit Druckplatten/Knöpfen in der Nähe von gelockten Türen
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onPressurePlateInteract(PlayerInteractEvent event) {
|
||||||
|
if (event.getAction() != Action.PHYSICAL) return;
|
||||||
|
|
||||||
|
Block block = event.getClickedBlock();
|
||||||
|
if (block == null) return;
|
||||||
|
|
||||||
|
// Prüfe, ob es eine Druckplatte ist
|
||||||
|
String typeName = block.getType().name();
|
||||||
|
if (!typeName.contains("PRESSURE_PLATE")) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID playerUUID = player.getUniqueId();
|
||||||
|
|
||||||
|
// Prüfe alle angrenzenden Blöcke auf gelockte Türen
|
||||||
|
for (BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||||
|
Block relative = block.getRelative(face);
|
||||||
|
|
||||||
|
// Prüfe bis zu 2 Blöcke in jede Richtung
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (relative.getType().name().contains("DOOR")) {
|
||||||
|
Location doorLoc = relative.getLocation();
|
||||||
|
|
||||||
|
// Prüfe beide Türhälften
|
||||||
|
LockData lock = getLockData(doorLoc);
|
||||||
|
|
||||||
|
if (lock != null && !hasAccess(player, lock)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
// Anti-Spam: Nur alle 3 Sekunden eine Nachricht senden
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Long lastMessage = lastDenyMessage.get(playerUUID);
|
||||||
|
|
||||||
|
if (lastMessage == null || (currentTime - lastMessage) > 3000) {
|
||||||
|
player.sendMessage(plugin.getMessage("lock.block-denied"));
|
||||||
|
lastDenyMessage.put(playerUUID, currentTime);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relative = relative.getRelative(face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLockedDoor(Location loc) {
|
||||||
|
return lockedBlocks.containsKey(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LockData getLockData(Location loc) {
|
||||||
|
LockData lock = lockedBlocks.get(loc);
|
||||||
|
if (lock == null) {
|
||||||
|
lock = lockedBlocks.get(loc.clone().add(0, 1, 0));
|
||||||
|
}
|
||||||
|
if (lock == null) {
|
||||||
|
lock = lockedBlocks.get(loc.clone().add(0, -1, 0));
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAccess(Player player, LockData lock) {
|
||||||
|
String playerUUID = player.getUniqueId().toString();
|
||||||
|
return lock.getOwnerUUID().equals(playerUUID) ||
|
||||||
|
lock.isFriend(playerUUID) ||
|
||||||
|
player.isOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hilfsmethode: Findet die andere Hälfte einer Doppeltruhe
|
||||||
|
private Block getOtherChestHalf(Block block) {
|
||||||
|
if (block.getType() != Material.CHEST && block.getType() != Material.TRAPPED_CHEST) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Versuche moderne BlockData API (1.13+)
|
||||||
|
if (block.getBlockData() instanceof Chest) {
|
||||||
|
Chest chestData = (Chest) block.getBlockData();
|
||||||
|
|
||||||
|
// Prüfe ob es eine Doppeltruhe ist
|
||||||
|
if (chestData.getType() == Chest.Type.SINGLE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finde die Richtung zur anderen Hälfte
|
||||||
|
BlockFace facing = chestData.getFacing();
|
||||||
|
BlockFace direction;
|
||||||
|
|
||||||
|
if (chestData.getType() == Chest.Type.LEFT) {
|
||||||
|
// Linke Hälfte: Andere Hälfte ist rechts
|
||||||
|
direction = getRight(facing);
|
||||||
|
} else {
|
||||||
|
// Rechte Hälfte: Andere Hälfte ist links
|
||||||
|
direction = getLeft(facing);
|
||||||
|
}
|
||||||
|
|
||||||
|
Block otherBlock = block.getRelative(direction);
|
||||||
|
if (otherBlock.getType() == block.getType()) {
|
||||||
|
return otherBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Fallback für ältere Versionen: Prüfe alle angrenzenden Blöcke
|
||||||
|
for (BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||||
|
Block relative = block.getRelative(face);
|
||||||
|
if (relative.getType() == block.getType()) {
|
||||||
|
return relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockFace getRight(BlockFace face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return BlockFace.EAST;
|
||||||
|
case EAST: return BlockFace.SOUTH;
|
||||||
|
case SOUTH: return BlockFace.WEST;
|
||||||
|
case WEST: return BlockFace.NORTH;
|
||||||
|
default: return face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockFace getLeft(BlockFace face) {
|
||||||
|
switch (face) {
|
||||||
|
case NORTH: return BlockFace.WEST;
|
||||||
|
case WEST: return BlockFace.SOUTH;
|
||||||
|
case SOUTH: return BlockFace.EAST;
|
||||||
|
case EAST: return BlockFace.NORTH;
|
||||||
|
default: return face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
@@ -174,6 +371,13 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
String playerUUID = player.getUniqueId().toString();
|
String playerUUID = player.getUniqueId().toString();
|
||||||
|
|
||||||
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
|
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
|
||||||
|
// Erlaube das Brechen und entferne beide Locks bei Doppeltruhen
|
||||||
|
lockedBlocks.remove(loc);
|
||||||
|
Block otherChest = getOtherChestHalf(block);
|
||||||
|
if (otherChest != null) {
|
||||||
|
lockedBlocks.remove(otherChest.getLocation());
|
||||||
|
}
|
||||||
|
saveLocks();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +437,13 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.no-permission-unlock"));
|
player.sendMessage(plugin.getMessage("lock.no-permission-unlock"));
|
||||||
} else {
|
} else {
|
||||||
lockedBlocks.remove(loc);
|
lockedBlocks.remove(loc);
|
||||||
|
|
||||||
|
// Entferne auch Lock von der anderen Hälfte bei Doppeltruhen
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
lockedBlocks.remove(otherChest.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.unlocked"));
|
player.sendMessage(plugin.getMessage("lock.unlocked"));
|
||||||
}
|
}
|
||||||
@@ -254,6 +465,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.friendadd.not-found"));
|
player.sendMessage(plugin.getMessage("lock.friendadd.not-found"));
|
||||||
} else {
|
} else {
|
||||||
lock.addFriend(friend.getUniqueId().toString());
|
lock.addFriend(friend.getUniqueId().toString());
|
||||||
|
|
||||||
|
// Füge Friend auch zur anderen Hälfte bei Doppeltruhen hinzu
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
LockData otherLock = lockedBlocks.get(otherChest.getLocation());
|
||||||
|
if (otherLock != null) {
|
||||||
|
otherLock.addFriend(friend.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.friendadd.success").replace("{player}", friend.getName()));
|
player.sendMessage(plugin.getMessage("lock.friendadd.success").replace("{player}", friend.getName()));
|
||||||
}
|
}
|
||||||
@@ -276,6 +497,16 @@ public class LockSystem implements Listener, CommandExecutor {
|
|||||||
player.sendMessage(plugin.getMessage("lock.friendremove.not-found"));
|
player.sendMessage(plugin.getMessage("lock.friendremove.not-found"));
|
||||||
} else {
|
} else {
|
||||||
lock.removeFriend(friend.getUniqueId().toString());
|
lock.removeFriend(friend.getUniqueId().toString());
|
||||||
|
|
||||||
|
// Entferne Friend auch von der anderen Hälfte bei Doppeltruhen
|
||||||
|
Block otherChest = getOtherChestHalf(targetBlock);
|
||||||
|
if (otherChest != null) {
|
||||||
|
LockData otherLock = lockedBlocks.get(otherChest.getLocation());
|
||||||
|
if (otherLock != null) {
|
||||||
|
otherLock.removeFriend(friend.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
saveLocks();
|
saveLocks();
|
||||||
player.sendMessage(plugin.getMessage("lock.friendremove.success").replace("{player}", friend.getName()));
|
player.sendMessage(plugin.getMessage("lock.friendremove.success").replace("{player}", friend.getName()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ inventory:
|
|||||||
player-only: "§cDieser Befehl ist nur für Spieler!"
|
player-only: "§cDieser Befehl ist nur für Spieler!"
|
||||||
|
|
||||||
claim:
|
claim:
|
||||||
|
usage: "&cVerwendung: /claim mark <1|2> oder /claim"
|
||||||
points-not-set: "&cDu musst zuerst zwei Punkte markieren! Verwende /claim mark <1|2>."
|
points-not-set: "&cDu musst zuerst zwei Punkte markieren! Verwende /claim mark <1|2>."
|
||||||
different-worlds: "&cDie markierten Punkte müssen in derselben Welt liegen!"
|
different-worlds: "&cDie markierten Punkte müssen in derselben Welt liegen!"
|
||||||
too-large: "&cDer Bereich ist zu groß! Maximal erlaubt: %max% Blöcke²."
|
too-large: "&cDer Bereich ist zu groß! Maximal erlaubt: %max% Blöcke²."
|
||||||
@@ -428,5 +429,6 @@ claim:
|
|||||||
enter: "&aDu hast das Gebiet von %owner% betreten."
|
enter: "&aDu hast das Gebiet von %owner% betreten."
|
||||||
leave: "&eDu hast das Gebiet von %owner% verlassen."
|
leave: "&eDu hast das Gebiet von %owner% verlassen."
|
||||||
|
|
||||||
|
|
||||||
force-survival:
|
force-survival:
|
||||||
join-message: "§aDu wurdest in den Survivalmodus gesetzt!"
|
join-message: "§aDu wurdest in den Survivalmodus gesetzt!"
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
name: SurvivalPlus
|
name: SurvivalPlus
|
||||||
version: 1.0.9
|
version: 1.1.0
|
||||||
|
|
||||||
|
|
||||||
main: de.viper.survivalplus.SurvivalPlus
|
main: de.viper.survivalplus.SurvivalPlus
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
@@ -270,12 +269,6 @@ commands:
|
|||||||
description: Manages claims for anti-griefing
|
description: Manages claims for anti-griefing
|
||||||
usage: /<command> [unclaim | trust <player> | untrust <player>]
|
usage: /<command> [unclaim | trust <player> | untrust <player>]
|
||||||
aliases: [cl]
|
aliases: [cl]
|
||||||
survivalplus.claim.use:
|
|
||||||
description: Allows claiming and unclaiming chunks
|
|
||||||
default: true
|
|
||||||
survivalplus.claim.trust:
|
|
||||||
description: Allows trusting/untrusting players in claims
|
|
||||||
default: true
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
survivalplus.*:
|
survivalplus.*:
|
||||||
@@ -345,6 +338,8 @@ permissions:
|
|||||||
survivalplus.heal.others: true
|
survivalplus.heal.others: true
|
||||||
survivalplus.notify: true
|
survivalplus.notify: true
|
||||||
survivalplus.chunkanimals: true
|
survivalplus.chunkanimals: true
|
||||||
|
survivalplus.claim.use: true
|
||||||
|
survivalplus.claim.trust: true
|
||||||
survivalplus.commandblocker.add:
|
survivalplus.commandblocker.add:
|
||||||
description: Erlaubt das Hinzufügen von Befehlen zur Blockierliste
|
description: Erlaubt das Hinzufügen von Befehlen zur Blockierliste
|
||||||
default: op
|
default: op
|
||||||
|
|||||||
Reference in New Issue
Block a user