Dateien nach "src/main/java" hochladen
This commit is contained in:
737
src/main/java/PlayerStatusSign.java
Normal file
737
src/main/java/PlayerStatusSign.java
Normal file
@@ -0,0 +1,737 @@
|
|||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Statistic;
|
||||||
|
import org.bukkit.block.Sign;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.SignChangeEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PlayerStatusSign extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
|
private File signsFile;
|
||||||
|
private FileConfiguration signsConfig;
|
||||||
|
private File playersFile;
|
||||||
|
private FileConfiguration playersConfig;
|
||||||
|
private File configFile;
|
||||||
|
private FileConfiguration config;
|
||||||
|
|
||||||
|
private Map<Location, String> signLocations; // Schildposition -> Spielername
|
||||||
|
private Map<UUID, Long> lastPlayerMovement; // Spieler UUID -> Zeitpunkt
|
||||||
|
private Map<UUID, Boolean> afkPlayers; // Spieler UUID -> AFK-Status
|
||||||
|
private Map<UUID, Boolean> fakeOfflinePlayers; // Spieler UUID -> Fake-Offline-Status
|
||||||
|
private Map<UUID, GameMode> originalGameModes; // Spieler UUID -> Ursprünglicher Gamemode
|
||||||
|
|
||||||
|
private String prefix;
|
||||||
|
private String onlineColor;
|
||||||
|
private String afkColor;
|
||||||
|
private String offlineColor;
|
||||||
|
private String playerColor;
|
||||||
|
private String dateFormat;
|
||||||
|
private long afkTimeout;
|
||||||
|
private boolean afkChangeGamemode;
|
||||||
|
|
||||||
|
private static final String CONFIG_VERSION = "1.0.6";
|
||||||
|
private static final String PLUGIN_AUTHOR = "M_Viper";
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Lifecycle
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
try {
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
|
signLocations = new HashMap<>();
|
||||||
|
lastPlayerMovement = new HashMap<>();
|
||||||
|
afkPlayers = new HashMap<>();
|
||||||
|
fakeOfflinePlayers = new HashMap<>();
|
||||||
|
originalGameModes = new HashMap<>();
|
||||||
|
|
||||||
|
loadConfig();
|
||||||
|
loadSigns();
|
||||||
|
loadPlayers();
|
||||||
|
startSignUpdater();
|
||||||
|
|
||||||
|
// Konsolenmeldung beim Plugin-Start
|
||||||
|
getLogger().info("[>] ========================================== [<]");
|
||||||
|
getLogger().info(" PlayerStatusSign - " + getDescription().getVersion() + " (cfg " + CONFIG_VERSION + ")");
|
||||||
|
getLogger().info(" Ersteller: " + PLUGIN_AUTHOR);
|
||||||
|
getLogger().info("[>] ========================================== [<]");
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().severe("Fehler beim Laden des Plugins: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
// Setze alle AFK- und Fake-Offline-Spieler zurück
|
||||||
|
for (UUID uuid : new HashSet<>(afkPlayers.keySet())) {
|
||||||
|
Player player = getServer().getPlayer(uuid);
|
||||||
|
if (player != null && afkPlayers.getOrDefault(uuid, false)) {
|
||||||
|
setPlayerAfk(player, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (UUID uuid : new HashSet<>(fakeOfflinePlayers.keySet())) {
|
||||||
|
Player player = getServer().getPlayer(uuid);
|
||||||
|
if (player != null && fakeOfflinePlayers.getOrDefault(uuid, false)) {
|
||||||
|
setPlayerFakeOffline(player, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSigns();
|
||||||
|
savePlayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Config / Storage
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
private void loadConfig() {
|
||||||
|
configFile = new File(getDataFolder(), "config.yml");
|
||||||
|
try {
|
||||||
|
if (!getDataFolder().exists() && !getDataFolder().mkdirs()) {
|
||||||
|
getLogger().severe("Konnte Plugin-Verzeichnis nicht erstellen!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
saveResource("config.yml", false);
|
||||||
|
getLogger().info("config.yml wurde erstellt.");
|
||||||
|
}
|
||||||
|
config = YamlConfiguration.loadConfiguration(configFile);
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
prefix = config.getString("prefix", "Status");
|
||||||
|
onlineColor = config.getString("colors.online", "&a");
|
||||||
|
afkColor = config.getString("colors.afk", "&e");
|
||||||
|
offlineColor = config.getString("colors.offline", "&c");
|
||||||
|
playerColor = config.getString("colors.player", "&9");
|
||||||
|
dateFormat = config.getString("date-format", "dd.MM.yyyy HH:mm");
|
||||||
|
afkTimeout = config.getLong("afk-timeout-seconds", 300) * 1000L;
|
||||||
|
afkChangeGamemode = config.getBoolean("afk-change-gamemode", true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().severe("Fehler beim Laden von config.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
config = new YamlConfiguration(); // Fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureSignsFile() throws IOException {
|
||||||
|
if (signsFile == null) {
|
||||||
|
signsFile = new File(getDataFolder(), "playerstatussign_signs.yml");
|
||||||
|
}
|
||||||
|
if (!signsFile.exists()) {
|
||||||
|
signsFile.createNewFile();
|
||||||
|
getLogger().info("playerstatussign_signs.yml erstellt.");
|
||||||
|
}
|
||||||
|
if (signsConfig == null) {
|
||||||
|
signsConfig = YamlConfiguration.loadConfiguration(signsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSigns() {
|
||||||
|
try {
|
||||||
|
ensureSignsFile();
|
||||||
|
signLocations.clear();
|
||||||
|
|
||||||
|
if (!signsConfig.contains("signs")) {
|
||||||
|
getLogger().info("Keine Schilder gefunden.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : signsConfig.getConfigurationSection("signs").getKeys(false)) {
|
||||||
|
String world = signsConfig.getString("signs." + key + ".world");
|
||||||
|
int x = signsConfig.getInt("signs." + key + ".x");
|
||||||
|
int y = signsConfig.getInt("signs." + key + ".y");
|
||||||
|
int z = signsConfig.getInt("signs." + key + ".z");
|
||||||
|
String playerName = signsConfig.getString("signs." + key + ".player");
|
||||||
|
|
||||||
|
if (world != null && playerName != null) {
|
||||||
|
Location loc = new Location(getServer().getWorld(world), x, y, z);
|
||||||
|
if (loc.getWorld() != null) {
|
||||||
|
signLocations.put(loc, playerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getLogger().info("playerstatussign_signs.yml geladen. (" + signLocations.size() + " Schilder)");
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Fehler beim Laden von playerstatussign_signs.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSigns() {
|
||||||
|
try {
|
||||||
|
ensureSignsFile();
|
||||||
|
|
||||||
|
signsConfig.set("signs", null); // Reset
|
||||||
|
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
|
||||||
|
Location loc = entry.getKey();
|
||||||
|
String key = locationKey(loc);
|
||||||
|
|
||||||
|
signsConfig.set("signs." + key + ".world", loc.getWorld().getName());
|
||||||
|
signsConfig.set("signs." + key + ".x", loc.getBlockX());
|
||||||
|
signsConfig.set("signs." + key + ".y", loc.getBlockY());
|
||||||
|
signsConfig.set("signs." + key + ".z", loc.getBlockZ());
|
||||||
|
signsConfig.set("signs." + key + ".player", entry.getValue());
|
||||||
|
}
|
||||||
|
signsConfig.save(signsFile);
|
||||||
|
getLogger().info("playerstatussign_signs.yml erfolgreich gespeichert.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Fehler beim Speichern von playerstatussign_signs.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadPlayers() {
|
||||||
|
playersFile = new File(getDataFolder(), "playerstatussign_players.yml");
|
||||||
|
try {
|
||||||
|
if (!playersFile.exists()) {
|
||||||
|
playersFile.createNewFile();
|
||||||
|
getLogger().info("playerstatussign_players.yml erstellt.");
|
||||||
|
}
|
||||||
|
playersConfig = YamlConfiguration.loadConfiguration(playersFile);
|
||||||
|
getLogger().info("playerstatussign_players.yml geladen.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Fehler beim Erstellen oder Laden von playerstatussign_players.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePlayers() {
|
||||||
|
if (playersConfig == null || playersFile == null) {
|
||||||
|
getLogger().severe("Fehler: playersConfig oder playersFile ist null!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
playersConfig.save(playersFile);
|
||||||
|
getLogger().info("playerstatussign_players.yml erfolgreich gespeichert.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Fehler beim Speichern von playerstatussign_players.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Utils
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
private String getMessage(String key) {
|
||||||
|
if (config == null) {
|
||||||
|
getLogger().warning("Konfigurationsdatei nicht geladen! Schlüssel: " + key);
|
||||||
|
return ChatColor.RED + "Fehler: Nachricht nicht gefunden (" + key + ")";
|
||||||
|
}
|
||||||
|
String message = config.getString("messages." + key, "Message not found: " + key);
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String locationKey(Location loc) {
|
||||||
|
return loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Scheduler
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
private void startSignUpdater() {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Prüfe Inaktivität für alle Spieler
|
||||||
|
for (Player player : getServer().getOnlinePlayers()) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (!afkPlayers.getOrDefault(uuid, false) && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
|
||||||
|
Long lastMove = lastPlayerMovement.get(uuid);
|
||||||
|
if (lastMove != null && System.currentTimeMillis() - lastMove > afkTimeout) {
|
||||||
|
setPlayerAfk(player, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualisiere Schilder
|
||||||
|
List<Location> toRemove = new ArrayList<>();
|
||||||
|
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
|
||||||
|
Location loc = entry.getKey();
|
||||||
|
String playerName = entry.getValue();
|
||||||
|
try {
|
||||||
|
if (loc.getBlock().getState() instanceof Sign) {
|
||||||
|
Sign sign = (Sign) loc.getBlock().getState();
|
||||||
|
updateSign(sign, playerName);
|
||||||
|
} else {
|
||||||
|
toRemove.add(loc);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Aktualisieren des Schildes bei " + loc + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!toRemove.isEmpty()) {
|
||||||
|
for (Location loc : toRemove) {
|
||||||
|
signLocations.remove(loc);
|
||||||
|
String key = locationKey(loc);
|
||||||
|
signsConfig.set("signs." + key, null);
|
||||||
|
}
|
||||||
|
saveSigns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(this, 0L, 100L); // alle 5 Sekunden
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Core
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
private void updateSign(Sign sign, String playerName) {
|
||||||
|
Player player = getServer().getPlayerExact(playerName);
|
||||||
|
String line1, line2, line3, line4;
|
||||||
|
|
||||||
|
line2 = ChatColor.translateAlternateColorCodes('&', playerColor + playerName); // Spielername
|
||||||
|
|
||||||
|
if (player != null && player.isOnline() && !fakeOfflinePlayers.getOrDefault(player.getUniqueId(), false)) {
|
||||||
|
if (isAfk(player)) {
|
||||||
|
// AFK
|
||||||
|
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + afkColor + "^&r-x");
|
||||||
|
line3 = ChatColor.translateAlternateColorCodes('&', afkColor + "AFK");
|
||||||
|
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + afkColor + "v&r-x");
|
||||||
|
} else {
|
||||||
|
// Online
|
||||||
|
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + onlineColor + "^&r-x");
|
||||||
|
line3 = ChatColor.translateAlternateColorCodes('&', onlineColor + "Online");
|
||||||
|
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + onlineColor + "v&r-x");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Offline (oder Fake-Offline)
|
||||||
|
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + offlineColor + "^&r-x");
|
||||||
|
long lastLogin = playersConfig.getLong("players." + playerName + ".last-login", -1);
|
||||||
|
String dateStr = lastLogin != -1 ? new SimpleDateFormat(dateFormat).format(new Date(lastLogin)) : "Unbekannt";
|
||||||
|
line3 = ChatColor.translateAlternateColorCodes('&', offlineColor + dateStr);
|
||||||
|
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + offlineColor + "v&r-x");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sign.setLine(0, line1);
|
||||||
|
sign.setLine(1, line2);
|
||||||
|
sign.setLine(2, line3);
|
||||||
|
sign.setLine(3, line4);
|
||||||
|
sign.update();
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Aktualisieren des Schildes für " + playerName + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAfk(Player player) {
|
||||||
|
return afkPlayers.getOrDefault(player.getUniqueId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPlayerAfk(Player player, boolean afk) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
try {
|
||||||
|
if (afk && !afkPlayers.getOrDefault(uuid, false)) {
|
||||||
|
afkPlayers.put(uuid, true);
|
||||||
|
if (afkChangeGamemode) {
|
||||||
|
originalGameModes.put(uuid, player.getGameMode());
|
||||||
|
player.setGameMode(GameMode.ADVENTURE);
|
||||||
|
}
|
||||||
|
player.sendMessage(getMessage("afk-enabled"));
|
||||||
|
updateSignsForPlayer(player.getName());
|
||||||
|
} else if (!afk && afkPlayers.getOrDefault(uuid, false)) {
|
||||||
|
afkPlayers.put(uuid, false);
|
||||||
|
if (afkChangeGamemode) {
|
||||||
|
GameMode originalMode = originalGameModes.getOrDefault(uuid, GameMode.SURVIVAL);
|
||||||
|
player.setGameMode(originalMode);
|
||||||
|
originalGameModes.remove(uuid);
|
||||||
|
}
|
||||||
|
player.sendMessage(getMessage("afk-disabled"));
|
||||||
|
updateSignsForPlayer(player.getName());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Setzen des AFK-Status für " + player.getName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPlayerFakeOffline(Player player, boolean fakeOffline) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
String playerName = player.getName();
|
||||||
|
try {
|
||||||
|
if (fakeOffline && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
|
||||||
|
// Spieler wird Fake-Offline
|
||||||
|
fakeOfflinePlayers.put(uuid, true);
|
||||||
|
|
||||||
|
// Timestamp direkt speichern
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
playersConfig.set("players." + playerName + ".last-login", now);
|
||||||
|
savePlayers();
|
||||||
|
|
||||||
|
player.sendMessage(getMessage("status-offline-enabled"));
|
||||||
|
updateSignsForPlayer(playerName);
|
||||||
|
} else if (!fakeOffline && fakeOfflinePlayers.getOrDefault(uuid, false)) {
|
||||||
|
// Spieler wieder sichtbar
|
||||||
|
fakeOfflinePlayers.put(uuid, false);
|
||||||
|
player.sendMessage(getMessage("status-offline-disabled"));
|
||||||
|
updateSignsForPlayer(playerName);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Setzen des Fake-Offline-Status für " + playerName + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSignsForPlayer(String playerName) {
|
||||||
|
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
|
||||||
|
if (entry.getValue().equalsIgnoreCase(playerName)) {
|
||||||
|
Location loc = entry.getKey();
|
||||||
|
try {
|
||||||
|
if (loc.getBlock().getState() instanceof Sign) {
|
||||||
|
Sign sign = (Sign) loc.getBlock().getState();
|
||||||
|
updateSign(sign, playerName);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Aktualisieren des Schildes für " + playerName + " bei " + loc + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// GUI
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
private void openStatsGUI(Player viewer, String targetPlayerName) {
|
||||||
|
try {
|
||||||
|
Player target = getServer().getPlayerExact(targetPlayerName);
|
||||||
|
Inventory gui = getServer().createInventory(null, 9, ChatColor.translateAlternateColorCodes('&', "&6Statistiken von " + targetPlayerName));
|
||||||
|
|
||||||
|
long playTimeTicks = 0;
|
||||||
|
int deaths = 0;
|
||||||
|
int playerKills = 0;
|
||||||
|
int blocksMined = 0;
|
||||||
|
double distanceWalkedCm = 0;
|
||||||
|
|
||||||
|
if (target != null && target.isOnline()) {
|
||||||
|
playTimeTicks = target.getStatistic(Statistic.PLAY_ONE_MINUTE);
|
||||||
|
deaths = target.getStatistic(Statistic.DEATHS);
|
||||||
|
playerKills = target.getStatistic(Statistic.PLAYER_KILLS);
|
||||||
|
for (Material material : Material.values()) {
|
||||||
|
if (material.isBlock()) {
|
||||||
|
try {
|
||||||
|
blocksMined += target.getStatistic(Statistic.MINE_BLOCK, material);
|
||||||
|
} catch (IllegalArgumentException ignored) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distanceWalkedCm = target.getStatistic(Statistic.WALK_ONE_CM);
|
||||||
|
} else {
|
||||||
|
playTimeTicks = playersConfig.getLong ("players." + targetPlayerName + ".stats.play-time", 0);
|
||||||
|
deaths = playersConfig.getInt ("players." + targetPlayerName + ".stats.deaths", 0);
|
||||||
|
playerKills = playersConfig.getInt ("players." + targetPlayerName + ".stats.player-kills", 0);
|
||||||
|
blocksMined = playersConfig.getInt ("players." + targetPlayerName + ".stats.blocks-mined", 0);
|
||||||
|
distanceWalkedCm = playersConfig.getDouble("players." + targetPlayerName + ".stats.distance-walked", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double playTimeHours = playTimeTicks / 72000.0; // 20 Ticks * 3600 Sekunden
|
||||||
|
double distanceWalkedKm = distanceWalkedCm / 100000.0;
|
||||||
|
|
||||||
|
ItemStack playTimeItem = new ItemStack(Material.CLOCK);
|
||||||
|
ItemMeta playTimeMeta = playTimeItem.getItemMeta();
|
||||||
|
if (playTimeMeta != null) {
|
||||||
|
playTimeMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&eSpielzeit"));
|
||||||
|
playTimeMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + String.format("%.2f", playTimeHours) + " Stunden")));
|
||||||
|
playTimeItem.setItemMeta(playTimeMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(0, playTimeItem);
|
||||||
|
|
||||||
|
ItemStack deathsItem = new ItemStack(Material.SKELETON_SKULL);
|
||||||
|
ItemMeta deathsMeta = deathsItem.getItemMeta();
|
||||||
|
if (deathsMeta != null) {
|
||||||
|
deathsMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&cTode"));
|
||||||
|
deathsMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + deaths + " Tode")));
|
||||||
|
deathsItem.setItemMeta(deathsMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(1, deathsItem);
|
||||||
|
|
||||||
|
ItemStack killsItem = new ItemStack(Material.DIAMOND_SWORD);
|
||||||
|
ItemMeta killsMeta = killsItem.getItemMeta();
|
||||||
|
if (killsMeta != null) {
|
||||||
|
killsMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&aSpieler-Kills"));
|
||||||
|
killsMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + playerKills + " Kills")));
|
||||||
|
killsItem.setItemMeta(killsMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(2, killsItem);
|
||||||
|
|
||||||
|
ItemStack blocksMinedItem = new ItemStack(Material.IRON_PICKAXE);
|
||||||
|
ItemMeta blocksMinedMeta = blocksMinedItem.getItemMeta();
|
||||||
|
if (blocksMinedMeta != null) {
|
||||||
|
blocksMinedMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&bAbgebaute Blöcke"));
|
||||||
|
blocksMinedMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + blocksMined + " Blöcke")));
|
||||||
|
blocksMinedItem.setItemMeta(blocksMinedMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(3, blocksMinedItem);
|
||||||
|
|
||||||
|
ItemStack distanceItem = new ItemStack(Material.COMPASS);
|
||||||
|
ItemMeta distanceMeta = distanceItem.getItemMeta();
|
||||||
|
if (distanceMeta != null) {
|
||||||
|
distanceMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&9Gelaufene Distanz"));
|
||||||
|
distanceMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + String.format("%.2f", distanceWalkedKm) + " km")));
|
||||||
|
distanceItem.setItemMeta(distanceMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(4, distanceItem);
|
||||||
|
|
||||||
|
viewer.openInventory(gui);
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Öffnen der Statistik-GUI für " + targetPlayerName + ": " + e.getMessage());
|
||||||
|
viewer.sendMessage(getMessage("gui-error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Commands
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
sender.sendMessage(getMessage("player-only"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
if (config == null) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Fehler: Plugin-Konfiguration nicht geladen!");
|
||||||
|
getLogger().severe("Konfigurationsdatei nicht verfügbar bei Befehlsausführung!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command.getName().toLowerCase()) {
|
||||||
|
case "statussign":
|
||||||
|
if (args.length == 0) {
|
||||||
|
player.sendMessage(getMessage("help-title"));
|
||||||
|
player.sendMessage(getMessage("help-reload"));
|
||||||
|
player.sendMessage(getMessage("help-help"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("reload")) {
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-admin"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
loadConfig();
|
||||||
|
loadSigns();
|
||||||
|
loadPlayers();
|
||||||
|
player.sendMessage(getMessage("reload-success"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("help")) {
|
||||||
|
player.sendMessage(getMessage("help-title"));
|
||||||
|
player.sendMessage(getMessage("help-reload"));
|
||||||
|
player.sendMessage(getMessage("help-help"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendMessage(getMessage("unknown-subcommand"));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "statusafk":
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-admin"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (fakeOfflinePlayers.getOrDefault(player.getUniqueId(), false)) {
|
||||||
|
player.sendMessage(getMessage("cannot-afk-while-offline"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setPlayerAfk(player, !isAfk(player));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "statusoffline":
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-admin"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isAfk(player)) {
|
||||||
|
setPlayerAfk(player, false);
|
||||||
|
}
|
||||||
|
setPlayerFakeOffline(player, true);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "statusonline":
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-admin"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setPlayerFakeOffline(player, false);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Events
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onSignChange(SignChangeEvent event) {
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-admin"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getLine(0).equalsIgnoreCase("[" + prefix + "]")) {
|
||||||
|
String playerName = event.getLine(1);
|
||||||
|
if (playerName == null || playerName.trim().isEmpty()) {
|
||||||
|
player.sendMessage(getMessage("invalid-player"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Location loc = event.getBlock().getLocation();
|
||||||
|
String key = locationKey(loc);
|
||||||
|
|
||||||
|
signLocations.put(loc, playerName);
|
||||||
|
|
||||||
|
ensureSignsFile();
|
||||||
|
signsConfig.set("signs." + key + ".world", loc.getWorld().getName());
|
||||||
|
signsConfig.set("signs." + key + ".x", loc.getBlockX());
|
||||||
|
signsConfig.set("signs." + key + ".y", loc.getBlockY());
|
||||||
|
signsConfig.set("signs." + key + ".z", loc.getBlockZ());
|
||||||
|
signsConfig.set("signs." + key + ".player", playerName);
|
||||||
|
signsConfig.save(signsFile);
|
||||||
|
|
||||||
|
// Sofortige Status-Anzeige
|
||||||
|
Sign sign = (Sign) event.getBlock().getState();
|
||||||
|
updateSign(sign, playerName);
|
||||||
|
player.sendMessage(getMessage("sign-created").replace("%player%", playerName));
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Erstellen des Schildes für " + playerName + ": " + e.getMessage());
|
||||||
|
player.sendMessage(getMessage("sign-error"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
||||||
|
if (event.getClickedBlock() == null || !(event.getClickedBlock().getState() instanceof Sign)) return;
|
||||||
|
|
||||||
|
Sign sign = (Sign) event.getClickedBlock().getState();
|
||||||
|
Location loc = sign.getLocation();
|
||||||
|
if (!signLocations.containsKey(loc)) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (!player.hasPermission("statussign.use")) {
|
||||||
|
player.sendMessage(getMessage("no-permission-use"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetPlayer = signLocations.get(loc);
|
||||||
|
openStatsGUI(player, targetPlayer);
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
if (!(event.getBlock().getState() instanceof Sign)) return;
|
||||||
|
|
||||||
|
Location loc = event.getBlock().getLocation();
|
||||||
|
if (!signLocations.containsKey(loc)) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (!player.hasPermission("statussign.admin")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage(getMessage("no-permission-break-sign"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!player.isSneaking()) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.sendMessage(getMessage("break-sign-sneak"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String playerName = signLocations.get(loc);
|
||||||
|
signLocations.remove(loc);
|
||||||
|
|
||||||
|
String key = locationKey(loc);
|
||||||
|
ensureSignsFile();
|
||||||
|
signsConfig.set("signs." + key, null);
|
||||||
|
signsConfig.save(signsFile);
|
||||||
|
|
||||||
|
player.sendMessage(getMessage("sign-removed").replace("%player%", playerName));
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Entfernen des Schildes bei " + loc + ": " + e.getMessage());
|
||||||
|
player.sendMessage(getMessage("sign-error"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
lastPlayerMovement.put(uuid, System.currentTimeMillis());
|
||||||
|
if (isAfk(player) && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
|
||||||
|
setPlayerAfk(player, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
String playerName = player.getName();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Speichere Statistiken
|
||||||
|
playersConfig.set("players." + playerName + ".last-login", System.currentTimeMillis());
|
||||||
|
playersConfig.set("players." + playerName + ".stats.play-time", player.getStatistic(Statistic.PLAY_ONE_MINUTE));
|
||||||
|
playersConfig.set("players." + playerName + ".stats.deaths", player.getStatistic(Statistic.DEATHS));
|
||||||
|
playersConfig.set("players." + playerName + ".stats.player-kills", player.getStatistic(Statistic.PLAYER_KILLS));
|
||||||
|
|
||||||
|
int blocksMined = 0;
|
||||||
|
for (Material material : Material.values()) {
|
||||||
|
if (material.isBlock()) {
|
||||||
|
try {
|
||||||
|
blocksMined += player.getStatistic(Statistic.MINE_BLOCK, material);
|
||||||
|
} catch (IllegalArgumentException ignored) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playersConfig.set("players." + playerName + ".stats.blocks-mined", blocksMined);
|
||||||
|
playersConfig.set("players." + playerName + ".stats.distance-walked", player.getStatistic(Statistic.WALK_ONE_CM));
|
||||||
|
savePlayers();
|
||||||
|
|
||||||
|
afkPlayers.remove(uuid);
|
||||||
|
fakeOfflinePlayers.remove(uuid);
|
||||||
|
originalGameModes.remove(uuid);
|
||||||
|
lastPlayerMovement.remove(uuid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("Fehler beim Speichern der Daten für " + playerName + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user