Update from Git Manager GUI
This commit is contained in:
@@ -28,24 +28,51 @@ public class ShopManager {
|
|||||||
return shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
return shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getStock(String itemKey) {
|
||||||
|
return shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spieler kauft Item: Lager sinkt, Preis steigt (Verknappung)
|
||||||
|
*/
|
||||||
public boolean buyItem(String itemKey, int amount) {
|
public boolean buyItem(String itemKey, int amount) {
|
||||||
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
|
||||||
if (stock < amount) {
|
if (stock < amount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
|
|
||||||
|
// Lager aktualisieren
|
||||||
shopConfig.set("items." + itemKey + ".stock", stock - amount);
|
shopConfig.set("items." + itemKey + ".stock", stock - amount);
|
||||||
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
|
|
||||||
|
// Preis erhöhen (Faktor 1.05 = +5%)
|
||||||
|
double newPrice = price * 1.05;
|
||||||
|
shopConfig.set("items." + itemKey + ".current-price", newPrice);
|
||||||
|
|
||||||
saveShop();
|
saveShop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sellItem(String itemKey, int amount) {
|
/**
|
||||||
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
* Spieler verkauft Item: Lager steigt, Preis sinkt (Überfluss)
|
||||||
|
*/
|
||||||
|
public boolean sellItem(String itemKey, int amount) {
|
||||||
|
// Hier könnte man prüfen, ob der Shop genügend Geld hat (falls nötig)
|
||||||
|
|
||||||
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
double price = shopConfig.getDouble("items." + itemKey + ".current-price", 0);
|
||||||
|
int stock = shopConfig.getInt("items." + itemKey + ".stock", 0);
|
||||||
|
|
||||||
|
// Lager aktualisieren
|
||||||
shopConfig.set("items." + itemKey + ".stock", stock + amount);
|
shopConfig.set("items." + itemKey + ".stock", stock + amount);
|
||||||
shopConfig.set("items." + itemKey + ".current-price", price * 0.95);
|
|
||||||
|
// Preis senken (Faktor 0.95 = -5%)
|
||||||
|
double newPrice = price * 0.95;
|
||||||
|
shopConfig.set("items." + itemKey + ".current-price", newPrice);
|
||||||
|
|
||||||
saveShop();
|
saveShop();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addOrUpdateItem(String itemKey, double basePrice, int stock) {
|
public void addOrUpdateItem(String itemKey, double basePrice, int stock) {
|
||||||
|
|||||||
@@ -1,31 +1,28 @@
|
|||||||
package de.viper.survivalplus.Manager;
|
package de.viper.survivalplus.Manager;
|
||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import net.luckperms.api.LuckPerms;
|
||||||
|
import net.luckperms.api.LuckPermsProvider;
|
||||||
|
import net.luckperms.api.model.user.User;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scoreboard.Scoreboard;
|
import org.bukkit.scoreboard.Scoreboard;
|
||||||
import org.bukkit.scoreboard.ScoreboardManager;
|
import org.bukkit.scoreboard.ScoreboardManager;
|
||||||
import org.bukkit.scoreboard.Team;
|
import org.bukkit.scoreboard.Team;
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
|
||||||
import net.luckperms.api.LuckPerms;
|
|
||||||
import net.luckperms.api.LuckPermsProvider;
|
|
||||||
import net.luckperms.api.model.user.User;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -47,19 +44,20 @@ public class TablistManager implements Listener {
|
|||||||
private String separatorLine;
|
private String separatorLine;
|
||||||
private LuckPerms luckPerms;
|
private LuckPerms luckPerms;
|
||||||
private boolean hasPlaceholderAPI;
|
private boolean hasPlaceholderAPI;
|
||||||
private final Scoreboard scoreboard;
|
|
||||||
private final Map<String, Team> prefixTeams;
|
|
||||||
private FileConfiguration nicknameConfig;
|
private FileConfiguration nicknameConfig;
|
||||||
|
|
||||||
|
private final Scoreboard scoreboard;
|
||||||
|
private final Map<String, Team> prefixTeams = new HashMap<>();
|
||||||
|
|
||||||
|
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
||||||
|
|
||||||
public TablistManager(SurvivalPlus plugin) {
|
public TablistManager(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.prefixTeams = new HashMap<>();
|
|
||||||
|
|
||||||
// Scoreboard initialisieren
|
// Scoreboard initialisieren
|
||||||
ScoreboardManager scoreboardManager = Bukkit.getScoreboardManager();
|
ScoreboardManager scoreboardManager = Bukkit.getScoreboardManager();
|
||||||
this.scoreboard = scoreboardManager != null ? scoreboardManager.getMainScoreboard() : null;
|
this.scoreboard = scoreboardManager != null ? scoreboardManager.getMainScoreboard() : null;
|
||||||
|
|
||||||
// Resource sicherstellen, Config laden
|
|
||||||
try {
|
try {
|
||||||
File tablistFile = new File(plugin.getDataFolder(), "tablist.yml");
|
File tablistFile = new File(plugin.getDataFolder(), "tablist.yml");
|
||||||
if (!tablistFile.exists()) {
|
if (!tablistFile.exists()) {
|
||||||
@@ -73,7 +71,6 @@ public class TablistManager implements Listener {
|
|||||||
|
|
||||||
FileConfiguration config = plugin.getTablistConfig();
|
FileConfiguration config = plugin.getTablistConfig();
|
||||||
|
|
||||||
// Konfigurationswerte laden
|
|
||||||
this.enabled = config.getBoolean("enabled", true);
|
this.enabled = config.getBoolean("enabled", true);
|
||||||
this.serverName = config.getString("server-name", "SurvivalPlus");
|
this.serverName = config.getString("server-name", "SurvivalPlus");
|
||||||
this.website = config.getString("website", "www.example.com");
|
this.website = config.getString("website", "www.example.com");
|
||||||
@@ -84,27 +81,22 @@ public class TablistManager implements Listener {
|
|||||||
this.staffPermission = config.getString("staff-permission", "survivalplus.staff");
|
this.staffPermission = config.getString("staff-permission", "survivalplus.staff");
|
||||||
this.separatorLine = config.getString("separator-line", "&8&l&m================");
|
this.separatorLine = config.getString("separator-line", "&8&l&m================");
|
||||||
|
|
||||||
// LuckPerms API initialisieren
|
|
||||||
try {
|
try {
|
||||||
this.luckPerms = LuckPermsProvider.get();
|
this.luckPerms = LuckPermsProvider.get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
luckPerms = null;
|
luckPerms = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfen, ob PlaceholderAPI verfügbar ist
|
|
||||||
this.hasPlaceholderAPI = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
this.hasPlaceholderAPI = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
||||||
|
|
||||||
// Chat-Listener registrieren
|
// Registriere Chat-Listener hier, damit Prefix im Chat gesetzt wird
|
||||||
if (enabled) {
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||||
}
|
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
plugin.getLogger().info("Tablist ist deaktiviert (tablist.yml -> enabled: false)");
|
plugin.getLogger().info("Tablist ist deaktiviert (tablist.yml -> enabled: false)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header- und Footer-Animationen füllen
|
|
||||||
List<String> configHeader = config.getStringList("header-animations");
|
List<String> configHeader = config.getStringList("header-animations");
|
||||||
List<String> configFooter = config.getStringList("footer-animations");
|
List<String> configFooter = config.getStringList("footer-animations");
|
||||||
|
|
||||||
@@ -131,45 +123,49 @@ public class TablistManager implements Listener {
|
|||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Nickname Config neu laden
|
|
||||||
reloadNicknameConfig();
|
reloadNicknameConfig();
|
||||||
|
|
||||||
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
if (headerAnim.isEmpty() || footerAnim.isEmpty()) return;
|
||||||
|
|
||||||
// Online-Spieler und Staff zählen
|
|
||||||
int onlinePlayers = Bukkit.getOnlinePlayers().size();
|
int onlinePlayers = Bukkit.getOnlinePlayers().size();
|
||||||
int onlineStaff = (int) Bukkit.getOnlinePlayers().stream()
|
int onlineStaff = (int) Bukkit.getOnlinePlayers().stream()
|
||||||
.filter(p -> p.hasPermission(staffPermission))
|
.filter(p -> p.hasPermission(staffPermission))
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
// Aktuelles Datum und Uhrzeit formatieren
|
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
|
||||||
String currentTime = dateFormat.format(new Date());
|
String currentTime = dateFormat.format(new Date());
|
||||||
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
try {
|
try {
|
||||||
// Nickname abrufen (farbig)
|
// ------ Name / Nick handling exactly like in your old code ------
|
||||||
String displayName = getNickname(player);
|
String displayName = getNickname(player);
|
||||||
// Falls kein Nickname, Name nehmen
|
|
||||||
if (displayName == null || displayName.trim().isEmpty()) {
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
displayName = player.getName();
|
displayName = player.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spielername für die Tablist setzen (Spielerliste auf der rechten Seite)
|
|
||||||
String playerListName;
|
|
||||||
String rankPrefix = getPlayerPrefix(player);
|
String rankPrefix = getPlayerPrefix(player);
|
||||||
|
// Update nametag (prefix above head) as in old code:
|
||||||
|
updateNametag(player, rankPrefix, getNickname(player)); // pass raw nickname (colored) if present
|
||||||
|
|
||||||
|
// PlayerList (TAB)
|
||||||
|
int ping = getPlayerPing(player);
|
||||||
|
String playerListName;
|
||||||
if (luckPerms == null && !hasPlaceholderAPI) {
|
if (luckPerms == null && !hasPlaceholderAPI) {
|
||||||
playerListName = displayName;
|
playerListName = displayName;
|
||||||
updateNametag(player, rankPrefix, displayName);
|
|
||||||
} else {
|
} else {
|
||||||
int ping = getPlayerPing(player);
|
|
||||||
playerListName = color(rankPrefix + displayName + (ping >= 0 ? "&8 | &e" + ping + "ms" : ""));
|
playerListName = color(rankPrefix + displayName + (ping >= 0 ? "&8 | &e" + ping + "ms" : ""));
|
||||||
updateNametag(player, rankPrefix, displayName);
|
|
||||||
}
|
}
|
||||||
player.setPlayerListName(playerListName);
|
|
||||||
|
|
||||||
// Header mit Spielername/Nickname und Statistiken
|
try {
|
||||||
|
player.setPlayerListName(playerListName);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
// safe fallback: set without prefix
|
||||||
|
try {
|
||||||
|
player.setPlayerListName(color(displayName));
|
||||||
|
} catch (Exception ignored2) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header/Footer build (including TS/Discord/Website and time)
|
||||||
String headerRaw = headerAnim.get(headerIndex)
|
String headerRaw = headerAnim.get(headerIndex)
|
||||||
.replace("{server}", serverName)
|
.replace("{server}", serverName)
|
||||||
.replace("{player}", displayName)
|
.replace("{player}", displayName)
|
||||||
@@ -177,11 +173,9 @@ public class TablistManager implements Listener {
|
|||||||
.replace("{staff}", String.valueOf(onlineStaff));
|
.replace("{staff}", String.valueOf(onlineStaff));
|
||||||
String footerRaw = footerAnim.get(footerIndex);
|
String footerRaw = footerAnim.get(footerIndex);
|
||||||
|
|
||||||
// Footer zusammenstellen: TS und Discord nebeneinander, Webseite zentriert
|
|
||||||
StringBuilder footerBuilder = new StringBuilder();
|
StringBuilder footerBuilder = new StringBuilder();
|
||||||
footerBuilder.append("\n"); // Extra Abstand
|
footerBuilder.append("\n");
|
||||||
footerBuilder.append(color(footerRaw)).append("\n");
|
footerBuilder.append(color(footerRaw)).append("\n");
|
||||||
|
|
||||||
footerBuilder.append(color(separatorLine)).append("\n");
|
footerBuilder.append(color(separatorLine)).append("\n");
|
||||||
if (showTeamspeak || showDiscord) {
|
if (showTeamspeak || showDiscord) {
|
||||||
StringBuilder socialLine = new StringBuilder();
|
StringBuilder socialLine = new StringBuilder();
|
||||||
@@ -203,28 +197,25 @@ public class TablistManager implements Listener {
|
|||||||
String header = color(headerRaw);
|
String header = color(headerRaw);
|
||||||
String footer = color(footerBuilder.toString());
|
String footer = color(footerBuilder.toString());
|
||||||
|
|
||||||
// 1) Adventure (Component) Variante
|
// Try Adventure-based header/footer first, fallback to String reflection
|
||||||
boolean done = tryAdventureComponent(player, headerRaw, footerBuilder.toString());
|
boolean done = tryAdventureComponent(player, headerRaw, footerBuilder.toString());
|
||||||
|
|
||||||
// 2) String-Variante fallback
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = tryStringMethod(player, header, footer);
|
tryStringMethod(player, header, footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Keine Warnung bei Fehlschlag
|
} catch (Exception ex) {
|
||||||
} catch (Exception ignored) {
|
plugin.getLogger().warning("TablistManager error: " + ex.getMessage());
|
||||||
// Keine Konsolenausgabe für Fehler bei der Tablist
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headerIndex = (headerIndex + 1) % headerAnim.size();
|
headerIndex = (headerIndex + 1) % headerAnim.size();
|
||||||
footerIndex = (footerIndex + 1) % footerAnim.size();
|
footerIndex = (footerIndex + 1) % footerAnim.size();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 0L, interval);
|
}.runTaskTimer(plugin, 40L, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lädt die nicknames.yml neu
|
* Lädt nicknames.yml neu.
|
||||||
*/
|
*/
|
||||||
private void reloadNicknameConfig() {
|
private void reloadNicknameConfig() {
|
||||||
try {
|
try {
|
||||||
@@ -239,7 +230,7 @@ public class TablistManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nickname abrufen und formatieren
|
* Nickname abrufen und formatieren (farbig + hex)
|
||||||
*/
|
*/
|
||||||
private String getNickname(Player player) {
|
private String getNickname(Player player) {
|
||||||
if (nicknameConfig == null) return null;
|
if (nicknameConfig == null) return null;
|
||||||
@@ -254,70 +245,11 @@ public class TablistManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nametag über dem Kopf aktualisieren
|
* Übersetzt &-Codes und Hex-Farben
|
||||||
*/
|
|
||||||
private void updateNametag(Player player, String rankPrefix, String nickname) {
|
|
||||||
if (scoreboard == null) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
String teamName = generateTeamName(player, rankPrefix);
|
|
||||||
Team team = scoreboard.getTeam(teamName);
|
|
||||||
|
|
||||||
if (team == null) {
|
|
||||||
team = scoreboard.registerNewTeam(teamName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WICHTIG:
|
|
||||||
// Wir nutzen den Rang-Prefix ODER den Nickname als Team-Prefix.
|
|
||||||
// Da wir den Namen über dem Kopf nicht komplett ersetzen können (ohne ProtocolLib),
|
|
||||||
// zeigen wir den Nickname als Prefix an.
|
|
||||||
// Ergebnis über Kopf: [Nick] Spielername
|
|
||||||
|
|
||||||
String prefix;
|
|
||||||
|
|
||||||
// Wenn ein Nickname existiert, hat er Vorrang über den Rang-Prefix (damit man ihn sieht)
|
|
||||||
if (nickname != null && !nickname.trim().isEmpty()) {
|
|
||||||
prefix = nickname;
|
|
||||||
} else {
|
|
||||||
prefix = color(rankPrefix != null && !rankPrefix.trim().isEmpty() ? rankPrefix : (luckPerms != null ? "&7[Spieler] " : ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
team.setPrefix(prefix);
|
|
||||||
|
|
||||||
// WICHTIG: Der Entry MUSS der echte Spielername sein.
|
|
||||||
// Wir nutzen hier den echten Namen, nicht den Nicknamen, da Nicks zu lang sein können oder Sonderzeichen enthalten.
|
|
||||||
String entry = player.getName();
|
|
||||||
|
|
||||||
if (!team.hasEntry(entry)) {
|
|
||||||
// Spieler aus anderen Teams entfernen
|
|
||||||
for (Team existingTeam : scoreboard.getTeams()) {
|
|
||||||
if (!existingTeam.getName().equals(teamName)) {
|
|
||||||
existingTeam.removeEntry(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
team.addEntry(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scoreboard für alle Spieler synchronisieren
|
|
||||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
|
||||||
if (onlinePlayer.getScoreboard() != scoreboard) {
|
|
||||||
onlinePlayer.setScoreboard(scoreboard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Farben übersetzen
|
|
||||||
*/
|
*/
|
||||||
private String translateNickColors(String input) {
|
private String translateNickColors(String input) {
|
||||||
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
return replaceHexColors(withLegacy);
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceHexColors(String input) {
|
|
||||||
Matcher matcher = HEX_PATTERN.matcher(input);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = matcher.group();
|
String hexCode = matcher.group();
|
||||||
@@ -328,7 +260,68 @@ public class TablistManager implements Listener {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern HEX_PATTERN = Pattern.compile("#[a-fA-F0-9]{6}");
|
/**
|
||||||
|
* Aktualisiert den Nametag über dem Kopf genau wie in deinem alten Code:
|
||||||
|
* - Wenn Nick vorhanden: Nick als Prefix (zeigt [Nick] Spielername)
|
||||||
|
* - Sonst Rang-Prefix (oder [Spieler] wenn kein Rang)
|
||||||
|
* Der Entry ist dabei immer der echte Spielername.
|
||||||
|
*/
|
||||||
|
private void updateNametag(Player player, String rankPrefix, String nickname) {
|
||||||
|
if (scoreboard == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String teamName = generateTeamName(player, rankPrefix);
|
||||||
|
Team team = scoreboard.getTeam(teamName);
|
||||||
|
|
||||||
|
if (team == null) {
|
||||||
|
// register new team if not exists
|
||||||
|
try {
|
||||||
|
team = scoreboard.registerNewTeam(teamName);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
team = scoreboard.getTeam(teamName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (team == null) return;
|
||||||
|
|
||||||
|
String prefix;
|
||||||
|
if (nickname != null && !nickname.trim().isEmpty()) {
|
||||||
|
prefix = nickname;
|
||||||
|
} else {
|
||||||
|
String rp = (rankPrefix != null && !rankPrefix.trim().isEmpty()) ? rankPrefix : "&7[&aSpieler&7]&f ";
|
||||||
|
prefix = color(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
team.setPrefix(prefix);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
// Ensure the genuine player name is used as the team entry
|
||||||
|
String entry = player.getName();
|
||||||
|
|
||||||
|
if (!team.hasEntry(entry)) {
|
||||||
|
// Remove from other teams to avoid duplicates
|
||||||
|
for (Team existingTeam : scoreboard.getTeams()) {
|
||||||
|
if (existingTeam != null && !existingTeam.getName().equals(teamName)) {
|
||||||
|
try {
|
||||||
|
existingTeam.removeEntry(entry);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
team.addEntry(entry);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize scoreboard to online players (use main scoreboard)
|
||||||
|
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||||
|
try {
|
||||||
|
if (onlinePlayer.getScoreboard() != scoreboard) {
|
||||||
|
onlinePlayer.setScoreboard(scoreboard);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Eindeutigen Teamnamen generieren
|
* Eindeutigen Teamnamen generieren
|
||||||
@@ -342,74 +335,7 @@ public class TablistManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rang-Prefix abrufen
|
* Versucht, Adventure Components zu verwenden (falls verfügbar).
|
||||||
*/
|
|
||||||
private String getPlayerPrefix(Player player) {
|
|
||||||
if (luckPerms != null) {
|
|
||||||
try {
|
|
||||||
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
|
||||||
String prefix = user.getCachedData().getMetaData().getPrefix();
|
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
|
||||||
return prefix + " ";
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
if (hasPlaceholderAPI) {
|
|
||||||
try {
|
|
||||||
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
|
||||||
return prefix + " ";
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
return "&7[Spieler] ";
|
|
||||||
}
|
|
||||||
if (hasPlaceholderAPI) {
|
|
||||||
try {
|
|
||||||
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
|
||||||
if (prefix != null && !prefix.trim().isEmpty()) {
|
|
||||||
return prefix + " ";
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
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 ignored) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chat-Format (Nickname wird hier angezeigt)
|
|
||||||
*/
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
|
||||||
try {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
// Nickname abrufen (wichtig: hier neu abrufen, da es asynchron ist und sich geändert haben könnte)
|
|
||||||
// Da Config-Lesezugriffe meist Thread-Safe sind, ist das hier okay.
|
|
||||||
String displayName = getNickname(player);
|
|
||||||
if (displayName == null || displayName.trim().isEmpty()) {
|
|
||||||
displayName = player.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
String prefix = getPlayerPrefix(player);
|
|
||||||
// Format: Rang + Nick + ": " + Nachricht
|
|
||||||
String format = color(prefix + displayName + "&7: &f") + "%2$s";
|
|
||||||
event.setFormat(format);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adventure-Variante
|
|
||||||
*/
|
*/
|
||||||
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
private boolean tryAdventureComponent(Player player, String headerRaw, String footerRaw) {
|
||||||
try {
|
try {
|
||||||
@@ -458,13 +384,13 @@ public class TablistManager implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return false;
|
// fallback to string method
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String-Variante
|
* Fallback: konventionelle String-Header/Footer mittels Reflection
|
||||||
*/
|
*/
|
||||||
private boolean tryStringMethod(Player player, String header, String footer) {
|
private boolean tryStringMethod(Player player, String header, String footer) {
|
||||||
try {
|
try {
|
||||||
@@ -484,9 +410,7 @@ public class TablistManager implements Listener {
|
|||||||
mf.invoke(player, footer);
|
mf.invoke(player, footer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,6 +426,68 @@ public class TablistManager implements Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt den Rang-Prefix (LuckPerms -> PlaceholderAPI -> Default [Spieler])
|
||||||
|
*/
|
||||||
|
private String getPlayerPrefix(Player player) {
|
||||||
|
if (luckPerms != null) {
|
||||||
|
try {
|
||||||
|
User user = luckPerms.getPlayerAdapter(Player.class).getUser(player);
|
||||||
|
String prefix = user.getCachedData().getMetaData().getPrefix();
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
if (hasPlaceholderAPI) {
|
||||||
|
try {
|
||||||
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
return "&7[&aSpieler&7]&f ";
|
||||||
|
}
|
||||||
|
if (hasPlaceholderAPI) {
|
||||||
|
try {
|
||||||
|
String prefix = PlaceholderAPI.setPlaceholders(player, "%luckperms_prefix%");
|
||||||
|
if (prefix != null && !prefix.trim().isEmpty()) {
|
||||||
|
return prefix + " ";
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
return "&7[&aSpieler&7]&f ";
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ignored) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat-Format (Nickname wird hier angezeigt). Setzt Prefix + Nick/Name im Chat.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
|
try {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
String displayName = getNickname(player);
|
||||||
|
if (displayName == null || displayName.trim().isEmpty()) {
|
||||||
|
displayName = player.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String prefix = getPlayerPrefix(player);
|
||||||
|
// Format: Rang + Nick + ": " + Nachricht
|
||||||
|
String format = color(prefix + displayName + "&7: &f") + "%2$s";
|
||||||
|
event.setFormat(format);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
private String color(String msg) {
|
private String color(String msg) {
|
||||||
if (msg == null) return "";
|
if (msg == null) return "";
|
||||||
return msg.replace("&", "§");
|
return msg.replace("&", "§");
|
||||||
|
|||||||
@@ -92,6 +92,13 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
private FileConfiguration leashesConfig;
|
private FileConfiguration leashesConfig;
|
||||||
private File mobCapFile;
|
private File mobCapFile;
|
||||||
private FileConfiguration mobCapConfig;
|
private FileConfiguration mobCapConfig;
|
||||||
|
|
||||||
|
// --- NEU: Adaptive Mob System ---
|
||||||
|
private File mobAdaptFile;
|
||||||
|
private FileConfiguration mobAdaptConfig;
|
||||||
|
private AdaptiveMobListener adaptiveMobListener;
|
||||||
|
// --------------------------------
|
||||||
|
|
||||||
private FileConfiguration tablistConfig;
|
private FileConfiguration tablistConfig;
|
||||||
private File tablistFile;
|
private File tablistFile;
|
||||||
private File nicknamesFile;
|
private File nicknamesFile;
|
||||||
@@ -240,6 +247,7 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
createFriendsFile();
|
createFriendsFile();
|
||||||
createLeashesFile();
|
createLeashesFile();
|
||||||
createMobCapFile();
|
createMobCapFile();
|
||||||
|
createMobAdaptFile(); // NEU: Adaptive Mob File erstellen
|
||||||
createNicknamesFile();
|
createNicknamesFile();
|
||||||
reloadBlockedCommandsConfig();
|
reloadBlockedCommandsConfig();
|
||||||
loadClaims();
|
loadClaims();
|
||||||
@@ -334,6 +342,7 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
pluginManager.registerEvents(lootChestManager, this);
|
pluginManager.registerEvents(lootChestManager, this);
|
||||||
getCommand("lootchests").setExecutor(lootChestManager);
|
getCommand("lootchests").setExecutor(lootChestManager);
|
||||||
getCommand("tploot").setExecutor(lootChestManager);
|
getCommand("tploot").setExecutor(lootChestManager);
|
||||||
|
getCommand("ride").setExecutor(new RideCommand(this));
|
||||||
getCommand("claim").setExecutor(new ClaimCommand(this));
|
getCommand("claim").setExecutor(new ClaimCommand(this));
|
||||||
// HIER: (this) hinzugefügt, damit der BlockManager die Datei speichern kann
|
// HIER: (this) hinzugefügt, damit der BlockManager die Datei speichern kann
|
||||||
BlockManager blockManager = new BlockManager(this);
|
BlockManager blockManager = new BlockManager(this);
|
||||||
@@ -367,7 +376,14 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
pluginManager.registerEvents(new WarpInventoryListener(this, warpManager), this);
|
pluginManager.registerEvents(new WarpInventoryListener(this, warpManager), this);
|
||||||
pluginManager.registerEvents(new ChallengeSmeltListener(funChallengeManager), this);
|
pluginManager.registerEvents(new ChallengeSmeltListener(funChallengeManager), this);
|
||||||
pluginManager.registerEvents(new BlockDetectionListener(this), this);
|
pluginManager.registerEvents(new BlockDetectionListener(this), this);
|
||||||
|
pluginManager.registerEvents(new NickLoadListener(this), this);
|
||||||
pluginManager.registerEvents(new ClaimListener(this), this);
|
pluginManager.registerEvents(new ClaimListener(this), this);
|
||||||
|
|
||||||
|
// --- NEU: Adaptive Mob Listener registrieren ---
|
||||||
|
adaptiveMobListener = new AdaptiveMobListener(this);
|
||||||
|
pluginManager.registerEvents(adaptiveMobListener, this);
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
lockSystem = new LockSystem(this);
|
lockSystem = new LockSystem(this);
|
||||||
pluginManager.registerEvents(lockSystem, this);
|
pluginManager.registerEvents(lockSystem, this);
|
||||||
getCommand("sp").setExecutor(lockSystem);
|
getCommand("sp").setExecutor(lockSystem);
|
||||||
@@ -392,7 +408,6 @@ public class SurvivalPlus extends JavaPlugin {
|
|||||||
});
|
});
|
||||||
pluginManager.registerEvents(new RepairSignListener(getConfig(), getLangConfig()), this);
|
pluginManager.registerEvents(new RepairSignListener(getConfig(), getLangConfig()), this);
|
||||||
pluginManager.registerEvents(new ToolUpgradeListener(this), this);
|
pluginManager.registerEvents(new ToolUpgradeListener(this), this);
|
||||||
pluginManager.registerEvents(new NickLoadListener(this), this);
|
|
||||||
startAutoClearTask();
|
startAutoClearTask();
|
||||||
spawnArmorStandExample();
|
spawnArmorStandExample();
|
||||||
getLogger().info(getMessage("plugin.enabled"));
|
getLogger().info(getMessage("plugin.enabled"));
|
||||||
@@ -743,6 +758,7 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
|
|||||||
saveStats();
|
saveStats();
|
||||||
saveLeashesConfig();
|
saveLeashesConfig();
|
||||||
saveMobCapConfig();
|
saveMobCapConfig();
|
||||||
|
saveMobAdaptConfig(); // NEU: Adaptive Mob Config speichern
|
||||||
|
|
||||||
// NEU: NewbieProtection-Daten sichern
|
// NEU: NewbieProtection-Daten sichern
|
||||||
if (newbieListener != null) {
|
if (newbieListener != null) {
|
||||||
@@ -1089,6 +1105,33 @@ private void ensureConfigVersion(FileConfiguration config, File file, String ver
|
|||||||
getLogger().info("mobcap.yml erfolgreich neu geladen.");
|
getLogger().info("mobcap.yml erfolgreich neu geladen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === NEU: MobAdapt.yml ===
|
||||||
|
private void createMobAdaptFile() {
|
||||||
|
mobAdaptFile = new File(getDataFolder(), "mobadapt.yml");
|
||||||
|
if (!mobAdaptFile.exists()) {
|
||||||
|
try {
|
||||||
|
mobAdaptFile.createNewFile();
|
||||||
|
getLogger().info("mobadapt.yml wurde erstellt.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Fehler beim Erstellen der mobadapt.yml: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mobAdaptConfig = YamlConfiguration.loadConfiguration(mobAdaptFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileConfiguration getMobAdaptConfig() {
|
||||||
|
return mobAdaptConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveMobAdaptConfig() {
|
||||||
|
try {
|
||||||
|
mobAdaptConfig.save(mobAdaptFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().log(Level.SEVERE, "Fehler beim Speichern der mobadapt.yml: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ===========================
|
||||||
|
|
||||||
// === AutoClearTask ===
|
// === AutoClearTask ===
|
||||||
private void startAutoClearTask() {
|
private void startAutoClearTask() {
|
||||||
if (autoClearTaskId != -1) {
|
if (autoClearTaskId != -1) {
|
||||||
|
|||||||
@@ -116,14 +116,14 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendHelpMessage(Player player) {
|
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.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.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.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.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.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.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.tp", "&e/friend tp <Spielername> &7- Zu einem Freund teleportieren")));
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.footer", "&6=====================")));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.help.footer", "&6=======================")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFriendAdd(Player player, String targetName) {
|
private void handleFriendAdd(Player player, String targetName) {
|
||||||
@@ -155,15 +155,23 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
pendingRequests.add(playerUUID.toString());
|
pendingRequests.add(playerUUID.toString());
|
||||||
friendsConfig.set(targetUUID + ".pending_requests", pendingRequests);
|
friendsConfig.set(targetUUID + ".pending_requests", pendingRequests);
|
||||||
friendsConfig.set(targetUUID + ".name", targetName);
|
friendsConfig.set(targetUUID + ".name", targetName);
|
||||||
|
|
||||||
|
// --- FIX START: Absenderdaten speichern, damit er auch offline gefunden werden kann ---
|
||||||
|
friendsConfig.set(playerUUID + ".name", player.getName());
|
||||||
|
friendsConfig.set(playerUUID + ".last-online", System.currentTimeMillis());
|
||||||
|
// --- FIX END ---
|
||||||
|
|
||||||
saveFriendsConfig();
|
saveFriendsConfig();
|
||||||
|
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.sent", "&aFreundschaftsanfrage an %s gesendet!").replace("%s", targetName)));
|
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 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]")));
|
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()));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
accept.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend accept " + player.getName()));
|
||||||
TextComponent deny = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.add.deny-button", "&c [Deny]")));
|
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()));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
deny.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend deny " + player.getName()));
|
||||||
message.addExtra(accept);
|
message.addExtra(accept);
|
||||||
message.addExtra(deny);
|
message.addExtra(deny);
|
||||||
target.spigot().sendMessage(message);
|
target.spigot().sendMessage(message);
|
||||||
@@ -268,7 +276,8 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextComponent removeButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.list.remove-button", "&c[X]")));
|
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));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
removeButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend del " + friendName));
|
||||||
entry.addExtra(" ");
|
entry.addExtra(" ");
|
||||||
entry.addExtra(removeButton);
|
entry.addExtra(removeButton);
|
||||||
|
|
||||||
@@ -296,9 +305,11 @@ public class FriendCommand implements CommandExecutor {
|
|||||||
|
|
||||||
TextComponent confirmMessage = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.confirm", "&cMöchtest du %s wirklich aus deiner Freundesliste entfernen? ").replace("%s", friendName)));
|
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]")));
|
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));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
confirmButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend confirm " + friendName));
|
||||||
TextComponent cancelButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.cancel-button", "&c[Cancel]")));
|
TextComponent cancelButton = new TextComponent(ChatColor.translateAlternateColorCodes('&', langConfig.getString("friend.del.cancel-button", "&c[Cancel]")));
|
||||||
cancelButton.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/friend list"));
|
// ÄNDERUNG: RUN_COMMAND -> SUGGEST_COMMAND
|
||||||
|
cancelButton.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/friend list"));
|
||||||
confirmMessage.addExtra(confirmButton);
|
confirmMessage.addExtra(confirmButton);
|
||||||
confirmMessage.addExtra(" ");
|
confirmMessage.addExtra(" ");
|
||||||
confirmMessage.addExtra(cancelButton);
|
confirmMessage.addExtra(cancelButton);
|
||||||
|
|||||||
@@ -38,23 +38,21 @@ public class NickCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Befehl zum Entfernen des Nicks
|
// Entfernen des Nicks
|
||||||
if (args.length == 1 && (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("remove") || args[0].equalsIgnoreCase("reset"))) {
|
if (args.length == 1 && (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("remove") || args[0].equalsIgnoreCase("reset"))) {
|
||||||
String uuid = player.getUniqueId().toString();
|
String uuid = player.getUniqueId().toString();
|
||||||
|
|
||||||
// Aus Config entfernen
|
|
||||||
plugin.getNicknamesConfig().set(uuid, null);
|
plugin.getNicknamesConfig().set(uuid, null);
|
||||||
plugin.saveNicknamesConfig();
|
plugin.saveNicknamesConfig();
|
||||||
|
|
||||||
// Visuell sofort zurücksetzen
|
// WICHTIG: Nur DisplayName setzen, TablistManager übernimmt den Rest
|
||||||
player.setDisplayName(player.getName());
|
player.setDisplayName(player.getName());
|
||||||
player.setPlayerListName(player.getName());
|
|
||||||
|
|
||||||
player.sendMessage("§aDein Nickname wurde entfernt.");
|
player.sendMessage("§aDein Nickname wurde entfernt.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name zusammensetzen
|
// Zusammenbauen des Nicknames
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
sb.append(arg).append(" ");
|
sb.append(arg).append(" ");
|
||||||
@@ -73,28 +71,24 @@ public class NickCommand implements CommandExecutor {
|
|||||||
// Farben anwenden
|
// Farben anwenden
|
||||||
String coloredNick = translateColors(rawNick);
|
String coloredNick = translateColors(rawNick);
|
||||||
|
|
||||||
// Format: [Nickname] (Klammern weiß, Nickname farbig)
|
// Chat/Display: [Nick]
|
||||||
String finalNick = "§f[" + coloredNick + "§f]";
|
String finalNickForDisplay = "§f[" + coloredNick + "§f]";
|
||||||
|
|
||||||
// Anwenden
|
// WICHTIG: Nur DisplayName setzen
|
||||||
player.setDisplayName(finalNick);
|
// playerListName wird vom TablistManager automatisch gesetzt
|
||||||
player.setPlayerListName(finalNick);
|
player.setDisplayName(finalNickForDisplay);
|
||||||
|
|
||||||
// Speichern (ungefärbten Namen)
|
// Speichern (ungefärbten Namen)
|
||||||
plugin.getNicknamesConfig().set(player.getUniqueId().toString(), rawNick);
|
plugin.getNicknamesConfig().set(player.getUniqueId().toString(), rawNick);
|
||||||
plugin.saveNicknamesConfig();
|
plugin.saveNicknamesConfig();
|
||||||
|
|
||||||
player.sendMessage("§aDein Nickname wurde zu " + finalNick + " geändert.");
|
player.sendMessage("§aDein Nickname wurde zu " + finalNickForDisplay + " geändert.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String translateColors(String input) {
|
private String translateColors(String input) {
|
||||||
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
return replaceHexColors(withLegacy);
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceHexColors(String input) {
|
|
||||||
Matcher matcher = HEX_PATTERN.matcher(input);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = matcher.group();
|
String hexCode = matcher.group();
|
||||||
|
|||||||
100
src/main/java/de/viper/survivalplus/commands/RideCommand.java
Normal file
100
src/main/java/de/viper/survivalplus/commands/RideCommand.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
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.Entity;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
|
public class RideCommand implements CommandExecutor {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
|
||||||
|
public RideCommand(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 ist nur für Spieler!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player) sender;
|
||||||
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
|
|
||||||
|
if (!player.hasPermission("survivalplus.ride")) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du hast keine Berechtigung dafür!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FALL 1: ABSTEIGEN ---
|
||||||
|
if (args.length == 0) {
|
||||||
|
if (player.isInsideVehicle()) {
|
||||||
|
player.leaveVehicle();
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du bist abgestiegen!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FALL 2: AUFSTEIGEN (Via Raycast) ---
|
||||||
|
|
||||||
|
double maxDistance = 5.0;
|
||||||
|
|
||||||
|
// FIX: Wir übergeben einen Filter, der den Spieler selbst ignoriert
|
||||||
|
RayTraceResult rayTrace = player.getWorld().rayTraceEntities(
|
||||||
|
player.getEyeLocation(),
|
||||||
|
player.getEyeLocation().getDirection(),
|
||||||
|
maxDistance,
|
||||||
|
1.0, // Ray Größe (Dicke des Strahls)
|
||||||
|
entity -> !entity.getUniqueId().equals(player.getUniqueId()) // WICHTIG: Ignoriere mich selbst
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rayTrace == null || rayTrace.getHitEntity() == null) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du schaust auf nichts zum Reiten!");
|
||||||
|
player.sendMessage(ChatColor.GRAY + "Schaue einen Spieler oder Mob an.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity target = rayTrace.getHitEntity();
|
||||||
|
|
||||||
|
// Verhindern, dass man aufgesammelte Items reitet
|
||||||
|
if (target instanceof Item) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst keine aufgesammelten Items reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Zielle Logik ---
|
||||||
|
if (target instanceof Player) {
|
||||||
|
Player targetPlayer = (Player) target;
|
||||||
|
|
||||||
|
if (targetPlayer.equals(player)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst dich nicht selbst reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPlayer.hasPermission("survivalplus.ride.exempt")) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du kannst diesen Spieler nicht reiten!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.addPassenger(player);
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du reitest nun " + ChatColor.YELLOW + targetPlayer.getName() + ChatColor.GREEN + "!");
|
||||||
|
targetPlayer.sendMessage(ChatColor.GOLD + player.getName() + ChatColor.GREEN + " reitet dich jetzt!");
|
||||||
|
} else {
|
||||||
|
target.addPassenger(player);
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du reitest nun ein(e) " + target.getName() + "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendMessage(ChatColor.GRAY + "Benutzung: Schaue auf ein Wesen und tippe " + ChatColor.WHITE + "/ride");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.Manager.ShopManager;
|
import de.viper.survivalplus.Manager.ShopManager;
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.gui.ShopGui;
|
import de.viper.survivalplus.gui.ShopGui; // <--- WICHTIG: Dieser Import fehlte dir
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -34,7 +34,7 @@ public class ShopCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
|
|
||||||
// Shop-GUI öffnen, wenn kein Argument oder "gui"
|
// Shop-GUI öffnen
|
||||||
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
|
if (args.length == 0 || (args.length > 0 && args[0].toLowerCase().equals("gui"))) {
|
||||||
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
|
ShopGui shopGui = new ShopGui(plugin, player, shopManager);
|
||||||
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
|
Bukkit.getPluginManager().registerEvents(shopGui, plugin);
|
||||||
@@ -42,41 +42,69 @@ public class ShopCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length < 3) {
|
|
||||||
sender.sendMessage(getMessage("usage-add"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args[0].toLowerCase().equals("add")) {
|
if (!args[0].toLowerCase().equals("add")) {
|
||||||
sender.sendMessage(getMessage("unknown-subcommand"));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String itemKey = itemInHand.getType().name().toLowerCase();
|
// --- Neue Logik für /shop add ---
|
||||||
|
|
||||||
|
String itemKey;
|
||||||
double basePrice;
|
double basePrice;
|
||||||
int stock;
|
int stock;
|
||||||
|
|
||||||
|
// Fall 1: /shop add <Material> <Preis> <Stock> (4 Argumente)
|
||||||
|
if (args.length >= 4) {
|
||||||
|
String materialName = args[1];
|
||||||
|
Material mat = Material.matchMaterial(materialName);
|
||||||
|
|
||||||
|
if (mat == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Das Material '" + materialName + "' wurde nicht gefunden!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
itemKey = mat.name().toLowerCase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
basePrice = Double.parseDouble(args[2]);
|
||||||
|
stock = Integer.parseInt(args[3]);
|
||||||
|
} 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>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
itemKey = itemInHand.getType().name().toLowerCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
basePrice = Double.parseDouble(args[1]);
|
basePrice = Double.parseDouble(args[1]);
|
||||||
stock = Integer.parseInt(args[2]);
|
stock = Integer.parseInt(args[2]);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
sender.sendMessage(getMessage("number-error"));
|
sender.sendMessage(getMessage("number-error"));
|
||||||
return false;
|
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>");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
|
shopManager.addOrUpdateItem(itemKey, basePrice, stock);
|
||||||
|
|
||||||
String msg = getMessage("item-added")
|
String msg = getMessage("item-added")
|
||||||
.replace("{item}", itemKey)
|
.replace("{item}", itemKey)
|
||||||
.replace("{price}", args[1])
|
.replace("{price}", String.valueOf(basePrice))
|
||||||
.replace("{stock}", args[2]);
|
.replace("{stock}", String.valueOf(stock));
|
||||||
sender.sendMessage(msg);
|
sender.sendMessage(msg);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package de.viper.survivalplus.commands;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.listeners.SitListener;
|
import de.viper.survivalplus.listeners.SitListener;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
@@ -40,36 +41,50 @@ public class SitCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe, ob der Spieler bereits sitzt
|
// --- ÄNDERUNG: Wenn man schon sitzt, tue nichts ---
|
||||||
if (sitListener.isSitting(player)) {
|
if (sitListener.isSitting(player)) {
|
||||||
sitListener.standUp(player);
|
player.sendMessage(ChatColor.RED + "Du sitzt bereits!");
|
||||||
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
// Prüfe ob Spieler bereits in einem Fahrzeug ist
|
|
||||||
if (player.isInsideVehicle()) {
|
if (player.isInsideVehicle()) {
|
||||||
player.sendMessage(lang.getString("sit.already-in-vehicle", "§cDu kannst dich nicht setzen, während du in einem Fahrzeug bist!"));
|
player.sendMessage(lang.getString("sit.already-in-vehicle", "§cDu kannst dich nicht setzen, während du in einem Fahrzeug bist!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe ob unter dem Spieler Luft ist (Verhindert Sitzen beim Bauen in der Luft)
|
// Prüfe den Boden unter dem Spieler
|
||||||
Location loc = player.getLocation();
|
Location loc = player.getLocation();
|
||||||
Block blockBelow = loc.clone().subtract(0, 1, 0).getBlock();
|
Block blockBelow = loc.clone().subtract(0, 1, 0).getBlock();
|
||||||
|
|
||||||
// Wir erlauben das Sitzen nur, wenn der Block unter einem nicht Luft ist und kein Flüssigkeitsblock ist
|
|
||||||
if (blockBelow.getType().isAir() || !blockBelow.getType().isSolid()) {
|
if (blockBelow.getType().isAir() || !blockBelow.getType().isSolid()) {
|
||||||
player.sendMessage(plugin.getLangConfig().getString("sit.no-solid-ground", "§cDu kannst dich hier nicht hinsetzen (kein fester Boden)."));
|
player.sendMessage(plugin.getLangConfig().getString("sit.no-solid-ground", "§cDu kannst dich hier nicht hinsetzen (kein fester Boden)."));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setze den Spieler mittig auf den Block
|
// Position vorbereiten
|
||||||
Location location = player.getLocation();
|
Location location = player.getLocation();
|
||||||
location.setX(location.getBlockX() + 0.5);
|
location.setX(location.getBlockX() + 0.5);
|
||||||
location.setZ(location.getBlockZ() + 0.5);
|
location.setZ(location.getBlockZ() + 0.5);
|
||||||
location.setY(location.getBlockY());
|
|
||||||
|
// Höhe dynamisch berechnen
|
||||||
|
double y = location.getBlockY();
|
||||||
|
|
||||||
|
if (isStair(blockBelow.getType()) || isSlab(blockBelow.getType())) {
|
||||||
|
y += 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.setY(y);
|
||||||
|
|
||||||
sitListener.sitPlayer(player, location);
|
sitListener.sitPlayer(player, location);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStair(Material material) {
|
||||||
|
return material.name().endsWith("_STAIRS");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlab(Material material) {
|
||||||
|
return material.name().endsWith("_SLAB") || material.name().endsWith("_STEP") || material.name().equals("PRISMARINE_SLAB");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,8 +42,7 @@ public class ShopGui implements Listener {
|
|||||||
for (String itemKey : shopManager.getShopConfig().getConfigurationSection("items").getKeys(false)) {
|
for (String itemKey : shopManager.getShopConfig().getConfigurationSection("items").getKeys(false)) {
|
||||||
Material mat = getMaterialFromKey(itemKey);
|
Material mat = getMaterialFromKey(itemKey);
|
||||||
if (mat == null) {
|
if (mat == null) {
|
||||||
player.sendMessage(ChatColor.RED + "Material für '" + itemKey + "' konnte nicht gefunden werden.");
|
continue; // Unbekannte Materialien einfach überspringen
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addShopItem(itemKey, mat, 64);
|
addShopItem(itemKey, mat, 64);
|
||||||
@@ -64,6 +63,7 @@ public class ShopGui implements Listener {
|
|||||||
|
|
||||||
private void addShopItem(String itemKey, Material material, int amount) {
|
private void addShopItem(String itemKey, Material material, int amount) {
|
||||||
double pricePerUnit = shopManager.getCurrentPrice(itemKey);
|
double pricePerUnit = shopManager.getCurrentPrice(itemKey);
|
||||||
|
int currentStock = shopManager.getStock(itemKey);
|
||||||
double totalPrice = pricePerUnit * amount;
|
double totalPrice = pricePerUnit * amount;
|
||||||
|
|
||||||
ItemStack item = new ItemStack(material, amount);
|
ItemStack item = new ItemStack(material, amount);
|
||||||
@@ -71,9 +71,12 @@ public class ShopGui implements Listener {
|
|||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(ChatColor.GREEN.toString() + amount + "x " + material.name());
|
meta.setDisplayName(ChatColor.GREEN.toString() + amount + "x " + material.name());
|
||||||
meta.setLore(Arrays.asList(
|
meta.setLore(Arrays.asList(
|
||||||
|
ChatColor.GRAY + "Lagerbestand: " + ChatColor.YELLOW + currentStock,
|
||||||
ChatColor.YELLOW + "Preis pro Stück: " + pricePerUnit,
|
ChatColor.YELLOW + "Preis pro Stück: " + pricePerUnit,
|
||||||
ChatColor.YELLOW + "Gesamtpreis: " + totalPrice,
|
ChatColor.YELLOW + "Gesamtpreis: " + totalPrice,
|
||||||
ChatColor.GRAY + "Klicke, um zu kaufen"
|
"",
|
||||||
|
ChatColor.GREEN + "Linksklick zum Kaufen",
|
||||||
|
ChatColor.RED + "Rechtsklick zum Verkaufen"
|
||||||
));
|
));
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
@@ -101,6 +104,8 @@ public class ShopGui implements Listener {
|
|||||||
Material mat = clicked.getType();
|
Material mat = clicked.getType();
|
||||||
String itemKey = mat.name().toLowerCase();
|
String itemKey = mat.name().toLowerCase();
|
||||||
|
|
||||||
|
if (e.isLeftClick()) {
|
||||||
|
// --- KAUFEN ---
|
||||||
if (!shopManager.buyItem(itemKey, amount)) {
|
if (!shopManager.buyItem(itemKey, amount)) {
|
||||||
player.sendMessage(ChatColor.RED + "Nicht genügend Bestand im Shop.");
|
player.sendMessage(ChatColor.RED + "Nicht genügend Bestand im Shop.");
|
||||||
return;
|
return;
|
||||||
@@ -108,18 +113,45 @@ public class ShopGui implements Listener {
|
|||||||
|
|
||||||
double totalPrice = shopManager.getCurrentPrice(itemKey) * amount;
|
double totalPrice = shopManager.getCurrentPrice(itemKey) * amount;
|
||||||
|
|
||||||
// TODO: Economy Abzug einfügen
|
// TODO: Economy Abzug hier einfügen!
|
||||||
|
// Beispiel: if (!economy.withdrawPlayer(player, totalPrice)) { ... }
|
||||||
|
|
||||||
player.getInventory().addItem(new ItemStack(mat, amount));
|
player.getInventory().addItem(new ItemStack(mat, amount));
|
||||||
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + totalPrice + " Coins gekauft.");
|
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + String.format("%.2f", totalPrice) + " gekauft.");
|
||||||
|
|
||||||
|
} else if (e.isRightClick()) {
|
||||||
|
// --- VERKAUFEN ---
|
||||||
|
|
||||||
|
// Prüfen ob Spieler genug Items hat
|
||||||
|
if (!player.getInventory().containsAtLeast(new ItemStack(mat), amount)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Du hast nicht genug Items zum Verkaufen.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verkaufslogik
|
||||||
|
shopManager.sellItem(itemKey, amount);
|
||||||
|
|
||||||
|
double sellPrice = shopManager.getCurrentPrice(itemKey) * amount; // Neuer Preis nach dem Verkauf wird genutzt
|
||||||
|
// Hinweis: In echten Systemen bekommt man oft den Preis *vor* dem Preisverfall, hier nehmen wir den neuen für Einfachheit oder den gespeicherten:
|
||||||
|
// Besser wäre: double oldPrice = price * amount; ... player.giveMoney(oldPrice);
|
||||||
|
|
||||||
|
// TODO: Economy Gutschrift hier einfügen!
|
||||||
|
|
||||||
|
player.getInventory().removeItem(new ItemStack(mat, amount));
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Du hast " + amount + "x " + mat.name() + " für " + String.format("%.2f", sellPrice) + " verkauft.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inventory schließen, um Preise neu zu laden und Bugs zu vermeiden
|
||||||
player.closeInventory();
|
player.closeInventory();
|
||||||
|
// Optional: direkt neu öffnen mit createInventory() wenn es flüssig sein soll
|
||||||
|
// createInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent e) {
|
public void onInventoryClose(InventoryCloseEvent e) {
|
||||||
if (e.getView().getTitle().equals("Shop") && e.getPlayer().equals(player)) {
|
if (e.getView().getTitle().equals("Shop") && e.getPlayer().equals(player)) {
|
||||||
// Optional: Listener entfernen oder Aufräumarbeiten hier
|
// Listener kann entladen werden, wenn nicht mehr gebraucht
|
||||||
|
// HandlerList.unregisterAll(this); // Vorsicht: falls Singleton, sonst fliegt allen der GUI weg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.attribute.Attribute;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.*;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDeathEvent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AdaptiveMobListener implements Listener {
|
||||||
|
|
||||||
|
private final SurvivalPlus plugin;
|
||||||
|
|
||||||
|
// Konfiguration für die Anpassung
|
||||||
|
private final double SCALING_FACTOR = 0.1; // 10% mehr Stärke pro Level
|
||||||
|
private final int KILLS_PER_LEVEL = 5; // Alle 5 Kills steigt das Level
|
||||||
|
private final int MAX_LEVEL = 50; // Maximales Level (Cap)
|
||||||
|
|
||||||
|
public AdaptiveMobListener(SurvivalPlus plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Verhalten tracken: Zählt Kills des Spielers
|
||||||
|
@EventHandler
|
||||||
|
public void onMobDeath(EntityDeathEvent event) {
|
||||||
|
if (event.getEntity().getKiller() instanceof Player) {
|
||||||
|
Player killer = event.getEntity().getKiller();
|
||||||
|
UUID uuid = killer.getUniqueId();
|
||||||
|
|
||||||
|
FileConfiguration mobConfig = plugin.getMobAdaptConfig();
|
||||||
|
String uuidPath = uuid.toString();
|
||||||
|
|
||||||
|
int currentLevel = mobConfig.getInt(uuidPath + ".level", 0);
|
||||||
|
int currentKills = mobConfig.getInt(uuidPath + ".kills", 0);
|
||||||
|
|
||||||
|
currentKills++;
|
||||||
|
|
||||||
|
// Level up wenn genug Kills
|
||||||
|
if (currentKills >= KILLS_PER_LEVEL && currentLevel < MAX_LEVEL) {
|
||||||
|
currentLevel++;
|
||||||
|
currentKills = 0;
|
||||||
|
killer.sendMessage(ChatColor.GREEN + "[SurvivalPlus] " + ChatColor.GRAY + "Die Monster werden aggressiver! (Threat Level: " + currentLevel + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speichern
|
||||||
|
mobConfig.set(uuidPath + ".level", currentLevel);
|
||||||
|
mobConfig.set(uuidPath + ".kills", currentKills);
|
||||||
|
plugin.saveMobAdaptConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Anpassung: Monster werden beim Spawnen angepasst
|
||||||
|
@EventHandler
|
||||||
|
public void onCreatureSpawn(CreatureSpawnEvent event) {
|
||||||
|
// Nur aktivieren, wenn in Config gewünscht
|
||||||
|
if (!plugin.getConfig().getBoolean("adaptive-mobs.enabled", true)) return;
|
||||||
|
|
||||||
|
// Wir greifen nur bei natürlichen Spawns ein (oder Spawn-Eiern), aber nicht bei Spawner-Blöcken (Farmen schützen)
|
||||||
|
if (event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.NATURAL &&
|
||||||
|
event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.SPAWNER_EGG &&
|
||||||
|
event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.DISPENSE_EGG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity entity = event.getEntity();
|
||||||
|
|
||||||
|
// Keine Anpassung für friedliche Tiere
|
||||||
|
if (entity instanceof Animals || entity instanceof Ambient) return;
|
||||||
|
|
||||||
|
// Nächsten Spieler suchen (Radius: 30 Blöcke)
|
||||||
|
Player nearestPlayer = null;
|
||||||
|
double minDistance = 30.0;
|
||||||
|
|
||||||
|
for (Player p : entity.getWorld().getPlayers()) {
|
||||||
|
if (p.getLocation().distance(entity.getLocation()) <= minDistance) {
|
||||||
|
nearestPlayer = p;
|
||||||
|
minDistance = p.getLocation().distance(entity.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestPlayer != null) {
|
||||||
|
applyAttributesBasedOnPlayer(entity, nearestPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyAttributesBasedOnPlayer(LivingEntity entity, Player player) {
|
||||||
|
FileConfiguration mobConfig = plugin.getMobAdaptConfig();
|
||||||
|
int level = mobConfig.getInt(player.getUniqueId().toString() + ".level", 0);
|
||||||
|
|
||||||
|
if (level == 0) return;
|
||||||
|
|
||||||
|
// Multiplikator berechnen (z.B. Level 10 -> 1.0 + (10 * 0.1) = 2.0 = doppelte Stärke)
|
||||||
|
double multiplier = 1.0 + (level * SCALING_FACTOR);
|
||||||
|
|
||||||
|
// Cap bei 5-facher Stärke, damit es nicht unspielbar wird
|
||||||
|
if (multiplier > 5.0) multiplier = 5.0;
|
||||||
|
|
||||||
|
// Lebenspunkte erhöhen
|
||||||
|
if (entity.getAttribute(Attribute.GENERIC_MAX_HEALTH) != null) {
|
||||||
|
double baseHealth = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
|
||||||
|
entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(baseHealth * multiplier);
|
||||||
|
entity.setHealth(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angriffsschaden erhöhen
|
||||||
|
if (entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE) != null) {
|
||||||
|
double baseDamage = entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue();
|
||||||
|
entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(baseDamage * multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Visuelles Indiz (Name über dem Kopf), wenn Monster sehr stark sind
|
||||||
|
if (level >= 10) {
|
||||||
|
entity.setCustomName(ChatColor.RED + "⚠ " + ChatColor.GRAY + "Starkes Monster (Lvl " + level + ")");
|
||||||
|
entity.setCustomNameVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,14 @@ package de.viper.survivalplus.listeners;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import de.viper.survivalplus.util.Claim;
|
import de.viper.survivalplus.util.Claim;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Monster;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -70,4 +73,28 @@ public class ClaimListener implements Listener {
|
|||||||
lastClaim.put(playerId, currentClaim);
|
lastClaim.put(playerId, currentClaim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- NEU: Schutz vor Monstern im Claim ---
|
||||||
|
@EventHandler
|
||||||
|
public void onMobTarget(EntityTargetLivingEntityEvent event) {
|
||||||
|
// 1. Prüfen, ob das Ziel ein Spieler ist
|
||||||
|
if (!(event.getTarget() instanceof Player)) return;
|
||||||
|
|
||||||
|
// 2. Prüfen, ob das Angreifer ein Monster ist (Zombie, Skelett, etc.)
|
||||||
|
if (!(event.getEntity() instanceof Monster)) return;
|
||||||
|
|
||||||
|
Player player = (Player) event.getTarget();
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
|
||||||
|
// 3. Prüfen, ob der Spieler in einem Claim steht
|
||||||
|
Claim claim = plugin.getClaim(loc);
|
||||||
|
|
||||||
|
if (claim != null) {
|
||||||
|
// 4. Prüfen, ob der Spieler dort Rechte hat (Owner oder Trusted)
|
||||||
|
if (claim.getOwner().equals(player.getUniqueId()) || claim.getTrusted().contains(player.getUniqueId())) {
|
||||||
|
// Das Targeting abbrechen -> Monster greift nicht an
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,9 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
private final Map<UUID, BossBar> bossBars = new HashMap<>();
|
private final Map<UUID, BossBar> bossBars = new HashMap<>();
|
||||||
private final Map<UUID, Long> messageCooldowns = new HashMap<>();
|
private final Map<UUID, Long> messageCooldowns = new HashMap<>();
|
||||||
|
|
||||||
|
// NEU: Set um zu speichern, wer schon mal gejoint ist
|
||||||
|
private final Set<UUID> hasJoined = new HashSet<>();
|
||||||
|
|
||||||
// YAML Datei
|
// YAML Datei
|
||||||
private File dataFile;
|
private File dataFile;
|
||||||
private FileConfiguration dataConfig;
|
private FileConfiguration dataConfig;
|
||||||
@@ -59,17 +62,23 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
|
|
||||||
// Falls nicht gespeichert, neue Zeit einstellen
|
boolean isFirstJoin = !hasJoined.contains(uuid);
|
||||||
remainingSeconds.putIfAbsent(uuid, durationMinutes * 60);
|
|
||||||
|
|
||||||
// Bossbar erstellen/anzeigen
|
if (isFirstJoin) {
|
||||||
BossBar bar = Bukkit.createBossBar(
|
// Erster Join EVER -> Schutz geben und als "gejoint" markieren
|
||||||
ChatColor.GREEN + "Neulingsschutz: " + formatTime(remainingSeconds.get(uuid)),
|
remainingSeconds.put(uuid, durationMinutes * 60);
|
||||||
BarColor.GREEN,
|
hasJoined.add(uuid);
|
||||||
BarStyle.SOLID
|
|
||||||
);
|
createBossBar(player, remainingSeconds.get(uuid));
|
||||||
bar.addPlayer(player);
|
} else {
|
||||||
bossBars.put(uuid, bar);
|
// Spieler war schonmal da -> Prüfen ob noch Schutz übrig ist
|
||||||
|
Integer timeLeft = remainingSeconds.get(uuid);
|
||||||
|
if (timeLeft != null && timeLeft > 0) {
|
||||||
|
// Schutz läuft noch -> Bossbar wiederherstellen
|
||||||
|
createBossBar(player, timeLeft);
|
||||||
|
}
|
||||||
|
// Wenn timeLeft null ist oder 0, passiert nichts -> Kein Schutz für den "alten Hasen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -77,12 +86,13 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
// Bossbar entfernen, aber Zeit bleibt in Map bestehen
|
|
||||||
|
// Bossbar entfernen, aber Status (Zeit & Joined) in Map/Datei behalten
|
||||||
BossBar bar = bossBars.remove(uuid);
|
BossBar bar = bossBars.remove(uuid);
|
||||||
if (bar != null) {
|
if (bar != null) {
|
||||||
bar.removeAll();
|
bar.removeAll();
|
||||||
}
|
}
|
||||||
saveData(); // Beim Verlassen direkt speichern
|
saveData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -94,29 +104,27 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
UUID victimId = victim.getUniqueId();
|
UUID victimId = victim.getUniqueId();
|
||||||
Integer timeLeft = remainingSeconds.get(victimId);
|
Integer timeLeft = remainingSeconds.get(victimId);
|
||||||
|
|
||||||
if (timeLeft != null && timeLeft > 0) {
|
// Nur schützen, wenn Zeit > 0
|
||||||
|
if (timeLeft == null || timeLeft <= 0) return;
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
// Prüfe Abklingzeit für Opfer
|
// Prüfe Cooldown für Nachrichten
|
||||||
long currentTime = System.currentTimeMillis() / 1000;
|
long currentTime = System.currentTimeMillis() / 1000;
|
||||||
long lastMessageTimeVictim = messageCooldowns.getOrDefault(victimId, 0L);
|
if (currentTime >= messageCooldowns.getOrDefault(victimId, 0L) + COOLDOWN_SECONDS) {
|
||||||
if (currentTime >= lastMessageTimeVictim + COOLDOWN_SECONDS) {
|
|
||||||
victim.sendMessage(ChatColor.GREEN + "Du bist noch im Neulingsschutz!");
|
victim.sendMessage(ChatColor.GREEN + "Du bist noch im Neulingsschutz!");
|
||||||
messageCooldowns.put(victimId, currentTime);
|
messageCooldowns.put(victimId, currentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe Abklingzeit für Angreifer, falls es ein Spieler ist
|
|
||||||
if (event.getDamager() instanceof Player) {
|
if (event.getDamager() instanceof Player) {
|
||||||
Player damager = (Player) event.getDamager();
|
Player damager = (Player) event.getDamager();
|
||||||
UUID damagerId = damager.getUniqueId();
|
UUID damagerId = damager.getUniqueId();
|
||||||
long lastMessageTimeDamager = messageCooldowns.getOrDefault(damagerId, 0L);
|
if (currentTime >= messageCooldowns.getOrDefault(damagerId, 0L) + COOLDOWN_SECONDS) {
|
||||||
if (currentTime >= lastMessageTimeDamager + COOLDOWN_SECONDS) {
|
|
||||||
damager.sendMessage(ChatColor.RED + victim.getName() + " ist noch geschützt!");
|
damager.sendMessage(ChatColor.RED + victim.getName() + " ist noch geschützt!");
|
||||||
messageCooldowns.put(damagerId, currentTime);
|
messageCooldowns.put(damagerId, currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void startTimer() {
|
private void startTimer() {
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@@ -126,16 +134,15 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
Player p = Bukkit.getPlayer(uuid);
|
Player p = Bukkit.getPlayer(uuid);
|
||||||
|
|
||||||
if (p == null || !p.isOnline()) {
|
if (p == null || !p.isOnline()) {
|
||||||
// Spieler offline → Zeit pausiert
|
// Spieler offline -> Zeit pausiert
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timeLeft = remainingSeconds.getOrDefault(uuid, 0);
|
int timeLeft = remainingSeconds.getOrDefault(uuid, 0);
|
||||||
|
|
||||||
if (timeLeft <= 0) {
|
if (timeLeft <= 0) {
|
||||||
// Ablauf: Bossbar weg + Map clean
|
// Zeit abgelaufen -> Bossbar weg, aber aus hasJoined NICHT löschen
|
||||||
BossBar bar = bossBars.remove(uuid);
|
removeProtection(uuid);
|
||||||
if (bar != null) bar.removeAll();
|
|
||||||
remainingSeconds.remove(uuid);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,17 +151,41 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
remainingSeconds.put(uuid, timeLeft);
|
remainingSeconds.put(uuid, timeLeft);
|
||||||
|
|
||||||
// Bossbar updaten
|
// Bossbar updaten
|
||||||
BossBar bar = bossBars.get(uuid);
|
updateBossBar(p, timeLeft);
|
||||||
if (bar != null) {
|
|
||||||
bar.setTitle(ChatColor.GREEN + "Neulingsschutz: " + formatTime(timeLeft));
|
|
||||||
bar.setProgress(Math.max(0, timeLeft / (float) (durationMinutes * 60)));
|
|
||||||
}
|
}
|
||||||
}
|
// Jedes Mal zyklisch speichern
|
||||||
saveData(); // zyklisch speichern
|
saveData();
|
||||||
}
|
}
|
||||||
}.runTaskTimer(plugin, 20L, 20L);
|
}.runTaskTimer(plugin, 20L, 20L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeProtection(UUID uuid) {
|
||||||
|
remainingSeconds.remove(uuid);
|
||||||
|
BossBar bar = bossBars.remove(uuid);
|
||||||
|
if (bar != null) {
|
||||||
|
bar.removeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBossBar(Player player, int seconds) {
|
||||||
|
BossBar bar = Bukkit.createBossBar(
|
||||||
|
ChatColor.GREEN + "Neulingsschutz: " + formatTime(seconds),
|
||||||
|
BarColor.GREEN,
|
||||||
|
BarStyle.SOLID
|
||||||
|
);
|
||||||
|
bar.addPlayer(player);
|
||||||
|
bar.setProgress(Math.max(0, seconds / (float) (durationMinutes * 60)));
|
||||||
|
bossBars.put(player.getUniqueId(), bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBossBar(Player player, int seconds) {
|
||||||
|
BossBar bar = bossBars.get(player.getUniqueId());
|
||||||
|
if (bar != null) {
|
||||||
|
bar.setTitle(ChatColor.GREEN + "Neulingsschutz: " + formatTime(seconds));
|
||||||
|
bar.setProgress(Math.max(0, seconds / (float) (durationMinutes * 60)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- Datei Handling ----------
|
// ---------- Datei Handling ----------
|
||||||
private void loadData() {
|
private void loadData() {
|
||||||
dataFile = new File(plugin.getDataFolder(), "newbieprotection.yml");
|
dataFile = new File(plugin.getDataFolder(), "newbieprotection.yml");
|
||||||
@@ -166,20 +197,47 @@ public class NewbieProtectionListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
||||||
|
|
||||||
|
hasJoined.clear();
|
||||||
|
remainingSeconds.clear();
|
||||||
|
|
||||||
for (String key : dataConfig.getKeys(false)) {
|
for (String key : dataConfig.getKeys(false)) {
|
||||||
try {
|
try {
|
||||||
UUID uuid = UUID.fromString(key);
|
UUID uuid = UUID.fromString(key);
|
||||||
int sec = dataConfig.getInt(key);
|
|
||||||
|
// Gelesen: 'joined' Status und 'seconds'
|
||||||
|
boolean joined = dataConfig.getBoolean(key + ".joined", false);
|
||||||
|
int sec = dataConfig.getInt(key + ".seconds", 0);
|
||||||
|
|
||||||
|
if (joined) {
|
||||||
|
hasJoined.add(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sec > 0) {
|
||||||
remainingSeconds.put(uuid, sec);
|
remainingSeconds.put(uuid, sec);
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException ignored) {}
|
} catch (IllegalArgumentException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveData() {
|
public void saveData() {
|
||||||
if (dataConfig == null) return;
|
dataConfig = YamlConfiguration.loadConfiguration(dataFile);
|
||||||
for (Map.Entry<UUID, Integer> entry : remainingSeconds.entrySet()) {
|
|
||||||
dataConfig.set(entry.getKey().toString(), entry.getValue());
|
// Wir speichern ALLE Spieler, die schon mal gejoint sind (hasJoined)
|
||||||
|
// damit wir beim Rejoin wissen, dass sie keinen Neulingsschutz mehr bekommen.
|
||||||
|
for (UUID uuid : hasJoined) {
|
||||||
|
dataConfig.set(uuid + ".joined", true);
|
||||||
|
|
||||||
|
Integer sec = remainingSeconds.get(uuid);
|
||||||
|
if (sec != null && sec > 0) {
|
||||||
|
dataConfig.set(uuid + ".seconds", sec);
|
||||||
|
} else {
|
||||||
|
// Wenn Schutz abgelaufen (0 oder nicht in Map), speichern wir 0 oder löschen wir den Key?
|
||||||
|
// Besser: löschen wir den Key "seconds", aber "joined" bleibt true.
|
||||||
|
dataConfig.set(uuid + ".seconds", null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dataConfig.save(dataFile);
|
dataConfig.save(dataFile);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.viper.survivalplus.listeners;
|
||||||
|
|
||||||
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dieser Listener wird nicht mehr benötigt, da NickLoadListener
|
||||||
|
* mit ProtocolLib die Join/Quit Messages direkt auf Packet-Ebene behandelt.
|
||||||
|
*
|
||||||
|
* Diese Klasse kann gelöscht werden oder bleibt als leere Klasse bestehen.
|
||||||
|
*/
|
||||||
|
public class NickJoinMessageListener {
|
||||||
|
// Nicht mehr benötigt - ProtocolLib übernimmt die Arbeit
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@ package de.viper.survivalplus.listeners;
|
|||||||
|
|
||||||
import de.viper.survivalplus.SurvivalPlus;
|
import de.viper.survivalplus.SurvivalPlus;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -19,26 +22,78 @@ public class NickLoadListener implements Listener {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
|
||||||
|
|
||||||
|
// Immer die Standard-Join-Message unterdrücken — wir senden eine einzelne kontrollierte Nachricht später
|
||||||
|
event.setJoinMessage(null);
|
||||||
|
|
||||||
|
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
||||||
if (rawNick != null && !rawNick.isEmpty()) {
|
if (rawNick != null && !rawNick.isEmpty()) {
|
||||||
String coloredNick = translateColors(rawNick);
|
String coloredNick = translateColors(rawNick);
|
||||||
String finalNick = "§f[" + coloredNick + "§f]";
|
String plainNick = ChatColor.stripColor(coloredNick);
|
||||||
player.setDisplayName(finalNick);
|
|
||||||
player.setPlayerListName(finalNick);
|
// Kurz: DisplayName jetzt auf echten Namen lassen, damit andere Plugins / Bukkit intern konsistent sind.
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
|
||||||
|
// In 1 Tick: DisplayName für Chat setzen UND die Join-Nachricht EINMAL manuell versenden
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
// Chat-Display: [Nick]
|
||||||
|
player.setDisplayName("§f[" + coloredNick + "§f]");
|
||||||
|
|
||||||
|
// Nachricht an alle Spieler senden (keine Doppelung, weil wir event.setJoinMessage(null) gesetzt haben)
|
||||||
|
String message = coloredNick + " §ejoined the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log in Konsole (sauber, ohne Farb-Codes)
|
||||||
|
plugin.getLogger().info(plainNick + " joined the game");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Kein Nick vorhanden -> benutze Standardverhalten, aber ebenfalls manuell, um Doppelungen zu verhindern
|
||||||
|
player.setDisplayName(player.getName());
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
String message = player.getName() + " §ejoined the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(message);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(player.getName() + " joined the game");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
// Standard-Quit-Message unterdrücken
|
||||||
|
event.setQuitMessage(null);
|
||||||
|
|
||||||
|
String rawNick = plugin.getNicknamesConfig().getString(player.getUniqueId().toString());
|
||||||
|
if (rawNick != null && !rawNick.isEmpty()) {
|
||||||
|
String coloredNick = translateColors(rawNick);
|
||||||
|
String plainNick = ChatColor.stripColor(coloredNick);
|
||||||
|
|
||||||
|
// Sende Quit-Nachricht einmal manuell
|
||||||
|
String msg = coloredNick + " §eleft the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(msg);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(plainNick + " left the game");
|
||||||
|
} else {
|
||||||
|
String msg = player.getName() + " §eleft the game";
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
p.sendMessage(msg);
|
||||||
|
}
|
||||||
|
plugin.getLogger().info(player.getName() + " left the game");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String translateColors(String input) {
|
private String translateColors(String input) {
|
||||||
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
String withLegacy = org.bukkit.ChatColor.translateAlternateColorCodes('&', input);
|
||||||
return replaceHexColors(withLegacy);
|
Matcher matcher = HEX_PATTERN.matcher(withLegacy);
|
||||||
}
|
|
||||||
|
|
||||||
private String replaceHexColors(String input) {
|
|
||||||
Matcher matcher = HEX_PATTERN.matcher(input);
|
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String hexCode = matcher.group();
|
String hexCode = matcher.group();
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ import java.util.logging.Level;
|
|||||||
public class SitListener implements Listener {
|
public class SitListener implements Listener {
|
||||||
private final SurvivalPlus plugin;
|
private final SurvivalPlus plugin;
|
||||||
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
private final Map<UUID, ArmorStand> sittingPlayers = new HashMap<>();
|
||||||
private static final String SIT_TAG = "SP_SIT_STAND"; // Tag zum Identifizieren
|
private final Map<UUID, Long> sitCooldown = new HashMap<>(); // Neuer Cooldown gegen "Auto-Standup"
|
||||||
|
private static final String SIT_TAG = "SP_SIT_STAND";
|
||||||
|
|
||||||
public SitListener(SurvivalPlus plugin) {
|
public SitListener(SurvivalPlus plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
cleanUpGhostStands(); // Entferne alte Stands beim Laden
|
cleanUpGhostStands();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSitting(Player player) {
|
public boolean isSitting(Player player) {
|
||||||
@@ -45,37 +46,53 @@ public class SitListener implements Listener {
|
|||||||
// Erstelle einen unsichtbaren ArmorStand als Sitz
|
// Erstelle einen unsichtbaren ArmorStand als Sitz
|
||||||
ArmorStand armorStand = player.getWorld().spawn(location, ArmorStand.class);
|
ArmorStand armorStand = player.getWorld().spawn(location, ArmorStand.class);
|
||||||
armorStand.setGravity(false);
|
armorStand.setGravity(false);
|
||||||
armorStand.setMarker(true); // Keine Hitbox
|
armorStand.setMarker(true);
|
||||||
armorStand.setInvisible(true);
|
armorStand.setInvisible(true);
|
||||||
armorStand.setInvulnerable(true);
|
armorStand.setInvulnerable(true);
|
||||||
armorStand.addScoreboardTag(SIT_TAG); // Tag für Cleanup
|
armorStand.addScoreboardTag(SIT_TAG);
|
||||||
|
|
||||||
|
// Setze Rotation des Stands auf Rotation des Spielers
|
||||||
|
armorStand.setRotation(player.getLocation().getYaw(), player.getLocation().getPitch());
|
||||||
|
|
||||||
// Füge Spieler als Passenger hinzu
|
// Füge Spieler als Passenger hinzu
|
||||||
armorStand.addPassenger(player);
|
armorStand.addPassenger(player);
|
||||||
|
|
||||||
// Teleportiere den Spieler nochmals zur Sicherheit (Anti-Slide)
|
// FIX: KEIN player.teleport() hier ausführen!
|
||||||
player.teleport(location);
|
// In neueren Versionen "bricht" das Teleportieren das Mounten sofort wieder.
|
||||||
|
// Der Spieler wird automatisch durch addPassenger zum Stand teleportiert.
|
||||||
|
|
||||||
|
// Cooldown setzen, damit wir nicht sofort durch "Movement" aufstehen
|
||||||
|
sitCooldown.put(player.getUniqueId(), System.currentTimeMillis() + 500L);
|
||||||
|
|
||||||
sittingPlayers.put(player.getUniqueId(), armorStand);
|
sittingPlayers.put(player.getUniqueId(), armorStand);
|
||||||
|
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
player.sendMessage(lang.getString("sit.success", "§aDu hast dich hingesetzt!"));
|
||||||
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " sitzt bei " + locationToString(location));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void standUp(Player player) {
|
public void standUp(Player player) {
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
ArmorStand armorStand = sittingPlayers.remove(playerId);
|
||||||
|
sitCooldown.remove(playerId); // Cooldown löschen
|
||||||
|
|
||||||
if (armorStand != null) {
|
if (armorStand != null) {
|
||||||
if (player.isValid()) {
|
if (player.isValid() && armorStand.isValid()) {
|
||||||
|
// Wenn man absteigt, landet man oft leicht daneben. Wir korrigieren das leicht,
|
||||||
|
// aber nicht so aggressiv wie beim Hinsetzen.
|
||||||
|
Location loc = player.getLocation().add(0, 0.2, 0);
|
||||||
armorStand.removePassenger(player);
|
armorStand.removePassenger(player);
|
||||||
}
|
|
||||||
armorStand.remove();
|
armorStand.remove();
|
||||||
|
|
||||||
|
// Kleiner Fix, damit man nicht im Boden klebt
|
||||||
|
player.teleport(loc);
|
||||||
|
} else {
|
||||||
|
armorStand.remove();
|
||||||
|
}
|
||||||
|
|
||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
if (player.isOnline()) {
|
if (player.isOnline()) {
|
||||||
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
player.sendMessage(lang.getString("sit.stand-up", "§aDu bist aufgestanden!"));
|
||||||
}
|
}
|
||||||
plugin.getLogger().log(Level.FINE, "Spieler " + player.getName() + " ist aufgestanden");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +106,6 @@ public class SitListener implements Listener {
|
|||||||
FileConfiguration lang = plugin.getLangConfig();
|
FileConfiguration lang = plugin.getLangConfig();
|
||||||
|
|
||||||
if (!player.hasPermission("survivalplus.sit")) {
|
if (!player.hasPermission("survivalplus.sit")) {
|
||||||
// Kein Feedback nötig, wenn keine Permission, um nicht zu spammen
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,57 +114,62 @@ public class SitListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEU: Prüfen ob der Spieler nah genug dran ist (max 2 Blöcke Entfernung)
|
|
||||||
// Dies verhindert das versehentliche Sitzen beim Bauen in der Ferne.
|
|
||||||
double distance = player.getLocation().distance(block.getLocation());
|
double distance = player.getLocation().distance(block.getLocation());
|
||||||
if (distance > 3.0) {
|
if (distance > 3.0) {
|
||||||
return; // Spieler ist zu weit weg -> Ignorieren (normales Bauen möglich)
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn der Spieler bereits sitzt, stehe auf
|
|
||||||
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
if (sittingPlayers.containsKey(player.getUniqueId())) {
|
||||||
standUp(player);
|
standUp(player);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe ob in Fahrzeug
|
|
||||||
if (player.isInsideVehicle()) return;
|
if (player.isInsideVehicle()) return;
|
||||||
|
|
||||||
// Setze den Spieler genau auf der Treppenstufe
|
// Position berechnen
|
||||||
Location location = block.getLocation();
|
Location location = block.getLocation();
|
||||||
location.setX(location.getX() + 0.5);
|
location.setX(location.getX() + 0.5);
|
||||||
location.setZ(location.getZ() + 0.5);
|
location.setZ(location.getZ() + 0.5);
|
||||||
|
|
||||||
// Bei Treppen die Höhe anpassen (Y + 0.5 ist meist genau die "Sitzfläche")
|
// Bei Treppen: Y + 0.5 ist meistens korrekt für die Sitzfläche
|
||||||
location.setY(location.getY() + 0.5);
|
location.setY(location.getY() + 0.5);
|
||||||
|
|
||||||
|
// Drehung anpassen, damit man nicht auf der Treppe schräg sitzt
|
||||||
|
location.setYaw(player.getLocation().getYaw());
|
||||||
|
location.setPitch(player.getLocation().getPitch());
|
||||||
|
|
||||||
sitPlayer(player, location);
|
sitPlayer(player, location);
|
||||||
event.setCancelled(true); // Verhindere andere Interaktionen mit der Treppe
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerMove(PlayerMoveEvent event) {
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
if (!sittingPlayers.containsKey(playerId)) {
|
|
||||||
|
// Wenn der Spieler sitzt
|
||||||
|
if (sittingPlayers.containsKey(playerId)) {
|
||||||
|
|
||||||
|
// FIX: Cooldown prüfen (Verhindert "Auto-Standup" durch Lag beim Hinsetzen)
|
||||||
|
Long cooldown = sitCooldown.get(playerId);
|
||||||
|
if (cooldown != null && cooldown > System.currentTimeMillis()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe, ob der Spieler sich wirklich bewegt hat (Distanz > 0.05)
|
|
||||||
// Das verhindert, dass minimale "Wackler" durch Lag den Spieler abwerfen
|
|
||||||
Location from = event.getFrom();
|
Location from = event.getFrom();
|
||||||
Location to = event.getTo();
|
Location to = event.getTo();
|
||||||
if (to == null) return;
|
if (to == null) return;
|
||||||
|
|
||||||
if (from.distanceSquared(to) > 0.0025) { // ca 0.05 Blöcke Abstand
|
// Prüfe signifikante Bewegung
|
||||||
|
if (from.distanceSquared(to) > 0.0025) {
|
||||||
standUp(player);
|
standUp(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
// Wenn teleportiert, absteigen
|
|
||||||
if (sittingPlayers.containsKey(event.getPlayer().getUniqueId())) {
|
if (sittingPlayers.containsKey(event.getPlayer().getUniqueId())) {
|
||||||
standUp(event.getPlayer());
|
standUp(event.getPlayer());
|
||||||
}
|
}
|
||||||
@@ -164,11 +185,6 @@ public class SitListener implements Listener {
|
|||||||
return material.name().endsWith("_STAIRS");
|
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entfernt verbliebene ArmorStands von vorherigen Läufen (z.B. nach /reload)
|
|
||||||
private void cleanUpGhostStands() {
|
private void cleanUpGhostStands() {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
for (World world : Bukkit.getWorlds()) {
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Version (Nicht Ändern!)
|
# Version (Nicht Ändern!)
|
||||||
version: 1.0.9
|
version: 1.1.0
|
||||||
|
|
||||||
# Debug-Option
|
# Debug-Option
|
||||||
debug-logging: false
|
debug-logging: false
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ friend:
|
|||||||
notify: "&c%s hat deine Freundschaftsanfrage abgelehnt."
|
notify: "&c%s hat deine Freundschaftsanfrage abgelehnt."
|
||||||
|
|
||||||
list:
|
list:
|
||||||
header: "&6=== Deine Freundesliste ==="
|
header: "&6== Deine Freundesliste =="
|
||||||
entry: "&e%s: %s"
|
entry: "&e%s: %s"
|
||||||
entry-offline: "&e%s: %s &7(Zuletzt online: %s)"
|
entry-offline: "&e%s: %s &7(Zuletzt online: %s)"
|
||||||
online: "&aOnline"
|
online: "&aOnline"
|
||||||
@@ -168,7 +168,7 @@ friend:
|
|||||||
unknown: "&7Unbekannt"
|
unknown: "&7Unbekannt"
|
||||||
date-format: "dd.MM.yyyy HH:mm:ss"
|
date-format: "dd.MM.yyyy HH:mm:ss"
|
||||||
remove-button: "&c[X]"
|
remove-button: "&c[X]"
|
||||||
footer: "&6====================="
|
footer: "&6======================="
|
||||||
|
|
||||||
del:
|
del:
|
||||||
success: "&a%s wurde aus deiner Freundesliste entfernt."
|
success: "&a%s wurde aus deiner Freundesliste entfernt."
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
name: SurvivalPlus
|
name: SurvivalPlus
|
||||||
version: 1.1.0
|
version: 1.1.1
|
||||||
|
|
||||||
main: de.viper.survivalplus.SurvivalPlus
|
main: de.viper.survivalplus.SurvivalPlus
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
softdepend: [LuckPerms, PlaceholderAPI]
|
softdepend: [LuckPerms, PlaceholderAPI, ProtocolLib]
|
||||||
author: Viper
|
author: Viper
|
||||||
description: A plugin for enhancing survival gameplay in Minecraft.
|
description: A plugin for enhancing survival gameplay in Minecraft.
|
||||||
|
|
||||||
@@ -92,8 +92,7 @@ commands:
|
|||||||
friend:
|
friend:
|
||||||
description: Verwaltet die Freundesliste
|
description: Verwaltet die Freundesliste
|
||||||
usage: /<command> [add|accept|deny|list|del|tp] [Spielername]
|
usage: /<command> [add|accept|deny|list|del|tp] [Spielername]
|
||||||
permission: survivalplus.friend
|
# FIX: permission und permission-message entfernt um Warnung zu verhindern
|
||||||
permission-message: "§cDu hast keine Berechtigung für diesen Befehl."
|
|
||||||
stats:
|
stats:
|
||||||
description: Zeigt deine Statistiken an
|
description: Zeigt deine Statistiken an
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
@@ -184,6 +183,11 @@ commands:
|
|||||||
usage: /<command> <Name>
|
usage: /<command> <Name>
|
||||||
permission: survivalplus.nick
|
permission: survivalplus.nick
|
||||||
permission-message: "§cDu hast keine Berechtigung, deinen Nick zu ändern!"
|
permission-message: "§cDu hast keine Berechtigung, deinen Nick zu ändern!"
|
||||||
|
ride:
|
||||||
|
description: Reite einen Spieler
|
||||||
|
usage: /<command> [spieler]
|
||||||
|
permission: survivalplus.ride
|
||||||
|
permission-message: "§cDu hast keine Berechtigung, Spieler zu reiten!"
|
||||||
lootchests:
|
lootchests:
|
||||||
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
|
description: Zeigt eine Liste aller aktiven Loot-Kisten an. Admins können per Klick zu einer Kiste teleportieren.
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
@@ -320,6 +324,8 @@ permissions:
|
|||||||
survivalplus.blocklist: true
|
survivalplus.blocklist: true
|
||||||
survivalplus.kit: true
|
survivalplus.kit: true
|
||||||
survivalplus.nick: true
|
survivalplus.nick: true
|
||||||
|
survivalplus.ride: true
|
||||||
|
survivalplus.ride.exempt: true
|
||||||
survivalplus.lootchests: true
|
survivalplus.lootchests: true
|
||||||
survivalplus.day: true
|
survivalplus.day: true
|
||||||
survivalplus.night: true
|
survivalplus.night: true
|
||||||
@@ -475,6 +481,12 @@ permissions:
|
|||||||
survivalplus.nick:
|
survivalplus.nick:
|
||||||
description: Erlaubt das Ändern des eigenen Nicknamens (mit Farben & Hex)
|
description: Erlaubt das Ändern des eigenen Nicknamens (mit Farben & Hex)
|
||||||
default: op
|
default: op
|
||||||
|
survivalplus.ride:
|
||||||
|
description: Erlaubt das Reiten von Spielern
|
||||||
|
default: op
|
||||||
|
survivalplus.ride.exempt:
|
||||||
|
description: Spieler mit dieser Permission können nicht geritten werden
|
||||||
|
default: op
|
||||||
survivalplus.lootchests:
|
survivalplus.lootchests:
|
||||||
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
|
description: Erlaubt das Verwalten und Teleportieren zu Loot-Kisten
|
||||||
default: op
|
default: op
|
||||||
|
|||||||
Reference in New Issue
Block a user