diff --git a/src/main/java/com/massivecraft/factions/Conf.java b/src/main/java/com/massivecraft/factions/Conf.java index be72beaf..42e16c0a 100644 --- a/src/main/java/com/massivecraft/factions/Conf.java +++ b/src/main/java/com/massivecraft/factions/Conf.java @@ -250,6 +250,7 @@ public class Conf { public static double econCostMap = 0.0; public static double econCostPower = 0.0; public static double econCostShow = 0.0; + public static double econCostStuck = 0.0; public static double econCostOpen = 0.0; public static double econCostAlly = 0.0; public static double econCostTruce = 0.0; diff --git a/src/main/java/com/massivecraft/factions/cmd/CmdStuck.java b/src/main/java/com/massivecraft/factions/cmd/CmdStuck.java new file mode 100644 index 00000000..b6528008 --- /dev/null +++ b/src/main/java/com/massivecraft/factions/cmd/CmdStuck.java @@ -0,0 +1,113 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.*; +import com.massivecraft.factions.integration.Essentials; +import com.massivecraft.factions.struct.Permission; +import com.massivecraft.factions.util.SpiralTask; +import com.massivecraft.factions.zcore.util.TL; +import org.apache.commons.lang.time.DurationFormatUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Random; + +public class CmdStuck extends FCommand { + + private final static Random random = new Random(); + + public CmdStuck() { + super(); + + this.aliases.add("stuck"); + this.aliases.add("halp!"); // halp! c: + + this.permission = Permission.STUCK.node; + this.disableOnLock = true; + + senderMustBePlayer = false; + senderMustBeMember = false; + senderMustBeModerator = false; + senderMustBeAdmin = false; + } + + @Override + public void perform() { + final Player player = fme.getPlayer(); + final Location sentAt = player.getLocation(); + final FLocation chunk = fme.getLastStoodAt(); + final long delay = P.p.getConfig().getLong("hcf.stuck.delay", 30); + final int radius = P.p.getConfig().getInt("hcf.stuck.radius", 10); + + if (P.p.getStuckMap().containsKey(player.getUniqueId())) { + long wait = P.p.getTimers().get(player.getUniqueId()) - System.currentTimeMillis(); + String time = DurationFormatUtils.formatDuration(wait, TL.COMMAND_STUCK_TIMEFORMAT.toString(), true); + msg(TL.COMMAND_STUCK_EXISTS, time); + } else { + + // if economy is enabled, they're not on the bypass list, and this command has a cost set, make 'em pay + if (!payForCommand(Conf.econCostStuck, TL.COMMAND_STUCK_TOSTUCK.format(fme.getName()), TL.COMMAND_STUCK_FORSTUCK.format(fme.getName()))) { + return; + } + + final int id = Bukkit.getScheduler().runTaskLater(P.p, new BukkitRunnable() { + + @Override + public void run() { + if (!P.p.getStuckMap().containsKey(player.getUniqueId())) { + return; + } + + // check for world difference or radius exceeding + final World world = chunk.getWorld(); + if (world.getUID() != player.getWorld().getUID() || sentAt.distance(player.getLocation()) > radius) { + msg(TL.COMMAND_STUCK_OUTSIDE.format(radius)); + P.p.getTimers().remove(player.getUniqueId()); + P.p.getStuckMap().remove(player.getUniqueId()); + return; + } + + final Board board = Board.getInstance(); + // spiral task to find nearest wilderness chunk + new SpiralTask(new FLocation(me), radius * 2) { + + @Override + public boolean work() { + FLocation chunk = currentFLocation(); + Faction faction = board.getFactionAt(chunk); + if (faction.isNone()) { + int cx = FLocation.chunkToBlock((int) chunk.getX()); + int cz = FLocation.chunkToBlock((int) chunk.getZ()); + int y = world.getHighestBlockYAt(cx, cz); + Location tp = new Location(world, cx, y, cz); + msg(TL.COMMAND_STUCK_TELEPORT, tp.getBlockX(), tp.getBlockY(), tp.getBlockZ()); + P.p.getTimers().remove(player.getUniqueId()); + P.p.getStuckMap().remove(player.getUniqueId()); + if (!Essentials.handleTeleport(player, tp)) { + player.teleport(tp); + P.p.debug("/f stuck used regular teleport, not essentials!"); + } + this.stop(); + return false; + } + return true; + } + }; + } + }, delay * 20).getTaskId(); + + P.p.getTimers().put(player.getUniqueId(), System.currentTimeMillis() + (delay * 1000)); + long wait = P.p.getTimers().get(player.getUniqueId()) - System.currentTimeMillis(); + String time = DurationFormatUtils.formatDuration(wait, TL.COMMAND_STUCK_TIMEFORMAT.toString(), true); + msg(TL.COMMAND_STUCK_START, time); + P.p.getStuckMap().put(player.getUniqueId(), id); + } + } + + @Override + public TL getUsageTranslation() { + return TL.COMMAND_STUCK_DESCRIPTION; + } +} diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java index bad20c05..38884a22 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsEntityListener.java @@ -5,7 +5,6 @@ import com.massivecraft.factions.event.PowerLossEvent; import com.massivecraft.factions.struct.Relation; import com.massivecraft.factions.util.MiscUtil; import com.massivecraft.factions.zcore.util.TL; - import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.TravelAgent; @@ -96,10 +95,36 @@ public class FactionsEntityListener implements Listener { if (!this.canDamagerHurtDamagee(sub, true)) { event.setCancelled(true); } + // event is not cancelled by factions + + Entity damagee = sub.getEntity(); + Entity damager = sub.getDamager(); + + if (damagee != null && damagee instanceof Player) { + cancelFStuckTeleport((Player) damagee); + } + if (damager instanceof Player) { + cancelFStuckTeleport((Player) damager); + } } else if (Conf.safeZonePreventAllDamageToPlayers && isPlayerInSafeZone(event.getEntity())) { // Players can not take any damage in a Safe Zone event.setCancelled(true); } + + // entity took generic damage? + Entity entity = event.getEntity(); + if (entity instanceof Player) { + cancelFStuckTeleport((Player) event.getEntity()); + } + } + + public void cancelFStuckTeleport(Player player) { + if (player == null) return; + UUID uuid = player.getUniqueId(); + if (P.p.getStuckMap().containsKey(uuid)) { + FPlayers.getInstance().getByPlayer(player).msg(TL.COMMAND_STUCK_CANCELLED); + P.p.getStuckMap().remove(uuid); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) diff --git a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java index 70a4210c..4524259f 100644 --- a/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java +++ b/src/main/java/com/massivecraft/factions/listeners/FactionsPlayerListener.java @@ -94,6 +94,13 @@ public class FactionsPlayerListener implements Listener { // and update their last login time to point to when the logged off, for auto-remove routine me.setLastLoginTime(System.currentTimeMillis()); + // if player is waiting for fstuck teleport but leaves, remove + if (P.p.getStuckMap().containsKey(me.getPlayer().getUniqueId())) { + FPlayers.getInstance().getByPlayer(me.getPlayer()).msg(TL.COMMAND_STUCK_CANCELLED); + P.p.getStuckMap().remove(me.getPlayer().getUniqueId()); + P.p.getTimers().remove(me.getPlayer().getUniqueId()); + } + Faction myFaction = me.getFaction(); if (!myFaction.isNone()) { myFaction.memberLoggedOff(); diff --git a/src/main/java/com/massivecraft/factions/struct/Permission.java b/src/main/java/com/massivecraft/factions/struct/Permission.java index 297c2a73..e6a816a0 100644 --- a/src/main/java/com/massivecraft/factions/struct/Permission.java +++ b/src/main/java/com/massivecraft/factions/struct/Permission.java @@ -65,6 +65,7 @@ public enum Permission { SETHOME_ANY("sethome.any"), SHOW("show"), STATUS("status"), + STUCK("stuck"), TAG("tag"), TITLE("title"), TOGGLE_ALLIANCE_CHAT("togglealliancechat"), diff --git a/src/main/java/com/massivecraft/factions/zcore/MPlugin.java b/src/main/java/com/massivecraft/factions/zcore/MPlugin.java index 743ee498..91490680 100644 --- a/src/main/java/com/massivecraft/factions/zcore/MPlugin.java +++ b/src/main/java/com/massivecraft/factions/zcore/MPlugin.java @@ -59,6 +59,12 @@ public abstract class MPlugin extends JavaPlugin { return this.baseCommands; } + // holds f stuck start times + private Map timers = new HashMap(); + + //holds f stuck taskids + public Map stuckMap = new HashMap(); + // -------------------------------------------- // // ENABLE // -------------------------------------------- // @@ -318,6 +324,14 @@ public abstract class MPlugin extends JavaPlugin { } + public Map getStuckMap() { + return this.stuckMap; + } + + public Map getTimers() { + return this.timers; + } + // -------------------------------------------- // // LOGGING // -------------------------------------------- // diff --git a/src/main/java/com/massivecraft/factions/zcore/util/TL.java b/src/main/java/com/massivecraft/factions/zcore/util/TL.java index cdef10e9..1caafb10 100644 --- a/src/main/java/com/massivecraft/factions/zcore/util/TL.java +++ b/src/main/java/com/massivecraft/factions/zcore/util/TL.java @@ -461,6 +461,16 @@ public enum TL { COMMAND_STATUS_AGOSUFFIX(" ago."), COMMAND_STATUS_DESCRIPTION("Show the status of a player"), + COMMAND_STUCK_TIMEFORMAT("m 'minutes', s 'seconds.'"), + COMMAND_STUCK_CANCELLED("Teleport cancelled because you were damaged"), + COMMAND_STUCK_OUTSIDE("Teleport cancelled because you left %1$d block radius"), + COMMAND_STUCK_EXISTS("You are already teleporting, you must wait %1$s"), + COMMAND_STUCK_START("Teleport will commence in %s. Don't take or deal damage. "), + COMMAND_STUCK_TELEPORT("Teleported safely to %1$d, %2$d, %3$d."), + COMMAND_STUCK_TOSTUCK("to safely teleport %1$s out"), + COMMAND_STUCK_FORSTUCK("for %1$s initiating a safe teleport out"), + COMMAND_STUCK_DESCRIPTION("Safely teleports you out of enemy faction"), + COMMAND_TAG_TAKEN("That tag is already taken"), COMMAND_TAG_TOCHANGE("to change the faction tag"), COMMAND_TAG_FORCHANGE("for changing the faction tag"), diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 87de40dc..e1a1490a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -209,6 +209,10 @@ hcf: # always been. buffer-zone: 0 + stuck: + delay: 30 + radius: 10 + ############################################################ # +------------------------------------------------------+ # # | Configurable /f show | # diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2db2704c..e1734250 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -83,6 +83,7 @@ permissions: factions.relation: true factions.sethome: true factions.show: true + factions.stuck: true factions.tag: true factions.title: true factions.version: true @@ -205,6 +206,8 @@ permissions: description: designate a faction as permanent factions.setpermanentpower: description: set permanent power for a faction + factions.stuck: + description: teleports player outside a faction factions.power: description: show player power info factions.power.any: