package com.example.mcstats; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.*; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.configuration.file.FileConfiguration; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class PlayerStatistics extends JavaPlugin implements Listener { private Map playerStats; private FileConfiguration config; @Override public void onEnable() { playerStats = new ConcurrentHashMap<>(); saveDefaultConfig(); config = getConfig(); loadStats(); getServer().getPluginManager().registerEvents(this, this); // Register commands getCommand("stats").setExecutor((sender, command, label, args) -> { if (sender instanceof Player) { Player player = (Player) sender; showStats(player); } return true; }); // Auto-save task (every 5 minutes) getServer().getScheduler().runTaskTimerAsynchronously(this, this::saveStats, 6000L, 6000L); } @Override public void onDisable() { saveStats(); } private void loadStats() { if (config.contains("players")) { for (String uuid : config.getConfigurationSection("players").getKeys(false)) { UUID playerUUID = UUID.fromString(uuid); PlayerStatistics stats = new PlayerStatistics(); String path = "players." + uuid + "."; stats.blocksMined = config.getInt(path + "blocksMined"); stats.blocksPlaced = config.getInt(path + "blocksPlaced"); stats.mobKills = config.getInt(path + "mobKills"); stats.deaths = config.getInt(path + "deaths"); stats.distanceTraveled = config.getDouble(path + "distanceTraveled"); stats.itemsCrafted = config.getInt(path + "itemsCrafted"); stats.foodConsumed = config.getInt(path + "foodConsumed"); playerStats.put(playerUUID, stats); } } } private void saveStats() { for (Map.Entry entry : playerStats.entrySet()) { String path = "players." + entry.getKey().toString() + "."; PlayerStatistics stats = entry.getValue(); config.set(path + "blocksMined", stats.blocksMined); config.set(path + "blocksPlaced", stats.blocksPlaced); config.set(path + "mobKills", stats.mobKills); config.set(path + "deaths", stats.deaths); config.set(path + "distanceTraveled", stats.distanceTraveled); config.set(path + "itemsCrafted", stats.itemsCrafted); config.set(path + "foodConsumed", stats.foodConsumed); } saveConfig(); } private void showStats(Player player) { PlayerStatistics stats = playerStats.computeIfAbsent(player.getUniqueId(), k -> new PlayerStatistics()); player.sendMessage("§6=== Your Statistics ==="); player.sendMessage("§7Blocks Mined: §f" + stats.blocksMined); player.sendMessage("§7Blocks Placed: §f" + stats.blocksPlaced); player.sendMessage("§7Mob Kills: §f" + stats.mobKills); player.sendMessage("§7Deaths: §f" + stats.deaths); player.sendMessage("§7Distance Traveled: §f" + String.format("%.2f", stats.distanceTraveled) + " blocks"); player.sendMessage("§7Items Crafted: §f" + stats.itemsCrafted); player.sendMessage("§7Food Consumed: §f" + stats.foodConsumed); } // Event Handlers @EventHandler public void onBlockBreak(BlockBreakEvent event) { PlayerStatistics stats = playerStats.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new PlayerStatistics()); stats.blocksMined++; } @EventHandler public void onBlockPlace(BlockPlaceEvent event) { PlayerStatistics stats = playerStats.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new PlayerStatistics()); stats.blocksPlaced++; } @EventHandler public void onEntityDeath(EntityDeathEvent event) { if (event.getEntity().getKiller() instanceof Player) { Player player = event.getEntity().getKiller(); PlayerStatistics stats = playerStats.computeIfAbsent(player.getUniqueId(), k -> new PlayerStatistics()); stats.mobKills++; } } @EventHandler public void onPlayerDeath(PlayerDeathEvent event) { PlayerStatistics stats = playerStats.computeIfAbsent(event.getEntity().getUniqueId(), k -> new PlayerStatistics()); stats.deaths++; } @EventHandler public void onPlayerMove(PlayerMoveEvent event) { if (event.getFrom().distance(event.getTo()) > 0) { PlayerStatistics stats = playerStats.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new PlayerStatistics()); stats.distanceTraveled += event.getFrom().distance(event.getTo()); } } @EventHandler public void onItemConsume(PlayerItemConsumeEvent event) { if (event.getItem().getType().isEdible()) { PlayerStatistics stats = playerStats.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new PlayerStatistics()); stats.foodConsumed++; } } private static class PlayerStatistics { int blocksMined = 0; int blocksPlaced = 0; int mobKills = 0; int deaths = 0; double distanceTraveled = 0.0; int itemsCrafted = 0; int foodConsumed = 0; } }