package me.viper.survivalmechanics; import me.viper.survivalmechanics.mechanics.*; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.event.player.PlayerBedLeaveEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.ChatColor; import org.bukkit.scoreboard.*; import java.io.File; import java.io.IOException; import java.util.UUID; import java.util.HashMap; import java.util.Map; public class SurvivalMechanics extends JavaPlugin implements Listener { private HungerManager hungerManager; private ThirstManager thirstManager; private FatigueManager fatigueManager; private TemperatureManager temperatureManager; private StaminaManager staminaManager; private VulnerabilityManager vulnerabilityManager; private HygieneManager hygieneManager; private FileConfiguration langConfig; private FileConfiguration playerDataConfig; private File playerDataFile; // Better message cooldown management - store in memory instead of config file private final Map lastMessageTimes = new HashMap<>(); @Override public void onEnable() { // Load configurations saveDefaultConfig(); saveResource("lang.yml", false); saveResource("playerdata.yml", false); loadLangConfig(); loadPlayerDataConfig(); // Initialize managers hungerManager = new HungerManager(this); thirstManager = new ThirstManager(this); fatigueManager = new FatigueManager(this); temperatureManager = new TemperatureManager(this); staminaManager = new StaminaManager(this); vulnerabilityManager = new VulnerabilityManager(this); hygieneManager = new HygieneManager(this); // Start all tasks hungerManager.startHungerTask(); thirstManager.startThirstTask(); fatigueManager.startFatigueTask(); temperatureManager.startTemperatureTask(); staminaManager.startStaminaTask(); vulnerabilityManager.startVulnerabilityTask(); hygieneManager.startHygieneTask(); // Start scoreboard display startScoreboardDisplay(); // Register events getServer().getPluginManager().registerEvents(this, this); getLogger().info("SurvivalMechanics Plugin aktiviert!"); } @Override public void onDisable() { // Save all player data before shutdown for (Player player : getServer().getOnlinePlayers()) { savePlayerData(player.getUniqueId()); } savePlayerDataConfig(); getLogger().info("SurvivalMechanics Plugin deaktiviert!"); } private void loadLangConfig() { File langFile = new File(getDataFolder(), "lang.yml"); if (!langFile.exists()) { saveResource("lang.yml", false); } langConfig = YamlConfiguration.loadConfiguration(langFile); } private void loadPlayerDataConfig() { playerDataFile = new File(getDataFolder(), "playerdata.yml"); if (!playerDataFile.exists()) { saveResource("playerdata.yml", false); } playerDataConfig = YamlConfiguration.loadConfiguration(playerDataFile); } private void savePlayerDataConfig() { try { playerDataConfig.save(playerDataFile); } catch (IOException e) { getLogger().severe("Fehler beim Speichern von playerdata.yml: " + e.getMessage()); } } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); UUID playerId = player.getUniqueId(); String path = "players." + playerId + "."; // Load player data or use defaults if (playerDataConfig.contains(path)) { hungerManager.loadHunger(playerId, playerDataConfig.getInt(path + "hunger", getConfig().getInt("hunger.initial", 80))); thirstManager.loadThirst(playerId, playerDataConfig.getInt(path + "thirst", getConfig().getInt("thirst.initial", 80))); fatigueManager.loadFatigue(playerId, playerDataConfig.getInt(path + "fatigue", getConfig().getInt("fatigue.initial", 100))); temperatureManager.loadTemperature(playerId, playerDataConfig.getInt(path + "temperature", getConfig().getInt("temperature.initial", 50))); staminaManager.loadStamina(playerId, playerDataConfig.getInt(path + "stamina", getConfig().getInt("stamina.initial", 80))); vulnerabilityManager.loadVulnerability(playerId, playerDataConfig.getInt(path + "vulnerability", getConfig().getInt("vulnerability.initial", 0))); hygieneManager.loadHygiene(playerId, playerDataConfig.getInt(path + "hygiene", getConfig().getInt("hygiene.initial", 80))); } else { // First time join - use initial values hungerManager.loadHunger(playerId, getConfig().getInt("hunger.initial", 80)); thirstManager.loadThirst(playerId, getConfig().getInt("thirst.initial", 80)); fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.initial", 100)); temperatureManager.loadTemperature(playerId, getConfig().getInt("temperature.initial", 50)); staminaManager.loadStamina(playerId, getConfig().getInt("stamina.initial", 80)); vulnerabilityManager.loadVulnerability(playerId, getConfig().getInt("vulnerability.initial", 0)); hygieneManager.loadHygiene(playerId, getConfig().getInt("hygiene.initial", 80)); } setupPlayerScoreboard(player); } @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); UUID playerId = player.getUniqueId(); // Save player data savePlayerData(playerId); // Reset scoreboard player.setScoreboard(getServer().getScoreboardManager().getNewScoreboard()); } private void savePlayerData(UUID playerId) { String path = "players." + playerId + "."; playerDataConfig.set(path + "hunger", hungerManager.getHunger(playerId)); playerDataConfig.set(path + "thirst", thirstManager.getThirst(playerId)); playerDataConfig.set(path + "fatigue", fatigueManager.getFatigue(playerId)); playerDataConfig.set(path + "temperature", temperatureManager.getTemperature(playerId)); playerDataConfig.set(path + "stamina", staminaManager.getStamina(playerId)); playerDataConfig.set(path + "vulnerability", vulnerabilityManager.getVulnerability(playerId)); playerDataConfig.set(path + "hygiene", hygieneManager.getHygiene(playerId)); savePlayerDataConfig(); } @EventHandler public void onPlayerBedEnter(PlayerBedEnterEvent event) { Player player = event.getPlayer(); UUID playerId = player.getUniqueId(); // Allow sleeping anytime event.setCancelled(false); // Restore fatigue and stamina fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.max", 100)); staminaManager.loadStamina(playerId, getConfig().getInt("stamina.max", 100)); // Reduce hunger and thirst int hunger = hungerManager.getHunger(playerId); int thirst = thirstManager.getThirst(playerId); int hungerReduction = getConfig().getInt("hunger.sleep-reduction", 50); int thirstReduction = getConfig().getInt("thirst.sleep-reduction", 50); hungerManager.loadHunger(playerId, Math.max(0, hunger - hungerReduction)); thirstManager.loadThirst(playerId, Math.max(0, thirst - thirstReduction)); // Send message if (canSendMessage(playerId, "fatigue")) { player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("fatigue.rested", "§aDu erwachst erfrischt und voller Energie!"))); player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); setLastMessageTime(playerId, "fatigue"); } } @EventHandler public void onPlayerBedLeave(PlayerBedLeaveEvent event) { Player player = event.getPlayer(); // Set time to morning player.getWorld().setTime(0); } @EventHandler public void onPlayerDeath(PlayerDeathEvent event) { Player player = event.getEntity(); UUID playerId = player.getUniqueId(); String deathCause = null; // Determine death cause based on survival mechanics if (hungerManager.getHunger(playerId) == 0 && getConfig().getBoolean("hunger.death-enabled", true)) { deathCause = langConfig.getString("hunger.death", "§4Du bist verhungert!"); } else if (thirstManager.getThirst(playerId) == 0 && getConfig().getBoolean("thirst.death-enabled", true)) { deathCause = langConfig.getString("thirst.death", "§4Du bist verdurstet!"); } else if (fatigueManager.getFatigue(playerId) == 0 && getConfig().getBoolean("fatigue.death-enabled", true)) { deathCause = langConfig.getString("fatigue.death", "§4Du bist vor Erschöpfung zusammengebrochen!"); } else if (getConfig().getBoolean("temperature.death-enabled", true)) { int temperature = temperatureManager.getTemperature(playerId); String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase(); boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15; // Death from cold (temperature at 0) if (temperature == 0) { deathCause = langConfig.getString(isRaining ? "temperature.death-rain" : "temperature.death-cold", "§4Du bist erfroren!"); } // Death from heat (temperature at max) else if (temperature >= getConfig().getInt("temperature.max", 100)) { deathCause = langConfig.getString("temperature.death-hot", "§4Die Hitze hat dich umgebracht!"); } } else if (hygieneManager.getHygiene(playerId) == 0 && getConfig().getBoolean("hygiene.death-enabled", true)) { deathCause = langConfig.getString("hygiene.death", "§4Eine Infektion hat dich dahingerafft!"); } // Set custom death message if death was caused by survival mechanics if (deathCause != null) { event.setDeathMessage(ChatColor.translateAlternateColorCodes('&', deathCause)); player.getWorld().playSound(player.getLocation(), "entity.player.death", 1.0f, 1.0f); } // Reset player stats on death (configurable) if (getConfig().getBoolean("reset-on-death", true)) { hungerManager.loadHunger(playerId, getConfig().getInt("hunger.initial", 80)); thirstManager.loadThirst(playerId, getConfig().getInt("thirst.initial", 80)); fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.initial", 100)); temperatureManager.loadTemperature(playerId, getConfig().getInt("temperature.initial", 50)); staminaManager.loadStamina(playerId, getConfig().getInt("stamina.initial", 80)); vulnerabilityManager.loadVulnerability(playerId, getConfig().getInt("vulnerability.initial", 0)); hygieneManager.loadHygiene(playerId, getConfig().getInt("hygiene.initial", 80)); } } private void startScoreboardDisplay() { new BukkitRunnable() { @Override public void run() { for (Player player : getServer().getOnlinePlayers()) { updatePlayerScoreboard(player); } } }.runTaskTimer(this, 0L, getConfig().getLong("display.update-interval", 100)); // Default: every 5 seconds } private void setupPlayerScoreboard(Player player) { ScoreboardManager manager = getServer().getScoreboardManager(); Scoreboard scoreboard = manager.getNewScoreboard(); Objective objective = scoreboard.registerNewObjective("survival", "dummy", ChatColor.translateAlternateColorCodes('&', langConfig.getString("scoreboard.title", "&6Survival"))); objective.setDisplaySlot(DisplaySlot.SIDEBAR); player.setScoreboard(scoreboard); } private void updatePlayerScoreboard(Player player) { UUID playerId = player.getUniqueId(); Scoreboard scoreboard = player.getScoreboard(); Objective objective = scoreboard.getObjective("survival"); if (objective == null) { setupPlayerScoreboard(player); scoreboard = player.getScoreboard(); objective = scoreboard.getObjective("survival"); } // Reset previous scores for (String entry : scoreboard.getEntries()) { scoreboard.resetScores(entry); } // Get player stats int hunger = hungerManager.getHunger(playerId); int thirst = thirstManager.getThirst(playerId); int fatigue = fatigueManager.getFatigue(playerId); int temperature = temperatureManager.getTemperature(playerId); int stamina = staminaManager.getStamina(playerId); int vulnerability = vulnerabilityManager.getVulnerability(playerId); int hygiene = hygieneManager.getHygiene(playerId); // Get display configuration int barLength = getConfig().getInt("display.bar-length", 5); String barFilled = getConfig().getString("display.bar-filled", "█"); String barEmpty = getConfig().getString("display.bar-empty", "▒"); String hungerColor = getConfig().getString("display.hunger-color", "§6"); String thirstColor = getConfig().getString("display.thirst-color", "§b"); String fatigueColor = getConfig().getString("display.fatigue-color", "§7"); String temperatureColor = getConfig().getString("display.temperature-color", "§c"); String staminaColor = getConfig().getString("display.stamina-color", "§a"); String vulnerabilityColor = getConfig().getString("display.vulnerability-color", "§4"); String hygieneColor = getConfig().getString("display.hygiene-color", "§9"); int mildThreshold = getConfig().getInt("display.mild-threshold", 60); int criticalThreshold = getConfig().getInt("vulnerability.critical-threshold", 80); // Get status for each mechanic String hungerStatus = getStatus("hunger", hunger, mildThreshold, getConfig().getInt("hunger.critical-threshold", 20)); String thirstStatus = getStatus("thirst", thirst, mildThreshold, getConfig().getInt("thirst.critical-threshold", 20)); String fatigueStatus = getStatus("fatigue", fatigue, mildThreshold, getConfig().getInt("fatigue.critical-threshold", 20)); String temperatureStatus = getTemperatureStatus(temperature, mildThreshold, getConfig().getInt("temperature.critical-threshold", 20)); String staminaStatus = getStatus("stamina", stamina, mildThreshold, getConfig().getInt("stamina.critical-threshold", 20)); String vulnerabilityStatus = getVulnerabilityStatus(vulnerability, mildThreshold, criticalThreshold); String hygieneStatus = getStatus("hygiene", hygiene, mildThreshold, getConfig().getInt("hygiene.critical-threshold", 20)); // Build scoreboard entries String[] entries = new String[] { "§r", // Empty line hungerColor + langConfig.getString("scoreboard.hunger", "HP") + ": " + getProgressBar(hunger, 100, barLength, barFilled, barEmpty) + " " + hungerStatus, thirstColor + langConfig.getString("scoreboard.thirst", "TH") + ": " + getProgressBar(thirst, 100, barLength, barFilled, barEmpty) + " " + thirstStatus, "§r ", // Empty line (with space to make unique) fatigueColor + langConfig.getString("scoreboard.fatigue", "FT") + ": " + getProgressBar(fatigue, 100, barLength, barFilled, barEmpty) + " " + fatigueStatus, temperatureColor + langConfig.getString("scoreboard.temperature", "TP") + ": " + getProgressBar(temperature, 100, barLength, barFilled, barEmpty) + " " + temperatureStatus, "§r ", // Empty line (with 2 spaces to make unique) staminaColor + langConfig.getString("scoreboard.stamina", "ST") + ": " + getProgressBar(stamina, 100, barLength, barFilled, barEmpty) + " " + staminaStatus, vulnerabilityColor + langConfig.getString("scoreboard.vulnerability", "VL") + ": " + getProgressBar(vulnerability, 100, barLength, barFilled, barEmpty) + " " + vulnerabilityStatus, hygieneColor + langConfig.getString("scoreboard.hygiene", "HY") + ": " + getProgressBar(hygiene, 100, barLength, barFilled, barEmpty) + " " + hygieneStatus }; // Set scores (higher scores appear at top) for (int i = 0; i < entries.length; i++) { String entry = ChatColor.translateAlternateColorCodes('&', entries[i]); if (entry.length() > 40) { entry = entry.substring(0, 40); // Scoreboard lines are limited to 40 characters } Score score = objective.getScore(entry); score.setScore(entries.length - i); } } private String getProgressBar(int current, int max, int totalBars, String filled, String empty) { int filledBars = (int) ((double) current / max * totalBars); int emptyBars = totalBars - filledBars; StringBuilder bar = new StringBuilder(); for (int i = 0; i < filledBars; i++) { bar.append(filled); } for (int i = 0; i < emptyBars; i++) { bar.append(empty); } return bar.toString(); } private String getStatus(String mechanic, int value, int mildThreshold, int criticalThreshold) { String statusKey; if (value >= mildThreshold) { statusKey = mechanic + ".status.full"; } else if (value > criticalThreshold) { statusKey = mechanic + ".status.mild"; } else if (value > 0) { // Special cases for different mechanics if (mechanic.equals("hygiene")) { statusKey = mechanic + ".status.dirty"; } else { statusKey = mechanic + ".status.tired"; } } else { // Critical/Zero states if (mechanic.equals("hunger")) { statusKey = mechanic + ".status.starving"; } else if (mechanic.equals("thirst")) { statusKey = mechanic + ".status.dehydrated"; } else if (mechanic.equals("fatigue") || mechanic.equals("stamina")) { statusKey = mechanic + ".status.exhausted"; } else { statusKey = mechanic + ".status.critical"; } } return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); } private String getTemperatureStatus(int value, int mildThreshold, int criticalThreshold) { String statusKey; // Comfortable range: 40-60 if (value >= 40 && value <= 60) { statusKey = "temperature.status.full"; } // Hot (above 60) else if (value > 60) { // Very hot/critical (above 80) statusKey = value >= (100 - criticalThreshold) ? "temperature.status.critical" : "temperature.status.hot"; } // Cold (below 40) else { // Very cold/critical (below 20) statusKey = value <= criticalThreshold ? "temperature.status.critical" : "temperature.status.cold"; } return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); } private String getVulnerabilityStatus(int value, int mildThreshold, int criticalThreshold) { String statusKey; if (value >= criticalThreshold) { statusKey = "vulnerability.status.critical"; } else if (value > mildThreshold) { statusKey = "vulnerability.status.injured"; } else if (value > getConfig().getInt("display.critical-threshold", 20)) { statusKey = "vulnerability.status.mild"; } else { statusKey = "vulnerability.status.full"; } return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); } // IMPROVED: Use in-memory storage instead of constantly writing to config file public boolean canSendMessage(UUID playerId, String mechanic) { long currentTime = System.currentTimeMillis(); String key = playerId + ":" + mechanic; long lastTime = lastMessageTimes.getOrDefault(key, 0L); return (currentTime - lastTime) / 1000 >= getConfig().getInt(mechanic + ".message-cooldown", 60); } public void setLastMessageTime(UUID playerId, String mechanic) { String key = playerId + ":" + mechanic; lastMessageTimes.put(key, System.currentTimeMillis()); } // Getter methods for managers public HungerManager getHungerManager() { return hungerManager; } public ThirstManager getThirstManager() { return thirstManager; } public FatigueManager getFatigueManager() { return fatigueManager; } public TemperatureManager getTemperatureManager() { return temperatureManager; } public StaminaManager getStaminaManager() { return staminaManager; } public VulnerabilityManager getVulnerabilityManager() { return vulnerabilityManager; } public HygieneManager getHygieneManager() { return hygieneManager; } public FileConfiguration getLangConfig() { return langConfig; } }