Adds a bunch of event cancellations

Blocks dropping items in a clear region
Blocks usage of XP bottles in a clear region
Block TNT priming in a clear region
Blocks placement of blocks across clear region borders
Blocks breaking of blocks across clear region borders
Blocks blocks inside clear regions from dropping items.
Prevents keeping inventory on death when in a clear region, and makes sure players' inventory is cleared upon death in a clear region, to avoid the potential of players outside the region picking up the items.
Prevents picking up items in a clear region
Prevents pistons from extending if it would push blocks across clear region borders
Prevents pistons from retracting if it would pull blocks across clear region borders
Prevents interacting with items across the clear region border
Prevents changing the mob inside spawners in clear regions
Prevents the usage of spawn eggs in clear regions
Changes Java version to 16
This commit is contained in:
Kristian Knarvik 2024-01-09 23:47:53 +01:00
parent c9a2f082e2
commit d73f4d5377
3 changed files with 225 additions and 21 deletions

View File

@ -1,9 +1,11 @@
# Clear on WorldGuard
This plugin will clear a player's items when they enter or leave one of the configured regions. This is mainly useful
if players are able to go in creative mode in specific WorldGuard regions. This plugin would prevent players from
leaving with all kinds of items. Note that this plugin won't necessarily be useful unless the region has proper
restrictions, like denying item dropping, and denying any sell commands within the region.
This plugin will clear a player's items when they enter or leave, or teleport to or from one of the configured regions.
This is mainly useful if players are able to temporarily go in creative mode in specific WorldGuard regions. A lot of
additional things are blocked within clear regions in order to prevent creative mode abuse, such as: projectiles, XP
bottle usage, spawn egg usage, changing the mob in a spawner, dropping items, picking up items, breaking, placing or
interacting with blocks across clear region borders, block drops, pistons pushing or pulling across clear region
borders, TNT priming and keeping any inventory items if dying within a clear area. This list might not be exhaustive.
## Dependencies

View File

@ -12,7 +12,7 @@
<name>ClearOnWorldGuard</name>
<properties>
<java.version>1.8</java.version>
<java.version>16</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -83,7 +83,7 @@
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.1.0</version>
<version>24.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -9,15 +9,32 @@ import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.TNTPrimeEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SpawnEggMeta;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@ -117,6 +134,138 @@ public class WorldGuardListener implements Listener {
clearIfClearRegionChange(fromLocation, toLocation, event.getPlayer());
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemDrop(@NotNull PlayerDropItemEvent event) {
// Prevent a player from dropping an item while inside a clear region
if (isInClearRegion(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onXpBottle(@NotNull ProjectileLaunchEvent event) {
// Prevent a player from using an XP bottle in a clear region
if (isInClearRegion(event.getEntity())) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onTNT(@NotNull TNTPrimeEvent event) {
// Prevent TNT from being primed in a clear region, or by a player in a clear region
Entity primingEntity = event.getPrimingEntity();
if (primingEntity != null && isInClearRegion(primingEntity)) {
event.setCancelled(true);
return;
}
Block primingBlock = event.getPrimingBlock();
if (primingBlock != null && isInClearRegion(primingBlock)) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockPlace(@NotNull BlockPlaceEvent event) {
// Prevent placing a block outside a clear region
if (isInDifferentClearRegions(event.getPlayer().getLocation(), event.getBlockPlaced().getLocation())) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockBreak(@NotNull BlockBreakEvent event) {
// Prevent breaking a block outside a clear region, while in the clear region
if (isInDifferentClearRegions(event.getPlayer().getLocation(), event.getBlock().getLocation())) {
event.setCancelled(true);
return;
}
// Prevent item drops when the item is destroyed
if (isInClearRegion(event.getBlock())) {
event.setDropItems(false);
}
}
// TODO: Prevent creepers from blowing up
// TODO: Prevent ignition of anything except netherrack and soul sand/soil
// TODO: Prevent dispensers from dispensing
// TODO: Prevent droppers from dropping
@EventHandler(priority = EventPriority.HIGHEST)
public void onDeath(@NotNull PlayerDeathEvent event) {
// Prevent deaths in clear regions from causing items to be kept or dropped
if (isInClearRegion(event.getEntity())) {
event.setKeepInventory(false);
event.setKeepLevel(true);
event.getEntity().getInventory().clear();
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemPickup(@NotNull EntityPickupItemEvent event) {
// Prevent item pickup in clear regions
if (!(event.getEntity() instanceof Player player)) {
return;
}
if (isInClearRegion(player)) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPistonExtend(@NotNull BlockPistonExtendEvent event) {
// Prevent pistons from pushing blocks across the clear region border
Block piston = event.getBlock();
List<Block> blocks = event.getBlocks();
for (Block block : blocks) {
if (isInDifferentClearRegions(piston.getLocation(), block.getLocation())) {
event.setCancelled(true);
return;
}
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPistonRetract(@NotNull BlockPistonRetractEvent event) {
// Prevent pistons from pulling blocks across the clear region border
Block piston = event.getBlock();
List<Block> blocks = event.getBlocks();
for (Block block : blocks) {
if (isInDifferentClearRegions(piston.getLocation(), block.getLocation())) {
event.setCancelled(true);
return;
}
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onInteract(@NotNull PlayerInteractEvent event) {
// Prevent interacting with blocks outside the clear region, such as chests
Block clicked = event.getClickedBlock();
if (clicked != null && isInDifferentClearRegions(event.getPlayer().getLocation(), clicked.getLocation())) {
event.setCancelled(true);
return;
}
// Block changing the creature in a spawner
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && clicked != null && clicked.getType() == Material.SPAWNER &&
isInClearRegion(clicked)) {
event.setCancelled(true);
return;
}
// Block usage of spawn eggs
ItemStack item = event.getItem();
if (item != null && isInClearRegion(event.getPlayer()) && item.hasItemMeta()) {
ItemMeta meta = event.getItem().getItemMeta();
if (meta instanceof SpawnEggMeta) {
event.setCancelled(true);
}
}
}
/**
* Clears the given player's inventory if they are leaving or entering a clear region
*
@ -126,25 +275,78 @@ public class WorldGuardListener implements Listener {
*/
private void clearIfClearRegionChange(@NotNull Location fromLocation, @NotNull Location toLocation,
@NotNull Player player) {
World playerWorld = fromLocation.getWorld();
if (playerWorld == null) {
ClearOnWorldGuard.logger().log(Level.WARNING, "Unable to check region change, as location " +
fromLocation + " has no world.");
return;
}
ApplicableRegionSet setFrom = query.getApplicableRegions(BukkitAdapter.adapt(fromLocation));
ApplicableRegionSet setTo = query.getApplicableRegions(BukkitAdapter.adapt(toLocation));
Set<ProtectedRegion> fromRegions = getOccupiedClearRegions(playerWorld, setFrom.getRegions());
Set<ProtectedRegion> toRegions = getOccupiedClearRegions(playerWorld, setTo.getRegions());
// If the player is in one or more clear regions, clear unless the clear regions are the same
if ((!fromRegions.isEmpty() || !toRegions.isEmpty()) && !fromRegions.equals(toRegions)) {
if (isInDifferentClearRegions(fromLocation, toLocation)) {
player.getInventory().clear();
}
}
/**
* Checks whether the given locations are in different clear regions
*
* <p>If location1 is in a clear region and location2 is not, or if location1 is in a different clear region than
* region2, or if region 1 is in an additional clear region, this will return true.</p>
*
* @param location1 <p>The first location to check</p>
* @param location2 <p>The second location to check</p>
* @return <p>True if the two locations are in different clear regions</p>
*/
private boolean isInDifferentClearRegions(@NotNull Location location1, @NotNull Location location2) {
World fromWorld = location1.getWorld();
if (fromWorld == null) {
ClearOnWorldGuard.logger().log(Level.WARNING, "Unable to check region change, as location " +
location1 + " has no world.");
return false;
}
ApplicableRegionSet setFrom = query.getApplicableRegions(BukkitAdapter.adapt(location1));
ApplicableRegionSet setTo = query.getApplicableRegions(BukkitAdapter.adapt(location2));
Set<ProtectedRegion> fromRegions = getOccupiedClearRegions(fromWorld, setFrom.getRegions());
Set<ProtectedRegion> toRegions = getOccupiedClearRegions(fromWorld, setTo.getRegions());
// If the player is in one or more clear regions, clear unless the clear regions are the same
return (!fromRegions.isEmpty() || !toRegions.isEmpty()) && !fromRegions.equals(toRegions);
}
/**
* Checks whether the given block is in a clear region
*
* @param entity <p>The entity to check</p>
* @return <p>True if the block is in a clear region</p>
*/
private boolean isInClearRegion(@NotNull Entity entity) {
return isInClearRegion(entity.getLocation());
}
/**
* Checks whether the given block is in a clear region
*
* @param block <p>The block to check</p>
* @return <p>True if the block is in a clear region</p>
*/
private boolean isInClearRegion(@NotNull Block block) {
return isInClearRegion(block.getLocation());
}
/**
* Checks whether the given location is in a clear region
*
* @param location <p>The location to check</p>
* @return <p>True if the location is in a clear region</p>
*/
private boolean isInClearRegion(@NotNull Location location) {
World playerWorld = location.getWorld();
if (playerWorld == null) {
ClearOnWorldGuard.logger().log(Level.WARNING, "Unable to check region change, as location " +
location + " has no world.");
return false;
}
ApplicableRegionSet setFrom = query.getApplicableRegions(BukkitAdapter.adapt(location));
Set<ProtectedRegion> fromRegions = getOccupiedClearRegions(playerWorld, setFrom.getRegions());
return !fromRegions.isEmpty();
}
/**
* Gets all regions set as clear regions the player currently occupies
*