diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java b/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java index db25a17e..5dc4f7eb 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/BlockSafety.java @@ -35,6 +35,13 @@ public interface BlockSafety { */ boolean playerCanSpawnHereSafely(Location l); + /** + * Gets a safe bed spawn location OR null if the bed is invalid. + * @param l The location of the bead head (block with the pillow on it). + * @return Safe location around the bed or null if no location was found. + */ + Location getSafeBedSpawn(Location l); + /** * Gets the location of the top block at the specified {@link Location}. * @param l Any {@link Location}. diff --git a/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java b/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java index 42bc8c56..5b73d0a9 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java +++ b/src/main/java/com/onarandombox/MultiverseCore/destination/BedDestination.java @@ -7,7 +7,9 @@ package com.onarandombox.MultiverseCore.destination; +import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVDestination; +import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -21,6 +23,7 @@ public class BedDestination implements MVDestination { private boolean isValid; private Location knownBedLoc; + private MultiverseCore plugin; /** * {@inheritDoc} @@ -46,7 +49,10 @@ public class BedDestination implements MVDestination { @Override public Location getLocation(Entity entity) { if (entity instanceof Player) { - this.knownBedLoc = ((Player) entity).getBedSpawnLocation(); + this.knownBedLoc = this.plugin.getBlockSafety().getSafeBedSpawn(((Player) entity).getBedSpawnLocation()); + if (this.knownBedLoc == null) { + ((Player) entity).sendMessage("Your bed was " + ChatColor.RED + "invalid or blocked" + ChatColor.RESET + ". Sorry."); + } return this.knownBedLoc; } return null; @@ -65,7 +71,7 @@ public class BedDestination implements MVDestination { */ @Override public void setDestination(JavaPlugin plugin, String destination) { - // Not needed. + this.plugin = (MultiverseCore) plugin; } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java b/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java index fed74950..2ea79357 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/MVPermissions.java @@ -76,6 +76,10 @@ public class MVPermissions implements PermissionsInterface { * @return Whether the {@link CommandSender} can travel to the specified {@link Location}. */ public boolean canTravelFromLocation(CommandSender sender, Location location) { + // Now The Bed destination can return null now. + if (location == null) { + return false; + } if (!(sender instanceof Player)) { return true; } diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java index de01b6f4..fd667d68 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java @@ -13,14 +13,24 @@ import com.onarandombox.MultiverseCore.api.Core; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Minecart; import org.bukkit.entity.Vehicle; +import org.bukkit.material.Bed; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; /** * The default-implementation of {@link BlockSafety}. */ public class SimpleBlockSafety implements BlockSafety { private final Core plugin; + private final static Set AROUND_BLOCK = new HashSet(){{ add(BlockFace.NORTH); add(BlockFace.NORTH_EAST); + add(BlockFace.EAST); add(BlockFace.SOUTH_EAST); + add(BlockFace.SOUTH); add(BlockFace.SOUTH_WEST); + add(BlockFace.WEST); add(BlockFace.NORTH_WEST); }}; public SimpleBlockSafety(Core plugin) { this.plugin = plugin; @@ -89,6 +99,63 @@ public class SimpleBlockSafety implements BlockSafety { return true; } + /** + * {@inheritDoc} + */ + @Override + public Location getSafeBedSpawn(Location l) { + // The passed location, may be null (if the bed is invalid) + if (l == null) { + return null; + } + final Location trySpawn = this.getSafeSpawnAroundABlock(l); + if (trySpawn != null) { + return trySpawn; + } + Location otherBlock = this.findOtherBedPiece(l); + if (otherBlock == null) { + return null; + } + // Now we have 2 locations, check around each, if the type is bed, skip it. + return this.getSafeSpawnAroundABlock(otherBlock); + } + + /** + * Find a safe spawn around a location. (N,S,E,W,NE,NW,SE,SW) + * @param l Location to check around + * @return A safe location, or none if it wasn't found. + */ + private Location getSafeSpawnAroundABlock(Location l) { + Iterator checkblock = AROUND_BLOCK.iterator(); + while(checkblock.hasNext()) { + final BlockFace face = checkblock.next(); + if (this.playerCanSpawnHereSafely(l.getBlock().getRelative(face).getLocation())) { + // Don't forget to center the player. + return l.getBlock().getRelative(face).getLocation().add(.5, 0, .5); + } + } + return null; + } + + /** + * Find the other bed block. + * @param checkLoc The location to check for the other piece at + * @return The location of the other bed piece, or null if it was a jacked up bed. + */ + private Location findOtherBedPiece(Location checkLoc) { + if (checkLoc.getBlock().getType() != Material.BED_BLOCK) { + return null; + } + // Construct a bed object at this location + final Bed b = new Bed(Material.BED_BLOCK, checkLoc.getBlock().getData()); + if (b.isHeadOfBed()) { + return checkLoc.getBlock().getRelative(b.getFacing().getOppositeFace()).getLocation(); + } + // We shouldn't ever be looking at the foot, but here's the code for it. + return checkLoc.getBlock().getRelative(b.getFacing()).getLocation(); + } + + /** * {@inheritDoc} */