Compare commits

...
47 Commits
Author SHA1 Message Date
wizjany 3827266eb3 Release 7.0.5. 2021-06-07 22:52:20 -04:00
wizjany c3dbfdd699 Changelog for 7.0.5. 2021-06-07 22:49:23 -04:00
wizjany f19ebab0e1 Handle spigot's entity mount event (#1755)
* Add handler for spigot's EntityMountEvent.

Closes #1677.

* checkstyle.
2021-06-06 19:34:26 -04:00
stonar96andwizjany f8f95a44f0 Fix Iron Doors (#1781)
Co-authored-by: wizjany <wizjany@gmail.com>
2021-06-06 19:30:40 -04:00
stonar96 0a74d02fc9 Add nonplayer-protection-domains flag (#1763) 2021-06-06 19:28:00 -04:00
stonar96 46a662e1a7 Fix Dispenser Shulker Box bug and cleanup (#1776) 2021-06-06 19:27:48 -04:00
stonar96 149d1f84e8 Remove unused RegionGroup.MEMBERS from the teleport flag (#1769) 2021-05-23 12:37:06 -04:00
stonar96andwizjany c4e76af5f4 Fix Cause#isKnown() (#1768)
* Fix Cause#isKnown()

* Grammar

Co-authored-by: wizjany <wizjany@gmail.com>
2021-05-15 15:03:55 -04:00
stonar96 c1c26360e3 Remove unnecessary FlagValueCalculator#getPriority(ProtectedRegion) calls 2021-05-15 15:03:02 -04:00
stonar96 65c894cfe9 Fix doc comment of FlagValueCalculator#getMembership(RegionAssociable) 2021-05-15 15:02:08 -04:00
TheBusyBiscuitandwizjany 7dcec2b3b4 Small performance improvement for PlayerDomain#contains() (#1765)
* Improve performance by putting UUID checks first.

* Added wizjany's suggestion

Co-authored-by: wizjany <wizjany@gmail.com>
2021-05-15 15:01:15 -04:00
stonar96 09ce3b6373 Update Java version in CONTRIBUTING.md (#1764) 2021-05-10 11:22:38 +10:00
wizjany de22a5cd25 Deprecate and immediately void setMin/MaxPoint in ProtectedCuboidRegion.
Not sure why these were here to begin with, Poly doesn't have them either
and mutating regions after creation leads to undefined behavior.
2021-04-12 14:18:11 -04:00
JOO200 d2c2bfbab2 Deprecate flags (replaced by RegistryFlag), added some null checks (#1747) 2021-04-10 13:58:39 -04:00
wizjany 528ba32a93 Also change paperlib to shade.
This change has been sitting here for a while uncommitted and unpushed.
2021-03-06 15:36:25 -05:00
JOO200 f37fbb1ae8 Fix Falling blocks may change snow layers to that block 2021-03-06 15:31:06 -05:00
wizjany f1f8b625a8 Gradle cleanup/unfuckery.
Fixes #1729
2021-02-10 15:21:03 -05:00
wizjany e933050436 Change relocated/shaded artifacts to compileOnly. 2021-02-10 13:33:48 -05:00
wizjany 59d4c7b96d Fix nullability annotation. 2021-02-10 00:02:28 -05:00
Shane Freeder 0c7f4bb8f7 Fix TimedHandler not calling delegated handler (#1727)
The original commit was calling super, which means that the actual
registered handlers were not called, also, added getInvincibility
which was originally missing
2021-02-09 23:48:03 -05:00
wizjany 3c9b21d01f Add timings to third-party session handlers (#1717)
* Add Timings for third-party session handlers.

These often cause WorldGuard to get blamed by timings.

* Add config option to turn off extra timings.

* Move relocation to the right build file.

* Move config to a map for potential future expansion.

* Calculate timing immediately per-factory.

Instead of on each handler creation.
2021-02-06 11:10:04 -05:00
wizjany aeea455560 Ignore BlockFertilizeEvent with empty list.
Plugins can clear this list without fully cancelling the event.
Fixes #1723
2021-02-06 10:58:29 -05:00
wizjany 129d27351a Don't send empty messages from chorus-fruit/enderpearl teleports. 2021-02-02 19:44:38 -05:00
wizjany 310ce9a662 Make UUIDFlag ctors public.
smh.
2021-01-26 16:18:07 -05:00
kikelkik e04c654cde Added arguments to /rg toggle-bypass: on, off 2021-01-23 22:01:28 -05:00
JOO200 b1674e5cb7 Added test cases for FlagValueCalculator and MapFlags 2021-01-23 21:43:44 -05:00
JOO200 89c6a33b90 Improved queryMapValue to return defaultValue instead of null 2021-01-23 21:43:44 -05:00
JOO200 88c91ce3fc Add fallback value to queryMapValue, use Flag$chooseValue 2021-01-23 21:43:44 -05:00
JOO200 b70f5a73ce Added methods to query values from map flags 2021-01-23 21:43:44 -05:00
JOO200 b6fc9ddd93 Add UUIDFlag 2021-01-23 21:33:29 -05:00
wizjany cbb3212082 Don't throw error when swapping armor slots into the offhand.
Lots of conflicting info here, but the offhand slot is in fact part of
the quickbar/hotbar (yay bukkit naming) but does *not* use a hotbar "button",
since it has its own hotkey (i.e., F by default instead of 0-8).
The result is a hotbar_swap *action* with a swap_offhand *clicktype*.

Fixes #1698.
2021-01-09 18:16:40 -05:00
Intelli 04d5a3b437 Fixed NoClassDefFoundError if WorldEdit failed to initialize 2021-01-03 17:46:29 -05:00
Matthew Millerandwizjany 282425f3cf Move the Mob Blocker feature from CraftBook to WorldGuard (#1695)
* Move the Mob Blocker feature from CraftBook to WorldGuard

* Formatting.

Co-authored-by: wizjany <wizjany@gmail.com>
2020-12-31 10:51:49 +10:00
wizjany 15a08097ae Small readme tweaks.
Fix dead/outdated links, clarify deps.
2020-12-09 11:28:13 -05:00
wizjany 035a645de0 Deal with bamboo as growth from spread event listener.
Closes #1673, #1674.
2020-11-27 09:10:28 -05:00
wizjany 59c146f59a Don't allow setting unknown flags in FlagHelperBox. 2020-11-17 18:53:22 -05:00
wizjany d313f2caad Add nether warts to crop list.
Closes #1669.
2020-11-17 18:50:35 -05:00
wizjany 8350267b10 Don't marshal SetFlag in FlagHelperBox. 2020-11-17 18:50:35 -05:00
JOO200 e98196af40 Catch Throwables instead of Exceptions while (un)marshalling flags 2020-11-17 17:17:26 -05:00
wizjany 3879772103 Move /rg bypass perm check inside the command.
Using @CommandPermissions would cause the root command to be excluded
from the client. This is a temp workaround until piston/proper perms
are somehow implemented.
2020-11-17 16:36:36 -05:00
wizjany 48233c3327 Make resource processing update with project version.
Should prevent old version strings from finding their way into plugin.yml
2020-11-03 14:42:39 -05:00
wizjany 664ab18f00 Fix sponge-simulation clearing NBT of waterlogged blocks.
Fixes #1659.
Didn't realize people still used this feature.
2020-10-23 23:41:56 -04:00
Matthew Miller 07bf1871ab Add an SVG logo 2020-10-23 21:44:09 +10:00
JOO200 5921be432c Change anvil usage to build permissions and add use-anvil flag (#1644) 2020-10-17 17:51:39 -04:00
wizjany 60b16fc4c7 Add sweet berry bush to crop list. 2020-09-26 22:16:19 -04:00
wizjany 746b630d01 Note the new region converter class for devs. 2020-09-26 16:05:27 -04:00
wizjany 0b362088f4 Bump to snapshot version. 2020-09-26 12:57:03 -04:00
49 changed files with 975 additions and 131 deletions

No files matched your search

+21
View File
@@ -1,5 +1,25 @@
# Changelog
## 7.0.5
* Add a use-anvil flag and exclude it from the use flag (since they can break on use.)
* Expand crop-related options (crop-growth, etc) to sweet berry bushes, nether wart, and bamboo.
* Add a config option (`mobs.block-vehicle-entry`) to prevent non-players from entering vehicles.
* Add a UUID flag (for developers/API usage).
* Add map query methods with fallback flag (for developers/API usage).
* Add `on` and `off` optional arguments for `/rg toggle-bypass` command.
* Add additional timings info for session handlers.
* Fix sponge-simulation clearing NBT from blocks. Note that if you are using sponge simulation you should switch to something like CraftBook as the feature will be removed from WorldGuard in a future (major) version.
* Fix the `/rg` command showing up as unknown client-side to players without bypass perms.
* Fix error propagation from third-party flag loading causing WG to error.
* Fix a (harmless) exception that occurred when swapping armor slots to the offhand slot.
* Fix empty lines being sent on enderpearl/chorus-fruit teleport if the deny messages were empty.
* Fix an issue with falling blocks when using max-priority-association.
* Fix performance issues with third-party plugins querying protection for offline players.
* Fix dispensing shulkers over region boundaries.
* Fix iron door interaction being denied as if it were a regular door.
* Fix being able to enter/exit regions with the flag denied by using entity mounting functions in other plugins.
## 7.0.4 (including beta1)
* Add support for MC 1.16. Dropped support for previous versions.
@@ -13,6 +33,7 @@
* Fix ride flag being checked on striders that didn't have saddles.
* Add config option to have /rg bypass toggled off on login.
* Developer changes: Methods taking names in Domains are now explicitly deprecated (was previously just a javadoc comment.); These will eventually be removed: there is no reason to use names over UUIDs. Offline players and NPCs alike have stable UUIDs.
* Also for developers; The new `com.sk89q.worldguard.protection.util.WorldEditRegionConverter` class has some useful static methods to convert to and from WorldEdit's Region and WorldGuard's ProtectedRegion classes.
## 7.0.3
+2 -2
View File
@@ -7,9 +7,9 @@ ask that you make note of the following guidelines.
* **Follow the [Oracle coding conventions](https://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html).**
We can't stress this enough; if your code has notable issues, it may delay
the process significantly.
* **Target Java 6 for source and compilation.** Make sure to mark methods with
* **Target Java 8 for source and compilation.** Make sure to mark methods with
` @Override` that override methods of parent classes, or that implement
methods of interfaces (Java 6+).
methods of interfaces.
* **Use only spaces for indentation.** Our indents are 4-spaces long, and tabs
are unacceptable.
* **Wrap code to a 89 column limit.** We do this to make side by side diffs
+5 -4
View File
@@ -1,4 +1,6 @@
# ![WorldGuard](worldguard-logo.png)
<h1>
<img src="worldguard-logo.svg" alt="WorldGuard" width="400" />
</h1>
WorldGuard lets you and players guard areas of land against griefers and undesirables, as well as tweak and disable various gameplay features of Minecraft.
@@ -16,7 +18,7 @@ WorldGuard lets you and players guard areas of land against griefers and undesir
WorldGuard is open source and is available under the GNU Lesser
General Public License v3.
Currently, Bukkit is required to use WorldGuard. You can get a release copy of WorldGuard from the [BukkitDev site](http://dev.bukkit.org/bukkit-plugins/worldguard/).
A Bukkit server implementation (such as [Paper](https://papermc.io)) and the [WorldEdit plugin](https://dev.bukkit.org/projects/worldedit) are required to use WorldGuard. You can get a release copy of WorldGuard from the [BukkitDev site](https://dev.bukkit.org/projects/worldguard).
Compiling
---------
@@ -40,7 +42,6 @@ Links
* [Homepage](http://enginehub.org/worldguard)
* [Discord](https://discord.gg/enginehub)
* [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net)
* [Issue tracker](https://dev.enginehub.org/issues/WORLDGUARD)
* [Issue tracker](https://github.com/EngineHub/WorldGuard/issues)
* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://ci.enginehub.org/app/rest/builds/buildType:bt11,branch:master/statusIcon.svg)](http://ci.enginehub.org/viewType.html?buildTypeId=bt11&guest=1)
* [End-user documentation](https://worldguard.enginehub.org/en/latest/)
+2
View File
@@ -29,6 +29,8 @@
<allow pkg="org.bstats.bukkit"/>
<allow pkg="io.papermc.lib"/>
<allow pkg="com.destroystokyo.paper"/>
<allow pkg="co.aikar.timings.lib" />
<allow pkg="org.spigotmc" />
</subpackage>
</subpackage>
+1 -1
View File
@@ -1,2 +1,2 @@
group=com.sk89q.worldguard
version=7.0.4
version=7.0.5
+24 -6
View File
@@ -19,17 +19,26 @@ repositories {
name = "bstats"
url = uri("https://repo.codemc.org/repository/maven-public")
}
maven {
name = "aikar-timings"
url = uri("http://repo.aikar.co/nexus/content/groups/aikar/")
}
}
configurations {
compileClasspath.extendsFrom(create("shade"))
}
dependencies {
"compile"(project(":worldguard-core"))
//"compile"(project(":worldguard-libs:bukkit"))
"api"("com.destroystokyo.paper:paper-api:1.16.2-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.4")
"shade"("io.papermc:paperlib:1.0.4")
"api"("com.sk89q.worldedit:worldedit-bukkit:${Versions.WORLDEDIT}") { isTransitive = false }
"implementation"("com.google.guava:guava:${Versions.GUAVA}")
"implementation"("com.sk89q:commandbook:2.3") { isTransitive = false }
"implementation"("org.bstats:bstats-bukkit:1.7")
"shade"("org.bstats:bstats-bukkit:1.7")
"shade"("co.aikar:minecraft-timings:1.0.4")
}
tasks.named<Upload>("install") {
@@ -48,24 +57,33 @@ tasks.named<Upload>("install") {
}
tasks.named<Copy>("processResources") {
val internalVersion = project.ext["internalVersion"]
inputs.property("internalVersion", internalVersion)
filesMatching("plugin.yml") {
expand("internalVersion" to project.ext["internalVersion"])
expand("internalVersion" to internalVersion)
}
}
tasks.named<Jar>("jar") {
val projectVersion = project.version
inputs.property("projectVersion", projectVersion)
manifest {
attributes("Implementation-Version" to project.version)
attributes("Implementation-Version" to projectVersion)
}
}
tasks.named<ShadowJar>("shadowJar") {
configurations = listOf(project.configurations["shade"], project.configurations["runtimeClasspath"])
dependencies {
relocate("org.bstats", "com.sk89q.worldguard.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.7"))
include(dependency("org.bstats:bstats-bukkit"))
}
relocate ("io.papermc.lib", "com.sk89q.worldguard.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.4"))
include(dependency("io.papermc:paperlib"))
}
relocate ("co.aikar.timings.lib", "com.sk89q.worldguard.bukkit.timingslib") {
include(dependency("co.aikar:minecraft-timings"))
}
}
}
@@ -37,6 +37,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
private boolean hasCommandBookGodMode;
boolean extraStats;
boolean timedSessionHandlers;
/**
* Construct the object.
@@ -56,6 +57,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
public void load() {
super.load();
this.extraStats = getConfig().getBoolean("custom-metrics-charts", true);
this.timedSessionHandlers = getConfig().getBoolean("extra-timings.session-handlers", true);
}
@Override
@@ -218,6 +218,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
blockGroundSlimes = getBoolean("mobs.block-above-ground-slimes", false);
blockOtherExplosions = getBoolean("mobs.block-other-explosions", false);
blockZombieDoorDestruction = getBoolean("mobs.block-zombie-door-destruction", false);
blockEntityVehicleEntry = getBoolean("mobs.block-vehicle-entry", false);
disableFallDamage = getBoolean("player-damage.disable-fall-damage", false);
disableLavaDamage = getBoolean("player-damage.disable-lava-damage", false);
@@ -67,7 +67,7 @@ import java.util.stream.Collectors;
public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
private SessionManager sessionManager;
private BukkitSessionManager sessionManager;
private BukkitConfigurationManager configuration;
private BukkitRegionContainer regionContainer;
private BukkitDebugHandler debugHandler;
@@ -138,6 +138,7 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
sessionManager = new BukkitSessionManager();
configuration = new BukkitConfigurationManager(WorldGuardPlugin.inst());
configuration.load();
sessionManager.setUsingTimings(configuration.timedSessionHandlers);
regionContainer = new BukkitRegionContainer(WorldGuardPlugin.inst());
regionContainer.initialize();
debugHandler = new BukkitDebugHandler(WorldGuardPlugin.inst());
@@ -385,6 +385,8 @@ public class WorldGuardPlugin extends JavaPlugin {
Plugin worldEdit = getServer().getPluginManager().getPlugin("WorldEdit");
if (worldEdit == null) {
throw new CommandException("WorldEdit does not appear to be installed.");
} else if (!worldEdit.isEnabled()) {
throw new CommandException("WorldEdit does not appear to be enabled.");
}
if (worldEdit instanceof WorldEditPlugin) {
@@ -90,26 +90,15 @@ public final class Cause {
}
/**
* Return whether a cause is known. This method will return true if
* the list of causes is empty or the list of causes only contains
* objects that really are not root causes (i.e primed TNT).
* Return whether a cause is known. This method will return false if
* the list of causes is empty or the root cause is really not known
* (e.g. primed TNT).
*
* @return true if known
*/
public boolean isKnown() {
if (causes.isEmpty()) {
return false;
}
boolean found = false;
for (Object object : causes) {
if (!(object instanceof TNTPrimed) && !(object instanceof Vehicle)) {
found = true;
break;
}
}
return found;
Object object = getRootCause();
return !(object == null || object instanceof TNTPrimed || object instanceof Vehicle);
}
@Nullable
@@ -49,6 +49,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockDispenseArmorEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCreativeEvent;
@@ -58,6 +59,7 @@ import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import static com.sk89q.worldguard.bukkit.BukkitUtil.createTarget;
@@ -330,6 +332,9 @@ public class BlacklistListener extends AbstractListener {
return cursor;
}
case HOTBAR_SWAP:
if (event.getClick() == ClickType.SWAP_OFFHAND) {
return clickedInventory == null ? null : ((PlayerInventory) clickedInventory).getItemInOffHand();
}
return clickedInventory == null ? null : clickedInventory.getItem(event.getHotbarButton());
default:
break;
@@ -273,6 +273,30 @@ public class EventAbstractionListener extends AbstractListener {
}
}
private void handleFallingBlock(EntityChangeBlockEvent event, boolean dropItem) {
Entity entity = event.getEntity();
Block block = event.getBlock();
if (entity instanceof FallingBlock) {
try {
if (dropItem) {
FallingBlock fallingBlock = (FallingBlock) entity;
if (!fallingBlock.getDropItem()) return;
final Material material = fallingBlock.getBlockData().getMaterial();
if (!material.isItem()) return;
ItemStack itemStack = new ItemStack(material, 1);
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
item.setVelocity(new Vector());
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
item.remove();
}
}
} finally {
Cause.untrackParentCause(entity);
}
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Block block = event.getBlock();
@@ -305,43 +329,24 @@ public class EventAbstractionListener extends AbstractListener {
if (denied && entity instanceof Player) {
playDenyEffect((Player) entity, block.getLocation());
}
} else {
if (toType == Material.AIR) {
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
Cause.trackParentCause(entity, block);
// Switch around the event
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
} else {
entityBreakBlockDebounce.debounce(
block, event.getEntity(), event, new BreakBlockEvent(event, cause, block));
}
handleFallingBlock(event, denied);
} else if (toType == Material.AIR) {
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
Cause.trackParentCause(entity, block);
// Switch around the event
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
} else {
boolean wasCancelled = event.isCancelled();
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), toType));
if (entity instanceof FallingBlock) {
try {
if (event.isCancelled() && !wasCancelled) {
FallingBlock fallingBlock = (FallingBlock) entity;
if (!fallingBlock.getDropItem()) return;
final Material material = fallingBlock.getBlockData().getMaterial();
if (!material.isItem()) return;
ItemStack itemStack = new ItemStack(material, 1);
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
item.setVelocity(new Vector());
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
item.remove();
}
}
} finally {
Cause.untrackParentCause(entity);
}
}
entityBreakBlockDebounce.debounce(
block, event.getEntity(), event, new BreakBlockEvent(event, cause, block));
}
} else { // toType != Material.AIR && fromType == Material.AIR
boolean denied = Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), toType));
handleFallingBlock(event, denied);
}
}
@EventHandler(ignoreCancelled = true)
@@ -560,6 +565,7 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onBlockFertilize(BlockFertilizeEvent event) {
if (event.getBlocks().isEmpty()) return;
Cause cause = create(event.getPlayer(), event.getBlock());
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getWorld(), event.getBlocks()));
}
@@ -1042,6 +1048,12 @@ public class EventAbstractionListener extends AbstractListener {
Block placed = dispenserBlock.getRelative(dispenser.getFacing());
Block clicked = placed.getRelative(dispenser.getFacing());
handleBlockRightClick(event, cause, item, clicked, placed);
// handle special dispenser behavior
if (item != null && Materials.isShulkerBox(item.getType())) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(), item.getType()));
return;
}
}
}
@@ -25,6 +25,7 @@ import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@@ -40,6 +41,7 @@ import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.util.Vector;
import org.spigotmc.event.entity.EntityMountEvent;
public class PlayerMoveListener implements Listener {
@@ -53,6 +55,9 @@ public class PlayerMoveListener implements Listener {
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().usePlayerMove) {
PluginManager pm = plugin.getServer().getPluginManager();
pm.registerEvents(this, plugin);
if (PaperLib.isSpigot()) {
pm.registerEvents(new EntityMountListener(), plugin);
}
}
}
@@ -145,4 +150,18 @@ public class PlayerMoveListener implements Listener {
player.teleport(BukkitAdapter.adapt(loc));
}
}
private class EntityMountListener implements Listener {
@EventHandler
public void onEntityMount(EntityMountEvent event) {
Entity entity = event.getEntity();
if (entity instanceof Player) {
LocalPlayer player = plugin.wrapPlayer((Player) entity);
Session session = WorldGuard.getInstance().getPlatform().getSessionManager().get(player);
if (null != session.testMoveTo(player, BukkitAdapter.adapt(event.getMount().getLocation()), MoveType.EMBARK, true)) {
event.setCancelled(true);
}
}
}
}
}
@@ -268,6 +268,11 @@ public class RegionProtectionListener extends AbstractListener {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.CHEST_ACCESS));
what = "take that";
/* Anvils */
} else if (Materials.isAnvil(type)) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.USE_ANVIL));
what = "use that";
/* Beds */
} else if (Materials.isBed(type)) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.INTERACT, Flags.SLEEP));
@@ -31,12 +31,14 @@ import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.util.SpongeUtil;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.Player;
import org.bukkit.entity.Snowman;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -610,13 +612,20 @@ public class WorldGuardBlockListener implements Listener {
return;
}
}
handleGrow(event, event.getBlock().getLocation(), newType);
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockGrow(BlockGrowEvent event) {
WorldConfiguration wcfg = getWorldConfig(event.getBlock().getWorld());
Location loc = event.getBlock().getLocation();
final Material type = event.getNewState().getType();
handleGrow(event, loc, type);
}
private void handleGrow(Cancellable event, Location loc, Material type) {
WorldConfiguration wcfg = getWorldConfig(loc.getWorld());
if (Materials.isCrop(type)) {
if (wcfg.disableCropGrowth) {
event.setCancelled(false);
@@ -624,7 +633,7 @@ public class WorldGuardBlockListener implements Listener {
}
if (wcfg.useRegions && !StateFlag.test(WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery()
.queryState(BukkitAdapter.adapt(event.getBlock().getLocation()), (RegionAssociable) null, Flags.CROP_GROWTH))) {
.queryState(BukkitAdapter.adapt(loc), (RegionAssociable) null, Flags.CROP_GROWTH))) {
event.setCancelled(true);
return;
}
@@ -82,6 +82,7 @@ import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PigZapEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
@@ -845,6 +846,16 @@ public class WorldGuardEntityListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onVehicleEnter(VehicleEnterEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getEntered().getWorld()));
if (wcfg.blockEntityVehicleEntry && !(event.getEntered() instanceof Player)) {
event.setCancelled(true);
}
}
/**
* Checks regions and config settings to protect items from being knocked
* out of item frames.
@@ -393,7 +393,7 @@ public class WorldGuardPlayerListener implements Listener {
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
if (message != null) {
if (message != null && !message.isEmpty()) {
player.sendMessage(message);
}
event.setCancelled(true);
@@ -412,7 +412,7 @@ public class WorldGuardPlayerListener implements Listener {
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
if (message != null) {
if (message != null && !message.isEmpty()) {
player.sendMessage(message);
}
event.setCancelled(true);
@@ -27,6 +27,7 @@ import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.session.AbstractSessionManager;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.Handler;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -40,6 +41,13 @@ import java.util.Collection;
*/
public class BukkitSessionManager extends AbstractSessionManager implements Runnable, Listener {
private boolean useTimings;
@Override
protected Handler.Factory<? extends Handler> wrapForRegistration(Handler.Factory<? extends Handler> factory) {
return useTimings ? new TimedHandlerFactory(factory) : factory;
}
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information for all players.
@@ -75,9 +83,17 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
public boolean hasBypass(LocalPlayer player, World world) {
if (player instanceof BukkitPlayer) {
if (((BukkitPlayer) player).getPlayer().hasMetadata("NPC")
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
return true;
}
return super.hasBypass(player, world);
}
public boolean isUsingTimings() {
return useTimings;
}
public void setUsingTimings(boolean useTimings) {
this.useTimings = useTimings;
}
}
@@ -0,0 +1,132 @@
/*
* 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.bukkit.session;
import co.aikar.timings.lib.MCTiming;
import co.aikar.timings.lib.TimingManager;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.Handler;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.security.CodeSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
class TimedHandlerFactory extends Handler.Factory<Handler> {
private static final TimingManager TIMINGS = TimingManager.of(WorldGuardPlugin.inst());
private static final MCTiming UNKNOWN_SOURCE = TIMINGS.of("Third-Party Session Handlers");
private static final Map<CodeSource, TimingManager> PLUGIN_SOURCES = new HashMap<>();
private final Handler.Factory<?> factory;
private final MCTiming timing;
TimedHandlerFactory(Handler.Factory<?> factory) {
this.factory = factory;
this.timing = makeTiming();
}
private MCTiming makeTiming() {
CodeSource codeSource = factory.getClass().getProtectionDomain().getCodeSource();
TimingManager owner = PLUGIN_SOURCES.computeIfAbsent(codeSource, source -> {
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
CodeSource pluginSource = plugin.getClass().getProtectionDomain().getCodeSource();
if (Objects.equals(pluginSource, source)) {
return TimingManager.of(plugin);
}
}
return null;
});
String handlerName = factory.getClass().getEnclosingClass().getSimpleName();
return owner == null
? TIMINGS.of(handlerName, UNKNOWN_SOURCE)
: owner.of(handlerName, owner.of("Session Handlers"));
}
@Override
public Handler create(Session session) {
return new TimedHandler(factory.create(session), session, timing);
}
static class TimedHandler extends Handler {
private final Handler handler;
private final MCTiming timing;
TimedHandler(Handler innerHandler, Session session, MCTiming timing) {
super(session);
this.handler = innerHandler;
this.timing = timing;
}
@Override
public void initialize(LocalPlayer player, Location current, ApplicableRegionSet set) {
try (MCTiming ignored = timing.startTiming()) {
handler.initialize(player, current, set);
}
}
@Override
public boolean testMoveTo(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, MoveType moveType) {
try (MCTiming ignored = timing.startTiming()) {
return handler.testMoveTo(player, from, to, toSet, moveType);
}
}
@Override
public boolean onCrossBoundary(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
try (MCTiming ignored = timing.startTiming()) {
return handler.onCrossBoundary(player, from, to, toSet, entered, exited, moveType);
}
}
@Override
public void tick(LocalPlayer player, ApplicableRegionSet set) {
try (MCTiming ignored = timing.startTiming()) {
handler.tick(player, set);
}
}
@Nullable
@Override
public StateFlag.State getInvincibility(LocalPlayer player) {
try (MCTiming ignored = timing.startTiming()) {
return handler.getInvincibility(player);
}
}
@Override
public Handler getWrappedHandler() {
return handler;
}
}
}
@@ -52,27 +52,7 @@ public final class Materials {
private static final Map<Material, Integer> MATERIAL_FLAGS = new EnumMap<>(Material.class);
private static final Set<PotionEffectType> DAMAGE_EFFECTS = new HashSet<>();
private static Set<Material> shulkerBoxes = new HashSet<>();
static {
shulkerBoxes.add(Material.SHULKER_BOX);
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.LIGHT_GRAY_SHULKER_BOX);
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);
ENTITY_ITEMS.put(EntityType.PAINTING, Material.PAINTING);
ENTITY_ITEMS.put(EntityType.ARROW, Material.ARROW);
ENTITY_ITEMS.put(EntityType.SNOWBALL, Material.SNOWBALL);
@@ -747,14 +727,15 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.WEEPING_VINES_PLANT, 0);
// Fake tags
for (Material m : shulkerBoxes) {
MATERIAL_FLAGS.put(m, MODIFIED_ON_RIGHT);
}
// Generated via tag
for (Material door : Tag.DOORS.getValues()) {
MATERIAL_FLAGS.put(door, MODIFIED_ON_RIGHT);
for (Material woodenDoor : Tag.WOODEN_DOORS.getValues()) {
MATERIAL_FLAGS.put(woodenDoor, MODIFIED_ON_RIGHT);
}
for (Material woodenTrapdoor : Tag.WOODEN_TRAPDOORS.getValues()) {
MATERIAL_FLAGS.put(woodenTrapdoor, MODIFIED_ON_RIGHT);
}
for (Material shulkerBox : Tag.SHULKER_BOXES.getValues()) {
MATERIAL_FLAGS.put(shulkerBox, MODIFIED_ON_RIGHT);
}
for (Material boat : Tag.ITEMS_BOATS.getValues()) {
MATERIAL_FLAGS.put(boat, 0);
@@ -1034,6 +1015,16 @@ public final class Materials {
return Tag.ITEMS_BOATS.isTagged(material);
}
/**
* Test whether the given material is a Shulker Box.
*
* @param material the material
* @return true if a Shulker Box block
*/
public static boolean isShulkerBox(Material material) {
return Tag.SHULKER_BOXES.isTagged(material);
}
/**
* Test whether the given material is an inventory block.
*
@@ -1052,7 +1043,7 @@ public final class Materials {
|| material == Material.BARREL
|| material == Material.BLAST_FURNACE
|| material == Material.SMOKER
|| shulkerBoxes.contains(material);
|| Tag.SHULKER_BOXES.isTagged(material);
}
public static boolean isSpawnEgg(Material material) {
@@ -1263,6 +1254,10 @@ public final class Materials {
return Tag.BEDS.isTagged(material);
}
public static boolean isAnvil(Material material) {
return Tag.ANVIL.isTagged(material);
}
public static boolean isCoral(Material material) {
return Tag.CORAL_BLOCKS.isTagged(material) ||
Tag.CORAL_PLANTS.isTagged(material) ||
@@ -1287,7 +1282,9 @@ public final class Materials {
|| type == Material.CACTUS
|| type == Material.SUGAR_CANE
|| type == Material.BAMBOO
|| type == Material.BAMBOO_SAPLING;
|| type == Material.BAMBOO_SAPLING
|| type == Material.SWEET_BERRY_BUSH
|| type == Material.NETHER_WART;
}
/**
@@ -1315,11 +1312,10 @@ public final class Materials {
*/
public static boolean isUseFlagApplicable(Material material) {
if (Tag.BUTTONS.isTagged(material)
|| Tag.DOORS.isTagged(material)
|| Tag.WOODEN_DOORS.isTagged(material)
|| Tag.WOODEN_TRAPDOORS.isTagged(material)
|| Tag.FENCE_GATES.isTagged(material)
|| Tag.PRESSURE_PLATES.isTagged(material)
|| Tag.ANVIL.isTagged(material)) {
|| Tag.PRESSURE_PLATES.isTagged(material)) {
return true;
}
switch (material) {
@@ -46,6 +46,7 @@ import com.sk89q.worldguard.protection.flags.RegistryFlag;
import com.sk89q.worldguard.protection.flags.SetFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StringFlag;
import com.sk89q.worldguard.protection.flags.registry.UnknownFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
@@ -108,7 +109,7 @@ class FlagHelperBox extends PaginationBox {
private Component createLine(Flag<?> flag, boolean thirdParty) {
final TextComponent.Builder builder = TextComponent.builder("");
appendFlagName(builder, flag, thirdParty ? TextColor.LIGHT_PURPLE : TextColor.GOLD);
appendFlagName(builder, flag, flag instanceof UnknownFlag ? TextColor.GRAY : thirdParty ? TextColor.LIGHT_PURPLE : TextColor.GOLD);
appendFlagValue(builder, flag);
return builder.build();
}
@@ -255,7 +256,7 @@ class FlagHelperBox extends PaginationBox {
boolean isExplicitSet = currVal != null && !inherited;
boolean maySet = perms.maySetFlag(region, flag);
boolean maySet = !(flag instanceof UnknownFlag) && perms.maySetFlag(region, flag);
TextColor col = isExplicitSet ? TextColor.WHITE : inherited ? TextColor.GRAY : TextColor.DARK_GRAY;
Set<TextDecoration> styles = currVal == defVal ? ImmutableSet.of(TextDecoration.UNDERLINED) : Collections.emptySet();
@@ -359,11 +360,9 @@ class FlagHelperBox extends PaginationBox {
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
@SuppressWarnings("unchecked")
List<V> values = currVal == null ? Collections.emptyList() : (List<V>) flag.marshal(currVal);
String display = (currVal == null ? "" : currVal.size() + "x ") + subName;
final String stringValue = currVal == null ? ""
: values.stream().map(String::valueOf).collect(Collectors.joining(","));
: currVal.stream().map(String::valueOf).collect(Collectors.joining(","));
TextComponent hoverComp = TextComponent.of("");
if (currVal != null) {
hoverComp = hoverComp.append(TextComponent.of("Current values:"))
@@ -25,7 +25,6 @@ import com.google.common.collect.Sets;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
@@ -1124,12 +1123,25 @@ public final class RegionCommands extends RegionCommandsBase {
}
@Command(aliases = {"toggle-bypass", "bypass"},
usage = "[on|off]",
desc = "Toggle region bypassing, effectively ignoring bypass permissions.")
@CommandPermissions({"worldguard.region.toggle-bypass"})
public void toggleBypass(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
if (!player.hasPermission("worldguard.region.toggle-bypass")) {
throw new CommandPermissionsException();
}
Session session = WorldGuard.getInstance().getPlatform().getSessionManager().get(player);
if (session.hasBypassDisabled()) {
boolean shouldEnableBypass;
if (args.argsLength() > 0) {
String arg1 = args.getString(0);
if (!arg1.equalsIgnoreCase("on") && !arg1.equalsIgnoreCase("off")) {
throw new CommandException("Allowed optional arguments are: on, off");
}
shouldEnableBypass = arg1.equalsIgnoreCase("on");
} else {
shouldEnableBypass = session.hasBypassDisabled();
}
if (shouldEnableBypass) {
session.setBypassDisabled(false);
player.print("You are now bypassing region protection (as long as you have permission).");
} else {
@@ -105,6 +105,7 @@ public abstract class WorldConfiguration {
public boolean blockEntityPaintingDestroy;
public boolean blockEntityItemFrameDestroy;
public boolean blockEntityArmorStandDestroy;
public boolean blockEntityVehicleEntry;
public boolean blockPluginSpawning;
public boolean blockGroundSlimes;
public boolean blockZombieDoorDestruction;
@@ -149,7 +149,7 @@ public class PlayerDomain implements Domain, ChangeTracked {
@Override
public boolean contains(LocalPlayer player) {
checkNotNull(player);
return contains(player.getName().trim().toLowerCase()) || contains(player.getUniqueId());
return contains(player.getUniqueId()) || (!names.isEmpty() && contains(player.getName()));
}
/**
@@ -23,6 +23,8 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.managers.RegionManager;
@@ -119,6 +121,50 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
@Nullable
<V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Get the effective value for a key in a {@link MapFlag}. If there are multiple values
* (for example, if there are multiple regions with the same priority
* but with different farewell messages set, there would be multiple
* completing values), then the selected (or "winning") value will be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
<V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key);
/**
* Get the effective value for a key in a {@link MapFlag}. If there are multiple values
* (for example, if there are multiple regions with the same priority
* but with different farewell messages set, there would be multiple
* completing values), then the selected (or "winning") value will be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
<V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback);
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
@@ -24,6 +24,7 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -31,6 +32,7 @@ import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
@@ -65,6 +67,19 @@ public class FailedLoadRegionSet extends AbstractRegionSet {
return flag.getDefault();
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return queryMapValue(subject, flag, key, null);
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
Map<K, V> defaultVal = flag.getDefault();
return defaultVal != null ? defaultVal.get(key) : fallback != null ? fallback.getDefault() : null;
}
@SuppressWarnings("unchecked")
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
@@ -26,6 +26,7 @@ import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
@@ -89,13 +90,14 @@ public class FlagValueCalculator {
/**
* Return the membership status of the given subject, indicating
* whether there are no (counted) regions in the list of regions,
* whether the subject is a member of all regions, or whether
* the region is not a member of all regions.
* whether the subject is a member of all (counted) regions, or
* whether the subject is not a member of all (counted) regions.
*
* <p>A region is "counted" if it doesn't have the
* {@link Flags#PASSTHROUGH} flag set to {@code ALLOW}. (The
* explicit purpose of the PASSTHROUGH flag is to have the region
* be skipped over in this check.)</p>
* {@link Flags#PASSTHROUGH} flag set to {@code ALLOW} and if
* there isn't another "counted" region with a higher priority.
* (The explicit purpose of the PASSTHROUGH flag is to have the
* region be skipped over in this check.)</p>
*
* <p>This method is mostly for internal use. It's not particularly
* useful.</p>
@@ -112,11 +114,13 @@ public class FlagValueCalculator {
Set<ProtectedRegion> ignoredRegions = Sets.newHashSet();
for (ProtectedRegion region : getApplicable()) {
int priority = getPriority(region);
// Don't consider lower priorities below minimumPriority
// (which starts at Integer.MIN_VALUE). A region that "counts"
// (has the flag set OR has members) will raise minimumPriority
// to its own priority.
if (getPriority(region) < minimumPriority) {
if (priority < minimumPriority) {
break;
}
@@ -129,7 +133,7 @@ public class FlagValueCalculator {
continue;
}
minimumPriority = getPriority(region);
minimumPriority = priority;
boolean member = RegionGroup.MEMBERS.contains(subject.getAssociation(Collections.singletonList(region)));
@@ -224,6 +228,112 @@ public class FlagValueCalculator {
return flag.chooseValue(values);
}
/**
* Get the effective value for a key in a {@link MapFlag}. If there are multiple values
* (for example, if there are multiple regions with the same priority
* but with different farewell messages set, there would be multiple
* completing values), then the selected (or "winning") value will be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
checkNotNull(flag);
checkNotNull(key);
Map<ProtectedRegion, V> consideredValues = new HashMap<>();
Map<ProtectedRegion, V> fallbackValues = new HashMap<>();
int minimumPriority = Integer.MIN_VALUE;
Set<ProtectedRegion> ignoredParents = new HashSet<>();
for(ProtectedRegion region : getApplicable()) {
int priority = getPriority(region);
if (priority < minimumPriority) {
break;
}
if (ignoredParents.contains(region)) {
continue;
}
V effectiveValue = getEffectiveMapValue(region, flag, key, subject);
if (effectiveValue != null) {
minimumPriority = priority;
consideredValues.put(region, effectiveValue);
} else if (fallback != null) {
effectiveValue = getEffectiveFlag(region, fallback, subject);
if (effectiveValue != null) {
minimumPriority = priority;
fallbackValues.put(region, effectiveValue);
}
}
addParents(ignoredParents, region);
}
if (consideredValues.isEmpty()) {
if (fallback != null && !fallbackValues.isEmpty()) {
return fallback.chooseValue(fallbackValues.values());
}
V defaultValue = flag.getValueFlag().getDefault();
return defaultValue != null ? defaultValue : fallback != null ? fallback.getDefault() : null;
}
return flag.getValueFlag().chooseValue(consideredValues.values());
}
@Nullable
private <V, K> V getEffectiveMapValue(ProtectedRegion region, MapFlag<K, V> mapFlag, K key, RegionAssociable subject) {
List<ProtectedRegion> seen = new ArrayList<>();
ProtectedRegion current = region;
while (current != null) {
seen.add(current);
Map<K, V> mapValue = current.getFlag(mapFlag);
if (mapValue != null && mapValue.containsKey(key)) {
boolean use = true;
if (mapFlag.getRegionGroupFlag() != null) {
RegionGroup group = current.getFlag(mapFlag.getRegionGroupFlag());
if (group == null) {
group = mapFlag.getRegionGroupFlag().getDefault();
}
if (group == null) {
use = false;
} else if (subject == null) {
use = group.contains(Association.NON_MEMBER);
} else if (!group.contains(subject.getAssociation(seen))) {
use = false;
}
}
if (use) {
return mapValue.get(key);
}
}
current = current.getParent();
}
return null;
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
@@ -283,7 +393,9 @@ public class FlagValueCalculator {
Set<ProtectedRegion> ignoredParents = new HashSet<>();
for (ProtectedRegion region : getApplicable()) {
if (getPriority(region) < minimumPriority) {
int priority = getPriority(region);
if (priority < minimumPriority) {
break;
}
@@ -292,7 +404,6 @@ public class FlagValueCalculator {
}
V value = getEffectiveFlag(region, flag, subject);
int priority = getPriority(region);
if (value != null) {
minimumPriority = priority;
@@ -310,7 +421,7 @@ public class FlagValueCalculator {
// PASSTHROUGH is not set to ALLOW
if (priority != minimumPriority && flag.implicitlySetWithMembership()
&& getEffectiveFlag(region, Flags.PASSTHROUGH, subject) != State.ALLOW) {
minimumPriority = getPriority(region);
minimumPriority = priority;
}
}
@@ -24,6 +24,7 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -31,6 +32,7 @@ import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
@@ -59,6 +61,19 @@ public class PermissiveRegionSet extends AbstractRegionSet {
return flag.getDefault();
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return queryMapValue(subject, flag, key, null);
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
Map<K, V> defaultVal = flag.getDefault();
return defaultVal != null ? defaultVal.get(key) : fallback != null ? fallback.getDefault() : null;
}
@SuppressWarnings("unchecked")
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
@@ -22,6 +22,7 @@ package com.sk89q.worldguard.protection;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -108,6 +109,18 @@ public class RegionResultSet extends AbstractRegionSet {
return flagValueCalculator.queryAllValues(subject, flag);
}
@Override
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return flagValueCalculator.queryMapValue(subject, flag, key, null);
}
@Override
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
return flagValueCalculator.queryMapValue(subject, flag, key, fallback);
}
@Override
public boolean isOwnerOfAll(LocalPlayer player) {
checkNotNull(player);
@@ -22,9 +22,13 @@ package com.sk89q.worldguard.protection.association;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -34,6 +38,7 @@ public abstract class AbstractRegionOverlapAssociation implements RegionAssociab
protected Set<ProtectedRegion> source;
private boolean useMaxPriorityAssociation;
private int maxPriority;
private Set<ProtectedRegion> maxPriorityRegions;
protected AbstractRegionOverlapAssociation(@Nullable Set<ProtectedRegion> source, boolean useMaxPriorityAssociation) {
this.source = source;
@@ -43,13 +48,39 @@ public abstract class AbstractRegionOverlapAssociation implements RegionAssociab
protected void calcMaxPriority() {
checkNotNull(source);
int best = 0;
Set<ProtectedRegion> bestRegions = new HashSet<>();
for (ProtectedRegion region : source) {
int priority = region.getPriority();
if (priority > best) {
best = priority;
bestRegions.clear();
bestRegions.add(region);
} else if (priority == best) {
bestRegions.add(region);
}
}
this.maxPriority = best;
this.maxPriorityRegions = bestRegions;
}
private boolean checkNonplayerProtectionDomains(Iterable<? extends ProtectedRegion> source, Collection<?> domains) {
if (source == null || domains == null || domains.isEmpty()) {
return false;
}
for (ProtectedRegion region : source) {
Set<String> regionDomains = region.getFlag(Flags.NONPLAYER_PROTECTION_DOMAINS);
if (regionDomains == null || regionDomains.isEmpty()) {
continue;
}
if (!Collections.disjoint(regionDomains, domains)) {
return true;
}
}
return false;
}
@Override
@@ -70,6 +101,18 @@ public abstract class AbstractRegionOverlapAssociation implements RegionAssociab
return Association.OWNER;
}
}
Set<ProtectedRegion> source;
if (useMaxPriorityAssociation) {
source = maxPriorityRegions;
} else {
source = this.source;
}
if (checkNonplayerProtectionDomains(source, region.getFlag(Flags.NONPLAYER_PROTECTION_DOMAINS))) {
return Association.OWNER;
}
}
return Association.NON_MEMBER;
@@ -26,7 +26,9 @@ import javax.annotation.Nullable;
/**
* Stores an entity type.
* @deprecated replaced by {@link RegistryFlag<EntityType>}, will be removed in WorldGuard 8
*/
@Deprecated
public class EntityTypeFlag extends Flag<EntityType> {
protected EntityTypeFlag(String name, @Nullable RegionGroup defaultGroup) {
@@ -48,7 +48,7 @@ public final class FlagUtil {
for (Entry<Flag<?>, Object> entry : values.entrySet()) {
try {
rawValues.put(entry.getKey().getName(), marshal(entry.getKey(), entry.getValue()));
} catch (Exception e) {
} catch (Throwable e) {
log.log(Level.WARNING, "Failed to marshal flag value for " + entry.getKey() + "; value is " + entry.getValue(), e);
}
}
@@ -46,6 +46,7 @@ public final class Flags {
// Overrides membership check
public static final StateFlag PASSTHROUGH = register(new StateFlag("passthrough", false));
public static final SetFlag<String> NONPLAYER_PROTECTION_DOMAINS = register(new SetFlag<>("nonplayer-protection-domains", new StringFlag(null)));
// This flag is unlike the others. It forces the checking of region membership
public static final StateFlag BUILD = register(new BuildFlag("build", true));
@@ -71,6 +72,7 @@ public final class Flags {
public static final StateFlag ITEM_FRAME_ROTATE = register(new StateFlag("item-frame-rotation", false));
public static final StateFlag TRAMPLE_BLOCKS = register(new StateFlag("block-trampling", false));
public static final StateFlag FIREWORK_DAMAGE = register(new StateFlag("firework-damage", false));
public static final StateFlag USE_ANVIL = register(new StateFlag("use-anvil", false));
// These flags are similar to the ones above (used in tandem with BUILD),
// but their defaults are set to TRUE because it is more user friendly.
@@ -133,7 +135,7 @@ public final class Flags {
public static final SetFlag<String> ALLOWED_CMDS = register(new SetFlag<>("allowed-cmds", new CommandStringFlag(null)));
// locations
public static final LocationFlag TELE_LOC = register(new LocationFlag("teleport", RegionGroup.MEMBERS));
public static final LocationFlag TELE_LOC = register(new LocationFlag("teleport"));
public static final LocationFlag SPAWN_LOC = register(new LocationFlag("spawn", RegionGroup.MEMBERS));
/**
@@ -24,6 +24,11 @@ import com.sk89q.worldedit.world.gamemode.GameModes;
import javax.annotation.Nullable;
/**
* Stores an gamemode type.
* @deprecated replaced by {@link RegistryFlag<GameMode>}, will be removed in WorldGuard 8
*/
@Deprecated
public class GameModeTypeFlag extends Flag<GameMode> {
protected GameModeTypeFlag(String name, @Nullable RegionGroup defaultGroup) {
@@ -25,6 +25,8 @@ import javax.annotation.Nullable;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.Objects.requireNonNull;
/**
* Stores a key value map of typed {@link Flag}s.
*/
@@ -35,12 +37,16 @@ public class MapFlag<K, V> extends Flag<Map<K, V>> {
public MapFlag(final String name, final Flag<K> keyFlag, final Flag<V> valueFlag) {
super(name);
requireNonNull(keyFlag, "keyFlag cannot be null.");
requireNonNull(valueFlag, "valueFlag cannot be null.");
this.keyFlag = keyFlag;
this.valueFlag = valueFlag;
}
public MapFlag(final String name, @Nullable final RegionGroup defaultGroup, final Flag<K> keyFlag, final Flag<V> valueFlag) {
super(name, defaultGroup);
requireNonNull(keyFlag, "keyFlag cannot be null.");
requireNonNull(valueFlag, "valueFlag cannot be null.");
this.keyFlag = keyFlag;
this.valueFlag = valueFlag;
}
@@ -26,16 +26,20 @@ import javax.annotation.Nullable;
import java.util.Locale;
import java.util.Optional;
import static java.util.Objects.requireNonNull;
public class RegistryFlag<T extends Keyed> extends Flag<T> {
private final Registry<T> registry;
public RegistryFlag(String name, Registry<T> registry) {
super(name);
requireNonNull(registry, "registry cannot be null.");
this.registry = registry;
}
public RegistryFlag(String name, @Nullable RegionGroup defaultGroup, Registry<T> registry) {
super(name, defaultGroup);
requireNonNull(registry, "registry cannot be null.");
this.registry = registry;
}
@@ -27,6 +27,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.util.Objects.requireNonNull;
/**
* Stores a set of types.
*/
@@ -36,11 +38,13 @@ public class SetFlag<T> extends Flag<Set<T>> {
public SetFlag(String name, RegionGroup defaultGroup, Flag<T> subFlag) {
super(name, defaultGroup);
requireNonNull(subFlag, "SubFlag cannot be null.");
this.subFlag = subFlag;
}
public SetFlag(String name, Flag<T> subFlag) {
super(name);
requireNonNull(subFlag, "SubFlag cannot be null.");
this.subFlag = subFlag;
}
@@ -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 javax.annotation.Nullable;
import java.util.UUID;
public class UUIDFlag extends Flag<UUID> {
public UUIDFlag(String name, @Nullable RegionGroup defaultGroup) {
super(name, defaultGroup);
}
public UUIDFlag(String name) {
super(name);
}
@Override
public UUID parseInput(FlagContext context) throws InvalidFlagFormat {
String input = context.getUserInput();
if ("self".equalsIgnoreCase(input)) {
return context.getSender().getUniqueId();
}
try {
return UUID.fromString(input);
} catch (IllegalArgumentException e) {
throw new InvalidFlagFormat("Not a valid uuid: " + input);
}
}
@Override
public UUID unmarshal(@Nullable Object o) {
if (!(o instanceof String)) {
return null;
}
try {
return UUID.fromString((String)o);
} catch (IllegalArgumentException e) {
return null;
}
}
@Override
public Object marshal(UUID o) {
return o.toString();
}
}
@@ -24,6 +24,11 @@ import com.sk89q.worldedit.world.weather.WeatherTypes;
import javax.annotation.Nullable;
/**
* Stores an weather type.
* @deprecated replaced by {@link RegistryFlag<WeatherType>}, will be removed in WorldGuard 8
*/
@Deprecated
public class WeatherTypeFlag extends Flag<WeatherType> {
protected WeatherTypeFlag(String name, @Nullable RegionGroup defaultGroup) {
@@ -144,7 +144,7 @@ public class SimpleFlagRegistry implements FlagRegistry {
} else {
log.warning("Failed to parse flag '" + flag.getName() + "' with value '" + entry.getValue() + "'");
}
} catch (Exception e) {
} catch (Throwable e) {
log.log(Level.WARNING, "Failed to unmarshal flag value for " + flag, e);
}
}
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.util.MathUtils;
import java.awt.Rectangle;
@@ -84,18 +85,24 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* Set the lower point of the cuboid.
*
* @param position the point to set as the minimum point
* @deprecated ProtectedRegion bounds should never be mutated. Regions must be redefined to move them.
* This method will be removed in a future release.
*/
@Deprecated
public void setMinimumPoint(BlockVector3 position) {
setMinMaxPoints(position, max);
WorldGuard.logger.warning("ProtectedCuboidRegion#setMinimumPoint call ignored. Mutating regions leads to undefined behavior.");
}
/**
* Set the upper point of the cuboid.
*
* @param position the point to set as the maximum point
* @deprecated ProtectedRegion bounds should never be mutated. Regions must be redefined to move them.
* This method will be removed in a future release.
*/
@Deprecated
public void setMaximumPoint(BlockVector3 position) {
setMinMaxPoints(min, position);
WorldGuard.logger.warning("ProtectedCuboidRegion#setMaximumPoint call ignored. Mutating regions leads to undefined behavior.");
}
@Override
@@ -34,6 +34,8 @@ import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.managers.RegionManager;
@@ -171,6 +173,56 @@ public class RegionQuery {
queryState(location, associable, flag)));
}
/**
* Returns true if the BUILD flag allows the action in the location, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>This method does include parameters for a {@link MapFlag}.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param location the location
* @param associable an optional associable
* @param mapFlag the MapFlag
* @param key the key for the MapFlag
* @param fallback the fallback flag for MapFlag
* @param flag the flags
* @return true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
*/
public <K> boolean testBuild(Location location, RegionAssociable associable, MapFlag<K, State> mapFlag, K key,
@Nullable StateFlag fallback, StateFlag... flag) {
if (mapFlag == null)
return testBuild(location, associable, flag);
if (flag.length == 0) {
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, associable, Flags.BUILD)),
queryMapValue(location, associable, mapFlag, key, fallback)
));
}
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, associable, Flags.BUILD)),
queryMapValue(location, associable, mapFlag, key, fallback),
queryState(location, associable, flag)
));
}
/**
* Test whether the (effective) value for a list of state flags equals
* {@code ALLOW}.
@@ -319,6 +371,58 @@ public class RegionQuery {
return getApplicableRegions(location).queryValue(associable, flag);
}
/**
* Get the effective value for a key in a {@link MapFlag}. If there are multiple values
* (for example, if there are multiple regions with the same priority
* but with different farewell messages set, there would be multiple
* completing values), then the selected (or "winning") value will be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
public <V, K> V queryMapValue(Location location, @Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return getApplicableRegions(location).queryMapValue(subject, flag, key);
}
/**
* Get the effective value for a key in a {@link MapFlag}. If there are multiple values
* (for example, if there are multiple regions with the same priority
* but with different farewell messages set, there would be multiple
* completing values), then the selected (or "winning") value will be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* <p>It's possible to provide a fallback flag for the case when the key doesn't
* exist in the {@link MapFlag}.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @param fallback the fallback flag
* @return a value, which could be {@code null}
*/
@Nullable
public <V, K> V queryMapValue(Location location, @Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
return getApplicableRegions(location).queryMapValue(subject, flag, key, fallback);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
@@ -44,8 +44,10 @@ import com.sk89q.worldguard.session.handler.WeatherLockFlag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
@@ -73,6 +75,8 @@ public abstract class AbstractSessionManager implements SessionManager {
createSession(key.playerRef.get())));
private boolean hasCustom = false;
// <original handler, wrapped handler>
private Map<Handler.Factory<? extends Handler>, Handler.Factory<? extends Handler>> wrappedHandlers = new HashMap<>();
private List<Handler.Factory<? extends Handler>> handlers = new LinkedList<>();
private static final List<Handler.Factory<? extends Handler>> defaultHandlers = new LinkedList<>();
@@ -106,20 +110,27 @@ public abstract class AbstractSessionManager implements SessionManager {
return hasCustom;
}
protected Handler.Factory<? extends Handler> wrapForRegistration(Handler.Factory<? extends Handler> factory) {
return factory;
}
@Override
public boolean registerHandler(Handler.Factory<? extends Handler> factory, @Nullable Handler.Factory<? extends Handler> after) {
if (factory == null) return false;
WorldGuard.logger.log(Level.INFO, "Registering session handler "
+ factory.getClass().getEnclosingClass().getName());
hasCustom = true;
Handler.Factory<? extends Handler> wrappedFactory = wrapForRegistration(factory);
if (after == null) {
handlers.add(factory);
handlers.add(wrappedFactory);
} else {
int index = handlers.indexOf(after);
Handler.Factory<? extends Handler> wrappedAfter = wrappedHandlers.get(after);
int index = handlers.indexOf(wrappedAfter != null ? wrappedAfter : after);
if (index == -1) return false;
handlers.add(index, factory); // shifts "after" right one, and everything after "after" right one
}
wrappedHandlers.put(factory, wrappedFactory);
return true;
}
@@ -131,6 +142,7 @@ public abstract class AbstractSessionManager implements SessionManager {
} else {
WorldGuard.logger.log(Level.INFO, "Unregistering session handler "
+ factory.getClass().getEnclosingClass().getName());
factory = wrappedHandlers.remove(factory);
}
return handlers.remove(factory);
}
@@ -34,10 +34,10 @@ import com.sk89q.worldguard.protection.regions.RegionQuery;
import com.sk89q.worldguard.session.handler.Handler;
import com.sk89q.worldguard.util.Locations;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -69,7 +69,7 @@ public class Session {
* @param handler A new handler
*/
public void register(Handler handler) {
handlers.put(handler.getClass(), handler);
handlers.put(handler.getWrappedHandler().getClass(), handler);
}
/**
@@ -91,7 +91,7 @@ public class Session {
@Nullable
@SuppressWarnings("unchecked")
public <T extends Handler> T getHandler(Class<T> type) {
return (T) handlers.get(type);
return (T) handlers.get(type).getWrappedHandler();
}
/**
@@ -138,4 +138,11 @@ public abstract class Handler {
return null;
}
/**
* Get the handler wrapped by this handler object, if applicable, or just return this if no handler is wrapped.
* @return any wrapped handler, or this handler itself
*/
public Handler getWrappedHandler() {
return this;
}
}
@@ -24,7 +24,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldguard.WorldGuard;
@@ -60,7 +60,7 @@ public final class SpongeUtil {
for (int cy = -wcfg.spongeRadius; cy <= wcfg.spongeRadius; cy++) {
for (int cz = -wcfg.spongeRadius; cz <= wcfg.spongeRadius; cz++) {
BlockVector3 vector = BlockVector3.at(ox + cx, oy + cy, oz + cz);
BlockState block = world.getBlock(vector);
BaseBlock block = world.getFullBlock(vector);
BlockType blockType = block.getBlockType();
if (isReplacable(blockType)) {
try {
@@ -0,0 +1,124 @@
/*
* 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;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StringFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@SuppressWarnings({"UnusedDeclaration"})
public class FlagValueCalculatorMapFlagTest {
@Test
public void testGetEffectiveMapFlagWithFallback() throws Exception {
MockApplicableRegionSet mock = new MockApplicableRegionSet();
ProtectedRegion global = mock.global();
global.setFlag(Flags.BUILD, StateFlag.State.DENY);
MapFlag<String, StateFlag.State> mapFlag =
new MapFlag<>("test", new StringFlag(null), new StateFlag(null, true));
Map<String, StateFlag.State> map = new HashMap<>();
map.put("allow", StateFlag.State.ALLOW);
map.put("deny", StateFlag.State.DENY);
global.setFlag(mapFlag, map);
ApplicableRegionSet applicableSet = mock.getApplicableSet();
assertThat(applicableSet.queryMapValue(null, mapFlag, "allow", Flags.BUILD),
equalTo(StateFlag.State.ALLOW));
assertThat(applicableSet.queryMapValue(null, mapFlag, "deny", Flags.BUILD),
equalTo(StateFlag.State.DENY));
assertThat(applicableSet.queryMapValue(null, mapFlag, "undefined", Flags.BUILD),
equalTo(StateFlag.State.DENY));
assertThat(applicableSet.queryMapValue(null, mapFlag, "allow", null),
equalTo(StateFlag.State.ALLOW));
assertThat(applicableSet.queryMapValue(null, mapFlag, "deny", null),
equalTo(StateFlag.State.DENY));
assertThat(applicableSet.queryMapValue(null, mapFlag, "undefined", null),
equalTo(StateFlag.State.ALLOW));
}
@Test
public void testGetEffectiveMapFlagWithSamePriority() throws Exception {
MockApplicableRegionSet mock = new MockApplicableRegionSet();
ProtectedRegion region1 = mock.add(0);
ProtectedRegion region2 = mock.add(0);
MapFlag<String, StateFlag.State> mapFlag =
new MapFlag<>("test", new StringFlag(null), new StateFlag(null, true));
Map<String, StateFlag.State> map1 = new HashMap<>();
Map<String, StateFlag.State> map2 = new HashMap<>();
map1.put("should-deny", StateFlag.State.ALLOW);
map2.put("should-deny", StateFlag.State.DENY);
map1.put("should-allow", StateFlag.State.ALLOW);
map1.put("should-allow2", StateFlag.State.ALLOW);
map2.put("should-allow2", StateFlag.State.ALLOW);
region1.setFlag(mapFlag, map1);
region2.setFlag(mapFlag, map2);
ApplicableRegionSet applicableSet = mock.getApplicableSet();
assertThat(applicableSet.queryMapValue(null, mapFlag, "should-deny", null),
equalTo(StateFlag.State.DENY));
assertThat(applicableSet.queryMapValue(null, mapFlag, "should-allow", null),
equalTo(StateFlag.State.ALLOW));
assertThat(applicableSet.queryMapValue(null, mapFlag, "should-allow2", null),
equalTo(StateFlag.State.ALLOW));
}
@Test
public void testGetEffectiveMapFlagWithInheritance() throws Exception {
MockApplicableRegionSet mock = new MockApplicableRegionSet();
ProtectedRegion parent = mock.add(0);
ProtectedRegion child = mock.add(0, parent);
MapFlag<String, StateFlag.State> mapFlag =
new MapFlag<>("test", new StringFlag(null), new StateFlag(null, true));
Map<String, StateFlag.State> parentMap = new HashMap<>();
Map<String, StateFlag.State> childMap = new HashMap<>();
parentMap.put("useChildValue", StateFlag.State.ALLOW);
childMap.put("useChildValue", StateFlag.State.DENY);
parentMap.put("useParentValue", StateFlag.State.ALLOW);
parent.setFlag(mapFlag, parentMap);
child.setFlag(mapFlag, childMap);
ApplicableRegionSet applicableSet = mock.getApplicableSet();
assertThat(applicableSet.queryMapValue(null, mapFlag, "useChildValue", null),
equalTo(StateFlag.State.DENY));
assertThat(applicableSet.queryMapValue(null, mapFlag, "useParentValue", null),
equalTo(StateFlag.State.ALLOW));
}
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 614.24 143.11"><defs><style>.cls-1{fill:none;}.cls-2{fill:#2d2d2d;}.cls-3{clip-path:url(#clip-path);}.cls-4{fill:url(#New_Gradient_Swatch_copy);}.cls-5{mask:url(#mask);}.cls-6{opacity:0.1;}.cls-7{fill:url(#New_Gradient_Swatch_copy-2);}.cls-8{mask:url(#mask-2);}.cls-9{fill:url(#New_Gradient_Swatch_copy-3);}.cls-10{mask:url(#mask-3);}.cls-11{fill:#fff;}.cls-12{filter:url(#luminosity-invert);}</style><clipPath id="clip-path"><path class="cls-1" d="M78.54,138.1c-3.85,3.85-10.45,3.45-14.33-.42L5.07,78.54a9.85,9.85,0,0,1-.07-14L63.63,6c3.85-3.85,11.25-4.68,15.13-.8l59,59c3.88,3.88,3.63,11.13-.23,15Z"/></clipPath><linearGradient id="New_Gradient_Swatch_copy" x1="71.56" y1="3.86" x2="71.56" y2="141.19" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#006bff"/><stop offset="1" stop-color="#004dff"/></linearGradient><filter id="luminosity-invert" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feColorMatrix values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/></filter><mask id="mask" x="29.59" y="-2.48" width="83" height="42" maskUnits="userSpaceOnUse"><g class="cls-12"><image width="83" height="42" transform="translate(29.59 -2.48)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFMAAAAqCAYAAADPn2cJAAAACXBIWXMAAAsSAAALEgHS3X78AAAGoklEQVRoQ+2bWXObQBCEGxDLcsjR6eT//7vEcbmcyDE3eVD11jBaST50PXiqKKILlo+entnFCQAM+IqTRHjsC1/x9pgc+8I1IwxDRFEEAAiCAH3fu+0W42ZhTiYTWGthjHFA27ZF0zQoyxJt2x45wuXjJmHGcYyiKJDn+Qhm13Wo6xovLy/YbDZomubIkS4bNwczSRJ8+/ZtBDMMt9be9z3qukaSJDDG4Pn5GWVZHjni5eKmYFprMZ/PcXd3h+l0iizLEMfxSJlN0yBJEsRxjDAM8fT0dDNAbwamtRar1Qrz+RzT6RRFUcBaiyRJRsqsqsq9T9CPj494fX09cobzx03ATNMUq9UKy+USs9kM0+kUeZ7DWutVZlmWDuZkMkEYhnh4eLg60KvDzLIM6/Uay+USi8Vi5JcynYGtMpum2VFnGIYO6MvLy5Ezni+uCjPLMtzf32O9XmOxWGA2m+Hu7g5FUSDLsqMwqcwoihBFEYIgwK9fv64G9Gow8zzH9+/fsVqtnFfOZjMURYGiKJCm6VGYxhgkSeKABkHggG42myMjOH1cBSZB3t/fY7lcOq+UKU6Y9ERgC7NtW5Rl6dKcfShhhmGIIAgwDMPFFXpxmHme48ePH1iv1zteOZ1OXUskZz+yALVtizRNXREyxjhl0juB7fTz58+f+Pv376HhnDQuCpMg6ZMEOZ/PnSqZ4tITtTLZa/pAMtX5m2EYLpbyF4MpQcr0plfKwpOmKYwxDlYQBAC2YNq2Hc2C4jh27ROhEugwbFcXL6XQi8DUINlTEiRTPM/zUYpLSMA2zdlr1nU9quZSmQB29pdQ6Nlh7gMp05sznizLXEtEmNIHufwmYUpF+mACuJhCzwpTVm16pATJ2Q5hsoLLmQ+rNLCF0nXdTmrr9GYMw+A2vu77/mxV/mwwsyxzINlLMrUlSO2VcprI4iNhsggRIj1Vf88XUqHnSPmzwCTI9Xq9k9bSIyVImd5siWSKM/q+dxClGiVIqUTeAG7y9b9//3bG/pk4OUw5RZQgZ7PZCKT2SRYdVnCpNBm+NkiDPASRewAnn3qeFGaapg6iVCIhUolylsOeUk4NtRp1BEHgKjxjH8S2bV0X0HXd6BkSv3uq1aaTwbTW7i0yhJjnuYNorXUeqRX51pBAj0H0Ae26DsMw4OHh4SQpfxKYXNhdLBYupaUS8zzfUaNuut8LkhGG2yeYcRyPWqc0TdG2rZsxyb0EK2/CZ1fsPw3TWrvTN/Kxg0xpLkxob5RN90eClVxWd2MM2raFtXYEVkLVYIdhwO/fvz8F9FMwkyQZtToSopzNSIi67ZF95EdDzsfDMHTHj+PYeXFd10jT1DX8hEmgVOfj4yOqqjp2Sm98GKYxZm9hkRCPLUicImRf6QNLK+F4rLXIsswpVKq073s8PT19COiHYMZx7CBKkNIPZfMtZyq6jem6zr2/rx06FLLosPUhXAmWFqChUq3SBgj0vc/l3w0zjmPXJ3JxgtWZ00C9AEFAsopybZKf6dXyQ1D19JBFR6YtVeYDK9VqrUVVVQ6qLE5//vx5F9B3wZxMJsjz/CBELk7oKSDhUQEsOPJzpqZWqJ4mcs/CIW+O9kQJlsciVN50+qq11v2Wv9tsNm/+U5w3w4yiCFmWjSD65tEMDZEApUrbtt2xAl4o4F9G41436F3XOYAEUpYlqqryFhuGzwKste77fb+ddr4F6JtgRlHkTFtDlKnpA1hVlVeF2g58xWlfuyS9UcKUyqdCq6oabbLg8Di+gmWMgbXWwX99fUXXdd7xMI7CZDr4WhupGF5IXdcjlTINeZGEKCu8hikVrL1TqpLH3geUCvVBresadV2PFMjzyX61abaPSLpu+0djh4AehEmQvqeAvKtahTqNm6aBMQZVVY18VTfsPK5UOuCHyb2u5NI7pUK5EWJVVc4C+J60AILluIwxo4ImbULGXpi8MAlQp7IuJBosZzoaYByPV8hl1ZcprkEyOAad6hKo9FCtVKlWKlT6qwTHsVCt8rw6vDClh2hYhwAyfSU8mc4yrWkFMq0lUI7DFzrVJVyCkJXcp9Z9gOVGsARHqLxxGuhemNIPOTipTJ6cSpOK0/B8RUaD9MHkWGTINJfj03uqVO4JWO6leiVwvecxfHwYOzA1RN4ZqtIHR9rBIWhvUeIhkAx5AT6VcuPYtbdqwNoe+Fqrm+/viwDY/a8rvouTfqY3Hxyf2uSmzyP3vrEwfF7lU6v+t7YD32v9md58x5bhhfkVH4uPLSJ+hTf+A45XAcRn3tf4AAAAAElFTkSuQmCC"/></g></mask><linearGradient id="New_Gradient_Swatch_copy-2" x1="71.55" y1="3.86" x2="71.55" y2="141.19" xlink:href="#New_Gradient_Swatch_copy"/><mask id="mask-2" x="-2.41" y="45.52" width="148" height="51" maskUnits="userSpaceOnUse"><g class="cls-12"><image width="148" height="51" transform="translate(-2.41 45.52)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJQAAAAzCAYAAABxJSGCAAAACXBIWXMAAAsSAAALEgHS3X78AAAInklEQVR4Xu1d63arvA4cY65J3/9BdxpuBnN+5IwRhiRA0n609azFSgMJYGk0koWztwIwICDgTYiefSAgYAviZx/4Diil3Cs3iWEYJttvB8cfRdHENgRtcES7HIJQAKC1RhzHiKJoYshhGGCtRd/3bjuK8b4ScRzPbEJYa2GtRdd1h7PJIQgVRRHiOEaSJEiSBFprZ0Aarus6GGNgrT2M8b4KURRBa40sy5CmqSOVUmoSYG3bomkaWGufnfLbcAhCKaWgtUaSJMiybEYorTWUUuj7fpYOfyOUUs4WaZoiSZKJavd9j67rnE2MMU/O+H04BKGAW8qj8RiRwI1QjExjzJ8hFANM2oRj77oOURRhGIbJ/iPgEISiAVkzcGOtAEyV6reD9mAZwLTHwGKw9X0/Cb6tWCr0X8VbCPXqjbHoJJEo8VprVzORcH+BUL4tZF0pCdV13UsKpZRy53xXbfoyoRhNwI1Mfd8/+cYcURQ5o3F2o7XGMAwz9eK1fjN8O8jZHm1irZ2o+R6QuMA4+Xm1wN93J/8Hb4jKYa11g/Z7I/xb9lUYIXmeu/NQmRiFSinEcYy+75EkCfI8n02V3xFZ/xV8e2itnT18UsnUJtWrKAo3E37Uk+K1mBFkbcZZozFmlygQuwkli0ZJKDqb9c/SACWZ0jR15+BAeQyAk3gSLU3TWQvBP//RCeanKI5X2kMGGMfuE4JES9MURVGgaRpnewBOzfxr0HfMCvRdkiSo6xpN06DrOuzBLkJxEHmeOzIAcIQyxswiRjqZg5MGI5G4yc9KAjKKGUVSon0VPDKWxiiVyB+ztIt/nJmC9gamtpDnj+MYWZY5dSKhhmGYzLCrqtpFqs2EoiSfTqdJ042FHfOw73BfNbhf67HwJnxS8fu8xiMFPLine truncated

After

Width:  |  Height:  |  Size: 14 KiB