diff --git a/src/main/java/wolfcraft/randomspawn/PlayerListener.java b/src/main/java/wolfcraft/randomspawn/PlayerListener.java index 25f970f..b515d5c 100644 --- a/src/main/java/wolfcraft/randomspawn/PlayerListener.java +++ b/src/main/java/wolfcraft/randomspawn/PlayerListener.java @@ -1,5 +1,8 @@ package wolfcraft.randomspawn; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -7,21 +10,24 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.scheduler.BukkitRunnable; public class PlayerListener implements Listener { private final RandomSpawn plugin; private final SpawnManager spawnManager; - + private final Set fallingSpawnedPlayers; + public PlayerListener(RandomSpawn plugin, SpawnManager spawnManager) { this.plugin = plugin; this.spawnManager = spawnManager; + this.fallingSpawnedPlayers = new HashSet<>(); } - + @EventHandler(priority = EventPriority.HIGH) public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - + // Only teleport on first join if (!player.hasPlayedBefore() && spawnManager.isFirstJoinEnabled()) { // Delay the teleport to ensure the player is fully loaded @@ -35,29 +41,50 @@ public void run() { }.runTaskLater(plugin, 5L); // 5 ticks = 0.25 seconds } } - + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPlayerRespawn(PlayerRespawnEvent event) { // Don't override if player has a bed or anchor respawn if (!event.isBedSpawn() && !event.isAnchorSpawn() && spawnManager.isRespawnOnDeathEnabled()) { Player player = event.getPlayer(); - + // Only apply to worlds that are enabled if (spawnManager.isWorldEnabled(player.getWorld().getName())) { Location randomLocation = spawnManager.getRandomSpawnLocation(player); - + if (randomLocation != null) { event.setRespawnLocation(randomLocation); + setFallingPlayer(player); } } } } - + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); + + if (spawnManager.isPreventFallDamageEnabled() && fallingSpawnedPlayers.contains(uuid) && player.isOnGround()) { + // The player has fall damage prevention enabled, is currently falling after a spawn, + // but has now touched ground, so we need to negate the fall damage and remove them from the falling players list + player.setFallDistance(0f); + fallingSpawnedPlayers.remove(uuid); + } + } + private void teleportToRandomSpawn(Player player) { Location randomLocation = spawnManager.getRandomSpawnLocation(player); - + if (randomLocation != null) { player.teleport(randomLocation); + setFallingPlayer(player); + } + } + + private void setFallingPlayer(Player player) { + if (spawnManager.isPreventFallDamageEnabled()) { + fallingSpawnedPlayers.add(player.getUniqueId()); } } } diff --git a/src/main/java/wolfcraft/randomspawn/RandomSpawn.java b/src/main/java/wolfcraft/randomspawn/RandomSpawn.java index 6cb335c..b379f61 100644 --- a/src/main/java/wolfcraft/randomspawn/RandomSpawn.java +++ b/src/main/java/wolfcraft/randomspawn/RandomSpawn.java @@ -14,27 +14,27 @@ public class RandomSpawn extends JavaPlugin { private FileConfiguration config; private SpawnManager spawnManager; private final String PREFIX = ChatColor.GOLD + "[RandomSpawn] " + ChatColor.RESET; - + @Override public void onEnable() { // Save default config if it doesn't exist saveDefaultConfig(); config = getConfig(); - + // Initialize spawn manager spawnManager = new SpawnManager(this); - + // Register event listeners getServer().getPluginManager().registerEvents(new PlayerListener(this, spawnManager), this); - + getLogger().info("RandomSpawn has been enabled!"); } - + @Override public void onDisable() { getLogger().info("RandomSpawn has been disabled!"); } - + @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { // Handle both command aliases: /rd and /random @@ -44,14 +44,14 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String showHelp(sender); return true; } - + if (args[0].equalsIgnoreCase("reload")) { // Check permission if (!sender.hasPermission("randomspawn.reload")) { sender.sendMessage(PREFIX + ChatColor.RED + "You don't have permission to use this command!"); return true; } - + // Reload config reloadConfig(); config = getConfig(); @@ -59,21 +59,21 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String sender.sendMessage(PREFIX + ChatColor.GREEN + "Configuration reloaded successfully!"); return true; } - + // Unknown argument, show help showHelp(sender); return true; } - + return false; } - + private void showHelp(CommandSender sender) { sender.sendMessage(ChatColor.YELLOW + "=== RandomSpawn Help ==="); sender.sendMessage(ChatColor.GOLD + "/rd reload " + ChatColor.WHITE + "- Reload the configuration"); sender.sendMessage(ChatColor.GOLD + "/random reload " + ChatColor.WHITE + "- Reload the configuration"); } - + public void reloadPluginConfig() { reloadConfig(); config = getConfig(); diff --git a/src/main/java/wolfcraft/randomspawn/SpawnManager.java b/src/main/java/wolfcraft/randomspawn/SpawnManager.java index ddeaedb..fc49c54 100644 --- a/src/main/java/wolfcraft/randomspawn/SpawnManager.java +++ b/src/main/java/wolfcraft/randomspawn/SpawnManager.java @@ -26,6 +26,8 @@ public class SpawnManager { private int zMin; private int zMax; private boolean forceGroundSpawn; + private boolean allowMidairSpawn; + private boolean preventFallDamage; private boolean enableFirstJoinSpawn; private boolean enableRespawnOnDeath; private int maxTries; @@ -49,6 +51,8 @@ public void reloadConfig() { zMin = config.getInt("spawn.z.min", -1000); zMax = config.getInt("spawn.z.max", 1000); forceGroundSpawn = config.getBoolean("spawn.force-ground-spawn", true); + allowMidairSpawn = config.getBoolean("spawn.allow-midair-spawn", false); + preventFallDamage = config.getBoolean("spawn.prevent-fall-damage", false); enableFirstJoinSpawn = config.getBoolean("events.first-join", true); enableRespawnOnDeath = config.getBoolean("events.respawn-on-death", true); maxTries = config.getInt("spawn.max-tries", 50); @@ -73,6 +77,10 @@ public boolean isRespawnOnDeathEnabled() { return enableRespawnOnDeath; } + public boolean isPreventFallDamageEnabled() { + return preventFallDamage; + } + public boolean isWorldEnabled(String worldName) { return enabledWorlds.contains(worldName); } @@ -134,8 +142,8 @@ private Location findSafeYPosition(Location location) { Block blockAbove = world.getBlockAt(x, y + 1, z); Block blockTwoAbove = world.getBlockAt(x, y + 2, z); - if (!block.getType().isAir() && - blockAbove.getType().isAir() && + if (!block.getType().isAir() && + blockAbove.getType().isAir() && blockTwoAbove.getType().isAir() && !block.isLiquid() && !isFatalBlock(block.getType().toString())) { @@ -157,9 +165,9 @@ private boolean isSafeLocation(Location location) { Block blockAbove = location.clone().add(0, 1, 0).getBlock(); if (!forceGroundSpawn) { - return block.getType().isAir() && + return block.getType().isAir() && blockAbove.getType().isAir() && - !blockBelow.getType().isAir() && + (!blockBelow.getType().isAir() || allowMidairSpawn) && !blockBelow.isLiquid() && !isFatalBlock(blockBelow.getType().toString()); } @@ -188,7 +196,7 @@ private void cacheLocation(String worldName, Location location) { locations.remove(locArray[random.nextInt(locArray.length)]); } } - + private int randomBetween(int min, int max) { if (min > max) { int temp = min; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6d438d6..2b4368f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -20,6 +20,13 @@ spawn: # If true, players will always spawn on the surface # This will disable the Y coordinate range setting above force-ground-spawn: true + + # If true, players can spawn in midair + # This might result in fall damage if prevent-fall-damage is false + allow-midair-spawn: false + + # If true, prevents fall damage from the player's first landing after being spawned + prevent-fall-damage: false # Maximum number of attempts to find a safe spawn location max-tries: 50 @@ -56,4 +63,3 @@ messages: prefix: "&6[RandomSpawn] &r" reload: "&aConfiguration reloaded successfully!" no-permission: "&cYou don't have permission to use this command!" -