Initial commit of SurvivalPlus plugin

This commit is contained in:
2025-08-23 03:00:10 +02:00
commit 0cec42b44d
101 changed files with 10356 additions and 0 deletions

BIN
Survival Plus.zip Normal file

Binary file not shown.

118
pom.xml Normal file
View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.viper</groupId>
<artifactId>SurvivalPlus</artifactId>
<version>1.0.5-Beta</version>
<packaging>jar</packaging>
<name>SurvivalPlus</name>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<!-- Repository für PlaceholderAPI -->
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- bStats Bukkit Dependency -->
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<!-- PlaceholderAPI Dependency -->
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
<!-- LuckPerms API Dependency -->
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>5.5.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>de.viper.survivalplus.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>plugin.yml</include>
<include>lang.yml</include>
<include>config.yml</include>
<include>homes.yml</include>
<include>inventory.yml</include>
<include>help.yml</include>
<include>graves.yml</include>
<include>stats.yml</include>
<include>leashes.yml</include>
<include>shop.yml</include>
<include>warps.yml</include>
<include>tablist.yml</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@@ -0,0 +1,148 @@
package de.viper.survivalplus.tasks;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarFlag;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
public class AFKManager {
private final Plugin plugin;
private final long afkAfterMillis;
private final long kickAfterMillis;
private final long joinGracePeriodMillis = 5000; // 5 Sekunden Schonfrist
private final Map<UUID, Long> lastActivity = new HashMap<>();
private final Map<UUID, Long> joinTimes = new HashMap<>();
private final Set<UUID> afkPlayers = new HashSet<>();
private final Map<UUID, BossBar> bossBars = new WeakHashMap<>();
private final Map<UUID, Integer> colorIndex = new HashMap<>();
private final Map<UUID, BukkitRunnable> colorTasks = new HashMap<>();
private final List<BarColor> colorCycle = List.of(
BarColor.RED, BarColor.YELLOW, BarColor.GREEN,
BarColor.BLUE, BarColor.PURPLE, BarColor.PINK
);
public AFKManager(Plugin plugin, long afkAfterSeconds, long kickAfterSeconds) {
this.plugin = plugin;
this.afkAfterMillis = afkAfterSeconds * 1000;
this.kickAfterMillis = kickAfterSeconds * 1000;
}
public void updateActivity(Player player) {
UUID uuid = player.getUniqueId();
long now = System.currentTimeMillis();
lastActivity.put(uuid, now);
// Optional: Schonfrist erneuern
joinTimes.put(uuid, now);
if (afkPlayers.remove(uuid)) {
removeAFKBossBar(player);
plugin.getLogger().fine("AFK-Status entfernt für " + player.getName());
}
}
public void reset(Player player) {
UUID uuid = player.getUniqueId();
lastActivity.remove(uuid);
joinTimes.remove(uuid);
afkPlayers.remove(uuid);
removeAFKBossBar(player);
}
public boolean isAFK(Player player) {
return afkPlayers.contains(player.getUniqueId());
}
public void checkAFKStatus(Player player) {
UUID uuid = player.getUniqueId();
long currentTime = System.currentTimeMillis();
// Schonfrist nach Join
if (joinTimes.containsKey(uuid) && (currentTime - joinTimes.get(uuid) < joinGracePeriodMillis)) {
return;
}
// Kreativ- oder Zuschauermodus ausschließen
if (player.getGameMode() == GameMode.CREATIVE ||
player.getGameMode() == GameMode.SPECTATOR) {
return;
}
if (!lastActivity.containsKey(uuid)) {
lastActivity.put(uuid, currentTime);
return;
}
long diff = currentTime - lastActivity.get(uuid);
if (diff >= afkAfterMillis) {
if (afkPlayers.add(uuid)) {
showAFKBossBar(player, "§cDu bist AFK!");
}
if (kickAfterMillis > 0 && diff >= kickAfterMillis) {
plugin.getLogger().info("Spieler " + player.getName() + " wird wegen AFK gekickt. Inaktiv seit: " + (diff / 1000) + " Sekunden");
player.kickPlayer("§cDu wurdest wegen AFK gekickt.");
removeAFKBossBar(player);
}
} else if (afkPlayers.remove(uuid)) {
removeAFKBossBar(player);
}
}
public void showAFKBossBar(Player player, String message) {
UUID uuid = player.getUniqueId();
removeAFKBossBar(player); // nur eine BossBar pro Spieler
BossBar bar = Bukkit.createBossBar(message, BarColor.YELLOW, BarStyle.SOLID, BarFlag.CREATE_FOG);
bar.addPlayer(player);
bar.setVisible(true);
bossBars.put(uuid, bar);
colorIndex.put(uuid, 0);
// ggf. alten Farbwechsel-Task stoppen
if (colorTasks.containsKey(uuid)) {
colorTasks.get(uuid).cancel();
colorTasks.remove(uuid);
}
// Farben wechseln
BukkitRunnable task = new BukkitRunnable() {
@Override
public void run() {
BossBar activeBar = bossBars.get(uuid);
if (activeBar == null) {
this.cancel();
colorTasks.remove(uuid);
return;
}
int index = colorIndex.getOrDefault(uuid, 0);
activeBar.setColor(colorCycle.get(index));
colorIndex.put(uuid, (index + 1) % colorCycle.size());
}
};
task.runTaskTimer(plugin, 0L, 20L);
colorTasks.put(uuid, task);
}
public void removeAFKBossBar(Player player) {
UUID uuid = player.getUniqueId();
if (colorTasks.containsKey(uuid)) {
colorTasks.get(uuid).cancel();
colorTasks.remove(uuid);
}
BossBar bar = bossBars.remove(uuid);
if (bar != null) {
bar.removeAll();
}
colorIndex.remove(uuid);
}
}

View File

@@ -0,0 +1,37 @@
package de.viper.survivalplus.Manager;
import java.util.*;
import org.bukkit.entity.Player;
public class BlockManager {
private final Map<UUID, Set<UUID>> blockedPlayers = new HashMap<>();
public void blockPlayer(Player blocker, Player toBlock) {
blockedPlayers.computeIfAbsent(blocker.getUniqueId(), k -> new HashSet<>()).add(toBlock.getUniqueId());
}
public void unblockPlayer(Player blocker, Player toUnblock) {
Set<UUID> blocked = blockedPlayers.get(blocker.getUniqueId());
if (blocked != null) {
blocked.remove(toUnblock.getUniqueId());
if (blocked.isEmpty()) {
blockedPlayers.remove(blocker.getUniqueId());
}
}
}
public boolean hasBlocked(Player blocker, Player potentialBlocked) {
return blockedPlayers.getOrDefault(blocker.getUniqueId(), Collections.emptySet())
.contains(potentialBlocked.getUniqueId());
}
public Set<UUID> getBlockedPlayers(Player player) {
return blockedPlayers.getOrDefault(player.getUniqueId(), Collections.emptySet());
}
public void clear(Player player) {
blockedPlayers.remove(player.getUniqueId());
}
}

View File

@@ -0,0 +1,323 @@
package de.viper.survivalplus.Manager;
import de.viper.survivalplus.SurvivalPlus;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.*;
import org.bukkit.block.Chest;
import org.bukkit.command.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class LootChestManager implements Listener, CommandExecutor {
private final SurvivalPlus plugin;
private final List<Location> activeChests = new ArrayList<>();
private final Map<Location, Long> chestSpawnTimes = new HashMap<>();
private final List<LootItem> lootItems = new ArrayList<>();
private final Map<UUID, Integer> playerLootCount = new HashMap<>();
private final long despawnMillis;
private final int maxActiveChests;
private final int maxLootPerPlayer;
private final long lootLimitResetMillis;
public LootChestManager(SurvivalPlus plugin) {
this.plugin = plugin;
loadLootFromConfig();
FileConfiguration cfg = plugin.getConfig();
this.despawnMillis = cfg.getLong("lootchest.despawn-minutes", 10) * 60 * 1000;
this.maxActiveChests = cfg.getInt("lootchest.max-active-chests", 10);
this.maxLootPerPlayer = cfg.getInt("lootchest.max-loot-per-player", 3);
this.lootLimitResetMillis = cfg.getLong("lootchest.loot-limit-reset-minutes", 60) * 60 * 1000;
startChestSpawnTask();
startChestDespawnTask();
startLootLimitResetTask();
}
private void loadLootFromConfig() {
FileConfiguration cfg = plugin.getConfig();
lootItems.clear();
if (cfg.isConfigurationSection("lootchest.items")) {
for (String key : cfg.getConfigurationSection("lootchest.items").getKeys(false)) {
lootItems.add(new LootItem(cfg, "lootchest.items." + key));
}
}
}
private void startLootLimitResetTask() {
new BukkitRunnable() {
@Override
public void run() {
playerLootCount.clear();
}
}.runTaskTimer(plugin, lootLimitResetMillis / 50, lootLimitResetMillis / 50);
}
private void startChestSpawnTask() {
long intervalTicks = plugin.getConfig().getLong("lootchest.interval-minutes", 30) * 60 * 20;
int spawnCount = plugin.getConfig().getInt("lootchest.spawn-count", 3);
new BukkitRunnable() {
@Override
public void run() {
if (!plugin.getConfig().getBoolean("lootchest.enabled", true)) return;
clearAllActiveChests();
for (int i = 0; i < spawnCount; i++) {
spawnRandomLootChest();
}
Bukkit.broadcastMessage(color(
plugin.getLangConfig().getString("lootchest.spawn-simple", "&aNeue Loot-Kisten sind gespawnt!")
));
}
}.runTaskTimer(plugin, 0L, intervalTicks);
}
private void startChestDespawnTask() {
new BukkitRunnable() {
@Override
public void run() {
long now = System.currentTimeMillis();
Iterator<Location> it = activeChests.iterator();
while (it.hasNext()) {
Location loc = it.next();
Long spawnTime = chestSpawnTimes.get(loc);
if (spawnTime != null && now - spawnTime >= despawnMillis) {
if (loc.getBlock().getType() == Material.CHEST) {
loc.getBlock().setType(Material.AIR);
}
it.remove();
chestSpawnTimes.remove(loc);
Bukkit.broadcastMessage(color(
plugin.getLangConfig().getString("lootchest.despawn-msg",
"&eEine Lootkiste ist von selbst verschwunden.")
));
}
}
}
}.runTaskTimer(plugin, 20L * 60, 20L * 60);
}
private void clearAllActiveChests() {
for (Location loc : new ArrayList<>(activeChests)) {
if (loc.getBlock().getType() == Material.CHEST) {
loc.getBlock().setType(Material.AIR);
}
}
activeChests.clear();
chestSpawnTimes.clear();
}
private void spawnRandomLootChest() {
if (activeChests.size() >= maxActiveChests) {
return;
}
World world = Bukkit.getWorld(plugin.getConfig().getString("lootchest.world", "world"));
if (world == null) return;
int radius = plugin.getConfig().getInt("lootchest.spawn-radius", 500);
ThreadLocalRandom r = ThreadLocalRandom.current();
int x = r.nextInt(-radius, radius);
int z = r.nextInt(-radius, radius);
int y = world.getHighestBlockYAt(x, z);
Location loc = new Location(world, x, y, z);
// Kein Spawn auf Wasser, Lava, Kelp, Seegras
Material below = world.getBlockAt(x, y - 1, z).getType();
if (below == Material.WATER || below == Material.LAVA
|| below == Material.KELP || below == Material.SEAGRASS
|| below == Material.TALL_SEAGRASS) {
return;
}
if (loc.getBlock().getType() != Material.AIR) {
loc.add(0, 1, 0);
}
loc.getBlock().setType(Material.CHEST);
Chest chest = (Chest) loc.getBlock().getState();
fillChestWithRandomLoot(chest.getInventory());
activeChests.add(loc);
chestSpawnTimes.put(loc, System.currentTimeMillis());
world.spawnParticle(Particle.FIREWORK, loc.clone().add(0.5, 1.0, 0.5),
20, 0.3, 0.5, 0.3);
world.playSound(loc, Sound.BLOCK_CHEST_OPEN, 1.0f, 1.0f);
}
private void fillChestWithRandomLoot(Inventory inv) {
inv.clear();
Random random = new Random();
for (LootItem lootItem : lootItems) {
if (lootItem.shouldSpawn(random)) {
inv.addItem(lootItem.createStack(random));
}
}
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player p)) {
sender.sendMessage(color(plugin.getLangConfig().getString("lootchest.player-only", "")));
return true;
}
if (!p.hasPermission("survivalplus.lootchests")) {
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.no-permission", "")));
return true;
}
if (cmd.getName().equalsIgnoreCase("lootchests")) {
if (activeChests.isEmpty()) {
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.no-chests", "")));
return true;
}
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.list-header", "")));
for (Location loc : activeChests) {
String coords = loc.getBlockX() + " " + loc.getBlockY() + " " + loc.getBlockZ();
net.md_5.bungee.api.chat.TextComponent msg =
new net.md_5.bungee.api.chat.TextComponent(ChatColor.AQUA + " - " + coords + " " + ChatColor.GREEN + "[TP]");
msg.setClickEvent(new net.md_5.bungee.api.chat.ClickEvent(
net.md_5.bungee.api.chat.ClickEvent.Action.RUN_COMMAND,
"/tploot " + loc.getWorld().getName() + " " + loc.getBlockX()
+ " " + loc.getBlockY() + " " + loc.getBlockZ()
));
msg.setHoverEvent(new net.md_5.bungee.api.chat.HoverEvent(
net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT,
new net.md_5.bungee.api.chat.ComponentBuilder(color(
plugin.getLangConfig().getString("lootchest.list-tp-hover", "")
)).create()
));
p.spigot().sendMessage(msg);
}
return true;
}
if (cmd.getName().equalsIgnoreCase("tploot")) {
if (!p.isOp() && !p.hasPermission("survivalplus.lootchests")) return true;
if (args.length != 4) {
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.tp-usage", "")));
return true;
}
World w = Bukkit.getWorld(args[0]);
if (w == null) {
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.tp-world-not-found", "")));
return true;
}
try {
double x = Double.parseDouble(args[1]);
double y = Double.parseDouble(args[2]);
double z = Double.parseDouble(args[3]);
p.teleport(new Location(w, x + 0.5, y, z + 0.5));
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.tp-success", "")));
} catch (NumberFormatException e) {
p.sendMessage(color(plugin.getLangConfig().getString("lootchest.tp-invalid-coords", "")));
}
return true;
}
return false;
}
@EventHandler
public void onInventoryOpen(InventoryOpenEvent event) {
if (!(event.getPlayer() instanceof Player player)) return;
InventoryHolder holder = event.getInventory().getHolder();
if (!(holder instanceof Chest chest)) return;
if (activeChests.contains(chest.getLocation())) {
UUID uuid = player.getUniqueId();
int looted = playerLootCount.getOrDefault(uuid, 0);
if (looted >= maxLootPerPlayer) {
player.sendMessage(color(plugin.getLangConfig().getString("lootchest.limit-reached", "&cDu hast dein Loot-Limit erreicht!")));
event.setCancelled(true);
}
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player player)) return;
InventoryHolder holder = event.getInventory().getHolder();
if (!(holder instanceof Chest chest)) return;
Location chestLoc = chest.getLocation();
if (activeChests.contains(chestLoc) && isInventoryEmpty(event.getInventory())) {
UUID uuid = player.getUniqueId();
int looted = playerLootCount.getOrDefault(uuid, 0);
if (looted >= maxLootPerPlayer) return;
playerLootCount.put(uuid, looted + 1);
chestLoc.getBlock().setType(Material.AIR);
activeChests.remove(chestLoc);
chestSpawnTimes.remove(chestLoc);
Bukkit.broadcastMessage(color(
plugin.getLangConfig().getString("lootchest.removed-msg", "&aEine Lootkiste wurde geleert und entfernt.")
));
}
}
private boolean isInventoryEmpty(Inventory inventory) {
for (ItemStack item : inventory.getContents()) {
if (item != null && item.getType() != Material.AIR) return false;
}
return true;
}
private String color(String msg) {
return ChatColor.translateAlternateColorCodes('&', msg == null ? "" : msg);
}
private static class LootItem {
private final Material material;
private final String name;
private final Map<Enchantment, Integer> enchantments = new HashMap<>();
private final double chance;
private final int min;
private final int max;
LootItem(FileConfiguration cfg, String path) {
material = Material.valueOf(cfg.getString(path + ".material", "STONE"));
name = cfg.getString(path + ".name", null);
chance = cfg.getDouble(path + ".chance", 1.0);
min = cfg.getInt(path + ".min", 1);
max = cfg.getInt(path + ".max", 1);
if (cfg.isConfigurationSection(path + ".enchantments")) {
for (String enchKey : cfg.getConfigurationSection(path + ".enchantments").getKeys(false)) {
Enchantment ench = Enchantment.getByName(enchKey.toUpperCase());
if (ench != null) {
enchantments.put(ench, cfg.getInt(path + ".enchantments." + enchKey));
}
}
}
}
boolean shouldSpawn(Random r) { return r.nextDouble() <= chance; }
ItemStack createStack(Random r) {
int amt = min + r.nextInt(max - min + 1);
ItemStack stack = new ItemStack(material, amt);
ItemMeta meta = stack.getItemMeta();
if (name != null) meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', name));
stack.setItemMeta(meta);
for (Map.Entry<Enchantment, Integer> e : enchantments.entrySet()) {
stack.addUnsafeEnchantment(e.getKey(), e.getValue());
}
return stack;
}
}
}

View File

@@ -0,0 +1,56 @@
package de.viper.survivalplus.report;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class ReportManager {
private final SurvivalPlus plugin;
private final File reportFile;
private FileConfiguration reportConfig;
public ReportManager(SurvivalPlus plugin) {
this.plugin = plugin;
this.reportFile = new File(plugin.getDataFolder(), "reports.yml");
if (!reportFile.exists()) {
try {
reportFile.createNewFile();
} catch (IOException e) {
plugin.getLogger().severe("Konnte reports.yml nicht erstellen!");
e.printStackTrace();
}
}
this.reportConfig = YamlConfiguration.loadConfiguration(reportFile);
}
public void addReport(String reportedPlayer, String reporter, String reason, String time) {
String path = "reports." + reportedPlayer;
List<String> reports = reportConfig.getStringList(path);
reports.add(time + " - Von: " + reporter + " | Grund: " + reason);
reportConfig.set(path, reports);
saveReports();
}
public List<String> getReports(String reportedPlayer) {
return reportConfig.getStringList("reports." + reportedPlayer);
}
public void clearReports(String reportedPlayer) {
reportConfig.set("reports." + reportedPlayer, null);
saveReports();
}
private void saveReports() {
try {
reportConfig.save(reportFile);
} catch (IOException e) {
plugin.getLogger().severe("Fehler beim Speichern der reports.yml: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,70 @@
package de.viper.survivalplus.Manager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
public class ShopManager {
private final SurvivalPlus plugin;
private final File shopFile;
private final FileConfiguration shopConfig;
public ShopManager(SurvivalPlus plugin) {
this.plugin = plugin;
this.shopFile = new File(plugin.getDataFolder(), "shop.yml");
if (!shopFile.exists()) {
plugin.saveResource("shop.yml", false);
}
this.shopConfig = YamlConfiguration.loadConfiguration(shopFile);
}
public double getCurrentPrice(String itemKey) {
return shopConfig.getDouble("items." + itemKey + ".current-price", 0);
}
public boolean buyItem(String itemKey, int amount) {
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
if (stock < amount) {
return false;
}
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
shopConfig.set("items." + itemKey + ".stock", stock - amount);
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
saveShop();
return true;
}
public void sellItem(String itemKey, int amount) {
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
shopConfig.set("items." + itemKey + ".stock", stock + amount);
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
saveShop();
}
public void addOrUpdateItem(String itemKey, double basePrice, int stock) {
shopConfig.set("items." + itemKey + ".base-price", basePrice);
shopConfig.set("items." + itemKey + ".stock", stock);
shopConfig.set("items." + itemKey + ".current-price", basePrice);
saveShop();
}
private void saveShop() {
try {
shopConfig.save(shopFile);
} catch (IOException e) {
plugin.getLogger().severe("Fehler beim Speichern von shop.yml");
e.printStackTrace();
}
}
public FileConfiguration getShopConfig() {
return shopConfig;
}
}

View File

@@ -0,0 +1,92 @@
package de.viper.survivalplus.Manager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
public class StatsManager {
private final SurvivalPlus plugin;
private File statsFile;
private FileConfiguration statsConfig;
public StatsManager(SurvivalPlus plugin) {
this.plugin = plugin;
createStatsFile();
}
private void createStatsFile() {
statsFile = new File(plugin.getDataFolder(), "stats.yml");
if (!statsFile.exists()) {
plugin.saveResource("stats.yml", false);
}
statsConfig = YamlConfiguration.loadConfiguration(statsFile);
}
public void saveStats() {
try {
statsConfig.save(statsFile);
} catch (IOException e) {
plugin.getLogger().severe("Fehler beim Speichern der stats.yml: " + e.getMessage());
}
}
// Spielzeit in Sekunden addieren
public void addPlayTime(UUID playerUUID, long seconds) {
long current = statsConfig.getLong(playerUUID + ".playtime", 0);
statsConfig.set(playerUUID + ".playtime", current + seconds);
}
// Kills addieren
public void addKills(UUID playerUUID, int amount) {
int current = statsConfig.getInt(playerUUID + ".kills", 0);
statsConfig.set(playerUUID + ".kills", current + amount);
}
// Tode addieren
public void addDeaths(UUID playerUUID, int amount) {
int current = statsConfig.getInt(playerUUID + ".deaths", 0);
statsConfig.set(playerUUID + ".deaths", current + amount);
}
// Abgebaute Blöcke addieren
public void addBlocksBroken(UUID playerUUID, int amount) {
int current = statsConfig.getInt(playerUUID + ".blocks_broken", 0);
statsConfig.set(playerUUID + ".blocks_broken", current + amount);
}
// Platzierte Blöcke addieren
public void addBlocksPlaced(UUID playerUUID, int amount) {
int current = statsConfig.getInt(playerUUID + ".blocks_placed", 0);
statsConfig.set(playerUUID + ".blocks_placed", current + amount);
}
// Getter für Statistikwerte
public long getPlayTime(UUID playerUUID) {
return statsConfig.getLong(playerUUID + ".playtime", 0);
}
public int getKills(UUID playerUUID) {
return statsConfig.getInt(playerUUID + ".kills", 0);
}
public int getDeaths(UUID playerUUID) {
return statsConfig.getInt(playerUUID + ".deaths", 0);
}
public int getBlocksBroken(UUID playerUUID) {
return statsConfig.getInt(playerUUID + ".blocks_broken", 0);
}
public int getBlocksPlaced(UUID playerUUID) {
return statsConfig.getInt(playerUUID + ".blocks_placed", 0);
}
}

View File

@@ -0,0 +1,327 @@
package de.viper.survivalplus.Manager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import me.clip.placeholderapi.PlaceholderAPI;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.user.User;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
public class TablistManager {
private final SurvivalPlus plugin;
private final List<String> headerAnim = new ArrayList<>();
private final List<String> footerAnim = new ArrayList<>();
private int headerIndex = 0;
private int footerIndex = 0;
private boolean enabled;
private String serverName;
private String website;
private String teamspeakAddress;
private String discordAddress;
private boolean showTeamspeak;
private boolean showDiscord;
private String staffPermission;
private String separatorLine;
private LuckPerms luckPerms;
public TablistManager(SurvivalPlus plugin) {
this.plugin = plugin;
// Resource sicherstellen, Config laden
try { plugin.saveResource("tablist.yml", false); } catch (Exception ignored) {}
try { plugin.reloadTablistConfig(); } catch (Throwable ignored) {}
FileConfiguration config = plugin.getTablistConfig();
// Konfigurationswerte laden
this.enabled = config.getBoolean("enabled", true);
this.serverName = config.getString("server-name", "SurvivalPlus");
this.website = config.getString("website", "www.example.com");
this.teamspeakAddress = config.getString("teamspeak-address", "ts.example.com");
this.discordAddress = config.getString("discord-address", "discord.gg/example");
this.showTeamspeak = config.getBoolean("show-teamspeak", true);
this.showDiscord = config.getBoolean("show-discord", true);
this.staffPermission = config.getString("staff-permission", "survivalplus.staff");
this.separatorLine = config.getString("separator-line", "&8&l&m================");
// LuckPerms API initialisieren
try {
this.luckPerms = LuckPermsProvider.get();
} catch (IllegalStateException e) {
plugin.getLogger().warning("LuckPerms nicht gefunden! Versuche Fallback auf PlaceholderAPI.");
}
// Prüfen, ob PlaceholderAPI verfügbar ist
if (!Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
plugin.getLogger().warning("PlaceholderAPI nicht gefunden! Verwende Standard-Prefix als Fallback.");
}
if (!enabled) {
plugin.getLogger().info("Tablist ist deaktiviert (tablist.yml -> enabled: false)");
return;
}
// Header- und Footer-Animationen füllen
List<String> configHeader = config.getStringList("header-animations");
List<String> configFooter = config.getStringList("footer-animations");
if (configHeader != null && !configHeader.isEmpty()) {
headerAnim.addAll(configHeader);
} else {
headerAnim.add("&6&l{server}\n&7Willkommen, &a{player}\n&7Online Player: &e{online}\n&6Online Staff: &e{staff}\n");
}
if (configFooter != null && !configFooter.isEmpty()) {
footerAnim.addAll(configFooter);
} else {
footerAnim.add("&7SurvivalPlus &8| &eDein Abenteuer!");
}
startAnimation();
}
private void startAnimation() {
if (!enabled) return;
int interval = Math.max(1, plugin.getTablistConfig().getInt("interval-ticks", 20));
new BukkitRunnable() {
@Override
public void run() {
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
// Online-Spieler und Staff zählen
int onlinePlayers = Bukkit.getOnlinePlayers().size();
int onlineStaff = (int) Bukkit.getOnlinePlayers().stream()
.filter(p -> p.hasPermission(staffPermission))
.count();
// Aktuelles Datum und Uhrzeit formatieren
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
String currentTime = dateFormat.format(new Date());
for (Player player : Bukkit.getOnlinePlayers()) {
try {
// Spieler-Prefix abrufen (LuckPerms primär, PlaceholderAPI als Fallback)
String prefix = getPlayerPrefix(player);
int ping = getPlayerPing(player);
// Korrigierte Formatierung: Gesamten String durch color-Methode leiten
String prefixedName = color(prefix + player.getName() + "&8 | &e" + ping + "ms");
player.setPlayerListName(prefixedName);
// Header mit Spielername und Statistiken
String headerRaw = headerAnim.get(headerIndex)
.replace("{server}", serverName)
.replace("{player}", player.getName())
.replace("{online}", String.valueOf(onlinePlayers))
.replace("{staff}", String.valueOf(onlineStaff));
String footerRaw = footerAnim.get(footerIndex);
// Footer zusammenstellen: TS und Discord nebeneinander, Webseite zentriert
StringBuilder footerBuilder = new StringBuilder();
footerBuilder.append("\n"); // Extra Abstand
footerBuilder.append(color(footerRaw)).append("\n");
footerBuilder.append(color(separatorLine)).append("\n");
if (showTeamspeak || showDiscord) {
StringBuilder socialLine = new StringBuilder();
if (showTeamspeak) {
socialLine.append("&7TS: &a").append(teamspeakAddress);
}
if (showTeamspeak && showDiscord) {
socialLine.append(" &8| ");
}
if (showDiscord) {
socialLine.append("&7Discord: &d").append(discordAddress);
}
footerBuilder.append(color(socialLine.toString())).append("\n");
}
footerBuilder.append(" &7Webseite: &b").append(website).append("\n");
footerBuilder.append(color(separatorLine)).append("\n");
footerBuilder.append("&7Datum & Uhrzeit: &e").append(currentTime);
String header = color(headerRaw);
String footer = color(footerBuilder.toString());
// 1) Adventure (Component) Variante
boolean done = tryAdventureComponent(player, headerRaw, footerBuilder.toString());
// 2) String-Variante fallback
if (!done) {
done = tryStringMethod(player, header, footer);
}
// 3) Wenn alles fehlschlägt -> Log
if (!done) {
plugin.getLogger().warning("Tablist: Keine geeignete Methode gefunden für Spieler " + player.getName());
}
} catch (Throwable t) {
plugin.getLogger().log(Level.FINE, "Fehler beim Setzen der Tablist für Spieler " + player.getName(), t);
}
}
headerIndex = (headerIndex + 1) % headerAnim.size();
footerIndex = (footerIndex + 1) % footerAnim.size();
}
}.runTaskTimer(plugin, 0L, interval);
}
/**
* Spieler-Prefix abrufen (LuckPerms primär, PlaceholderAPI als Fallback)
*/
private String getPlayerPrefix(Player player) {
// Versuche LuckPerms-API zuerst
if (luckPerms != null) {
try {
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
String prefix = user.getCachedData().getMetaData().getPrefix();
return (prefix == null || prefix.isEmpty()) ? "&7[Spieler] " : prefix + " ";
} catch (Exception e) {
plugin.getLogger().log(Level.FINE, "Fehler beim Abrufen des Prefix aus LuckPerms für Spieler " + player.getName(), e);
}
}
// Fallback auf PlaceholderAPI
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
return (prefix == null || prefix.isEmpty()) ? "&7[Spieler] " : prefix + " ";
}
// Letzter Fallback: Standard-Prefix
return "&7[Spieler] ";
}
/**
* Spieler-Ping abrufen
*/
private int getPlayerPing(Player player) {
try {
Method getHandle = player.getClass().getMethod("getHandle");
Object entityPlayer = getHandle.invoke(player);
return entityPlayer.getClass().getField("ping").getInt(entityPlayer);
} catch (Exception e) {
plugin.getLogger().log(Level.FINE, "Fehler beim Abrufen des Pings für Spieler " + player.getName(), e);
return -1;
}
}
/**
* Adventure-Variante mit Components
*/
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
try {
Class<?> compClass = Class.forName("net.kyori.adventure.text.Component");
Method textMethod = null;
try {
textMethod = compClass.getMethod("text", CharSequence.class);
} catch (NoSuchMethodException ignored) {
try { textMethod = compClass.getMethod("text", String.class); } catch (NoSuchMethodException ignored2) {}
}
Object headerComp = null;
Object footerComp = null;
if (textMethod != null) {
headerComp = textMethod.invoke(null, color(headerRaw));
footerComp = textMethod.invoke(null, color(footerRaw));
} else {
// Fallback: MiniMessage
try {
Class<?> miniMsgClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
Method miniMsgSingleton = miniMsgClass.getMethod("miniMessage");
Object miniMsg = miniMsgSingleton.invoke(null);
Method deserialize = miniMsgClass.getMethod("deserialize", String.class);
headerComp = deserialize.invoke(miniMsg, headerRaw);
footerComp = deserialize.invoke(miniMsg, footerRaw);
} catch (Throwable t) {
// kein MiniMessage
}
}
if (headerComp == null || footerComp == null) return false;
Method m = findMethod(player.getClass(), "sendPlayerListHeaderAndFooter", compClass, compClass);
if (m == null) m = findMethod(player.getClass(), "setPlayerListHeaderFooter", compClass, compClass);
if (m != null) {
m.invoke(player, headerComp, footerComp);
return true;
} else {
Method mh = findMethod(player.getClass(), "sendPlayerListHeader", compClass);
Method mf = findMethod(player.getClass(), "sendPlayerListFooter", compClass);
if (mh != null && mf != null) {
mh.invoke(player, headerComp);
mf.invoke(player, footerComp);
return true;
}
}
} catch (ClassNotFoundException cnf) {
return false;
} catch (Throwable t) {
plugin.getLogger().log(Level.FINER, "Adventure-Variante fehlgeschlagen: " + t.getMessage());
return false;
}
return false;
}
/**
* String-Variante
*/
private boolean tryStringMethod(Player player, String header, String footer) {
try {
Method m = findMethod(player.getClass(), "sendPlayerListHeaderFooter", String.class, String.class);
if (m == null) {
m = findMethod(player.getClass(), "setPlayerListHeaderFooter", String.class, String.class);
}
if (m != null) {
m.invoke(player, header, footer);
return true;
}
Method mh = findMethod(player.getClass(), "sendPlayerListHeader", String.class);
Method mf = findMethod(player.getClass(), "sendPlayerListFooter", String.class);
if (mh != null && mf != null) {
mh.invoke(player, header);
mf.invoke(player, footer);
return true;
}
} catch (Throwable t) {
plugin.getLogger().log(Level.FINER, "String-Variante fehlgeschlagen: " + t.getMessage());
return false;
}
return false;
}
/**
* Hilfsmethode für Reflection
*/
private Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
Class<?> current = clazz;
while (current != null) {
try {
Method m = current.getMethod(name, paramTypes);
if (m != null) return m;
} catch (NoSuchMethodException ignored) { }
current = current.getSuperclass();
}
return null;
}
/**
* Farbcode-Konvertierung (& -> §)
*/
private String color(String msg) {
if (msg == null) return "";
return msg.replace("&", "§");
}
}

View File

@@ -0,0 +1,44 @@
package de.viper.survivalplus.Manager;
import org.bukkit.inventory.ItemStack;
public class Warp {
private final String owner;
private final String name;
private final ItemStack item;
private final String worldName;
private final double x, y, z;
public Warp(String owner, String name, ItemStack item, String worldName, double x, double y, double z) {
this.owner = owner;
this.name = name;
this.item = item;
this.worldName = worldName;
this.x = x;
this.y = y;
this.z = z;
}
public String getOwner() {
return owner;
}
public String getName() {
return name;
}
public ItemStack getItem() {
return item;
}
public String getWorldName() {
return worldName;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
}

View File

@@ -0,0 +1,113 @@
package de.viper.survivalplus.Manager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class WarpManager {
private final SurvivalPlus plugin;
private File warpsFile;
private FileConfiguration warpsConfig;
private final Map<String, Warp> warps = new HashMap<>(); // key: owner:name
public WarpManager(SurvivalPlus plugin) {
this.plugin = plugin;
loadWarpsFile();
loadWarps();
}
private void loadWarpsFile() {
warpsFile = new File(plugin.getDataFolder(), "warps.yml");
if (!warpsFile.exists()) {
plugin.saveResource("warps.yml", false);
}
warpsConfig = YamlConfiguration.loadConfiguration(warpsFile);
}
public void saveWarpsFile() {
try {
warpsConfig.save(warpsFile);
} catch (IOException e) {
plugin.getLogger().severe("Konnte warps.yml nicht speichern!");
e.printStackTrace();
}
}
private void loadWarps() {
warps.clear();
if (warpsConfig.contains("warps")) {
for (String key : warpsConfig.getConfigurationSection("warps").getKeys(false)) {
String path = "warps." + key;
String owner = warpsConfig.getString(path + ".owner");
String name = warpsConfig.getString(path + ".name");
ItemStack item = warpsConfig.getItemStack(path + ".item");
double x = warpsConfig.getDouble(path + ".location.x");
double y = warpsConfig.getDouble(path + ".location.y");
double z = warpsConfig.getDouble(path + ".location.z");
String worldName = warpsConfig.getString(path + ".location.world");
Warp warp = new Warp(owner, name, item, worldName, x, y, z);
warps.put(owner + ":" + name, warp);
}
}
}
public void addWarp(Warp warp) {
warps.put(warp.getOwner() + ":" + warp.getName(), warp);
saveWarpToConfig(warp);
saveWarpsFile();
}
private void saveWarpToConfig(Warp warp) {
String path = "warps." + warp.getOwner() + "_" + warp.getName();
warpsConfig.set(path + ".owner", warp.getOwner());
warpsConfig.set(path + ".name", warp.getName());
warpsConfig.set(path + ".item", warp.getItem());
warpsConfig.set(path + ".location.x", warp.getX());
warpsConfig.set(path + ".location.y", warp.getY());
warpsConfig.set(path + ".location.z", warp.getZ());
warpsConfig.set(path + ".location.world", warp.getWorldName());
}
public Map<String, Warp> getWarps() {
return warps;
}
public Warp getWarp(String owner, String name) {
return warps.get(owner + ":" + name);
}
// Neu hinzugefügt: Anzahl der Warps eines Spielers zählen
public int getWarpCountForPlayer(String playerName) {
int count = 0;
for (Warp warp : warps.values()) {
if (warp.getOwner().equalsIgnoreCase(playerName)) {
count++;
}
}
return count;
}
// Neu hinzugefügt: Warp eines Spielers löschen
public boolean removeWarp(String owner, String name) {
String key = owner + ":" + name;
if (!warps.containsKey(key)) {
return false;
}
warps.remove(key);
String path = "warps." + owner + "_" + name;
warpsConfig.set(path, null); // Eintrag in Config entfernen
saveWarpsFile();
return true;
}
}

View File

@@ -0,0 +1,931 @@
package de.viper.survivalplus;
import de.viper.survivalplus.commands.*;
import de.viper.survivalplus.listeners.*;
import de.viper.survivalplus.report.ReportManager;
import de.viper.survivalplus.trade.TradeManager;
import de.viper.survivalplus.listeners.DebugArmorStandListener;
import de.viper.survivalplus.listeners.ArmorStandDestroyListener;
import de.viper.survivalplus.tasks.AutoClearTask;
import de.viper.survivalplus.recipe.BackpackRecipe;
import de.viper.survivalplus.Manager.StatsManager;
import de.viper.survivalplus.Manager.BlockManager;
import de.viper.survivalplus.util.LockSystem;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.event.HandlerList;
import de.viper.survivalplus.listeners.RepairSignListener;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart;
import de.viper.survivalplus.listeners.NickLoadListener;
import de.viper.survivalplus.Manager.LootChestManager;
import de.viper.survivalplus.commands.DayCommand;
import de.viper.survivalplus.commands.NightCommand;
import de.viper.survivalplus.commands.TradeCommand;
import de.viper.survivalplus.commands.ReportCommand;
import de.viper.survivalplus.Manager.ShopManager;
import de.viper.survivalplus.commands.HealCommand;
import de.viper.survivalplus.Manager.TablistManager;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.commands.SetWarpCommand;
import de.viper.survivalplus.commands.WarpsCommand;
import de.viper.survivalplus.fun.FunChallengeManager;
import de.viper.survivalplus.listeners.ChallengeCollectListener;
import de.viper.survivalplus.commands.StartFunChallengeCommand;
import java.util.Map;
import java.util.UUID;
import java.util.HashMap;
import org.bukkit.NamespacedKey;
import org.bukkit.plugin.PluginManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
// Zusätzliche Imports für Block-/Permission-Handling
import org.bukkit.GameRule;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
public class SurvivalPlus extends JavaPlugin {
private File langFile;
private FileConfiguration langConfig;
private File homesFile;
private FileConfiguration homesConfig;
private File gravesFile;
private FileConfiguration gravesConfig;
private File helpFile;
private FileConfiguration helpConfig;
private File backpackFile;
private FileConfiguration backpackConfig;
private File friendsFile;
private FileConfiguration friendsConfig;
private File leashesFile;
private FileConfiguration leashesConfig;
private File mobCapFile;
private FileConfiguration mobCapConfig;
private FileConfiguration tablistConfig;
private File tablistFile;
private File nicknamesFile;
private FileConfiguration nicknamesConfig;
private SpawnProtectionListener spawnProtectionListener;
private int autoClearTaskId = -1;
private StatsManager statsManager;
private NewbieProtectionListener newbieListener;
// Listener als Felder speichern
private MobLeashLimitListener mobLeashLimitListener;
private MobCapListener mobCapListener;
private SleepListener sleepListener;
private OreAlarmListener oreAlarmListener;
private AFKListener afkListener;
private GraveListener graveListener;
private SitListener sitListener;
private PlayerJoinListener playerJoinListener;
private FunChallengeManager challengeManager;
private NamespacedKey droppedKey;
private Map<UUID, Integer> progressMap = new HashMap<>();
// WarpManager als Feld
private WarpManager warpManager;
// FunChallengeManager als Feld
private FunChallengeManager funChallengeManager;
// ------------------- Tablist Config -------------------
public void reloadTablistConfig() {
// Lädt die tablist.yml aus dem Plugin-Ordner neu
if (tablistFile == null) tablistFile = new File(getDataFolder(), "tablist.yml");
if (!tablistFile.exists()) {
saveResource("tablist.yml", false); // kopiert die default tablist.yml, falls sie fehlt
}
tablistConfig = YamlConfiguration.loadConfiguration(tablistFile);
}
public FileConfiguration getTablistConfig() {
// Stellt sicher, dass die Config geladen ist
if (tablistConfig == null) {
reloadTablistConfig();
}
return tablistConfig;
}
@Override
public void onEnable() {
// Default-Config sicherstellen
saveDefaultConfig();
// bStats initialisieren
int pluginId = 26886;
Metrics metrics = new Metrics(this, pluginId);
metrics.addCustomChart(new SimplePie(
"default_gamemode",
() -> Bukkit.getDefaultGameMode().toString()
));
metrics.addCustomChart(new SingleLineChart(
"online_players",
() -> Bukkit.getOnlinePlayers().size()
));
metrics.addCustomChart(new SimplePie(
"plugin_language",
() -> getConfig().getString("language", "default")
));
// Konfigurationen/Dateien laden
updateConfigFiles();
createHomesFile();
createGravesFile();
createBackpackFile();
createFriendsFile();
createLeashesFile();
createMobCapFile();
createNicknamesFile();
// PluginManager holen (vor Listener-Registrierung!)
PluginManager pluginManager = getServer().getPluginManager();
// Permission registrieren: survivalplus.notify für OPs standardmäßig aktiv
try {
Permission notifyPerm = new Permission("survivalplus.notify", PermissionDefault.OP);
if (pluginManager.getPermission("survivalplus.notify") == null) {
pluginManager.addPermission(notifyPerm);
getLogger().info("Permission survivalplus.notify erfolgreich registriert.");
}
} catch (Exception e) {
getLogger().warning("Fehler beim Registrieren der Permission survivalplus.notify: " + e.getMessage());
}
// NamespacedKey für Item-Drop-Markierung erzeugen
droppedKey = new NamespacedKey(this, "droppedItem");
// FunChallengeManager initialisieren und laden
funChallengeManager = new FunChallengeManager();
funChallengeManager.load(getConfig());
// Listener registrieren mit droppedKey
pluginManager.registerEvents(new ChallengeCollectListener(funChallengeManager, droppedKey), this);
pluginManager.registerEvents(new ChallengeSmeltListener(funChallengeManager), this);
// FriendCommand
FriendCommand friendCommand = new FriendCommand(this, friendsConfig, langConfig, getLogger());
getCommand("day").setExecutor(new DayCommand(this));
getCommand("night").setExecutor(new NightCommand(this));
// TradeManager und ReportManager initialisieren
TradeManager tradeManager = new TradeManager(this);
ReportManager reportManager = new ReportManager(this);
// Report Commands registrieren
getCommand("report").setExecutor(new ReportCommand(this, reportManager));
getCommand("showreport").setExecutor(new ShowReportCommand(this, reportManager));
getCommand("clearreport").setExecutor(new ClearReportCommand(this, reportManager));
// Trade Commands registrieren
getCommand("trade").setExecutor(new TradeCommand(this, tradeManager));
getCommand("tradeaccept").setExecutor(new TradeAcceptCommand(this, tradeManager));
// StatsManager initialisieren
statsManager = new StatsManager(this);
// warpManager initialisieren
warpManager = new WarpManager(this);
// TablistManager starten
TablistManager tablistManager = new TablistManager(this);
// Listener-Instanzen
sitListener = new SitListener(this);
afkListener = new AFKListener(this);
graveListener = new GraveListener(this);
playerJoinListener = new PlayerJoinListener(friendCommand);
// Commands registrieren (Rest)
getCommand("gm").setExecutor(new GamemodeCommand(this));
getCommand("sp").setExecutor(new PluginCommand(this));
getCommand("sethome").setExecutor(new HomeCommand(this));
getCommand("delhome").setExecutor(new HomeCommand(this));
getCommand("homelist").setExecutor(new HomeCommand(this));
getCommand("inv").setExecutor(new InventoryCommand(this));
getCommand("ec").setExecutor(new EnderchestCommand(this));
getCommand("setspawn").setExecutor(new SetSpawnCommand(this));
getCommand("setworldspawn").setExecutor(new SetWorldSpawnCommand(this));
getCommand("clearchat").setExecutor(new ClearChatCommand());
getCommand("clearitems").setExecutor(new ClearItemsCommand(this));
getCommand("closedoors").setExecutor(new CloseDoorsCommand(this));
getCommand("sit").setExecutor(new SitCommand(this, sitListener));
getCommand("back").setExecutor(new BackCommand(this));
getCommand("friend").setExecutor(friendCommand);
getCommand("ir").setExecutor(new ItemRenameCommand(this));
getCommand("showarmorstands").setExecutor(new ShowArmorStandsCommand(this));
getCommand("cleardebugarmorstands").setExecutor(new ClearDebugArmorStandsCommand(this));
getCommand("trash").setExecutor(new TrashCommand());
getCommand("workbench").setExecutor(new WorkbenchCommand());
getCommand("anvil").setExecutor(new AnvilCommand());
getCommand("nick").setExecutor(new NickCommand(this));
getCommand("shop").setExecutor(new ShopCommand(this));
getCommand("stats").setExecutor(new StatsCommand(this, statsManager));
getCommand("spawn").setExecutor(new SpawnCommand(this));
getCommand("setwarp").setExecutor(new SetWarpCommand(this, warpManager));
getCommand("warps").setExecutor(new WarpsCommand(this, warpManager));
getCommand("delwarp").setExecutor(new DelWarpCommand(this, warpManager));
TeleportCommands teleportCommands = new TeleportCommands(this);
getCommand("tp").setExecutor(teleportCommands);
getCommand("tphere").setExecutor(teleportCommands);
getCommand("tpa").setExecutor(teleportCommands);
getCommand("tpaccept").setExecutor(teleportCommands);
getCommand("tpdeny").setExecutor(teleportCommands);
getCommand("startchallenge").setExecutor(new StartFunChallengeCommand(this, funChallengeManager));
getCommand("kit").setExecutor(new KitCommand(this));
getCommand("heal").setExecutor(new HealCommand(this));
// LootChestManager + Befehle
LootChestManager lootChestManager = new LootChestManager(this);
pluginManager.registerEvents(lootChestManager, this);
getCommand("lootchests").setExecutor(lootChestManager);
getCommand("tploot").setExecutor(lootChestManager);
// BlockManager
BlockManager blockManager = new BlockManager();
FileConfiguration config = getConfig();
// Listener registrieren
BackpackRecipe.register(this, langConfig);
pluginManager.registerEvents(new ChatBlockListener(blockManager), this);
pluginManager.registerEvents(new InventoryClickListener(this), this);
pluginManager.registerEvents(sitListener, this);
pluginManager.registerEvents(afkListener, this);
pluginManager.registerEvents(graveListener, this);
pluginManager.registerEvents(new BackpackListener(backpackConfig, langConfig, getLogger(), backpackFile), this);
pluginManager.registerEvents(new StatsListener(this, statsManager), this);
pluginManager.registerEvents(new LoginListener(this), this);
pluginManager.registerEvents(new DebugArmorStandListener(), this);
pluginManager.registerEvents(new ArmorStandDestroyListener(), this);
pluginManager.registerEvents(new FirstJoinListener(), this);
pluginManager.registerEvents(playerJoinListener, this);
pluginManager.registerEvents(new SignColorListener(this), this);
pluginManager.registerEvents(new SleepListener(this), this);
pluginManager.registerEvents(new OreAlarmListener(this), this);
pluginManager.registerEvents(new MobLeashLimitListener(this, getConfig()), this);
pluginManager.registerEvents(new MobCapListener(this, getConfig()), this);
pluginManager.registerEvents(new SpawnProtectionListener(this), this);
pluginManager.registerEvents(new NewbieProtectionListener(this), this);
pluginManager.registerEvents(new WarpInventoryListener(this, warpManager), this);
pluginManager.registerEvents(new ChallengeSmeltListener(funChallengeManager), this);
pluginManager.registerEvents(new BlockDetectionListener(this), this);
LockSystem lockSystem = new LockSystem(this);
pluginManager.registerEvents(lockSystem, this);
getCommand("sp").setExecutor(lockSystem);
pluginManager.registerEvents(new RepairSignListener(getConfig(), getLangConfig()), this);
pluginManager.registerEvents(new ToolUpgradeListener(this), this);
pluginManager.registerEvents(new NickLoadListener(this), this);
// AutoClear starten
startAutoClearTask();
spawnArmorStandExample();
getLogger().info(getMessage("plugin.enabled"));
// === Gamerule keepInventory aus Config setzen ===
if (getConfig().getBoolean("set-keepinventory", true)) {
Bukkit.getScheduler().runTaskLater(this, () -> {
if (Bukkit.getWorlds().isEmpty()) return;
Bukkit.getWorlds().forEach(world -> {
world.setGameRule(GameRule.KEEP_INVENTORY, false);
getLogger().info("Gamerule keepInventory in Welt '" + world.getName() + "' wurde auf false gesetzt.");
});
}, 20L);
}
// === Force Survival Mode aktivieren ===
if (getConfig().getBoolean("force-survival", true)) {
pluginManager.registerEvents(new ForceSurvivalListener(this), this);
getLogger().info("Force-Survival ist aktiv. Spieler werden beim Joinen in Survival gesetzt.");
}
// === Animierte Tablist konfigurieren und starten ===
try {
// tablist.yml laden / defaults setzen
if (tablistFile == null) tablistFile = new File(getDataFolder(), "tablist.yml");
if (!tablistFile.exists()) {
saveResource("tablist.yml", false);
}
tablistConfig = YamlConfiguration.loadConfiguration(tablistFile);
// Standardwerte aus Resource als Defaults setzen (falls vorhanden)
InputStream defStream = getResource("tablist.yml");
if (defStream != null) {
tablistConfig.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(defStream)));
}
getLogger().info("Animierte Tablist wurde geladen!");
} catch (Exception e) {
getLogger().log(Level.WARNING, "Fehler beim Laden der Tablist-Konfiguration", e);
}
// === Gamerules anwenden (kurze Verzögerung, damit Welten geladen sind) ===
Bukkit.getScheduler().runTaskLater(this, this::applyBlockRules, 20L);
}
/**
* Liest Config und setzt GameRule sowie entfernt verbotene Blöcke aus Inventaren online
*/
public void applyBlockRules() {
boolean cmdAllowed = getConfig().getBoolean("blocks.command-blocks.enabled", true);
boolean structAllowed = getConfig().getBoolean("blocks.structure-blocks.enabled", true);
for (World world : Bukkit.getWorlds()) {
try {
// moderner API-Aufruf
world.setGameRule(GameRule.COMMAND_BLOCK_OUTPUT, cmdAllowed);
} catch (NoSuchMethodError | NoClassDefFoundError e) {
// Fallback für ältere Server-Implementationen
world.setGameRuleValue(GameRule.COMMAND_BLOCK_OUTPUT.getName(), Boolean.toString(cmdAllowed));
}
getLogger().info("Gamerule commandBlockOutput in Welt '" + world.getName() + "' gesetzt auf " + cmdAllowed);
}
// Entferne verbotenes Zeug aus Inventaren aller online-Spieler direkt beim Start
removeForbiddenBlocksFromInventories(cmdAllowed, structAllowed);
getLogger().info("Block-Regeln angewendet: CommandBlocks erlaubt=" + cmdAllowed + ", StructureBlocks erlaubt=" + structAllowed);
}
/** Entfernt Command-/Structure-Blöcke aus Inventaren falls deaktiviert, ausgenommen Admins */
private void removeForbiddenBlocksFromInventories(boolean cmdAllowed, boolean structAllowed) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.hasPermission("survivalplus.notify")) {
continue; // Admins dürfen Blöcke behalten
}
Inventory inv = p.getInventory();
boolean removedCommandBlock = false;
boolean removedStructureBlock = false;
if (!cmdAllowed && inv.contains(Material.COMMAND_BLOCK)) {
inv.remove(Material.COMMAND_BLOCK);
removedCommandBlock = true;
p.sendMessage(ChatColor.RED + "[SurvivalPlus] Command-Blöcke wurden aus deinem Inventar entfernt, da sie deaktiviert sind.");
}
if (!structAllowed && inv.contains(Material.STRUCTURE_BLOCK)) {
inv.remove(Material.STRUCTURE_BLOCK);
removedStructureBlock = true;
p.sendMessage(ChatColor.RED + "[SurvivalPlus] Structure-Blöcke wurden aus deinem Inventar entfernt, da sie deaktiviert sind.");
}
// Benachrichtige Admins über entfernte Blöcke
if ((removedCommandBlock || removedStructureBlock) && getConfig().getBoolean("blocks.notify-admins-on-possession", true)) {
notifyAdmins(p.getName(), removedCommandBlock, removedStructureBlock);
}
}
}
/** Benachrichtigt Admins über entfernte Blöcke */
private void notifyAdmins(String playerName, boolean hadCommandBlock, boolean hadStructureBlock) {
String baseTag = ChatColor.GRAY + "[" + ChatColor.GREEN + "SurvivalPlus" + ChatColor.GRAY + "] ";
for (Player admin : Bukkit.getOnlinePlayers()) {
if (admin.hasPermission("survivalplus.notify")) {
if (hadCommandBlock) {
admin.sendMessage(baseTag + ChatColor.RED + "Spieler " + ChatColor.YELLOW + playerName +
ChatColor.RED + " hatte einen Command-Block im Inventar, der entfernt wurde.");
}
if (hadStructureBlock) {
admin.sendMessage(baseTag + ChatColor.RED + "Spieler " + ChatColor.YELLOW + playerName +
ChatColor.RED + " hatte einen Structure-Block im Inventar, der entfernt wurde.");
}
}
}
}
// Methoden für nicknames.yml
public void createNicknamesFile() {
nicknamesFile = new File(getDataFolder(), "nicknames.yml");
if (!nicknamesFile.exists()) {
try {
nicknamesFile.getParentFile().mkdirs();
nicknamesFile.createNewFile();
} catch (IOException e) {
getLogger().severe("Konnte nicknames.yml nicht erstellen!");
e.printStackTrace();
}
}
nicknamesConfig = YamlConfiguration.loadConfiguration(nicknamesFile);
}
public FileConfiguration getNicknamesConfig() {
return nicknamesConfig;
}
public void saveNicknamesConfig() {
try {
nicknamesConfig.save(nicknamesFile);
} catch (IOException e) {
getLogger().severe("Konnte nicknames.yml nicht speichern!");
e.printStackTrace();
}
}
private void spawnArmorStandExample() {
World world = Bukkit.getWorld("world");
if (world == null) {
getLogger().warning("Welt 'world' nicht gefunden, ArmorStand wird nicht gespawnt.");
return;
}
Location loc = new Location(world, 0.5, 100, 0.5);
ArmorStand armorStand = world.spawn(loc, ArmorStand.class);
armorStand.setVisible(false);
armorStand.setCustomName(ChatColor.GREEN + "Mein ArmorStand");
armorStand.setCustomNameVisible(true);
armorStand.setGravity(false);
armorStand.setMarker(true);
armorStand.addScoreboardTag("debugArmorStand");
}
@Override
public void onDisable() {
if (autoClearTaskId != -1) {
Bukkit.getScheduler().cancelTask(autoClearTaskId);
}
saveStats();
saveLeashesConfig();
saveMobCapConfig();
// NEU: NewbieProtection-Daten sichern
if (newbieListener != null) {
newbieListener.saveData();
}
getLogger().info(getMessage("plugin.disabled"));
}
public void saveStats() {
if (statsManager != null) {
statsManager.saveStats();
}
}
public String getPluginInfo() {
return ChatColor.translateAlternateColorCodes('&', getMessage("plugin.info"));
}
// === Config Updating Logic ===
private void updateConfigFiles() {
updateConfigFile("config.yml");
updateConfigFile("lang.yml");
updateConfigFile("help.yml");
}
private void updateConfigFile(String fileName) {
File file = new File(getDataFolder(), fileName);
FileConfiguration currentConfig = YamlConfiguration.loadConfiguration(file);
InputStream defaultStream = getResource(fileName);
if (defaultStream == null) {
getLogger().warning(fileName + " nicht im JAR gefunden. Erstelle leere Datei.");
if (!file.exists()) {
try {
file.createNewFile();
if (fileName.equals("config.yml")) {
saveDefaultConfig();
} else if (fileName.equals("lang.yml")) {
createLangFile();
} else if (fileName.equals("help.yml")) {
createHelpFile();
}
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der " + fileName + ": " + e.getMessage());
}
return;
}
}
FileConfiguration defaultConfig = defaultStream != null ?
YamlConfiguration.loadConfiguration(new InputStreamReader(defaultStream)) : new YamlConfiguration();
// Merge default config into current config
mergeConfigs(defaultConfig, currentConfig);
// Save updated config
try {
currentConfig.save(file);
getLogger().info(fileName + " erfolgreich aktualisiert.");
} catch (IOException e) {
getLogger().severe("Fehler beim Speichern der " + fileName + ": " + e.getMessage());
}
// Update instance variables
if (fileName.equals("config.yml")) {
reloadConfig();
} else if (fileName.equals("lang.yml")) {
langFile = file;
langConfig = currentConfig;
} else if (fileName.equals("help.yml")) {
helpFile = file;
helpConfig = currentConfig;
}
}
private void mergeConfigs(FileConfiguration defaultConfig, FileConfiguration currentConfig) {
for (String key : defaultConfig.getKeys(true)) {
if (!currentConfig.contains(key)) {
currentConfig.set(key, defaultConfig.get(key));
} else if (defaultConfig.isConfigurationSection(key) && currentConfig.isConfigurationSection(key)) {
// Rekursiv für Untersektionen
mergeConfigs(defaultConfig.getConfigurationSection(key), currentConfig.getConfigurationSection(key));
}
}
}
private void mergeConfigs(ConfigurationSection defaultSection, ConfigurationSection currentSection) {
for (String key : defaultSection.getKeys(false)) {
if (!currentSection.contains(key)) {
currentSection.set(key, defaultSection.get(key));
} else if (defaultSection.isConfigurationSection(key) && currentSection.isConfigurationSection(key)) {
mergeConfigs(defaultSection.getConfigurationSection(key), currentSection.getConfigurationSection(key));
}
}
}
// === Lang.yml ===
private void createLangFile() {
langFile = new File(getDataFolder(), "lang.yml");
if (!langFile.exists()) {
saveResource("lang.yml", false);
}
langConfig = YamlConfiguration.loadConfiguration(langFile);
}
public String getMessage(String key) {
String message = langConfig.getString(key);
if (message == null) {
getLogger().warning("Fehlender Sprachschlüssel: " + key);
return ChatColor.RED + "[Missing lang key: " + key + "]";
}
return ChatColor.translateAlternateColorCodes('&', message);
}
public void reloadLangConfig() {
updateConfigFile("lang.yml");
}
public FileConfiguration getLangConfig() {
return langConfig;
}
// === Homes.yml ===
private void createHomesFile() {
homesFile = new File(getDataFolder(), "homes.yml");
if (!homesFile.exists()) {
try {
homesFile.createNewFile();
getLogger().info("homes.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der homes.yml: " + e.getMessage());
}
}
homesConfig = YamlConfiguration.loadConfiguration(homesFile);
}
public FileConfiguration getHomesConfig() {
return homesConfig;
}
public void saveHomesConfig() {
try {
homesConfig.save(homesFile);
getLogger().info("homes.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der homes.yml: " + e.getMessage());
}
}
public void reloadHomesConfig() {
homesConfig = YamlConfiguration.loadConfiguration(homesFile);
getLogger().info("homes.yml erfolgreich neu geladen.");
}
// === Graves.yml ===
private void createGravesFile() {
gravesFile = new File(getDataFolder(), "graves.yml");
if (!gravesFile.exists()) {
try {
gravesFile.createNewFile();
getLogger().info("graves.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der graves.yml: " + e.getMessage());
}
}
gravesConfig = YamlConfiguration.loadConfiguration(gravesFile);
}
public FileConfiguration getGravesConfig() {
return gravesConfig;
}
public void saveGravesConfig() {
try {
gravesConfig.save(gravesFile);
getLogger().info("graves.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der graves.yml: " + e.getMessage());
}
}
public void reloadGravesConfig() {
gravesConfig = YamlConfiguration.loadConfiguration(gravesFile);
getLogger().info("graves.yml erfolgreich neu geladen.");
}
// === Help.yml ===
private void createHelpFile() {
helpFile = new File(getDataFolder(), "help.yml");
if (!helpFile.exists()) {
try {
InputStream resource = getResource("help.yml");
if (resource != null) {
saveResource("help.yml", false);
} else {
getLogger().warning("help.yml nicht im JAR gefunden. Erstelle leere Datei.");
helpConfig = new YamlConfiguration();
helpConfig.set("header", "§6=== SurvivalPlus Hilfe ===");
helpConfig.set("footer", "§6=====================");
helpConfig.save(helpFile);
}
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der help.yml: " + e.getMessage());
}
}
helpConfig = YamlConfiguration.loadConfiguration(helpFile);
}
public FileConfiguration getHelpConfig() {
return helpConfig;
}
public void reloadHelpConfig() {
updateConfigFile("help.yml");
}
// === Backpack.yml ===
private void createBackpackFile() {
backpackFile = new File(getDataFolder(), "backpacks.yml");
if (!backpackFile.exists()) {
try {
backpackFile.createNewFile();
getLogger().info("backpacks.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der backpacks.yml: " + e.getMessage());
}
}
backpackConfig = YamlConfiguration.loadConfiguration(backpackFile);
}
public FileConfiguration getBackpackConfig() {
return backpackConfig;
}
public void saveBackpackConfig() {
try {
backpackConfig.save(backpackFile);
getLogger().info("backpacks.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der backpacks.yml: " + e.getMessage());
}
}
public void reloadBackpackConfig() {
backpackConfig = YamlConfiguration.loadConfiguration(backpackFile);
getLogger().info("backpacks.yml erfolgreich neu geladen.");
}
// === Friends.yml ===
private void createFriendsFile() {
friendsFile = new File(getDataFolder(), "friends.yml");
if (!friendsFile.exists()) {
try {
friendsFile.createNewFile();
getLogger().info("friends.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der friends.yml: " + e.getMessage());
}
}
friendsConfig = YamlConfiguration.loadConfiguration(friendsFile);
}
public FileConfiguration getFriendsConfig() {
return friendsConfig;
}
public void saveFriendsConfig() {
try {
friendsConfig.save(friendsFile);
getLogger().info("friends.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der friends.yml: " + e.getMessage());
}
}
public void reloadFriendsConfig() {
friendsConfig = YamlConfiguration.loadConfiguration(friendsFile);
getLogger().info("friends.yml erfolgreich neu geladen.");
}
// === Leashes.yml ===
private void createLeashesFile() {
leashesFile = new File(getDataFolder(), "leashes.yml");
if (!leashesFile.exists()) {
try {
leashesFile.createNewFile();
getLogger().info("leashes.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der leashes.yml: " + e.getMessage());
}
}
leashesConfig = YamlConfiguration.loadConfiguration(leashesFile);
}
public FileConfiguration getLeashesConfig() {
return leashesConfig;
}
public void saveLeashesConfig() {
try {
leashesConfig.save(leashesFile);
getLogger().info("leashes.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der leashes.yml: " + e.getMessage());
}
}
public void reloadLeashesConfig() {
leashesConfig = YamlConfiguration.loadConfiguration(leashesFile);
getLogger().info("leashes.yml erfolgreich neu geladen.");
}
// === MobCap.yml ===
private void createMobCapFile() {
mobCapFile = new File(getDataFolder(), "mobcap.yml");
if (!mobCapFile.exists()) {
try {
mobCapFile.createNewFile();
getLogger().info("mobcap.yml wurde erstellt.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen der mobcap.yml: " + e.getMessage());
}
}
mobCapConfig = YamlConfiguration.loadConfiguration(mobCapFile);
}
public FileConfiguration getMobCapConfig() {
return mobCapConfig;
}
public void saveMobCapConfig() {
try {
mobCapConfig.save(mobCapFile);
getLogger().info("mobcap.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Fehler beim Speichern der mobcap.yml: " + e.getMessage());
}
}
public void reloadMobCapConfig() {
mobCapConfig = YamlConfiguration.loadConfiguration(mobCapFile);
getLogger().info("mobcap.yml erfolgreich neu geladen.");
}
// === AutoClearTask ===
private void startAutoClearTask() {
if (autoClearTaskId != -1) {
Bukkit.getScheduler().cancelTask(autoClearTaskId);
autoClearTaskId = -1;
}
if (getConfig().getBoolean("auto-clear-enabled", true)) {
int intervalMinutes = getConfig().getInt("auto-clear-interval-minutes", 15);
int intervalTicks = intervalMinutes * 60 * 20; // Minuten in Ticks umrechnen
if (intervalTicks > 0) {
autoClearTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new AutoClearTask(this), intervalTicks, intervalTicks);
getLogger().info("AutoClearTask gestartet mit Intervall von " + intervalMinutes + " Minuten.");
}
} else {
getLogger().info("AutoClearTask deaktiviert, da auto-clear-enabled auf false gesetzt ist.");
}
}
// === Reload Plugin ===
public void reloadPlugin() {
try {
// Config-Dateien aktualisieren
updateConfigFiles();
reloadBackpackConfig();
reloadFriendsConfig();
reloadHomesConfig();
reloadGravesConfig();
reloadLeashesConfig();
reloadMobCapConfig();
// AutoClearTask neu starten
startAutoClearTask();
// Bestehende Listener abmelden
PluginManager pm = getServer().getPluginManager();
HandlerList.unregisterAll(this);
// FriendCommand instanzieren für PlayerJoinListener
FriendCommand friendCommand = new FriendCommand(this, friendsConfig, langConfig, getLogger());
// Listener neu erstellen und registrieren
mobLeashLimitListener = new MobLeashLimitListener(this, getConfig());
mobLeashLimitListener.reloadConfig(getConfig());
pm.registerEvents(mobLeashLimitListener, this);
mobCapListener = new MobCapListener(this, getConfig());
mobCapListener.reloadConfig(getConfig());
pm.registerEvents(mobCapListener, this);
sleepListener = new SleepListener(this);
sleepListener.reloadConfig(getConfig());
pm.registerEvents(sleepListener, this);
oreAlarmListener = new OreAlarmListener(this);
oreAlarmListener.reloadConfig(getConfig());
pm.registerEvents(oreAlarmListener, this);
afkListener = new AFKListener(this);
afkListener.reloadConfig(getConfig());
pm.registerEvents(afkListener, this);
graveListener = new GraveListener(this);
graveListener.reloadConfig(getConfig());
pm.registerEvents(graveListener, this);
sitListener = new SitListener(this);
pm.registerEvents(sitListener, this);
playerJoinListener = new PlayerJoinListener(friendCommand);
pm.registerEvents(playerJoinListener, this);
pm.registerEvents(new InventoryClickListener(this), this);
pm.registerEvents(new BackpackListener(backpackConfig, langConfig, getLogger(), backpackFile), this);
pm.registerEvents(new StatsListener(this, statsManager), this);
pm.registerEvents(new LoginListener(this), this);
pm.registerEvents(new DebugArmorStandListener(), this);
pm.registerEvents(new ArmorStandDestroyListener(), this);
pm.registerEvents(new FirstJoinListener(), this);
spawnProtectionListener = new SpawnProtectionListener(this);
pm.registerEvents(spawnProtectionListener, this);
LockSystem lockSystem = new LockSystem(this);
pm.registerEvents(lockSystem, this);
getCommand("lock").setExecutor(lockSystem);
// Commands neu registrieren
getCommand("friend").setExecutor(friendCommand);
getLogger().info(getMessage("plugin.reloaded"));
} catch (Exception e) {
getLogger().severe("Fehler beim Neuladen des Plugins: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,24 @@
package de.viper.survivalplus.commands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
public class AnvilCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("Nur Spieler können diesen Befehl ausführen.");
return true;
}
Inventory anvil = Bukkit.createInventory(player, InventoryType.ANVIL, "Amboss");
player.openInventory(anvil);
return true;
}
}

View File

@@ -0,0 +1,67 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
public class BackCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public BackCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getLangConfig().getString("player-only", "§cDieser Befehl ist nur für Spieler!"));
return true;
}
Player player = (Player) sender;
FileConfiguration lang = plugin.getLangConfig();
FileConfiguration gravesConfig = plugin.getGravesConfig();
if (!player.hasPermission("survivalplus.back")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
if (args.length != 0) {
player.sendMessage(lang.getString("back.usage", "§cVerwendung: /back"));
return true;
}
// Lade Todesposition
String path = "graves." + player.getUniqueId();
if (!gravesConfig.contains(path)) {
player.sendMessage(lang.getString("back.no-death-point", "§cDu hast keinen Todespunkt!"));
return true;
}
String worldName = gravesConfig.getString(path + ".world");
double x = gravesConfig.getDouble(path + ".x");
double y = gravesConfig.getDouble(path + ".y");
double z = gravesConfig.getDouble(path + ".z");
World world = plugin.getServer().getWorld(worldName);
if (world == null) {
player.sendMessage(lang.getString("back.no-death-point", "§cDu hast keinen Todespunkt!"));
return true;
}
Location location = new Location(world, x, y, z);
player.teleport(location);
player.sendMessage(String.format(
lang.getString("back.success", "§aTeleportiert zum Todespunkt bei x=%.2f, y=%.2f, z=%.2f!"),
x, y, z
));
return true;
}
}

View File

@@ -0,0 +1,47 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.BlockManager;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
public class BlockCommand implements CommandExecutor {
private final BlockManager blockManager;
private final FileConfiguration config;
public BlockCommand(BlockManager blockManager, FileConfiguration config) {
this.blockManager = blockManager;
this.config = config;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(config.getString("messages.general.only_players"));
return true;
}
if (args.length != 1) {
player.sendMessage(config.getString("messages.block.usage"));
return true;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null || target == player) {
player.sendMessage(config.getString("messages.block.invalid_player"));
return true;
}
if (blockManager.hasBlocked(player, target)) {
player.sendMessage(config.getString("messages.block.already_blocked").replace("%player%", target.getName()));
} else {
blockManager.blockPlayer(player, target);
player.sendMessage(config.getString("messages.block.blocked").replace("%player%", target.getName()));
}
return true;
}
}

View File

@@ -0,0 +1,43 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.BlockManager;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.stream.Collectors;
public class BlockListCommand implements CommandExecutor {
private final BlockManager blockManager;
private final FileConfiguration config;
public BlockListCommand(BlockManager blockManager, FileConfiguration config) {
this.blockManager = blockManager;
this.config = config;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(config.getString("messages.general.only_players"));
return true;
}
var blocked = blockManager.getBlockedPlayers(player);
if (blocked.isEmpty()) {
player.sendMessage(config.getString("messages.blocklist.no_blocked_players"));
return true;
}
String list = blocked.stream()
.map(Bukkit::getOfflinePlayer)
.map(p -> p.getName() != null ? p.getName() : "Unbekannt")
.collect(Collectors.joining(", "));
player.sendMessage(config.getString("messages.blocklist.blocked_players").replace("%list%", list));
return true;
}
}

View File

@@ -0,0 +1,26 @@
package de.viper.survivalplus.commands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class ClearChatCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("survivalplus.clearchat")) {
sender.sendMessage("§cDu hast keine Rechte, den Chat zu löschen.");
return true;
}
// Chat für alle "leeren" (100 leere Zeilen senden)
for (int i = 0; i < 100; i++) {
Bukkit.broadcastMessage(" ");
}
Bukkit.broadcastMessage("§aDer Chat wurde von §e" + sender.getName() + " §agelöscht.");
return true;
}
}

View File

@@ -0,0 +1,43 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public class ClearDebugArmorStandsCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public ClearDebugArmorStandsCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Dieser Befehl kann nur von einem Spieler ausgeführt werden.");
return true;
}
Player player = (Player) sender;
int removedCount = 0;
for (Entity entity : player.getWorld().getEntities()) {
if (entity instanceof ArmorStand) {
ArmorStand armorStand = (ArmorStand) entity;
armorStand.setInvulnerable(false);
armorStand.setMarker(false);
armorStand.setGravity(true);
armorStand.remove();
removedCount++;
}
}
player.sendMessage("Es wurden " + removedCount + " ArmorStands entfernt.");
return true;
}
}

View File

@@ -0,0 +1,32 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Item;
public class ClearItemsCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public ClearItemsCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
int totalRemoved = 0;
for (World world : Bukkit.getWorlds()) {
for (Item item : world.getEntitiesByClass(Item.class)) {
item.remove();
totalRemoved++;
}
}
sender.sendMessage(ChatColor.RED + "Alle Items wurden entfernt (" + totalRemoved + " Stück).");
return true;
}
}

View File

@@ -0,0 +1,44 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.report.ReportManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class ClearReportCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final ReportManager reportManager;
public ClearReportCommand(SurvivalPlus plugin, ReportManager reportManager) {
this.plugin = plugin;
this.reportManager = reportManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(plugin.getLangConfig().getString("clearreport.only-players", "§cNur Spieler können diesen Befehl ausführen!"));
return true;
}
if (!player.hasPermission("survivalplus.report.clear")) {
player.sendMessage(plugin.getLangConfig().getString("no-permission", "§cDu hast keine Berechtigung!"));
return true;
}
if (args.length != 1) {
player.sendMessage(plugin.getLangConfig().getString("clearreport.usage", "§cVerwendung: /clearreport <Spieler>"));
return true;
}
String targetName = args[0];
reportManager.clearReports(targetName);
player.sendMessage(plugin.getLangConfig().getString("clearreport.cleared", "§aReports von %player% wurden gelöscht.").replace("%player%", targetName));
return true;
}
}

View File

@@ -0,0 +1,88 @@
package de.viper.survivalplus.commands;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.Openable;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import de.viper.survivalplus.SurvivalPlus;
public class CloseDoorsCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public CloseDoorsCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(plugin.getLangConfig().getString("commands.closedoors.noplayer", "Nur Spieler können diesen Befehl nutzen!"));
return true;
}
if (!player.hasPermission("survivalplus.closedoors")) {
player.sendMessage(plugin.getLangConfig().getString("commands.closedoors.nopermission", "Dafür hast du keine Rechte!"));
return true;
}
if (args.length != 1) {
player.sendMessage(plugin.getLangConfig().getString("commands.closedoors.usage", "Benutzung: /closedoors <radius>"));
return true;
}
int radius;
try {
radius = Integer.parseInt(args[0]);
if (radius <= 0) {
player.sendMessage(plugin.getLangConfig().getString("commands.closedoors.invalidradius", "Der Radius muss größer als 0 sein!"));
return true;
}
} catch (NumberFormatException e) {
player.sendMessage(plugin.getLangConfig().getString("commands.closedoors.invalidradius", "Der Radius muss eine Zahl sein!"));
return true;
}
int closedCount = 0;
var center = player.getLocation().getBlock();
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
for (int z = -radius; z <= radius; z++) {
Block block = center.getRelative(x, y, z);
Material type = block.getType();
if (type == Material.OAK_DOOR ||
type == Material.SPRUCE_DOOR ||
type == Material.BIRCH_DOOR ||
type == Material.JUNGLE_DOOR ||
type == Material.ACACIA_DOOR ||
type == Material.DARK_OAK_DOOR ||
type == Material.CRIMSON_DOOR ||
type == Material.WARPED_DOOR ||
type == Material.IRON_DOOR) {
var blockData = block.getBlockData();
if (blockData instanceof Openable openable) {
if (openable.isOpen()) {
openable.setOpen(false);
block.setBlockData(openable);
closedCount++;
}
}
}
}
}
}
player.sendMessage(plugin.getLangConfig()
.getString("commands.closedoors.success", "Es wurden %count% Türen geschlossen.")
.replace("%count%", String.valueOf(closedCount)));
return true;
}
}

View File

@@ -0,0 +1,33 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
public class DayCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public DayCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§cNur Spieler können diesen Befehl ausführen!");
return true;
}
if (!player.hasPermission("survivalplus.day")) {
player.sendMessage(plugin.getLangConfig().getString("no-permission", "§cDu hast keine Berechtigung!"));
return true;
}
player.getWorld().setTime(1000); // Tag setzen
player.sendMessage("§aEs ist jetzt Tag!");
return true;
}
}

View File

@@ -0,0 +1,45 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class DelWarpCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final WarpManager warpManager;
public DelWarpCommand(SurvivalPlus plugin, WarpManager warpManager) {
this.plugin = plugin;
this.warpManager = warpManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("warp.only_players"));
return true;
}
Player player = (Player) sender;
if (args.length < 1) {
player.sendMessage(ChatColor.RED + "Benutze: /delwarp <name>");
return true;
}
String warpName = args[0];
boolean removed = warpManager.removeWarp(player.getName(), warpName);
if (removed) {
player.sendMessage(ChatColor.GREEN + "Warp '" + warpName + "' wurde gelöscht.");
} else {
player.sendMessage(ChatColor.RED + "Du hast keinen Warp mit dem Namen '" + warpName + "'.");
}
return true;
}
}

View File

@@ -0,0 +1,123 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.util.UUID;
import java.util.logging.Level;
public class EnderchestCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public EnderchestCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getLangConfig().getString("player-only", "§cDieser Befehl ist nur für Spieler!"));
return true;
}
Player player = (Player) sender;
FileConfiguration lang = plugin.getLangConfig();
if (!player.hasPermission("survivalplus.enderchest.own")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
OfflinePlayer target;
String targetName;
if (args.length == 0) {
// Öffne die eigene Enderchest
target = player;
targetName = player.getName();
} else if (args.length == 1) {
// Öffne die Enderchest eines anderen Spielers
if (!player.hasPermission("survivalplus.enderchest.others")) {
player.sendMessage(lang.getString("no-permission-others-ec", "§cDu hast keine Berechtigung, die Enderchest anderer Spieler anzusehen!"));
return true;
}
targetName = args[0];
Player onlineTarget = Bukkit.getPlayerExact(targetName);
if (onlineTarget != null) {
target = onlineTarget;
} else {
target = Bukkit.getOfflinePlayer(targetName);
if (target.getName() == null || !target.hasPlayedBefore()) {
player.sendMessage(lang.getString("player-not-found", "§cSpieler nicht gefunden!"));
return true;
}
}
} else {
player.sendMessage(lang.getString("enderchest.usage", "§cVerwendung: /ec [spieler]"));
return true;
}
// Erstelle die GUI
Inventory gui = Bukkit.createInventory(null, 27, lang.getString("enderchest.gui-title", "Enderchest von ") + targetName);
// Lade die Enderchest
if (target.isOnline()) {
Player onlineTarget = target.getPlayer();
Inventory enderChest = onlineTarget.getEnderChest();
for (int i = 0; i < 27; i++) {
gui.setItem(i, enderChest.getItem(i));
}
plugin.getLogger().log(Level.INFO, "Enderchest für " + targetName + " (online) erfolgreich geladen");
} else {
UUID uuid = target.getUniqueId();
try {
// Lade Offline-Spieler-Enderchest aus playerdata
File dataFolder = new File(plugin.getServer().getWorlds().get(0).getWorldFolder(), "playerdata");
File playerFile = new File(dataFolder, uuid.toString() + ".dat");
if (!playerFile.exists()) {
player.sendMessage(lang.getString("enderchest.data-not-found", "§cDie Enderchest-Daten des Spielers konnten nicht gefunden werden! Der Spieler war möglicherweise nie auf diesem Server."));
return true;
}
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
plugin.getLogger().log(Level.INFO, "Versuche, Enderchest für " + targetName + " zu laden (UUID: " + uuid + ", Version: " + version + ")");
// Verwende Reflection, um die Enderchest-Daten zu laden
Class<?> nbtIoClass = Class.forName("net.minecraft.nbt.NbtIo");
Class<?> nbtCompoundClass = Class.forName("net.minecraft.nbt.NbtCompound");
Class<?> nbtListClass = Class.forName("net.minecraft.nbt.NbtList");
Class<?> craftInventoryClass = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftInventory");
Object nbtCompound = nbtIoClass.getMethod("readCompressed", java.nio.file.Path.class).invoke(null, playerFile.toPath());
Object enderItemsList = nbtCompoundClass.getMethod("getList", String.class, int.class).invoke(nbtCompound, "EnderItems", 10);
Object craftInventory = craftInventoryClass.getConstructor(nbtListClass).newInstance(enderItemsList);
ItemStack[] items = (ItemStack[]) craftInventoryClass.getMethod("getContents").invoke(craftInventory);
for (int i = 0; i < Math.min(items.length, 27); i++) {
gui.setItem(i, items[i]);
}
plugin.getLogger().log(Level.INFO, "Enderchest für " + targetName + " erfolgreich geladen");
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Fehler beim Laden der Enderchest für " + targetName + " (UUID: " + uuid + ")", e);
String errorMessage = e.getMessage() != null ? e.getMessage() : e.toString();
player.sendMessage(lang.getString("enderchest.load-error", "§cFehler beim Laden der Enderchest: %error%")
.replace("%error%", errorMessage));
return true;
}
}
player.openInventory(gui);
player.sendMessage(lang.getString("enderchest.opened", "§aEnderchest von %player% geöffnet!")
.replace("%player%", targetName));
return true;
}
}

View File

@@ -0,0 +1,423 @@
package de.viper.survivalplus.commands;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
public class FriendCommand implements CommandExecutor {
private final JavaPlugin plugin;
private final FileConfiguration friendsConfig;
private final FileConfiguration langConfig;
private final Logger logger;
public FriendCommand(JavaPlugin plugin, FileConfiguration friendsConfig, FileConfiguration langConfig, Logger logger) {
this.plugin = plugin;
this.friendsConfig = friendsConfig;
this.langConfig = langConfig;
this.logger = logger;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-only", "&cDieser Befehl ist nur für Spieler!")));
return true;
}
Player player = (Player) sender;
UUID playerUUID = player.getUniqueId();
if (args.length == 0) {
sendHelpMessage(player);
return true;
}
String subCommand = args[0].toLowerCase();
switch (subCommand) {
case "add":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.add-usage", "&cVerwendung: /friend add <Spielername>")));
return true;
}
handleFriendAdd(player, args[1]);
break;
case "accept":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.accept-usage", "&cVerwendung: /friend accept <Spielername>")));
return true;
}
handleFriendAccept(player, args[1]);
break;
case "deny":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.deny-usage", "&cVerwendung: /friend deny <Spielername>")));
return true;
}
handleFriendDeny(player, args[1]);
break;
case "list":
if (args.length != 1) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.list-usage", "&cVerwendung: /friend list")));
return true;
}
handleFriendList(player);
break;
case "del":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.del-usage", "&cVerwendung: /friend del <Spielername>")));
return true;
}
handleFriendDelete(player, args[1]);
break;
case "confirm":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.confirm-usage", "&cVerwendung: /friend confirm <Spielername>")));
return true;
}
handleFriendConfirmDelete(player, args[1]);
break;
case "tp":
if (args.length != 2) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.tp-usage", "&cVerwendung: /friend tp <Spielername>")));
return true;
}
handleFriendTeleport(player, args[1]);
break;
default:
sendHelpMessage(player);
break;
}
return true;
}
private void sendHelpMessage(Player player) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.header", "&6=== Freundesliste Hilfe ===")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.add", "&e/friend add <Spielername> &7- Freundschaftsanfrage senden")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.accept", "&e/friend accept <Spielername> &7- Freundschaftsanfrage akzeptieren")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.deny", "&e/friend deny <Spielername> &7- Freundschaftsanfrage ablehnen")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.list", "&e/friend list &7- Liste deiner Freunde anzeigen")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.del", "&e/friend del <Spielername> &7- Freund aus der Liste entfernen")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.tp", "&e/friend tp <Spielername> &7- Zu einem Freund teleportieren")));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.footer", "&6=====================")));
}
private void handleFriendAdd(Player player, String targetName) {
Player target = Bukkit.getPlayerExact(targetName);
if (target == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", targetName)));
return;
}
if (target.getUniqueId().equals(player.getUniqueId())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.self", "&cDu kannst dich nicht selbst hinzufügen!")));
return;
}
UUID playerUUID = player.getUniqueId();
UUID targetUUID = target.getUniqueId();
List<String> playerFriends = friendsConfig.getStringList(playerUUID + ".friends");
List<String> pendingRequests = friendsConfig.getStringList(targetUUID + ".pending_requests");
if (playerFriends.contains(targetUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.already-friends", "&cDu bist bereits mit %s befreundet!").replace("%s", targetName)));
return;
}
if (pendingRequests.contains(playerUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.request-pending", "&cDu hast bereits eine Anfrage an %s gesendet!").replace("%s", targetName)));
return;
}
pendingRequests.add(playerUUID.toString());
friendsConfig.set(targetUUID + ".pending_requests", pendingRequests);
friendsConfig.set(targetUUID + ".name", targetName);
saveFriendsConfig();
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.sent", "&aFreundschaftsanfrage an %s gesendet!").replace("%s", targetName)));
TextComponent message = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.received", "&aDu hast eine Freundschaftsanfrage von %s erhalten! ").replace("%s", player.getName())));
TextComponent accept = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.accept-button", "&a[Accept]")));
accept.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend accept " + player.getName()));
TextComponent deny = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.deny-button", "&c [Deny]")));
deny.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend deny " + player.getName()));
message.addExtra(accept);
message.addExtra(deny);
target.spigot().sendMessage(message);
logger.info("Freundschaftsanfrage von " + player.getName() + " an " + targetName + " gesendet.");
}
private void handleFriendAccept(Player player, String requesterName) {
Player requester = Bukkit.getPlayerExact(requesterName);
if (requester == null) {
UUID requesterUUID = getUUIDFromName(requesterName);
if (requesterUUID == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", requesterName)));
return;
}
acceptFriendRequest(player, requesterUUID, requesterName);
} else {
acceptFriendRequest(player, requester.getUniqueId(), requesterName);
}
}
private void acceptFriendRequest(Player player, UUID requesterUUID, String requesterName) {
UUID playerUUID = player.getUniqueId();
List<String> pendingRequests = friendsConfig.getStringList(playerUUID + ".pending_requests");
if (!pendingRequests.contains(requesterUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.no-request", "&cKeine Anfrage von %s gefunden!").replace("%s", requesterName)));
return;
}
pendingRequests.remove(requesterUUID.toString());
friendsConfig.set(playerUUID + ".pending_requests", pendingRequests);
List<String> playerFriends = friendsConfig.getStringList(playerUUID + ".friends");
List<String> requesterFriends = friendsConfig.getStringList(requesterUUID + ".friends");
playerFriends.add(requesterUUID.toString());
requesterFriends.add(playerUUID.toString());
friendsConfig.set(playerUUID + ".friends", playerFriends);
friendsConfig.set(playerUUID + ".name", player.getName());
friendsConfig.set(requesterUUID + ".friends", requesterFriends);
friendsConfig.set(requesterUUID + ".name", requesterName);
saveFriendsConfig();
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.accept.success", "&aDu bist jetzt mit %s befreundet!").replace("%s", requesterName)));
Player requester = Bukkit.getPlayer(requesterUUID);
if (requester != null) {
requester.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.accept.notify", "&a%s hat deine Freundschaftsanfrage akzeptiert!").replace("%s", player.getName())));
}
logger.info(player.getName() + " hat die Freundschaftsanfrage von " + requesterName + " akzeptiert.");
}
private void handleFriendDeny(Player player, String requesterName) {
UUID requesterUUID = getUUIDFromName(requesterName);
if (requesterUUID == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", requesterName)));
return;
}
UUID playerUUID = player.getUniqueId();
List<String> pendingRequests = friendsConfig.getStringList(playerUUID + ".pending_requests");
if (!pendingRequests.contains(requesterUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.no-request", "&cKeine Anfrage von %s gefunden!").replace("%s", requesterName)));
return;
}
pendingRequests.remove(requesterUUID.toString());
friendsConfig.set(playerUUID + ".pending_requests", pendingRequests);
saveFriendsConfig();
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.deny.success", "&aFreundschaftsanfrage von %s abgelehnt.").replace("%s", requesterName)));
Player requester = Bukkit.getPlayer(requesterUUID);
if (requester != null) {
requester.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.deny.notify", "&c%s hat deine Freundschaftsanfrage abgelehnt.").replace("%s", player.getName())));
}
logger.info(player.getName() + " hat die Freundschaftsanfrage von " + requesterName + " abgelehnt.");
}
private void handleFriendList(Player player) {
UUID playerUUID = player.getUniqueId();
List<String> friendUUIDs = friendsConfig.getStringList(playerUUID + ".friends");
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.header", "&6=== Deine Freundesliste ===")));
if (friendUUIDs.isEmpty()) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.empty", "&7Du hast keine Freunde.")));
} else {
SimpleDateFormat dateFormat = new SimpleDateFormat(langConfig.getString("friend.list.date-format", "dd.MM.yyyy HH:mm:ss"));
for (String friendUUID : friendUUIDs) {
String friendName = getNameFromUUID(UUID.fromString(friendUUID));
Player friend = Bukkit.getPlayer(UUID.fromString(friendUUID));
TextComponent entry = new TextComponent();
if (friend != null) {
entry.addExtra(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.entry", "&e%s: %s").replaceFirst("%s", friendName).replaceFirst("%s", langConfig.getString("friend.list.online", "&aOnline"))));
} else {
long lastOnline = friendsConfig.getLong(friendUUID + ".last-online", 0);
String lastOnlineStr = lastOnline > 0 ? dateFormat.format(new Date(lastOnline)) : langConfig.getString("friend.list.unknown", "&7Unbekannt");
entry.addExtra(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.entry-offline", "&e%s: %s &7(Zuletzt online: %s)").replaceFirst("%s", friendName).replaceFirst("%s", langConfig.getString("friend.list.offline", "&7Offline")).replace("%s", lastOnlineStr)));
}
TextComponent removeButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.remove-button", "&c[X]")));
removeButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend del " + friendName));
entry.addExtra(" ");
entry.addExtra(removeButton);
player.spigot().sendMessage(entry);
}
}
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.footer", "&6=====================")));
logger.info("Freundesliste für " + player.getName() + " angezeigt.");
}
private void handleFriendDelete(Player player, String friendName) {
UUID friendUUID = getUUIDFromName(friendName);
if (friendUUID == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", friendName)));
return;
}
UUID playerUUID = player.getUniqueId();
List<String> playerFriends = friendsConfig.getStringList(playerUUID + ".friends");
if (!playerFriends.contains(friendUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.not-friends", "&c%s ist nicht in deiner Freundesliste!").replace("%s", friendName)));
return;
}
TextComponent confirmMessage = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm", "&cMöchtest du %s wirklich aus deiner Freundesliste entfernen? ").replace("%s", friendName)));
TextComponent confirmButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm-button", "&a[Confirm]")));
confirmButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend confirm " + friendName));
TextComponent cancelButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.cancel-button", "&c[Cancel]")));
cancelButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend list"));
confirmMessage.addExtra(confirmButton);
confirmMessage.addExtra(" ");
confirmMessage.addExtra(cancelButton);
player.spigot().sendMessage(confirmMessage);
logger.info(player.getName() + " wurde zur Bestätigung aufgefordert, " + friendName + " aus der Freundesliste zu entfernen.");
}
private void handleFriendConfirmDelete(Player player, String friendName) {
UUID friendUUID = getUUIDFromName(friendName);
if (friendUUID == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", friendName)));
return;
}
UUID playerUUID = player.getUniqueId();
List<String> playerFriends = friendsConfig.getStringList(playerUUID + ".friends");
List<String> friendFriends = friendsConfig.getStringList(friendUUID + ".friends");
if (!playerFriends.contains(friendUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.not-friends", "&c%s ist nicht in deiner Freundesliste!").replace("%s", friendName)));
return;
}
playerFriends.remove(friendUUID.toString());
friendFriends.remove(playerUUID.toString());
friendsConfig.set(playerUUID + ".friends", playerFriends);
friendsConfig.set(friendUUID + ".friends", friendFriends);
saveFriendsConfig();
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.success", "&a%s wurde aus deiner Freundesliste entfernt.").replace("%s", friendName)));
Player friend = Bukkit.getPlayer(friendUUID);
if (friend != null) {
friend.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.notify", "&c%s hat dich aus seiner Freundesliste entfernt.").replace("%s", player.getName())));
}
logger.info(player.getName() + " hat " + friendName + " aus der Freundesliste entfernt.");
}
private void handleFriendTeleport(Player player, String friendName) {
Player friend = Bukkit.getPlayerExact(friendName);
if (friend == null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.player-not-found", "&cSpieler %s nicht gefunden!").replace("%s", friendName)));
return;
}
UUID playerUUID = player.getUniqueId();
UUID friendUUID = friend.getUniqueId();
List<String> playerFriends = friendsConfig.getStringList(playerUUID + ".friends");
if (!playerFriends.contains(friendUUID.toString())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.not-friends", "&c%s ist nicht in deiner Freundesliste!").replace("%s", friendName)));
return;
}
if (!player.getWorld().equals(friend.getWorld())) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.error.different-world", "&cIhr müsst in derselben Welt sein, um zu teleportieren!")));
return;
}
player.teleport(friend.getLocation());
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.tp.success", "&aDu wurdest zu %s teleportiert!").replace("%s", friendName)));
friend.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.tp.notify", "&a%s hat sich zu dir teleportiert.").replace("%s", player.getName())));
logger.info(player.getName() + " hat sich zu " + friendName + " teleportiert.");
}
private UUID getUUIDFromName(String name) {
Player target = Bukkit.getPlayerExact(name);
if (target != null) {
return target.getUniqueId();
}
for (String key : friendsConfig.getKeys(false)) {
try {
UUID uuid = UUID.fromString(key);
String storedName = friendsConfig.getString(key + ".name");
if (storedName != null && storedName.equalsIgnoreCase(name)) {
return uuid;
}
} catch (IllegalArgumentException ignored) {
}
}
return null;
}
private String getNameFromUUID(UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
return player.getName();
}
String storedName = friendsConfig.getString(uuid + ".name");
if (storedName != null) {
return storedName;
}
return uuid.toString();
}
private void saveFriendsConfig() {
try {
friendsConfig.save(new File(plugin.getDataFolder(), "friends.yml"));
logger.fine("friends.yml erfolgreich gespeichert.");
} catch (IOException e) {
logger.severe("Fehler beim Speichern der friends.yml: " + e.getMessage());
e.printStackTrace();
}
}
public void notifyFriendsOfJoin(Player player) {
UUID playerUUID = player.getUniqueId();
for (String friendUUIDStr : friendsConfig.getStringList(playerUUID + ".friends")) {
Player friend = Bukkit.getPlayer(UUID.fromString(friendUUIDStr));
if (friend != null) {
friend.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.join.notify", "&aDein Freund %s ist dem Server beigetreten.").replace("%s", player.getName())));
}
}
}
public void updateLastOnline(Player player) {
UUID playerUUID = player.getUniqueId();
friendsConfig.set(playerUUID + ".last-online", System.currentTimeMillis());
saveFriendsConfig();
}
}

View File

@@ -0,0 +1,83 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.GameMode;
import org.bukkit.configuration.file.FileConfiguration;
public class GamemodeCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public GamemodeCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
FileConfiguration lang = plugin.getLangConfig();
if (!sender.hasPermission("survivalplus.gamemode")) {
sender.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
if (args.length == 0) {
sender.sendMessage(lang.getString("gamemode.usage", "§cVerwendung: /gm <0|1|2|3> [spieler]"));
return true;
}
Player target = (args.length > 1) ? plugin.getServer().getPlayer(args[1]) : (sender instanceof Player ? (Player) sender : null);
if (args.length > 1 && !sender.hasPermission("survivalplus.gamemode.others")) {
sender.sendMessage(lang.getString("no-permission-others", "§cDu hast keine Berechtigung, den Spielmodus anderer zu ändern!"));
return true;
}
if (target == null) {
sender.sendMessage(lang.getString("player-not-found", "§cSpieler nicht gefunden!"));
return true;
}
GameMode gameMode;
String modeName;
switch (args[0].toLowerCase()) {
case "0":
case "survival":
gameMode = GameMode.SURVIVAL;
modeName = lang.getString("gamemode.survival", "Überleben");
break;
case "1":
case "creative":
gameMode = GameMode.CREATIVE;
modeName = lang.getString("gamemode.creative", "Kreativ");
break;
case "2":
case "adventure":
gameMode = GameMode.ADVENTURE;
modeName = lang.getString("gamemode.adventure", "Abenteuer");
break;
case "3":
case "spectator":
gameMode = GameMode.SPECTATOR;
modeName = lang.getString("gamemode.spectator", "Zuschauer");
break;
default:
sender.sendMessage(lang.getString("invalid-gamemode", "§cUngültiger Spielmodus! Verwende 0, 1, 2 oder 3"));
return true;
}
target.setGameMode(gameMode);
String message = sender == target ?
lang.getString("gamemode.changed-self", "§aDein Spielmodus wurde zu %mode% geändert!")
.replace("%mode%", modeName) :
lang.getString("gamemode.changed-other", "§aSpielmodus von %player% zu %mode% geändert!")
.replace("%player%", target.getName())
.replace("%mode%", modeName);
sender.sendMessage(message);
return true;
}
}

View File

@@ -0,0 +1,62 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class HealCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public HealCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§cDieser Befehl kann nur von Spielern verwendet werden!");
return true;
}
// /heal ohne Argument → eigener Spieler
if (args.length == 0) {
if (!player.hasPermission("survivalplus.heal")) {
player.sendMessage("§cDu hast keine Berechtigung, dich zu heilen!");
return true;
}
player.setHealth(player.getMaxHealth());
player.setFoodLevel(20);
player.sendMessage("§aDu wurdest vollständig geheilt!");
return true;
}
// /heal <Spieler> → anderen Spieler heilen
if (args.length == 1) {
if (!player.hasPermission("survivalplus.heal.others")) {
player.sendMessage("§cDu hast keine Berechtigung, andere Spieler zu heilen!");
return true;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null || !target.isOnline()) {
player.sendMessage("§cDieser Spieler ist nicht online!");
return true;
}
target.setHealth(target.getMaxHealth());
target.setFoodLevel(20);
target.sendMessage("§aDu wurdest von §e" + player.getName() + " §ageheilt!");
player.sendMessage("§aDu hast §e" + target.getName() + " §ageheilt!");
return true;
}
// Falsche Benutzung
player.sendMessage("§eBenutzung: /heal [Spieler]");
return true;
}
}

View File

@@ -0,0 +1,146 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.ArrayList;
import java.util.List;
public class HomeCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public HomeCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getLangConfig().getString("player-only", "§cDieser Befehl ist nur für Spieler!"));
return true;
}
Player player = (Player) sender;
FileConfiguration lang = plugin.getLangConfig();
FileConfiguration homes = plugin.getHomesConfig();
String commandName = command.getName().toLowerCase();
if (commandName.equals("sethome")) {
if (!player.hasPermission("survivalplus.homes.set")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
if (args.length != 1) {
player.sendMessage(lang.getString("sethome.usage", "§cVerwendung: /sethome <name>"));
return true;
}
String homeName = args[0].toLowerCase();
if (!homeName.matches("[a-z0-9_]+")) {
player.sendMessage(lang.getString("sethome.invalid-name", "§cDer Home-Name darf nur Buchstaben, Zahlen und Unterstriche enthalten!"));
return true;
}
String path = "homes." + player.getUniqueId() + "." + homeName;
if (homes.contains(path)) {
player.sendMessage(lang.getString("sethome.already-exists", "§cEin Home mit diesem Namen existiert bereits!"));
return true;
}
int maxHomes = player.hasPermission("survivalplus.homes.unlimited") ? Integer.MAX_VALUE : plugin.getConfig().getInt("max-homes", 3);
int currentHomes = homes.getConfigurationSection("homes." + player.getUniqueId()) != null ?
homes.getConfigurationSection("homes." + player.getUniqueId()).getKeys(false).size() : 0;
if (currentHomes >= maxHomes) {
player.sendMessage(lang.getString("sethome.limit-reached", "§cDu hast die maximale Anzahl an Homes erreicht!"));
return true;
}
Location loc = player.getLocation();
homes.set(path + ".world", loc.getWorld().getName());
homes.set(path + ".x", loc.getX());
homes.set(path + ".y", loc.getY());
homes.set(path + ".z", loc.getZ());
homes.set(path + ".yaw", loc.getYaw());
homes.set(path + ".pitch", loc.getPitch());
plugin.saveHomesConfig();
player.sendMessage(lang.getString("sethome.success", "§aHome %name% wurde gesetzt!")
.replace("%name%", homeName));
return true;
}
if (commandName.equals("delhome")) {
if (!player.hasPermission("survivalplus.homes.delete")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
if (args.length != 1) {
player.sendMessage(lang.getString("delhome.usage", "§cVerwendung: /delhome <name>"));
return true;
}
String homeName = args[0].toLowerCase();
String path = "homes." + player.getUniqueId() + "." + homeName;
if (!homes.contains(path)) {
player.sendMessage(lang.getString("delhome.not-found", "§cDieses Home existiert nicht!"));
return true;
}
homes.set(path, null);
plugin.saveHomesConfig();
player.sendMessage(lang.getString("delhome.success", "§aHome %name% wurde gelöscht!")
.replace("%name%", homeName));
return true;
}
if (commandName.equals("homelist")) {
if (!player.hasPermission("survivalplus.homes.list")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
String path = "homes." + player.getUniqueId();
if (!homes.contains(path) || homes.getConfigurationSection(path).getKeys(false).isEmpty()) {
player.sendMessage(lang.getString("homelist.no-homes", "§cDu hast keine Homes gesetzt!"));
return true;
}
Inventory gui = Bukkit.createInventory(null, 27, lang.getString("homelist.gui-title", "Deine Homes"));
List<String> homeNames = new ArrayList<>(homes.getConfigurationSection(path).getKeys(false));
for (int i = 0; i < Math.min(homeNames.size(), 27); i++) {
String homeName = homeNames.get(i);
String homePath = path + "." + homeName;
ItemStack item = new ItemStack(Material.RED_BED);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName("§a" + homeName);
List<String> lore = new ArrayList<>();
lore.add("§7Welt: " + homes.getString(homePath + ".world"));
lore.add("§7X: " + String.format("%.2f", homes.getDouble(homePath + ".x")));
lore.add("§7Y: " + String.format("%.2f", homes.getDouble(homePath + ".y")));
lore.add("§7Z: " + String.format("%.2f", homes.getDouble(homePath + ".z")));
meta.setLore(lore);
item.setItemMeta(meta);
gui.setItem(i, item);
}
player.openInventory(gui);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,140 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.UUID;
import java.util.logging.Level;
public class InventoryCommand implements CommandExecutor, Listener {
private final SurvivalPlus plugin;
public InventoryCommand(SurvivalPlus plugin) {
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
}
public static class SnapshotHolder implements InventoryHolder {
private final UUID targetUuid;
private final boolean readOnly;
public SnapshotHolder(UUID targetUuid, boolean readOnly) {
this.targetUuid = targetUuid;
this.readOnly = readOnly;
}
public UUID getTargetUuid() {
return targetUuid;
}
public boolean isReadOnly() {
return readOnly;
}
@Override
public Inventory getInventory() {
return null;
}
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
FileConfiguration lang = plugin.getLangConfig();
if (!(sender instanceof Player)) {
sender.sendMessage(lang.getString("player-only"));
return true;
}
Player player = (Player) sender;
if (!player.hasPermission("survivalplus.inventory.own")) {
player.sendMessage(lang.getString("no-permission"));
return true;
}
if (args.length != 1) {
player.sendMessage(lang.getString("inventory.usage"));
return true;
}
String targetName = args[0];
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
Player onlineTarget = Bukkit.getPlayerExact(targetName);
if (onlineTarget != null && onlineTarget.isOnline()) {
if (!player.getName().equalsIgnoreCase(targetName) && !player.hasPermission("survivalplus.inventory.others")) {
player.sendMessage(lang.getString("no-permission-others-inv"));
return true;
}
PlayerInventory targetInv = onlineTarget.getInventory();
player.openInventory(targetInv);
player.sendMessage(lang.getString("inventory.opened").replace("%player%", targetName));
plugin.getLogger().log(Level.INFO, "Inventar von " + targetName + " (online) wurde von " + player.getName() + " geöffnet.");
return true;
}
if (target.getName() == null || !target.hasPlayedBefore()) {
player.sendMessage(lang.getString("player-not-found"));
return true;
}
if (!player.getName().equalsIgnoreCase(targetName) && !player.hasPermission("survivalplus.inventory.others")) {
player.sendMessage(lang.getString("no-permission-others-inv"));
return true;
}
// Offline-Inventare nicht editierbar
player.sendMessage(lang.getString("inventory.offline-not-editable"));
plugin.getLogger().log(Level.INFO, "Inventar von " + targetName + " ist offline — Live-Bearbeitung nicht möglich.");
return true;
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof SnapshotHolder) {
SnapshotHolder sh = (SnapshotHolder) holder;
if (sh.isReadOnly()) {
if (event.getWhoClicked() instanceof Player) {
Player p = (Player) event.getWhoClicked();
FileConfiguration lang = plugin.getLangConfig();
p.sendMessage(lang.getString("inventory.read-only"));
}
event.setCancelled(true);
}
}
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof SnapshotHolder) {
SnapshotHolder sh = (SnapshotHolder) holder;
if (sh.isReadOnly()) {
if (event.getWhoClicked() instanceof Player) {
Player p = (Player) event.getWhoClicked();
FileConfiguration lang = plugin.getLangConfig();
p.sendMessage(lang.getString("inventory.read-only"));
}
event.setCancelled(true);
}
}
}
}

View File

@@ -0,0 +1,63 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class ItemRenameCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public ItemRenameCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(ChatColor.RED + plugin.getMessage("ir.only-player"));
return true;
}
if (!player.hasPermission("survivalplus.itemrename")) {
player.sendMessage(ChatColor.RED + plugin.getMessage("ir.no-permission"));
return true;
}
if (args.length == 0) {
player.sendMessage(ChatColor.RED + plugin.getMessage("ir.no-name"));
player.sendMessage(ChatColor.YELLOW + plugin.getMessage("ir.usage"));
return true;
}
ItemStack item = player.getInventory().getItemInMainHand();
if (item == null || item.getType().isAir()) {
player.sendMessage(ChatColor.RED + plugin.getMessage("ir.no-item"));
return true;
}
StringBuilder newNameBuilder = new StringBuilder();
for (String arg : args) {
newNameBuilder.append(arg).append(" ");
}
String newName = newNameBuilder.toString().trim();
newName = ChatColor.translateAlternateColorCodes('&', newName);
ItemMeta meta = item.getItemMeta();
if (meta == null) {
player.sendMessage(ChatColor.RED + plugin.getMessage("ir.cant-rename"));
return true;
}
meta.setDisplayName(newName);
item.setItemMeta(meta);
player.sendMessage(ChatColor.GREEN + plugin.getMessage("ir.success").replace("{name}", newName));
return true;
}
}

View File

@@ -0,0 +1,65 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
public class KitCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public KitCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
// Hole die Konfiguration
FileConfiguration config = plugin.getConfig();
// Hole die Items aus der Konfiguration
List<String> items = config.getStringList("first-join-kit.items");
for (String itemString : items) {
// Teile den Item-String auf
String[] itemParts = itemString.split(",");
String materialName = itemParts[0].toUpperCase();
int amount = Integer.parseInt(itemParts[1]);
String displayName = itemParts.length > 2 ? itemParts[2] : "";
// Erstelle das Item
Material material = Material.getMaterial(materialName);
if (material == null) {
player.sendMessage("Unbekanntes Item: " + materialName);
continue; // Falls das Item ungültig ist, überspringe es
}
ItemStack item = new ItemStack(material, amount);
ItemMeta meta = item.getItemMeta();
// Setze den Display-Namen (falls vorhanden)
if (meta != null && !displayName.isEmpty()) {
meta.setDisplayName(displayName);
}
item.setItemMeta(meta);
player.getInventory().addItem(item); // Gib das Item an den Spieler
}
player.sendMessage("Du hast dein Kit erhalten!");
return true;
}
return false;
}
}

View File

@@ -0,0 +1,30 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.listeners.MobLeashLimitListener;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class LeashCountCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final MobLeashLimitListener listener;
public LeashCountCommand(SurvivalPlus plugin, MobLeashLimitListener listener) {
this.plugin = plugin;
this.listener = listener;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("player-only"));
return true;
}
Player player = (Player) sender;
int count = listener.getLeashCount(player);
player.sendMessage(plugin.getMessage("leashcount.message").replace("%count%", String.valueOf(count)));
return true;
}
}

View File

@@ -0,0 +1,90 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NickCommand implements CommandExecutor {
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
private final SurvivalPlus plugin;
public NickCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§cDieser Befehl ist nur für Spieler!");
return true;
}
if (!player.hasPermission("survivalplus.nick")) {
player.sendMessage("§cDu hast keine Berechtigung für diesen Befehl!");
return true;
}
if (args.length == 0) {
player.sendMessage("§eBenutzung: /nick <Name>");
return true;
}
// Name zusammensetzen
StringBuilder sb = new StringBuilder();
for (String arg : args) {
sb.append(arg).append(" ");
}
String rawNick = sb.toString().trim();
// Verbotene Nicks prüfen
List<String> forbidden = plugin.getConfig().getStringList("forbidden-nicks");
for (String word : forbidden) {
if (rawNick.toLowerCase().contains(word.toLowerCase())) {
player.sendMessage("§cDieser Nickname ist nicht erlaubt!");
return true;
}
}
// Farben anwenden
String coloredNick = translateColors(rawNick);
// Format: [Nickname] (Klammern weiß, Nickname farbig)
String finalNick = "§f[" + coloredNick + "§f]";
// Anwenden
player.setDisplayName(finalNick);
player.setPlayerListName(finalNick);
// Speichern (ungefärbten Namen)
plugin.getNicknamesConfig().set(player.getUniqueId().toString(), rawNick);
plugin.saveNicknamesConfig();
player.sendMessage("§aDein Nickname wurde zu " + finalNick + " geändert.");
return true;
}
private String translateColors(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();
}
}

View File

@@ -0,0 +1,32 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NightCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public NightCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("§cNur Spieler können diesen Befehl ausführen!");
return true;
}
if (!player.hasPermission("survivalplus.night")) {
player.sendMessage(plugin.getLangConfig().getString("no-permission", "§cDu hast keine Berechtigung!"));
return true;
}
player.getWorld().setTime(13000); // Nacht setzen
player.sendMessage("§aEs ist jetzt Nacht!");
return true;
}
}

View File

@@ -0,0 +1,248 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class PluginCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private static final int COMMANDS_PER_PAGE = 5;
public PluginCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
FileConfiguration lang = plugin.getLangConfig();
// /sp oder /sp help
if (args.length == 0 || args[0].equalsIgnoreCase("help")) {
int page = 1;
if (args.length > 1 && args[0].equalsIgnoreCase("help")) {
try {
page = Integer.parseInt(args[1]);
if (page < 1) page = 1;
} catch (NumberFormatException e) {
sender.sendMessage(color(lang.getString(
"sp.invalid-subcommand",
"§cUngültiger Unterbefehl! Verwendung: /sp [reload|help|info|share]"
)));
return true;
}
}
showHelp(sender, page);
return true;
}
// /sp reload
if (args[0].equalsIgnoreCase("reload")) {
if (!sender.hasPermission("survivalplus.reload")) {
sender.sendMessage(color(lang.getString("sp.no-permission", "§cDu hast keine Berechtigung für diesen Befehl!")));
return true;
}
plugin.reloadPlugin();
sender.sendMessage(color(lang.getString("sp.plugin.reloaded", "§aSurvivalPlus wurde erfolgreich neu geladen!")));
return true;
}
// /sp info
if (args[0].equalsIgnoreCase("info")) {
sender.sendMessage(color(lang.getString("sp.info.header", "&7===== SurvivalPlus Info =====")));
sender.sendMessage(color(lang.getString("sp.info.name", "&ePlugin-Name: &f") + plugin.getDescription().getName()));
sender.sendMessage(color(lang.getString("sp.info.version", "&eVersion: &f") + plugin.getDescription().getVersion()));
sender.sendMessage(color(lang.getString("sp.info.author", "&eErsteller: &f") + "M_Viper"));
sender.sendMessage(color(lang.getString("sp.info.description", "&eBeschreibung:\n&f") + plugin.getDescription().getDescription()));
if (sender instanceof Player player) {
// Überschrift über die Links
player.sendMessage(ChatColor.GOLD + "Links:");
// Button: Spigot-Seite
TextComponent spigotLink = new TextComponent(ChatColor.GREEN + "[Spigot-Seite]");
spigotLink.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL,
"https://www.spigotmc.org/resources/authors/m-lukas-17.618600/"));
spigotLink.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(ChatColor.YELLOW + "Klicke, um die Spigot-Seite zu öffnen").create()
));
// Button: Bugs melden (Git)
TextComponent gitLink = new TextComponent(ChatColor.GREEN + " [Bugs melden]");
gitLink.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL,
"https://git.viper.ipv64.net/M_Viper/Survival-Plus/issues"));
gitLink.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(ChatColor.YELLOW + "Klicke, um den Bug-Tracker zu öffnen").create()
));
// Beide nebeneinander
spigotLink.addExtra(gitLink);
player.spigot().sendMessage(spigotLink);
} else {
sender.sendMessage(ChatColor.GOLD + "Links:");
sender.sendMessage(ChatColor.GREEN + "[Spigot-Seite] "
+ "https://www.spigotmc.org/resources/authors/m-lukas-17.618600/"
+ ChatColor.GREEN + " [Bugs melden] "
+ "https://git.viper.ipv64.net/M_Viper/Survival-Plus/issues");
}
sender.sendMessage(color(lang.getString("sp.info.footer", "&7==========================")));
return true;
}
// /sp share → Vorschau mit Buttons
if (args[0].equalsIgnoreCase("share")) {
if (!(sender instanceof Player player)) {
sender.sendMessage(color(lang.getString("player-only", "§cDieser Befehl ist nur für Spieler!")));
return true;
}
org.bukkit.Location loc = player.getLocation();
String coordsMsg = color(lang.getString("sp.share.preview-format", "")
.replace("%player%", player.getName())
.replace("%x%", String.valueOf(loc.getBlockX()))
.replace("%y%", String.valueOf(loc.getBlockY()))
.replace("%z%", String.valueOf(loc.getBlockZ()))
.replace("%world%", loc.getWorld().getName())
);
player.sendMessage(color(lang.getString("sp.share.preview-title", "§aDeine aktuellen Koordinaten wären:")));
player.sendMessage(coordsMsg);
TextComponent sendBtn = new TextComponent(color(lang.getString("sp.share.send-button", "§a[✅ Senden]")));
sendBtn.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sp shareconfirm"));
sendBtn.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(color(lang.getString("sp.share.send-hover",
"§aKlicke, um deine Koordinaten an alle zu senden."))).create()
));
TextComponent cancelBtn = new TextComponent(color(lang.getString("sp.share.cancel-button", "§c [❌ Abbrechen]")));
cancelBtn.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sp sharecancel"));
cancelBtn.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(color(lang.getString("sp.share.cancel-hover",
"§cKlicke, um das Senden abzubrechen."))).create()
));
sendBtn.addExtra(cancelBtn);
player.spigot().sendMessage(sendBtn);
return true;
}
// /sp shareconfirm → bestätigt und sendet
if (args[0].equalsIgnoreCase("shareconfirm")) {
if (!(sender instanceof Player player)) {
sender.sendMessage(color(lang.getString("player-only", "§cDieser Befehl ist nur für Spieler!")));
return true;
}
org.bukkit.Location loc = player.getLocation();
String message = color(lang.getString("sp.share.preview-format", "")
.replace("%player%", player.getName())
.replace("%x%", String.valueOf(loc.getBlockX()))
.replace("%y%", String.valueOf(loc.getBlockY()))
.replace("%z%", String.valueOf(loc.getBlockZ()))
.replace("%world%", loc.getWorld().getName())
);
Bukkit.broadcastMessage(message);
player.sendMessage(color(lang.getString("sp.share.sent", "§aKoordinaten gesendet.")));
return true;
}
// /sp sharecancel → bricht ab
if (args[0].equalsIgnoreCase("sharecancel")) {
if (sender instanceof Player p) {
p.sendMessage(color(lang.getString("sp.share.cancelled", "§eSenden der Koordinaten abgebrochen.")));
}
return true;
}
// Ungültiger Unterbefehl
sender.sendMessage(color(lang.getString(
"sp.invalid-subcommand",
"§cUngültiger Unterbefehl! Verwendung: /sp [reload|help|info|share]"
)));
return true;
}
private void showHelp(CommandSender sender, int page) {
FileConfiguration help = plugin.getHelpConfig();
FileConfiguration lang = plugin.getLangConfig();
if (help == null || help.getConfigurationSection("commands") == null) {
sender.sendMessage(color(lang.getString("sp.help-not-found", "&cHilfedatei (help.yml) konnte nicht geladen werden!")));
return;
}
List<String> commands = new ArrayList<>(help.getConfigurationSection("commands").getKeys(false));
if (commands.isEmpty()) {
sender.sendMessage(color(lang.getString("sp.help-not-found", "&cKeine Befehle verfügbar.")));
return;
}
int totalPages = (int) Math.ceil((double) commands.size() / COMMANDS_PER_PAGE);
if (page > totalPages) page = totalPages;
if (page < 1) page = 1;
sender.sendMessage(color(help.getString("header", "&7===== &eSurvivalPlus Hilfe &7=====")));
int startIndex = (page - 1) * COMMANDS_PER_PAGE;
int endIndex = Math.min(startIndex + COMMANDS_PER_PAGE, commands.size());
for (int i = startIndex; i < endIndex; i++) {
String cmd = commands.get(i);
String usage = help.getString("commands." + cmd + ".usage", "");
String description = help.getString("commands." + cmd + ".description", "");
sender.sendMessage(color(usage + " §7- " + description));
}
if (sender instanceof Player player) {
TextComponent navigation = new TextComponent();
if (page > 1) {
TextComponent prev = new TextComponent(color(help.getString("navigation.prev", "« Vorherige ")));
prev.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sp help " + (page - 1)));
navigation.addExtra(prev);
} else {
navigation.addExtra(color(help.getString("navigation.prev-disabled", "« ")));
}
TextComponent pageInfo = new TextComponent(color(help.getString("navigation.page", " §fSeite {current} von {total} "))
.replace("{current}", String.valueOf(page))
.replace("{total}", String.valueOf(totalPages)));
navigation.addExtra(pageInfo);
if (page < totalPages) {
TextComponent next = new TextComponent(color(help.getString("navigation.next", " Nächste »")));
next.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sp help " + (page + 1)));
navigation.addExtra(next);
} else {
navigation.addExtra(color(help.getString("navigation.next-disabled", " »")));
}
player.spigot().sendMessage(navigation);
} else {
for (String cmd : commands) {
String usage = help.getString("commands." + cmd + ".usage", "");
String description = help.getString("commands." + cmd + ".description", "");
sender.sendMessage(color(usage + " §7- " + description));
}
}
sender.sendMessage(color(help.getString("footer", "&7==========================")));
}
private String color(String input) {
return ChatColor.translateAlternateColorCodes('&', input == null ? "" : input);
}
}

View File

@@ -0,0 +1,65 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.report.ReportManager;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ReportCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final ReportManager reportManager;
public ReportCommand(SurvivalPlus plugin, ReportManager reportManager) {
this.plugin = plugin;
this.reportManager = reportManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(plugin.getLangConfig().getString("report.only-players", "§cNur Spieler können diesen Befehl ausführen!"));
return true;
}
if (args.length < 1) {
player.sendMessage(plugin.getLangConfig().getString("report.usage", "§cVerwendung: /report <Spieler> [Grund]"));
return true;
}
String targetName = args[0];
String reason = "Kein Grund angegeben";
if (args.length > 1) {
reason = String.join(" ", java.util.Arrays.copyOfRange(args, 1, args.length));
}
if (Bukkit.getPlayer(targetName) == null) {
player.sendMessage(plugin.getLangConfig().getString("report.player-not-online", "§cDieser Spieler ist nicht online!"));
return true;
}
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
reportManager.addReport(targetName, player.getName(), reason, time);
player.sendMessage(plugin.getLangConfig().getString("report.success", "§aDein Report wurde erfolgreich gesendet."));
// Nachricht an Admins
String msg = plugin.getLangConfig().getString("report.notify-admin",
"§cREPORT§r: %reporter% hat %target% gemeldet. Grund: %reason%")
.replace("%reporter%", player.getName())
.replace("%target%", targetName)
.replace("%reason%", reason);
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.hasPermission("survivalplus.report.receive"))
.forEach(p -> p.sendMessage(msg));
return true;
}
}

View File

@@ -0,0 +1,41 @@
package de.viper.survivalplus.commands;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import de.viper.survivalplus.SurvivalPlus;
public class SetSpawnCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public SetSpawnCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("Nur Spieler können diesen Befehl verwenden!");
return true;
}
if (!player.hasPermission("survivalplus.setspawn")) {
player.sendMessage("§cDu hast keine Rechte für diesen Befehl.");
return true;
}
Location loc = player.getLocation();
plugin.getConfig().set("spawn.world", loc.getWorld().getName());
plugin.getConfig().set("spawn.x", loc.getX());
plugin.getConfig().set("spawn.y", loc.getY());
plugin.getConfig().set("spawn.z", loc.getZ());
plugin.getConfig().set("spawn.yaw", loc.getYaw());
plugin.getConfig().set("spawn.pitch", loc.getPitch());
plugin.saveConfig();
player.sendMessage("§aSpawnpunkt erfolgreich gesetzt!");
return true;
}
}

View File

@@ -0,0 +1,68 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.Warp;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class SetWarpCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final WarpManager warpManager;
public SetWarpCommand(SurvivalPlus plugin, WarpManager warpManager) {
this.plugin = plugin;
this.warpManager = warpManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("warp.only_players"));
return true;
}
Player player = (Player) sender;
if (args.length < 1) {
player.sendMessage(ChatColor.RED + "Benutze: /setwarp <name>");
return true;
}
String warpName = args[0];
int maxWarps = plugin.getConfig().getInt("maxWarpsPerPlayer", 5);
int currentWarpCount = warpManager.getWarpCountForPlayer(player.getName());
Warp existingWarp = warpManager.getWarp(player.getName(), warpName);
// Limit prüfen - Falls Warp mit dem Namen schon existiert, Update erlaubt
if (currentWarpCount >= maxWarps && existingWarp == null) {
player.sendMessage(ChatColor.RED + "Du hast das maximale Warp-Limit von " + maxWarps + " erreicht.");
return true;
}
ItemStack item = player.getInventory().getItemInMainHand();
// Default Item wenn leer (aus config oder Schild)
if (item == null || item.getType().isAir()) {
String defaultItemName = plugin.getConfig().getString("defaultWarpItem", "OAK_SIGN");
try {
item = new org.bukkit.inventory.ItemStack(org.bukkit.Material.valueOf(defaultItemName));
} catch (IllegalArgumentException e) {
item = new org.bukkit.inventory.ItemStack(org.bukkit.Material.OAK_SIGN);
}
}
Location loc = player.getLocation();
Warp warp = new Warp(player.getName(), warpName, item, loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ());
warpManager.addWarp(warp);
player.sendMessage(plugin.getMessage("warp.set_success").replace("%warp%", warpName));
return true;
}
}

View File

@@ -0,0 +1,40 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetWorldSpawnCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public SetWorldSpawnCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(ChatColor.RED + "Dieser Befehl kann nur von einem Spieler verwendet werden.");
return true;
}
if (!player.hasPermission("survivalplus.setworldspawn")) {
player.sendMessage(ChatColor.RED + "Du hast keine Rechte für diesen Befehl.");
return true;
}
Location loc = player.getLocation();
World world = player.getWorld();
world.setSpawnLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
player.sendMessage(ChatColor.GREEN + "Spawnpunkt gesetzt bei §e" +
loc.getBlockX() + " " + loc.getBlockY() + " " + loc.getBlockZ());
return true;
}
}

View File

@@ -0,0 +1,84 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.ShopManager;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.gui.ShopGui;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class ShopCommand implements CommandExecutor {
private final ShopManager shopManager;
private final SurvivalPlus plugin;
public ShopCommand(SurvivalPlus plugin) {
this.plugin = plugin;
this.shopManager = new ShopManager(plugin);
}
private String getMessage(String key) {
return plugin.getMessage("shop." + key);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(getMessage("only-players"));
return true;
}
Player player = (Player) sender;
// Shop-GUI öffnen, wenn kein Argument oder "gui"
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
player.openInventory(shopGui.getInventory());
return true;
}
if (args.length < 3) {
sender.sendMessage(getMessage("usage-add"));
return false;
}
if (!args[0].toLowerCase().equals("add")) {
sender.sendMessage(getMessage("unknown-subcommand"));
return false;
}
ItemStack itemInHand = player.getInventory().getItemInMainHand();
if (itemInHand == null || itemInHand.getType() == Material.AIR) {
sender.sendMessage(ChatColor.RED + "Du musst das Item, das du hinzufügen willst, in der Hand halten!");
return true;
}
String itemKey = itemInHand.getType().name().toLowerCase();
double basePrice;
int stock;
try {
basePrice = Double.parseDouble(args[1]);
stock = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {
sender.sendMessage(getMessage("number-error"));
return false;
}
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
String msg = getMessage("item-added")
.replace("{item}", itemKey)
.replace("{price}", args[1])
.replace("{stock}", args[2]);
sender.sendMessage(msg);
return true;
}
}

View File

@@ -0,0 +1,43 @@
package de.viper.survivalplus.commands;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.java.JavaPlugin;
public class ShowArmorStandsCommand implements CommandExecutor {
private final JavaPlugin plugin;
public ShowArmorStandsCommand(JavaPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("survivalplus.showarmorstands")) {
sender.sendMessage("§cDu hast keine Rechte für diesen Befehl.");
return true;
}
int count = 0;
for (World world : Bukkit.getWorlds()) {
for (Entity entity : world.getEntities()) {
if (entity instanceof ArmorStand) {
ArmorStand armorStand = (ArmorStand) entity;
if (!armorStand.isVisible()) {
armorStand.setVisible(true);
count++;
}
}
}
}
sender.sendMessage("§a" + count + " unsichtbare Armor Stands wurden sichtbar gemacht.");
return true;
}
}

View File

@@ -0,0 +1,52 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.report.ReportManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class ShowReportCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final ReportManager reportManager;
public ShowReportCommand(SurvivalPlus plugin, ReportManager reportManager) {
this.plugin = plugin;
this.reportManager = reportManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(plugin.getLangConfig().getString("showreport.only-players", "§cNur Spieler können diesen Befehl ausführen!"));
return true;
}
if (!player.hasPermission("survivalplus.report.show")) {
player.sendMessage(plugin.getLangConfig().getString("no-permission", "§cDu hast keine Berechtigung!"));
return true;
}
if (args.length != 1) {
player.sendMessage(plugin.getLangConfig().getString("showreport.usage", "§cVerwendung: /showreport <Spieler>"));
return true;
}
String targetName = args[0];
List<String> reports = reportManager.getReports(targetName);
if (reports.isEmpty()) {
player.sendMessage(plugin.getLangConfig().getString("showreport.no-reports", "§aEs wurden keine Reports für diesen Spieler gefunden."));
return true;
}
player.sendMessage("§6--- Reports für Spieler " + targetName + " ---");
reports.forEach(r -> player.sendMessage("§7" + r));
return true;
}
}

View File

@@ -0,0 +1,57 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.listeners.SitListener;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
public class SitCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final SitListener sitListener;
public SitCommand(SurvivalPlus plugin, SitListener sitListener) {
this.plugin = plugin;
this.sitListener = sitListener;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getLangConfig().getString("player-only", "§cDieser Befehl ist nur für Spieler!"));
return true;
}
Player player = (Player) sender;
FileConfiguration lang = plugin.getLangConfig();
if (!player.hasPermission("survivalplus.sit")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return true;
}
if (args.length != 0) {
player.sendMessage(lang.getString("sit.usage", "§cVerwendung: /sit"));
return true;
}
// Prüfe, ob der Spieler bereits sitzt
if (sitListener.isSitting(player)) {
sitListener.standUp(player);
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
return true;
}
// Setze den Spieler mittig auf den Block und leicht oberhalb (Fix)
Location location = player.getLocation();
location.setX(location.getBlockX() + 0.5);
location.setY(location.getBlockY() + 0.25);
location.setZ(location.getBlockZ() + 0.5);
sitListener.sitPlayer(player, location);
return true;
}
}

View File

@@ -0,0 +1,39 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.Location;
import org.bukkit.World;
public class SpawnCommand implements CommandExecutor {
private final SurvivalPlus plugin;
public SpawnCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("spawn.only_player"));
return true;
}
Player player = (Player) sender;
World world = player.getWorld();
Location spawnLocation = world.getSpawnLocation();
if (spawnLocation == null) {
player.sendMessage(plugin.getMessage("spawn.no_spawn_found"));
return true;
}
player.teleport(spawnLocation);
player.sendMessage(plugin.getMessage("spawn.teleported"));
return true;
}
}

View File

@@ -0,0 +1,50 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.fun.FunChallenge;
import de.viper.survivalplus.fun.FunChallengeManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class StartFunChallengeCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final FunChallengeManager challengeManager;
public StartFunChallengeCommand(SurvivalPlus plugin, FunChallengeManager challengeManager) {
this.plugin = plugin;
this.challengeManager = challengeManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getLangConfig().getString("challenge.only_players"));
return true;
}
if (args.length < 1) {
sender.sendMessage(plugin.getLangConfig().getString("challenge.usage"));
return true;
}
String challengeName = args[0];
for (FunChallenge fc : challengeManager.getChallenges()) {
if (fc.getName().equalsIgnoreCase(challengeName)) {
fc.setActive(true);
String msg = plugin.getLangConfig()
.getString("challenge.start_success")
.replace("%challenge%", fc.getDescription());
sender.sendMessage(msg);
// Hier ggf. Timer und Tracking starten!
plugin.saveConfig();
return true;
}
}
String failMsg = plugin.getLangConfig()
.getString("challenge.start_fail")
.replace("%challenge%", challengeName);
sender.sendMessage(failMsg);
return true;
}
}

View File

@@ -0,0 +1,69 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.StatsManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class StatsCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final StatsManager statsManager;
public StatsCommand(SurvivalPlus plugin, StatsManager statsManager) {
this.plugin = plugin;
this.statsManager = statsManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("stats.only_player"));
return true;
}
Player player = (Player) sender;
long time = statsManager.getPlayTime(player.getUniqueId());
int kills = statsManager.getKills(player.getUniqueId());
int deaths = statsManager.getDeaths(player.getUniqueId());
int placed = statsManager.getBlocksPlaced(player.getUniqueId());
int broken = statsManager.getBlocksBroken(player.getUniqueId());
if (time == 0 && kills == 0 && deaths == 0 && placed == 0 && broken == 0) {
player.sendMessage(plugin.getMessage("stats.no_stats"));
return true;
}
// K/D Ratio berechnen (vermeide Division durch 0)
String kdRatio = deaths > 0 ? String.format("%.2f", (double) kills / deaths) : "";
// Zusätzliche Minecraft Statistik
int jumps = player.getStatistic(org.bukkit.Statistic.JUMP);
double walkKm = player.getStatistic(org.bukkit.Statistic.WALK_ONE_CM) / 100_000.0; // cm zu km
player.sendMessage(plugin.getMessage("stats.header").replace("{player}", player.getName()));
player.sendMessage(plugin.getMessage("stats.playtime").replace("{time}", formatPlayTime(time)));
player.sendMessage(plugin.getMessage("stats.kills").replace("{kills}", String.valueOf(kills)));
player.sendMessage(plugin.getMessage("stats.deaths").replace("{deaths}", String.valueOf(deaths)));
player.sendMessage(plugin.getMessage("stats.kd_ratio").replace("{kd}", kdRatio));
player.sendMessage(plugin.getMessage("stats.blocks_placed").replace("{placed}", String.valueOf(placed)));
player.sendMessage(plugin.getMessage("stats.blocks_broken").replace("{broken}", String.valueOf(broken)));
player.sendMessage(plugin.getMessage("stats.jumps").replace("{jumps}", String.valueOf(jumps)));
player.sendMessage(plugin.getMessage("stats.walked").replace("{walked}", String.format("%.2f", walkKm)));
player.sendMessage(plugin.getMessage("stats.footer"));
return true;
}
private String formatPlayTime(long seconds) {
long hours = seconds / 3600;
long minutes = (seconds % 3600) / 60;
long secs = seconds % 60;
return String.format("%02dh %02dm %02ds", hours, minutes, secs);
}
}

View File

@@ -0,0 +1,157 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TeleportCommands implements CommandExecutor {
private final SurvivalPlus plugin;
private final Map<UUID, UUID> teleportRequests = new HashMap<>();
public TeleportCommands(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("only-players"));
return true;
}
Player player = (Player) sender;
String cmd = label.toLowerCase();
switch (cmd) {
case "tp":
return handleTp(player, args);
case "tphere":
return handleTphere(player, args);
case "tpa":
return handleTpa(player, args);
case "tpaccept":
return handleTpAccept(player);
case "tpdeny":
return handleTpDeny(player);
default:
return false;
}
}
private boolean handleTp(Player sender, String[] args) {
if (!sender.hasPermission("survivalplus.tp")) {
sender.sendMessage(plugin.getMessage("no-permission"));
return true;
}
if (args.length != 1) {
sender.sendMessage(plugin.getMessage("teleport-usage"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
sender.sendMessage(plugin.getMessage("player-not-found").replace("%player%", args[0]));
return true;
}
sender.teleport(target);
sender.sendMessage(plugin.getMessage("teleport-success").replace("%player%", target.getName()));
return true;
}
private boolean handleTphere(Player sender, String[] args) {
if (!sender.hasPermission("survivalplus.tphere")) {
sender.sendMessage(plugin.getMessage("no-permission"));
return true;
}
if (args.length != 1) {
sender.sendMessage(plugin.getMessage("tphere-usage"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
sender.sendMessage(plugin.getMessage("player-not-found").replace("%player%", args[0]));
return true;
}
target.teleport(sender);
sender.sendMessage(plugin.getMessage("tphere-success").replace("%player%", target.getName()));
return true;
}
private boolean handleTpa(Player sender, String[] args) {
if (!sender.hasPermission("survivalplus.tpa")) {
sender.sendMessage(plugin.getMessage("no-permission"));
return true;
}
if (args.length != 1) {
sender.sendMessage(plugin.getMessage("tpa-usage"));
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
sender.sendMessage(plugin.getMessage("player-not-found").replace("%player%", args[0]));
return true;
}
teleportRequests.put(target.getUniqueId(), sender.getUniqueId());
sender.sendMessage(plugin.getMessage("tpa-sent").replace("%player%", target.getName()));
target.sendMessage(plugin.getMessage("tpa-received").replace("%player%", sender.getName()));
return true;
}
private boolean handleTpAccept(Player target) {
if (!target.hasPermission("survivalplus.tpaccept")) {
target.sendMessage(plugin.getMessage("no-permission"));
return true;
}
UUID senderId = teleportRequests.remove(target.getUniqueId());
if (senderId == null) {
target.sendMessage(plugin.getMessage("no-tpa-request"));
return true;
}
Player sender = Bukkit.getPlayer(senderId);
if (sender == null) {
target.sendMessage(plugin.getMessage("player-not-found"));
return true;
}
sender.teleport(target);
sender.sendMessage(plugin.getMessage("tpa-accepted").replace("%player%", target.getName()));
target.sendMessage(plugin.getMessage("tpaccept-success").replace("%player%", sender.getName()));
return true;
}
private boolean handleTpDeny(Player target) {
if (!target.hasPermission("survivalplus.tpdeny")) {
target.sendMessage(plugin.getMessage("no-permission"));
return true;
}
UUID senderId = teleportRequests.remove(target.getUniqueId());
if (senderId == null) {
target.sendMessage(plugin.getMessage("no-tpa-request"));
return true;
}
Player sender = Bukkit.getPlayer(senderId);
if (sender != null) {
sender.sendMessage(plugin.getMessage("tpa-denied").replace("%player%", target.getName()));
}
target.sendMessage(plugin.getMessage("tpdeny-success"));
return true;
}
}

View File

@@ -0,0 +1,35 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.trade.TradeManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class TradeAcceptCommand implements CommandExecutor {
private final TradeManager tradeManager;
private final SurvivalPlus plugin;
public TradeAcceptCommand(SurvivalPlus plugin, TradeManager tradeManager) {
this.plugin = plugin;
this.tradeManager = tradeManager;
}
@Override
public boolean onCommand(CommandSender senderS, Command command, String label, String[] args) {
if (!(senderS instanceof Player target)) {
senderS.sendMessage(plugin.getLangConfig().getString("only-players", "§cNur Spieler können diesen Befehl ausführen!"));
return true;
}
if (args.length != 1) {
target.sendMessage(plugin.getLangConfig().getString("trade.accept.usage", "§cVerwendung: /tradeaccept <Spieler>"));
return true;
}
tradeManager.acceptTrade(target, args[0]);
return true;
}
}

View File

@@ -0,0 +1,42 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.trade.TradeManager;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class TradeCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final TradeManager tradeManager;
public TradeCommand(SurvivalPlus plugin, TradeManager tradeManager) {
this.plugin = plugin;
this.tradeManager = tradeManager;
}
@Override
public boolean onCommand(CommandSender senderS, Command command, String label, String[] args) {
if (!(senderS instanceof Player sender)) {
senderS.sendMessage(plugin.getLangConfig().getString("only-players", "§cNur Spieler können diesen Befehl ausführen!"));
return true;
}
if (args.length != 1) {
sender.sendMessage(plugin.getLangConfig().getString("trade.usage", "§cVerwendung: /trade <Spieler>"));
return true;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null || !target.isOnline()) {
sender.sendMessage(plugin.getLangConfig().getString("trade.player-not-online", "§cDieser Spieler ist nicht online!"));
return true;
}
tradeManager.requestTrade(sender, target);
return true;
}
}

View File

@@ -0,0 +1,23 @@
package de.viper.survivalplus.commands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
public class TrashCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("Nur Spieler können diesen Befehl ausführen.");
return true;
}
Inventory trash = Bukkit.createInventory(player, 9 * 3, "Trash");
player.openInventory(trash);
return true;
}
}

View File

@@ -0,0 +1,48 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.BlockManager;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.configuration.file.FileConfiguration;
public class UnblockCommand implements CommandExecutor {
private final BlockManager blockManager;
private final FileConfiguration config;
public UnblockCommand(BlockManager blockManager, FileConfiguration config) {
this.blockManager = blockManager;
this.config = config;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(config.getString("messages.general.only_players"));
return true;
}
if (args.length != 1) {
player.sendMessage(config.getString("messages.unblock.usage"));
return true;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null || target == player) {
player.sendMessage(config.getString("messages.unblock.invalid_player"));
return true;
}
if (blockManager.hasBlocked(player, target)) {
blockManager.unblockPlayer(player, target);
player.sendMessage(config.getString("messages.unblock.unblocked").replace("%player%", target.getName()));
target.sendMessage(config.getString("messages.unblock.unblocked_by").replace("%player%", player.getName()));
} else {
player.sendMessage(config.getString("messages.unblock.not_blocked").replace("%player%", target.getName()));
}
return true;
}
}

View File

@@ -0,0 +1,75 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.Warp;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.*;
import java.util.stream.Collectors;
public class WarpsCommand implements CommandExecutor {
private final SurvivalPlus plugin;
private final WarpManager warpManager;
public WarpsCommand(SurvivalPlus plugin, WarpManager warpManager) {
this.plugin = plugin;
this.warpManager = warpManager;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("warp.only_players"));
return true;
}
Player player = (Player) sender;
Map<String, List<Warp>> warpsByOwner = warpManager.getWarps().values().stream()
.collect(Collectors.groupingBy(Warp::getOwner));
List<String> ownersSorted = new ArrayList<>(warpsByOwner.keySet());
Collections.sort(ownersSorted);
int totalWarps = warpManager.getWarps().size();
int size = ((totalWarps + 8) / 9) * 9;
if (size < 27) size = 27; // mindestens 27 Slots
Inventory inv = Bukkit.createInventory(null, size, ChatColor.GOLD + "Player Warps");
int slot = 0;
for (String owner : ownersSorted) {
for (Warp warp : warpsByOwner.get(owner)) {
if (slot >= size) break;
ItemStack item = warp.getItem().clone();
item.setAmount(1);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ChatColor.YELLOW + warp.getName());
List<String> lore = new ArrayList<>();
lore.add(ChatColor.GRAY + "Owner: " + warp.getOwner());
lore.add(ChatColor.GRAY + "World: " + warp.getWorldName());
meta.setLore(lore);
meta.setUnbreakable(true);
item.setItemMeta(meta);
}
inv.setItem(slot++, item);
}
if (slot >= size) break;
}
player.openInventory(inv);
return true;
}
}

View File

@@ -0,0 +1,20 @@
package de.viper.survivalplus.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class WorkbenchCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("Nur Spieler können diesen Befehl ausführen.");
return true;
}
player.openWorkbench(null, true); // Öffnet die Werkbank-GUI für den Spieler
return true;
}
}

View File

@@ -0,0 +1,39 @@
package de.viper.survivalplus.fun;
public class FunChallenge {
private String name;
private String description;
private String type;
private String item;
private int amount;
private int timeLimitMinutes;
private boolean active;
private String reward;
public FunChallenge() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getItem() { return item; }
public void setItem(String item) { this.item = item; }
public int getAmount() { return amount; }
public void setAmount(int amount) { this.amount = amount; }
public int getTimeLimitMinutes() { return timeLimitMinutes; }
public void setTimeLimitMinutes(int timeLimitMinutes) { this.timeLimitMinutes = timeLimitMinutes; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
public String getReward() { return reward; }
public void setReward(String reward) { this.reward = reward; }
}

View File

@@ -0,0 +1,122 @@
package de.viper.survivalplus.fun;
import org.bukkit.Bukkit;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FunChallengeManager {
private final List<FunChallenge> challenges = new ArrayList<>();
private final Map<String, Integer> globalProgress = new HashMap<>(); // Fortschritt global für alle Spieler
private final Map<Player, BossBar> playerBossBars = new HashMap<>();
private BukkitRunnable bossBarTask;
public void load(FileConfiguration config) {
challenges.clear();
globalProgress.clear();
if (config.contains("funChallenges")) {
for (Map<?, ?> entry : config.getMapList("funChallenges")) {
FunChallenge fc = new FunChallenge();
fc.setName((String) entry.get("name"));
fc.setDescription((String) entry.get("description"));
fc.setType((String) entry.get("type"));
fc.setItem((String) entry.get("item"));
fc.setAmount((Integer) entry.get("amount"));
fc.setTimeLimitMinutes((Integer) entry.get("timeLimitMinutes"));
fc.setActive(Boolean.parseBoolean(entry.get("active").toString()));
fc.setReward((String) entry.get("reward"));
challenges.add(fc);
globalProgress.put(fc.getName(), 0);
}
}
startBossBar(); // automatisch BossBar starten, falls eine Challenge aktiv ist
}
public List<FunChallenge> getChallenges() { return challenges; }
public FunChallenge getActiveChallenge() {
for (FunChallenge c : challenges) {
if (c.isActive()) return c;
}
return null;
}
public int getGlobalProgress(String challengeName) {
return globalProgress.getOrDefault(challengeName, 0);
}
public void setGlobalProgress(String challengeName, int amount) {
globalProgress.put(challengeName, amount);
}
public void resetProgress(String challengeName) {
globalProgress.put(challengeName, 0);
}
// ====================== BossBar-Funktion ======================
public void startBossBar() {
FunChallenge active = getActiveChallenge();
if (active == null) return;
stopBossBar(); // alte Bars entfernen, falls vorhanden
int totalTime = active.getTimeLimitMinutes() * 60; // Gesamtzeit in Sekunden
final int[] timeLeft = {totalTime};
bossBarTask = new BukkitRunnable() {
@Override
public void run() {
if (timeLeft[0] <= 0 || getActiveChallenge() == null) {
stopBossBar();
return;
}
double progress = (double) timeLeft[0] / totalTime;
String formattedTime = formatTime(timeLeft[0]);
for (Player player : Bukkit.getOnlinePlayers()) {
BossBar bar = playerBossBars.computeIfAbsent(player, p -> {
BossBar newBar = Bukkit.createBossBar(
active.getName() + " (" + formattedTime + ")",
BarColor.BLUE,
BarStyle.SOLID
);
newBar.addPlayer(p);
return newBar;
});
bar.setProgress(progress);
bar.setTitle(active.getName() + " (" + formattedTime + ")");
}
timeLeft[0]--;
}
};
bossBarTask.runTaskTimer(Bukkit.getPluginManager().getPlugin("SurvivalPlus"), 0L, 20L);
}
public void stopBossBar() {
if (bossBarTask != null) bossBarTask.cancel();
for (BossBar bar : playerBossBars.values()) {
bar.removeAll();
}
playerBossBars.clear();
}
private String formatTime(int seconds) {
int minutes = seconds / 60;
int sec = seconds % 60;
return String.format("%02d:%02d", minutes, sec);
}
}

View File

@@ -0,0 +1,129 @@
package de.viper.survivalplus.gui;
import de.viper.survivalplus.Manager.ShopManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Arrays;
public class ShopGui implements Listener {
private final ShopManager shopManager;
private final Player player;
private Inventory inv;
private final SurvivalPlus plugin;
public ShopGui(SurvivalPlus plugin, Player player, ShopManager shopManager) {
this.plugin = plugin;
this.player = player;
this.shopManager = shopManager;
createInventory();
}
private void createInventory() {
inv = Bukkit.createInventory(null, 27, "Shop");
if (shopManager.getShopConfig().getConfigurationSection("items") == null) {
player.sendMessage(ChatColor.RED + "Der Shop ist momentan leer.");
return;
}
// Alle Items aus shop.yml einlesen
for (String itemKey : shopManager.getShopConfig().getConfigurationSection("items").getKeys(false)) {
Material mat = getMaterialFromKey(itemKey);
if (mat == null) {
player.sendMessage(ChatColor.RED + "Material für '" + itemKey + "' konnte nicht gefunden werden.");
continue;
}
addShopItem(itemKey, mat, 64);
addShopItem(itemKey, mat, 16);
addShopItem(itemKey, mat, 1);
}
player.openInventory(inv);
}
private Material getMaterialFromKey(String key) {
try {
return Material.valueOf(key.toUpperCase());
} catch (IllegalArgumentException e) {
return null;
}
}
private void addShopItem(String itemKey, Material material, int amount) {
double pricePerUnit = shopManager.getCurrentPrice(itemKey);
double totalPrice = pricePerUnit * amount;
ItemStack item = new ItemStack(material, amount);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ChatColor.GREEN.toString() + amount + "x " + material.name());
meta.setLore(Arrays.asList(
ChatColor.YELLOW + "Preis pro Stück: " + pricePerUnit,
ChatColor.YELLOW + "Gesamtpreis: " + totalPrice,
ChatColor.GRAY + "Klicke, um zu kaufen"
));
item.setItemMeta(meta);
}
for (int i = 0; i < inv.getSize(); i++) {
if (inv.getItem(i) == null) {
inv.setItem(i, item);
break;
}
}
}
@EventHandler
public void onInventoryClick(InventoryClickEvent e) {
if (!e.getView().getTitle().equals("Shop")) return;
if (e.getClickedInventory() == null) return;
if (!e.getWhoClicked().equals(player)) return;
e.setCancelled(true);
ItemStack clicked = e.getCurrentItem();
if (clicked == null || clicked.getType() == Material.AIR) return;
int amount = clicked.getAmount();
Material mat = clicked.getType();
String itemKey = mat.name().toLowerCase();
if (!shopManager.buyItem(itemKey, amount)) {
player.sendMessage(ChatColor.RED + "Nicht genügend Bestand im Shop.");
return;
}
double totalPrice = shopManager.getCurrentPrice(itemKey) * amount;
// TODO: Economy Abzug einfügen
player.getInventory().addItem(new ItemStack(mat, amount));
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + totalPrice + " Coins gekauft.");
player.closeInventory();
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent e) {
if (e.getView().getTitle().equals("Shop") && e.getPlayer().equals(player)) {
// Optional: Listener entfernen oder Aufräumarbeiten hier
}
}
public Inventory getInventory() {
return inv;
}
}

View File

@@ -0,0 +1,115 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.tasks.AFKManager;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.player.*;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.scheduler.BukkitRunnable;
public class AFKListener implements Listener {
private final SurvivalPlus plugin;
private AFKManager afkManager;
private boolean afkEnabled;
private FileConfiguration config;
private BukkitRunnable afkTask;
public AFKListener(SurvivalPlus plugin) {
this.plugin = plugin;
this.config = plugin.getConfig();
loadSettings();
if (afkEnabled) {
startTask();
}
}
private void loadSettings() {
this.afkEnabled = config.getBoolean("afk.enabled", true);
long afkAfter = config.getLong("afk.afk-after-seconds", 300);
long kickAfter = config.getLong("afk.kick-after-seconds", 0);
this.afkManager = new AFKManager(plugin, afkAfter, kickAfter);
}
private void startTask() {
if (afkTask != null) {
afkTask.cancel();
}
afkTask = new BukkitRunnable() {
@Override
public void run() {
for (Player player : Bukkit.getOnlinePlayers()) {
afkManager.checkAFKStatus(player);
}
}
};
afkTask.runTaskTimer(plugin, 60L, 100L);
}
private void handleActivity(Player player) {
if (!afkEnabled) return;
afkManager.updateActivity(player);
}
@org.bukkit.event.EventHandler
public void onMove(PlayerMoveEvent event) {
if (!event.getFrom().toVector().equals(event.getTo().toVector())) {
handleActivity(event.getPlayer());
}
}
@org.bukkit.event.EventHandler
public void onChat(AsyncPlayerChatEvent event) {
handleActivity(event.getPlayer());
}
@org.bukkit.event.EventHandler
public void onInteract(PlayerInteractEvent event) {
handleActivity(event.getPlayer());
}
@org.bukkit.event.EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getWhoClicked() instanceof Player player) {
handleActivity(player);
}
}
@org.bukkit.event.EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
handleActivity(event.getPlayer());
}
@org.bukkit.event.EventHandler
public void onBlockBreak(BlockBreakEvent event) {
handleActivity(event.getPlayer());
}
@org.bukkit.event.EventHandler
public void onJoin(PlayerJoinEvent event) {
afkManager.updateActivity(event.getPlayer());
}
@org.bukkit.event.EventHandler
public void onQuit(PlayerQuitEvent event) {
afkManager.reset(event.getPlayer());
}
public void reloadConfig(FileConfiguration config) {
this.config = config;
loadSettings();
if (afkTask != null) {
afkTask.cancel();
afkTask = null;
}
if (afkEnabled) {
startTask();
}
}
}

View File

@@ -0,0 +1,27 @@
package de.viper.survivalplus.listeners;
import org.bukkit.ChatColor;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
public class ArmorStandDestroyListener implements Listener {
@EventHandler
public void onArmorStandInteract(PlayerInteractAtEntityEvent event) {
if (!(event.getRightClicked() instanceof ArmorStand armorStand)) return;
Player player = event.getPlayer();
if (!player.hasPermission("survivalplus.armorstand.destroy")) {
player.sendMessage(ChatColor.RED + "Du hast keine Berechtigung, diesen ArmorStand zu entfernen.");
return;
}
armorStand.remove();
player.sendMessage(ChatColor.YELLOW + "ArmorStand wurde erfolgreich entfernt.");
event.setCancelled(true);
}
}

View File

@@ -0,0 +1,111 @@
package de.viper.survivalplus.listeners;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.logging.Logger;
public class BackpackListener implements Listener {
private final FileConfiguration backpackConfig;
private final FileConfiguration langConfig;
private final Logger logger;
private final File backpackFile;
public BackpackListener(FileConfiguration backpackConfig, FileConfiguration langConfig, Logger logger, File backpackFile) {
this.backpackConfig = backpackConfig;
this.langConfig = langConfig;
this.logger = logger;
this.backpackFile = backpackFile;
}
@EventHandler
public void onRightClick(PlayerInteractEvent event) {
if (!event.hasItem() || !event.getAction().toString().contains("RIGHT")) return;
Player player = event.getPlayer();
ItemStack item = event.getItem();
if (item == null || item.getType() != Material.CHEST) {
logger.fine("Kein Rucksack-Item: " + (item != null ? item.getType() : "null"));
return;
}
if (!item.hasItemMeta()) {
logger.fine("Item hat kein ItemMeta: " + item.getType());
return;
}
ItemMeta meta = item.getItemMeta();
if (!meta.hasDisplayName()) {
logger.fine("Item hat keinen Display-Namen: " + item.getType());
return;
}
String expectedName = ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.name", "&eRucksack"));
if (!meta.getDisplayName().equals(expectedName)) {
logger.fine("Item hat falschen Namen: " + meta.getDisplayName() + ", erwartet: " + expectedName);
return;
}
event.setCancelled(true);
UUID uuid = player.getUniqueId();
String inventoryTitle = ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.inventory-title", "&eDein Rucksack"));
Inventory backpackInv = Bukkit.createInventory(null, 27, inventoryTitle);
logger.info("Öffne Rucksack-Inventar für Spieler " + player.getName() + " (" + uuid + ")");
for (int i = 0; i < 27; i++) {
String path = uuid + ".slot" + i;
if (backpackConfig.contains(path)) {
backpackInv.setItem(i, backpackConfig.getItemStack(path));
}
}
player.openInventory(backpackInv);
}
@EventHandler
public void onClose(InventoryCloseEvent event) {
String expectedTitle = ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.inventory-title", "&eDein Rucksack"));
if (!event.getView().getTitle().equals(expectedTitle)) return;
Player player = (Player) event.getPlayer();
UUID uuid = player.getUniqueId();
Inventory inv = event.getInventory();
logger.info("Speichere Rucksack-Inventar für Spieler " + player.getName() + " (" + uuid + ")");
for (int i = 0; i < inv.getSize(); i++) {
String path = uuid + ".slot" + i;
ItemStack item = inv.getItem(i);
backpackConfig.set(path, item);
}
try {
if (!backpackFile.exists()) {
backpackFile.createNewFile();
logger.info("backpacks.yml wurde erstellt.");
}
backpackConfig.save(backpackFile);
logger.info("Rucksack-Inventar gespeichert für " + player.getName());
} catch (IOException e) {
player.sendMessage(ChatColor.RED + "Fehler beim Speichern deines Rucksacks.");
logger.severe("Fehler beim Speichern der backpacks.yml: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,115 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class BlockDetectionListener implements Listener {
private final SurvivalPlus plugin;
public BlockDetectionListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
scanAndHandle(player, false);
}
@EventHandler
public void onPickUp(EntityPickupItemEvent event) {
if (!(event.getEntity() instanceof Player)) return;
Player player = (Player) event.getEntity();
scanAndHandle(player, true);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) return;
Player player = (Player) event.getWhoClicked();
scanAndHandle(player, true);
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
Player player = event.getPlayer();
if (player.hasPermission("survivalplus.notify")) {
return; // Admins dürfen Blöcke platzieren
}
Material material = event.getBlock().getType();
boolean cmdAllowed = plugin.getConfig().getBoolean("blocks.command-blocks.enabled", true);
boolean structAllowed = plugin.getConfig().getBoolean("blocks.structure-blocks.enabled", true);
if ((!cmdAllowed && material == Material.COMMAND_BLOCK) ||
(!structAllowed && material == Material.STRUCTURE_BLOCK)) {
event.setCancelled(true);
player.sendMessage(ChatColor.RED + "[SurvivalPlus] Du darfst diesen Block hier nicht platzieren!");
}
}
private void scanAndHandle(Player player, boolean notifyPlayer) {
if (player.hasPermission("survivalplus.notify")) {
return; // Admins dürfen Blöcke behalten
}
Inventory inventory = player.getInventory();
boolean hasCommandBlock = false;
boolean hasStructureBlock = false;
boolean cmdAllowed = plugin.getConfig().getBoolean("blocks.command-blocks.enabled", true);
boolean structAllowed = plugin.getConfig().getBoolean("blocks.structure-blocks.enabled", true);
boolean notifyAdmins = plugin.getConfig().getBoolean("blocks.notify-admins-on-possession", true);
for (ItemStack item : inventory.getContents()) {
if (item == null) continue;
Material material = item.getType();
if (material == Material.COMMAND_BLOCK) hasCommandBlock = true;
if (material == Material.STRUCTURE_BLOCK) hasStructureBlock = true;
}
if (!cmdAllowed && hasCommandBlock) {
inventory.remove(Material.COMMAND_BLOCK);
if (notifyPlayer) {
player.sendMessage(ChatColor.RED + "[SurvivalPlus] Command-Blöcke wurden aus deinem Inventar entfernt, da sie deaktiviert sind.");
}
}
if (!structAllowed && hasStructureBlock) {
inventory.remove(Material.STRUCTURE_BLOCK);
if (notifyPlayer) {
player.sendMessage(ChatColor.RED + "[SurvivalPlus] Structure-Blöcke wurden aus deinem Inventar entfernt, da sie deaktiviert sind.");
}
}
if (notifyAdmins && (hasCommandBlock || hasStructureBlock)) {
notifyOnlineAdmins(player.getName(), hasCommandBlock, hasStructureBlock, cmdAllowed, structAllowed);
}
}
private void notifyOnlineAdmins(String playerName, boolean hadCommandBlock, boolean hadStructureBlock, boolean cmdAllowed, boolean structAllowed) {
String baseTag = ChatColor.GRAY + "[" + ChatColor.GREEN + "SurvivalPlus" + ChatColor.GRAY + "] ";
for (Player admin : Bukkit.getOnlinePlayers()) {
if (admin.hasPermission("survivalplus.notify")) {
if (hadCommandBlock && !cmdAllowed) {
String message = baseTag + ChatColor.RED + "Spieler " + ChatColor.YELLOW + playerName +
ChatColor.RED + " hatte einen Command-Block im Inventar, der entfernt wurde.";
admin.sendMessage(message);
}
if (hadStructureBlock && !structAllowed) {
String message = baseTag + ChatColor.RED + "Spieler " + ChatColor.YELLOW + playerName +
ChatColor.RED + " hatte einen Structure-Block im Inventar, der entfernt wurde.";
admin.sendMessage(message);
}
}
}
}
}

View File

@@ -0,0 +1,86 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.fun.FunChallenge;
import de.viper.survivalplus.fun.FunChallengeManager;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
public class ChallengeCollectListener implements Listener {
private final FunChallengeManager challengeManager;
private final NamespacedKey droppedKey;
public ChallengeCollectListener(FunChallengeManager challengeManager, NamespacedKey droppedKey) {
this.challengeManager = challengeManager;
this.droppedKey = droppedKey;
}
@EventHandler
public void onItemDrop(PlayerDropItemEvent event) {
ItemStack dropped = event.getItemDrop().getItemStack();
ItemMeta meta = dropped.getItemMeta();
if (meta != null) {
meta.getPersistentDataContainer().set(droppedKey, PersistentDataType.INTEGER, 1);
dropped.setItemMeta(meta);
}
}
@EventHandler
public void onPlayerPickup(PlayerPickupItemEvent event) {
FunChallenge challenge = challengeManager.getActiveChallenge();
if (challenge == null) return;
Player player = event.getPlayer();
ItemStack item = event.getItem().getItemStack();
ItemMeta meta = item.getItemMeta();
if (meta != null && meta.getPersistentDataContainer().has(droppedKey, PersistentDataType.INTEGER)) {
return; // Item aus Inventar gedroppt, nicht zählen
}
if (item.getType().name().equalsIgnoreCase(challenge.getItem())) {
int current = challengeManager.getGlobalProgress(challenge.getName());
current += item.getAmount();
challengeManager.setGlobalProgress(challenge.getName(), current);
if (current >= challenge.getAmount()) {
player.getServer().broadcastMessage("§aChallenge \"" + challenge.getName() + "\" geschafft!");
giveReward(player, challenge.getReward());
challenge.setActive(false);
challengeManager.resetProgress(challenge.getName());
} else {
player.sendMessage("§eFortschritt: " + current + "/" + challenge.getAmount() + " " + challenge.getItem());
}
}
}
private void giveReward(Player player, String reward) {
if (reward == null || reward.isEmpty()) return;
String[] parts = reward.split(",");
if (parts.length != 2) return;
String itemName = parts[0];
int amount;
try {
amount = Integer.parseInt(parts[1]);
} catch (NumberFormatException e) {
return;
}
Material material = Material.matchMaterial(itemName);
if (material == null) return;
ItemStack rewardItem = new ItemStack(material, amount);
player.getInventory().addItem(rewardItem);
player.sendMessage("§aDu hast deine Belohnung erhalten: " + amount + "x " + itemName);
}
}

View File

@@ -0,0 +1,70 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.fun.FunChallenge;
import de.viper.survivalplus.fun.FunChallengeManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.FurnaceExtractEvent;
import org.bukkit.inventory.ItemStack;
public class ChallengeSmeltListener implements Listener {
private final FunChallengeManager challengeManager;
public ChallengeSmeltListener(FunChallengeManager challengeManager) {
this.challengeManager = challengeManager;
}
@EventHandler
public void onFurnaceExtract(FurnaceExtractEvent event) {
Player player = (Player) event.getPlayer();
FunChallenge active = challengeManager.getActiveChallenge();
if (active == null) return;
if (!"COLLECT".equalsIgnoreCase(active.getType())) return;
String requiredItem = active.getItem();
int requiredAmount = active.getAmount();
String smeltedItem = event.getItemType().name();
if (!smeltedItem.equalsIgnoreCase(requiredItem)) return;
int current = challengeManager.getGlobalProgress(active.getName());
current += event.getItemAmount();
challengeManager.setGlobalProgress(active.getName(), current);
if (current >= requiredAmount) {
player.getServer().broadcastMessage("§aChallenge \"" + active.getName() + "\" geschafft!");
giveReward(player, active.getReward());
active.setActive(false);
challengeManager.resetProgress(active.getName());
} else {
player.sendMessage("§eFortschritt: " + current + "/" + requiredAmount + " " + requiredItem);
}
}
private void giveReward(Player player, String reward) {
if (reward == null || reward.isEmpty()) return;
String[] parts = reward.split(",");
if (parts.length != 2) return;
String itemName = parts[0];
int amount;
try {
amount = Integer.parseInt(parts[1]);
} catch (NumberFormatException e) {
return;
}
Material material = Material.matchMaterial(itemName);
if (material == null) return;
ItemStack rewardItem = new ItemStack(material, amount);
player.getInventory().addItem(rewardItem);
player.sendMessage("§aDu hast deine Belohnung erhalten: " + amount + "x " + itemName);
}
}

View File

@@ -0,0 +1,26 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.Manager.BlockManager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
public class ChatBlockListener implements Listener {
private final BlockManager blockManager;
public ChatBlockListener(BlockManager blockManager) {
this.blockManager = blockManager;
}
@EventHandler
public void onChat(AsyncPlayerChatEvent event) {
Player sender = event.getPlayer();
event.getRecipients().removeIf(recipient ->
blockManager.hasBlocked(recipient, sender) || blockManager.hasBlocked(sender, recipient)
);
}
}

View File

@@ -0,0 +1,46 @@
package de.viper.survivalplus.listeners;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class DebugArmorStandListener implements Listener {
private static final double MAX_DISTANCE = 3.0;
@EventHandler
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
if (event.getRightClicked() instanceof ArmorStand armorStand) {
Player player = event.getPlayer();
if (armorStand.getScoreboardTags().contains("debugArmorStand")) {
if (armorStand.getLocation().distance(player.getLocation()) <= MAX_DISTANCE) {
armorStand.remove();
player.sendMessage("§aDebug-ArmorStand wurde entfernt.");
event.setCancelled(true);
} else {
player.sendMessage("§cDieser Debug-ArmorStand ist zu weit entfernt.");
}
}
}
}
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (event.getEntity() instanceof ArmorStand armorStand) {
if (armorStand.getScoreboardTags().contains("debugArmorStand")) {
if (event.getDamager() instanceof Player player) {
if (armorStand.getLocation().distance(player.getLocation()) <= MAX_DISTANCE) {
armorStand.remove();
player.sendMessage("§aDebug-ArmorStand wurde zerstört.");
event.setCancelled(true);
} else {
player.sendMessage("§cDieser Debug-ArmorStand ist zu weit entfernt.");
}
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
package de.viper.survivalplus.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.Material;
import org.bukkit.inventory.PlayerInventory;
public class FirstJoinListener implements Listener {
@EventHandler
public void onPlayerFirstJoin(PlayerJoinEvent event) {
if (event.getPlayer().hasPlayedBefore()) {
return; // Nur für den ersten Join
}
// Erstelle ein ItemStack für einen Trank (z.B. Heiltrank)
ItemStack potion = new ItemStack(Material.POTION, 1);
if (potion.getItemMeta() instanceof PotionMeta) {
PotionMeta potionMeta = (PotionMeta) potion.getItemMeta();
PotionEffect effect = new PotionEffect(PotionEffectType.REGENERATION, 600, 1);
potionMeta.addCustomEffect(effect, true);
potion.setItemMeta(potionMeta);
}
// Füge das Trank-Item zum Inventar des Spielers hinzu
PlayerInventory inventory = event.getPlayer().getInventory();
inventory.addItem(potion);
}
}

View File

@@ -0,0 +1,26 @@
package de.viper.survivalplus;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class ForceSurvivalListener implements Listener {
private final SurvivalPlus plugin;
public ForceSurvivalListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
// Spieler in Survival setzen
if (player.getGameMode() != GameMode.SURVIVAL) {
player.setGameMode(GameMode.SURVIVAL);
player.sendMessage(plugin.getMessage("force-survival.join-message"));
}
}
}

View File

@@ -0,0 +1,186 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class GraveListener implements Listener {
private final SurvivalPlus plugin;
private final HashMap<Location, UUID> graveOwners = new HashMap<>();
private final HashMap<Location, UUID> graveArmorStands = new HashMap<>();
private long despawnTime;
public GraveListener(SurvivalPlus plugin) {
this.plugin = plugin;
reloadConfig(plugin.getConfig());
}
public void reloadConfig(FileConfiguration config) {
this.despawnTime = config.getLong("graves.despawn-time", 1800);
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
if (event.getKeepInventory()) return;
Player player = event.getEntity();
UUID playerId = player.getUniqueId();
FileConfiguration gravesConfig = plugin.getGravesConfig();
FileConfiguration lang = plugin.getLangConfig();
Location deathLocation = player.getLocation().clone();
Block block = deathLocation.getBlock();
// Save to graves.yml
gravesConfig.set("graves." + playerId + ".world", deathLocation.getWorld().getName());
gravesConfig.set("graves." + playerId + ".x", deathLocation.getX());
gravesConfig.set("graves." + playerId + ".y", deathLocation.getY());
gravesConfig.set("graves." + playerId + ".z", deathLocation.getZ());
plugin.saveGravesConfig();
// Suche Platz für Truhe
if (block.isEmpty() || block.getType().isAir()) {
block.setType(Material.CHEST);
} else {
for (int i = 1; i <= 10; i++) {
Block above = block.getRelative(0, i, 0);
if (above.isEmpty() || above.getType().isAir()) {
above.setType(Material.CHEST);
block = above;
deathLocation = block.getLocation();
break;
}
}
}
if (block.getType() == Material.CHEST) {
Chest chest = (Chest) block.getState();
for (ItemStack item : event.getDrops()) {
if (item != null && item.getType() != Material.AIR) {
chest.getInventory().addItem(item);
}
}
event.getDrops().clear();
graveOwners.put(block.getLocation(), playerId);
// Nachricht an Spieler
player.sendMessage(String.format(
lang.getString("graves.created", "§aDein Grab wurde bei x=%.2f, y=%.2f, z=%.2f erstellt!"),
deathLocation.getX(),
deathLocation.getY(),
deathLocation.getZ()
));
// ArmorStand mit "Grab von <Name>"
Location standLocation = deathLocation.clone().add(0.5, 1.2, 0.5);
ArmorStand stand = deathLocation.getWorld().spawn(standLocation, ArmorStand.class);
stand.setVisible(false);
stand.setCustomName("§cGrab von " + player.getName());
stand.setCustomNameVisible(true);
stand.setMarker(true);
stand.setGravity(false);
stand.setInvulnerable(true);
stand.setSilent(true);
stand.setSmall(true);
// Speichere ArmorStand UUID
graveArmorStands.put(block.getLocation(), stand.getUniqueId());
// Entfernen nach Zeit
if (despawnTime >= 0) {
final Block graveBlock = block;
final Location graveLocation = graveBlock.getLocation();
final Player deadPlayer = player;
final FileConfiguration langConfigFinal = lang;
new BukkitRunnable() {
@Override
public void run() {
if (graveBlock.getType() == Material.CHEST) {
graveBlock.setType(Material.AIR);
graveOwners.remove(graveLocation);
removeArmorStand(graveLocation);
deadPlayer.sendMessage(String.format(
langConfigFinal.getString("graves.despawned", "§cDein Grab bei x=%.2f, y=%.2f, z=%.2f ist verschwunden!"),
graveLocation.getX(),
graveLocation.getY(),
graveLocation.getZ()
));
}
}
}.runTaskLater(plugin, despawnTime * 20L);
}
// Überwache, ob Truhe geleert wurde
final Block chestBlockFinal = block;
final Player playerFinal = player;
final FileConfiguration langFinal = lang;
new BukkitRunnable() {
@Override
public void run() {
if (chestBlockFinal.getType() != Material.CHEST) {
cancel();
return;
}
Chest c = (Chest) chestBlockFinal.getState();
boolean empty = true;
for (ItemStack item : c.getInventory().getContents()) {
if (item != null && item.getType() != Material.AIR) {
empty = false;
break;
}
}
if (empty) {
c.getBlock().setType(Material.AIR);
graveOwners.remove(c.getLocation());
removeArmorStand(c.getLocation());
playerFinal.sendMessage(String.format(
langFinal.getString("graves.emptied", "§7Dein Grab bei x=%.2f, y=%.2f, z=%.2f wurde geleert."),
(double)c.getX(),
(double)c.getY(),
(double)c.getZ()
));
cancel();
}
}
}.runTaskTimer(plugin, 20L, 60L);
}
}
private void removeArmorStand(Location chestLocation) {
UUID standId = graveArmorStands.remove(chestLocation);
if (standId == null) return;
Entity entity = Bukkit.getEntity(standId);
if (entity != null && entity instanceof ArmorStand) {
entity.remove();
}
}
public boolean isOwner(Player player, Location location) {
return graveOwners.getOrDefault(location, null) != null &&
graveOwners.get(location).equals(player.getUniqueId());
}
}

View File

@@ -0,0 +1,69 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.logging.Level;
public class InventoryClickListener implements Listener {
private final SurvivalPlus plugin;
public InventoryClickListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
FileConfiguration lang = plugin.getLangConfig();
String guiTitle = event.getView().getTitle();
String homeGuiTitle = lang.getString("homelist.gui-title", "Deine Homes");
if (!guiTitle.equals(homeGuiTitle)) {
plugin.getLogger().log(Level.FINE, "Ignoriere Klick in GUI mit Titel: " + guiTitle);
return;
}
plugin.getLogger().log(Level.FINE, "Verarbeite Klick in Home-Liste GUI für Spieler: " + event.getWhoClicked().getName());
event.setCancelled(true);
if (!(event.getWhoClicked() instanceof Player) || event.getCurrentItem() == null) {
return;
}
Player player = (Player) event.getWhoClicked();
String homeName = event.getCurrentItem().getItemMeta().getDisplayName().replace("§a", "");
String path = "homes." + player.getUniqueId() + "." + homeName.toLowerCase();
FileConfiguration homes = plugin.getHomesConfig();
if (!homes.contains(path)) {
player.sendMessage(lang.getString("homelist.home-deleted", "§cDieses Home existiert nicht mehr!"));
player.closeInventory();
return;
}
String worldName = homes.getString(path + ".world");
World world = plugin.getServer().getWorld(worldName);
if (world == null) {
player.sendMessage(lang.getString("homelist.world-not-found", "§cDie Welt dieses Homes existiert nicht!"));
player.closeInventory();
return;
}
Location loc = new Location(
world,
homes.getDouble(path + ".x"),
homes.getDouble(path + ".y"),
homes.getDouble(path + ".z"),
(float) homes.getDouble(path + ".yaw"),
(float) homes.getDouble(path + ".pitch")
);
player.teleport(loc);
player.sendMessage(lang.getString("homelist.teleported", "§aZum Home %name% teleportiert!")
.replace("%name%", homeName));
player.closeInventory();
}
}

View File

@@ -0,0 +1,53 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class LoginListener implements Listener {
private final SurvivalPlus plugin;
public LoginListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
if (!player.hasPlayedBefore()) {
// Erster Login
sendWelcomeMessage(player, true);
} else {
// Wiederkehrer
sendWelcomeMessage(player, false);
}
}
private void sendWelcomeMessage(Player player, boolean firstJoin) {
String messageKey = firstJoin ? "welcome.first-join-message" : "welcome.return-message";
String soundKey = firstJoin ? "welcome.first-join-sound" : "welcome.return-sound";
String volumeKey = firstJoin ? "welcome.first-join-sound-volume" : "welcome.return-sound-volume";
String pitchKey = firstJoin ? "welcome.first-join-sound-pitch" : "welcome.return-sound-pitch";
String rawMessage = plugin.getLangConfig().getString(messageKey, "&6Willkommen, &e{player}&6!");
String message = ChatColor.translateAlternateColorCodes('&', rawMessage.replace("{player}", player.getName()));
player.sendMessage(message);
String soundName = plugin.getLangConfig().getString(soundKey, "ENTITY_PLAYER_LEVELUP");
float volume = (float) plugin.getLangConfig().getDouble(volumeKey, 1.0);
float pitch = (float) plugin.getLangConfig().getDouble(pitchKey, 1.0);
try {
Sound sound = Sound.valueOf(soundName);
player.playSound(player.getLocation(), sound, volume, pitch);
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Ungültiger Sound-Name in lang.yml: " + soundName);
}
}
}

View File

@@ -0,0 +1,181 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Chunk;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Animals;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class MobCapListener implements Listener {
private final SurvivalPlus plugin;
private boolean enabled;
private int maxAnimalsPerChunk;
private final Map<String, Map<UUID, UUID>> chunkAnimalMap = new HashMap<>(); // Chunk -> Tier-UUID -> Spieler-UUID
public MobCapListener(SurvivalPlus plugin, FileConfiguration config) {
this.plugin = plugin;
reloadConfig(config);
}
public void reloadConfig(FileConfiguration config) {
this.enabled = config.getBoolean("mob-cap.enabled", true);
this.maxAnimalsPerChunk = config.getInt("mob-cap.max-animals-per-chunk", 10);
plugin.getLogger().info("MobCapListener: enabled=" + enabled + ", maxAnimalsPerChunk=" + maxAnimalsPerChunk);
// Bereinige bestehende Daten
chunkAnimalMap.clear();
if (!enabled) {
plugin.getMobCapConfig().set("mobcap", null); // Bereinige mobcap.yml
plugin.saveMobCapConfig();
plugin.getLogger().info("MobCapListener: Daten bereinigt, da enabled=false");
return;
}
// Lade Zuordnungen aus mobcap.yml
FileConfiguration mobCapConfig = plugin.getMobCapConfig();
if (mobCapConfig.contains("mobcap")) {
for (String chunkKey : mobCapConfig.getConfigurationSection("mobcap").getKeys(false)) {
Map<UUID, UUID> animalToPlayer = new HashMap<>();
for (String animalIdStr : mobCapConfig.getConfigurationSection("mobcap." + chunkKey).getKeys(false)) {
try {
UUID animalId = UUID.fromString(animalIdStr);
String playerIdStr = mobCapConfig.getString("mobcap." + chunkKey + "." + animalIdStr);
if (playerIdStr != null) {
UUID playerId = UUID.fromString(playerIdStr);
Entity entity = plugin.getServer().getEntity(animalId);
if (entity instanceof Animals) {
animalToPlayer.put(animalId, playerId);
} else {
// Entferne ungültige Einträge
mobCapConfig.set("mobcap." + chunkKey + "." + animalIdStr, null);
}
}
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Ungültige UUID in mobcap.yml: " + animalIdStr);
}
}
chunkAnimalMap.put(chunkKey, animalToPlayer);
}
}
// Scanne alle Welten nach Tieren
for (org.bukkit.World world : plugin.getServer().getWorlds()) {
for (Chunk chunk : world.getLoadedChunks()) {
String chunkKey = getChunkKey(chunk);
Map<UUID, UUID> animalToPlayer = chunkAnimalMap.computeIfAbsent(chunkKey, k -> new HashMap<>());
for (Entity entity : chunk.getEntities()) {
if (entity instanceof Animals) {
UUID id = entity.getUniqueId();
if (!animalToPlayer.containsKey(id)) {
animalToPlayer.put(id, null); // Kein Spieler zugeordnet
}
}
}
}
}
// Speichere aktualisierte mobcap.yml
saveChunkAnimalMap();
plugin.getLogger().info("MobCapListener: Nach Reload " + chunkAnimalMap.size() + " Chunks mit Tieren gefunden.");
}
@EventHandler
public void onCreatureSpawn(CreatureSpawnEvent event) {
if (!enabled) return;
LivingEntity entity = event.getEntity();
if (!(entity instanceof Animals)) return;
Chunk chunk = entity.getLocation().getChunk();
String chunkKey = getChunkKey(chunk);
Map<UUID, UUID> animalToPlayer = chunkAnimalMap.computeIfAbsent(chunkKey, k -> new HashMap<>());
int animalCount = animalToPlayer.size();
if (animalCount >= maxAnimalsPerChunk) {
event.setCancelled(true);
plugin.getLogger().info("Spawn von " + entity.getType() + " in Chunk " + chunkKey + " verhindert: Limit von " + maxAnimalsPerChunk + " erreicht.");
// HINWEIS: Wenn du dem Züchter eine Nachricht schicken willst, nutze EntityBreedEvent
// Hier ist das nicht möglich, weil man beim Spawn keinen Spielerzugriff hat
} else {
animalToPlayer.put(entity.getUniqueId(), null); // Kein Spieler zugeordnet
saveChunkAnimalMap();
}
}
@EventHandler
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!enabled) return;
if (!(event.getRightClicked() instanceof Animals)) return;
Player player = event.getPlayer();
Entity entity = event.getRightClicked();
Chunk chunk = entity.getLocation().getChunk();
String chunkKey = getChunkKey(chunk);
Map<UUID, UUID> animalToPlayer = chunkAnimalMap.computeIfAbsent(chunkKey, k -> new HashMap<>());
int animalCount = animalToPlayer.size();
if (animalCount >= maxAnimalsPerChunk) {
event.setCancelled(true);
player.sendMessage(plugin.getMessage("mob-cap.limit-reached").replace("%max%", String.valueOf(maxAnimalsPerChunk)));
plugin.getLogger().info("Interaktion mit " + entity.getType() + " in Chunk " + chunkKey + " verhindert: Limit von " + maxAnimalsPerChunk + " erreicht.");
} else {
animalToPlayer.put(entity.getUniqueId(), player.getUniqueId());
saveChunkAnimalMap();
}
}
@EventHandler
public void onEntityDeath(EntityDeathEvent event) {
if (!enabled) return;
if (!(event.getEntity() instanceof Animals)) return;
LivingEntity entity = event.getEntity();
Chunk chunk = entity.getLocation().getChunk();
String chunkKey = getChunkKey(chunk);
Map<UUID, UUID> animalToPlayer = chunkAnimalMap.get(chunkKey);
if (animalToPlayer != null) {
UUID animalId = entity.getUniqueId();
animalToPlayer.remove(animalId);
if (animalToPlayer.isEmpty()) {
chunkAnimalMap.remove(chunkKey);
}
saveChunkAnimalMap();
plugin.getLogger().info("Tier " + entity.getType() + " in Chunk " + chunkKey + " gestorben. Verbleibende Tiere: " + animalToPlayer.size());
}
}
private String getChunkKey(Chunk chunk) {
return chunk.getWorld().getName() + "," + chunk.getX() + "," + chunk.getZ();
}
private void saveChunkAnimalMap() {
FileConfiguration mobCapConfig = plugin.getMobCapConfig();
mobCapConfig.set("mobcap", null); // Bereinige vorherige Daten
for (Map.Entry<String, Map<UUID, UUID>> entry : chunkAnimalMap.entrySet()) {
String chunkKey = entry.getKey();
Map<UUID, UUID> animalToPlayer = entry.getValue();
for (Map.Entry<UUID, UUID> animalEntry : animalToPlayer.entrySet()) {
mobCapConfig.set("mobcap." + chunkKey + "." + animalEntry.getKey().toString(),
animalEntry.getValue() != null ? animalEntry.getValue().toString() : null);
}
}
plugin.saveMobCapConfig();
}
}

View File

@@ -0,0 +1,253 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.Material;
import java.util.*;
public class MobLeashLimitListener implements Listener {
private final SurvivalPlus plugin;
private boolean enabled;
private int maxLeashCount;
private final Map<UUID, Set<UUID>> leashedEntities = new HashMap<>();
private final Map<UUID, Integer> leashCounts = new HashMap<>();
private final Map<UUID, UUID> entityToPlayer = new HashMap<>();
public MobLeashLimitListener(SurvivalPlus plugin, FileConfiguration config) {
this.plugin = plugin;
reloadConfig(config);
}
public void reloadConfig(FileConfiguration config) {
this.enabled = config.getBoolean("mob-leash-limit.enabled", true);
this.maxLeashCount = config.getInt("mob-leash-limit.max-leash-count", 5);
plugin.getLogger().info("MobLeashLimitListener: enabled=" + enabled + ", maxLeashCount=" + maxLeashCount);
// Bereinige bestehende Daten
leashedEntities.clear();
leashCounts.clear();
entityToPlayer.clear();
if (!enabled) {
plugin.getLeashesConfig().set("leashes", null); // Bereinige leashes.yml
plugin.saveLeashesConfig();
plugin.getLogger().info("MobLeashLimitListener: Daten bereinigt, da enabled=false");
return;
}
// Lade Zuordnungen aus leashes.yml
FileConfiguration leashesConfig = plugin.getLeashesConfig();
if (leashesConfig.contains("leashes")) {
for (String entityIdStr : leashesConfig.getConfigurationSection("leashes").getKeys(false)) {
UUID entityId;
try {
entityId = UUID.fromString(entityIdStr);
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Ungültige UUID in leashes.yml: " + entityIdStr);
continue;
}
String playerIdStr = leashesConfig.getString("leashes." + entityIdStr);
if (playerIdStr != null) {
try {
UUID playerId = UUID.fromString(playerIdStr);
LivingEntity entity = (LivingEntity) plugin.getServer().getEntity(entityId);
if (entity != null && entity.isLeashed()) {
Set<UUID> playerLeashedEntities = leashedEntities.computeIfAbsent(playerId, k -> new HashSet<>());
playerLeashedEntities.add(entityId);
leashCounts.put(playerId, playerLeashedEntities.size());
entityToPlayer.put(entityId, playerId);
} else {
// Entferne ungültige Einträge aus leashes.yml
leashesConfig.set("leashes." + entityIdStr, null);
}
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Ungültige Spieler-UUID in leashes.yml für Entity " + entityIdStr + ": " + playerIdStr);
}
}
}
}
// Scanne alle Welten nach angeleinten Tieren, die noch nicht in leashes.yml sind
for (org.bukkit.World world : plugin.getServer().getWorlds()) {
for (LivingEntity entity : world.getLivingEntities()) {
if (entity.isLeashed() && !entityToPlayer.containsKey(entity.getUniqueId())) {
// Nur Tiere zählen, die von einem Spieler gehalten werden (für neue Leashes)
if (entity.getLeashHolder() instanceof Player) {
Player player = (Player) entity.getLeashHolder();
UUID playerId = player.getUniqueId();
UUID entityId = entity.getUniqueId();
Set<UUID> playerLeashedEntities = leashedEntities.computeIfAbsent(playerId, k -> new HashSet<>());
playerLeashedEntities.add(entityId);
leashCounts.put(playerId, playerLeashedEntities.size());
entityToPlayer.put(entityId, playerId);
// Speichere in leashes.yml
leashesConfig.set("leashes." + entityId.toString(), playerId.toString());
}
}
}
}
// Prüfe, ob das neue Limit überschritten wird
for (Map.Entry<UUID, Set<UUID>> entry : leashedEntities.entrySet()) {
UUID playerId = entry.getKey();
Set<UUID> playerLeashedEntities = entry.getValue();
if (playerLeashedEntities.size() > maxLeashCount) {
Player player = plugin.getServer().getPlayer(playerId);
if (player != null && player.isOnline()) {
player.sendMessage(plugin.getMessage("mob-leash-limit.limit-adjusted")
.replace("%count%", String.valueOf(playerLeashedEntities.size()))
.replace("%max%", String.valueOf(maxLeashCount)));
}
}
}
// Entferne leere Einträge
leashedEntities.entrySet().removeIf(entry -> entry.getValue().isEmpty());
leashCounts.entrySet().removeIf(entry -> entry.getValue() == 0);
// Speichere aktualisierte leashes.yml
plugin.saveLeashesConfig();
plugin.getLogger().info("MobLeashLimitListener: Nach Reload " + leashedEntities.size() + " Spieler mit angeleinten Tieren gefunden.");
}
@EventHandler
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!enabled) return;
Player player = event.getPlayer();
ItemStack itemInHand = player.getInventory().getItemInMainHand();
UUID playerId = player.getUniqueId();
LivingEntity entity = (LivingEntity) event.getRightClicked();
UUID entityId = entity.getUniqueId();
if (itemInHand != null && itemInHand.getType() == Material.LEAD) {
Set<UUID> playerLeashedEntities = leashedEntities.computeIfAbsent(playerId, k -> new HashSet<>());
int currentCount = playerLeashedEntities.size();
plugin.getLogger().info("PlayerInteractEntity: player=" + player.getName() + ", currentCount=" + currentCount + ", maxLeashCount=" + maxLeashCount);
if (playerLeashedEntities.contains(entityId)) {
// Ableinen
playerLeashedEntities.remove(entityId);
leashCounts.put(playerId, currentCount - 1);
entityToPlayer.remove(entityId);
plugin.getLeashesConfig().set("leashes." + entityId.toString(), null);
plugin.saveLeashesConfig();
player.sendMessage(plugin.getMessage("mob-leash-limit.unleashed")
.replace("%count%", String.valueOf(currentCount - 1)));
// Entferne leere Einträge
if (playerLeashedEntities.isEmpty()) {
leashedEntities.remove(playerId);
leashCounts.remove(playerId);
}
} else {
// Anleinen
if (currentCount >= maxLeashCount) {
player.sendMessage(plugin.getMessage("mob-leash-limit.max-reached")
.replace("%count%", String.valueOf(maxLeashCount)));
event.setCancelled(true);
} else {
playerLeashedEntities.add(entityId);
leashCounts.put(playerId, currentCount + 1);
entityToPlayer.put(entityId, playerId);
plugin.getLeashesConfig().set("leashes." + entityId.toString(), playerId.toString());
plugin.saveLeashesConfig();
player.sendMessage(plugin.getMessage("mob-leash-limit.leashed")
.replace("%count%", String.valueOf(currentCount + 1)));
}
}
}
}
@EventHandler
public void onEntityDeath(EntityDeathEvent event) {
if (!enabled) {
UUID entityId = event.getEntity().getUniqueId();
entityToPlayer.remove(entityId);
plugin.getLeashesConfig().set("leashes." + entityId.toString(), null);
plugin.saveLeashesConfig();
return;
}
LivingEntity entity = event.getEntity();
UUID entityId = entity.getUniqueId();
UUID playerId = entityToPlayer.remove(entityId);
if (playerId != null) {
Set<UUID> playerLeashedEntities = leashedEntities.getOrDefault(playerId, new HashSet<>());
playerLeashedEntities.remove(entityId);
int newCount = playerLeashedEntities.size();
leashCounts.put(playerId, newCount);
// Entferne aus leashes.yml
plugin.getLeashesConfig().set("leashes." + entityId.toString(), null);
plugin.saveLeashesConfig();
// Entferne leere Einträge
if (playerLeashedEntities.isEmpty()) {
leashedEntities.remove(playerId);
leashCounts.remove(playerId);
}
Player player = plugin.getServer().getPlayer(playerId);
if (player != null && player.isOnline()) {
player.sendMessage(plugin.getMessage("mob-leash-limit.entity-died")
.replace("%count%", String.valueOf(newCount)));
}
}
}
public void updateLeashCount(Player player) {
UUID playerId = player.getUniqueId();
Set<UUID> playerLeashedEntities = leashedEntities.getOrDefault(playerId, new HashSet<>());
// Entferne nicht existierende oder nicht angeleinte Entities
playerLeashedEntities.removeIf(entityId -> {
LivingEntity entity = (LivingEntity) plugin.getServer().getEntity(entityId);
if (entity == null || !entity.isLeashed()) {
plugin.getLeashesConfig().set("leashes." + entityId.toString(), null);
return true;
}
return false;
});
int currentCount = playerLeashedEntities.size();
leashCounts.put(playerId, currentCount);
// Aktualisiere entityToPlayer-Map
entityToPlayer.entrySet().removeIf(entry -> entry.getValue().equals(playerId) && !playerLeashedEntities.contains(entry.getKey()));
// Entferne leere Einträge
if (playerLeashedEntities.isEmpty()) {
leashedEntities.remove(playerId);
leashCounts.remove(playerId);
}
// Falls disabled, bereinige die Daten für diesen Spieler
if (!enabled) {
playerLeashedEntities.clear();
leashedEntities.remove(playerId);
leashCounts.remove(playerId);
entityToPlayer.entrySet().removeIf(entry -> entry.getValue().equals(playerId));
plugin.getLeashesConfig().set("leashes", null);
plugin.saveLeashesConfig();
}
plugin.getLogger().info("updateLeashCount: player=" + player.getName() + ", currentCount=" + currentCount);
}
public int getLeashCount(Player player) {
updateLeashCount(player);
return leashCounts.getOrDefault(player.getUniqueId(), 0);
}
}

View File

@@ -0,0 +1,179 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class NewbieProtectionListener implements Listener {
private final SurvivalPlus plugin;
private final boolean enabled;
private final int durationMinutes;
// Maps für Zeiten und BossBars
private final Map<UUID, Integer> remainingSeconds = new HashMap<>();
private final Map<UUID, BossBar> bossBars = new HashMap<>();
// YAML Datei
private File dataFile;
private FileConfiguration dataConfig;
public NewbieProtectionListener(SurvivalPlus plugin) {
this.plugin = plugin;
this.enabled = plugin.getConfig().getBoolean("newbie-protection.enabled", true);
this.durationMinutes = plugin.getConfig().getInt("newbie-protection.duration-minutes", 30);
if (!plugin.getDataFolder().exists()) {
plugin.getDataFolder().mkdirs();
}
loadData();
if (enabled) {
startTimer();
}
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if (!enabled) return;
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
// Falls nicht gespeichert, neue Zeit einstellen
remainingSeconds.putIfAbsent(uuid, durationMinutes * 60);
// Bossbar erstellen/anzeigen
BossBar bar = Bukkit.createBossBar(
ChatColor.GREEN + "Neulingsschutz: " + formatTime(remainingSeconds.get(uuid)),
BarColor.GREEN,
BarStyle.SOLID
);
bar.addPlayer(player);
bossBars.put(uuid, bar);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
if (!enabled) return;
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
// Bossbar entfernen, aber Zeit bleibt in Map bestehen
BossBar bar = bossBars.remove(uuid);
if (bar != null) {
bar.removeAll();
}
saveData(); // Beim Verlassen direkt speichern
}
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (!enabled) return;
if (!(event.getEntity() instanceof Player)) return;
Player victim = (Player) event.getEntity();
UUID vid = victim.getUniqueId();
Integer timeLeft = remainingSeconds.get(vid);
if (timeLeft != null && timeLeft > 0) {
event.setCancelled(true);
victim.sendMessage(ChatColor.GREEN + "Du bist noch im Neulingsschutz!");
if (event.getDamager() instanceof Player) {
((Player) event.getDamager()).sendMessage(ChatColor.RED + victim.getName() + " ist noch geschützt!");
}
}
}
private void startTimer() {
new BukkitRunnable() {
@Override
public void run() {
for (UUID uuid : new HashSet<>(remainingSeconds.keySet())) {
Player p = Bukkit.getPlayer(uuid);
if (p == null || !p.isOnline()) {
// Spieler offline → Zeit pausiert
continue;
}
int timeLeft = remainingSeconds.getOrDefault(uuid, 0);
if (timeLeft <= 0) {
// Ablauf: Bossbar weg + Map clean
BossBar bar = bossBars.remove(uuid);
if (bar != null) bar.removeAll();
remainingSeconds.remove(uuid);
continue;
}
// Zeit runterzählen
timeLeft--;
remainingSeconds.put(uuid, timeLeft);
// Bossbar updaten
BossBar bar = bossBars.get(uuid);
if (bar != null) {
bar.setTitle(ChatColor.GREEN + "Neulingsschutz: " + formatTime(timeLeft));
bar.setProgress(Math.max(0, timeLeft / (float) (durationMinutes * 60)));
}
}
saveData(); // zyklisch speichern
}
}.runTaskTimer(plugin, 20L, 20L);
}
// ---------- Datei Handling ----------
private void loadData() {
dataFile = new File(plugin.getDataFolder(), "newbieprotection.yml");
if (!dataFile.exists()) {
try {
dataFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
for (String key : dataConfig.getKeys(false)) {
try {
UUID uuid = UUID.fromString(key);
int sec = dataConfig.getInt(key);
remainingSeconds.put(uuid, sec);
} catch (IllegalArgumentException ignored) {}
}
}
// WICHTIG: Public gemacht, damit von SurvivalPlus.java aufrufbar
public void saveData() {
if (dataConfig == null) return;
for (Map.Entry<UUID, Integer> entry : remainingSeconds.entrySet()) {
dataConfig.set(entry.getKey().toString(), entry.getValue());
}
try {
dataConfig.save(dataFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private String formatTime(int totalSec) {
int min = totalSec / 60;
int sec = totalSec % 60;
return String.format("%02d:%02d", min, sec);
}
}

View File

@@ -0,0 +1,51 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.entity.Player;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NickLoadListener implements Listener {
private final SurvivalPlus plugin;
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
public NickLoadListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
if (rawNick != null && !rawNick.isEmpty()) {
String coloredNick = translateColors(rawNick);
String finalNick = "§f[" + coloredNick + "§f]";
player.setDisplayName(finalNick);
player.setPlayerListName(finalNick);
}
}
private String translateColors(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();
}
}

View File

@@ -0,0 +1,139 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class OreAlarmListener implements Listener {
private static final long TIME_FRAME_MILLIS = 30 * 1000;
private final SurvivalPlus plugin;
private final Map<UUID, Map<Material, OreData>> playerOreData = new HashMap<>();
private FileConfiguration config;
// Schwellenwert wird jetzt aus der Config geladen (Fallback DEFAULT_THRESHOLD)
private int threshold;
public OreAlarmListener(SurvivalPlus plugin) {
this.plugin = plugin;
this.config = plugin.getConfig();
loadSettings();
}
private void loadSettings() {
this.threshold = config.getInt("ore-alarm.threshold", 10);
}
/**
* Reloadet die Config, lädt die Einstellungen neu und leert gespeicherte Daten.
*/
public void reloadConfig(FileConfiguration newConfig) {
this.config = newConfig;
loadSettings();
playerOreData.clear();
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Player player = event.getPlayer();
Material blockType = event.getBlock().getType();
if (!isMonitoredOre(blockType)) {
return;
}
UUID playerId = player.getUniqueId();
long now = System.currentTimeMillis();
playerOreData.putIfAbsent(playerId, new HashMap<>());
Map<Material, OreData> oreMap = playerOreData.get(playerId);
oreMap.putIfAbsent(blockType, new OreData(0, now));
OreData data = oreMap.get(blockType);
if (now - data.startTime > TIME_FRAME_MILLIS) {
data.count = 1;
data.startTime = now;
} else {
data.count++;
}
oreMap.put(blockType, data);
int threshold = calculateDynamicThreshold(playerId, blockType);
if (data.count >= threshold) {
String oreName = prettifyMaterialName(blockType);
String rawMessage = plugin.getLangConfig().getString("orealarm.message",
"§c[Erz-Alarm] Spieler §e%player% §chat in %seconds% Sekunden ungewöhnlich viele %ore% abgebaut: §e%count%");
String message = rawMessage
.replace("%player%", player.getName())
.replace("%ore%", oreName)
.replace("%count%", Integer.toString(data.count))
.replace("%seconds%", Long.toString(TIME_FRAME_MILLIS / 1000));
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.isOp() || p.hasPermission("survivalplus.orealarm"))
.forEach(p -> p.sendMessage(message));
data.count = 0;
data.startTime = now;
}
}
private boolean isMonitoredOre(Material material) {
switch (material) {
case DIAMOND_ORE:
case DEEPSLATE_DIAMOND_ORE:
case REDSTONE_ORE:
case DEEPSLATE_REDSTONE_ORE:
case GOLD_ORE:
case DEEPSLATE_GOLD_ORE:
case IRON_ORE:
case DEEPSLATE_IRON_ORE:
case LAPIS_ORE:
case DEEPSLATE_LAPIS_ORE:
case EMERALD_ORE:
case DEEPSLATE_EMERALD_ORE:
return true;
default:
return false;
}
}
private int calculateDynamicThreshold(UUID playerId, Material ore) {
// Nutzt jetzt das geladene threshold, kann später erweitert werden
return threshold;
}
private String prettifyMaterialName(Material material) {
String name = material.name().toLowerCase();
name = name.replace("_ore", " Erz");
name = name.replace("deepslate ", "Tiefgeschichtetes ");
name = Character.toUpperCase(name.charAt(0)) + name.substring(1);
return name;
}
private static class OreData {
int count;
long startTime;
OreData(int count, long startTime) {
this.count = count;
this.startTime = startTime;
}
}
}

View File

@@ -0,0 +1,28 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.commands.FriendCommand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerJoinListener implements Listener {
private final FriendCommand friendCommand;
public PlayerJoinListener(FriendCommand friendCommand) {
this.friendCommand = friendCommand;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
friendCommand.notifyFriendsOfJoin(player);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
friendCommand.updateLastOnline(player);
}
}

View File

@@ -0,0 +1,157 @@
package de.viper.survivalplus.listeners;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
public class RepairSignListener implements Listener {
private final FileConfiguration config;
private final FileConfiguration lang;
public RepairSignListener(FileConfiguration config, FileConfiguration lang) {
this.config = config;
this.lang = lang;
}
private String msg(String key) {
String raw = lang.getString(key, "&c[Missing lang key: " + key + "]");
return ChatColor.translateAlternateColorCodes('&', raw);
}
private String msg(String key, String... replacements) {
String raw = lang.getString(key, "&c[Missing lang key: " + key + "]");
for (int i = 0; i < replacements.length - 1; i += 2) {
raw = raw.replace(replacements[i], replacements[i + 1]);
}
return ChatColor.translateAlternateColorCodes('&', raw);
}
@EventHandler
public void onSignCreate(SignChangeEvent event) {
Player player = event.getPlayer();
if (event.getLine(0) != null && event.getLine(0).equalsIgnoreCase("[Repair]")) {
if (player.hasPermission("survivalplus.createrepairsign")) {
event.setLine(0, ChatColor.DARK_GREEN + "[Repair]");
event.setLine(1, ChatColor.GRAY + config.getString("repair.currency"));
event.setLine(2, ChatColor.GOLD + String.valueOf(config.getInt("repair.price")));
player.sendMessage(msg("repair.sign_created"));
} else {
player.sendMessage(msg("repair.no_permission_create"));
event.setCancelled(true);
}
}
}
// Verhindert Bearbeitung bestehender Repair-Schilder
@EventHandler
public void onSignEdit(SignChangeEvent event) {
Block block = event.getBlock();
if (block.getState() instanceof Sign) {
Sign sign = (Sign) block.getState();
String line0 = ChatColor.stripColor(sign.getLine(0));
if (line0.equalsIgnoreCase("[Repair]") && !event.getPlayer().isOp()) {
event.getPlayer().sendMessage(msg("repair.no_edit"));
event.setCancelled(true);
}
}
}
// Nur OP darf Schild abbauen
@EventHandler
public void onSignBreak(BlockBreakEvent event) {
if (event.getBlock().getState() instanceof Sign) {
Sign sign = (Sign) event.getBlock().getState();
String line0 = ChatColor.stripColor(sign.getLine(0));
if (line0.equalsIgnoreCase("[Repair]") && !event.getPlayer().isOp()) {
event.getPlayer().sendMessage(msg("repair.no_break"));
event.setCancelled(true);
}
}
}
@EventHandler
public void onSignClick(PlayerInteractEvent event) {
if (event.getClickedBlock() == null) return;
if (!(event.getClickedBlock().getState() instanceof Sign)) return;
Sign sign = (Sign) event.getClickedBlock().getState();
String line0 = ChatColor.stripColor(sign.getLine(0));
if (!line0.equalsIgnoreCase("[Repair]")) return;
Player player = event.getPlayer();
ItemStack item = player.getInventory().getItemInMainHand();
if (!(item.getItemMeta() instanceof Damageable)) {
player.sendMessage(msg("repair.not_repairable"));
return;
}
Damageable meta = (Damageable) item.getItemMeta();
int currentDamage = meta.getDamage();
// Prüfen ob bereits voll repariert
if (currentDamage <= 0) {
player.sendMessage(msg("repair.already_fully_repaired"));
return;
}
String currencyType = config.getString("repair.currency", "GOLD_INGOT");
int price = config.getInt("repair.price", 5);
Material currencyMaterial;
try {
currencyMaterial = Material.valueOf(currencyType.toUpperCase());
} catch (IllegalArgumentException e) {
player.sendMessage(msg("repair.invalid_currency"));
return;
}
// Prüfung ob Währung erlaubt ist
if (!isAllowedCurrency(currencyMaterial)) {
player.sendMessage(msg("repair.invalid_currency"));
return;
}
if (!player.getInventory().containsAtLeast(new ItemStack(currencyMaterial), price)) {
player.sendMessage(msg("repair.not_enough_currency", "%currency%", currencyType));
return;
}
// Zahlung abbuchen
player.getInventory().removeItem(new ItemStack(currencyMaterial, price));
// Item reparieren
meta.setDamage(0);
item.setItemMeta(meta);
player.sendMessage(msg("repair.success",
"%price%", String.valueOf(price),
"%currency%", currencyType));
}
private boolean isAllowedCurrency(Material mat) {
switch (mat) {
case GOLD_INGOT:
case IRON_INGOT:
case DIAMOND:
case NETHERITE_INGOT:
case COPPER_INGOT:
case EMERALD:
case LAPIS_LAZULI:
return true;
default:
return false;
}
}
}

View File

@@ -0,0 +1,89 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor; // Für &-Codes
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.SignChangeEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SignColorListener implements Listener {
private final SurvivalPlus plugin;
// Muster für Hex-Farbcodes (#FFFFFF)
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
// Muster für RGB-Farben rgb(255,255,255)
private static final Pattern RGB_PATTERN = Pattern.compile("rgb\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)");
public SignColorListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onSignChange(SignChangeEvent event) {
// Optional: Permission-Check einfügen
// if (!event.getPlayer().hasPermission("survivalplus.signcolor")) return;
for (int i = 0; i < event.getLines().length; i++) {
String line = event.getLine(i);
if (line != null && !line.isEmpty()) {
// 1. &-Codes übersetzen (z.B. &a -> §a)
String translated = ChatColor.translateAlternateColorCodes('&', line);
// 2. Hex-Farben ersetzen ( #RRGGBB )
translated = replaceHexColors(translated);
// 3. RGB-Farben ersetzen ( rgb(r,g,b) )
translated = replaceRgbColors(translated);
// 4. Final auf dem Schild setzen
event.setLine(i, translated);
}
}
}
private String replaceHexColors(String input) {
Matcher matcher = HEX_PATTERN.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String hexCode = matcher.group();
// Mit Bungee ChatColor.of in §x-Format umwandeln
String color = net.md_5.bungee.api.ChatColor.of(hexCode).toString();
matcher.appendReplacement(sb, color);
}
matcher.appendTail(sb);
return sb.toString();
}
private String replaceRgbColors(String input) {
Matcher matcher = RGB_PATTERN.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
int r = clampColorValue(matcher.group(1));
int g = clampColorValue(matcher.group(2));
int b = clampColorValue(matcher.group(3));
String hex = String.format("#%02X%02X%02X", r, g, b);
String color = net.md_5.bungee.api.ChatColor.of(hex).toString();
matcher.appendReplacement(sb, color);
}
matcher.appendTail(sb);
return sb.toString();
}
private int clampColorValue(String val) {
try {
int v = Integer.parseInt(val);
return Math.min(255, Math.max(0, v));
} catch (NumberFormatException e) {
return 0;
}
}
}

View File

@@ -0,0 +1,128 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.event.block.Action;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
public class SitListener implements Listener {
private final SurvivalPlus plugin;
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
public SitListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
public boolean isSitting(Player player) {
return sittingPlayers.containsKey(player.getUniqueId());
}
public void sitPlayer(Player player, Location location) {
if (sittingPlayers.containsKey(player.getUniqueId())) {
return;
}
// Erstelle einen unsichtbaren ArmorStand als Sitz
ArmorStand armorStand = player.getWorld().spawn(location, ArmorStand.class);
armorStand.setGravity(false);
armorStand.setMarker(true);
armorStand.setInvisible(true);
armorStand.setInvulnerable(true);
armorStand.addPassenger(player);
sittingPlayers.put(player.getUniqueId(), armorStand);
FileConfiguration lang = plugin.getLangConfig();
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " sitzt bei " + locationToString(location));
}
public void standUp(Player player) {
UUID playerId = player.getUniqueId();
ArmorStand armorStand = sittingPlayers.remove(playerId);
if (armorStand != null) {
armorStand.remove();
FileConfiguration lang = plugin.getLangConfig();
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " ist aufgestanden");
}
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getHand() != EquipmentSlot.HAND || event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
Player player = event.getPlayer();
FileConfiguration lang = plugin.getLangConfig();
if (!player.hasPermission("survivalplus.sit")) {
player.sendMessage(lang.getString("no-permission", "§cDu hast keine Berechtigung für diesen Befehl!"));
return;
}
Block block = event.getClickedBlock();
if (block == null || !isStair(block.getType())) {
return;
}
// Wenn der Spieler bereits sitzt, stehe auf
if (sittingPlayers.containsKey(player.getUniqueId())) {
standUp(player);
event.setCancelled(true);
return;
}
// Setze den Spieler genau auf der Treppenstufe
Location location = block.getLocation();
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);
sitPlayer(player, location);
event.setCancelled(true); // Verhindere andere Interaktionen mit der Treppe
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
if (!sittingPlayers.containsKey(playerId)) {
return;
}
// Prüfe, ob der Spieler sich bewegt hat (nur Positionsänderung, nicht Kopfbewegung)
Location from = event.getFrom();
Location to = event.getTo();
if (from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ()) {
standUp(player);
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
standUp(player);
}
private boolean isStair(Material material) {
return material.name().endsWith("_STAIRS");
}
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());
}
}

View File

@@ -0,0 +1,68 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent;
public class SleepListener implements Listener {
private final SurvivalPlus plugin;
private double requiredPercentage;
public SleepListener(SurvivalPlus plugin) {
this.plugin = plugin;
reloadConfig(plugin.getConfig());
}
public void reloadConfig(FileConfiguration config) {
this.requiredPercentage = config.getDouble("sleep.required-percentage", 50.0);
}
@EventHandler
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
Bukkit.getScheduler().runTaskLater(plugin, () -> checkSleepProgress(event.getPlayer().getWorld()), 1L);
}
@EventHandler
public void onPlayerBedLeave(PlayerBedLeaveEvent event) {
Bukkit.getScheduler().runTaskLater(plugin, () -> checkSleepProgress(event.getPlayer().getWorld()), 1L);
}
private void checkSleepProgress(World world) {
long time = world.getTime();
if (time < 12541 || time > 23458) return; // Nur bei Nacht prüfen
int sleeping = 0;
int total = 0;
for (Player player : world.getPlayers()) {
if (player.isSleepingIgnored()) continue;
total++;
if (player.isSleeping()) sleeping++;
}
if (total == 0) return;
double percent = (sleeping * 100.0) / total;
if (percent >= requiredPercentage) {
world.setTime(0);
world.setStorm(false);
world.setThundering(false);
Bukkit.broadcastMessage(plugin.getMessage("sleep.skipped")
.replace("%sleeping%", String.valueOf(sleeping))
.replace("%total%", String.valueOf(total)));
} else {
Bukkit.broadcastMessage(plugin.getMessage("sleep.progress")
.replace("%sleeping%", String.valueOf(sleeping))
.replace("%total%", String.valueOf(total))
.replace("%required%", String.valueOf(requiredPercentage)));
}
}
}

View File

@@ -0,0 +1,75 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class SpawnProtectionListener implements Listener {
private final SurvivalPlus plugin;
private final int radius;
private final boolean protectBlockBreak;
private final boolean protectBlockPlace;
private final boolean protectPvP;
private final String bypassPermission;
public SpawnProtectionListener(SurvivalPlus plugin) {
this.plugin = plugin;
this.radius = plugin.getConfig().getInt("spawnprotection.radius", 20);
this.protectBlockBreak = plugin.getConfig().getBoolean("spawnprotection.protect-block-break", true);
this.protectBlockPlace = plugin.getConfig().getBoolean("spawnprotection.protect-block-place", true);
this.protectPvP = plugin.getConfig().getBoolean("spawnprotection.protect-pvp", true);
this.bypassPermission = plugin.getConfig().getString("spawnprotection.bypass-permission", "survivalplus.spawnprotection.bypass");
}
private boolean isInSpawnProtection(Location loc) {
if (loc == null) return false;
Location spawn = loc.getWorld().getSpawnLocation();
return spawn.distance(loc) <= radius;
}
private boolean canBypass(Player player) {
// Nur OPs oder Spieler mit spezieller Berechtigung dürfen bypassen
return player.isOp() || player.hasPermission(bypassPermission);
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
if (!protectBlockBreak) return;
Player player = event.getPlayer();
if (isInSpawnProtection(event.getBlock().getLocation()) && !canBypass(player)) {
player.sendMessage(plugin.getMessage("spawnprotection.blockbreak-denied"));
event.setCancelled(true);
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
if (!protectBlockPlace) return;
Player player = event.getPlayer();
if (isInSpawnProtection(event.getBlock().getLocation()) && !canBypass(player)) {
player.sendMessage(plugin.getMessage("spawnprotection.blockplace-denied"));
event.setCancelled(true);
}
}
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (!protectPvP) return;
if (!(event.getEntity() instanceof Player)) return;
if (!(event.getDamager() instanceof Player)) return;
Player damaged = (Player) event.getEntity();
Player damager = (Player) event.getDamager();
if (isInSpawnProtection(damaged.getLocation()) && !canBypass(damager)) {
damager.sendMessage(plugin.getMessage("spawnprotection.pvp-denied"));
event.setCancelled(true);
}
}
}

View File

@@ -0,0 +1,81 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.Manager.StatsManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class StatsListener implements Listener {
private final SurvivalPlus plugin;
private final StatsManager statsManager;
// Spielzeit-Tracking
private final Map<UUID, Long> joinTimes = new HashMap<>();
public StatsListener(SurvivalPlus plugin, StatsManager statsManager) {
this.plugin = plugin;
this.statsManager = statsManager;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
joinTimes.put(event.getPlayer().getUniqueId(), System.currentTimeMillis());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
UUID uuid = event.getPlayer().getUniqueId();
long joinTime = joinTimes.getOrDefault(uuid, System.currentTimeMillis());
long now = System.currentTimeMillis();
long secondsPlayed = (now - joinTime) / 1000;
statsManager.addPlayTime(uuid, secondsPlayed);
statsManager.saveStats();
joinTimes.remove(uuid);
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
Player player = event.getEntity();
UUID uuid = player.getUniqueId();
statsManager.addDeaths(uuid, 1);
statsManager.saveStats();
// Optional: Kill-Stat beim Killer erhöhen
if (player.getKiller() != null) {
Player killer = player.getKiller();
statsManager.addKills(killer.getUniqueId(), 1);
statsManager.saveStats();
}
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
statsManager.addBlocksBroken(uuid, 1);
statsManager.saveStats();
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
statsManager.addBlocksPlaced(uuid, 1);
statsManager.saveStats();
}
}

View File

@@ -0,0 +1,250 @@
package de.viper.survivalplus.listeners;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ToolUpgradeListener implements Listener {
private final JavaPlugin plugin;
private final NamespacedKey levelKey;
private final int maxLevel;
private final Map<Integer, Material> levelMaterials = new HashMap<>();
private static final int REQUIRED_AMOUNT = 2; // immer 2 pro Slot
public ToolUpgradeListener(JavaPlugin plugin) {
this.plugin = plugin;
this.levelKey = new NamespacedKey(plugin, "tool_level");
this.maxLevel = plugin.getConfig().getInt("tool-upgrades.max-level", 5);
// Material aus Config laden
for (int i = 1; i <= maxLevel; i++) {
String matName = plugin.getConfig().getString("tool-upgrades.levels." + i + ".material");
if (matName != null) {
try {
levelMaterials.put(i, Material.valueOf(matName.toUpperCase()));
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Ungültiges Material für Level " + i + ": " + matName);
}
}
}
}
/** Vorschau-Ergebnis setzen */
@EventHandler
public void onPrepareCraft(PrepareItemCraftEvent event) {
if (!(event.getInventory() instanceof CraftingInventory)) return;
CraftingInventory inv = (CraftingInventory) event.getInventory();
ItemStack[] matrix = inv.getMatrix();
if (matrix.length < 9) {
inv.setResult(null);
return;
}
ItemStack center = matrix[4];
if (center == null || center.getType() == Material.AIR) {
inv.setResult(null);
return;
}
if (!isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) {
inv.setResult(null);
return;
}
int currentLevel = getToolLevel(center);
if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) {
inv.setResult(null);
return;
}
Material requiredMat = levelMaterials.get(currentLevel + 1);
if (requiredMat == null) {
inv.setResult(null);
return;
}
// Prüfen ob alle Slots (außer Mitte) mind. 2 Stück vom richtigen Material haben
for (int i = 0; i < matrix.length; i++) {
if (i == 4) continue;
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) {
inv.setResult(null);
return;
}
}
inv.setResult(createUpgradedTool(center, currentLevel + 1));
}
/** Klick auf Ergebnis-Slot handhaben + Items verbrauchen */
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) return;
Player player = (Player) event.getWhoClicked();
if (!(event.getView().getTopInventory() instanceof CraftingInventory)) return;
CraftingInventory inv = (CraftingInventory) event.getView().getTopInventory();
if (event.getRawSlot() != 0) return; // Nur Ergebnis-Slot (Slot 0 in Werkbank)
if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR) return;
ItemStack[] matrix = inv.getMatrix();
ItemStack center = matrix[4];
if (center == null || !isUpgradeableTool(center.getType()) || isWoodTool(center.getType())) return;
int currentLevel = getToolLevel(center);
if (currentLevel >= maxLevel || currentLevel >= getMaxAllowedLevel(center.getType())) return;
Material requiredMat = levelMaterials.get(currentLevel + 1);
if (requiredMat == null) return;
for (int i = 0; i < matrix.length; i++) {
if (i == 4) continue;
if (matrix[i] == null || matrix[i].getType() != requiredMat || matrix[i].getAmount() < REQUIRED_AMOUNT) return;
}
// Gültig: Event abbrechen, Upgrade geben, Items verbrauchen
event.setCancelled(true);
ItemStack result = createUpgradedTool(center, currentLevel + 1);
// Upgrade dem Spieler geben (Einzel- oder Shift-Klick)
if (event.isShiftClick()) {
player.getInventory().addItem(result);
} else {
if (event.getCursor() == null || event.getCursor().getType() == Material.AIR) {
event.setCursor(result);
} else {
player.getInventory().addItem(result);
}
}
// Items verbrauchen: 2 pro Slot (außer Mitte), Mitte leeren
for (int i = 0; i < matrix.length; i++) {
if (i == 4) {
matrix[i] = null; // Mitte leeren
} else if (matrix[i] != null) {
int newAmount = matrix[i].getAmount() - REQUIRED_AMOUNT;
if (newAmount <= 0) {
matrix[i] = null;
} else {
matrix[i].setAmount(newAmount);
}
}
}
inv.setMatrix(matrix);
inv.setResult(null); // Ergebnis-Slot leeren
// Inventar-Update verzögert senden
new BukkitRunnable() {
@Override
public void run() {
player.updateInventory();
}
}.runTaskLater(plugin, 2L); // 2 Ticks Verzögerung
}
/** Effekte beim Benutzen */
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE) return;
ItemStack tool = player.getInventory().getItemInMainHand();
if (tool == null || !isUpgradeableTool(tool.getType()) || isWoodTool(tool.getType())) return;
int level = getToolLevel(tool);
if (level <= 0) return;
// Drop-Multiplikator
int multiplier = getDropMultiplier(tool.getType());
if (multiplier > 1) {
event.setDropItems(false);
for (ItemStack drop : event.getBlock().getDrops(tool, player)) {
for (int i = 0; i < multiplier; i++) {
event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), drop.clone());
}
}
}
// Haste-Effekt
int hasteLevel = Math.min(5, level);
player.addPotionEffect(new PotionEffect(PotionEffectType.HASTE, 40, hasteLevel - 1, true, false));
// Sound
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_USE, 0.4f, 1.6f);
}
/** Upgrade-Item erstellen */
private ItemStack createUpgradedTool(ItemStack baseTool, int newLevel) {
ItemStack upgraded = baseTool.clone();
ItemMeta meta = upgraded.getItemMeta();
if (meta != null) {
meta.getPersistentDataContainer().set(levelKey, PersistentDataType.INTEGER, newLevel);
Enchantment eff = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
Enchantment fortune = Enchantment.getByKey(NamespacedKey.minecraft("fortune"));
if (eff != null) meta.addEnchant(eff, Math.min(5, newLevel), true);
int fLevel = getFortuneForMaterial(baseTool.getType());
if (fLevel > 0 && fortune != null) meta.addEnchant(fortune, fLevel, true);
meta.setLore(Collections.singletonList("§7Upgrade-Level: §e" + newLevel));
upgraded.setItemMeta(meta);
}
return upgraded;
}
/** Hilfsmethoden */
private boolean isUpgradeableTool(Material mat) {
String n = mat.name();
return n.endsWith("_AXE") || n.endsWith("_PICKAXE") ||
n.endsWith("_SHOVEL") || n.endsWith("_HOE") ||
n.endsWith("_SWORD");
}
private boolean isWoodTool(Material mat) { return mat.name().startsWith("WOODEN"); }
private int getMaxAllowedLevel(Material mat) {
String s = mat.name();
if (s.startsWith("IRON")) return 3;
if (s.startsWith("GOLDEN")) return 3;
if (s.startsWith("DIAMOND")) return maxLevel;
if (s.startsWith("NETHERITE")) return maxLevel;
return 0;
}
private int getFortuneForMaterial(Material mat) {
String s = mat.name();
if (s.startsWith("GOLDEN")) return 1;
if (s.startsWith("DIAMOND")) return 2;
if (s.startsWith("NETHERITE")) return 3;
return 0;
}
private int getDropMultiplier(Material mat) {
String s = mat.name();
if (s.startsWith("GOLDEN")) return 2;
if (s.startsWith("DIAMOND")) return 3;
if (s.startsWith("NETHERITE")) return 6;
return 1;
}
private int getToolLevel(ItemStack item) {
if (item == null || !item.hasItemMeta()) return 0;
Integer lvl = item.getItemMeta().getPersistentDataContainer().get(levelKey, PersistentDataType.INTEGER);
return lvl != null ? lvl : 0;
}
}

View File

@@ -0,0 +1,80 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.Manager.Warp;
import de.viper.survivalplus.Manager.WarpManager;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.ItemStack;
public class WarpInventoryListener implements Listener {
private final SurvivalPlus plugin;
private final WarpManager warpManager;
private final String inventoryTitle;
public WarpInventoryListener(SurvivalPlus plugin, WarpManager warpManager) {
this.plugin = plugin;
this.warpManager = warpManager;
this.inventoryTitle = ChatColor.GOLD + "Player Warps";
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getView() == null) return;
if (event.getView().getTitle() == null) return;
if (!event.getView().getTitle().equalsIgnoreCase(inventoryTitle)) return;
// Verhindert Verschieben und Entnehmen
event.setCancelled(true);
ItemStack clickedItem = event.getCurrentItem();
if (clickedItem == null || clickedItem.getType().isAir()) return;
if (!(event.getWhoClicked() instanceof Player)) return;
Player player = (Player) event.getWhoClicked();
if (!clickedItem.hasItemMeta() || !clickedItem.getItemMeta().hasDisplayName()) return;
String warpName = ChatColor.stripColor(clickedItem.getItemMeta().getDisplayName());
Warp warpFound = null;
for (Warp warp : warpManager.getWarps().values()) {
if (warp.getName().equalsIgnoreCase(warpName)) {
warpFound = warp;
break;
}
}
if (warpFound == null) {
player.sendMessage(ChatColor.RED + "Warp nicht gefunden.");
player.closeInventory();
return;
}
if (Bukkit.getWorld(warpFound.getWorldName()) == null) {
player.sendMessage(ChatColor.RED + "Die Welt dieses Warps existiert nicht.");
player.closeInventory();
return;
}
player.teleport(
Bukkit.getWorld(warpFound.getWorldName())
.getBlockAt((int) warpFound.getX(), (int) warpFound.getY(), (int) warpFound.getZ())
.getLocation().add(0.5, 1.0, 0.5) // leicht über dem Block für sicheren Spawn
);
player.sendMessage(ChatColor.GREEN + "Teleportiert zu Warp: " + warpName);
player.closeInventory();
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
if (event.getView() == null) return;
if (event.getView().getTitle() == null) return;
if (!event.getView().getTitle().equalsIgnoreCase(inventoryTitle)) return;
event.setCancelled(true);
}
}

View File

@@ -0,0 +1,38 @@
package de.viper.survivalplus.recipe;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
public class BackpackRecipe {
public static void register(JavaPlugin plugin, org.bukkit.configuration.file.FileConfiguration langConfig) {
// Ergebnis-Item: Truhe mit Namen "Rucksack"
ItemStack backpack = new ItemStack(Material.CHEST);
ItemMeta meta = backpack.getItemMeta();
if (meta != null) {
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', langConfig.getString("backpack.name", "&eRucksack")));
backpack.setItemMeta(meta);
}
NamespacedKey key = new NamespacedKey(plugin, "backpack");
ShapedRecipe recipe = new ShapedRecipe(key, backpack);
recipe.shape(
"S L", // Faden, leer, Leder
" C ", // leer, Truhe, leer
"S L" // Faden, leer, Leder
);
recipe.setIngredient('S', Material.STRING); // Faden
recipe.setIngredient('L', Material.LEATHER); // Leder
recipe.setIngredient('C', Material.CHEST); // Truhe
Bukkit.addRecipe(recipe);
plugin.getLogger().info("Backpack Rezept wurde registriert.");
}
}

View File

@@ -0,0 +1,45 @@
package de.viper.survivalplus.tasks;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Item;
public class AutoClearTask implements Runnable {
private final SurvivalPlus plugin;
public AutoClearTask(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public void run() {
FileConfiguration lang = plugin.getLangConfig();
// Vorwarnung
String warningMessage = ChatColor.translateAlternateColorCodes('&',
lang.getString("autoclear.warning", "&e&lAchtung! &rIn 10 Sekunden werden alle Items gelöscht!"));
Bukkit.broadcastMessage(warningMessage);
// Nach 10 Sekunden: Items löschen
Bukkit.getScheduler().runTaskLater(plugin, () -> {
int totalRemoved = 0;
for (World world : Bukkit.getWorlds()) {
for (Item item : world.getEntitiesByClass(Item.class)) {
item.remove();
totalRemoved++;
}
}
// Bestätigung
String resultMessage = ChatColor.translateAlternateColorCodes('&',
lang.getString("autoclear.cleared", "&c&l%count% Items wurden automatisch gelöscht."));
resultMessage = resultMessage.replace("%count%", String.valueOf(totalRemoved));
Bukkit.broadcastMessage(resultMessage);
}, 20L * 10); // 10 Sekunden Verzögerung
}
}

View File

@@ -0,0 +1,106 @@
package de.viper.survivalplus.trade;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TradeManager {
private final SurvivalPlus plugin;
private final Map<UUID, TradeSession> activeTrades = new HashMap<>();
private final Map<UUID, UUID> pendingRequests = new HashMap<>();
public TradeManager(SurvivalPlus plugin) {
this.plugin = plugin;
}
public void requestTrade(Player sender, Player target) {
if (sender == null || target == null) return;
if (isTrading(sender) || isTrading(target)) {
sender.sendMessage(plugin.getLangConfig().getString("trade.already-trading", "§cEiner von euch ist bereits im Handel."));
return;
}
if (sender.getUniqueId().equals(target.getUniqueId())) {
sender.sendMessage(plugin.getLangConfig().getString("trade.with-yourself-not-allowed", "§cHandel mit dir selbst ist nicht erlaubt!"));
return;
}
pendingRequests.put(target.getUniqueId(), sender.getUniqueId());
String requestText = plugin.getLangConfig().getString("trade.request-text", "%player% möchte mit dir handeln. Klicke hier, um anzunehmen!")
.replace("%player%", sender.getName());
try {
net.md_5.bungee.api.chat.TextComponent message = new net.md_5.bungee.api.chat.TextComponent(requestText);
message.setColor(net.md_5.bungee.api.ChatColor.GREEN);
message.setClickEvent(new net.md_5.bungee.api.chat.ClickEvent(net.md_5.bungee.api.chat.ClickEvent.Action.RUN_COMMAND, "/tradeaccept " + sender.getName()));
target.spigot().sendMessage(message);
} catch (Throwable ex) {
target.sendMessage(requestText + " (/tradeaccept " + sender.getName() + ")");
}
sender.sendMessage(plugin.getLangConfig().getString("trade.request-sent", "§aHandelsanfrage an %player% gesendet.").replace("%player%", target.getName()));
}
public void acceptTrade(Player target, String requesterName) {
if (target == null || requesterName == null) return;
UUID pendingSenderUUID = pendingRequests.get(target.getUniqueId());
if (pendingSenderUUID == null) {
target.sendMessage(plugin.getLangConfig().getString("trade.no-pending-request", "§cKeine Handelsanfrage gefunden."));
return;
}
Player sender = Bukkit.getPlayer(pendingSenderUUID);
if (sender == null || !sender.isOnline()) {
target.sendMessage(plugin.getLangConfig().getString("trade.player-not-online", "§cDieser Spieler ist nicht online!"));
pendingRequests.remove(target.getUniqueId());
return;
}
pendingRequests.remove(target.getUniqueId());
startTrade(sender, target);
}
public void startTrade(Player sender, Player receiver) {
if (isTrading(sender) || isTrading(receiver)) {
sender.sendMessage(plugin.getLangConfig().getString("trade.already-trading", "§cEiner von euch ist bereits im Handel."));
return;
}
TradeSession session = new TradeSession(plugin, sender, receiver);
Bukkit.getPluginManager().registerEvents(session, plugin);
activeTrades.put(sender.getUniqueId(), session);
activeTrades.put(receiver.getUniqueId(), session);
session.openInventories();
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()));
}
public void endTrade(TradeSession session) {
if (session == null) return;
Player s = session.getSender();
Player r = session.getReceiver();
if (s != null) activeTrades.remove(s.getUniqueId());
if (r != null) activeTrades.remove(r.getUniqueId());
session.endSession();
}
public TradeSession getTrade(Player player) {
if (player == null) return null;
return activeTrades.get(player.getUniqueId());
}
public boolean isTrading(Player player) {
if (player == null) return false;
return activeTrades.containsKey(player.getUniqueId());
}
}

View File

@@ -0,0 +1,165 @@
package de.viper.survivalplus.trade;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class TradeSession implements Listener {
private final SurvivalPlus plugin;
private final Player sender;
private final Player receiver;
private final Inventory invSender;
private final Inventory invReceiver;
private boolean senderConfirmed = false;
private boolean receiverConfirmed = false;
private boolean ended = false; // Flag gegen Rekursion
public TradeSession(SurvivalPlus plugin, Player sender, Player receiver) {
this.plugin = plugin;
this.sender = sender;
this.receiver = receiver;
String titleForSender = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
.replace("%player%", receiver.getName());
String titleForReceiver = plugin.getLangConfig().getString("trade.inventory-title", "Handel mit %player%")
.replace("%player%", sender.getName());
this.invSender = Bukkit.createInventory(sender, 27, titleForSender);
this.invReceiver = Bukkit.createInventory(receiver, 27, titleForReceiver);
addConfirmButton(invSender);
addConfirmButton(invReceiver);
}
private void addConfirmButton(Inventory inv) {
ItemStack confirm = new ItemStack(Material.LIME_CONCRETE);
ItemMeta meta = confirm.getItemMeta();
meta.setDisplayName(plugin.getLangConfig().getString("trade.confirm-button", "§aBestätigen"));
confirm.setItemMeta(meta);
inv.setItem(26, confirm);
}
public Player getSender() { return sender; }
public Player getReceiver() { return receiver; }
public void openInventories() {
if (sender.isOnline()) sender.openInventory(invSender);
if (receiver.isOnline()) receiver.openInventory(invReceiver);
}
private void returnItems(Player player, Inventory inventory) {
for (int i = 0; i < 26; i++) {
ItemStack item = inventory.getItem(i);
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();
}
if (receiver.isOnline() && receiver.getOpenInventory().getTopInventory() == invReceiver) {
receiver.closeInventory();
}
HandlerList.unregisterAll(this);
}
private Inventory getOwnInventory(Player p) {
return p.getUniqueId().equals(sender.getUniqueId()) ? invSender : invReceiver;
}
private Inventory getOtherInventory(Player p) {
return p.getUniqueId().equals(sender.getUniqueId()) ? invReceiver : invSender;
}
private void updateOtherView(Player p) {
Inventory own = getOwnInventory(p);
Inventory other = getOtherInventory(p);
for (int i = 0; i < 26; i++) {
other.setItem(i, own.getItem(i));
}
}
private void executeTrade() {
for (int i = 0; i < 26; i++) {
ItemStack itemFromSender = invSender.getItem(i);
ItemStack itemFromReceiver = invReceiver.getItem(i);
if (itemFromSender != null) sender.getInventory().addItem(itemFromSender);
if (itemFromReceiver != null) receiver.getInventory().addItem(itemFromReceiver);
}
String success = plugin.getLangConfig().getString("trade.success", "§aHandel erfolgreich abgeschlossen!");
if (sender.isOnline()) sender.sendMessage(success);
if (receiver.isOnline()) receiver.sendMessage(success);
endSession();
}
private void resetConfirmations() {
senderConfirmed = false;
receiverConfirmed = false;
}
@EventHandler
public void onInventoryClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player p)) return;
if (!p.getUniqueId().equals(sender.getUniqueId()) && !p.getUniqueId().equals(receiver.getUniqueId())) return;
Inventory top = e.getView().getTopInventory();
Inventory clicked = e.getClickedInventory();
int slot = e.getSlot();
if (clicked == null) return;
// Bestätigen-Button
if (slot == 26 && clicked.equals(top)) {
e.setCancelled(true);
if (p.getUniqueId().equals(sender.getUniqueId())) senderConfirmed = true;
if (p.getUniqueId().equals(receiver.getUniqueId())) receiverConfirmed = true;
p.sendMessage(plugin.getLangConfig().getString("trade.confirmed", "§aDu hast den Handel bestätigt!"));
if (senderConfirmed && receiverConfirmed) executeTrade();
return;
}
// Nur das eigene Trade-Inventar editierbar
if (clicked.equals(top)) {
Bukkit.getScheduler().runTaskLater(plugin, () -> {
updateOtherView(p);
resetConfirmations();
}, 1L);
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent e) {
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
Bukkit.getScheduler().runTaskLater(plugin, this::endSession, 1L);
}
}
}

View File

@@ -0,0 +1,292 @@
package de.viper.survivalplus.util;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Location;
import org.bukkit.block.Block;
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.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class LockSystem implements Listener, CommandExecutor {
private final SurvivalPlus plugin;
private final Map<Location, LockData> lockedBlocks = new HashMap<>();
private final Set<UUID> lockMode = new HashSet<>();
private final Map<UUID, BukkitRunnable> lockTimeoutTasks = new HashMap<>();
private final File lockFile;
private FileConfiguration lockConfig;
public LockSystem(SurvivalPlus plugin) {
this.plugin = plugin;
this.lockFile = new File(plugin.getDataFolder(), "locks.yml");
this.lockConfig = YamlConfiguration.loadConfiguration(lockFile);
loadLocks();
}
public static class LockData {
private final String ownerUUID;
private final Set<String> friendsUUID;
public LockData(String ownerUUID) {
this.ownerUUID = ownerUUID;
this.friendsUUID = new HashSet<>();
}
public String getOwnerUUID() {
return ownerUUID;
}
public Set<String> getFriendsUUID() {
return friendsUUID;
}
public void addFriend(String friendUUID) {
friendsUUID.add(friendUUID);
}
public void removeFriend(String friendUUID) {
friendsUUID.remove(friendUUID);
}
public boolean isFriend(String uuid) {
return friendsUUID.contains(uuid);
}
}
private void loadLocks() {
lockedBlocks.clear();
if (!lockFile.exists()) return;
for (String key : lockConfig.getKeys(false)) {
String path = key + ".";
String owner = lockConfig.getString(path + "owner");
List<String> friends = lockConfig.getStringList(path + "friends");
String[] parts = key.split("_");
if (parts.length != 4) continue;
String worldName = parts[0];
double x = Double.parseDouble(parts[1]);
double y = Double.parseDouble(parts[2]);
double z = Double.parseDouble(parts[3]);
Location loc = new Location(plugin.getServer().getWorld(worldName), x, y, z);
LockData lock = new LockData(owner);
lock.getFriendsUUID().addAll(friends);
lockedBlocks.put(loc, lock);
}
}
private void saveLocks() {
lockConfig = new YamlConfiguration();
for (Map.Entry<Location, LockData> entry : lockedBlocks.entrySet()) {
Location loc = entry.getKey();
LockData lock = entry.getValue();
String key = loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
lockConfig.set(key + ".owner", lock.getOwnerUUID());
lockConfig.set(key + ".friends", new ArrayList<>(lock.getFriendsUUID()));
}
try {
lockConfig.save(lockFile);
} catch (IOException e) {
plugin.getLogger().severe("Konnte locks.yml nicht speichern!");
e.printStackTrace();
}
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
Block block = event.getClickedBlock();
if (block == null) return;
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
Location loc = block.getLocation();
boolean isLockable = block.getState() instanceof InventoryHolder || block.getType().name().contains("DOOR");
if (lockMode.contains(uuid)) {
lockMode.remove(uuid);
BukkitRunnable timeout = lockTimeoutTasks.remove(uuid);
if (timeout != null) timeout.cancel();
if (!isLockable) {
player.sendMessage(plugin.getMessage("lock.not-lockable"));
return;
}
if (lockedBlocks.containsKey(loc)) {
player.sendMessage(plugin.getMessage("lock.already-locked"));
} else {
lockedBlocks.put(loc, new LockData(uuid.toString()));
saveLocks();
player.sendMessage(plugin.getMessage("lock.locked"));
}
event.setCancelled(true);
return;
}
if (!isLockable) return;
if (!lockedBlocks.containsKey(loc)) return;
LockData lock = lockedBlocks.get(loc);
String playerUUID = uuid.toString();
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
return;
}
player.sendMessage(plugin.getMessage("lock.block-denied"));
event.setCancelled(true);
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Player player = event.getPlayer();
Block block = event.getBlock();
Location loc = block.getLocation();
if (!lockedBlocks.containsKey(loc)) return;
LockData lock = lockedBlocks.get(loc);
String playerUUID = player.getUniqueId().toString();
if (lock.getOwnerUUID().equals(playerUUID) || lock.isFriend(playerUUID) || player.isOp()) {
return;
}
player.sendMessage(plugin.getMessage("lock.break-denied"));
event.setCancelled(true);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.getMessage("lock.only-players"));
return true;
}
Player player = (Player) sender;
UUID uuid = player.getUniqueId();
// NEU: Lock als Subcommand von /sp
if (args.length == 0 || args[0].equalsIgnoreCase("lock")) {
if (lockMode.contains(uuid)) {
player.sendMessage(plugin.getMessage("lock.mode-already"));
return true;
}
lockMode.add(uuid);
player.sendMessage(plugin.getMessage("lock.mode-start"));
BukkitRunnable timeout = new BukkitRunnable() {
@Override
public void run() {
if (lockMode.remove(uuid)) {
player.sendMessage(plugin.getMessage("lock.mode-timeout"));
lockTimeoutTasks.remove(uuid);
}
}
};
timeout.runTaskLater(plugin, 20 * 30); // 30 Sekunden
lockTimeoutTasks.put(uuid, timeout);
return true;
}
String sub = args[0].toLowerCase();
Block targetBlock = player.getTargetBlockExact(5);
if (targetBlock == null) {
player.sendMessage(plugin.getMessage("lock.no-target-block"));
return true;
}
Location loc = targetBlock.getLocation();
switch (sub) {
case "unlock":
LockData lock = lockedBlocks.get(loc);
if (lock == null) {
player.sendMessage(plugin.getMessage("lock.not-locked"));
} else if (!lock.getOwnerUUID().equals(uuid.toString()) && !player.isOp()) {
player.sendMessage(plugin.getMessage("lock.no-permission-unlock"));
} else {
lockedBlocks.remove(loc);
saveLocks();
player.sendMessage(plugin.getMessage("lock.unlocked"));
}
break;
case "friendadd":
if (args.length < 2) {
player.sendMessage(plugin.getMessage("lock.friendadd.usage"));
return true;
}
lock = lockedBlocks.get(loc);
if (lock == null) {
player.sendMessage(plugin.getMessage("lock.not-locked"));
} else if (!lock.getOwnerUUID().equals(uuid.toString()) && !player.isOp()) {
player.sendMessage(plugin.getMessage("lock.no-permission-friends"));
} else {
Player friend = player.getServer().getPlayer(args[1]);
if (friend == null) {
player.sendMessage(plugin.getMessage("lock.friendadd.not-found"));
} else {
lock.addFriend(friend.getUniqueId().toString());
saveLocks();
player.sendMessage(plugin.getMessage("lock.friendadd.success").replace("{player}", friend.getName()));
}
}
break;
case "friendremove":
if (args.length < 2) {
player.sendMessage(plugin.getMessage("lock.friendremove.usage"));
return true;
}
lock = lockedBlocks.get(loc);
if (lock == null) {
player.sendMessage(plugin.getMessage("lock.not-locked"));
} else if (!lock.getOwnerUUID().equals(uuid.toString()) && !player.isOp()) {
player.sendMessage(plugin.getMessage("lock.no-permission-friends"));
} else {
Player friend = player.getServer().getPlayer(args[1]);
if (friend == null) {
player.sendMessage(plugin.getMessage("lock.friendremove.not-found"));
} else {
lock.removeFriend(friend.getUniqueId().toString());
saveLocks();
player.sendMessage(plugin.getMessage("lock.friendremove.success").replace("{player}", friend.getName()));
}
}
break;
default:
player.sendMessage(plugin.getMessage("lock.unknown-subcommand"));
break;
}
return true;
}
}

View File

@@ -0,0 +1,2 @@
# Backpacks configuration file
backpacks: {}

View File

@@ -0,0 +1,246 @@
# Neulings Schutz
newbie-protection:
enabled: true
duration-minutes: 30
# Soll keepInventory automatisch beim Start gesetzt werden?
set-keepinventory: true
# SurvivalPlus - Block Kontrolle
blocks:
command-blocks:
enabled: false # true = Command Blocks sind erlaubt, false = verboten und werden entfernt
structure-blocks:
enabled: false # true = Structure Blocks sind erlaubt, false = verboten und werden entfernt
notify-admins-on-possession: true
# Sollen alle Spieler beim Joinen automatisch in Survival gesetzt werden?
force-survival: true
# Warp Default Item
defaultWarpItem: OAK_SIGN
# Anzahl der erlaubten Warps für Member
maxWarpsPerPlayer: 5
# Anzahl der erlaubten Homes für Member
max-homes: 3
# Item Reparaturkosten (GOLD_INGOT - IRON_INGOT - DIAMOND - NETHERITE_INGOT - COPPER_INGOT - SMARAGD - LAPIS_LAZULI)
repair:
currency: GOLD_INGOT
price: 5
# Aktivieren oder Deaktivieren des automatischen Löschens von Items
auto-clear-enabled: true
# Intervall in Minuten für das automatische Löschen herumliegender Items
auto-clear-interval-minutes: 15
# Zeit in Sekunden, nach der Gräber verschwinden (Standard: 30 Minuten)
graves:
despawn-time: 1800
# AFK Aktivieren/Deaktivieren (Wenn du kick-after-seconds auf 0 setzt, wird kein Spieler gekickt, nur AFK markiert.)
afk:
enabled: true
# nach 5 Minuten Inaktivität als AFK markieren
afk-after-seconds: 300
# nach 15 Minuten wird Spieler gekickt
kick-after-seconds: 900
# Nacht/Schlafmodus
sleep:
required-percentage: 50.0
# Mob-Leash-Limit
mob-leash-limit:
enabled: true
max-leash-count: 5
# Mobcap-Begrenzung
mob-cap:
enabled: true
max-animals-per-chunk: 10
# Spawn Schutz Radius
spawnprotection:
enabled: true
radius: 40
protect-block-break: true
protect-block-place: true
protect-pvp: true
bypass-permission: survivalplus.spawnprotection.bypass
# Start Kit (Minecraft item, Menge, Custom-Name)
first-join-kit:
items:
- "bread,2,§6Bernd das Brot"
- "apple,1,§7Dornröschen Apfel"
- "wooden_sword,1,§eSchwert"
- "suspicious_stew,1,§6Heldensuppe"
# Werkzeug Upgrade
tool-upgrades:
max-level: 5
levels:
1:
material: COPPER_INGOT
2:
material: IRON_INGOT
3:
material: GOLD_INGOT
4:
material: DIAMOND
5:
material: NETHERITE_INGOT
# Verbotene Nicknamen
forbidden-nicks:
- admin
- mod
- owner
- staff
- Hitler
- Adolf
- Nazi
- Führer
- SS
- KZ
- Konzentrationslager
- Nazi Deutschland
- Holocaust
- Drittes Reich
- Juden
- Holocaust
- Shoah
- Antisemitismus
# LootChest Konfiguration
lootchest:
enabled: false
interval-minutes: 30
despawn-minutes: 10
spawn-count: 5
max-active-chests: 10
max-loot-per-player: 3
loot-limit-reset-minutes: 60
world: world
spawn-radius: 500
items:
# --- Essen & Trinken ---
bread:
material: BREAD
name: "&eFrisches Brot"
chance: 1.0
min: 2
max: 4
apple:
material: APPLE
name: "&cRoter Apfel"
chance: 0.9
min: 1
max: 3
cooked_beef:
material: COOKED_BEEF
name: "&6Gebratenes Steak"
chance: 0.8
min: 2
max: 5
baked_potato:
material: BAKED_POTATO
name: "&eOfenkartoffel"
chance: 0.8
min: 1
max: 2
mushroom_stew:
material: MUSHROOM_STEW
name: "&6Pilzsuppe"
chance: 0.6
min: 1
max: 2
suspicious_stew:
material: SUSPICIOUS_STEW
name: "&dGeheime Suppe"
chance: 0.4
min: 1
max: 1
honey_bottle:
material: HONEY_BOTTLE
name: "&6Honigflasche"
chance: 0.5
min: 1
max: 2
# --- Werkzeuge ---
wooden_sword:
material: WOODEN_SWORD
name: "&6Einfaches Holzschwert"
chance: 0.4
min: 1
max: 1
wooden_pickaxe:
material: WOODEN_PICKAXE
name: "&6Einfache Holzspitzhacke"
chance: 0.8
min: 1
max: 1
wooden_axe:
material: WOODEN_AXE
name: "&6Einfache Holzaxt"
chance: 0.7
min: 1
max: 1
stone_sword:
material: STONE_SWORD
name: "&7Steinschwert"
chance: 0.5
min: 1
max: 1
stone_pickaxe:
material: STONE_PICKAXE
name: "&7Steinspitzhacke"
chance: 0.5
min: 1
max: 1
stone_axe:
material: STONE_AXE
name: "&7Steinaxt"
chance: 0.4
min: 1
max: 1
funChallenges:
- name: "Karottenjäger"
description: "Sammle 100 Karotten in 1 Stunde"
type: "COLLECT"
item: "CARROT"
amount: 100
timeLimitMinutes: 60
active: false # per Command/Script auf true setzen!
reward: "DIAMOND,1" # Item und Menge des Rewards
- name: "Eisen-Farmer"
description: "Sammle 50 Eisenbarren in 30 Minuten"
type: "COLLECT"
item: "IRON_INGOT"
amount: 50
timeLimitMinutes: 30
active: false
reward: "EMERALD,2"
- name: "Holzsammler"
description: "Sammle 200 Holzbretter in 45 Minuten"
type: "COLLECT"
item: "OAK_PLANKS" # Minecraft Material-Name für Holzbretter
amount: 200
timeLimitMinutes: 45
active: false
reward: "GOLD_INGOT,5"
- name: "Schlaf-Challenge"
description: "Schlafe 10 Mal in 1 Stunde"
type: "ACTION"
action: "SLEEP"
amount: 10
timeLimitMinutes: 60
active: false
reward: "SLEEPING_BAG,1"

View File

View File

223
src/main/resources/help.yml Normal file
View File

@@ -0,0 +1,223 @@
header: "&6=== SurvivalPlus Hilfe ==="
footer: "&6==========================="
commands:
gm:
description: "&eWechselt den Spielmodus (survival, creative, adventure, spectator)."
usage: "&b/gm [spieler]"
sp:
description: "&eHauptbefehl für SurvivalPlus mit Unterbefehlen."
usage: "&b/sp "
share:
description: "&eTeilt deine aktuellen Koordinaten nach Bestätigung mit allen Spielern."
usage: "&b/sp share"
shareconfirm:
description: "&eBestätigt das Teilen deiner Koordinaten mit allen Spielern."
usage: "&b/sp shareconfirm"
sharecancel:
description: "&eBricht das Teilen deiner Koordinaten ab."
usage: "&b/sp sharecancel"
sethome:
description: "&eSetzt einen neuen Homepunkt."
usage: "&b/sethome "
delhome:
description: "&eLöscht einen Homepunkt."
usage: "&b/delhome "
homelist:
description: "&eZeigt alle deine Homes."
usage: "&b/homelist"
home:
description: "&eTeleportiert dich zu einem gespeicherten Home."
usage: "&b/home "
inv:
description: "&eÖffnet dein Inventar oder das eines anderen Spielers."
usage: "&b/inv "
ec:
description: "&eÖffnet deine Endertruhe oder die eines anderen Spielers."
usage: "&b/ec [spieler]"
setspawn:
description: "&eSetzt den Spawnpunkt der Welt."
usage: "&b/setspawn"
setworldspawn:
description: "&eSetzt den globalen Weltspawnpunkt."
usage: "&b/setworldspawn"
clearchat:
description: "&eLöscht den Chat für alle Spieler."
usage: "&b/clearchat"
clearitems:
description: "&eEntfernt alle Items auf dem Boden."
usage: "&b/clearitems"
closedoors:
description: "&eSchließt alle Türen im angegebenen Radius."
usage: "&b/closedoors "
sit:
description: "&eSetzt dich hin oder steht wieder auf."
usage: "&b/sit"
back:
description: "&eTeleportiert dich zurück zum letzten Todespunkt."
usage: "&b/back"
friend:
description: "&eVerwalte deine Freundesliste (hinzufügen, entfernen, anzeigen, teleportieren). Unterstützt anklickbare Anfragen und Bestätigungen."
usage: "&b/friend [Spieler]"
ir:
description: "&eBenennt Items um."
usage: "&b/ir "
showarmorstands:
description: "&eZeigt unsichtbare ArmorStands an."
usage: "&b/showarmorstands"
cleardebugarmorstands:
description: "&eLöscht alle Debug ArmorStands."
usage: "&b/cleardebugarmorstands"
trash:
description: "&eÖffnet den Mülleimer."
usage: "&b/trash"
workbench:
description: "&eÖffnet eine Werkbank GUI."
usage: "&b/workbench"
anvil:
description: "&eÖffnet eine Amboss GUI."
usage: "&b/anvil"
stats:
description: "&eZeigt deine persönlichen Statistiken an."
usage: "&b/stats"
spawn:
description: "&eTeleportiert dich zum Welt-Spawnpunkt."
usage: "&b/spawn"
lock:
description: "&eSchützt Container mit dem LockSystem."
usage: "&b/lock [Spieler]"
tp:
description: "&eTeleportiert dich zu einem anderen Spieler."
usage: "&b/tp "
tphere:
description: "&eTeleportiert einen Spieler zu dir."
usage: "&b/tphere "
tpa:
description: "&eSendet eine Teleport-Anfrage an einen Spieler."
usage: "&b/tpa "
tpaccept:
description: "&eAkzeptiert eine Teleport-Anfrage."
usage: "&b/tpaccept"
tpdeny:
description: "&eLehnt eine Teleport-Anfrage ab."
usage: "&b/tpdeny"
block:
description: "&eBlockiert Nachrichten eines Spielers."
usage: "&b/block "
unblock:
description: "&eHebt eine Blockierung auf."
usage: "&b/unblock "
blocklist:
description: "&eZeigt eine Liste blockierter Spieler."
usage: "&b/blocklist"
kit:
description: "&eErhalte dein Starterkit."
usage: "&b/kit"
leashcount:
description: "&eZeigt die Anzahl der angeleinten Tiere an."
usage: "&b/leashcount"
nick:
description: "&eÄndert deinen angezeigten Namen mit Farben (&) und Hex-Farben (#RRGGBB)."
usage: "&b/nick "
trade:
description: "&eStartet einen Handel mit einem Spieler."
usage: "&b/trade "
tradeaccept:
description: "&eAkzeptiert eine Handelsanfrage."
usage: "&b/tradeaccept "
day:
description: "&eSetzt die Zeit auf Tag."
usage: "&b/day"
night:
description: "&eSetzt die Zeit auf Nacht."
usage: "&b/night"
report:
description: "&eMeldet einen Spieler an die Admins."
usage: "&b/report [Grund]"
showreport:
description: "&eZeigt alle Reports eines Spielers an."
usage: "&b/showreport "
clearreport:
description: "&eLöscht alle Reports eines Spielers."
usage: "&b/clearreport "
shop:
description: "&eVerwaltet den Server-Shop (z.B. Items hinzufügen)."
usage: "&b/shop add "
messages:
header: "&6=== Befehle ==="
footer: "&6================"
navigation:
prev: "&7« Vorherige "
next: "&7 Nächste »"
prev-disabled: "&8« "
next-disabled: "&8 »"
page: "&fSeite {current} von {total} "
sp:
invalid-subcommand: "&cUngültiger Unterbefehl! Verwendung: /sp [reload|help|info|share]"
no-permission: "&cDu hast keine Berechtigung für diesen Befehl!"
plugin:
reloaded: "&aSurvivalPlus wurde erfolgreich neu geladen!"
info:
header: "&7===== SurvivalPlus Info ====="
name: "&ePlugin-Name: &f"
version: "&eVersion: &f"
author: "&eErsteller: &f"
description: "&eBeschreibung:\\n&f"
footer: "&7=========================="
share:
preview-title: "&aDeine aktuellen Koordinaten wären:"
preview-format: "&e%player% &7teilt Koordinaten: &eX: %x%, Y: %y%, Z: %z% &7in Welt &e%world%"
send-button: "&a[✅ Senden]"
cancel-button: "&c [❌ Abbrechen]"
send-hover: "&aKlicke, um deine Koordinaten an alle zu senden."
cancel-hover: "&cKlicke, um das Senden abzubrechen."
sent: "&aKoordinaten gesendet."
cancelled: "&eSenden der Koordinaten abgebrochen."
help-not-found: "&cHilfedatei (help.yml) konnte nicht geladen werden!"

View File

@@ -0,0 +1,3 @@
# Diese Datei speichert die Home-Daten der Spieler
# Format: homes.<UUID>.<home-name>.{world,x,y,z,yaw,pitch}
homes: {}

406
src/main/resources/lang.yml Normal file
View File

@@ -0,0 +1,406 @@
sp:
no-permission: "§cDu hast keine Berechtigung für diesen Befehl!"
plugin.reloaded: "§aSurvivalPlus wurde erfolgreich neu geladen!"
invalid-subcommand: "§cUngültiger Unterbefehl! Verwendung: /sp [ reload | help | info | share ]"
help-not-found: "§cHilfedatei (help.yml) konnte nicht geladen werden!"
share:
preview-title: "§aDeine aktuellen Koordinaten wären:"
preview-format: "§6%player% §eist bei X: §b%x% §eY: §b%y% §eZ: §b%z% §ein Welt: §b%world%"
send-button: "§a[✅ Senden]"
send-hover: "§aKlicke, um deine Koordinaten an alle zu senden."
cancel-button: "§c [❌ Abbrechen]"
cancel-hover: "§cKlicke, um das Senden abzubrechen."
sent: "§aKoordinaten gesendet."
cancelled: "§eSenden der Koordinaten abgebrochen."
plugin:
enabled: "&aSurvivalPlus wurde erfolgreich aktiviert!"
reloaded: "&aSurvivalPlus wurde erfolgreich neu geladen!"
disabled: "&cSurvivalPlus wurde deaktiviert."
info: "&6SurvivalPlus Plugin-Info: Version %version%"
no-permission: "§cDu hast keine Berechtigung für diesen Befehl!"
no-permission-others: "§cDu hast keine Berechtigung, den Spielmodus anderer Spieler zu ändern!"
no-permission-others-ec: "§cDu hast keine Berechtigung, die Enderchest anderer Spieler anzusehen!"
no-permission-others-inv: "§cDu hast keine Berechtigung, das Inventar anderer Spieler anzusehen!"
player-not-found: "§cSpieler nicht gefunden!"
player-only: "§cDieser Befehl ist nur für Spieler!"
autoclear:
cleared: "&c&l%count% Items wurden automatisch gelöscht."
warning: "&e&lAchtung! &rIn 10 Sekunden werden alle Items gelöscht!"
clearchat:
cleared: "§aDer Chat wurde erfolgreich gelöscht."
no-permission: "§cDu hast keine Rechte, den Chat zu löschen."
clearitems:
no-permission: "§cDu hast keine Rechte, Items zu löschen."
closedoors:
invalidradius: "Der Radius muss eine gültige positive Zahl sein!"
noplayer: "Nur Spieler können diesen Befehl nutzen!"
nopermission: "Dafür hast du keine Rechte!"
success: "Es wurden %count% Türen geschlossen."
usage: "Benutzung: /closedoors <radius>"
delhome:
not-found: "§cDieses Home existiert nicht!"
success: "§aHome %name% wurde gelöscht!"
usage: "§cVerwendung: /delhome <name>"
enderchest:
data-not-found: "§cDie Enderchest-Daten des Spielers konnten nicht gefunden werden! Der Spieler war möglicherweise nie auf diesem Server."
gui-title: "Enderchest von "
load-error: "§cFehler beim Laden der Enderchest: %error%"
opened: "§aEnderchest von %player% geöffnet!"
usage: "§cVerwendung: /ec [spieler]"
gamemode:
adventure: "Abenteuer"
changed-other: "§aSpielmodus von %player% zu %mode% geändert!"
changed-self: "§aDein Spielmodus wurde zu %mode% geändert!"
creative: "Kreativ"
invalid-gamemode: "§cUngültiger Spielmodus! Verwende 0, 1, 2 oder 3"
spectator: "Zuschauer"
survival: "Überleben"
usage: "§cVerwendung: /gm <0|1|2|3> [spieler]"
homelist:
gui-title: "Deine Homes"
home-deleted: "§cDieses Home existiert nicht mehr!"
no-homes: "§cDu hast keine Homes gesetzt!"
teleported: "§aZum Home %name% teleportiert!"
inventory:
data-not-found: "§cDie Inventardaten des Spielers konnten nicht gefunden werden! Der Spieler war möglicherweise nie auf diesem Server."
gui-title: "Inventar von "
load-error: "§cFehler beim Laden des Inventars: %error%"
opened: "§aInventar von %player% geöffnet!"
usage: "§cVerwendung: /inv <spieler>"
sethome:
already-exists: "§cEin Home mit diesem Namen existiert bereits!"
invalid-name: "§cDer Home-Name darf nur Buchstaben, Zahlen und Unterstriche enthalten!"
limit-reached: "§cDu hast die maximale Anzahl an Homes erreicht!"
success: "§aHome %name% wurde gesetzt!"
usage: "§cVerwendung: /sethome <name>"
setspawn:
no-permission: "§cDu hast keine Berechtigung, den Spawnpunkt zu setzen!"
success: "§aSpawnpunkt wurde erfolgreich gesetzt!"
setworldspawn:
no-permission: "§cDu hast keine Berechtigung, den Weltspawn zu setzen!"
success: "§aWeltspawn wurde erfolgreich gesetzt!"
sit:
stand-up: "§aDu bist aufgestanden!"
success: "§aDu hast dich hingesetzt!"
usage: "§cVerwendung: /sit"
graves:
created: "§aDein Grab wurde bei x=%.2f, y=%.2f, z=%.2f erstellt!"
despawned: "§cDein Grab bei x=%.2f, y=%.2f, z=%.2f ist verschwunden!"
access-denied: "§cNur der Eigentümer kann dieses Grab öffnen!"
back:
usage: "§cVerwendung: /back"
no-death-point: "§cDu hast keinen Todespunkt!"
success: "§aTeleportiert zum Todespunkt bei x=%.2f, y=%.2f, z=%.2f!"
msg:
description: "Sende eine private Nachricht an einen Spieler."
usage: "/msg <Spieler> <Nachricht>"
r:
description: "Antworte auf die letzte private Nachricht."
usage: "/r <Nachricht>"
pm:
description: "Schalte private Nachrichten an oder aus."
usage: "/pm toggle"
backpack:
name: "&eRucksack"
inventory-title: "&eDein Rucksack"
friend:
error:
player-only: "&cDieser Befehl ist nur für Spieler!"
player-not-found: "&cSpieler %s nicht gefunden!"
self: "&cDu kannst dich nicht selbst hinzufügen!"
already-friends: "&cDu bist bereits mit %s befreundet!"
request-pending: "&cDu hast bereits eine Anfrage an %s gesendet!"
no-request: "&cKeine Anfrage von %s gefunden!"
not-friends: "&c%s ist nicht in deiner Freundesliste!"
different-world: "&cIhr müsst in derselben Welt sein, um zu teleportieren!"
add-usage: "&cVerwendung: /friend add <Spielername>"
accept-usage: "&cVerwendung: /friend accept <Spielername>"
deny-usage: "&cVerwendung: /friend deny <Spielername>"
list-usage: "&cVerwendung: /friend list"
del-usage: "&cVerwendung: /friend del <Spielername>"
confirm-usage: "&cVerwendung: /friend confirm <Spielername>"
tp-usage: "&cVerwendung: /friend tp <Spielername>"
add:
sent: "&aFreundschaftsanfrage an %s gesendet!"
received: "&aDu hast eine Freundschaftsanfrage von %s erhalten! "
accept-button: "&a[Accept]"
deny-button: "&c [Deny]"
accept:
success: "&aDu bist jetzt mit %s befreundet!"
notify: "&a%s hat deine Freundschaftsanfrage akzeptiert!"
deny:
success: "&aFreundschaftsanfrage von %s abgelehnt."
notify: "&c%s hat deine Freundschaftsanfrage abgelehnt."
list:
header: "&6=== Deine Freundesliste ==="
entry: "&e%s: %s"
entry-offline: "&e%s: %s &7(Zuletzt online: %s)"
online: "&aOnline"
offline: "&7Offline"
unknown: "&7Unbekannt"
date-format: "dd.MM.yyyy HH:mm:ss"
remove-button: "&c[X]"
footer: "&6====================="
del:
success: "&a%s wurde aus deiner Freundesliste entfernt."
notify: "&c%s hat dich aus seiner Freundesliste entfernt."
confirm: "&cMöchtest du %s wirklich aus deiner Freundesliste entfernen? "
confirm-button: "&a[Confirm]"
cancel-button: "&c[Cancel]"
tp:
success: "&aDu wurdest zu %s teleportiert!"
notify: "&a%s hat sich zu dir teleportiert."
join:
notify: "&aDein Freund %s ist dem Server beigetreten."
ir:
only-player: "&cDieser Befehl kann nur von Spielern ausgeführt werden."
no-permission: "&cDu hast keine Berechtigung, diesen Befehl zu benutzen."
no-name: "&cBitte gib einen neuen Namen an."
usage: "&eBenutze: /ir <NeuerName>"
no-item: "&cDu hältst kein Item in der Hand."
cant-rename: "&cDieses Item kann nicht umbenannt werden."
success: "&aDas Item wurde erfolgreich in {name} umbenannt!"
afk:
set: "&7Du bist jetzt AFK."
unset: "&7Du bist nicht mehr AFK."
sleep:
skipped: "&aDie Nacht wurde übersprungen! (%sleeping% von %total% Spielern haben geschlafen)"
progress: "&e%sleeping%/%total% Spielern schlafen... (%required%% benötigt zum Überspringen der Nacht)"
orealarm:
message: "§c[Erz-Alarm] Spieler §e%player% §chat in %seconds% Sekunden ungewöhnlich viele %ore% abgebaut: §e%count%"
stats:
header: "§6§l========== §e§lStatistik von {player} §6§l=========="
playtime: "§7Spielzeit: §a{time}"
kills: "§7Kills: §a{kills}"
deaths: "§7Tode: §a{deaths}"
kd_ratio: "§7K/D Ratio: §a{kd}"
blocks_placed: "§7Blöcke platziert: §a{placed}"
blocks_broken: "§7Blöcke abgebaut: §a{broken}"
jumps: "§7Gesprungen: §a{jumps}"
walked: "§7Gelaufene Strecke: §a{walked} km"
footer: "§6§l====================================="
no_stats: "§cEs sind noch keine Statistiken für dich vorhanden."
only_player: "§cNur Spieler können diesen Befehl nutzen!"
spawn:
only_player: "§cNur Spieler können diesen Befehl verwenden."
no_spawn_found: "§cKein Spawnpunkt in deiner Welt gefunden."
teleported: "§aDu wurdest zum Spawnpunkt teleportiert."
welcome:
first-join-message: "&aWillkommen auf dem Server, &e{player}&a! Viel Spaß!"
welcome.first-join-sound: ENTITY_FIREWORK_ROCKET_LAUNCH
welcome.first-join-sound-volume: 1.0
welcome.first-join-sound-pitch: 1.0
return-message: "&6Willkommen zurück, &e{player}&6!"
welcome.return-sound: ENTITY_FIREWORK_ROCKET_BLAST
welcome.return-sound-volume: 1.0
welcome.return-sound-pitch: 1.0
mob-leash-limit:
max-reached: "§cDu hast das maximale Leinen-Limit von §e%count%§c erreicht!"
leashed: "§aTier angeleint. Du hast jetzt §e%count%§a geleinte Tiere."
unleashed: "§aTier abgeleint. Du hast jetzt §e%count%§a geleinte Tiere."
entity-died: "§cEin angeleintes Tier ist gestorben. Du hast jetzt §e%count%§c geleinte Tiere."
mob-cap:
limit-reached: "&cZu viele Tiere in diesem Chunk! Maximal %max% Tiere erlaubt."
animal-removed: "&cEin Tier wurde entfernt, da das Chunk-Limit von %max% erreicht wurde."
spawnprotection:
blockbreak-denied: "&cDu kannst im Spawnbereich keine Blöcke abbauen."
blockplace-denied: "&cDu kannst im Spawnbereich keine Blöcke platzieren."
pvp-denied: "&cPvP ist im Spawnbereich deaktiviert."
lock:
not-lockable: "§cDieser Block kann nicht gesperrt werden."
already-locked: "§cDieser Block ist bereits gesperrt."
locked: "§aDer Block wurde erfolgreich gesperrt."
block-denied: "§cDu darfst diesen Block nicht benutzen, er ist gesperrt."
break-denied: "§cDu darfst diesen Block nicht abbauen, er ist gesperrt."
only-players: "§cNur Spieler können diesen Befehl ausführen."
mode-already: "§cDu bist bereits im Lock-Modus."
mode-start: "§aLock-Modus aktiviert. Klicke auf einen Block, um ihn zu sperren."
mode-timeout: "§cDer Lock-Modus wurde beendet."
usage: "§cVerwendung: /lock [unlock|friendadd|friendremove]"
not-locked: "§cDieser Block ist nicht gesperrt."
no-permission-unlock: "§cDu darfst diesen Block nicht entsperren."
unlocked: "§aBlock erfolgreich entsperrt."
friendadd:
usage: "§cVerwendung: /lock friendadd <Spieler>"
not-found: "§cSpieler nicht gefunden."
success: "§a{player} wurde als Freund hinzugefügt."
friendremove:
usage: "§cVerwendung: /lock friendremove <Spieler>"
not-found: "§cSpieler nicht gefunden."
success: "§a{player} wurde als Freund entfernt."
no-permission-friends: "§cDu darfst Freunde nur für deine eigenen Blöcke verwalten."
unknown-subcommand: "§cUnbekannter Unterbefehl."
no-target-block: "§cDu musst auf einen Block schauen, um diesen Befehl auszuführen."
teleport-usage: "§cVerwendung: /tp <Spieler>"
teleport-success: "§aDu wurdest zu %player% teleportiert!"
tphere-usage: "§cVerwendung: /tphere <Spieler>"
tphere-success: "§a%player% wurde zu dir teleportiert!"
tpa-usage: "§cVerwendung: /tpa <Spieler>"
tpa-sent: "§aTeleportanfrage an %player% gesendet!"
tpa-received: "§e%player% möchte sich zu dir teleportieren. Nutze /tpaccept oder /tpdeny."
tpaccept-success: "§aTeleportanfrage von %player% akzeptiert!"
tpa-accepted: "§aDeine Teleportanfrage wurde von %player% angenommen."
tpdeny-success: "§cTeleportanfrage abgelehnt!"
tpa-denied: "§cDeine Teleportanfrage wurde von %player% abgelehnt."
no-tpa-request: "§cDu hast keine ausstehende Teleportanfrage."
no-permission: "§cDu hast keine Berechtigung für diesen Befehl!"
only-players: "§cDieser Befehl kann nur von Spielern ausgeführt werden!"
player-not-found: "§cSpieler %player% nicht gefunden!"
block:
usage: "Benutze: /block <Spieler>"
invalid_player: "Ungültiger Spieler."
blocked: "Du hast §e%player%§c blockiert."
already_blocked: "Du hast §e%player%§c schon blockiert."
unblocked: "Du hast §e%player%§a entblockt."
unblock:
usage: "Benutze: /unblock <Spieler>"
invalid_player: "Ungültiger Spieler."
not_blocked: "Du hast §e%player%§c nicht blockiert."
unblocked: "Du hast §e%player%§a entblockt."
unblocked_by: "Du wurdest von §e%player%§a entblockt."
blocklist:
no_blocked_players: "§7Du hast aktuell niemanden blockiert."
blocked_players: "§7Blockierte Spieler: §e%list%"
repair:
sign_created: "&aReparaturschild erstellt!"
no_permission_create: "&cDu hast keine Berechtigung, Reparaturschilder zu erstellen!"
no_edit: "&cDu darfst dieses Reparaturschild nicht bearbeiten!"
no_break: "&cNur Operatoren dürfen dieses Reparaturschild abbauen!"
not_repairable: "&cDas Item in deiner Hand kann nicht repariert werden!"
invalid_currency: "&cUngültige Währung in der Config!"
not_enough_currency: "&cDu hast nicht genug %currency%!"
success: "&aDein Item wurde erfolgreich repariert mit %price% %currency%!"
already_fully_repaired: "&cDas Item ist bereits vollständig repariert!"
lootchest:
spawn-simple: "&aNeue Loot-Kisten sind gespawnt!"
despawn-msg: "&eEine Lootkiste ist von selbst verschwunden."
removed-msg: "&aEine Lootkiste wurde geleert und entfernt."
limit-reached: "&cDu hast dein Loot-Limit erreicht!"
player-only: "&cNur Spieler können diesen Befehl nutzen."
no-permission: "&cDazu hast du keine Berechtigung."
no-chests: "&eZur Zeit sind keine Loot-Kisten aktiv."
list-header: "&6Aktive Loot-Kisten:"
list-tp-hover: "&eKlicke zum Teleportieren!"
tp-usage: "&cBenutzung: /tploot <welt> <x> <y> <z>"
tp-world-not-found: "&cWelt nicht gefunden."
tp-success: "&aTeleportiert!"
tp-invalid-coords: "&cUngültige Koordinaten!"
trade:
only-players: "§cNur Spieler können diesen Befehl ausführen!"
usage: "§cVerwendung: /trade <Spieler>"
player-not-online: "§cDieser Spieler ist nicht online!"
with-yourself-not-allowed: "§cHandel mit dir selbst ist nicht erlaubt!"
already-trading: "§cEiner von euch ist bereits im Handel."
request-text: "%player% möchte mit dir handeln. Klicke hier, um anzunehmen!"
request-sent: "§aHandelsanfrage an %player% gesendet."
inventory-title: "Handel mit %player%"
confirm-button: "§aBestätigen"
confirmed: "§aDu hast den Handel bestätigt!"
success: "§aHandel erfolgreich abgeschlossen!"
report:
only-players: "§cNur Spieler können diesen Befehl ausführen!"
usage: "§cVerwendung: /report <Spieler> [Grund]"
player-not-online: "§cDieser Spieler ist nicht online!"
success: "§aDein Report wurde erfolgreich gesendet."
notify-admin: "§cREPORT§r: %reporter% hat %target% gemeldet. Grund: %reason%"
showreport:
only-players: "§cNur Spieler können diesen Befehl ausführen!"
usage: "§cVerwendung: /showreport <Spieler>"
no-reports: "§aEs wurden keine Reports für diesen Spieler gefunden."
clearreport:
only-players: "§cNur Spieler können diesen Befehl ausführen!"
usage: "§cVerwendung: /clearreport <Spieler>"
cleared: "§aReports von %player% wurden gelöscht."
shop:
only-players: "&cDieser Befehl kann nur von Spielern genutzt werden."
usage-add: "&eVerwendung: /shop add <item> <basispreis> <lagerbestand>"
unknown-subcommand: "&cUnbekannter Unterbefehl."
number-error: "&cPreis und Lagerbestand müssen gültige Zahlen sein."
item-added: "&aItem &e{item}&a mit Basispreis &e{price}&a und Lagerbestand &e{stock}&a hinzugefügt/aktualisiert."
warp:
only_players: "&cNur Spieler können diesen Befehl benutzen."
set_success: "&aWarp \"%warp%\" wurde erfolgreich gesetzt."
challenge:
only_players: "§cDieser Befehl kann nur von Spielern ausgeführt werden."
usage: "&eBenutze: /startchallenge <Name>"
start_success: "§aDie Challenge \"%challenge%\" wurde gestartet!"
start_fail: "§cChallenge \"%challenge%\" nicht gefunden."
inventory:
data-not-found: "§cDie Inventardaten des Spielers konnten nicht gefunden werden! Der Spieler war möglicherweise nie auf diesem Server."
gui-title: "Inventar von "
load-error: "§cFehler beim Laden des Inventars: %error%"
opened: "§aInventar von %player% geöffnet!"
usage: "§cVerwendung: /inv <spieler>"
no-permission-others: "§cDu hast keine Berechtigung, das Inventar anderer Spieler anzusehen!"
player-only: "§cDieser Befehl ist nur für Spieler!"
force-survival:
join-message: "§aDu wurdest in den Survivalmodus gesetzt!"

View File

View File

@@ -0,0 +1,508 @@
name: SurvivalPlus
version: 1.0.5
main: de.viper.survivalplus.SurvivalPlus
api-version: 1.21
softdepend: [LuckPerms, PlaceholderAPI]
author: Viper
description: A plugin for enhancing survival gameplay in Minecraft.
commands:
ir:
description: Benennt das Item in der Hand um.
usage: /ir <neuer_name>
permission: survivalplus.itemrename
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
gm:
description: Ändert den Spielmodus eines Spielers
usage: /<command> <modus> [spieler]
aliases: [gamemode]
permission: survivalplus.gamemode
sp:
description: Zeigt Plugin-Informationen oder führt weitere Befehle aus
usage: /<command> [reload|help|info|share] [seite]
permission: survivalplus.sp
sethome:
description: Setzt ein Home mit dem angegebenen Namen
usage: /<command> <name>
permission: survivalplus.homes.set
delhome:
description: Löscht ein Home mit dem angegebenen Namen
usage: /<command> <name>
permission: survivalplus.homes.delete
homelist:
description: Öffnet eine GUI mit allen Homes
usage: /<command>
permission: survivalplus.homes.list
home:
description: Teleportiert zu einem Home
usage: /<command> <name>
permission: survivalplus.homes
inv:
description: Öffnet das Inventar (eigenes oder das eines anderen Spielers)
usage: /<command> [spieler]
permission: survivalplus.inventory.own
ec:
description: Öffnet die Endertruhe (eigene oder die eines anderen Spielers)
usage: /<command> [spieler]
permission: survivalplus.enderchest.own
setworldspawn:
description: Setzt den Weltspawnpunkt auf die Position des Spielers
usage: /<command>
permission: survivalplus.setworldspawn
setspawn:
description: Setzt den Server-Spawnpunkt auf die Position des Spielers
usage: /<command>
permission: survivalplus.setspawn
clearchat:
description: Löscht den Chat für alle Spieler
usage: /<command>
permission: survivalplus.clearchat
clearitems:
description: Löscht alle herumliegenden Items
usage: /<command>
permission: survivalplus.clearitems
closedoors:
description: Schließt alle Türen im angegebenen Radius
usage: /<command> <radius>
permission: survivalplus.closedoors
sit:
description: Lässt den Spieler sich hinsetzen
usage: /<command>
permission: survivalplus.sit
back:
description: Teleportiert zum letzten Todespunkt
usage: /<command>
permission: survivalplus.back
friend:
description: Verwaltet die Freundesliste
usage: /<command> [add|accept|deny|list|del|tp] [Spielername]
permission: survivalplus.friend
stats:
description: Zeigt deine Statistiken an
usage: /stats
permission: survivalplus.stats
showarmorstands:
description: Macht alle unsichtbaren Armor Stands sichtbar.
usage: /showarmorstands
permission: survivalplus.showarmorstands
permission-message: "§cDu hast keine Rechte für diesen Befehl."
cleardebugarmorstands:
description: Entfernt alle Debug-ArmorStands
usage: /cleardebugarmorstands
permission: survivalplus.cleardebugarmorstands
permission-message: "§cDu hast keine Rechte für diesen Befehl."
trash:
description: Öffnet den Mülleimer
usage: /trash
permission: survivalplus.trash
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
workbench:
description: Öffnet eine Werkbank GUI
usage: /workbench
permission: survivalplus.workbench
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
anvil:
description: Öffnet eine Amboss GUI
usage: /anvil
permission: survivalplus.anvil
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
leashcount:
description: Zeigt die Anzahl der geleinten Tiere an.
usage: /leashcount
permission: survivalplus.leashcount
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
splock:
description: Verwaltet das Sperrsystem für Kisten und Türen
usage: /sp lock|unlock|friendadd|friendremove [Spieler]
permission: survivalplus.lock
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
tp:
description: Teleportiere dich zu einem Spieler
usage: /tp <Spieler>
tphere:
description: Teleportiere einen Spieler zu dir
usage: /tphere <Spieler>
tpa:
description: Sende eine Teleportanfrage an einen Spieler
usage: /tpa <Spieler>
tpaccept:
description: Akzeptiere eine Teleportanfrage
usage: /tpaccept
tpdeny:
description: Lehne eine Teleportanfrage ab
usage: /tpdeny
block:
description: Blockiere einen Spieler
usage: /block <Spieler>
permission: survivalplus.block
unblock:
description: Entblocke einen Spieler
usage: /unblock <Spieler>
permission: survivalplus.unlock
blocklist:
description: Zeige eine Liste der blockierten Spieler
usage: /blocklist
permission: survivalplus.blocklist
kit:
description: Hol dir das Starterkit!
usage: /kit
permission: survivalplus.kit
nick:
description: Ändert deinen Nicknamen mit Farb- und Hex-Support.
usage: /nick <Name>
permission: survivalplus.nick
permission-message: "§cDu hast keine Berechtigung, deinen Nick zu ändern!"
lootchests:
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
usage: /lootchests
permission: survivalplus.lootchests
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
tploot:
description: Teleportiere dich zu einer Loot-Kiste (nur Admins)
usage: /tploot <welt> <x> <y> <z>
permission: survivalplus.lootchests
permission-message: "§cDu hast keine Berechtigung für diesen Befehl!"
day:
description: Setzt die Zeit auf Tag
usage: /day
permission: survivalplus.day
night:
description: Setzt die Zeit auf Nacht
usage: /night
permission: survivalplus.night
trade:
description: Startet einen Handel mit einem Spieler
usage: /trade <Spieler>
permission: survivalplus.trade
tradeaccept:
description: Akzeptiert eine Handelsanfrage
usage: /tradeaccept <Spieler>
permission: survivalplus.tradeaccept
report:
description: Meldet einen Spieler an die Admins
usage: /report <Spieler> [Grund]
permission: survivalplus.report
showreport:
description: Zeigt alle Reports eines Spielers an
usage: /showreport <Spieler>
permission: survivalplus.report.show
clearreport:
description: Löscht alle Reports eines Spielers
usage: /clearreport <Spieler>
permission: survivalplus.report.clear
shop:
description: Verwalten des Server-Shops (z.B. Items hinzufügen)
usage: /shop add <item> <basispreis> <lagerbestand>
permission: survivalplus.shop
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
spawn:
description: Teleportiert dich zum Weltspawnpunkt.
usage: /spawn
permission: survivalplus.spawn
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
setwarp:
description: Setzt einen persönlichen Warp mit dem Item in der Hand.
usage: /setwarp <name>
permission: survivalplus.setwarp
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
delwarp:
description: Löscht einen persönlichen Warp .
usage: /delwarp <name>
permission: survivalplus.delwarp
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
warps:
description: Öffnet die GUI mit allen Spieler-Warps.
usage: /warps
permission: survivalplus.warps
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
startchallenge:
description: Startet eine Fun-Challenge
usage: /startchallenge <name>
permission: survivalplus.startchallenge
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
heal:
description: Heilt einen Spieler vollständig
usage: /heal [spieler]
permission: survivalplus.heal
permission-message: "§cDu hast keine Berechtigung, Spieler zu heilen!"
survivalplus.notify:
description: Erhält Benachrichtigungen, wenn ein Spieler einen Command- oder Structure-Block besitzt
default: op
permissions:
survivalplus.*:
description: Gibt Zugriff auf alle SurvivalPlus-Befehle
default: op
children:
survivalplus.gamemode: true
survivalplus.gamemode.others: true
survivalplus.sp: true
survivalplus.share: true
survivalplus.homes.set: true
survivalplus.homes.delete: true
survivalplus.homes.list: true
survivalplus.homes: true
survivalplus.homes.unlimited: true
survivalplus.inventory.own: true
survivalplus.inventory.others: true
survivalplus.enderchest.own: true
survivalplus.enderchest.others: true
survivalplus.setworldspawn: true
survivalplus.setspawn: true
survivalplus.clearchat: true
survivalplus.clearitems: true
survivalplus.closedoors: true
survivalplus.sit: true
survivalplus.back: true
survivalplus.graves: true
survivalplus.friend: true
survivalplus.itemrename: true
survivalplus.stats: true
survivalplus.showarmorstands: true
survivalplus.cleardebugarmorstands: true
survivalplus.trash: true
survivalplus.workbench: true
survivalplus.anvil: true
survivalplus.leashcount: true
survivalplus.nick: true
survivalplus.lootchests: true
survivalplus.startchallenge: true
survivalplus.heal: true
survivalplus.heal.others: true
survivalplus.notify: true
survivalplus.lootchests:
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
default: op
survivalplus.gamemode:
description: Erlaubt das Ändern des eigenen Spielmodus
default: op
survivalplus.gamemode.others:
description: Erlaubt das Ändern des Spielmodus anderer Spieler
default: op
survivalplus.sp:
description: Erlaubt den Zugriff auf den /sp-Befehl
default: op
survivalplus.share:
description: Erlaubt das Teilen der eigenen Koordinaten mit /sp share
default: true
survivalplus.homes.set:
description: Erlaubt das Setzen von Homes
default: true
survivalplus.homes.delete:
description: Erlaubt das Löschen von Homes
default: true
survivalplus.homes.list:
description: Erlaubt das Öffnen der Home-Liste GUI
default: true
survivalplus.homes:
description: Erlaubt das Teleportieren zu Homes
default: true
survivalplus.homes.unlimited:
description: Erlaubt unbegrenzte Homes
default: op
survivalplus.inventory.own:
description: Erlaubt das Ansehen des eigenen Inventars
default: true
survivalplus.inventory.others:
description: Erlaubt das Ansehen des Inventars anderer Spieler
default: op
survivalplus.enderchest.own:
description: Erlaubt das Ansehen der eigenen Endertruhe
default: true
survivalplus.enderchest.others:
description: Erlaubt das Ansehen der Endertruhen anderer Spieler
default: op
survivalplus.setworldspawn:
description: Erlaubt das Setzen des Weltspawnpunkts
default: op
survivalplus.setspawn:
description: Erlaubt das Setzen des Server-Spawnpunkts
default: op
survivalplus.clearchat:
description: Erlaubt das Löschen des Chats
default: op
survivalplus.clearitems:
description: Erlaubt das manuelle Löschen der herumliegenden Items
default: op
survivalplus.closedoors:
description: Erlaubt das Schließen von Türen mit /closedoors
default: op
survivalplus.sit:
description: Erlaubt das Sitzen auf Treppen oder mit /sit
default: true
survivalplus.graves:
description: Erlaubt das Erstellen von Gräbern bei Tod
default: true
survivalplus.back:
description: Erlaubt das Teleportieren zum letzten Todespunkt
default: true
survivalplus.friend:
description: Erlaubt die Verwaltung der Freundesliste
default: true
survivalplus.itemrename:
description: Erlaubt das Umbenennen von Items mit /ir
default: true
survivalplus.stats:
description: Erlaubt den Zugriff auf den /stats-Befehl
default: true
survivalplus.showarmorstands:
description: Erlaubt das Sichtbarmachen von Armor Stands mit /showarmorstands
default: op
survivalplus.cleardebugarmorstands:
description: Erlaubt das Entfernen von Debug-ArmorStands
default: op
survivalplus.trash:
description: Erlaubt die Nutzung von /trash
default: true
survivalplus.workbench:
description: Erlaubt die Nutzung von /workbench
default: true
survivalplus.anvil:
description: Erlaubt die Nutzung von /anvil
default: true
survivalplus.leashcount:
description: Erlaubt die Nutzung von /leashcount
default: true
survivalplus.chunkanimals:
description: Erlaubt das Anzeigen der Anzahl der Tiere im aktuellen Chunk
default: op
survivalplus.lock:
description: Erlaubt das Verwenden von /lock-Befehlen
default: true
survivalplus.tp:
description: Erlaube das Teleportieren zu anderen Spielern
default: op
survivalplus.tphere:
description: Erlaube das Teleportieren anderer Spieler zu dir
default: op
survivalplus.tpa:
description: Erlaube das Senden von Teleportanfragen
default: true
survivalplus.tpaccept:
description: Erlaube das Annehmen von Teleportanfragen
default: true
survivalplus.tpdeny:
description: Erlaube das Ablehnen von Teleportanfragen
default: true
survivalplus.block:
description: Erlaubt das Blockieren anderer Spieler im Chat
default: true
survivalplus.info:
description: Erlaubt den Zugriff auf /sp info
default: true
survivalplus.nick:
description: Erlaubt es, den eigenen Nicknamen zu ändern (mit Farben & Hex)
default: op
survivalplus.shop:
description: Erlaubt die Nutzung des Shop-Befehls
default: op
survivalplus.spawn:
description: Erlaubt die Nutzung des /spawn Befehls
default: true
survivalplus.setwarp:
description: Erlaubt das Setzen von persönlichen Warps
default: true
survivalplus.warps:
description: Erlaubt das Öffnen der Warps-GUI
default: true
delwarp:
description: Erlaubt das Löschen von persönlichen Warps
default: true

View File

View File

@@ -0,0 +1,2 @@
# stats.yml

View File

@@ -0,0 +1,42 @@
# ===============================
# Tablist-Konfiguration für SurvivalPlus
# ===============================
# Tablist aktivieren/deaktivieren
enabled: true
# Servername für den Header
server-name: "&l&6✦✦ SURVIVALPLUS ✦✦"
# Webseite des Servers
website: "www.example.com"
# TeamSpeak-Adresse
teamspeak-address: "ts.example.com"
show-teamspeak: true
# Discord-Adresse
discord-address: "discord.gg/example"
show-discord: true
# Berechtigung für Staff-Zählung
staff-permission: "survivalplus.staff"
# Trennlinie für den Footer
separator-line: "&8&l&m================================"
# Kopf-Animationen
# Platzhalter: {server} = Servername, {player} = Spielername, {online} = Online-Spieler, {staff} = Online-Staff
header-animations:
- "&6&l{server}\n&7Willkommen, &a{player}\n&7Online Player: &e{online}\n&6Online Staff: &e{staff}\n"
- "&e&l{server}\n&7Willkommen, &a{player}\n&7Online Player: &e{online}\n&6Online Staff: &e{staff}\n"
- "&b&l{server}\n&7Willkommen, &a{player}\n&7Online Player: &e{online}\n&6Online Staff: &e{staff}\n"
# Fuß-Animationen
footer-animations:
- "&7SurvivalPlus &8| &eDein Abenteuer!"
- "&7SurvivalPlus &8| &bEntdecke die Welt!"
- "&7SurvivalPlus &8| &aBaue, kämpfe, überlebe!"
# Intervall der Animation in Ticks (20 = 1 Sekunde)
interval-ticks: 40

Some files were not shown because too many files have changed in this diff Show More