Compare commits

...
27 Commits
Author SHA1 Message Date
wizjany f147402d30 Release 6.2 and bump. 2016-11-30 14:12:18 -05:00
wizjany 8e35db0f35 Retain backwards compatibility for the LingeringPotion event listener. 2016-11-29 01:35:21 -05:00
wizjany 9b2eff0a71 Really remove construct flag. 2016-11-27 20:04:43 -05:00
wizjany 104cdc023d Add a method to unregister handlers. 2016-11-27 20:00:46 -05:00
wizjany deb283c44b Remove construct flag.
It's been deprecated for ages and is a strict subset of build flag functionality.
Also deprecate unused flags. They can be re-added by plugins that need them now.
2016-11-27 18:42:22 -05:00
wizjany 324e90c68a Add 1.11 materials. 2016-11-23 22:17:26 -05:00
wizjany c60502ffd8 Fix entity combustion in regions always getting cancelled.
Note that this technically might lead to some inaccuracies if
entity is on a region boundary, but requires server fix.
Fixes WORLDGUARD-3758, WORLDGUARD-3770.
2016-11-20 02:32:42 -05:00
wizjany 26e59955ed Handle LingeringPotions as their own event.
potion-splash flag should now filter them when denied.
Fixes WORLDGUARD-3765.
2016-11-15 21:21:23 -05:00
filoghost 4746e95249 Fix Materials.ARMOR_STAND being null in 1.8. (#356)
In 1.8 Materials.ARMOR_STAND is null because END_CRYSTAL throws NoSuchFieldError and in the catch block ARMOR_STAND is set to null. This causes side effects such as players being able to place armor stands in protected regions.
2016-11-10 23:32:25 -05:00
wizjany 9cafb07e4d Protect entities from endercrystal explosions using explosionFlagCancellation setting.
Should be more consistent with other explosion flags (tnt, creepers) now.
Improves fix for WORLDGUARD-2620.
2016-08-24 18:22:43 -04:00
wizjany b2b0fe65c6 Revert "Add frosted ice to ice-melt flag."
Re-Un-Fixes WORLDGUARD-3745 because apparently this isn't what was
requested.
2016-08-18 03:50:31 -04:00
wizjany 06e6ce589b Add frosted ice to ice-melt flag.
Fixes WORLDGUARD-3745.
2016-08-13 16:57:26 -04:00
wizjany 12fc1438c2 Add explicit ender crystal protection.
Fixes WORLDGUARD-2620.
2016-08-08 10:39:40 -04:00
wizjany e5e1f71a2a Birch boats are also vehicles.
Fixes WORLDGUARD-3740.
2016-07-29 13:32:51 -04:00
wizjany 2aaa14261b Actually add 1.10 blocks. 2016-07-05 19:22:32 -04:00
wizjany f006a9584c Fix Location flag bounding.
Fixes WORLDGUARD-3716.
2016-06-22 14:52:19 -04:00
wizjany 03cf9a668b Actually fix unmarshalling of region group flags. 2016-06-15 23:47:59 -04:00
Weasel_Squeezer db70e6f346 Add transientRegion property to ProtectedRegion as a flag to only be stored in memory and not saved (#355) 2016-06-13 22:31:10 -04:00
wizjany e0df194ff2 Fix unmarshalling of region group flags.
Fixes WORLDGUARD-3708.
2016-06-13 22:31:09 -04:00
wizjany ab55137f59 Allow FlagContext to be added to by plugins. 2016-06-13 22:31:09 -04:00
ZephireNZ bbb79526b2 Make RegionPrintoutBuilder use the FlagRegistry to print flags 2016-06-13 22:31:08 -04:00
wizjany cde9a403f7 Allow plugins to register session handlers. 2016-06-13 22:31:08 -04:00
wizjany 43a9228304 Add config setting to allow clamping of location flags.
Prevents players from setting locations (teleport, spawn) to point outside of the region.
The permission to override this is "worldguard.region.locationoverride.(own/member/.)regionid".
Also prevents location flags from being set to under the map or over the max world height.
Fixes WORLDGUARD-2775, WORLDGUARD-3370.
2016-06-13 22:31:07 -04:00
wizjany c1b8d12d05 Add FlagContext. 2016-06-13 22:31:00 -04:00
sk89q a25674e9a5 Add preliminary custom flags support. 2016-06-13 22:27:53 -04:00
wizjany 778ec404ff Prevent fishing rod PvP.
Fixes WORLDGUARD-3707.
2016-06-13 21:29:26 -04:00
wizjany 4ab38e5b89 Bump version to 6.1.3-SNAPSHOT for development. 2016-06-11 12:38:45 -04:00
75 changed files with 1333 additions and 340 deletions

No files matched your search

+2 -2
View File
@@ -1,7 +1,7 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
project.version = '6.1.2'
project.version = '6.2.1-SNAPSHOT'
ext.internalVersion = project.version + ";" + gitCommitHash
sourceCompatibility = 1.7
@@ -11,7 +11,7 @@ checkstyle.configFile = new File(projectDir, "config/checkstyle/checkstyle.xml")
dependencies {
compile 'org.khelekore:prtree:1.5.0'
compile 'org.bukkit:bukkit:1.9.4-R0.1-SNAPSHOT'
compile 'org.bukkit:bukkit:1.11-R0.1-SNAPSHOT'
compile 'com.sk89q.worldedit:worldedit-bukkit:6.1.3-SNAPSHOT'
compile 'com.sk89q:squirrelid:0.1.0'
compile 'com.sk89q:guavabackport:1.1'
@@ -85,7 +85,7 @@ public class RegionContainer {
*/
void initialize() {
ConfigurationManager config = plugin.getGlobalStateManager();
container = new RegionContainerImpl(config.selectedRegionStoreDriver);
container = new RegionContainerImpl(config.selectedRegionStoreDriver, plugin.getFlagRegistry());
// Migrate to UUIDs
autoMigrate();
@@ -293,7 +293,7 @@ public class RegionContainer {
if (config.migrateRegionsToUuid) {
RegionDriver driver = getDriver();
UUIDMigration migrator = new UUIDMigration(driver, plugin.getProfileService());
UUIDMigration migrator = new UUIDMigration(driver, plugin.getProfileService(), plugin.getFlagRegistry());
migrator.setKeepUnresolvedNames(config.keepUnresolvedNames);
try {
migrate(migrator);
@@ -145,6 +145,7 @@ public class WorldConfiguration {
public int maxClaimVolume;
public boolean claimOnlyInsideExistingRegions;
public int maxRegionCountPerPlayer;
public boolean boundedLocationFlags;
public boolean antiWolfDumbness;
public boolean signChestProtection;
public boolean disableSignChestProtectionCheck;
@@ -462,6 +463,7 @@ public class WorldConfiguration {
regionWand = getInt("regions.wand", 334);
maxClaimVolume = getInt("regions.max-claim-volume", 30000);
claimOnlyInsideExistingRegions = getBoolean("regions.claim-only-inside-existing-regions", false);
boundedLocationFlags = getBoolean("regions.location-flags-only-inside-regions", false);
maxRegionCountPerPlayer = getInt("regions.max-region-count-per-player.default", 7);
maxRegionCounts = new HashMap<String, Integer>();
@@ -37,10 +37,33 @@ import com.sk89q.worldguard.bukkit.commands.GeneralCommands;
import com.sk89q.worldguard.bukkit.commands.ProtectionCommands;
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.bukkit.listener.BlacklistListener;
import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
import com.sk89q.worldguard.bukkit.listener.BuildPermissionListener;
import com.sk89q.worldguard.bukkit.listener.ChestProtectionListener;
import com.sk89q.worldguard.bukkit.listener.DebuggingListener;
import com.sk89q.worldguard.bukkit.listener.EventAbstractionListener;
import com.sk89q.worldguard.bukkit.listener.InvincibilityListener;
import com.sk89q.worldguard.bukkit.listener.PlayerModesListener;
import com.sk89q.worldguard.bukkit.listener.PlayerMoveListener;
import com.sk89q.worldguard.bukkit.listener.RegionFlagsListener;
import com.sk89q.worldguard.bukkit.listener.RegionProtectionListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardBlockListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardCommandBookListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardEntityListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardHangingListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardPlayerListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardServerListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardVehicleListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardWeatherListener;
import com.sk89q.worldguard.bukkit.listener.WorldGuardWorldListener;
import com.sk89q.worldguard.bukkit.listener.WorldRulesListener;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
@@ -68,8 +91,17 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import javax.annotation.Nullable;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
@@ -91,6 +123,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 final SimpleFlagRegistry flagRegistry = new SimpleFlagRegistry();
private SessionManager sessionManager;
private final Supervisor supervisor = new SimpleSupervisor();
private ListeningExecutorService executorService;
@@ -110,6 +143,7 @@ public class WorldGuardPlugin extends JavaPlugin {
return plugin.hasPermission(player, perm);
}
};
flagRegistry.registerAll(DefaultFlag.getDefaultFlags());
}
/**
@@ -127,6 +161,7 @@ public class WorldGuardPlugin extends JavaPlugin {
@SuppressWarnings("deprecation")
public void onEnable() {
configureLogger();
flagRegistry.setInitialized(true);
getDataFolder().mkdirs(); // Need to create the plugins/WorldGuard folder
@@ -388,6 +423,15 @@ public class WorldGuardPlugin extends JavaPlugin {
return profileCache;
}
/**
* Get the flag registry.
*
* @return the flag registry
*/
public FlagRegistry getFlagRegistry() {
return flagRegistry;
}
/**
* Check whether a player is in a group.
* This calls the corresponding method in PermissionsResolverManager
@@ -46,9 +46,11 @@ import com.sk89q.worldguard.bukkit.util.logging.LoggerToChatHandler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
import com.sk89q.worldguard.protection.managers.migration.DriverMigration;
@@ -466,6 +468,7 @@ public final class RegionCommands extends RegionCommandsBase {
String flagName = args.getString(1);
String value = args.argsLength() >= 3 ? args.getJoinedStrings(2) : null;
RegionGroup groupValue = null;
FlagRegistry flagRegistry = plugin.getFlagRegistry();
RegionPermissionModel permModel = getPermissionModel(sender);
if (args.hasFlag('e')) {
@@ -490,7 +493,7 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
Flag<?> foundFlag = DefaultFlag.fuzzyMatchFlag(flagName);
Flag<?> foundFlag = DefaultFlag.fuzzyMatchFlag(flagRegistry, flagName);
// We didn't find the flag, so let's print a list of flags that the user
// can use, and do nothing afterwards
@@ -498,7 +501,7 @@ public final class RegionCommands extends RegionCommandsBase {
StringBuilder list = new StringBuilder();
// Need to build a list
for (Flag<?> flag : DefaultFlag.getFlags()) {
for (Flag<?> flag : flagRegistry) {
// Can the user set this flag?
if (!permModel.maySetFlag(existing, flag)) {
continue;
@@ -537,7 +540,7 @@ public final class RegionCommands extends RegionCommandsBase {
// Parse the [-g group] separately so entire command can abort if parsing
// the [value] part throws an error.
try {
groupValue = groupFlag.parseInput(plugin, sender, group);
groupValue = groupFlag.parseInput(FlagContext.create().setSender(sender).setInput(group).setObject("region", existing).build());
} catch (InvalidFlagFormat e) {
throw new CommandException(e.getMessage());
}
@@ -913,7 +916,7 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandException("The driver specified as 'to' does not seem to be supported in your version of WorldGuard.");
}
DriverMigration migration = new DriverMigration(fromDriver, toDriver);
DriverMigration migration = new DriverMigration(fromDriver, toDriver, plugin.getFlagRegistry());
LoggerToChatHandler handler = null;
Logger minecraftLogger = null;
@@ -972,7 +975,7 @@ public final class RegionCommands extends RegionCommandsBase {
ConfigurationManager config = plugin.getGlobalStateManager();
RegionContainer container = plugin.getRegionContainer();
RegionDriver driver = container.getDriver();
UUIDMigration migration = new UUIDMigration(driver, plugin.getProfileService());
UUIDMigration migration = new UUIDMigration(driver, plugin.getProfileService(), plugin.getFlagRegistry());
migration.setKeepUnresolvedNames(config.keepUnresolvedNames);
sender.sendMessage(ChatColor.YELLOW + "Now performing migration... this may take a while.");
container.migrate(migration);
@@ -35,6 +35,7 @@ import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
@@ -391,7 +392,7 @@ class RegionCommandsBase {
* @throws InvalidFlagFormat thrown if the value is invalid
*/
protected static <V> void setFlag(ProtectedRegion region, Flag<V> flag, CommandSender sender, String value) throws InvalidFlagFormat {
region.setFlag(flag, flag.parseInput(WorldGuardPlugin.inst(), sender, value));
region.setFlag(flag, flag.parseInput(FlagContext.create().setSender(sender).setInput(value).setObject("region", region).build()));
}
}
@@ -21,10 +21,12 @@ package com.sk89q.worldguard.bukkit.commands.region;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -105,7 +107,7 @@ public class RegionPrintoutBuilder implements Callable<String> {
public void appendFlagsList(boolean useColors) {
boolean hasFlags = false;
for (Flag<?> flag : DefaultFlag.getFlags()) {
for (Flag<?> flag : WorldGuardPlugin.inst().getFlagRegistry()) {
Object val = region.getFlag(flag), group = null;
// No value
@@ -70,8 +70,10 @@ import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.*;
import org.bukkit.material.Dispenser;
import org.bukkit.material.MaterialData;
import org.bukkit.material.PistonExtensionMaterial;
import org.bukkit.material.SpawnEgg;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector;
@@ -107,6 +109,10 @@ public class EventAbstractionListener extends AbstractListener {
getPlugin().getServer().getPluginManager().registerEvents(new SpigotCompatListener(), getPlugin());
} catch (LinkageError ignored) {
}
try {
getPlugin().getServer().getPluginManager().registerEvents(new LingeringPotionListener(), getPlugin());
} catch (NoClassDefFoundError ignored) {
}
}
//-------------------------------------------------------------------------
@@ -633,7 +639,7 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new DestroyEntityEvent(event, create(event.getPlayer(), event.getHook()), caught));
} else if (Entities.isConsideredBuildingIfUsed(caught)) {
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer(), event.getHook()), caught));
} else if (Entities.isNonHostile(caught)) {
} else if (Entities.isNonHostile(caught) || caught instanceof Player) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(event.getPlayer(), event.getHook()), caught));
}
}
@@ -711,8 +717,9 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onEntityCombust(EntityCombustEvent event) {
if (event instanceof EntityCombustByBlockEvent) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityCombustByBlockEvent) event).getCombuster()), event.getEntity()));
// at the time of writing, spigot is throwing null for the event's combuster. this causes lots of issues downstream.
// whenever (i mean if ever) it is fixed, use getCombuster again instead of the current block
Events.fireToCancel(event, new DamageEntityEvent(event, create(event.getEntity().getLocation().getBlock()), event.getEntity()));
} else if (event instanceof EntityCombustByEntityEvent) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityCombustByEntityEvent) event).getCombuster()), event.getEntity()));
}
@@ -832,6 +839,7 @@ public class EventAbstractionListener extends AbstractListener {
// Fire entity interaction event
if (!event.isCancelled()) {
int blocked = 0;
int affectedSize = event.getAffectedEntities().size();
boolean hasDamageEffect = Materials.hasDamageEffect(potion.getEffects());
for (LivingEntity affected : event.getAffectedEntities()) {
@@ -848,7 +856,7 @@ public class EventAbstractionListener extends AbstractListener {
}
}
if (blocked == event.getAffectedEntities().size()) {
if (blocked == affectedSize) { // server does weird things with this if the event is modified, so use cached number
event.setCancelled(true);
}
}
@@ -889,23 +897,36 @@ public class EventAbstractionListener extends AbstractListener {
// next to redstone, without plugins getting the clicked place event
// (not sure if this actually still happens)
Events.fireToCancel(event, new UseBlockEvent(event, cause, clicked.getLocation(), Material.TNT));
// Workaround for http://leaky.bukkit.org/issues/1034
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), Material.TNT));
return;
}
// Handle created Minecarts
if (item != null && Materials.isMinecart(item.getType())) {
// TODO: Give a more specific Minecart type
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.MINECART));
return;
}
// Handle created boats
if (item != null && Materials.isBoat(item.getType())) {
// TODO as above
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.BOAT));
return;
}
// Handle created armor stands
if (item != null && item.getType() == Materials.ARMOR_STAND) {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.ARMOR_STAND));
return;
}
if (item != null && item.getType() == Materials.END_CRYSTAL) { /*&& placed.getType() == Material.BEDROCK) {*/ // in vanilla you can only place them on bedrock but who knows what plugins will add
// may be overprotective as a result, but better than being underprotective
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.ENDER_CRYSTAL));
return;
}
// Handle created spawn eggs
@@ -918,6 +939,7 @@ public class EventAbstractionListener extends AbstractListener {
}
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), type));
}
return;
}
// Handle cocoa beans
@@ -926,11 +948,7 @@ public class EventAbstractionListener extends AbstractListener {
if (!(faceClicked == BlockFace.DOWN || faceClicked == BlockFace.UP)) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), Material.COCOA));
}
}
// Workaround for http://leaky.bukkit.org/issues/1034
if (item != null && item.getType() == Material.TNT) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), Material.TNT));
return;
}
}
@@ -990,4 +1008,22 @@ public class EventAbstractionListener extends AbstractListener {
}
}
public class LingeringPotionListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onLingeringSplash(LingeringPotionSplashEvent event) {
AreaEffectCloud aec = event.getAreaEffectCloud();
LingeringPotion potion = event.getEntity();
World world = potion.getWorld();
Cause cause = create(event.getEntity());
// Fire item interaction event
Events.fireToCancel(event, new UseItemEvent(event, cause, world, potion.getItem()));
// Fire entity spawn event
if (!event.isCancelled()) {
// radius unfortunately doesn't go through with this, so only a single location is tested
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, aec.getLocation().add(0.5, 0, 0.5), EntityType.AREA_EFFECT_CLOUD));
}
}
}
}
@@ -25,6 +25,7 @@ import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
@@ -61,10 +62,6 @@ public class RegionFlagsListener extends AbstractListener {
Block block;
if ((block = event.getCause().getFirstBlock()) != null) {
// ================================================================
// PISTONS flag
// ================================================================
if (Materials.isPistonBlock(block.getType())) {
event.filter(testState(query, DefaultFlag.PISTONS), false);
}
@@ -80,31 +77,22 @@ public class RegionFlagsListener extends AbstractListener {
Block block;
if ((block = event.getCause().getFirstBlock()) != null) {
// ================================================================
// PISTONS flag
// ================================================================
if (Materials.isPistonBlock(block.getType())) {
event.filter(testState(query, DefaultFlag.PISTONS), false);
}
}
// ================================================================
// CREEPER_EXPLOSION flag
// ================================================================
if (event.getCause().find(EntityType.CREEPER) != null) { // Creeper
event.filter(testState(query, DefaultFlag.CREEPER_EXPLOSION), config.explosionFlagCancellation);
}
// ================================================================
// ENDERDRAGON_BLOCK_DAMAGE flag
// ================================================================
if (event.getCause().find(EntityType.ENDER_DRAGON) != null) { // Enderdragon
event.filter(testState(query, DefaultFlag.ENDERDRAGON_BLOCK_DAMAGE), config.explosionFlagCancellation);
}
if (event.getCause().find(Entities.enderCrystalType) != null) { // should be nullsafe even if enderCrystalType field is null
event.filter(testState(query, DefaultFlag.OTHER_EXPLOSION), config.explosionFlagCancellation);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@@ -340,10 +340,14 @@ public class RegionProtectionListener extends AbstractListener {
what = "drop items";
/* XP drops */
} else if (event.getEffectiveType() == EntityType.EXPERIENCE_ORB) {
} else if (type == EntityType.EXPERIENCE_ORB) {
canSpawn = query.testBuild(target, associable, combine(event, DefaultFlag.EXP_DROPS));
what = "drop XP";
} else if (Entities.isAoECloud(type)) {
canSpawn = query.testBuild(target, associable, combine(event, DefaultFlag.POTION_SPLASH));
what = "use lingering potions";
/* Everything else */
} else {
canSpawn = query.testBuild(target, associable, combine(event));
@@ -167,6 +167,19 @@ public class WorldGuardEntityListener implements Listener {
}
}
if (attacker.getType() == Entities.enderCrystalType) {
// this isn't handled elsewhere because ender crystal explosions don't carry a player cause
// in the same way that creepers or tnt can
WorldConfiguration wcfg = plugin.getGlobalStateManager().get(defender.getWorld());
if (wcfg.useRegions && wcfg.explosionFlagCancellation) {
if (!plugin.getRegionContainer().createQuery().getApplicableRegions(defender.getLocation())
.testState(null, DefaultFlag.OTHER_EXPLOSION)) {
event.setCancelled(true);
return;
}
}
}
if (defender instanceof Player) {
Player player = (Player) defender;
LocalPlayer localPlayer = plugin.wrapPlayer(player);
@@ -99,6 +99,10 @@ public class RegionPermissionModel extends AbstractPermissionModel {
public boolean mayTeleportTo(ProtectedRegion region) {
return hasPatternPermission("teleport", region);
}
public boolean mayOverrideLocationFlagBounds(ProtectedRegion region) {
return hasPatternPermission("locationoverride", region);
}
public boolean mayList() {
return hasPluginPermission("region.list");
@@ -182,6 +182,8 @@ public final class Entities {
private static final EntityType armorStandType =
Enums.findByValue(EntityType.class, "ARMOR_STAND");
public static final EntityType enderCrystalType =
Enums.findByValue(EntityType.class, "ENDER_CRYSTAL");
/**
* Test whether using the given entity should be considered "building"
@@ -192,7 +194,8 @@ public final class Entities {
*/
public static boolean isConsideredBuildingIfUsed(Entity entity) {
return entity instanceof Hanging
|| entity.getType() == armorStandType;
|| entity.getType() == armorStandType
|| entity.getType() == enderCrystalType;
}
private static final EntityType tippedArrow = Enums.findByValue(EntityType.class, "TIPPED_ARROW");
@@ -201,4 +204,9 @@ public final class Entities {
return (entity != null &&
(entity.getType() == tippedArrow || entity.getType() == spectralArrow));
}
private static final EntityType aoeCloud = Enums.findByValue(EntityType.class, "AREA_EFFECT_CLOUD");
public static boolean isAoECloud(EntityType type) {
return type == aoeCloud;
}
}
@@ -47,12 +47,35 @@ public final class Materials {
private static final Set<PotionEffectType> DAMAGE_EFFECTS = new HashSet<PotionEffectType>();
public static Material ARMOR_STAND;
public static Material END_CRYSTAL;
private static Set<Material> shulkerBoxes = new HashSet<>();
static {
try {
// for backwards compatible access to material enum
ARMOR_STAND = Material.ARMOR_STAND;
END_CRYSTAL = Material.END_CRYSTAL;
} catch (NoSuchFieldError ignored) {}
try {
shulkerBoxes.add(Material.WHITE_SHULKER_BOX);
shulkerBoxes.add(Material.ORANGE_SHULKER_BOX);
shulkerBoxes.add(Material.MAGENTA_SHULKER_BOX);
shulkerBoxes.add(Material.LIGHT_BLUE_SHULKER_BOX);
shulkerBoxes.add(Material.YELLOW_SHULKER_BOX);
shulkerBoxes.add(Material.LIME_SHULKER_BOX);
shulkerBoxes.add(Material.PINK_SHULKER_BOX);
shulkerBoxes.add(Material.GRAY_SHULKER_BOX);
shulkerBoxes.add(Material.SILVER_SHULKER_BOX); // who called this silver?
shulkerBoxes.add(Material.CYAN_SHULKER_BOX);
shulkerBoxes.add(Material.PURPLE_SHULKER_BOX);
shulkerBoxes.add(Material.BLUE_SHULKER_BOX);
shulkerBoxes.add(Material.BROWN_SHULKER_BOX);
shulkerBoxes.add(Material.GREEN_SHULKER_BOX);
shulkerBoxes.add(Material.RED_SHULKER_BOX);
shulkerBoxes.add(Material.BLACK_SHULKER_BOX);
} catch (NoSuchFieldError ignored) {
ARMOR_STAND = null;
}
ENTITY_ITEMS.put(EntityType.PAINTING, Material.PAINTING);
@@ -276,7 +299,9 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.JUNGLE_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.ACACIA_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DARK_OAK_DOOR, MODIFIED_ON_RIGHT);
} catch (NoSuchFieldError ignored) {
}
try {
MATERIAL_FLAGS.put(Material.GRASS_PATH, 0);
MATERIAL_FLAGS.put(Material.CHORUS_PLANT, 0);
MATERIAL_FLAGS.put(Material.CHORUS_FLOWER, 0);
@@ -293,9 +318,19 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.STRUCTURE_BLOCK, MODIFIED_ON_LEFT | MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.COMMAND_REPEATING, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.COMMAND_CHAIN , MODIFIED_ON_RIGHT);
} catch (NoSuchFieldError ignored) {
}
try { // 1.10
MATERIAL_FLAGS.put(Material.MAGMA, 0);
MATERIAL_FLAGS.put(Material.NETHER_WART_BLOCK, 0);
MATERIAL_FLAGS.put(Material.RED_NETHER_BRICK, 0);
MATERIAL_FLAGS.put(Material.BONE_BLOCK, 0);
MATERIAL_FLAGS.put(Material.STRUCTURE_VOID, 0);
} catch (NoSuchFieldError ignored) {
}
for (Material m : shulkerBoxes) {
MATERIAL_FLAGS.put(m, MODIFIED_ON_RIGHT);
}
MATERIAL_FLAGS.put(Material.IRON_SPADE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.IRON_PICKAXE, 0);
@@ -456,7 +491,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.LEASH, 0);
MATERIAL_FLAGS.put(Material.NAME_TAG, 0);
MATERIAL_FLAGS.put(Material.COMMAND_MINECART, 0);
try {
try { // 1.8
MATERIAL_FLAGS.put(Material.PRISMARINE_SHARD, 0);
MATERIAL_FLAGS.put(Material.PRISMARINE_CRYSTALS, 0);
MATERIAL_FLAGS.put(Material.RABBIT, 0);
@@ -476,7 +511,9 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.JUNGLE_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.ACACIA_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.DARK_OAK_DOOR_ITEM, 0);
} catch (NoSuchFieldError ignored) {
}
try { // 1.9 + 1.10 (oops)
MATERIAL_FLAGS.put(Material.BOAT_SPRUCE, 0);
MATERIAL_FLAGS.put(Material.BOAT_BIRCH, 0);
MATERIAL_FLAGS.put(Material.BOAT_ACACIA, 0);
@@ -493,7 +530,11 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.LINGERING_POTION, 0);
MATERIAL_FLAGS.put(Material.ELYTRA, 0);
MATERIAL_FLAGS.put(Material.END_CRYSTAL, 0);
} catch (NoSuchFieldError ignored) {
}
try { // 1.11
MATERIAL_FLAGS.put(Material.TOTEM, 0);
MATERIAL_FLAGS.put(Material.SHULKER_SHELL, 0);
} catch (NoSuchFieldError ignored) {
}
MATERIAL_FLAGS.put(Material.GOLD_RECORD, 0);
@@ -701,7 +742,8 @@ public final class Materials {
|| material == Material.BOAT_ACACIA
|| material == Material.BOAT_SPRUCE
|| material == Material.BOAT_DARK_OAK
|| material == Material.BOAT_JUNGLE;
|| material == Material.BOAT_JUNGLE
|| material == Material.BOAT_BIRCH;
} catch (NoSuchFieldError ignored) {
return material == Material.BOAT;
}
@@ -722,7 +764,8 @@ public final class Materials {
|| material == Material.BREWING_STAND
|| material == Material.TRAPPED_CHEST
|| material == Material.HOPPER
|| material == Material.DROPPER;
|| material == Material.DROPPER
|| shulkerBoxes.contains(material);
}
/**
@@ -23,8 +23,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
@@ -42,14 +40,6 @@ public abstract class AbstractRegionSet implements ApplicableRegionSet {
return test(queryState(player, DefaultFlag.BUILD));
}
@Override
@Deprecated
public boolean canConstruct(LocalPlayer player) {
checkNotNull(player);
final RegionGroup flag = getFlag(DefaultFlag.CONSTRUCT, player);
return RegionGroupFlag.isMember(this, flag, player);
}
@Override
public boolean testState(@Nullable RegionAssociable subject, StateFlag... flags) {
return test(queryState(subject, flags));
@@ -149,17 +149,6 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*/
<V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Test whether the construct flag evaluates true for the given player.
*
* @param player the player
* @return true if true
* @deprecated The {@code CONSTRUCT} flag is being removed and is no longer
* needed because flags now support groups assigned to them.
*/
@Deprecated
boolean canConstruct(LocalPlayer player);
/**
* Gets the state of a state flag. This cannot be used for the build flag.
*
@@ -37,8 +37,8 @@ public class BooleanFlag extends Flag<Boolean> {
}
@Override
public Boolean parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
public Boolean parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
if (input.equalsIgnoreCase("true") || input.equalsIgnoreCase("yes")
|| input.equalsIgnoreCase("on")
@@ -37,7 +37,8 @@ public class CommandStringFlag extends Flag<String> {
}
@Override
public String parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
public String parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
input = input.trim();
if (!input.startsWith("/")) {
input = "/" + input;
@@ -19,11 +19,15 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.WeatherType;
import org.bukkit.entity.EntityType;
import java.util.Arrays;
import java.util.List;
/**
* The flags that are used in WorldGuard.
*/
@@ -32,13 +36,6 @@ public final class DefaultFlag {
// Overrides membership check
public static final StateFlag PASSTHROUGH = new StateFlag("passthrough", false);
/**
* @deprecated This flag is being removed because group flags can now be
* set on all flags.
*/
@Deprecated
public static final RegionGroupFlag CONSTRUCT = new RegionGroupFlag("construct", RegionGroup.MEMBERS);
// This flag is unlike the others. It forces the checking of region membership
public static final StateFlag BUILD = new BuildFlag("build", true);
@@ -134,14 +131,19 @@ public final class DefaultFlag {
// public static final StringFlag MAX_PLAYERS_MESSAGE = new StringFlag("max-players-reject-message");
public static final LocationFlag TELE_LOC = new LocationFlag("teleport", RegionGroup.MEMBERS);
public static final LocationFlag SPAWN_LOC = new LocationFlag("spawn", RegionGroup.MEMBERS);
public static final StateFlag ENABLE_SHOP = new StateFlag("allow-shop", false);
public static final BooleanFlag BUYABLE = new BooleanFlag("buyable");
public static final DoubleFlag PRICE = new DoubleFlag("price");
public static final SetFlag<String> BLOCKED_CMDS = new SetFlag<String>("blocked-cmds", new CommandStringFlag(null));
public static final SetFlag<String> ALLOWED_CMDS = new SetFlag<String>("allowed-cmds", new CommandStringFlag(null));
// these 3 are not used by worldguard and should be re-implemented in plugins that may use them using custom flag api
@Deprecated
public static final StateFlag ENABLE_SHOP = new StateFlag("allow-shop", false);
@Deprecated
public static final BooleanFlag BUYABLE = new BooleanFlag("buyable");
@Deprecated
public static final DoubleFlag PRICE = new DoubleFlag("price");
public static final Flag<?>[] flagsList = new Flag<?>[] {
PASSTHROUGH, BUILD, CONSTRUCT, BLOCK_BREAK, BLOCK_PLACE, PVP, CHEST_ACCESS, PISTONS,
PASSTHROUGH, BUILD, BLOCK_BREAK, BLOCK_PLACE, PVP, CHEST_ACCESS, PISTONS,
TNT, LIGHTER, RIDE, USE, INTERACT, PLACE_VEHICLE, DESTROY_VEHICLE, DAMAGE_ANIMALS, SLEEP,
MOB_DAMAGE, MOB_SPAWNING, DENY_SPAWN, INVINCIBILITY, EXP_DROPS,
CREEPER_EXPLOSION, OTHER_EXPLOSION, ENDERDRAGON_BLOCK_DAMAGE, GHAST_FIREBALL, ENDER_BUILD,
@@ -161,18 +163,35 @@ public final class DefaultFlag {
private DefaultFlag() {
}
/**
* Get a list of default flags.
*
* @deprecated Use {@link FlagRegistry}
* @return An array of flags
*/
@Deprecated
public static Flag<?>[] getFlags() {
return flagsList;
}
/**
* Get a list of default flags.
*
* @return An array of flags
*/
public static List<Flag<?>> getDefaultFlags() {
return Arrays.asList(flagsList);
}
/**
* Try to match the flag with the given ID using a fuzzy name match.
*
* @param flagRegistry the flag registry
* @param id the flag ID
* @return a flag, or null
*/
public static Flag<?> fuzzyMatchFlag(String id) {
for (Flag<?> flag : DefaultFlag.getFlags()) {
public static Flag<?> fuzzyMatchFlag(FlagRegistry flagRegistry, String id) {
for (Flag<?> flag : flagRegistry) {
if (flag.getName().replace("-", "").equalsIgnoreCase(id.replace("-", ""))) {
return flag;
}
@@ -180,4 +199,5 @@ public final class DefaultFlag {
return null;
}
}
@@ -19,10 +19,6 @@
package com.sk89q.worldguard.protection.flags;
import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
* Stores doubles.
*/
@@ -37,14 +33,8 @@ public class DoubleFlag extends Flag<Double> {
}
@Override
public Double parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
try {
return Double.parseDouble(input);
} catch (NumberFormatException e) {
throw new InvalidFlagFormat("Not a number: " + input);
}
public Double parseInput(FlagContext context) throws InvalidFlagFormat {
return context.getUserInputAsDouble();
}
@Override
@@ -19,10 +19,6 @@
package com.sk89q.worldguard.protection.flags;
import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
* Stores an enum value.
*/
@@ -78,7 +74,8 @@ public class EnumFlag<T extends Enum<T>> extends Flag<T> {
}
@Override
public T parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
public T parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
try {
return findValue(input);
} catch (IllegalArgumentException e) {
@@ -19,28 +19,44 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.google.common.collect.Iterators;
import com.sk89q.worldguard.protection.FlagValueCalculator;
import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A flag carries extra data on a region.
*
* <p>Each flag implementation is a singleton and must be registered with a
* {@link FlagRegistry} to be useful. Flag values are stored as their
* proper data type, but they are first "loaded" by calling
* {@link #unmarshal(Object)}. On save, the objects are fed
* through {@link #marshal(Object)} and then saved.</p>
*/
public abstract class Flag<T> {
private static final Pattern VALID_NAME = Pattern.compile("^[:A-Za-z0-9\\-]{1,40}$");
private final String name;
private final RegionGroupFlag regionGroup;
/**
* Create a new flag.
*
* <p>Flag names should match the regex {@code ^[:A-Za-z0-9\-]{1,40}$}.</p>
*
* @param name The name of the flag
* @param defaultGroup The default group
* @throws IllegalArgumentException Thrown if the name is invalid
*/
public Flag(String name, @Nullable RegionGroup defaultGroup) {
protected Flag(String name, @Nullable RegionGroup defaultGroup) {
if (name != null && !isValidName(name)) {
throw new IllegalArgumentException("Invalid flag name used");
}
this.name = name;
this.regionGroup = defaultGroup != null ? new RegionGroupFlag(name + "-group", defaultGroup) : null;
}
@@ -48,9 +64,12 @@ public abstract class Flag<T> {
/**
* Create a new flag with {@link RegionGroup#ALL} as the default group.
*
* <p>Flag names should match the regex {@code ^[:A-Za-z0-9\-]{1,40}$}.</p>
*
* @param name The name of the flag
* @throws IllegalArgumentException Thrown if the name is invalid
*/
public Flag(String name) {
protected Flag(String name) {
this(name, RegionGroup.ALL);
}
@@ -59,7 +78,7 @@ public abstract class Flag<T> {
*
* @return The name of the flag
*/
public String getName() {
public final String getName() {
return name;
}
@@ -73,13 +92,20 @@ public abstract class Flag<T> {
return null;
}
/**
* Given a list of values, choose the best one.
*
* <p>If there is no "best value" defined, then the first value should
* be returned. The default implementation returns the first value. If
* an implementation does have a strategy defined, then
* {@link #hasConflictStrategy()} should be overridden too.</p>
*
* @param values A collection of values
* @return The chosen value
*/
@Nullable
public T chooseValue(Collection<T> values) {
if (!values.isEmpty()) {
return values.iterator().next();
} else {
return null;
}
return Iterators.getNext(values.iterator(), null);
}
/**
@@ -145,20 +171,18 @@ public abstract class Flag<T> {
*
* @return The region group flag
*/
public RegionGroupFlag getRegionGroupFlag() {
public final RegionGroupFlag getRegionGroupFlag() {
return regionGroup;
}
/**
* Parse a given input to coerce it to a type compatible with the flag.
*
* @param plugin The plugin
* @param sender The sender
* @param input THe input
* @param context the {@link FlagContext}
* @return The coerced type
* @throws InvalidFlagFormat Raised if the input is invalid
*/
public abstract T parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat;
public abstract T parseInput(FlagContext context) throws InvalidFlagFormat;
/**
* Convert a raw type that was loaded (from a YAML file, for example)
@@ -184,4 +208,16 @@ public abstract class Flag<T> {
"name='" + name + '\'' +
'}';
}
/**
* Test whether a flag name is valid.
*
* @param name The flag name
* @return Whether the name is valid
*/
public static boolean isValidName(String name) {
checkNotNull(name, "name");
return VALID_NAME.matcher(name).matches();
}
}
@@ -0,0 +1,173 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import com.google.common.collect.Maps;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.util.Map;
public final class FlagContext {
private final CommandSender sender;
private final String input;
private Map<String, Object> context;
private FlagContext(CommandSender sender, String input, Map<String, Object> values) {
this.sender = sender;
this.input = input;
this.context = values;
}
public static FlagContextBuilder create() {
return new FlagContextBuilder();
}
public void put(String name, Object value) {
context.put(name, value);
}
public CommandSender getSender() {
return sender;
}
public String getUserInput() {
return input;
}
/**
* Gets the CommandSender as a player.
*
* @return Player
* @throws InvalidFlagFormat if the sender is not a player
*/
public Player getPlayerSender() throws InvalidFlagFormat {
try {
return WorldGuardPlugin.inst().checkPlayer(sender);
} catch (CommandException e) {
throw new InvalidFlagFormat(e.getMessage());
}
}
public Integer getUserInputAsInt() throws InvalidFlagFormat {
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
throw new InvalidFlagFormat("Not a number: " + input);
}
}
public Double getUserInputAsDouble() throws InvalidFlagFormat {
try {
return Double.parseDouble(input);
} catch (NumberFormatException e) {
throw new InvalidFlagFormat("Not a number: " + input);
}
}
/**
* Get an object from the context by key name.
* May return null if the object does not exist in the context.
*
* @param name key name of the object
* @return the object matching the key, or null
*/
@Nullable
public Object get(String name) {
return get(name, null);
}
/**
* Get an object from the context by key name.
* Will only return null if
* a) you provide null as the default
* b) the key has explicity been set to null
*
* @param name key name of the object
* @return the object matching the key
*/
@Nullable
public Object get(String name, Object defaultValue) {
Object obj;
return (((obj = context.get(name)) != null) || context.containsKey(name)
? obj : defaultValue);
}
/**
* Create a copy of this FlagContext, with optional substitutions for values
*
* If any supplied variable is null, it will be ignored.
* If a map is supplied, it will override this FlagContext's values of the same key,
* but unprovided keys will not be overriden and will be returned as shallow copies.
*
* @param commandSender CommandSender for the new FlagContext to run under
* @param s String of the user input for the new FlagContext
* @param values map of values to override from the current FlagContext
* @return a copy of this FlagContext
*/
public FlagContext copyWith(@Nullable CommandSender commandSender, @Nullable String s, @Nullable Map<String, Object> values) {
Map<String, Object> map = Maps.newHashMap();
map.putAll(context);
if (values != null) {
map.putAll(values);
}
return new FlagContext(commandSender == null ? this.sender : commandSender, s == null ? this.input : s, map);
}
public static class FlagContextBuilder {
private CommandSender sender;
private String input;
private Map<String, Object> map = Maps.newHashMap();
public FlagContextBuilder setSender(CommandSender sender) {
this.sender = sender;
return this;
}
public FlagContextBuilder setInput(String input) {
this.input = input;
return this;
}
public FlagContextBuilder setObject(String key, Object value) {
this.map.put(key, value);
return this;
}
protected boolean tryAddToMap(String key, Object value) {
if (map.containsKey(key)) return false;
this.map.put(key, value);
return true;
}
public FlagContext build() {
Bukkit.getServer().getPluginManager().callEvent(new FlagContextCreateEvent(this));
return new FlagContext(sender, input, map);
}
}
}
@@ -0,0 +1,56 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.protection.flags.FlagContext.FlagContextBuilder;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class FlagContextCreateEvent extends Event {
private FlagContextBuilder builder;
public FlagContextCreateEvent(FlagContextBuilder builder) {
this.builder = builder;
}
/**
* Add an object to the flag context with the given key. Keys must be unique.
*
* @param key a unique string to identify the object
* @param value the object to store in the context
* @return true if added successfully, false if the key was already used
*/
public boolean addObject(String key, Object value) {
return builder.tryAddToMap(key, value);
}
private static final HandlerList handlers = new HandlerList();
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,64 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
public final class Flags {
private static final Logger log = Logger.getLogger(Flags.class.getCanonicalName());
private Flags() {
}
/**
* Marshal a value of flag values into a map of raw values.
*
* @param values The unmarshalled flag values map
* @return The raw values map
*/
public static Map<String, Object> marshal(Map<Flag<?>, Object> values) {
checkNotNull(values, "values");
Map<String, Object> rawValues = Maps.newHashMap();
for (Entry<Flag<?>, Object> entry : values.entrySet()) {
try {
rawValues.put(entry.getKey().getName(), marshal(entry.getKey(), entry.getValue()));
} catch (Exception e) {
log.log(Level.WARNING, "Failed to marshal flag value for " + entry.getKey() + "; value is " + entry.getValue(), e);
}
}
return rawValues;
}
@SuppressWarnings("unchecked")
private static <T> Object marshal(Flag<T> flag, Object value) {
return flag.marshal((T) value);
}
}
@@ -19,10 +19,6 @@
package com.sk89q.worldguard.protection.flags;
import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
* Stores an integer.
*/
@@ -37,14 +33,8 @@ public class IntegerFlag extends Flag<Integer> {
}
@Override
public Integer parseInput(WorldGuardPlugin plugin, CommandSender sender,String input) throws InvalidFlagFormat {
input = input.trim();
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
throw new InvalidFlagFormat("Not a number: " + input);
}
public Integer parseInput(FlagContext context) throws InvalidFlagFormat {
return context.getUserInputAsInt();
}
@Override
@@ -19,13 +19,14 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
@@ -42,18 +43,13 @@ public class LocationFlag extends Flag<Location> {
}
@Override
public Location parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
final Player player;
try {
player = plugin.checkPlayer(sender);
} catch (CommandException e) {
throw new InvalidFlagFormat(e.getMessage());
}
public Location parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
Player player = context.getPlayerSender();
Location loc = null;
if ("here".equalsIgnoreCase(input)) {
return toLazyLocation(player.getLocation());
loc = toLazyLocation(player.getLocation());
} else if ("none".equalsIgnoreCase(input)) {
return null;
} else {
@@ -67,13 +63,32 @@ public class LocationFlag extends Flag<Location> {
final float yaw = split.length < 4 ? 0 : Float.parseFloat(split[3]);
final float pitch = split.length < 5 ? 0 : Float.parseFloat(split[4]);
return new LazyLocation(world.getName(), new Vector(x, y, z), yaw, pitch);
loc = new LazyLocation(world.getName(), new Vector(x, y, z), yaw, pitch);
} catch (NumberFormatException ignored) {
}
}
throw new InvalidFlagFormat("Expected 'here' or x,y,z.");
}
if (loc != null) {
Object obj = context.get("region");
if (obj instanceof ProtectedRegion) {
ProtectedRegion rg = (ProtectedRegion) obj;
if (WorldGuardPlugin.inst().getGlobalStateManager().get(player.getWorld()).boundedLocationFlags) {
if (!rg.contains(loc.getPosition())) {
if (new RegionPermissionModel(WorldGuardPlugin.inst(), player).mayOverrideLocationFlagBounds(rg)) {
player.sendMessage(ChatColor.GRAY + "WARNING: Flag location is outside of region.");
} else {
// no permission
throw new InvalidFlagFormat("You can't set that flag outside of the region boundaries.");
}
}
// clamp height to world limits
loc.setPosition(loc.getPosition().clampY(0, player.getWorld().getMaxHeight()));
return loc;
}
}
return loc;
}
throw new InvalidFlagFormat("Expected 'here' or x,y,z.");
}
private Location toLazyLocation(org.bukkit.Location location) {
@@ -20,8 +20,6 @@
package com.sk89q.worldguard.protection.flags;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.Collection;
@@ -56,14 +54,16 @@ public class SetFlag<T> extends Flag<Set<T>> {
}
@Override
public Set<T> parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
public Set<T> parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
if (input.isEmpty()) {
return Sets.newHashSet();
} else {
Set<T> items = Sets.newHashSet();
for (String str : input.split(",")) {
items.add(subFlag.parseInput(plugin, sender, str.trim()));
FlagContext copy = context.copyWith(null, str, null);
items.add(subFlag.parseInput(copy));
}
return items;
@@ -81,8 +81,8 @@ public class StateFlag extends Flag<StateFlag.State> {
}
@Override
public State parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
public State parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
if (input.equalsIgnoreCase("allow")) {
return State.ALLOW;
@@ -59,8 +59,8 @@ public class StringFlag extends Flag<String> {
}
@Override
public String parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
return input.replaceAll("(?!\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\n");
public String parseInput(FlagContext context) throws InvalidFlagFormat {
return context.getUserInput().replaceAll("(?!\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\n");
}
@Override
@@ -19,11 +19,8 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.command.CommandSender;
import java.util.HashMap;
import java.util.Map;
@@ -42,15 +39,11 @@ public class VectorFlag extends Flag<Vector> {
}
@Override
public Vector parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
public Vector parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
if ("here".equalsIgnoreCase(input)) {
try {
return BukkitUtil.toVector(plugin.checkPlayer(sender).getLocation());
} catch (CommandException e) {
throw new InvalidFlagFormat(e.getMessage());
}
return BukkitUtil.toVector(context.getPlayerSender().getLocation());
} else {
String[] split = input.split(",");
if (split.length == 3) {
@@ -0,0 +1,28 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags.registry;
public class FlagConflictException extends RuntimeException {
public FlagConflictException(String message) {
super(message);
}
}
@@ -0,0 +1,85 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags.registry;
import com.sk89q.worldguard.protection.flags.Flag;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
/**
* Keeps track of registered flags.
*/
public interface FlagRegistry extends Iterable<Flag<?>> {
/**
* Register a new flag.
*
* <p>There may be an appropriate time to register flags. If flags are
* registered outside this time, then an exception may be thrown.</p>
*
* @param flag The flag
* @throws FlagConflictException Thrown when an existing flag exists with the same name
* @throws IllegalStateException If it is not the right time to register new flags
*/
void register(Flag<?> flag) throws FlagConflictException;
/**
* Register a collection of flags.
*
* <p>There may be an appropriate time to register flags. If flags are
* registered outside this time, then an exception may be thrown.</p>
*
* <p>If there is a flag conflict, then an error will be logged but
* no exception will be thrown.</p>
*
* @param flags a collection of flags
* @throws IllegalStateException If it is not the right time to register new flags
*/
void registerAll(Collection<Flag<?>> flags);
/**
* Get af flag by its name.
*
* @param name The name
* @return The flag, if it has been registered
*/
@Nullable
Flag<?> get(String name);
/**
* Unmarshal a raw map of values into a map of flags with their
* unmarshalled values.
*
* @param rawValues The raw values map
* @param createUnknown Whether "just in time" flags should be created for unknown flags
* @return The unmarshalled flag values map
*/
Map<Flag<?>, Object> unmarshal(Map<String, Object> rawValues, boolean createUnknown);
/**
* Get the number of registered flags.
*
* @return The number of registered flags
*/
int size();
}
@@ -0,0 +1,163 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags.registry;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
import com.sk89q.worldguard.protection.flags.Flag;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
public class SimpleFlagRegistry implements FlagRegistry {
private static final Logger log = Logger.getLogger(SimpleFlagRegistry.class.getCanonicalName());
private final Object lock = new Object();
private final ConcurrentMap<String, Flag<?>> flags = Maps.newConcurrentMap();
private boolean initialized;
public boolean isInitialized() {
return initialized;
}
public void setInitialized(boolean initialized) {
this.initialized = initialized;
}
@Override
public void register(Flag<?> flag) throws FlagConflictException {
synchronized (lock) {
if (initialized) {
throw new IllegalStateException("New flags cannot be registered at this time");
}
forceRegister(flag);
}
}
@Override
public void registerAll(Collection<Flag<?>> flags) {
synchronized (lock) {
for (Flag<?> flag : flags) {
try {
register(flag);
} catch (FlagConflictException e) {
log.log(Level.WARNING, e.getMessage());
}
}
}
}
private Flag<?> forceRegister(Flag<?> flag) throws FlagConflictException {
checkNotNull(flag, "flag");
checkNotNull(flag.getName(), "flag.getName()");
synchronized (lock) {
String name = flag.getName().toLowerCase();
if (flags.containsKey(name)) {
throw new FlagConflictException("A flag already exists by the name " + name);
}
flags.put(name, flag);
}
return flag;
}
@Override
@Nullable
public Flag<?> get(String name) {
checkNotNull(name, "name");
return flags.get(name.toLowerCase());
}
private Flag<?> getOrCreate(String name) {
Flag<?> flag = get(name);
if (flag != null) {
return flag;
}
synchronized (lock) {
flag = get(name); // Load again because the previous load was not synchronized
return flag != null ? flag : forceRegister(new UnknownFlag(name));
}
}
@Override
public Map<Flag<?>, Object> unmarshal(Map<String, Object> rawValues, boolean createUnknown) {
checkNotNull(rawValues, "rawValues");
ConcurrentMap<Flag<?>, Object> values = Maps.newConcurrentMap();
ConcurrentMap<String, Object> regionFlags = Maps.newConcurrentMap();
for (Entry<String, Object> entry : rawValues.entrySet()) {
if (entry.getKey().endsWith("-group")) {
regionFlags.put(entry.getKey(), entry.getValue());
continue;
}
Flag<?> flag = createUnknown ? getOrCreate(entry.getKey()) : get(entry.getKey());
if (flag != null) {
try {
Object unmarshalled = flag.unmarshal(entry.getValue());
if (unmarshalled != null) {
values.put(flag, unmarshalled);
} else {
log.warning("Failed to parse flag '" + flag.getName() + "' with value '" + entry.getValue() + "'");
}
} catch (Exception e) {
log.log(Level.WARNING, "Failed to unmarshal flag value for " + flag, e);
}
}
}
for (Entry<String, Object> entry : regionFlags.entrySet()) {
String parentName = entry.getKey().replaceAll("-group", "");
Flag<?> parent = get(parentName);
if (parent == null || parent instanceof UnknownFlag) {
if (createUnknown) forceRegister(new UnknownFlag(entry.getKey()));
} else {
values.put(parent.getRegionGroupFlag(), parent.getRegionGroupFlag().unmarshal(entry.getValue()));
}
}
return values;
}
@Override
public int size() {
return flags.size();
}
@Override
public Iterator<Flag<?>> iterator() {
return Iterators.unmodifiableIterator(flags.values().iterator());
}
}
@@ -0,0 +1,49 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags.registry;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import javax.annotation.Nullable;
public class UnknownFlag extends Flag<Object> {
public UnknownFlag(String name) {
super(name);
}
@Override
public Object parseInput(FlagContext context) throws InvalidFlagFormat {
throw new InvalidFlagFormat("The plugin that registered this flag is not currently installed");
}
@Override
public Object unmarshal(@Nullable Object o) {
return o;
}
@Override
public Object marshal(Object o) {
return o;
}
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.protection.managers;
import com.google.common.base.Supplier;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
@@ -29,16 +30,7 @@ import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
@@ -62,6 +54,7 @@ public class RegionContainerImpl {
private final RegionDriver driver;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer();
private final FlagRegistry flagRegistry;
private final Set<Normal> failingLoads = new HashSet<Normal>();
private final Set<RegionManager> failingSaves = Collections.synchronizedSet(
@@ -71,12 +64,15 @@ public class RegionContainerImpl {
* Create a new instance.
*
* @param driver the region store driver
* @param flagRegistry the flag registry
*/
public RegionContainerImpl(RegionDriver driver) {
public RegionContainerImpl(RegionDriver driver, FlagRegistry flagRegistry) {
checkNotNull(driver);
checkNotNull(flagRegistry, "flagRegistry");
this.driver = driver;
timer.schedule(new BackgroundLoader(), LOAD_ATTEMPT_INTERVAL, LOAD_ATTEMPT_INTERVAL);
timer.schedule(new BackgroundSaver(), SAVE_INTERVAL, SAVE_INTERVAL);
this.flagRegistry = flagRegistry;
}
/**
@@ -129,7 +125,7 @@ public class RegionContainerImpl {
*/
private RegionManager createAndLoad(String name) throws StorageException {
RegionDatabase store = driver.get(name);
RegionManager manager = new RegionManager(store, indexFactory);
RegionManager manager = new RegionManager(store, indexFactory, flagRegistry);
manager.load(); // Try loading, although it may fail
return manager;
}
@@ -27,6 +27,7 @@ import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
import com.sk89q.worldguard.protection.managers.index.RegionIndex;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
@@ -37,14 +38,7 @@ import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -57,6 +51,7 @@ public final class RegionManager {
private final RegionDatabase store;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory;
private final FlagRegistry flagRegistry;
private ConcurrentRegionIndex index;
/**
@@ -64,14 +59,17 @@ public final class RegionManager {
*
* @param store the region store
* @param indexFactory the factory for creating new instances of the index
* @param flagRegistry the flag registry
*/
public RegionManager(RegionDatabase store, Supplier<? extends ConcurrentRegionIndex> indexFactory) {
public RegionManager(RegionDatabase store, Supplier<? extends ConcurrentRegionIndex> indexFactory, FlagRegistry flagRegistry) {
checkNotNull(store);
checkNotNull(indexFactory);
checkNotNull(flagRegistry, "flagRegistry");
this.store = store;
this.indexFactory = indexFactory;
this.index = indexFactory.get();
this.flagRegistry = flagRegistry;
}
/**
@@ -93,7 +91,7 @@ public final class RegionManager {
* @throws StorageException thrown when loading fails
*/
public void load() throws StorageException {
Set<ProtectedRegion> regions = store.loadAll();
Set<ProtectedRegion> regions = store.loadAll(flagRegistry);
for (ProtectedRegion region : regions) {
region.setDirty(false);
}
@@ -107,7 +105,7 @@ public final class RegionManager {
*/
public void save() throws StorageException {
index.setDirty(false);
store.saveAll(new HashSet<ProtectedRegion>(getValuesCopy()));
store.saveAll(new HashSet<ProtectedRegion>(getFilteredValuesCopy()));
}
/**
@@ -424,12 +422,18 @@ public final class RegionManager {
}
/**
* Get an {@link ArrayList} copy of regions in the index.
* Get an {@link ArrayList} copy of regions in the index with transient regions filtered.
*
* @return a list
*/
private List<ProtectedRegion> getValuesCopy() {
return new ArrayList<ProtectedRegion>(index.values());
private List<ProtectedRegion> getFilteredValuesCopy() {
List<ProtectedRegion> filteredValues = new ArrayList<ProtectedRegion>();
for (ProtectedRegion region : index.values()) {
if (!region.isTransient()) {
filteredValues.add(region);
}
}
return filteredValues;
}
// =============== HELPER METHODS ===============
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection.managers.migration;
import com.google.common.base.Preconditions;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
@@ -36,17 +38,21 @@ public class DriverMigration extends AbstractMigration {
private static final Logger log = Logger.getLogger(DriverMigration.class.getCanonicalName());
private final RegionDriver target;
private final FlagRegistry flagRegistry;
/**
* Create a new instance.
*
* @param driver the source storage driver
* @param target the target storage driver
* @param flagRegistry the flag registry
*/
public DriverMigration(RegionDriver driver, RegionDriver target) {
public DriverMigration(RegionDriver driver, RegionDriver target, FlagRegistry flagRegistry) {
super(driver);
checkNotNull(target);
Preconditions.checkNotNull(flagRegistry, "flagRegistry");
this.target = target;
this.flagRegistry = flagRegistry;
}
@Override
@@ -56,7 +62,7 @@ public class DriverMigration extends AbstractMigration {
log.info("Loading the regions for '" + store.getName() + "' with the old driver...");
try {
regions = store.loadAll();
regions = store.loadAll(flagRegistry);
} catch (StorageException e) {
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
}
@@ -24,18 +24,14 @@ import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.domains.PlayerDomain;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
@@ -53,6 +49,7 @@ public class UUIDMigration extends AbstractMigration {
private final Timer timer = new Timer();
private final ProfileService profileService;
private final FlagRegistry flagRegistry;
private final ConcurrentMap<String, UUID> resolvedNames = new ConcurrentHashMap<String, UUID>();
private final Set<String> unresolvedNames = new HashSet<String>();
private boolean keepUnresolvedNames = true;
@@ -62,11 +59,14 @@ public class UUIDMigration extends AbstractMigration {
*
* @param driver the storage driver
* @param profileService the profile service
* @param flagRegistry the flag registry
*/
public UUIDMigration(RegionDriver driver, ProfileService profileService) {
public UUIDMigration(RegionDriver driver, ProfileService profileService, FlagRegistry flagRegistry) {
super(driver);
checkNotNull(profileService);
checkNotNull(flagRegistry, "flagRegistry");
this.profileService = profileService;
this.flagRegistry = flagRegistry;
}
@Override
@@ -76,7 +76,7 @@ public class UUIDMigration extends AbstractMigration {
Set<ProtectedRegion> regions;
try {
regions = store.loadAll();
regions = store.loadAll(flagRegistry);
} catch (StorageException e) {
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
}
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.managers.storage;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -42,7 +43,7 @@ public class MemoryRegionDatabase implements RegionDatabase {
}
@Override
public Set<ProtectedRegion> loadAll() {
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) {
return regions;
}
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.managers.storage;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -53,10 +54,11 @@ public interface RegionDatabase {
* {@code get()} and {@code put()} calls in order to maximize performance.
* </p>
*
* @param flags a flag registry
* @return a set of loaded regions
* @throws StorageException thrown on read error
*/
Set<ProtectedRegion> loadAll() throws StorageException;
Set<ProtectedRegion> loadAll(FlagRegistry flags) throws StorageException;
/**
* Replace all the data in the store with the given collection of regions.
@@ -19,12 +19,9 @@
package com.sk89q.worldguard.protection.managers.storage;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.logging.Logger;
@@ -43,62 +40,6 @@ public final class RegionDatabaseUtils {
private RegionDatabaseUtils() {
}
/**
* Try setting the given map of flags onto the region.
*
* @param region the region
* @param flagData the map of flag data
*/
public static void trySetFlagMap(ProtectedRegion region, Map<String, Object> flagData) {
checkNotNull(region);
checkNotNull(flagData);
for (Flag<?> flag : DefaultFlag.getFlags()) {
if (flag == null) {
// Some plugins that add custom flags to WorldGuard are doing
// something very wrong -- see WORLDGUARD-3094
continue;
}
Object o = flagData.get(flag.getName());
if (o != null) {
RegionDatabaseUtils.trySetFlag(region, flag, o);
}
// Set group
if (flag.getRegionGroupFlag() != null) {
Object o2 = flagData.get(flag.getRegionGroupFlag().getName());
if (o2 != null) {
RegionDatabaseUtils.trySetFlag(region, flag.getRegionGroupFlag(), o2);
}
}
}
}
/**
* Try to set a flag on the region.
*
* @param region the region
* @param flag the flag
* @param value the value of the flag, which may be {@code null}
* @param <T> the flag's type
* @return true if the set succeeded
*/
public static <T> boolean trySetFlag(ProtectedRegion region, Flag<T> flag, @Nullable Object value) {
checkNotNull(region);
checkNotNull(flag);
T val = flag.unmarshal(value);
if (val != null) {
region.setFlag(flag, val);
return true;
} else {
log.warning("Failed to parse flag '" + flag.getName() + "' with value '" + value + "'");
return false;
}
}
/**
* Re-link parent regions on each provided region using the two
* provided maps.
@@ -26,7 +26,8 @@ import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
@@ -45,15 +46,7 @@ import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -97,8 +90,8 @@ public class YamlRegionFile implements RegionDatabase {
* @param file the file
*/
public YamlRegionFile(String name, File file) {
checkNotNull(name);
checkNotNull(file);
checkNotNull(name, "name");
checkNotNull(file, "file");
this.name = name;
this.file = file;
}
@@ -109,7 +102,7 @@ public class YamlRegionFile implements RegionDatabase {
}
@Override
public Set<ProtectedRegion> loadAll() throws StorageException {
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
YAMLProcessor config = createYamlProcessor(file);
@@ -162,7 +155,7 @@ public class YamlRegionFile implements RegionDatabase {
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
setFlags(region, node.getNode("flags"));
setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(parseDomain(node.getNode("owners")));
region.setMembers(parseDomain(node.getNode("members")));
@@ -287,31 +280,15 @@ public class YamlRegionFile implements RegionDatabase {
}
private Map<String, Object> getFlagData(ProtectedRegion region) {
Map<String, Object> flagData = new HashMap<String, Object>();
for (Map.Entry<Flag<?>, Object> entry : region.getFlags().entrySet()) {
Flag<?> flag = entry.getKey();
addMarshalledFlag(flagData, flag, entry.getValue());
}
return flagData;
return Flags.marshal(region.getFlags());
}
private void setFlags(ProtectedRegion region, YAMLNode flagsData) {
private void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
RegionDatabaseUtils.trySetFlagMap(region, flagsData.getMap());
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
@SuppressWarnings("unchecked")
private <V> void addMarshalledFlag(Map<String, Object> flagData, Flag<V> flag, Object val) {
if (val == null) {
return;
}
flagData.put(flag.getName(), flag.marshal((V) val));
}
private Map<String, Object> getDomainData(DefaultDomain domain) {
Map<String, Object> domainData = new HashMap<String, Object>();
@@ -27,6 +27,7 @@ import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
@@ -45,6 +46,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@@ -59,17 +61,19 @@ class DataLoader {
final Connection conn;
final DataSourceConfig config;
final int worldId;
final FlagRegistry flagRegistry;
private final Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
private final Map<ProtectedRegion, String> parentSets = new HashMap<ProtectedRegion, String>();
private final Yaml yaml = SQLRegionDatabase.createYaml();
DataLoader(SQLRegionDatabase regionStore, Connection conn) throws SQLException {
DataLoader(SQLRegionDatabase regionStore, Connection conn, FlagRegistry flagRegistry) throws SQLException {
checkNotNull(regionStore);
this.conn = conn;
this.config = regionStore.getDataSourceConfig();
this.worldId = regionStore.getWorldId();
this.flagRegistry = flagRegistry;
}
public Set<ProtectedRegion> load() throws SQLException {
@@ -239,13 +243,9 @@ class DataLoader {
unmarshalFlagValue(rs.getString("value")));
}
for (Map.Entry<String, Map<String, Object>> entry : data.rowMap().entrySet()) {
for (Entry<String, Map<String, Object>> entry : data.rowMap().entrySet()) {
ProtectedRegion region = loaded.get(entry.getKey());
if (region != null) {
RegionDatabaseUtils.trySetFlagMap(region, entry.getValue());
} else {
throw new RuntimeException("An unexpected error occurred (loaded.get() returned null)");
}
region.setFlags(flagRegistry.unmarshal(entry.getValue(), true));
}
} finally {
closer.closeQuietly();
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.managers.storage.sql;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
@@ -198,7 +199,7 @@ class SQLRegionDatabase implements RegionDatabase {
}
@Override
public Set<ProtectedRegion> loadAll() throws StorageException {
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
initialize();
Closer closer = Closer.create();
@@ -206,7 +207,7 @@ class SQLRegionDatabase implements RegionDatabase {
try {
try {
loader = new DataLoader(this, closer.register(getConnection()));
loader = new DataLoader(this, closer.register(getConnection()), flagRegistry);
} catch (SQLException e) {
throw new StorageException("Failed to get a connection to the database", e);
}
@@ -39,12 +39,24 @@ import java.util.List;
public class GlobalProtectedRegion extends ProtectedRegion {
/**
* Create a new instance.
* Create a new instance.<br>
* Equivalent to {@link #GlobalProtectedRegion(String, boolean) GlobalProtectedRegion(id, false)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the ID
*/
public GlobalProtectedRegion(String id) {
super(id);
this(id, false);
}
/**
* Create a new instance.
*
* @param id the ID
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
public GlobalProtectedRegion(String id, boolean transientRegion) {
super(id, transientRegion);
min = new BlockVector(0, 0, 0);
max = new BlockVector(0, 0, 0);
}
@@ -39,14 +39,29 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class ProtectedCuboidRegion extends ProtectedRegion {
/**
* Construct a new instance of this cuboid region.
* Construct a new instance of this cuboid region.<br>
* Equivalent to {@link #ProtectedCuboidRegion(String, boolean, BlockVector, BlockVector)
* ProtectedCuboidRegion(id, false, pt1, pt2)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region id
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(String id, BlockVector pt1, BlockVector pt2) {
super(id);
this(id, false, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.
*
* @param id the region id
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(String id, boolean transientRegion, BlockVector pt1, BlockVector pt2) {
super(id, transientRegion);
setMinMaxPoints(pt1, pt2);
}
@@ -36,8 +36,32 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
private final int minY;
private final int maxY;
/**
* Construct a new instance of this polygonal region.<br>
* Equivalent to {@link #ProtectedPolygonalRegion(String, boolean, List, int, int)
* ProtectedPolygonalRegion(id, false, points, minY, maxY)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region id
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(String id, List<BlockVector2D> points, int minY, int maxY) {
super(id);
this(id, false, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.
*
* @param id the region id
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(String id, boolean transientRegion, List<BlockVector2D> points, int minY, int maxY) {
super(id, transientRegion);
ImmutableList<BlockVector2D> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY);
this.points = immutablePoints;
@@ -56,6 +56,7 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
protected BlockVector max;
private final String id;
private final boolean transientRegion;
private int priority = 0;
private ProtectedRegion parent;
private DefaultDomain owners = new DefaultDomain();
@@ -67,9 +68,10 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* Construct a new instance of this region.
*
* @param id the name of this region
* @param transientRegion whether this region should only be kept in memory and not be saved
* @throws IllegalArgumentException thrown if the ID is invalid (see {@link #isValidId(String)}
*/
ProtectedRegion(String id) { // Package private because we can't have people creating their own region types
ProtectedRegion(String id, boolean transientRegion) { // Package private because we can't have people creating their own region types
checkNotNull(id);
if (!isValidId(id)) {
@@ -77,6 +79,7 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
}
this.id = Normal.normalize(id);
this.transientRegion = transientRegion;
}
/**
@@ -680,8 +683,21 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
*/
abstract Area toArea();
/**
* @return <code>true</code> if this region should only be kept in memory and not be saved
*/
public boolean isTransient() {
return transientRegion;
}
/**
* @return <code>true</code> if this region is not transient and changes have been made.
*/
@Override
public boolean isDirty() {
if (isTransient()) {
return false;
}
return dirty || owners.isDirty() || members.isDirty();
}
@@ -25,6 +25,7 @@ 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 com.sk89q.worldguard.session.handler.Handler.Factory;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -33,9 +34,14 @@ import org.bukkit.event.player.PlayerJoinEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -77,6 +83,7 @@ public class SessionManager implements Runnable, Listener {
public SessionManager(WorldGuardPlugin plugin) {
checkNotNull(plugin, "plugin");
this.plugin = plugin;
handlers.addAll(defaultHandlers);
}
/**
@@ -129,6 +136,82 @@ public class SessionManager implements Runnable, Listener {
}
}
private LinkedList<Factory<? extends Handler>> handlers = new LinkedList<Factory<? extends Handler>>();
private static final Set<Factory<? extends Handler>> defaultHandlers = new HashSet<Factory<? extends Handler>>();
static {
Factory<?>[] factories = {
FeedFlag.FACTORY,
FeedFlag.FACTORY,
NotifyEntryFlag.FACTORY,
NotifyExitFlag.FACTORY,
EntryFlag.FACTORY,
ExitFlag.FACTORY,
FarewellFlag.FACTORY,
GreetingFlag.FACTORY,
GameModeFlag.FACTORY,
InvincibilityFlag.FACTORY,
TimeLockFlag.FACTORY,
WeatherLockFlag.FACTORY,
GodMode.FACTORY,
WaterBreathing.FACTORY
};
defaultHandlers.addAll(Arrays.asList(factories));
}
/**
* Register a handler with the SessionManager.
*
* You may specify another handler class to ensure your handler is always registered after that class.
* If that class is not already registered, this method will return false.
*
* For example, flags that always act on a player in a region (like {@link HealFlag} and {@link FeedFlag})
* should be registered earlier, whereas flags that only take effect when a player leaves the region (like
* {@link FarewellFlag} and {@link GreetingFlag}) should be registered after the {@link ExitFlag.Factory}.class handler factory.
*
* @param factory a factory which takes a session and returns an instance of your handler
* @param after the handler factory to insert the first handler after, to ensure a specific order when creating new sessions
*
* @return {@code true} (as specified by {@link Collection#add})
* {@code false} if {@param after} is not registered, or {@param factory} is null
*/
public boolean registerHandler(Factory<? extends Handler> factory, @Nullable Factory<? extends Handler> after) {
if (factory == null) return false;
WorldGuardPlugin.inst().getLogger().log(Level.INFO, "Registering session handler "
+ factory.getClass().getEnclosingClass().getName());
if (after == null) {
handlers.add(factory);
} else {
int index = handlers.indexOf(after);
if (index == -1) return false;
handlers.add(index, factory); // shifts "after" right one, and everything after "after" right one
}
return true;
}
/**
* Unregister a handler.
*
* This will prevent it from being added to newly created sessions only. Existing
* sessions with the handler will continue to use it.
*
* Will return false if the handler was not registered to begin with.
*
* @param factory the handler factory to unregister
* @return true if the handler was registered and is now unregistered, false otherwise
*/
public boolean unregisterHandler(Factory<? extends Handler> factory) {
if (defaultHandlers.contains(factory)) {
WorldGuardPlugin.inst().getLogger().log(Level.WARNING, "Someone is unregistering a default WorldGuard handler: "
+ factory.getClass().getEnclosingClass().getName() + ". This may cause parts of WorldGuard to stop functioning");
} else {
WorldGuardPlugin.inst().getLogger().log(Level.INFO, "Unregistering session handler "
+ factory.getClass().getEnclosingClass().getName());
}
return handlers.remove(factory);
}
/**
* Create a session for a player.
*
@@ -137,20 +220,9 @@ public class SessionManager implements Runnable, Listener {
*/
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 FarewellFlag(session));
session.register(new GreetingFlag(session));
session.register(new GameModeFlag(session));
session.register(new InvincibilityFlag(session));
session.register(new TimeLockFlag(session));
session.register(new WeatherLockFlag(session));
session.register(new GodMode(session));
session.register(new WaterBreathing(session));
for (Factory<? extends Handler> factory : handlers) {
session.register(factory.create(session));
}
session.initialize(player);
return session;
}
@@ -33,6 +33,14 @@ import java.util.Set;
public class EntryFlag extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<EntryFlag> {
@Override
public EntryFlag create(Session session) {
return new EntryFlag(session);
}
}
private static final long MESSAGE_THRESHOLD = 1000 * 2;
private long lastMessage;
@@ -32,6 +32,14 @@ import org.bukkit.entity.Player;
public class ExitFlag extends FlagValueChangeHandler<State> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<ExitFlag> {
@Override
public ExitFlag create(Session session) {
return new ExitFlag(session);
}
}
private static final long MESSAGE_THRESHOLD = 1000 * 2;
private String storedMessage;
private boolean exitViaTeleport = false;
@@ -34,6 +34,14 @@ import java.util.Set;
public class FarewellFlag extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<FarewellFlag> {
@Override
public FarewellFlag create(Session session) {
return new FarewellFlag(session);
}
}
private Set<String> lastMessageStack = Collections.emptySet();
public FarewellFlag(Session session) {
@@ -28,6 +28,14 @@ import org.bukkit.entity.Player;
public class FeedFlag extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<FeedFlag> {
@Override
public FeedFlag create(Session session) {
return new FeedFlag(session);
}
}
private long lastFeed = 0;
public FeedFlag(Session session) {
@@ -32,6 +32,14 @@ import javax.annotation.Nullable;
public class GameModeFlag extends FlagValueChangeHandler<GameMode> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<GameModeFlag> {
@Override
public GameModeFlag create(Session session) {
return new GameModeFlag(session);
}
}
private GameMode originalGameMode;
private GameMode setGameMode;
@@ -29,6 +29,14 @@ import javax.annotation.Nullable;
public class GodMode extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<GodMode> {
@Override
public GodMode create(Session session) {
return new GodMode(session);
}
}
private boolean godMode;
public GodMode(Session session) {
@@ -35,6 +35,14 @@ import java.util.Set;
public class GreetingFlag extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<GreetingFlag> {
@Override
public GreetingFlag create(Session session) {
return new GreetingFlag(session);
}
}
private Set<String> lastMessageStack = Collections.emptySet();
public GreetingFlag(Session session) {
@@ -39,6 +39,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public abstract class Handler {
public static abstract class Factory<T extends Handler> {
public abstract T create(Session session);
}
private final Session session;
/**
@@ -28,6 +28,14 @@ import org.bukkit.entity.Player;
public class HealFlag extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<HealFlag> {
@Override
public HealFlag create(Session session) {
return new HealFlag(session);
}
}
private long lastHeal = 0;
public HealFlag(Session session) {
@@ -31,6 +31,14 @@ import javax.annotation.Nullable;
public class InvincibilityFlag extends FlagValueChangeHandler<State> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<InvincibilityFlag> {
@Override
public InvincibilityFlag create(Session session) {
return new InvincibilityFlag(session);
}
}
@Nullable
private State invincibility;
@@ -30,6 +30,14 @@ import org.bukkit.entity.Player;
public class NotifyEntryFlag extends FlagValueChangeHandler<Boolean> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<NotifyEntryFlag> {
@Override
public NotifyEntryFlag create(Session session) {
return new NotifyEntryFlag(session);
}
}
public NotifyEntryFlag(Session session) {
super(session, DefaultFlag.NOTIFY_ENTER);
}
@@ -29,6 +29,14 @@ import org.bukkit.entity.Player;
public class NotifyExitFlag extends FlagValueChangeHandler<Boolean> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<NotifyExitFlag> {
@Override
public NotifyExitFlag create(Session session) {
return new NotifyExitFlag(session);
}
}
private Boolean notifiedForLeave = false;
public NotifyExitFlag(Session session) {
@@ -31,6 +31,14 @@ import java.util.regex.Pattern;
public class TimeLockFlag extends FlagValueChangeHandler<String> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<TimeLockFlag> {
@Override
public TimeLockFlag create(Session session) {
return new TimeLockFlag(session);
}
}
private Long initialTime;
private boolean initialRelative;
@@ -24,6 +24,14 @@ import org.bukkit.entity.Player;
public class WaterBreathing extends Handler {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<WaterBreathing> {
@Override
public WaterBreathing create(Session session) {
return new WaterBreathing(session);
}
}
public boolean waterBreathing;
public WaterBreathing(Session session) {
@@ -31,6 +31,14 @@ import javax.annotation.Nullable;
public class WeatherLockFlag extends FlagValueChangeHandler<WeatherType> {
public static final Factory FACTORY = new Factory();
public static class Factory extends Handler.Factory<WeatherLockFlag> {
@Override
public WeatherLockFlag create(Session session) {
return new WeatherLockFlag(session);
}
}
private WeatherType initialWeather;
public WeatherLockFlag(Session session) {
@@ -27,7 +27,7 @@ public class HashMapIndexPriorityTest extends RegionPriorityTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory(), getFlagRegistry());
}
}
@@ -27,7 +27,7 @@ public class HashMapIndexRegionOverlapTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory(), getFlagRegistry());
}
}
@@ -19,15 +19,15 @@
package com.sk89q.worldguard.protection;
import com.sk89q.worldguard.protection.managers.index.HashMapIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.index.HashMapIndex;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class HashMapIndexTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory(), getFlagRegistry());
}
}
@@ -27,7 +27,7 @@ public class PriorityRTreeIndexTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory(), getFlagRegistry());
}
}
@@ -27,7 +27,7 @@ public class PriorityRTreeRegionEntryExitTest extends RegionEntryExitTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory(), getFlagRegistry());
}
}
@@ -27,7 +27,7 @@ public class PriorityRTreeRegionOverlapTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory(), getFlagRegistry());
}
}
@@ -27,7 +27,7 @@ public class PriorityRTreeRegionPriorityTest extends RegionPriorityTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory(), getFlagRegistry());
}
}
@@ -26,6 +26,8 @@ import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
@@ -53,6 +55,12 @@ public abstract class RegionEntryExitTest {
TestPlayer vipPlayer;
TestPlayer builderPlayer;
protected FlagRegistry getFlagRegistry() {
FlagRegistry registry = new SimpleFlagRegistry();
registry.registerAll(DefaultFlag.getDefaultFlags());
return registry;
}
protected abstract RegionManager createRegionManager() throws Exception;
@Before
@@ -19,15 +19,6 @@
package com.sk89q.worldguard.protection;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.HashSet;
import org.junit.Before;
import org.junit.Test;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
@@ -35,11 +26,21 @@ import com.sk89q.worldguard.TestPlayer;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashSet;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public abstract class RegionOverlapTest {
static String COURTYARD_ID = "courtyard";
@@ -58,6 +59,12 @@ public abstract class RegionOverlapTest {
ProtectedRegion fountain;
TestPlayer player1;
TestPlayer player2;
protected FlagRegistry getFlagRegistry() {
FlagRegistry registry = new SimpleFlagRegistry();
registry.registerAll(DefaultFlag.getDefaultFlags());
return registry;
}
protected abstract RegionManager createRegionManager() throws Exception;
@@ -26,6 +26,8 @@ import com.sk89q.worldguard.TestPlayer;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
@@ -55,6 +57,12 @@ public abstract class RegionPriorityTest {
ProtectedRegion fountain;
TestPlayer player1;
TestPlayer player2;
protected FlagRegistry getFlagRegistry() {
FlagRegistry registry = new SimpleFlagRegistry();
registry.registerAll(DefaultFlag.getDefaultFlags());
return registry;
}
protected abstract RegionManager createRegionManager() throws Exception;