Update from Git Manager GUI

This commit is contained in:
2026-01-13 21:06:39 +01:00
parent 08b05167d8
commit e5251933e1
13 changed files with 1242 additions and 128 deletions

View File

@@ -13,6 +13,10 @@ public class ShopManager {
private final File shopFile;
private final FileConfiguration shopConfig;
// Multiplikatoren für dynamische Preise
private double buyMultiplier;
private double sellMultiplier;
public ShopManager(SurvivalPlus plugin) {
this.plugin = plugin;
this.shopFile = new File(plugin.getDataFolder(), "shop.yml");
@@ -20,8 +24,16 @@ public class ShopManager {
if (!shopFile.exists()) {
plugin.saveResource("shop.yml", false);
}
this.shopConfig = YamlConfiguration.loadConfiguration(shopFile);
// Multiplikatoren laden
loadMultipliers();
}
public void loadMultipliers() {
this.buyMultiplier = plugin.getConfig().getDouble("economy.buy-multiplier", 1.05);
this.sellMultiplier = plugin.getConfig().getDouble("economy.sell-multiplier", 0.95);
plugin.getLogger().info("Shop-Multiplikatoren geladen: Buy=" + buyMultiplier + ", Sell=" + sellMultiplier);
}
public double getCurrentPrice(String itemKey) {
@@ -33,22 +45,22 @@ public class ShopManager {
}
/**
* Spieler kauft Item: Lager sinkt, Preis steigt (Verknappung)
* Spieler kauft Item: Preis steigt
*/
public boolean buyItem(String itemKey, int amount) {
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
if (stock < amount) {
return false;
// Fallback auf Base-Price wenn noch keine Transaktion stattfand (sonst wird 1.05 auf 0 gerechnet)
double currentPrice = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
if (currentPrice == 0) {
currentPrice = shopConfig.getDouble("items." + itemKey + ".base-price", 100);
}
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
// Lager aktualisieren (optional, oder unendlich)
// shopConfig.set("items." + itemKey + ".stock", stock - amount);
// Lager aktualisieren
shopConfig.set("items." + itemKey + ".stock", stock - amount);
// Preis erhöhen (Faktor 1.05 = +5%)
double newPrice = price * 1.05;
// Preis erhöhen (Dynamisch)
double newPrice = currentPrice * buyMultiplier;
shopConfig.set("items." + itemKey + ".current-price", newPrice);
saveShop();
@@ -56,19 +68,20 @@ public class ShopManager {
}
/**
* Spieler verkauft Item: Lager steigt, Preis sinkt (Überfluss)
* Spieler verkauft Item: Preis sinkt
*/
public boolean sellItem(String itemKey, int amount) {
// Hier könnte man prüfen, ob der Shop genügend Geld hat (falls nötig)
// Fallback auf Base-Price
double currentPrice = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
if (currentPrice == 0) {
currentPrice = shopConfig.getDouble("items." + itemKey + ".base-price", 100);
}
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
// Lager aktualisieren (optional)
// shopConfig.set("items." + itemKey + ".stock", stock + amount);
// Lager aktualisieren
shopConfig.set("items." + itemKey + ".stock", stock + amount);
// Preis senken (Faktor 0.95 = -5%)
double newPrice = price * 0.95;
// Preis senken (Dynamisch)
double newPrice = currentPrice * sellMultiplier;
shopConfig.set("items." + itemKey + ".current-price", newPrice);
saveShop();
@@ -78,7 +91,10 @@ public class ShopManager {
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);
// Wenn der Preis noch nicht existiert (neues Item), setze ihn auf Base-Preis
if (!shopConfig.contains("items." + itemKey + ".current-price")) {
shopConfig.set("items." + itemKey + ".current-price", basePrice);
}
saveShop();
}

View File

@@ -33,6 +33,7 @@ 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.ShopCommand;
import de.viper.survivalplus.commands.HealCommand;
import de.viper.survivalplus.Manager.TablistManager;
import de.viper.survivalplus.Manager.CommandBlocker;
@@ -42,6 +43,19 @@ import de.viper.survivalplus.commands.WarpsCommand;
import de.viper.survivalplus.fun.FunChallengeManager;
import de.viper.survivalplus.listeners.ChallengeCollectListener;
import de.viper.survivalplus.commands.StartFunChallengeCommand;
// --- NEU: Imports für Heads, Vanish & Shops ---
import de.viper.survivalplus.commands.HeadCommand;
import de.viper.survivalplus.listeners.HeadDropListener;
import de.viper.survivalplus.listeners.VanishListener;
import de.viper.survivalplus.listeners.SignShopListener;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import java.util.Map;
import java.util.UUID;
import java.util.HashMap;
@@ -71,8 +85,9 @@ import java.io.FileWriter;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.RegisteredServiceProvider;
public class SurvivalPlus extends JavaPlugin {
@@ -136,6 +151,12 @@ public class SurvivalPlus extends JavaPlugin {
private File consoleFile;
private PrintWriter consoleWriter;
// --- NEU: Vanish & Economy Support ---
private Map<UUID, Boolean> vanishedPlayers = new HashMap<>();
private Economy economy = null;
private final String VANISH_META_KEY = "vanished";
// ---------------------------------------
public void reloadTablistConfig() {
if (tablistFile == null) tablistFile = new File(getDataFolder(), "tablist.yml");
if (!tablistFile.exists()) {
@@ -251,6 +272,19 @@ public class SurvivalPlus extends JavaPlugin {
createNicknamesFile();
reloadBlockedCommandsConfig();
loadClaims();
// --- NEU: Vault Economy Setup ---
if (Bukkit.getPluginManager().getPlugin("Vault") != null) {
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
if (rsp != null) {
economy = rsp.getProvider();
getLogger().info("Vault Economy erfolgreich verbunden.");
} else {
getLogger().warning("Vault Plugin gefunden, aber kein Economy Provider!");
}
}
// -------------------------------------------------
PluginManager pluginManager = getServer().getPluginManager();
try {
Permission notifyPerm = new Permission("survivalplus.notify", PermissionDefault.OP);
@@ -342,9 +376,11 @@ public class SurvivalPlus extends JavaPlugin {
pluginManager.registerEvents(lootChestManager, this);
getCommand("lootchests").setExecutor(lootChestManager);
getCommand("tploot").setExecutor(lootChestManager);
getCommand("vanish").setExecutor(new AdminToolsCommand(this));
getCommand("freeze").setExecutor(new AdminToolsCommand(this));
getCommand("ride").setExecutor(new RideCommand(this));
getCommand("claim").setExecutor(new ClaimCommand(this));
// HIER: (this) hinzugefügt, damit der BlockManager die Datei speichern kann
BlockManager blockManager = new BlockManager(this);
FileConfiguration config = getConfig();
BackpackRecipe.register(this, langConfig);
@@ -354,6 +390,12 @@ public class SurvivalPlus extends JavaPlugin {
getCommand("unblock").setExecutor(new UnblockCommand(blockManager, getConfig()));
getCommand("blocklist").setExecutor(new BlockListCommand(blockManager, getConfig()));
// --- NEU: NEUE LISTENER & COMMANDS ---
getCommand("head").setExecutor(new HeadCommand(this));
pluginManager.registerEvents(new HeadDropListener(this), this);
pluginManager.registerEvents(new VanishListener(this), this);
// ------------------------------------
pluginManager.registerEvents(new ChatBlockListener(blockManager), this);
pluginManager.registerEvents(new InventoryClickListener(this), this);
pluginManager.registerEvents(sitListener, this);
@@ -367,6 +409,7 @@ public class SurvivalPlus extends JavaPlugin {
pluginManager.registerEvents(new FirstJoinListener(), this);
pluginManager.registerEvents(playerJoinListener, this);
pluginManager.registerEvents(new SignColorListener(this), this);
pluginManager.registerEvents(new SignShopListener(this), this);
pluginManager.registerEvents(new SleepListener(this), this);
pluginManager.registerEvents(new OreAlarmListener(this), this);
pluginManager.registerEvents(new MobLeashLimitListener(this, getConfig()), this);
@@ -456,7 +499,7 @@ public class SurvivalPlus extends JavaPlugin {
getLogger().info("Block-Regeln angewendet: CommandBlocks erlaubt=" + cmdAllowed + ", StructureBlocks erlaubt=" + structAllowed);
}
private void ensureVersionAtTop(File file, String version) {
private void ensureVersionAtTop(File file, String version) {
try {
if (!file.exists()) return; // Datei existiert nicht
List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
@@ -526,7 +569,6 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
}
}
private void removeForbiddenBlocksFromInventories(boolean cmdAllowed, boolean structAllowed) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.hasPermission("survivalplus.notify")) {
@@ -567,6 +609,7 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
}
}
// === Claims.yml ===
private void createClaimsFile() {
claimsFile = new File(getDataFolder(), "claims.yml");
if (!claimsFile.exists()) {
@@ -700,6 +743,30 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
return false;
}
// --- NEU: Delete Claim Methode ---
public void deleteClaim(Claim claim) {
String key = getClaimKey(claim);
if (key != null) {
claims.remove(key);
playerClaimCounts.merge(claim.getOwner(), -1, Integer::sum);
saveClaims();
}
}
private String getClaimKey(Claim claim) {
for (Map.Entry<String, Claim> entry : claims.entrySet()) {
if (entry.getValue() == claim) {
return entry.getKey();
}
}
return null;
}
// -----------------------------
// WICHTIG: Getter für Claim Config für Ban-System
public FileConfiguration getClaimsConfig() {
return claimsConfig;
}
// Methoden für nicknames.yml
@@ -750,8 +817,8 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
@Override
public void onDisable() {
if (debugWriter != null) {
debugWriter.close();
}
debugWriter.close();
}
if (autoClearTaskId != -1) {
Bukkit.getScheduler().cancelTask(autoClearTaskId);
}
@@ -760,15 +827,14 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
saveMobCapConfig();
saveMobAdaptConfig(); // NEU: Adaptive Mob Config speichern
// NEU: NewbieProtection-Daten sichern
if (newbieListener != null) {
newbieListener.saveData();
}
// NEU: NewbieProtection-Daten sichern
if (newbieListener != null) {
newbieListener.saveData();
}
getLogger().info(getMessage("plugin.disabled"));
}
public void saveStats() {
if (statsManager != null) {
statsManager.saveStats();
@@ -1228,11 +1294,12 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
e.printStackTrace();
}
}
public BannerManager getBannerManager() {
return bannerManager;
}
}
// Nur Fehler/Exceptions
// Nur Fehler/Exceptions
public void log(String msg) {
if (getConfig().getBoolean("debug-logging", false) && debugWriter != null) {
debugWriter.println("[" + new java.util.Date() + "] " + msg);
@@ -1258,4 +1325,33 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
getLogger().info(msg); // Optional: zusätzlich Konsole ausgeben
}
// --- NEU: HELFERMETHODEN FÜR NEUE FEATURES ---
// Vanish
public void setVanished(UUID uuid, boolean vanished) {
if (vanished) {
vanishedPlayers.put(uuid, true);
} else {
vanishedPlayers.remove(uuid);
}
}
public boolean isVanished(UUID uuid) {
return vanishedPlayers.containsKey(uuid) && vanishedPlayers.get(uuid);
}
public Map<UUID, Boolean> getVanishedPlayers() {
return vanishedPlayers;
}
// Economy
public Economy getEconomy() {
return economy;
}
// ProtocolLib Bridge (für Silent Vanish)
public ProtocolManager getProtocolManager() {
return ProtocolLibrary.getProtocolManager();
}
}

View File

@@ -0,0 +1,141 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location; // <--- WICHTIG: Das war der Fehler
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.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class AdminToolsCommand implements CommandExecutor, Listener {
private final SurvivalPlus plugin;
private final Set<UUID> vanishedPlayers = new HashSet<>();
private final Set<UUID> frozenPlayers = new HashSet<>();
public AdminToolsCommand(SurvivalPlus plugin) {
this.plugin = plugin;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Nur Spieler können diesen Befehl nutzen!");
return true;
}
Player player = (Player) sender;
FileConfiguration lang = plugin.getLangConfig();
// --- VANISH ---
if (command.getName().equalsIgnoreCase("vanish")) {
if (!player.hasPermission("survivalplus.vanish")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
if (vanishedPlayers.contains(player.getUniqueId())) {
// Ent-vanish
for (Player all : Bukkit.getOnlinePlayers()) {
all.showPlayer(plugin, player);
}
player.setPlayerListName(player.getName()); // Name wieder in Tab-Liste anzeigen
vanishedPlayers.remove(player.getUniqueId());
player.sendMessage(ChatColor.GREEN + "Du bist nun sichtbar.");
} else {
// Vanish
for (Player all : Bukkit.getOnlinePlayers()) {
all.hidePlayer(plugin, player);
}
vanishedPlayers.add(player.getUniqueId());
player.sendMessage(ChatColor.GREEN + "Du bist nun unsichtbar.");
}
return true;
}
// --- FREEZE ---
if (command.getName().equalsIgnoreCase("freeze")) {
if (!player.hasPermission("survivalplus.freeze")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
if (args.length == 0) {
player.sendMessage(ChatColor.RED + "Verwendung: /freeze <Spieler>");
return true;
}
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
player.sendMessage(ChatColor.RED + "Spieler nicht gefunden!");
return true;
}
if (frozenPlayers.contains(target.getUniqueId())) {
// Ent-freezen
frozenPlayers.remove(target.getUniqueId());
player.sendMessage(ChatColor.GREEN + target.getName() + " wurde aufgetaut.");
target.sendMessage(ChatColor.GREEN + "Du bist nicht mehr eingefroren.");
} else {
// Einfrieren
frozenPlayers.add(target.getUniqueId());
player.sendMessage(ChatColor.GREEN + target.getName() + " wurde eingefroren.");
target.sendMessage(ChatColor.RED + "Du wurdest von einem Admin eingefroren! " + ChatColor.BOLD + "Keine Bewegung möglich!");
}
return true;
}
return false;
}
// --- EVENTS ---
// Verhindert Bewegung wenn eingefroren
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
// Kopf drehen (YAW/PITCH) ist okay, Blocken wenn Position (X/Y/Z) ändert
if (frozenPlayers.contains(player.getUniqueId())) {
Location from = event.getFrom();
Location to = event.getTo();
// Wenn die Koordinaten sich ändern
if (to.getX() != from.getX() || to.getY() != from.getY() || to.getZ() != from.getZ()) {
event.setCancelled(true);
// Optional: Kleine Meldung beim Versuch zu laufen
// player.sendMessage(ChatColor.RED + "Du bist eingefroren!");
}
}
}
// Wenn ein Spieler joint: Hide vanished players for him
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player joiner = event.getPlayer();
for (UUID vanishedUUID : vanishedPlayers) {
Player vanishedPlayer = Bukkit.getPlayer(vanishedUUID);
if (vanishedPlayer != null && vanishedPlayer.isOnline()) {
joiner.hidePlayer(plugin, vanishedPlayer);
}
}
}
// Cleanup wenn ein Spieler geht
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
vanishedPlayers.remove(event.getPlayer().getUniqueId());
frozenPlayers.remove(event.getPlayer().getUniqueId());
}
}

View File

@@ -3,15 +3,19 @@ package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.util.Claim;
import org.bukkit.Bukkit;
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.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.util.UUID;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.UUID;
public class ClaimCommand implements CommandExecutor {
private SurvivalPlus plugin;
@@ -71,7 +75,7 @@ public class ClaimCommand implements CommandExecutor {
}
switch (args[0].toLowerCase()) {
case "mark":
case "mark": {
if (!player.hasPermission("survivalplus.claim.use")) {
player.sendMessage(plugin.getMessage("commands.no-permission"));
return true;
@@ -89,22 +93,13 @@ public class ClaimCommand implements CommandExecutor {
player.sendMessage(plugin.getMessage("claim.point2-set").replace("%x%", String.valueOf(location.getBlockX())).replace("%z%", String.valueOf(location.getBlockZ())));
}
return true;
}
case "unclaim":
if (args.length == 1) {
if (!player.hasPermission("survivalplus.claim.use")) {
player.sendMessage(plugin.getMessage("commands.no-permission"));
return true;
}
Claim claim = plugin.getClaim(player.getLocation());
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
player.sendMessage(plugin.getMessage("claim.not-owner"));
return true;
}
plugin.removeClaim(player.getLocation(), player);
player.sendMessage(plugin.getMessage("claim.unclaimed"));
return true;
} else if (args.length == 2 && player.isOp()) {
case "del":
case "delete": {
// 1. Mass Delete (Admin): /claim unclaim <Spieler> (oder del/delete)
if (args.length == 2 && player.isOp()) {
Player target = Bukkit.getPlayer(args[1]);
UUID targetUUID;
if (target != null) {
@@ -127,12 +122,38 @@ public class ClaimCommand implements CommandExecutor {
.replace("%player%", args[1]));
}
return true;
} else {
player.sendMessage(plugin.getMessage("claim.usage"));
}
// 2. Normaler oder Admin Targeted Delete
Claim claim = plugin.getClaim(player.getLocation());
if (claim == null) {
player.sendMessage(plugin.getMessage("claim.no-claim-at-location"));
return true;
}
case "trust":
// Prüfen, ob Spieler Owner ist (oder OP)
if (!claim.getOwner().equals(player.getUniqueId())) {
// NICHT Owner -> Aber Admin?
if (player.isOp()) {
plugin.deleteClaim(claim);
String ownerName = Bukkit.getOfflinePlayer(claim.getOwner()).getName();
if (ownerName == null) ownerName = "Unbekannt";
player.sendMessage(ChatColor.GREEN + "Claim wurde entfernt. (Besitzer war: " + ChatColor.YELLOW + ownerName + ChatColor.GREEN + ")");
return true;
} else {
// Nicht Owner und kein Admin -> Abbruch
player.sendMessage(plugin.getMessage("claim.not-owner"));
return true;
}
}
// Owner löscht eigenen Claim
plugin.deleteClaim(claim);
player.sendMessage(plugin.getMessage("claim.unclaimed"));
return true;
}
case "trust": {
if (!player.hasPermission("survivalplus.claim.trust")) {
player.sendMessage(plugin.getMessage("commands.no-permission"));
return true;
@@ -146,17 +167,18 @@ public class ClaimCommand implements CommandExecutor {
player.sendMessage(plugin.getMessage("commands.player-not-found"));
return true;
}
Claim claim = plugin.getClaim(player.getLocation());
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
Claim trustClaim = plugin.getClaim(player.getLocation());
if (trustClaim == null || !trustClaim.getOwner().equals(player.getUniqueId())) {
player.sendMessage(plugin.getMessage("claim.not-owner"));
return true;
}
claim.addTrusted(target.getUniqueId());
trustClaim.addTrusted(target.getUniqueId());
player.sendMessage(plugin.getMessage("claim.trusted").replace("%player%", args[1]));
plugin.saveClaims();
break;
return true;
}
case "untrust":
case "untrust": {
if (!player.hasPermission("survivalplus.claim.trust")) {
player.sendMessage(plugin.getMessage("commands.no-permission"));
return true;
@@ -165,43 +187,145 @@ public class ClaimCommand implements CommandExecutor {
player.sendMessage(plugin.getMessage("claim.usage-untrust"));
return true;
}
target = Bukkit.getPlayer(args[1]);
Player target = Bukkit.getPlayer(args[1]);
if (target == null) {
player.sendMessage(plugin.getMessage("commands.player-not-found"));
return true;
}
claim = plugin.getClaim(player.getLocation());
if (claim == null || !claim.getOwner().equals(player.getUniqueId())) {
Claim trustClaim = plugin.getClaim(player.getLocation());
if (trustClaim == null || !trustClaim.getOwner().equals(player.getUniqueId())) {
player.sendMessage(plugin.getMessage("claim.not-owner"));
return true;
}
claim.removeTrusted(target.getUniqueId());
trustClaim.removeTrusted(target.getUniqueId());
player.sendMessage(plugin.getMessage("claim.untrusted").replace("%player%", args[1]));
plugin.saveClaims();
break;
return true;
}
case "info":
// --- NEU: KICK ---
case "kick": {
if (!player.hasPermission("survivalplus.claim.kick")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
if (args.length < 2) {
player.sendMessage(ChatColor.RED + "Verwendung: /claim kick <Spieler>");
return true;
}
Player kickTarget = Bukkit.getPlayer(args[1]);
if (kickTarget == null) {
player.sendMessage(ChatColor.RED + "Spieler nicht gefunden oder offline!");
return true;
}
Claim currentClaim = plugin.getClaim(kickTarget.getLocation());
if (currentClaim == null || !currentClaim.getOwner().equals(player.getUniqueId())) {
player.sendMessage(ChatColor.RED + "Du bist hier nicht Besitzer oder kein Claim.");
return true;
}
kickPlayerFromClaim(kickTarget, currentClaim);
player.sendMessage(ChatColor.GREEN + "Spieler " + kickTarget.getName() + " wurde aus dem Claim gekickt!");
kickTarget.sendMessage(ChatColor.RED + "Du wurdest aus dem Claim geworfen!");
return true;
}
// --- NEU: BAN ---
case "ban": {
if (!player.hasPermission("survivalplus.claim.ban")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
if (args.length < 2) {
player.sendMessage(ChatColor.RED + "Verwendung: /claim ban <Spieler>");
return true;
}
String claimKey = getClaimKeyAtLocation(player.getLocation());
if (claimKey == null) {
player.sendMessage(ChatColor.RED + "Du stehst in keinem Claim.");
return true;
}
Player banTarget = Bukkit.getPlayer(args[1]);
UUID banUUID;
if (banTarget != null) {
banUUID = banTarget.getUniqueId();
Claim banCheck = plugin.getClaim(player.getLocation());
if (banCheck != null && banCheck.isInside(banTarget.getLocation())) {
kickPlayerFromClaim(banTarget, banCheck);
banTarget.sendMessage(ChatColor.RED + "Du wurdest aus dem Claim geworfen und gebannt!");
}
} else {
try {
banUUID = UUID.fromString(args[1]);
} catch (IllegalArgumentException e) {
player.sendMessage(ChatColor.RED + "Ungültige UUID oder Spieler nicht online.");
return true;
}
}
banPlayerInClaim(banUUID, claimKey);
player.sendMessage(ChatColor.GREEN + "Spieler wurde von diesem Claim gebannt.");
return true;
}
// --- NEU: UNBAN ---
case "unban": {
if (!player.hasPermission("survivalplus.claim.ban")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
if (args.length < 2) {
player.sendMessage(ChatColor.RED + "Verwendung: /claim unban <Spieler>");
return true;
}
Player unbanTarget = Bukkit.getPlayer(args[1]);
UUID unbanUUID;
if (unbanTarget != null) {
unbanUUID = unbanTarget.getUniqueId();
} else {
try {
unbanUUID = UUID.fromString(args[1]);
} catch (IllegalArgumentException e) {
player.sendMessage(ChatColor.RED + "Ungültige UUID.");
return true;
}
}
String claimKeyUnban = getClaimKeyAtLocation(player.getLocation());
if (claimKeyUnban == null) {
player.sendMessage(ChatColor.RED + "Du stehst in keinem Claim.");
return true;
}
unbanPlayerInClaim(unbanUUID, claimKeyUnban);
player.sendMessage(ChatColor.GREEN + "Spieler wurde für diesen Claim entbannt.");
return true;
}
case "info": {
if (!player.hasPermission("survivalplus.claim.use")) {
player.sendMessage(plugin.getMessage("commands.no-permission"));
return true;
}
claim = plugin.getClaim(player.getLocation());
if (claim == null) {
Claim infoClaim = plugin.getClaim(player.getLocation());
if (infoClaim == null) {
player.sendMessage(plugin.getMessage("claim.no-claim-at-location"));
return true;
}
String ownerName = Bukkit.getOfflinePlayer(claim.getOwner()).getName();
String ownerName = Bukkit.getOfflinePlayer(infoClaim.getOwner()).getName();
if (ownerName == null) {
ownerName = claim.getOwner().toString(); // Fallback to UUID if name not found
ownerName = infoClaim.getOwner().toString();
}
player.sendMessage(plugin.getMessage("claim.info")
.replace("%owner%", ownerName)
.replace("%world%", claim.getWorldName())
.replace("%x1%", String.valueOf(claim.getX1()))
.replace("%z1%", String.valueOf(claim.getZ1()))
.replace("%x2%", String.valueOf(claim.getX2()))
.replace("%z2%", String.valueOf(claim.getZ2())));
.replace("%world%", infoClaim.getWorldName())
.replace("%x1%", String.valueOf(infoClaim.getX1()))
.replace("%z1%", String.valueOf(infoClaim.getZ1()))
.replace("%x2%", String.valueOf(infoClaim.getX2()))
.replace("%z2%", String.valueOf(infoClaim.getZ2())));
return true;
}
default:
player.sendMessage(plugin.getMessage("claim.usage"));
@@ -223,4 +347,62 @@ public class ClaimCommand implements CommandExecutor {
}
return removedCount;
}
// --- HILFSMETHODEN ---
private void kickPlayerFromClaim(Player player, Claim claim) {
Location loc = player.getLocation();
int x = loc.getBlockX();
int z = loc.getBlockZ();
int minX = Math.min(claim.getX1(), claim.getX2());
int maxX = Math.max(claim.getX1(), claim.getX2());
int minZ = Math.min(claim.getZ1(), claim.getZ2());
int maxZ = Math.max(claim.getZ1(), claim.getZ2());
int distX1 = Math.abs(x - minX);
int distX2 = Math.abs(x - maxX);
int distZ1 = Math.abs(z - minZ);
int distZ2 = Math.abs(z - maxZ);
int minDist = Math.min(Math.min(distX1, distX2), Math.min(distZ1, distZ2));
Location newLoc = loc.clone();
if (minDist == distX1) {
newLoc.setX(minX - 1);
} else if (minDist == distX2) {
newLoc.setX(maxX + 1);
} else if (minDist == distZ1) {
newLoc.setZ(minZ - 1);
} else {
newLoc.setZ(maxZ + 1);
}
newLoc.setY(newLoc.getY() + 1);
player.teleport(newLoc);
}
private String getClaimKeyAtLocation(Location loc) {
for (String key : plugin.getClaims().keySet()) {
if (plugin.getClaims().get(key).isInside(loc)) {
return key;
}
}
return null;
}
private void banPlayerInClaim(UUID uuid, String claimKey) {
FileConfiguration config = plugin.getClaimsConfig();
List<String> banned = config.getStringList(claimKey + ".banned");
if (!banned.contains(uuid.toString())) {
banned.add(uuid.toString());
config.set(claimKey + ".banned", banned);
plugin.saveClaims();
}
}
private void unbanPlayerInClaim(UUID uuid, String claimKey) {
FileConfiguration config = plugin.getClaimsConfig();
List<String> banned = config.getStringList(claimKey + ".banned");
banned.remove(uuid.toString());
config.set(claimKey + ".banned", banned);
plugin.saveClaims();
}
}

View File

@@ -0,0 +1,58 @@
package de.viper.survivalplus.commands;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
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.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
public class HeadCommand implements CommandExecutor {
private SurvivalPlus plugin;
public HeadCommand(SurvivalPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Nur Spieler können diesen Befehl nutzen.");
return true;
}
Player player = (Player) sender;
if (args.length == 0) {
player.sendMessage(plugin.getMessage("commands.player-only"));
return true;
}
if (!player.hasPermission("survivalplus.head")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung!");
return true;
}
String targetName = args[0];
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
if (target == null) {
player.sendMessage(ChatColor.RED + "Spieler '" + targetName + "' wurde nie gefunden.");
return true;
}
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) head.getItemMeta();
meta.setOwningPlayer(target);
meta.setDisplayName(ChatColor.YELLOW + "Kopf von " + targetName);
head.setItemMeta(meta);
player.getInventory().addItem(head);
player.sendMessage(ChatColor.GREEN + "Du hast den Kopf von " + targetName + " erhalten!");
return true;
}
}

View File

@@ -2,7 +2,7 @@ package de.viper.survivalplus.commands;
import de.viper.survivalplus.Manager.ShopManager;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.gui.ShopGui; // <--- WICHTIG: Dieser Import fehlte dir
import de.viper.survivalplus.gui.ShopGui;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -11,15 +11,33 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.plugin.RegisteredServiceProvider;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
public class ShopCommand implements CommandExecutor {
private final ShopManager shopManager;
private final SurvivalPlus plugin;
private Economy economy;
public ShopCommand(SurvivalPlus plugin) {
this.plugin = plugin;
this.shopManager = new ShopManager(plugin);
// Economy laden (für Admin-Verkauf an Server)
try {
if (Bukkit.getPluginManager().isPluginEnabled("Vault")) {
RegisteredServiceProvider<Economy> rsp = Bukkit.getServicesManager().getRegistration(Economy.class);
if (rsp != null) {
this.economy = rsp.getProvider();
plugin.getLogger().info("Vault Economy für ShopCommand gefunden.");
}
}
} catch (Exception e) {
// Ignorieren wenn Vault fehlt
}
}
private String getMessage(String key) {
@@ -35,78 +53,102 @@ public class ShopCommand implements CommandExecutor {
Player player = (Player) sender;
// Shop-GUI öffnen
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
if (args.length == 0 || (args.length > 0 && args[0].equalsIgnoreCase("gui"))) {
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
player.openInventory(shopGui.getInventory());
return true;
}
if (!args[0].toLowerCase().equals("add")) {
sender.sendMessage(getMessage("unknown-subcommand"));
return true;
}
// --- SHOP ADD LOGIK ---
if (args.length >= 4 && args[0].equalsIgnoreCase("add")) {
// --- Neue Logik für /shop add ---
// Economy-Check
if (economy == null) {
sender.sendMessage(ChatColor.RED + "Vault Economy ist nicht verfügbar!");
return true;
}
String itemKey;
double basePrice;
int stock;
// Fall 1: /shop add <Material> <Preis> <Stock> (4 Argumente)
if (args.length >= 4) {
String materialName = args[1];
String priceStr = args[2];
String amountStr = args[3];
Material mat = Material.matchMaterial(materialName);
if (mat == null) {
sender.sendMessage(ChatColor.RED + "Das Material '" + materialName + "' wurde nicht gefunden!");
return true;
}
itemKey = mat.name().toLowerCase();
double price;
int amount;
try {
basePrice = Double.parseDouble(args[2]);
stock = Integer.parseInt(args[3]);
price = Double.parseDouble(priceStr);
amount = Integer.parseInt(amountStr);
} catch (NumberFormatException e) {
sender.sendMessage(ChatColor.RED + "Ungültige Preis oder Bestandszahl! Beispiel: /shop add Diamond 20 64");
return true;
}
}
// Fall 2: /shop add <Preis> <Stock> (3 Argumente) -> Nimmt Item in der Hand
else if (args.length == 3) {
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!");
sender.sendMessage(ChatColor.GRAY + "Oder benutze: /shop add <Material> <Preis> <Bestand>");
if (amount <= 0 || price < 0) {
sender.sendMessage(ChatColor.RED + "Menge und Preis müssen positiv sein.");
return true;
}
itemKey = itemInHand.getType().name().toLowerCase();
try {
basePrice = Double.parseDouble(args[1]);
stock = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {
sender.sendMessage(getMessage("number-error"));
// 1. Prüfen: Hat der Spieler die Items?
int hasAmount = countItems(player.getInventory(), mat);
if (hasAmount < amount) {
sender.sendMessage(ChatColor.RED + "Du hast nicht genug Items! (Benötigt: " + amount + ", Vorhanden: " + hasAmount + ")");
return true;
}
}
// Falsche Anzahl an Argumenten
else {
sender.sendMessage(ChatColor.RED + "Falsche Benutzung!");
sender.sendMessage(ChatColor.GRAY + "Mit Item in Hand: /shop add <Preis> <Bestand>");
sender.sendMessage(ChatColor.GRAY + "Mit Namen: /shop add <Material> <Preis> <Bestand>");
// 2. Items aus Inventar entfernen
player.getInventory().removeItem(new ItemStack(mat, amount));
player.updateInventory(); // Wichtig für Client-Update
// 3. Spieler Geld geben (Verkauf an Server)
double totalCost = price * amount;
EconomyResponse response = economy.depositPlayer(player, totalCost);
if (response.transactionSuccess()) {
sender.sendMessage(ChatColor.GREEN + "Du hast " + amount + " " + mat.name() + " für " + totalCost + " Coins an den Server verkauft!");
// 4. Shop-Config aktualisieren (Lagerbestand erhöhen)
String itemKey = mat.name().toLowerCase();
shopManager.addOrUpdateItem(itemKey, price, shopManager.getStock(itemKey) + amount);
} else {
sender.sendMessage(ChatColor.RED + "Fehler bei der Auszahlung!");
return true;
}
return true;
}
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
String msg = getMessage("item-added")
.replace("{item}", itemKey)
.replace("{price}", String.valueOf(basePrice))
.replace("{stock}", String.valueOf(stock));
sender.sendMessage(msg);
// Fallback für falsche Argumente
if (args.length > 0 && args[0].equalsIgnoreCase("add")) {
sender.sendMessage(ChatColor.RED + "Falsche Benutzung!");
sender.sendMessage(ChatColor.GRAY + "Mit Item in Hand: /shop add <Preis> <Bestand>");
sender.sendMessage(ChatColor.GRAY + "Mit Namen: /shop add <Material> <Preis> <Bestand>");
return true;
}
sender.sendMessage(ChatColor.RED + "Unbekannter Befehl! Benutze /shop [add|gui]");
return true;
}
/**
* Zählt die Anzahl der Items eines bestimmten Materials im Inventar.
* Nutzt StorageContents, um auch Rüstung/Shulker-Slots zu prüfen.
*/
private int countItems(PlayerInventory inv, Material mat) {
int count = 0;
for (ItemStack item : inv.getStorageContents()) {
if (item != null && item.getType().equals(mat)) {
count += item.getAmount();
}
}
return count;
}
}

View File

@@ -2,7 +2,9 @@ package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import de.viper.survivalplus.util.Claim;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -51,6 +53,25 @@ public class ClaimListener implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
Claim currentClaim = plugin.getClaim(event.getTo());
Location to = event.getTo();
// --- NEU: BAN CHECK ---
if (currentClaim != null) {
// Checken ob Spieler in der Ban-Liste der Claims Config steht
String claimKey = getClaimKeyFromLocation(to);
if (claimKey != null) {
FileConfiguration config = plugin.getClaimsConfig();
if (config.contains(claimKey + ".banned")) {
if (config.getStringList(claimKey + ".banned").contains(playerId.toString())) {
event.setCancelled(true);
player.sendMessage(ChatColor.RED + "Du bist aus diesem Gebiet verbannt!");
// Optional: Knockback effect
player.teleport(event.getFrom().add(0, 0.2, 0));
return;
}
}
}
}
// Prüfe, ob sich der Claim-Status geändert hat
Claim previousClaim = lastClaim.getOrDefault(playerId, null);
@@ -97,4 +118,15 @@ public class ClaimListener implements Listener {
}
}
}
// Helper für ClaimListener (Kopiert, da wir die Methode in Command nicht sehen können)
private String getClaimKeyFromLocation(Location loc) {
// Da wir hier keinen direkten Zugriff auf den Key haben, iterieren wir kurz
for (String key : plugin.getClaims().keySet()) {
if (plugin.getClaims().get(key).isInside(loc)) {
return key;
}
}
return null;
}
}

View File

@@ -0,0 +1,36 @@
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.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
public class HeadDropListener implements Listener {
private SurvivalPlus plugin;
public HeadDropListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
if (!plugin.getConfig().getBoolean("heads.drop-on-death", true)) {
return;
}
Player player = event.getEntity();
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) head.getItemMeta();
meta.setOwningPlayer(player);
meta.setDisplayName(ChatColor.YELLOW + "Kopf von " + player.getName());
head.setItemMeta(meta);
event.getDrops().add(head);
}
}

View File

@@ -0,0 +1,324 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.RegisteredServiceProvider;
public class SignShopListener implements Listener {
private final SurvivalPlus plugin;
private Economy economy;
public SignShopListener(SurvivalPlus plugin) {
this.plugin = plugin;
try {
if (plugin.getServer().getPluginManager().isPluginEnabled("Vault")) {
RegisteredServiceProvider<Economy> rsp = plugin.getServer().getServicesManager().getRegistration(Economy.class);
if (rsp != null) {
this.economy = rsp.getProvider();
plugin.getLogger().info("Vault Economy für Sign Shops gefunden.");
} else {
plugin.getLogger().warning("Vault Economy Service nicht gefunden!");
}
} else {
plugin.getLogger().warning("Vault Plugin nicht installiert! Sign Shops funktionieren nicht.");
}
} catch (Exception e) {
plugin.getLogger().warning("Fehler beim Laden der Vault API.");
}
}
// --- Schild erstellung ---
@EventHandler(priority = EventPriority.HIGHEST)
public void onSignChange(SignChangeEvent event) {
String line0Raw = event.getLine(0);
if (!line0Raw.equalsIgnoreCase("[buy]") && !line0Raw.equalsIgnoreCase("[sell]")) {
return;
}
Player player = event.getPlayer();
if (!player.hasPermission("survivalplus.shop.create")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung, Shops zu erstellen.");
return;
}
String line2 = event.getLine(1);
String line3 = event.getLine(2);
String[] parts = line2.split(" ");
if (parts.length < 2) {
player.sendMessage(ChatColor.RED + "Format in Zeile 2 falsch! Beispiel: 64 Diamond");
event.setCancelled(true);
return;
}
try {
Integer.parseInt(parts[0]);
if (Material.matchMaterial(parts[1]) == null) {
player.sendMessage(ChatColor.RED + "Das Item '" + parts[1] + "' existiert nicht.");
event.setCancelled(true);
return;
}
Double.parseDouble(line3);
} catch (Exception e) {
player.sendMessage(ChatColor.RED + "Fehler im Format! Benutze: [Buy] \n 64 Diamond \n 500");
event.setCancelled(true);
return;
}
// --- NEU: Schild farbig machen ---
if (line0Raw.equalsIgnoreCase("[buy]")) {
event.setLine(0, ChatColor.GREEN + "[BUY]");
event.setLine(1, ChatColor.WHITE + parts[0] + " " + ChatColor.AQUA + parts[1]);
event.setLine(2, ChatColor.GOLD + line3 + " Coins");
} else if (line0Raw.equalsIgnoreCase("[sell]")) {
event.setLine(0, ChatColor.RED + "[SELL]");
event.setLine(1, ChatColor.WHITE + parts[0] + " " + ChatColor.AQUA + parts[1]);
event.setLine(2, ChatColor.GOLD + line3 + " Coins");
}
if (event.getLine(3) != null && !event.getLine(3).isEmpty()) {
event.setLine(3, ChatColor.GRAY + event.getLine(3));
}
}
// --- Interaktion ---
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerInteract(PlayerInteractEvent event) {
Block block = event.getClickedBlock();
if (block == null || !(block.getState() instanceof Sign)) {
return;
}
Sign sign = (Sign) block.getState();
String line0 = ChatColor.stripColor(sign.getLine(0));
if (!line0.equalsIgnoreCase("[buy]") && !line0.equalsIgnoreCase("[sell]")) {
return;
}
if (economy == null) {
event.getPlayer().sendMessage(ChatColor.RED + "Shop System offline (Vault fehlt).");
return;
}
// --- FEATURE: SHIFT+KLICK LOGIK (LÖSCHEN) ---
if (event.getPlayer().isSneaking()) {
Player player = event.getPlayer();
if (!player.hasPermission("survivalplus.shop.create")) {
player.sendMessage(ChatColor.RED + "Keine Berechtigung, Shops zu entfernen.");
event.setCancelled(true);
return;
}
block.breakNaturally();
player.sendMessage(ChatColor.GREEN + "Shop entfernt.");
event.setCancelled(true);
return;
}
// --- ROUTING ---
if (line0.equalsIgnoreCase("[buy]")) {
handleBuy(event, sign);
} else if (line0.equalsIgnoreCase("[sell]")) {
handleSell(event, sign);
}
}
// --- KAUFS LOGIK (ROBUST) ---
private void handleBuy(PlayerInteractEvent event, Sign sign) {
event.setCancelled(true); // Interaktion stoppen
Player player = event.getPlayer();
String line1Raw = ChatColor.stripColor(sign.getLine(1)); // "64 Diamond"
String line2Raw = ChatColor.stripColor(sign.getLine(2)); // "500" oder "500 Coins"
// 1. Validierung: Zeilen leer?
if (line1Raw == null || line1Raw.isEmpty()) {
player.sendMessage(ChatColor.RED + "Zeile 1 des Schildes ist leer! (Format: 64 Diamond)");
return;
}
if (line2Raw == null || line2Raw.isEmpty()) {
player.sendMessage(ChatColor.RED + "Preiszeile ist leer! (Format: 500)");
return;
}
// 2. Parsing: Zeile 1 "64 Diamond"
String[] partsRaw = line1Raw.split(" ");
if (partsRaw.length < 2) {
player.sendMessage(ChatColor.RED + "Falsches Format! Benutze: [Buy] \n 64 Diamond");
return;
}
String amountStr = partsRaw[0].trim(); // "64"
String itemNameStr = partsRaw[1].trim(); // "Diamond"
if (amountStr.isEmpty() || itemNameStr.isEmpty()) {
player.sendMessage(ChatColor.RED + "Format Fehler!");
return;
}
int amount;
Material material;
try {
amount = Integer.parseInt(amountStr);
material = Material.matchMaterial(itemNameStr);
} catch (NumberFormatException e) {
player.sendMessage(ChatColor.RED + "Angebot '" + amountStr + "' ist keine Zahl! (Beispiel: 64)");
return;
}
if (material == null) {
player.sendMessage(ChatColor.RED + "Item '" + itemNameStr + "' existiert nicht!");
return;
}
// 3. Parsing: Zeile 2 "500 Coins" (Hier passierte der Fehler!)
String[] priceParts = line2Raw.split(" ");
if (priceParts.length == 0) {
player.sendMessage(ChatColor.RED + "Preiszeile ist leer! (Beispiel: 500)");
return;
}
String priceStr = priceParts[0].trim();
if (priceStr.isEmpty()) {
player.sendMessage(ChatColor.RED + "Kein Preis gefunden! (Beispiel: 500)");
return;
}
double price;
try {
price = Double.parseDouble(priceStr);
} catch (NumberFormatException e) {
player.sendMessage(ChatColor.RED + "Preis '" + priceStr + "' ist keine Zahl! (Beispiel: 500)");
return;
} catch (ArrayIndexOutOfBoundsException e) {
player.sendMessage(ChatColor.RED + "Fehlerhafter Preis! (Beispiel: 500)");
return;
}
if (amount <= 0 || price < 0) {
player.sendMessage(ChatColor.RED + "Negative Werte sind nicht erlaubt.");
return;
}
// 4. Transaktion
try {
ItemStack item = new ItemStack(material, amount);
if (economy.getBalance(player) >= price) {
EconomyResponse response = economy.withdrawPlayer(player, price);
if (response.transactionSuccess()) {
player.getInventory().addItem(item);
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + " " + material.name().toLowerCase() + " für " + price + " gekauft!");
} else {
player.sendMessage(ChatColor.RED + "Fehler bei der Transaktion.");
}
} else {
player.sendMessage(ChatColor.RED + "Du hast nicht genug Geld! Du brauchst " + price + ".");
}
} catch (Exception e) {
player.sendMessage(ChatColor.RED + "Ein Fehler ist beim Lesen des Shops aufgetreten.");
// Loggen für Debugging, falls Vault spinnt
e.printStackTrace();
}
}
// --- VERKAUFS LOGIK ---
private void handleSell(PlayerInteractEvent event, Sign sign) {
event.setCancelled(true);
Player player = event.getPlayer();
String line1Raw = ChatColor.stripColor(sign.getLine(1));
String line2Raw = ChatColor.stripColor(sign.getLine(2));
if (line1Raw == null || line1Raw.isEmpty()) {
player.sendMessage(ChatColor.RED + "Zeile 1 ist leer!");
return;
}
if (line2Raw == null || line2Raw.isEmpty()) {
player.sendMessage(ChatColor.RED + "Zeile 2 ist leer!");
return;
}
String[] partsRaw = line1Raw.split(" ");
if (partsRaw.length < 2) {
player.sendMessage(ChatColor.RED + "Format falsch! Benutze: [Sell] \n 64 Diamond");
return;
}
String amountStr = partsRaw[0].trim();
String itemNameStr = partsRaw[1].trim();
int amount;
Material material;
try {
amount = Integer.parseInt(amountStr);
material = Material.matchMaterial(itemNameStr);
} catch (NumberFormatException e) {
player.sendMessage(ChatColor.RED + "Menge ist keine Zahl!");
return;
}
if (material == null) {
player.sendMessage(ChatColor.RED + "Item existiert nicht!");
return;
}
// Preis Parsing (wie im Kauf, nur sicherer)
String[] priceParts = line2Raw.split(" ");
if (priceParts.length == 0) {
player.sendMessage(ChatColor.RED + "Preiszeile ist leer!");
return;
}
String priceStr = priceParts[0].trim();
if (priceStr.isEmpty()) {
player.sendMessage(ChatColor.RED + "Kein Preis!");
return;
}
double price;
try {
price = Double.parseDouble(priceStr);
} catch (NumberFormatException e) {
player.sendMessage(ChatColor.RED + "Preis '" + priceStr + "' ist keine Zahl!");
return;
}
if (amount <= 0 || price < 0) {
player.sendMessage(ChatColor.RED + "Negativer Wert!");
return;
}
ItemStack tempItem = new ItemStack(material, amount);
int hasAmount = 0;
for (ItemStack item : player.getInventory().getStorageContents()) {
if (item != null && item.isSimilar(tempItem)) {
hasAmount += item.getAmount();
}
}
if (hasAmount < amount) {
player.sendMessage(ChatColor.RED + "Du hast nicht genug Items!");
return;
}
// Verkauf durchführen
player.getInventory().removeItem(new ItemStack(material, amount));
economy.depositPlayer(player, price);
player.updateInventory();
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + " " + material.name().toLowerCase() + " für " + price + " Coins verkauft!");
}
}

View File

@@ -0,0 +1,88 @@
package de.viper.survivalplus.listeners;
import de.viper.survivalplus.SurvivalPlus;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPickupItemEvent; // NEU: EntityPickupItemEvent
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
public class VanishListener implements Listener {
private final SurvivalPlus plugin;
public VanishListener(SurvivalPlus plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
if (plugin.isVanished(player.getUniqueId())) {
// Join Message ausblenden
event.setJoinMessage(null);
// Silent Join (Teleport-Effekt) via ProtocolLib
if (player.hasPermission("survivalplus.vanish.silent")) {
hideJoinParticles(player);
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
if (plugin.isVanished(player.getUniqueId())) {
// Quit Message ausblenden
event.setQuitMessage(null);
}
}
@EventHandler
public void onTeleport(PlayerTeleportEvent event) {
Player player = event.getPlayer();
// Silent Teleport verhindert den Endermann-Teleportations-Effekt
if (plugin.isVanished(player.getUniqueId()) && player.hasPermission("survivalplus.vanish.silent")) {
// In 4.8.0 ist das stumme Teleportieren komplex.
// Wir lassen es hier beim Abschalten der Join-Partikel bewenden.
}
}
@EventHandler
public void onPickup(EntityPickupItemEvent event) {
if (!(event.getEntity() instanceof Player)) return; // Vorsichtshalber prüfen
Player player = (Player) event.getEntity();
if (plugin.isVanished(player.getUniqueId()) && player.hasPermission("survivalplus.vanish.no-pickup")) {
event.setCancelled(true); // Item nicht aufheben
}
}
private void hideJoinParticles(Player player) {
if (!plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib")) return;
try {
// Direkter Cast auf ProtocolManager ist in 4.8.0 sicherer
ProtocolManager manager = (ProtocolManager) plugin.getServer().getPluginManager().getPlugin("ProtocolLib");
if (manager == null) return;
// Packet Container erstellen
PacketContainer packet = manager.createPacket(PacketType.Play.Server.ENTITY_STATUS);
packet.getIntegers().write(0, player.getEntityId());
packet.getBytes().write(0, (byte) 0x20); // 32 = Invisibel/Unsichtbar Status Client-Side
for (Player online : plugin.getServer().getOnlinePlayers()) {
if (online.equals(player)) continue;
manager.sendServerPacket(online, packet);
}
} catch (Exception e) {
// Ignorieren Fehler bei ProtocolLib
}
}
}

View File

@@ -4,6 +4,10 @@ version: 1.1.0
# Debug-Option
debug-logging: false
# Spieler Kopf bei Tod
heads:
drop-on-death: true
# Neulings Schutz
newbie-protection:
enabled: true

View File

@@ -137,6 +137,10 @@ commands:
description: "&eTeleportiert dich zu einem Freund."
usage: "&b/friend tp <Spieler>"
freeze:
description: "&eFriert einen Spieler ein (Bewegung unmöglich)."
usage: "&b/freeze <Spieler>"
ir:
description: "&eBenennt das Item in der Hand um."
usage: "&b/ir <neuer_name>"
@@ -201,6 +205,10 @@ commands:
description: "&eZeigt eine Liste der blockierten Spieler."
usage: "&b/blocklist"
vanish:
description: "&eMacht dich für andere Spieler unsichtbar."
usage: "&b/vanish"
kit:
description: "&eHolt das Starterkit."
usage: "&b/kit"
@@ -213,6 +221,10 @@ commands:
description: "&eÄndert deinen Nicknamen mit Farb- und Hex-Support."
usage: "&b/nick <Name>"
ride:
description: "&eReite einen Spieler oder Mob."
usage: "&b/ride [spieler]"
lootchests:
description: "&eZeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick teleportieren."
usage: "&b/lootchests"
@@ -275,7 +287,7 @@ commands:
claim:
description: "&eVerwaltet Claims für den Anti-Grief-Schutz."
usage: "&b/claim [mark <1|2>| unclaim | trust <spieler> | untrust <spieler>]"
usage: "&b/claim [mark <1|2>| unclaim | trust <spieler> | untrust <spieler> | info | kick <spieler> | ban <spieler> | unban <spieler>]"
subcommands:
mark:
description: "&eMarkiert die erste oder zweite Ecke eines zu schützenden Bereichs."
@@ -289,6 +301,18 @@ commands:
untrust:
description: "&eEntfernt die Vertrauensberechtigung eines Spielers für den Bereich."
usage: "&b/claim untrust <spieler>"
info:
description: "&eZeigt Informationen über den aktuellen Claim an."
usage: "&b/claim info"
kick:
description: "&eWirft einen Spieler aus dem Claim."
usage: "&b/claim kick <Spieler>"
ban:
description: "&eVerbannt einen Spieler permanent aus dem Claim."
usage: "&b/claim ban <Spieler>"
unban:
description: "&eEntbannt einen Spieler aus dem Claim."
usage: "&b/claim unban <Spieler>"
messages:
header: "&6=== Befehle ==="
@@ -309,7 +333,7 @@ messages:
name: "&ePlugin-Name: &f"
version: "&eVersion: &f"
author: "&eErsteller: &f"
description: "&eBeschreibung:\\n&f"
description: "&eBeschreibung:\n&f"
footer: "&7=========================="
share:
preview-title: "&aDeine aktuellen Koordinaten wären:"
@@ -321,3 +345,18 @@ messages:
sent: "&aKoordinaten gesendet."
cancelled: "&eSenden der Koordinaten abgebrochen."
help-not-found: "&cHilfedatei (help.yml) konnte nicht geladen werden!"
vanish:
activated: "&aDu bist nun unsichtbar."
deactivated: "&cDu bist nun sichtbar."
freeze:
frozen: "&cDu wurdest von einem Admin eingefroren! &lKeine Bewegung möglich!"
unfrozen: "&aDu bist nicht mehr eingefroren."
player-frozen: "&a%player% wurde eingefroren."
player-unfrozen: "&a%player% wurde aufgetaut."
claim:
kicked: "&cDu wurdest aus dem Claim geworfen!"
kicked-target: "&aSpieler wurde aus dem Claim geworfen."
banned: "&cDu bist aus diesem Gebiet verbannt!"
unbanned: "&aDu bist für dieses Gebiet entbannt."
admin-banned: "&aSpieler wurde von diesem Claim gebannt."
admin-unbanned: "&aSpieler wurde für diesen Claim entbannt."

View File

@@ -1,9 +1,9 @@
name: SurvivalPlus
version: 1.1.1
version: 1.1.2
main: de.viper.survivalplus.SurvivalPlus
api-version: 1.21
softdepend: [LuckPerms, PlaceholderAPI, ProtocolLib]
softdepend: [LuckPerms, PlaceholderAPI, ProtocolLib, Vault]
author: Viper
description: A plugin for enhancing survival gameplay in Minecraft.
@@ -188,6 +188,16 @@ commands:
usage: /<command> [spieler]
permission: survivalplus.ride
permission-message: "§cDu hast keine Berechtigung, Spieler zu reiten!"
vanish:
description: Macht dich unsichtbar
usage: /<command>
permission: survivalplus.vanish
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
freeze:
description: Friert einen Spieler ein
usage: /<command> <Spieler>
permission: survivalplus.freeze
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
lootchests:
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
usage: /<command>
@@ -268,11 +278,19 @@ commands:
usage: /<command> [spieler]
permission: survivalplus.heal
permission-message: "§cDu hast keine Berechtigung, Spieler zu heilen!"
claim:
description: Manages claims for anti-griefing
usage: /<command> [unclaim | trust <player> | untrust <player>]
usage: /<command> [mark|unclaim|del|delete|trust|untrust|info|kick|ban|unban]
aliases: [cl]
permission: survivalplus.claim.use
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
# --- NEU: HEAD COMMAND ---
head:
description: Hol dir den Kopf eines Spielers.
usage: /<command> <name>
permission: survivalplus.head
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
permissions:
survivalplus.*:
@@ -326,6 +344,8 @@ permissions:
survivalplus.nick: true
survivalplus.ride: true
survivalplus.ride.exempt: true
survivalplus.vanish: true
survivalplus.freeze: true
survivalplus.lootchests: true
survivalplus.day: true
survivalplus.night: true
@@ -346,6 +366,12 @@ permissions:
survivalplus.chunkanimals: true
survivalplus.claim.use: true
survivalplus.claim.trust: true
survivalplus.claim.kick: true
survivalplus.claim.ban: true
survivalplus.head: true
survivalplus.claim.admin: true
survivalplus.vanish.silent: true
survivalplus.vanish.no-pickup: true
survivalplus.commandblocker.add:
description: Erlaubt das Hinzufügen von Befehlen zur Blockierliste
default: op
@@ -487,6 +513,12 @@ permissions:
survivalplus.ride.exempt:
description: Spieler mit dieser Permission können nicht geritten werden
default: op
survivalplus.vanish:
description: Erlaubt das Unsichtbar werden
default: op
survivalplus.freeze:
description: Erlaubt das Einfrieren von Spielern
default: op
survivalplus.lootchests:
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
default: op
@@ -541,3 +573,27 @@ permissions:
survivalplus.chunkanimals:
description: Erlaubt das Anzeigen der Anzahl der Tiere im aktuellen Chunk
default: op
survivalplus.claim.use:
description: Erlaubt das Erstellen von Claims
default: true
survivalplus.claim.trust:
description: Erlaubt das Verwalten von Trusted-Spielern in Claims
default: true
survivalplus.claim.kick:
description: Erlaubt das Kicken von Spielern aus Claims
default: op
survivalplus.claim.ban:
description: Erlaubt das Bannen von Spielern aus Claims
default: op
survivalplus.claim.admin:
description: Erlaubt das Löschen von fremden Claims (Admin Feature)
default: op
survivalplus.vanish.silent:
description: Erlaubt stummes Einloggen
default: op
survivalplus.vanish.no-pickup:
description: Kein Items aufheben im Vanish-Modus
default: op
survivalplus.head:
description: Erlaubt das Holen von Spielerköpfen
default: true