From aae521b7279519c5fe24f53845db4eb013d492d9 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 17 Jan 2015 18:54:10 -0800 Subject: [PATCH] Rewrite session and movement flag code. Also adds entry-deny-message and exit-deny-message. Fixes WORLDGUARD-3086, WORLDGUARD-2542, WORLDGUARD-2731. --- .../bukkit/ConfigurationManager.java | 64 +---- .../worldguard/bukkit/WorldGuardPlugin.java | 26 +- .../bukkit/commands/GeneralCommands.java | 74 ++--- .../bukkit/commands/WorldGuardCommands.java | 4 +- .../bukkit/internal/RegionQueryUtil.java | 88 ------ .../bukkit/listener/FlagStateManager.java | 252 ------------------ .../bukkit/listener/PlayerModesListener.java | 14 +- .../bukkit/listener/PlayerMoveListener.java | 247 +++-------------- .../listener/WorldGuardEntityListener.java | 86 +----- .../listener/WorldGuardPlayerListener.java | 70 +---- .../listener/WorldGuardVehicleListener.java | 15 +- .../protection/flags/DefaultFlag.java | 9 +- .../sk89q/worldguard/session/MoveType.java | 48 ++++ .../com/sk89q/worldguard/session/Session.java | 222 +++++++++++++++ .../worldguard/session/SessionManager.java | 219 +++++++++++++++ .../worldguard/session/WorldPlayerTuple.java | 55 ++++ .../worldguard/session/handler/EntryFlag.java | 60 +++++ .../worldguard/session/handler/ExitFlag.java | 85 ++++++ .../session/handler/FarewellFlag.java | 78 ++++++ .../worldguard/session/handler/FeedFlag.java | 77 ++++++ .../handler/FlagValueChangeHandler.java | 74 +++++ .../session/handler/GameModeFlag.java | 80 ++++++ .../worldguard/session/handler/GodMode.java | 76 ++++++ .../session/handler/GreetingFlag.java | 69 +++++ .../worldguard/session/handler/Handler.java | 148 ++++++++++ .../worldguard/session/handler/HealFlag.java | 84 ++++++ .../session/handler/InvincibilityFlag.java | 68 +++++ .../session/handler/NotifyEntryFlag.java | 68 +++++ .../session/handler/NotifyExitFlag.java | 55 ++++ .../session/handler/WaterBreathing.java | 51 ++++ 30 files changed, 1767 insertions(+), 799 deletions(-) delete mode 100644 src/main/java/com/sk89q/worldguard/bukkit/internal/RegionQueryUtil.java delete mode 100644 src/main/java/com/sk89q/worldguard/bukkit/listener/FlagStateManager.java create mode 100644 src/main/java/com/sk89q/worldguard/session/MoveType.java create mode 100644 src/main/java/com/sk89q/worldguard/session/Session.java create mode 100644 src/main/java/com/sk89q/worldguard/session/SessionManager.java create mode 100644 src/main/java/com/sk89q/worldguard/session/WorldPlayerTuple.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/EntryFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/ExitFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/FarewellFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/FeedFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/FlagValueChangeHandler.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/GameModeFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/GodMode.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/GreetingFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/Handler.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/HealFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/InvincibilityFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/NotifyEntryFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/NotifyExitFlag.java create mode 100644 src/main/java/com/sk89q/worldguard/session/handler/WaterBreathing.java diff --git a/src/main/java/com/sk89q/worldguard/bukkit/ConfigurationManager.java b/src/main/java/com/sk89q/worldguard/bukkit/ConfigurationManager.java index b3c0e88f..7c08295b 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/ConfigurationManager.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/ConfigurationManager.java @@ -20,15 +20,13 @@ package com.sk89q.worldguard.bukkit; import com.google.common.collect.ImmutableMap; -import com.sk89q.commandbook.CommandBook; -import com.sk89q.commandbook.GodComponent; import com.sk89q.util.yaml.YAMLFormat; import com.sk89q.util.yaml.YAMLProcessor; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.protection.managers.storage.file.DirectoryYamlDriver; import com.sk89q.worldguard.protection.managers.storage.DriverType; import com.sk89q.worldguard.protection.managers.storage.RegionDriver; +import com.sk89q.worldguard.protection.managers.storage.file.DirectoryYamlDriver; import com.sk89q.worldguard.protection.managers.storage.sql.SQLDriver; +import com.sk89q.worldguard.session.handler.WaterBreathing; import com.sk89q.worldguard.util.report.Unreported; import com.sk89q.worldguard.util.sql.DataSourceConfig; import org.bukkit.World; @@ -37,9 +35,7 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; @@ -79,12 +75,9 @@ public class ConfigurationManager { @Unreported private WorldGuardPlugin plugin; @Unreported private ConcurrentMap worlds; @Unreported private YAMLProcessor config; - @Deprecated @Unreported private Set hasGodMode = new HashSet(); - @Unreported private Set hasAmphibious = new HashSet(); private boolean hasCommandBookGodMode = false; - public boolean useRegionsScheduler; public boolean useRegionsCreatureSpawnEvent; public boolean activityHaltToggle = false; public boolean useGodPermission; @@ -152,7 +145,6 @@ public void load() { } config.removeProperty("suppress-tick-sync-warnings"); - useRegionsScheduler = config.getBoolean("regions.use-scheduler", true); migrateRegionsToUuid = config.getBoolean("regions.uuid-migration.perform-on-next-start", true); keepUnresolvedNames = config.getBoolean("regions.uuid-migration.keep-names-that-lack-uuids", true); useRegionsCreatureSpawnEvent = config.getBoolean("regions.use-creature-spawn-event", true); @@ -242,37 +234,6 @@ public WorldConfiguration get(World world) { return config; } - /** - * Forget a player. - * - * @param player The player to forget about - */ - public void forgetPlayer(LocalPlayer player) { - hasGodMode.remove(player.getName()); - hasAmphibious.remove(player.getName()); - } - - /** - * Enable god mode for a player. - * - * @param player The player to enable god mode for. - */ - @Deprecated - public void enableGodMode(Player player) { - - hasGodMode.add(player.getName()); - } - - /** - * Disable god mode for a player. - * - * @param player The player to disable godmode for - */ - @Deprecated - public void disableGodMode(Player player) { - hasGodMode.remove(player.getName()); - } - /** * Check to see if god mode is enabled for a player. * @@ -280,13 +241,7 @@ public void disableGodMode(Player player) { * @return Whether the player has godmode through WorldGuard or CommandBook */ public boolean hasGodMode(Player player) { - if (hasCommandBookGodMode) { - GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class); - if (god != null) { - return god.hasGodMode(player); - } - } - return hasGodMode.contains(player.getName()); + return plugin.getSessionManager().get(player).isInvincible(player); } /** @@ -295,7 +250,10 @@ public boolean hasGodMode(Player player) { * @param player The player to enable amphibious mode for */ public void enableAmphibiousMode(Player player) { - hasAmphibious.add(player.getName()); + WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class); + if (handler != null) { + handler.setWaterBreathing(true); + } } /** @@ -304,7 +262,10 @@ public void enableAmphibiousMode(Player player) { * @param player The player to disable amphibious mode for */ public void disableAmphibiousMode(Player player) { - hasAmphibious.remove(player.getName()); + WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class); + if (handler != null) { + handler.setWaterBreathing(false); + } } /** @@ -314,7 +275,8 @@ public void disableAmphibiousMode(Player player) { * @return Whether {@code player} has amphibious mode */ public boolean hasAmphibiousMode(Player player) { - return hasAmphibious.contains(player.getName()); + WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class); + return handler != null && handler.hasWaterBreathing(); } public void updateCommandBookGodMode() { diff --git a/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java b/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java index e33cc297..abb36f1f 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java @@ -37,6 +37,7 @@ import com.sk89q.worldguard.bukkit.commands.ToggleCommands; import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent; import com.sk89q.worldguard.bukkit.listener.*; +import com.sk89q.worldguard.session.SessionManager; import com.sk89q.worldguard.bukkit.util.Events; import com.sk89q.worldguard.protection.GlobalRegionManager; import com.sk89q.worldguard.protection.managers.RegionManager; @@ -85,7 +86,7 @@ public class WorldGuardPlugin extends JavaPlugin { private final ConfigurationManager configuration = new ConfigurationManager(this); private final RegionContainer regionContainer = new RegionContainer(this); private final GlobalRegionManager globalRegionManager = new GlobalRegionManager(this, regionContainer); - private FlagStateManager flagStateManager; + private SessionManager sessionManager; private final Supervisor supervisor = new SimpleSupervisor(); private ListeningExecutorService executorService; private ProfileService profileService; @@ -126,6 +127,8 @@ public void onEnable() { executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20)); + sessionManager = new SessionManager(this); + // Set the proper command injector commands.setInjector(new SimpleInjector(this)); @@ -164,14 +167,10 @@ public void run() { log.info("Loading region data..."); regionContainer.initialize(); - flagStateManager = new FlagStateManager(this); - - if (configuration.useRegionsScheduler) { - getServer().getScheduler().scheduleSyncRepeatingTask(this, flagStateManager, - FlagStateManager.RUN_DELAY, FlagStateManager.RUN_DELAY); - } + getServer().getScheduler().scheduleSyncRepeatingTask(this, sessionManager, SessionManager.RUN_DELAY, SessionManager.RUN_DELAY); // Register events + getServer().getPluginManager().registerEvents(sessionManager, this); (new WorldGuardPlayerListener(this)).registerEvents(); (new WorldGuardBlockListener(this)).registerEvents(); (new WorldGuardEntityListener(this)).registerEvents(); @@ -327,8 +326,8 @@ public ConfigurationManager getGlobalConfiguration() { * * @return The flag state manager */ - public FlagStateManager getFlagStateManager() { - return flagStateManager; + public SessionManager getSessionManager() { + return sessionManager; } /** @@ -925,15 +924,6 @@ public void broadcastNotification(String msg) { log.info(msg); } - /** - * Forgets a player. - * - * @param player The player to remove state information for - */ - public void forgetPlayer(Player player) { - flagStateManager.forget(player); - } - /** * Checks to see if a player can build at a location. This will return * true if region protection is disabled. diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/GeneralCommands.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/GeneralCommands.java index 75f8f668..bc6dd347 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/commands/GeneralCommands.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/GeneralCommands.java @@ -19,11 +19,6 @@ package com.sk89q.worldguard.bukkit.commands; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; @@ -31,6 +26,12 @@ import com.sk89q.worldedit.blocks.ItemType; import com.sk89q.worldguard.bukkit.ConfigurationManager; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.session.Session; +import com.sk89q.worldguard.session.handler.GodMode; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; public class GeneralCommands { private final WorldGuardPlugin plugin; @@ -54,7 +55,7 @@ public void god(CommandContext args, CommandSender sender) throws CommandExcepti // Check permissions! plugin.checkPermission(sender, "worldguard.god"); - } else if (args.argsLength() == 1) { + } else { targets = plugin.matchPlayers(sender, args.getString(0)); // Check permissions! @@ -62,26 +63,29 @@ public void god(CommandContext args, CommandSender sender) throws CommandExcepti } for (Player player : targets) { - config.enableGodMode(player); - player.setFireTicks(0); - - // Tell the user - if (player.equals(sender)) { - player.sendMessage(ChatColor.YELLOW + "God mode enabled! Use /ungod to disable."); - - // Keep track of this - included = true; - } else { - player.sendMessage(ChatColor.YELLOW + "God enabled by " - + plugin.toName(sender) + "."); - + Session session = plugin.getSessionManager().get(player); + + if (GodMode.set(player, session, true)) { + player.setFireTicks(0); + + // Tell the user + if (player.equals(sender)) { + player.sendMessage(ChatColor.YELLOW + "God mode enabled! Use /ungod to disable."); + + // Keep track of this + included = true; + } else { + player.sendMessage(ChatColor.YELLOW + "God enabled by " + + plugin.toName(sender) + "."); + + } } } // The player didn't receive any items, then we need to send the // user a message so s/he know that something is indeed working if (!included && args.hasFlag('s')) { - sender.sendMessage(ChatColor.YELLOW.toString() + "Players now have god mode."); + sender.sendMessage(ChatColor.YELLOW + "Players now have god mode."); } } @@ -100,7 +104,7 @@ public void ungod(CommandContext args, CommandSender sender) throws CommandExcep // Check permissions! plugin.checkPermission(sender, "worldguard.god"); - } else if (args.argsLength() == 1) { + } else { targets = plugin.matchPlayers(sender, args.getString(0)); // Check permissions! @@ -108,25 +112,27 @@ public void ungod(CommandContext args, CommandSender sender) throws CommandExcep } for (Player player : targets) { - config.disableGodMode(player); - - // Tell the user - if (player.equals(sender)) { - player.sendMessage(ChatColor.YELLOW + "God mode disabled!"); - - // Keep track of this - included = true; - } else { - player.sendMessage(ChatColor.YELLOW + "God disabled by " - + plugin.toName(sender) + "."); - + Session session = plugin.getSessionManager().get(player); + + if (GodMode.set(player, session, false)) { + // Tell the user + if (player.equals(sender)) { + player.sendMessage(ChatColor.YELLOW + "God mode disabled!"); + + // Keep track of this + included = true; + } else { + player.sendMessage(ChatColor.YELLOW + "God disabled by " + + plugin.toName(sender) + "."); + + } } } // The player didn't receive any items, then we need to send the // user a message so s/he know that something is indeed working if (!included && args.hasFlag('s')) { - sender.sendMessage(ChatColor.YELLOW.toString() + "Players no longer have god mode."); + sender.sendMessage(ChatColor.YELLOW + "Players no longer have god mode."); } } diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java index e64db526..1320e036 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java @@ -250,12 +250,12 @@ public void stopProfile(CommandContext args, final CommandSender sender) throws @CommandPermissions("worldguard.flushstates") public void flushStates(CommandContext args, CommandSender sender) throws CommandException { if (args.argsLength() == 0) { - plugin.getFlagStateManager().forgetAll(); + plugin.getSessionManager().resetAllStates(); sender.sendMessage("Cleared all states."); } else { Player player = plugin.getServer().getPlayer(args.getString(0)); if (player != null) { - plugin.getFlagStateManager().forget(player); + plugin.getSessionManager().resetState(player); sender.sendMessage("Cleared states for player \"" + player.getName() + "\"."); } } diff --git a/src/main/java/com/sk89q/worldguard/bukkit/internal/RegionQueryUtil.java b/src/main/java/com/sk89q/worldguard/bukkit/internal/RegionQueryUtil.java deleted file mode 100644 index 5989fc58..00000000 --- a/src/main/java/com/sk89q/worldguard/bukkit/internal/RegionQueryUtil.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * WorldGuard, a suite of tools for Minecraft - * Copyright (C) sk89q - * Copyright (C) WorldGuard team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldguard.bukkit.internal; - -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.bukkit.listener.FlagStateManager; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; - -public final class RegionQueryUtil { - - private RegionQueryUtil() { - } - - public static boolean isInvincible(WorldGuardPlugin plugin, Player player) { - return isInvincible(plugin, player, null); - } - - public static boolean isInvincible(WorldGuardPlugin plugin, Player player, - ApplicableRegionSet set) { - Location loc = player.getLocation(); - World world = player.getWorld(); - - FlagStateManager.PlayerFlagState state = plugin.getFlagStateManager().getState(player); - - if (state.lastInvincibleWorld == null || - !state.lastInvincibleWorld.equals(world) || - state.lastInvincibleX != loc.getBlockX() || - state.lastInvincibleY != loc.getBlockY() || - state.lastInvincibleZ != loc.getBlockZ()) { - state.lastInvincibleX = loc.getBlockX(); - state.lastInvincibleY = loc.getBlockY(); - state.lastInvincibleZ = loc.getBlockZ(); - state.lastInvincibleWorld = world; - - if (set == null) { - Vector vec = new Vector(state.lastInvincibleX, - state.lastInvincibleY, state.lastInvincibleZ); - RegionManager mgr = plugin.getGlobalRegionManager().get(world); - set = mgr.getApplicableRegions(vec); - } - - state.wasInvincible = set.allows(DefaultFlag.INVINCIBILITY, plugin.wrapPlayer(player)); - } - - return state.wasInvincible; - } - - public static Boolean isAllowedInvinciblity(WorldGuardPlugin plugin, Player player) { - World world = player.getWorld(); - FlagStateManager.PlayerFlagState state = plugin.getFlagStateManager().getState(player); - Vector vec = new Vector(state.lastInvincibleX, state.lastInvincibleY, state.lastInvincibleZ); - - StateFlag.State regionState = plugin.getGlobalRegionManager().get(world). - getApplicableRegions(vec).getFlag(DefaultFlag.INVINCIBILITY, plugin.wrapPlayer(player)); - if (regionState == StateFlag.State.ALLOW) { - return Boolean.TRUE; - } else if (regionState == StateFlag.State.DENY) { - return Boolean.FALSE; - } else { - return null; - } - } -} diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/FlagStateManager.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/FlagStateManager.java deleted file mode 100644 index c21eeb52..00000000 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/FlagStateManager.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * WorldGuard, a suite of tools for Minecraft - * Copyright (C) sk89q - * Copyright (C) WorldGuard team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldguard.bukkit.listener; - -import com.sk89q.worldguard.bukkit.BukkitUtil; -import com.sk89q.worldguard.bukkit.ConfigurationManager; -import com.sk89q.worldguard.bukkit.WorldConfiguration; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.bukkit.internal.RegionQueryUtil; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import org.bukkit.GameMode; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * This processes per-player state information and is also meant to be used - * as a scheduled task. - * - * @author sk89q - */ -public class FlagStateManager implements Runnable { - - public static final int RUN_DELAY = 20; - - private WorldGuardPlugin plugin; - private Map states; - - /** - * Construct the object. - * - * @param plugin The plugin instance - */ - public FlagStateManager(WorldGuardPlugin plugin) { - this.plugin = plugin; - - states = new HashMap(); - } - - /** - * Run the task. - */ - @Override - public void run() { - Collection players = BukkitUtil.getOnlinePlayers(); - ConfigurationManager config = plugin.getGlobalStateManager(); - - for (Player player : players) { - WorldConfiguration worldConfig = config.get(player.getWorld()); - - if (!worldConfig.useRegions) { - continue; - } - - PlayerFlagState state; - - synchronized (this) { - state = states.get(player.getName()); - - if (state == null) { - state = new PlayerFlagState(); - states.put(player.getName(), state); - } - } - - ApplicableRegionSet applicable = plugin.getRegionContainer().createQuery().getApplicableRegions(player.getLocation()); - - if (!RegionQueryUtil.isInvincible(plugin, player, applicable) - && !plugin.getGlobalStateManager().hasGodMode(player) - && !(player.getGameMode() == GameMode.CREATIVE)) { - processHeal(applicable, player, state); - processFeed(applicable, player, state); - } - } - } - - /** - * Process healing for a player. - * - * @param applicable The set of applicable regions - * @param player The player to process healing flags on - * @param state The player's state - */ - private void processHeal(ApplicableRegionSet applicable, Player player, - PlayerFlagState state) { - - if (player.getHealth() <= 0) { - return; - } - - long now = System.currentTimeMillis(); - - Integer healAmount = applicable.getFlag(DefaultFlag.HEAL_AMOUNT); - Integer healDelay = applicable.getFlag(DefaultFlag.HEAL_DELAY); - Double minHealth = applicable.getFlag(DefaultFlag.MIN_HEAL); - Double maxHealth = applicable.getFlag(DefaultFlag.MAX_HEAL); - - if (healAmount == null || healDelay == null || healAmount == 0 || healDelay < 0) { - return; - } - if (minHealth == null) { - minHealth = 0.0; - } - if (maxHealth == null) { - maxHealth = player.getMaxHealth(); - } - - // Apply a cap to prevent possible exceptions - minHealth = Math.min(player.getMaxHealth(), minHealth); - maxHealth = Math.min(player.getMaxHealth(), maxHealth); - - if (player.getHealth() >= maxHealth && healAmount > 0) { - return; - } - - if (healDelay <= 0) { - player.setHealth(healAmount > 0 ? maxHealth : minHealth); // this will insta-kill if the flag is unset - state.lastHeal = now; - } else if (now - state.lastHeal > healDelay * 1000) { - // clamp health between minimum and maximum - player.setHealth(Math.min(maxHealth, Math.max(minHealth, player.getHealth() + healAmount))); - state.lastHeal = now; - } - } - - /** - * Process restoring hunger for a player. - * - * @param applicable The set of applicable regions - * @param player The player to process hunger flags on - * @param state The player's state - */ - private void processFeed(ApplicableRegionSet applicable, Player player, - PlayerFlagState state) { - - long now = System.currentTimeMillis(); - - Integer feedAmount = applicable.getFlag(DefaultFlag.FEED_AMOUNT); - Integer feedDelay = applicable.getFlag(DefaultFlag.FEED_DELAY); - Integer minHunger = applicable.getFlag(DefaultFlag.MIN_FOOD); - Integer maxHunger = applicable.getFlag(DefaultFlag.MAX_FOOD); - - if (feedAmount == null || feedDelay == null || feedAmount == 0 || feedDelay < 0) { - return; - } - if (minHunger == null) { - minHunger = 0; - } - if (maxHunger == null) { - maxHunger = 20; - } - - // Apply a cap to prevent possible exceptions - minHunger = Math.min(20, minHunger); - maxHunger = Math.min(20, maxHunger); - - if (player.getFoodLevel() >= maxHunger && feedAmount > 0) { - return; - } - - if (feedDelay <= 0) { - player.setFoodLevel(feedAmount > 0 ? maxHunger : minHunger); - player.setSaturation(player.getFoodLevel()); - state.lastFeed = now; - } else if (now - state.lastFeed > feedDelay * 1000) { - // clamp health between minimum and maximum - player.setFoodLevel(Math.min(maxHunger, Math.max(minHunger, player.getFoodLevel() + feedAmount))); - player.setSaturation(player.getFoodLevel()); - state.lastFeed = now; - } - } - - /** - * Forget a player. - * - * @param player The player to forget - */ - public synchronized void forget(Player player) { - states.remove(player.getName()); - } - - /** - * Forget all managed players. Use with caution. - */ - public synchronized void forgetAll() { - states.clear(); - } - - /** - * Get a player's flag state. A new state will be created if there is no existing - * state for the player. - * - * @param player The player to get a state for - * @return The {@code player}'s state - */ - public synchronized PlayerFlagState getState(Player player) { - PlayerFlagState state = states.get(player.getName()); - - if (state == null) { - state = new PlayerFlagState(); - states.put(player.getName(), state); - } - - return state; - } - - /** - * Keeps state per player. - */ - public static class PlayerFlagState { - public long lastHeal; - public long lastFeed; - public String lastGreeting; - public String lastFarewell; - public Boolean lastExitAllowed = null; - public Boolean notifiedForLeave = false; - public Boolean notifiedForEnter = false; - public GameMode lastGameMode; - public World lastWorld; - public int lastBlockX; - public int lastBlockY; - public int lastBlockZ; - - /* Used to cache invincibility status */ - public World lastInvincibleWorld; - public int lastInvincibleX; - public int lastInvincibleY; - public int lastInvincibleZ; - public boolean wasInvincible; - } -} diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerModesListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerModesListener.java index 3380662a..ab10bd5e 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerModesListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerModesListener.java @@ -22,6 +22,9 @@ import com.sk89q.worldguard.bukkit.ConfigurationManager; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent; +import com.sk89q.worldguard.session.Session; +import com.sk89q.worldguard.session.handler.GodMode; +import com.sk89q.worldguard.session.handler.WaterBreathing; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -61,17 +64,18 @@ private boolean hasAmphibiousGroup(Player player) { public void onProcessPlayer(ProcessPlayerEvent event) { ConfigurationManager config = getConfig(); Player player = event.getPlayer(); + Session session = getPlugin().getSessionManager().get(player); - if (!config.hasCommandBookGodMode()) { - if (hasGodModeGroup(player) || hasGodModePermission(player)) { + if (hasGodModeGroup(player) || hasGodModePermission(player)) { + if (GodMode.set(player, session, true)) { log.log(Level.INFO, "Enabled auto-god mode for " + player.getName()); - config.enableGodMode(player); } } if (hasAmphibiousGroup(player)) { - log.log(Level.INFO, "Enabled no-drowning mode for " + player.getName() + " (player is in group 'wg-amphibious')"); - config.enableAmphibiousMode(player); + if (WaterBreathing.set(player, session, true)) { + log.log(Level.INFO, "Enabled water breathing mode for " + player.getName() + " (player is in group 'wg-amphibious')"); + } } } diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerMoveListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerMoveListener.java index 3df6a660..2aadedca 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerMoveListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/PlayerMoveListener.java @@ -19,46 +19,25 @@ package com.sk89q.worldguard.bukkit.listener; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.bukkit.BukkitUtil; -import com.sk89q.worldguard.bukkit.ConfigurationManager; -import com.sk89q.worldguard.bukkit.WorldConfiguration; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.bukkit.listener.FlagStateManager.PlayerFlagState; -import com.sk89q.guavabackport.cache.CacheBuilder; -import com.sk89q.guavabackport.cache.CacheLoader; -import com.sk89q.guavabackport.cache.LoadingCache; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.plugin.PluginManager; - -import java.util.concurrent.TimeUnit; +import org.bukkit.util.Vector; public class PlayerMoveListener implements Listener { private final WorldGuardPlugin plugin; - private LoadingCache bypassCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .expireAfterAccess(5, TimeUnit.SECONDS) - .build(new CacheLoader() { - @Override - public Boolean load(WorldPlayerTuple tuple) throws Exception { - return plugin.getGlobalRegionManager().hasBypass(tuple.player, tuple.world); - } - }); public PlayerMoveListener(WorldGuardPlugin plugin) { this.plugin = plugin; @@ -71,196 +50,56 @@ public void registerEvents() { } } - private boolean hasBypass(Player player, World world) { - return bypassCache.getUnchecked(new WorldPlayerTuple(world, player)); - } + @EventHandler + public void onPlayerRespawn(PlayerRespawnEvent event) { + Player player = event.getPlayer(); - /** - * Handles movement related events, including changing gamemode, sending - * greeting/farewell messages, etc. - * - * @param from The before location - * @param to The to location - * @return True if the movement should not be allowed - */ - public boolean shouldDenyMove(Player player, Location from, Location to) { - PlayerFlagState state = plugin.getFlagStateManager().getState(player); - - // Flush states in multi-world scenario - if (state.lastWorld != null && !state.lastWorld.equals(to.getWorld())) { - plugin.getFlagStateManager().forget(player); - state = plugin.getFlagStateManager().getState(player); - } - - // TODO: Clean up this disaster - - World world = from.getWorld(); - World toWorld = to.getWorld(); - - LocalPlayer localPlayer = plugin.wrapPlayer(player); - boolean hasBypass = hasBypass(player, world); - boolean hasRemoteBypass; - if (world.equals(toWorld)) { - hasRemoteBypass = hasBypass; - } else { - hasRemoteBypass = hasBypass(player, toWorld); - } - - RegionManager regions = plugin.getGlobalRegionManager().get(toWorld); - if (regions == null) { - return false; - } - - Vector pt = new Vector(to.getBlockX(), to.getBlockY(), to.getBlockZ()); - ApplicableRegionSet set = regions.getApplicableRegions(pt); - - boolean entryAllowed = set.allows(DefaultFlag.ENTRY, localPlayer); - if (!hasRemoteBypass && !entryAllowed) { - player.sendMessage(ChatColor.DARK_RED + "You are not permitted to enter this area."); - return true; - } - - // Have to set this state - if (state.lastExitAllowed == null) { - state.lastExitAllowed = plugin.getRegionContainer().createQuery().getApplicableRegions(from).allows(DefaultFlag.EXIT, localPlayer); - } - - boolean exitAllowed = set.allows(DefaultFlag.EXIT, localPlayer); - if (!hasBypass && exitAllowed && !state.lastExitAllowed) { - player.sendMessage(ChatColor.DARK_RED + "You are not permitted to leave this area."); - return true; - } - - String greeting = set.getFlag(DefaultFlag.GREET_MESSAGE); - String farewell = set.getFlag(DefaultFlag.FAREWELL_MESSAGE); - Boolean notifyEnter = set.getFlag(DefaultFlag.NOTIFY_ENTER); - Boolean notifyLeave = set.getFlag(DefaultFlag.NOTIFY_LEAVE); - GameMode gameMode = set.getFlag(DefaultFlag.GAME_MODE); - - if (state.lastFarewell != null && (farewell == null || !state.lastFarewell.equals(farewell))) { - String replacedFarewell = plugin.replaceMacros(player, BukkitUtil.replaceColorMacros(state.lastFarewell)); - player.sendMessage(replacedFarewell.replaceAll("\\\\n", "\n").split("\\n")); - } - - if (greeting != null && (state.lastGreeting == null || !state.lastGreeting.equals(greeting))) { - String replacedGreeting = plugin.replaceMacros(player, BukkitUtil.replaceColorMacros(greeting)); - player.sendMessage(replacedGreeting.replaceAll("\\\\n", "\n").split("\\n")); - } - - if ((notifyLeave == null || !notifyLeave) && state.notifiedForLeave != null && state.notifiedForLeave) { - plugin.broadcastNotification(ChatColor.GRAY + "WG: " - + ChatColor.LIGHT_PURPLE + player.getName() - + ChatColor.GOLD + " left NOTIFY region"); - } - - if (notifyEnter != null && notifyEnter && (state.notifiedForEnter == null || !state.notifiedForEnter)) { - StringBuilder regionList = new StringBuilder(); - - for (ProtectedRegion region : set) { - if (regionList.length() != 0) { - regionList.append(", "); - } - - regionList.append(region.getId()); - } - - plugin.broadcastNotification(ChatColor.GRAY + "WG: " - + ChatColor.LIGHT_PURPLE + player.getName() - + ChatColor.GOLD + " entered NOTIFY region: " - + ChatColor.WHITE - + regionList); - } - - if (!hasBypass && gameMode != null) { - if (player.getGameMode() != gameMode) { - state.lastGameMode = player.getGameMode(); - player.setGameMode(gameMode); - } else if (state.lastGameMode == null) { - state.lastGameMode = player.getServer().getDefaultGameMode(); - } - } else { - if (state.lastGameMode != null) { - GameMode mode = state.lastGameMode; - state.lastGameMode = null; - player.setGameMode(mode); - } - } - - state.lastGreeting = greeting; - state.lastFarewell = farewell; - state.notifiedForEnter = notifyEnter; - state.notifiedForLeave = notifyLeave; - state.lastExitAllowed = exitAllowed; - state.lastWorld = to.getWorld(); - state.lastBlockX = to.getBlockX(); - state.lastBlockY = to.getBlockY(); - state.lastBlockZ = to.getBlockZ(); - return false; + Session session = plugin.getSessionManager().get(player); + session.testMoveTo(player, event.getRespawnLocation(), MoveType.RESPAWN, true); } @EventHandler(priority = EventPriority.HIGH) public void onPlayerMove(PlayerMoveEvent event) { final Player player = event.getPlayer(); - World world = player.getWorld(); - ConfigurationManager cfg = plugin.getGlobalStateManager(); - WorldConfiguration wcfg = cfg.get(world); + Session session = plugin.getSessionManager().get(player); + final Location override = session.testMoveTo(player, event.getTo(), MoveType.MOVE); - if (wcfg.useRegions) { - if (hasMoved(event.getFrom(), event.getTo())) { - if (shouldDenyMove(player, event.getFrom(), event.getTo())) { - Location newLoc = event.getFrom(); - newLoc.setX(newLoc.getBlockX() + 0.5); - newLoc.setY(newLoc.getBlockY()); - newLoc.setZ(newLoc.getBlockZ() + 0.5); - event.setTo(newLoc); + if (override != null) { + override.setX(override.getBlockX() + 0.5); + override.setY(override.getBlockY()); + override.setZ(override.getBlockZ() + 0.5); + override.setPitch(event.getTo().getPitch()); + override.setYaw(event.getTo().getYaw()); - Entity vehicle = player.getVehicle(); - if (vehicle != null) { - vehicle.eject(); - vehicle.teleport(newLoc); - player.teleport(newLoc); - vehicle.setPassenger(player); + event.setTo(override.clone()); + + Entity vehicle = player.getVehicle(); + if (vehicle != null) { + vehicle.eject(); + + Entity current = vehicle; + while (current != null) { + current.eject(); + vehicle.setVelocity(new Vector()); + if (vehicle instanceof LivingEntity) { + vehicle.teleport(override.clone()); + } else { + vehicle.teleport(override.clone().add(0, 1, 0)); } + current = current.getVehicle(); } + + player.teleport(override.clone().add(0, 1, 0)); + + Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { + @Override + public void run() { + player.teleport(override.clone().add(0, 1, 0)); + } + }, 1); } } } - private static boolean hasMoved(Location loc1, Location loc2) { - return loc1.getBlockX() != loc2.getBlockX() - || loc1.getBlockY() != loc2.getBlockY() - || loc1.getBlockZ() != loc2.getBlockZ(); - } - - private static class WorldPlayerTuple { - private final World world; - private final Player player; - - private WorldPlayerTuple(World world, Player player) { - this.world = world; - this.player = player; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - WorldPlayerTuple that = (WorldPlayerTuple) o; - - if (!player.equals(that.player)) return false; - if (!world.equals(that.world)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = world.hashCode(); - result = 31 * result + player.hashCode(); - return result; - } - } - } diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java index 0282f330..9fa63334 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardEntityListener.java @@ -21,59 +21,21 @@ import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.bukkit.BukkitUtil; -import com.sk89q.worldguard.bukkit.ConfigurationManager; -import com.sk89q.worldguard.bukkit.RegionQuery; -import com.sk89q.worldguard.bukkit.WorldConfiguration; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.bukkit.internal.RegionQueryUtil; +import com.sk89q.worldguard.bukkit.*; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.GlobalRegionManager; import com.sk89q.worldguard.protection.flags.DefaultFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.entity.Creeper; -import org.bukkit.entity.EnderDragon; -import org.bukkit.entity.Enderman; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Fireball; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.entity.Tameable; -import org.bukkit.entity.ThrownPotion; -import org.bukkit.entity.Wither; -import org.bukkit.entity.WitherSkull; -import org.bukkit.entity.Wolf; +import org.bukkit.entity.*; import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.event.entity.CreeperPowerEvent; -import org.bukkit.event.entity.EntityBreakDoorEvent; -import org.bukkit.event.entity.EntityChangeBlockEvent; -import org.bukkit.event.entity.EntityCombustEvent; -import org.bukkit.event.entity.EntityCreatePortalEvent; -import org.bukkit.event.entity.EntityDamageByBlockEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.entity.EntityInteractEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.ExplosionPrimeEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; -import org.bukkit.event.entity.PigZapEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.entity.PotionSplashEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; @@ -144,7 +106,7 @@ private void onEntityDamageByBlock(EntityDamageByBlockEvent event) { } else if (defender instanceof Player) { Player player = (Player) defender; - if (isInvincible(player)) { + if (plugin.getSessionManager().get(player).isInvincible(player)) { event.setCancelled(true); return; } @@ -216,7 +178,7 @@ private void onEntityDamageByEntity(EntityDamageByEntityEvent event) { ConfigurationManager cfg = plugin.getGlobalStateManager(); WorldConfiguration wcfg = cfg.get(player.getWorld()); - if (isInvincible(player)) { + if (plugin.getSessionManager().get(player).isInvincible(player)) { if (wcfg.regionInvinciblityRemovesMobs && attacker instanceof LivingEntity && !(attacker instanceof Player) && !(attacker instanceof Tameable && ((Tameable) attacker).isTamed())) { @@ -323,7 +285,7 @@ private void onEntityDamageByProjectile(EntityDamageByEntityEvent event) { WorldConfiguration wcfg = cfg.get(player.getWorld()); // Check Invincible - if (isInvincible(player)) { + if (plugin.getSessionManager().get(player).isInvincible(player)) { event.setCancelled(true); return; } @@ -375,7 +337,7 @@ public void onEntityDamage(EntityDamageEvent event) { } else if (defender instanceof Player) { Player player = (Player) defender; - if (isInvincible(player)) { + if (plugin.getSessionManager().get(player).isInvincible(player)) { event.setCancelled(true); player.setFireTicks(0); return; @@ -455,9 +417,8 @@ public void onEntityCombust(EntityCombustEvent event) { if (entity instanceof Player) { Player player = (Player) entity; - if (cfg.hasGodMode(player) || (wcfg.useRegions && RegionQueryUtil.isInvincible(plugin, player))) { + if (plugin.getSessionManager().get(player).isInvincible(player)) { event.setCancelled(true); - return; } } } @@ -762,41 +723,12 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) { public void onFoodLevelChange(FoodLevelChangeEvent event) { if (event.getEntity() instanceof Player) { Player player = (Player) event.getEntity(); - if (event.getFoodLevel() < player.getFoodLevel() && isInvincible(player)) { + if (event.getFoodLevel() < player.getFoodLevel() && plugin.getSessionManager().get(player).isInvincible(player)) { event.setCancelled(true); } } } - /** - * Check if a player is invincible, via either god mode or region flag. If - * the region denies invincibility, the player must have an extra permission - * to override it. (worldguard.god.override-regions) - * - * @param player The player to check - * @return Whether {@code player} is invincible - */ - private boolean isInvincible(Player player) { - ConfigurationManager cfg = plugin.getGlobalStateManager(); - WorldConfiguration wcfg = cfg.get(player.getWorld()); - - boolean god = cfg.hasGodMode(player); - if (wcfg.useRegions) { - Boolean flag = RegionQueryUtil.isAllowedInvinciblity(plugin, player); - boolean allowed = flag == null || flag; - boolean invincible = RegionQueryUtil.isInvincible(plugin, player); - - if (allowed) { - return god || invincible; - } else { - return (god && plugin.hasPermission(player, "worldguard.god.override-regions")) - || invincible; - } - } else { - return god; - } - } - /** * Checks regions and config settings to protect items from being knocked * out of item frames. diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java index 8bb82e72..84a3b88e 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardPlayerListener.java @@ -26,11 +26,12 @@ import com.sk89q.worldguard.bukkit.WorldConfiguration; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent; -import com.sk89q.worldguard.bukkit.listener.FlagStateManager.PlayerFlagState; import com.sk89q.worldguard.bukkit.util.Events; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.handler.GameModeFlag; import com.sk89q.worldguard.util.command.CommandFilter; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -83,10 +84,10 @@ public void registerEvents() { public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { Player player = event.getPlayer(); WorldConfiguration wcfg = plugin.getGlobalStateManager().get(player.getWorld()); - if (wcfg.useRegions && !plugin.getGlobalRegionManager().hasBypass(player, player.getWorld())) { - GameMode gameMode = plugin.getRegionContainer().createQuery().getApplicableRegions(player.getLocation()).getFlag(DefaultFlag.GAME_MODE); - if (plugin.getFlagStateManager().getState(player).lastGameMode != null - && gameMode != null && event.getNewGameMode() != gameMode) { + GameModeFlag handler = plugin.getSessionManager().get(player).getHandler(GameModeFlag.class); + if (handler != null && wcfg.useRegions && !plugin.getGlobalRegionManager().hasBypass(player, player.getWorld())) { + GameMode expected = handler.getSetGameMode(); + if (expected != event.getNewGameMode()) { event.setCancelled(true); } } @@ -126,14 +127,7 @@ public void onPlayerJoin(PlayerJoinEvent event) { Events.fire(new ProcessPlayerEvent(player)); - if (wcfg.useRegions) { - PlayerFlagState state = plugin.getFlagStateManager().getState(player); - Location loc = player.getLocation(); - state.lastWorld = loc.getWorld(); - state.lastBlockX = loc.getBlockX(); - state.lastBlockY = loc.getBlockY(); - state.lastBlockZ = loc.getBlockZ(); - } + plugin.getSessionManager().get(player); // Initializes a session } @EventHandler(ignoreCancelled = true) @@ -186,46 +180,6 @@ public void onPlayerLogin(PlayerLoginEvent event) { } } - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - World world = player.getWorld(); - - ConfigurationManager cfg = plugin.getGlobalStateManager(); - WorldConfiguration wcfg = cfg.get(world); - - // This is to make the enter/exit flags accurate -- move events are not - // sent constantly, so it is possible to move just a little enough to - // not trigger the event and then rejoin so that you are then considered - // outside the border. This should work around that. - if (wcfg.useRegions) { - boolean hasBypass = plugin.getGlobalRegionManager().hasBypass(player, world); - PlayerFlagState state = plugin.getFlagStateManager().getState(player); - - if (state.lastWorld != null && !hasBypass) { - LocalPlayer localPlayer = plugin.wrapPlayer(player); - Location loc = player.getLocation(); - ApplicableRegionSet set = plugin.getRegionContainer().createQuery().getApplicableRegions(loc); - - if (state.lastExitAllowed == null) { - state.lastExitAllowed = set.allows(DefaultFlag.EXIT, localPlayer); - } - - if (!state.lastExitAllowed || !set.allows(DefaultFlag.ENTRY, localPlayer)) { - // Only if we have the last location cached - if (state.lastWorld.equals(world)) { - Location newLoc = new Location(world, state.lastBlockX + 0.5, - state.lastBlockY, state.lastBlockZ + 0.5); - player.teleport(newLoc); - } - } - } - } - - cfg.forgetPlayer(plugin.wrapPlayer(player)); - plugin.forgetPlayer(player); - } - @EventHandler(priority = EventPriority.HIGH) public void onPlayerInteract(PlayerInteractEvent event) { Player player = event.getPlayer(); @@ -378,20 +332,20 @@ public void onItemHeldChange(PlayerItemHeldEvent event) { } } - @EventHandler(priority= EventPriority.LOW, ignoreCancelled = true) + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerTeleport(PlayerTeleportEvent event) { World world = event.getFrom().getWorld(); + Player player = event.getPlayer(); ConfigurationManager cfg = plugin.getGlobalStateManager(); WorldConfiguration wcfg = cfg.get(world); if (wcfg.useRegions) { ApplicableRegionSet set = plugin.getRegionContainer().createQuery().getApplicableRegions(event.getTo()); ApplicableRegionSet setFrom = plugin.getRegionContainer().createQuery().getApplicableRegions(event.getFrom()); - LocalPlayer localPlayer = plugin.wrapPlayer(event.getPlayer()); + LocalPlayer localPlayer = plugin.wrapPlayer(player); if (cfg.usePlayerTeleports) { - boolean result = plugin.getPlayerMoveListener().shouldDenyMove(event.getPlayer(), event.getFrom(), event.getTo()); - if (result) { + if (null != plugin.getSessionManager().get(player).testMoveTo(player, event.getTo(), MoveType.TELEPORT)) { event.setCancelled(true); return; } @@ -401,7 +355,7 @@ public void onPlayerTeleport(PlayerTeleportEvent event) { if (!plugin.getGlobalRegionManager().hasBypass(localPlayer, world) && !(set.allows(DefaultFlag.ENDERPEARL, localPlayer) && setFrom.allows(DefaultFlag.ENDERPEARL, localPlayer))) { - event.getPlayer().sendMessage(ChatColor.DARK_RED + "You're not allowed to go there."); + player.sendMessage(ChatColor.DARK_RED + "You're not allowed to go there."); event.setCancelled(true); return; } diff --git a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardVehicleListener.java b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardVehicleListener.java index d5807334..55d4eb4c 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardVehicleListener.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/listener/WorldGuardVehicleListener.java @@ -22,12 +22,15 @@ import com.sk89q.worldguard.bukkit.ConfigurationManager; import com.sk89q.worldguard.bukkit.WorldConfiguration; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.bukkit.util.Locations; +import com.sk89q.worldguard.session.MoveType; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.util.Vector; public class WorldGuardVehicleListener implements Listener { @@ -52,8 +55,7 @@ public void registerEvents() { @EventHandler public void onVehicleMove(VehicleMoveEvent event) { Vehicle vehicle = event.getVehicle(); - if (vehicle.getPassenger() == null - || !(vehicle.getPassenger() instanceof Player)) return; + if (vehicle.getPassenger() == null || !(vehicle.getPassenger() instanceof Player)) return; Player player = (Player) vehicle.getPassenger(); World world = vehicle.getWorld(); ConfigurationManager cfg = plugin.getGlobalStateManager(); @@ -61,12 +63,9 @@ public void onVehicleMove(VehicleMoveEvent event) { if (wcfg.useRegions) { // Did we move a block? - if (event.getFrom().getBlockX() != event.getTo().getBlockX() - || event.getFrom().getBlockY() != event.getTo().getBlockY() - || event.getFrom().getBlockZ() != event.getTo().getBlockZ()) { - boolean result = plugin.getPlayerMoveListener().shouldDenyMove(player, event.getFrom(), event.getTo()); - if (result) { - vehicle.setVelocity(new org.bukkit.util.Vector(0,0,0)); + if (Locations.isDifferentBlock(event.getFrom(), event.getTo())) { + if (null != plugin.getSessionManager().get(player).testMoveTo(player, event.getTo(), MoveType.RIDE)) { + vehicle.setVelocity(new Vector(0,0,0)); vehicle.teleport(event.getFrom()); } } diff --git a/src/main/java/com/sk89q/worldguard/protection/flags/DefaultFlag.java b/src/main/java/com/sk89q/worldguard/protection/flags/DefaultFlag.java index c960f9c9..0f0db962 100644 --- a/src/main/java/com/sk89q/worldguard/protection/flags/DefaultFlag.java +++ b/src/main/java/com/sk89q/worldguard/protection/flags/DefaultFlag.java @@ -96,7 +96,7 @@ public final class DefaultFlag { public static final StateFlag SEND_CHAT = new StateFlag("send-chat", true); public static final StateFlag RECEIVE_CHAT = new StateFlag("receive-chat", true); public static final StateFlag ENTRY = new StateFlag("entry", true, RegionGroup.NON_MEMBERS); - public static final StateFlag EXIT = new StateFlag("exit", true, RegionGroup.NON_MEMBERS); + public static final StateFlag EXIT = new StateFlag("exit", false, RegionGroup.NON_MEMBERS); public static final StateFlag ENDERPEARL = new StateFlag("enderpearl", true); public static final StateFlag ENTITY_PAINTING_DESTROY = new StateFlag("entity-painting-destroy", true); public static final StateFlag ENTITY_ITEM_FRAME_DESTROY = new StateFlag("entity-item-frame-destroy", true); @@ -104,6 +104,10 @@ public final class DefaultFlag { // Flags that adjust behaviors that aren't state flags public static final StringFlag DENY_MESSAGE = new StringFlag("deny-message", "" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " Sorry, but you can't %what% here."); + public static final StringFlag ENTRY_DENY_MESSAGE = new StringFlag("entry-deny-message", + "" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " You are not permitted to enter this area."); + public static final StringFlag EXIT_DENY_MESSAGE = new StringFlag("exit-deny-message", + "" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " You are not permitted to leave this area."); public static final StringFlag GREET_MESSAGE = new StringFlag("greeting"); public static final StringFlag FAREWELL_MESSAGE = new StringFlag("farewell"); public static final BooleanFlag NOTIFY_ENTER = new BooleanFlag("notify-enter"); @@ -133,7 +137,8 @@ public final class DefaultFlag { TNT, LIGHTER, RIDE, USE, INTERACT, PLACE_VEHICLE, DESTROY_VEHICLE, SLEEP, MOB_DAMAGE, MOB_SPAWNING, DENY_SPAWN, INVINCIBILITY, EXP_DROPS, CREEPER_EXPLOSION, OTHER_EXPLOSION, ENDERDRAGON_BLOCK_DAMAGE, GHAST_FIREBALL, ENDER_BUILD, - DENY_MESSAGE, GREET_MESSAGE, FAREWELL_MESSAGE, NOTIFY_ENTER, NOTIFY_LEAVE, + DENY_MESSAGE, ENTRY_DENY_MESSAGE, EXIT_DENY_MESSAGE, + GREET_MESSAGE, FAREWELL_MESSAGE, NOTIFY_ENTER, NOTIFY_LEAVE, EXIT, ENTRY, LIGHTNING, ENTITY_PAINTING_DESTROY, ENDERPEARL, ENTITY_ITEM_FRAME_DESTROY, ITEM_PICKUP, ITEM_DROP, /*MAX_PLAYERS, MAX_PLAYERS_MESSAGE,*/ HEAL_AMOUNT, HEAL_DELAY, MIN_HEAL, MAX_HEAL, diff --git a/src/main/java/com/sk89q/worldguard/session/MoveType.java b/src/main/java/com/sk89q/worldguard/session/MoveType.java new file mode 100644 index 00000000..037741af --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/MoveType.java @@ -0,0 +1,48 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session; + +import org.bukkit.Location; + +/** + * Types of movements. + * + *

Used with {@link Session#testMoveTo(Location, MoveType)}.

+ */ +public enum MoveType { + + RESPAWN(false), + MOVE(true), + TELEPORT(true), + RIDE(true), + OTHER_NON_CANCELLABLE(false), + OTHER_CANCELLABLE(true); + + private final boolean cancellable; + + MoveType(boolean cancellable) { + this.cancellable = cancellable; + } + + public boolean isCancellable() { + return cancellable; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/Session.java b/src/main/java/com/sk89q/worldguard/session/Session.java new file mode 100644 index 00000000..55c2f9da --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/Session.java @@ -0,0 +1,222 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.sk89q.worldguard.bukkit.RegionQuery; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.bukkit.util.Locations; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.handler.Handler; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Keeps session information on a player. + */ +public class Session { + + private final SessionManager manager; + private final HashMap, Handler> handlers = Maps.newLinkedHashMap(); + private Location lastValid; + private Set lastRegionSet; + + /** + * Create a new session. + * + * @param manager The session manager + */ + public Session(SessionManager manager) { + checkNotNull(manager, "manager"); + this.manager = manager; + } + + /** + * Register a new handler. + * + * @param handler A new handler + */ + void register(Handler handler) { + handlers.put(handler.getClass(), handler); + } + + /** + * Get the plugin. + * + * @return The plugin + */ + public WorldGuardPlugin getPlugin() { + return getManager().getPlugin(); + } + + /** + * Get the session manager. + * + * @return The session manager + */ + public SessionManager getManager() { + return manager; + } + + /** + * Get a handler by class, if has been registered. + * + * @param type The type of handler + * @param The type of handler + * @return A handler instance, otherwise null + */ + @Nullable + @SuppressWarnings("unchecked") + public T getHandler(Class type) { + return (T) handlers.get(type); + } + + /** + * Initialize the session. + * + * @param player The player + */ + void initialize(Player player) { + RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery(); + Location location = player.getLocation(); + ApplicableRegionSet set = query.getApplicableRegions(location); + + lastValid = location; + lastRegionSet = set.getRegions(); + + for (Handler handler : handlers.values()) { + handler.initialize(player, location, set); + } + } + + /** + * Tick the session. + * + * @param player The player + */ + void tick(Player player) { + RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery(); + Location location = player.getLocation(); + ApplicableRegionSet set = query.getApplicableRegions(location); + + for (Handler handler : handlers.values()) { + handler.tick(player, set); + } + } + + /** + * Re-initialize the session. + * + * @param player The player + */ + void resetState(Player player) { + initialize(player); + } + + /** + * Test whether the session has invincibility enabled. + * + * @return Whether invincibility is enabled + */ + public boolean isInvincible(Player player) { + boolean invincible = false; + + for (Handler handler : handlers.values()) { + State state = handler.getInvincibility(player); + if (state != null) { + switch (state) { + case DENY: return false; + case ALLOW: invincible = true; + } + } + } + + return invincible; + } + + /** + * Test movement to the given location. + * + * @param player The player + * @param to The new location + * @param moveType The type of move + * @return The overridden location, if the location is being overridden + * @see #testMoveTo(Player, Location, MoveType, boolean) For an explanation + */ + @Nullable + public Location testMoveTo(Player player, Location to, MoveType moveType) { + return testMoveTo(player, to, moveType, false); + } + + /** + * Test movement to the given location. + * + *

If a non-null {@link Location} is returned, the player should be + * at that location instead of where the player has tried to move to.

+ * + *

If the {@code moveType} is cancellable + * ({@link MoveType#isCancellable()}, then the last valid location will + * be set to the given one.

+ * + * @param player The player + * @param to The new location + * @param moveType The type of move + * @param forced Whether to force a check + * @return The overridden location, if the location is being overridden + */ + @Nullable + public Location testMoveTo(Player player, Location to, MoveType moveType, boolean forced) { + RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery(); + + if (forced || Locations.isDifferentBlock(lastValid, to)) { + ApplicableRegionSet toSet = query.getApplicableRegions(to); + + for (Handler handler : handlers.values()) { + if (!handler.testMoveTo(player, lastValid, to, toSet, moveType) && moveType.isCancellable()) { + return lastValid; + } + } + + Set entered = Sets.difference(toSet.getRegions(), lastRegionSet); + Set exited = Sets.difference(lastRegionSet, toSet.getRegions()); + + for (Handler handler : handlers.values()) { + if (!handler.onCrossBoundary(player, lastValid, to, toSet, entered, exited, moveType) && moveType.isCancellable()) { + return lastValid; + } + } + + lastValid = to; + lastRegionSet = toSet.getRegions(); + } + + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/SessionManager.java b/src/main/java/com/sk89q/worldguard/session/SessionManager.java new file mode 100644 index 00000000..ef6d4b18 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/SessionManager.java @@ -0,0 +1,219 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session; + +import com.sk89q.guavabackport.cache.CacheBuilder; +import com.sk89q.guavabackport.cache.CacheLoader; +import com.sk89q.guavabackport.cache.LoadingCache; +import com.sk89q.worldguard.bukkit.BukkitUtil; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.session.handler.*; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Keeps tracks of sessions and also does session-related handling + * (flags, etc.). + */ +public class SessionManager implements Runnable, Listener { + + public static final int RUN_DELAY = 20; + public static final long SESSION_LIFETIME = 10; + + private final WorldGuardPlugin plugin; + + private final LoadingCache bypassCache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterAccess(2, TimeUnit.SECONDS) + .build(new CacheLoader() { + @Override + public Boolean load(WorldPlayerTuple tuple) throws Exception { + return plugin.getGlobalRegionManager().hasBypass(tuple.player, tuple.world); + } + }); + + private final LoadingCache sessions = CacheBuilder.newBuilder() + .expireAfterAccess(SESSION_LIFETIME, TimeUnit.MINUTES) + .build(new CacheLoader() { + @Override + public Session load(CacheKey key) throws Exception { + return createSession(key.playerRef.get()); + } + }); + + /** + * Create a new instance. + * + * @param plugin The plugin + */ + public SessionManager(WorldGuardPlugin plugin) { + checkNotNull(plugin, "plugin"); + this.plugin = plugin; + } + + /** + * Get the plugin. + * + * @return The plugin + */ + public WorldGuardPlugin getPlugin() { + return plugin; + } + + /** + * Check whether a player has the region bypass permission. + * + *

The return value may be cached for a few seconds.

+ * + * @param player The player + * @param world The world + * @return A value + */ + public boolean hasBypass(Player player, World world) { + return bypassCache.getUnchecked(new WorldPlayerTuple(world, player)); + } + + /** + * Re-initialize handlers and clear "last position," "last state," etc. + * information for all players. + */ + public void resetAllStates() { + Collection players = BukkitUtil.getOnlinePlayers(); + for (Player player : players) { + Session session = sessions.getIfPresent(player); + if (session != null) { + session.resetState(player); + } + } + } + + /** + * Re-initialize handlers and clear "last position," "last state," etc. + * information. + * + * @param player The player + */ + public void resetState(Player player) { + checkNotNull(player, "player"); + @Nullable Session session = sessions.getIfPresent(player); + if (session != null) { + session.resetState(player); + } + } + + /** + * Create a session for a player. + * + * @param player The player + * @return The new session + */ + private Session createSession(Player player) { + Session session = new Session(this); + session.register(new HealFlag(session)); + session.register(new FeedFlag(session)); + session.register(new NotifyEntryFlag(session)); + session.register(new NotifyExitFlag(session)); + session.register(new EntryFlag(session)); + session.register(new ExitFlag(session)); + session.register(new GreetingFlag(session)); + session.register(new FarewellFlag(session)); + session.register(new GameModeFlag(session)); + session.register(new InvincibilityFlag(session)); + session.register(new GodMode(session)); + session.register(new WaterBreathing(session)); + session.initialize(player); + return session; + } + + /** + * Get a player's session, if one exists. + * + * @param player The player + * @return The session + */ + @Nullable + public Session getIfPresent(Player player) { + return sessions.getIfPresent(player); + } + + /** + * Get a player's session. A session will be created if there is no + * existing session for the player. + * + *

This method can only be called from the main thread. While the + * session manager itself is thread-safe, some of the handlers may + * require initialization that requires the server main thread.

+ * + * @param player The player to get a session for + * @return The {@code player}'s session + */ + public Session get(Player player) { + return sessions.getUnchecked(new CacheKey(player)); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + // Pre-load a session + get(event.getPlayer()); + } + + @Override + public void run() { + for (Player player : BukkitUtil.getOnlinePlayers()) { + get(player).tick(player); + } + } + + private static final class CacheKey { + private final WeakReference playerRef; + private final UUID uuid; + + private CacheKey(Player player) { + playerRef = new WeakReference(player); + uuid = player.getUniqueId(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CacheKey cacheKey = (CacheKey) o; + return uuid.equals(cacheKey.uuid); + + } + + @Override + public int hashCode() { + return uuid.hashCode(); + } + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/WorldPlayerTuple.java b/src/main/java/com/sk89q/worldguard/session/WorldPlayerTuple.java new file mode 100644 index 00000000..02d4d115 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/WorldPlayerTuple.java @@ -0,0 +1,55 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +class WorldPlayerTuple { + + final World world; + final Player player; + + WorldPlayerTuple(World world, Player player) { + this.world = world; + this.player = player; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + WorldPlayerTuple that = (WorldPlayerTuple) o; + + if (!player.equals(that.player)) return false; + if (!world.equals(that.world)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = world.hashCode(); + result = 31 * result + player.hashCode(); + return result; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/EntryFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/EntryFlag.java new file mode 100644 index 00000000..8f7dd4ca --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/EntryFlag.java @@ -0,0 +1,60 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class EntryFlag extends Handler { + + private static final long MESSAGE_THRESHOLD = 1000 * 2; + private long lastMessage; + + public EntryFlag(Session session) { + super(session); + } + + @Override + public boolean testMoveTo(Player player, Location from, Location to, ApplicableRegionSet toSet, MoveType moveType) { + LocalPlayer localPlayer = getPlugin().wrapPlayer(player); + boolean allowed = toSet.testState(localPlayer, DefaultFlag.ENTRY); + + if (!getSession().getManager().hasBypass(player, to.getWorld()) && !allowed && moveType.isCancellable()) { + String message = toSet.queryValue(localPlayer, DefaultFlag.ENTRY_DENY_MESSAGE); + long now = System.currentTimeMillis(); + + if ((now - lastMessage) > MESSAGE_THRESHOLD && message != null && !message.isEmpty()) { + player.sendMessage(message); + lastMessage = now; + } + + return false; + } else { + return true; + } + } + + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/ExitFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/ExitFlag.java new file mode 100644 index 00000000..6534e80b --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/ExitFlag.java @@ -0,0 +1,85 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class ExitFlag extends FlagValueChangeHandler { + + private static final long MESSAGE_THRESHOLD = 1000 * 2; + private String storedMessage; + private long lastMessage; + + public ExitFlag(Session session) { + super(session, DefaultFlag.EXIT); + } + + private void update(LocalPlayer localPlayer, ApplicableRegionSet set, State newState) { + if (newState == State.DENY) { + storedMessage = set.queryValue(localPlayer, DefaultFlag.EXIT_DENY_MESSAGE); + } + } + + private void sendMessage(Player player) { + long now = System.currentTimeMillis(); + + if ((now - lastMessage) > MESSAGE_THRESHOLD && storedMessage != null && !storedMessage.isEmpty()) { + player.sendMessage(storedMessage); + lastMessage = now; + } + } + + @Override + protected void onInitialValue(Player player, ApplicableRegionSet set, State value) { + update(getPlugin().wrapPlayer(player), set, value); + } + + @Override + protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State currentValue, State lastValue, MoveType moveType) { + if (getSession().getManager().hasBypass(player, from.getWorld())) { + return true; + } + + update(getPlugin().wrapPlayer(player), toSet, currentValue); + return true; + } + + @Override + protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State lastValue, MoveType moveType) { + if (getSession().getManager().hasBypass(player, from.getWorld())) { + return true; + } + + if (lastValue == State.DENY) { + sendMessage(player); + return false; + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/FarewellFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/FarewellFlag.java new file mode 100644 index 00000000..b0ee2763 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/FarewellFlag.java @@ -0,0 +1,78 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.google.common.collect.Sets; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.Set; + +public class FarewellFlag extends Handler { + + private Set lastMessageStack = Collections.emptySet(); + + public FarewellFlag(Session session) { + super(session); + } + + private Set getMessages(Player player, ApplicableRegionSet set) { + return Sets.newLinkedHashSet(set.queryAllValues(getPlugin().wrapPlayer(player), DefaultFlag.FAREWELL_MESSAGE)); + } + + @Override + public void initialize(Player player, Location current, ApplicableRegionSet set) { + lastMessageStack = getMessages(player, set); + } + + @Override + public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set entered, Set exited, MoveType moveType) { + Set messages = getMessages(player, toSet); + + if (!messages.isEmpty()) { + // Due to flag priorities, we have to collect the lower + // priority flag values separately + for (ProtectedRegion region : toSet) { + String message = region.getFlag(DefaultFlag.FAREWELL_MESSAGE); + if (message != null) { + messages.add(message); + } + } + } + + for (String message : lastMessageStack) { + if (!messages.contains(message)) { + player.sendMessage(getPlugin().replaceMacros(player, message).replaceAll("\\\\n", "\n").split("\\n")); + break; + } + } + + lastMessageStack = messages; + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/FeedFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/FeedFlag.java new file mode 100644 index 00000000..dd1a32b6 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/FeedFlag.java @@ -0,0 +1,77 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.session.Session; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +public class FeedFlag extends Handler { + + private long lastFeed = 0; + + public FeedFlag(Session session) { + super(session); + } + + @Override + public void tick(Player player, ApplicableRegionSet set) { + if (!getSession().isInvincible(player) && player.getGameMode() != GameMode.CREATIVE) { + long now = System.currentTimeMillis(); + + Integer feedAmount = set.getFlag(DefaultFlag.FEED_AMOUNT); + Integer feedDelay = set.getFlag(DefaultFlag.FEED_DELAY); + Integer minHunger = set.getFlag(DefaultFlag.MIN_FOOD); + Integer maxHunger = set.getFlag(DefaultFlag.MAX_FOOD); + + if (feedAmount == null || feedDelay == null || feedAmount == 0 || feedDelay < 0) { + return; + } + if (minHunger == null) { + minHunger = 0; + } + if (maxHunger == null) { + maxHunger = 20; + } + + // Apply a cap to prevent possible exceptions + minHunger = Math.min(20, minHunger); + maxHunger = Math.min(20, maxHunger); + + if (player.getFoodLevel() >= maxHunger && feedAmount > 0) { + return; + } + + if (feedDelay <= 0) { + player.setFoodLevel(feedAmount > 0 ? maxHunger : minHunger); + player.setSaturation(player.getFoodLevel()); + lastFeed = now; + } else if (now - lastFeed > feedDelay * 1000) { + // clamp health between minimum and maximum + player.setFoodLevel(Math.min(maxHunger, Math.max(minHunger, player.getFoodLevel() + feedAmount))); + player.setSaturation(player.getFoodLevel()); + lastFeed = now; + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/FlagValueChangeHandler.java b/src/main/java/com/sk89q/worldguard/session/handler/FlagValueChangeHandler.java new file mode 100644 index 00000000..3df398a0 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/FlagValueChangeHandler.java @@ -0,0 +1,74 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.Set; + +public abstract class FlagValueChangeHandler extends Handler { + + private final Flag flag; + private T lastValue; + + protected FlagValueChangeHandler(Session session, Flag flag) { + super(session); + this.flag = flag; + } + + @Override + public final void initialize(Player player, Location current, ApplicableRegionSet set) { + lastValue = set.queryValue(getPlugin().wrapPlayer(player), flag); + if (lastValue != null) { + onInitialValue(player, set, lastValue); + } + } + + @Override + public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set entered, Set exited, MoveType moveType) { + T currentValue = toSet.queryValue(getPlugin().wrapPlayer(player), flag); + boolean allowed = true; + + if (currentValue == null && lastValue != null) { + allowed = onAbsentValue(player, from, to, toSet, lastValue, moveType); + } else if (currentValue != null && currentValue != lastValue) { + allowed = onSetValue(player, from, to, toSet, currentValue, lastValue, moveType); + } + + if (allowed) { + lastValue = currentValue; + } + + return allowed; + } + + protected abstract void onInitialValue(Player player, ApplicableRegionSet set, T value); + + protected abstract boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, T currentValue, T lastValue, MoveType moveType); + + protected abstract boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, T lastValue, MoveType moveType); + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/GameModeFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/GameModeFlag.java new file mode 100644 index 00000000..fd4fd03b --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/GameModeFlag.java @@ -0,0 +1,80 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; + +public class GameModeFlag extends FlagValueChangeHandler { + + private GameMode originalGameMode; + private GameMode setGameMode; + + public GameModeFlag(Session session) { + super(session, DefaultFlag.GAME_MODE); + } + + public GameMode getSetGameMode() { + return setGameMode; + } + + private void updateGameMode(Player player, GameMode newValue, World world) { + if (player.getGameMode() != newValue) { + if (originalGameMode == null) { + originalGameMode = player.getGameMode(); + } + + if (!getSession().getManager().hasBypass(player, world)) { + player.setGameMode(newValue); + setGameMode = newValue; + } + } + } + + @Override + protected void onInitialValue(Player player, ApplicableRegionSet set, GameMode value) { + updateGameMode(player, value, player.getWorld()); + } + + @Override + protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, GameMode currentValue, GameMode lastValue, MoveType moveType) { + updateGameMode(player, currentValue, to.getWorld()); + return true; + } + + @Override + protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, GameMode lastValue, MoveType moveType) { + if (originalGameMode != null) { + if (player.getGameMode() == setGameMode) { + player.setGameMode(originalGameMode); + } + originalGameMode = null; + } + + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/GodMode.java b/src/main/java/com/sk89q/worldguard/session/handler/GodMode.java new file mode 100644 index 00000000..cccf880b --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/GodMode.java @@ -0,0 +1,76 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.commandbook.CommandBook; +import com.sk89q.commandbook.GodComponent; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.session.Session; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; + +public class GodMode extends Handler { + + private boolean godMode; + + public GodMode(Session session) { + super(session); + } + + public boolean hasGodMode(Player player) { + if (getPlugin().getGlobalStateManager().hasCommandBookGodMode()) { + GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class); + if (god != null) { + return god.hasGodMode(player); + } + } + + return godMode; + } + + public void setGodMode(Player player, boolean godMode) { + if (getPlugin().getGlobalStateManager().hasCommandBookGodMode()) { + GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class); + if (god != null) { + god.enableGodMode(player); + } + } + + this.godMode = godMode; + } + + @Nullable + @Override + public State getInvincibility(Player player) { + return hasGodMode(player) ? State.ALLOW : null; + } + + public static boolean set(Player player, Session session, boolean value) { + GodMode godMode = session.getHandler(GodMode.class); + if (godMode != null) { + godMode.setGodMode(player, value); + return true; + } else{ + return false; + } + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/GreetingFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/GreetingFlag.java new file mode 100644 index 00000000..d5e96e51 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/GreetingFlag.java @@ -0,0 +1,69 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.google.common.collect.Sets; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class GreetingFlag extends Handler { + + private Set lastMessageStack = Collections.emptySet(); + + public GreetingFlag(Session session) { + super(session); + } + + @Override + public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set entered, Set exited, MoveType moveType) { + Collection messages = toSet.queryAllValues(getPlugin().wrapPlayer(player), DefaultFlag.GREET_MESSAGE); + + for (String message : messages) { + if (!lastMessageStack.contains(message)) { + player.sendMessage(getPlugin().replaceMacros(player, message).replaceAll("\\\\n", "\n").split("\\n")); + break; + } + } + + lastMessageStack = Sets.newHashSet(messages); + + if (!lastMessageStack.isEmpty()) { + // Due to flag priorities, we have to collect the lower + // priority flag values separately + for (ProtectedRegion region : toSet) { + String message = region.getFlag(DefaultFlag.GREET_MESSAGE); + if (message != null) { + lastMessageStack.add(message); + } + } + } + + return true; + } +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/Handler.java b/src/main/java/com/sk89q/worldguard/session/handler/Handler.java new file mode 100644 index 00000000..bd74d803 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/Handler.java @@ -0,0 +1,148 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import com.sk89q.worldguard.session.SessionManager; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Stores session data and possibly acts on it. + */ +public abstract class Handler { + + private final Session session; + + /** + * Create a new handler. + * + * @param session The session + */ + protected Handler(Session session) { + checkNotNull(session, "session"); + this.session = session; + } + + /** + * Get the plugin. + * + * @return The plugin + */ + public WorldGuardPlugin getPlugin() { + return getSession().getManager().getPlugin(); + } + + /** + * Get the session. + * + * @return The session + */ + public Session getSession() { + return session; + } + + /** + * Called when the session is first being created or + * {@code /wg flushstates} is used. + * + * @param player The player + * @param current The player's current location + * @param set The regions for the current location + */ + public void initialize(Player player, Location current, ApplicableRegionSet set) { + } + + /** + * Called when {@link Session#testMoveTo(Player, Location, MoveType)} is called. + * + *

If this method returns {@code false}, then no other handlers + * will be run (for this move attempt).

+ * + * @param player The player + * @param from The previous, valid, location + * @param to The new location to test + * @param toSet The regions for the new location + * @param moveType The type of movement + * @return Whether the movement should be allowed + */ + public boolean testMoveTo(Player player, Location from, Location to, ApplicableRegionSet toSet, MoveType moveType) { + return true; + } + + /** + * Called when a player has moved into a new location where either + * there are fewer regions or more regions. + * + *

This is called only if the move test + * ({@link Session#testMoveTo(Player, Location, MoveType)}) was successful.

+ * + *

If this method returns {@code false}, then no other handlers + * will be run (for this move attempt).

+ * + * @param player The player + * @param from The previous, valid, location + * @param to The new location to test + * @param toSet The regions for the new location + * @param entered The list of regions that have been entered + * @param exited The list of regions that have been left + * @param moveType The type of move + * @return Whether the movement should be allowed + */ + public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, + Set entered, Set exited, MoveType moveType) { + return true; + } + + /** + * Called periodically (at least once every second) by + * {@link SessionManager} in the server's main thread. + * + * @param player The player + * @param set The regions for the player's current location + */ + public void tick(Player player, ApplicableRegionSet set) { + } + + /** + * Return whether the player should be invincible. + * + *

{@link State#DENY} can be returned to prevent invincibility + * even if another handler permits it.

+ * + * @param player The player + * @return Invincibility state + */ + @Nullable + public State getInvincibility(Player player) { + return null; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/HealFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/HealFlag.java new file mode 100644 index 00000000..39f68aef --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/HealFlag.java @@ -0,0 +1,84 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.session.Session; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + +public class HealFlag extends Handler { + + private long lastHeal = 0; + + public HealFlag(Session session) { + super(session); + } + + @Override + public void tick(Player player, ApplicableRegionSet set) { + LocalPlayer localPlayer = getPlugin().wrapPlayer(player); + + if (!getSession().isInvincible(player) && player.getGameMode() != GameMode.CREATIVE) { + if (player.getHealth() <= 0) { + return; + } + + long now = System.currentTimeMillis(); + + Integer healAmount = set.queryValue(localPlayer, DefaultFlag.HEAL_AMOUNT); + Integer healDelay = set.queryValue(localPlayer, DefaultFlag.HEAL_DELAY); + Double minHealth = set.queryValue(localPlayer, DefaultFlag.MIN_HEAL); + Double maxHealth = set.queryValue(localPlayer, DefaultFlag.MAX_HEAL); + + if (healAmount == null || healDelay == null || healAmount == 0 || healDelay < 0) { + return; + } + + if (minHealth == null) { + minHealth = 0.0; + } + + if (maxHealth == null) { + maxHealth = player.getMaxHealth(); + } + + // Apply a cap to prevent possible exceptions + minHealth = Math.min(player.getMaxHealth(), minHealth); + maxHealth = Math.min(player.getMaxHealth(), maxHealth); + + if (player.getHealth() >= maxHealth && healAmount > 0) { + return; + } + + if (healDelay <= 0) { + player.setHealth(healAmount > 0 ? maxHealth : minHealth); // this will insta-kill if the flag is unset + lastHeal = now; + } else if (now - lastHeal > healDelay * 1000) { + // clamp health between minimum and maximum + player.setHealth(Math.min(maxHealth, Math.max(minHealth, player.getHealth() + healAmount))); + lastHeal = now; + } + } + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/InvincibilityFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/InvincibilityFlag.java new file mode 100644 index 00000000..52a0a09a --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/InvincibilityFlag.java @@ -0,0 +1,68 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; + +public class InvincibilityFlag extends FlagValueChangeHandler { + + @Nullable + private State invincibility; + + public InvincibilityFlag(Session session) { + super(session, DefaultFlag.INVINCIBILITY); + } + + @Override + protected void onInitialValue(Player player, ApplicableRegionSet set, State value) { + invincibility = value; + } + + @Override + protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State currentValue, State lastValue, MoveType moveType) { + invincibility = currentValue; + return true; + } + + @Override + protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State lastValue, MoveType moveType) { + invincibility = null; + return true; + } + + @Override + @Nullable + public State getInvincibility(Player player) { + if (invincibility == State.DENY && getPlugin().hasPermission(player, "worldguard.god.override-regions")) { + return null; + } + + return invincibility; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/NotifyEntryFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/NotifyEntryFlag.java new file mode 100644 index 00000000..beca0fb0 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/NotifyEntryFlag.java @@ -0,0 +1,68 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class NotifyEntryFlag extends FlagValueChangeHandler { + + public NotifyEntryFlag(Session session) { + super(session, DefaultFlag.NOTIFY_ENTER); + } + + @Override + protected void onInitialValue(Player player, ApplicableRegionSet set, Boolean value) { + + } + + @Override + protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean currentValue, Boolean lastValue, MoveType moveType) { + StringBuilder regionList = new StringBuilder(); + + for (ProtectedRegion region : toSet) { + if (regionList.length() != 0) { + regionList.append(", "); + } + + regionList.append(region.getId()); + } + + getPlugin().broadcastNotification(ChatColor.GRAY + "WG: " + + ChatColor.LIGHT_PURPLE + player.getName() + + ChatColor.GOLD + " entered NOTIFY region: " + + ChatColor.WHITE + + regionList); + + return true; + } + + @Override + protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean lastValue, MoveType moveType) { + return true; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/NotifyExitFlag.java b/src/main/java/com/sk89q/worldguard/session/handler/NotifyExitFlag.java new file mode 100644 index 00000000..731abcac --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/NotifyExitFlag.java @@ -0,0 +1,55 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class NotifyExitFlag extends FlagValueChangeHandler { + + private Boolean notifiedForLeave = false; + + public NotifyExitFlag(Session session) { + super(session, DefaultFlag.NOTIFY_LEAVE); + } + + @Override + protected void onInitialValue(Player player, ApplicableRegionSet set, Boolean value) { + + } + + @Override + protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean currentValue, Boolean lastValue, MoveType moveType) { + return true; + } + + @Override + protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean lastValue, MoveType moveType) { + getPlugin().broadcastNotification(ChatColor.GRAY + "WG: " + + ChatColor.LIGHT_PURPLE + player.getName() + + ChatColor.GOLD + " left NOTIFY region"); + return true; + } +} diff --git a/src/main/java/com/sk89q/worldguard/session/handler/WaterBreathing.java b/src/main/java/com/sk89q/worldguard/session/handler/WaterBreathing.java new file mode 100644 index 00000000..4c153d8b --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/session/handler/WaterBreathing.java @@ -0,0 +1,51 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.session.handler; + +import com.sk89q.worldguard.session.Session; +import org.bukkit.entity.Player; + +public class WaterBreathing extends Handler { + + public boolean waterBreathing; + + public WaterBreathing(Session session) { + super(session); + } + + public boolean hasWaterBreathing() { + return waterBreathing; + } + + public void setWaterBreathing(boolean waterBreathing) { + this.waterBreathing = waterBreathing; + } + + public static boolean set(Player player, Session session, boolean value) { + WaterBreathing waterBreathing = session.getHandler(WaterBreathing.class); + if (waterBreathing != null) { + waterBreathing.setWaterBreathing(value); + return true; + } else{ + return false; + } + } + +}