Compare commits

...
13 Commits
Author SHA1 Message Date
Maddy Miller 0b6c3f1045 Release 7.0.20 2026-10-17 16:41:25 +10:00
Maddy Miller 3f9b7cf4e0 Add cushions to ENTITY_ITEMS 2026-10-17 16:13:38 +10:00
HPnetwork fdbdb91816 Avoid NPE when clearing a region flag (#2307)
* Fix region flag clear feedback

* Use unset feedback when state flag parsing returns null
2026-10-16 21:33:07 +10:00
BaiChuan a670fc70f9 Guard Folia creature cause expansion by region ownership (#2312) 2026-10-16 20:52:49 +10:00
Maddy Miller 408845ad09 Add materials map for 26.3 blocks/items 2026-10-16 20:44:07 +10:00
CatTeaA 96d18c4efc Fix PlayerBucketEmptyEvent to use correct position check (#2313)
* Fix PlayerBucketEmptyEvent to use correct position check

* Considering that cauldrons trigger PlayerBucketEmptyEvent
2026-10-16 09:55:21 +10:00
nivcoo a468153cd8 feat. add entity break event handling and update Paper API version to 26.3 (#2315)
* feat. add entity break event handling and update Paper API version to 26.3

* improv. add braces to handle Hanging entities
2026-10-15 20:27:30 +10:00
Maddy Miller 4181ebfe36 Fixed Poplar boats causing an error, and harden against future issues (#2309) 2026-09-23 19:29:35 +10:00
Maddy Miller a6d64dcc79 Back to SNAPSHOT for continued development 2026-09-18 22:09:41 +10:00
Maddy Miller f395a1675b Release 7.0.19 2026-09-18 22:09:17 +10:00
Brokkonaut 0aeb9d8d54 Fix lock flag restoration after session reinitialization (#2304) 2026-09-18 21:18:27 +10:00
Rasmus Kjær Damgaard 7c280a1348 Cancel blocked natural spawns before the entity is created (#2300)
* Cancel blocked natural spawns before the entity is created

The mob-spawning and deny-spawn checks in WorldGuardEntityListener fire
on CreatureSpawnEvent, at the very end of the spawn pipeline. By that
point the server has picked a spawn position, run the placement checks,
constructed the mob and run finalizeSpawn, and the cancelled mob is
thrown away. Since a cancelled spawn never counts toward the mob cap,
the natural spawner keeps retrying the same area at full rate, so
regions that deny mob spawning become permanent spawn attempt hotspots
that pay entity construction over and over for nothing.

On Paper servers the same checks can run in PreCreatureSpawnEvent,
before the entity exists. Cancelling there also ends the remaining
attempts for the chunk in that spawn cycle, so the wasted work is gone
almost entirely. Measured on a flat test world with a region denying
mob-spawning over the whole spawn range and the mob cap kept empty, the
attempt rate around a single player collapsed from roughly 75000
attempts per second to roughly 60 per second, with no entities
constructed at all.

The new listener mirrors the natural spawn conditions from
onCreatureSpawn exactly: activity halt, block-creature-spawn,
mob-spawning and deny-spawn region flags, and block-ground-slimes. All
other spawn reasons keep going through the existing CreatureSpawnEvent
checks unchanged, and the listener is only registered when the Paper
event class is present.

* Move the pre spawn handler into the existing Paper inner listener

Review feedback: platform specific code lives in the Paper inner
classes of the main listeners, and WorldGuardEntityListener already has
one for EntityZapEvent, so the handler moves in there and the separate
listener class is gone.

* Match the HIGH priority of the other protection handlers

* Extract the shared spawn checks into a method used by both handlers

The pre spawn handler duplicated the tail of onCreatureSpawn. Both now
call handleCreatureSpawn, which takes the event as a Cancellable and
the location, entity type and spawn reason as parameters, following
the same shape as handlePigZap. The entity specific checks (plugin
spawning, armor stands, tamed animals) stay in onCreatureSpawn since
no entity exists yet at pre spawn time, and the activity halt check
stays in each handler so its ordering relative to those checks is
unchanged.

* Pass cfg and wcfg into the shared spawn checks

Both handlers already have them, so the shared method no longer does a
second lookup.

* Correct the rationale on the pre spawn handler

The comment claimed that cancelling ends the chunk's remaining spawn
attempts. It does not. Only setShouldAbortSpawn(true) makes the spawner
return early; a plain cancel falls through to the next candidate position
exactly like a failed placement check.

What the handler does buy is stated accurately instead: the placement
checks, the entity construction and finalizeSpawn are skipped for a spawn
that was going to be refused.

Two consequences a server operator should know are now named. The region
query runs for every candidate position rather than every constructed mob,
because Paper fires the event before the vanilla suitability checks. And on
Paper with per-player-mob-spawns enabled, every cancelled pre spawn is
charged to a per player mob backoff counter, so a large denied region can
suppress spawning in neighbouring chunks that allow mobs.

* Add a config option for the pre spawn handler

regions.use-pre-creature-spawn-event, default true, matching how
regions.use-creature-spawn-event already gates the CreatureSpawnEvent
path. Turning it off leaves the existing handler doing all the work, so
a server that sees a regression can revert without downgrading.
2026-08-11 21:21:44 +10:00
Vladimir Turov c90c483862 Add Cause tracking for SulfurCube (#2295) 2026-08-02 18:20:44 +10:00
16 changed files with 199 additions and 38 deletions

No files matched your search

+16
View File
@@ -1,5 +1,21 @@
# Changelog
## 7.0.20
* Require 26.3+.
* Fixed poplar boats causing errors in some situations.
* Support Paper's new EntityBreakEvent (used for cushion destruction) in protection.
* Improved handling of buckets on waterlogged blocks when sneaking.
* Fixed a Folia error caused by entity actions occuring across Folia region boundaries.
* Improved command feedback when setting a state flag to "none".
## 7.0.19
* Require 26.2+.
* Improved handling for TNT inside of sulfur cubes.
* Improve performance of mob spawn prevention on Paper servers in some situations.
* Improved handling of certain flags when `/wg flushstates` is run, or in certain login situations.
## 7.0.18
* Add lava-harden flag for cobblestone/stone/obsidian/basalt forming.
+1 -1
View File
@@ -1,4 +1,4 @@
group=com.sk89q.worldguard
version=7.0.19-SNAPSHOT
version=7.0.20
org.gradle.parallel=true
+1 -1
View File
@@ -27,7 +27,7 @@ autoService = "com.google.auto.service:auto-service:1.1.1"
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
jetbrains-annotations = "org.jetbrains:annotations:24.1.0"
paperApi = "io.papermc.paper:paper-api:26.2.build.+"
paperApi = "io.papermc.paper:paper-api:26.3.build.+"
paperLib = "io.papermc:paperlib:1.0.8"
dummypermscompat = "com.sk89q:dummypermscompat:1.10"
@@ -40,6 +40,7 @@ import org.bukkit.entity.Firework;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.SulfurCube;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
@@ -117,7 +118,7 @@ public final class Cause {
return false;
}
if (object instanceof TNTPrimed || object instanceof Vehicle) {
if (object instanceof TNTPrimed || object instanceof Vehicle || object instanceof SulfurCube) {
if (!PaperLib.isPaper()) {
return false;
}
@@ -330,10 +331,16 @@ public final class Cause {
}
} else if (o instanceof Creeper c) {
indirect = true;
addAll(c.getTarget(), c.getIgniter());
if (!WorldGuardPlugin.inst().isFolia()
|| Bukkit.isOwnedByCurrentRegion(c)) {
addAll(c.getTarget(), c.getIgniter());
}
} else if (o instanceof Creature c) {
indirect = true;
addAll(c.getTarget());
if (!WorldGuardPlugin.inst().isFolia()
|| Bukkit.isOwnedByCurrentRegion(c)) {
addAll(c.getTarget());
}
} else if (o instanceof BlockProjectileSource) {
addAll(((BlockProjectileSource) o).getBlock());
} else if (o instanceof LightningStrike && PaperLib.isPaper() &&
@@ -48,6 +48,8 @@ import com.sk89q.worldguard.bukkit.util.PaperInterop;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.protection.flags.Flags;
import io.papermc.lib.PaperLib;
import io.papermc.paper.event.entity.EntityBreakByEntityEvent;
import io.papermc.paper.event.entity.EntityBreakEvent;
import io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent;
import io.papermc.paper.event.player.PlayerOpenSignEvent;
import org.bukkit.Bukkit;
@@ -77,12 +79,14 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Firework;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Player;
import org.bukkit.entity.SulfurCube;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.WindCharge;
@@ -667,8 +671,13 @@ public class EventAbstractionListener extends AbstractListener {
Player player = event.getPlayer();
Block blockClicked = event.getBlockClicked();
Block blockAffected;
if (blockClicked.getBlockData() instanceof Waterlogged) {
boolean canPlaceInside = false;
// Can be placed inside blocks only when not sneaking
if (!player.isSneaking()) {
canPlaceInside = (event.getBucket() != Material.LAVA_BUCKET && blockClicked.getBlockData() instanceof Waterlogged)
|| (Materials.isCauldron(blockClicked.getType()) && Materials.isCauldronBucketType(event.getBucket()));
}
if (canPlaceInside) {
blockAffected = blockClicked;
} else {
blockAffected = blockClicked.getRelative(event.getBlockFace());
@@ -895,7 +904,18 @@ public class EventAbstractionListener extends AbstractListener {
if (matchingItem != null && hasInteractBypass(world, matchingItem)) {
useEntityEvent.setAllowed(true);
}
Events.fireToCancel(event, useEntityEvent);
if (!Events.fireToCancel(event, useEntityEvent)) {
/* Sulfur cube doesn't have API for interaction/ignition source tracking */
if(entity instanceof SulfurCube) {
/* Remove player in case of using shears */
if(item.getType() == Material.SHEARS) {
Cause.untrackParentCause(entity);
/* Save player overwise */
} else {
Cause.trackParentCause(entity, player);
}
}
}
}
@EventHandler(ignoreCancelled = true)
@@ -917,6 +937,8 @@ public class EventAbstractionListener extends AbstractListener {
eventToFire.getRelevantFlags().add(Flags.FIREWORK_DAMAGE);
} else if (damager instanceof Creeper) {
eventToFire.getRelevantFlags().add(Flags.CREEPER_EXPLOSION);
} else if (damager instanceof SulfurCube) {
eventToFire.getRelevantFlags().add(Flags.TNT);
}
if (Events.fireToCancel(event, eventToFire)) {
if (damager instanceof Tameable && damager instanceof Mob) {
@@ -1244,7 +1266,11 @@ public class EventAbstractionListener extends AbstractListener {
// Handle created boats
if (item != null && Materials.isBoat(item.getType())) {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), Materials.getRelatedEntity(item.getType())));
EntityType entityType = Materials.getRelatedEntity(item.getType());
if (entityType == null) {
entityType = EntityType.OAK_BOAT;
}
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), entityType));
return;
}
@@ -1362,6 +1388,26 @@ public class EventAbstractionListener extends AbstractListener {
public void onEntityKnockbackByEntity(EntityPushedByEntityAttackEvent event) {
handleKnockback(event, event.getPushedBy());
}
@EventHandler(ignoreCancelled = true)
public void onEntityBreak(EntityBreakEvent event) {
if (event.getEntity() instanceof Hanging) {
return;
}
if (event instanceof EntityBreakByEntityEvent entityEvent) {
Entity remover = entityEvent.getRemover();
Events.fireToCancel(event, new DestroyEntityEvent(event, create(remover), event.getEntity()));
if (event.isCancelled() && remover instanceof Player player) {
playDenyEffect(player, event.getEntity().getLocation());
}
} else if (event.getCause() == EntityBreakEvent.RemoveCause.EXPLOSION) {
DestroyEntityEvent destroyEntityEvent = new DestroyEntityEvent(event, Cause.unknown(), event.getEntity());
destroyEntityEvent.getRelevantFlags().add(Flags.OTHER_EXPLOSION);
Events.fireToCancel(event, destroyEntityEvent);
}
}
}
@SuppressWarnings("removal")
@@ -57,6 +57,7 @@ import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.entity.SulfurCube;
import org.bukkit.entity.Tameable;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
@@ -222,7 +223,7 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* TNT */
if (event.getCause().find(EntityType.TNT, EntityType.TNT_MINECART) != null) {
if (event.getCause().find(EntityType.TNT, EntityType.TNT_MINECART, EntityType.SULFUR_CUBE) != null) {
canBreak = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.BLOCK_BREAK, Flags.TNT));
what = "use dynamite";
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.bukkit.listener;
import com.destroystokyo.paper.event.entity.EntityZapEvent;
import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.LocalPlayer;
@@ -61,6 +62,7 @@ import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.SulfurCube;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.WindCharge;
@@ -487,7 +489,7 @@ public class WorldGuardEntityListener extends AbstractListener {
event.blockList().clear();
return;
}
} else if (ent instanceof TNTPrimed || ent instanceof ExplosiveMinecart) {
} else if (ent instanceof TNTPrimed || ent instanceof ExplosiveMinecart || ent instanceof SulfurCube) {
if (wcfg.blockTNTExplosions) {
event.setCancelled(true);
return;
@@ -615,7 +617,8 @@ public class WorldGuardEntityListener extends AbstractListener {
return;
}
} else if (event.getEntityType() == EntityType.TNT
|| event.getEntityType() == EntityType.TNT_MINECART) {
|| event.getEntityType() == EntityType.TNT_MINECART
|| event.getEntityType() == EntityType.SULFUR_CUBE) {
if (wcfg.blockTNTExplosions) {
event.setCancelled(true);
return;
@@ -655,8 +658,11 @@ public class WorldGuardEntityListener extends AbstractListener {
return;
}
EntityType entityType = event.getEntityType();
handleCreatureSpawn(event, event.getLocation(), event.getEntityType(), event.getSpawnReason(), cfg, wcfg);
}
private static void handleCreatureSpawn(Cancellable event, Location location, EntityType entityType, SpawnReason spawnReason,
ConfigurationManager cfg, WorldConfiguration wcfg) {
com.sk89q.worldedit.world.entity.EntityType weEntityType = BukkitAdapter.adapt(entityType);
if (weEntityType != null && wcfg.blockCreatureSpawn.contains(weEntityType)) {
@@ -664,11 +670,9 @@ public class WorldGuardEntityListener extends AbstractListener {
return;
}
Location eventLoc = event.getLocation();
if (wcfg.useRegions && cfg.useRegionsCreatureSpawnEvent) {
ApplicableRegionSet set =
WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(eventLoc));
WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(location));
if (!set.testState(null, Flags.MOB_SPAWNING)) {
event.setCancelled(true);
@@ -683,8 +687,8 @@ public class WorldGuardEntityListener extends AbstractListener {
}
if (wcfg.blockGroundSlimes && entityType == EntityType.SLIME
&& eventLoc.getY() >= 60
&& event.getSpawnReason() == SpawnReason.NATURAL) {
&& location.getY() >= 60
&& spawnReason == SpawnReason.NATURAL) {
event.setCancelled(true);
return;
}
@@ -905,6 +909,53 @@ public class WorldGuardEntityListener extends AbstractListener {
handlePigZap(event.getEntity(), event);
}
}
/**
* Applies the natural spawn checks from {@link WorldGuardEntityListener#onCreatureSpawn} before the
* server constructs the entity. The CreatureSpawnEvent checks fire at the very
* end of the spawn pipeline, after the position was picked, the placement
* checks ran and the mob was constructed and finalized, so a region that denies
* mob spawning pays for a mob to be built and thrown away on every attempt.
* Cancelling here skips the placement checks, the construction and
* finalizeSpawn for a spawn that was going to be refused anyway.
*
* Cancelling does not end the chunk's remaining attempts. Only
* setShouldAbortSpawn(true) makes the spawner return early; a plain cancel
* falls through to the next candidate position exactly like a failed
* placement check.
*
* Note that Paper fires this event for every candidate position, before the
* light, block and collision checks, so the region query below runs
* considerably more often than the CreatureSpawnEvent one did. On Paper with
* per-player-mob-spawns enabled, which is the default, every cancelled pre
* spawn is also charged to a per player mob backoff counter that is added to
* the mob cap of every player within tick view distance and bleeds off one per
* spawn cycle, so a large denied region can suppress spawning in neighbouring
* chunks that allow mobs.
*
* Only NATURAL spawns are handled here; every other spawn reason keeps going
* through the CreatureSpawnEvent checks unchanged.
*/
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPreCreatureSpawn(PreCreatureSpawnEvent event) {
if (event.getReason() != SpawnReason.NATURAL) {
return;
}
ConfigurationManager cfg = getConfig();
if (!cfg.useRegionsPreCreatureSpawnEvent) {
return;
}
if (cfg.activityHaltToggle) {
event.setCancelled(true);
return;
}
Location spawnLoc = event.getSpawnLocation();
handleCreatureSpawn(event, spawnLoc, event.getType(), event.getReason(), cfg, getWorldConfig(spawnLoc.getWorld()));
}
}
private static class SpigotListener implements Listener {
@@ -43,8 +43,8 @@ import java.util.function.Consumer;
public class BukkitSessionManager extends AbstractSessionManager implements Runnable, Listener {
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information for all players.
* Restore handler-managed state, re-initialize handlers, and clear
* "last position," "last state," etc. information for all players.
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
@@ -72,9 +72,14 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
@EventHandler
public void onPlayerProcess(ProcessPlayerEvent event) {
// Pre-load a session
// Create a new session or re-initialize a cached one.
LocalPlayer player = WorldGuardPlugin.inst().wrapPlayer(event.getPlayer());
get(player).initialize(player);
Session session = getIfPresent(player);
if (session == null) {
get(player); // this also initializes the new session
} else {
session.resetState(player); // old sessions need explicit re-initialization
}
}
@Override
@@ -43,6 +43,7 @@ import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.Steerable;
import org.bukkit.entity.SulfurCube;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
@@ -78,7 +79,9 @@ public final class Entities {
* @return true if TNT based
*/
public static boolean isTNTBased(Entity entity) {
return entity instanceof TNTPrimed || entity instanceof ExplosiveMinecart;
return entity instanceof TNTPrimed
|| entity instanceof ExplosiveMinecart
|| entity instanceof SulfurCube sulfurCube && sulfurCube.canExplode();
}
/**
@@ -265,6 +268,7 @@ public final class Entities {
case Wither wither -> Flags.WITHER_DAMAGE;
case Creeper creeper -> Flags.CREEPER_EXPLOSION;
case TNTPrimed tnt -> Flags.TNT;
case SulfurCube sulfurCube -> Flags.TNT;
case ExplosiveMinecart minecart -> Flags.TNT;
case EnderDragon dragon -> Flags.ENDERDRAGON_BLOCK_DAMAGE;
case null, default -> Flags.OTHER_EXPLOSION;
@@ -80,15 +80,15 @@ public final class Materials {
ENTITY_ITEMS.put(EntityType.EGG, Material.EGG);
ENTITY_ITEMS.put(EntityType.ARMOR_STAND, Material.ARMOR_STAND);
ENTITY_ITEMS.put(EntityType.END_CRYSTAL, Material.END_CRYSTAL);
ENTITY_ITEMS.put(EntityType.CUSHION, Material.WHITE_CUSHION);
for (String wood : new String[]{"OAK", "SPRUCE", "BIRCH", "JUNGLE", "ACACIA", "DARK_OAK", "MANGROVE", "CHERRY", "PALE_OAK"}) {
String regular = wood + "_BOAT";
String chest = wood + "_CHEST_BOAT";
ENTITY_ITEMS.put(EntityType.valueOf(regular), Material.getMaterial(regular));
ENTITY_ITEMS.put(EntityType.valueOf(chest), Material.getMaterial(chest));
}
ENTITY_ITEMS.put(EntityType.BAMBOO_RAFT, Material.BAMBOO_RAFT);
ENTITY_ITEMS.put(EntityType.BAMBOO_CHEST_RAFT, Material.BAMBOO_CHEST_RAFT);
// All boat items should have an entity equivalent, so we can use the tag to map them out.
Tag.ITEMS_BOATS.getValues().forEach(mat -> {
EntityType entityEquivalent = Registry.ENTITY_TYPE.get(mat.getKey());
if (entityEquivalent != null) {
ENTITY_ITEMS.put(entityEquivalent, mat);
}
});
// preset some tags to a default value, override some of them:
putMaterialTag(Tag.DOORS, MODIFIED_ON_RIGHT);
@@ -489,6 +489,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.SUGAR, 0);
MATERIAL_FLAGS.put(Material.COOKIE, 0);
MATERIAL_FLAGS.put(Material.MAP, 0);
putMaterialTag(Tag.ITEMS_CLONABLE_MAPS, 0);
MATERIAL_FLAGS.put(Material.SHEARS, 0);
MATERIAL_FLAGS.put(Material.MELON_SLICE, 0);
MATERIAL_FLAGS.put(Material.PUMPKIN_SEEDS, 0);
@@ -602,6 +603,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.TRIDENT, 0);
MATERIAL_FLAGS.put(Material.TROPICAL_FISH, 0);
MATERIAL_FLAGS.put(Material.TROPICAL_FISH_BUCKET, 0);
MATERIAL_FLAGS.put(Material.SULFUR_CUBE_BUCKET, 0);
MATERIAL_FLAGS.put(Material.CREEPER_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.FLOWER_BANNER_PATTERN, 0);
@@ -747,6 +749,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.MOSS_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HANGING_ROOTS, 0);
MATERIAL_FLAGS.put(Material.POINTED_DRIPSTONE, 0);
MATERIAL_FLAGS.put(Material.DRIPSTONE_BLOCK, 0);
// 1.19
MATERIAL_FLAGS.put(Material.MUD, 0);
@@ -948,6 +951,12 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.CHISELED_SULFUR, 0);
putMaterialTag(Tag.SPELEOTHEMS, 0);
// 26.3
MATERIAL_FLAGS.put(Material.RED_SHRUB, 0);
MATERIAL_FLAGS.put(Material.STRAW_BED, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SHELF_MUSHROOM, 0);
putMaterialTag(Tag.ITEMS_CUSHIONS, 0);
Stream.concat(Stream.concat(
Tag.CORAL_BLOCKS.getValues().stream(),
Tag.CORALS.getValues().stream()),
@@ -1058,6 +1067,7 @@ public final class Materials {
return switch (type) {
case LAVA_BUCKET -> Material.LAVA;
case WATER_BUCKET -> Material.WATER;
case POWDER_SNOW_BUCKET -> Material.POWDER_SNOW;
default -> Material.WATER;
};
}
@@ -1584,4 +1594,19 @@ public final class Materials {
public static boolean isSculkGrowth(Material mat) {
return mat == Material.SCULK || mat == Material.SCULK_VEIN;
}
public static boolean isCauldron(Material mat) {
return switch (mat) {
case CAULDRON, LAVA_CAULDRON, POWDER_SNOW_CAULDRON, WATER_CAULDRON -> true;
default -> false;
};
}
// Other buckets containing mobs cannot be placed inside cauldrons
public static boolean isCauldronBucketType(Material mat) {
return switch (mat) {
case WATER_BUCKET, LAVA_BUCKET, POWDER_SNOW_BUCKET -> true;
default -> false;
};
}
}
@@ -2,5 +2,5 @@ name: WorldGuard
main: com.sk89q.worldguard.bukkit.WorldGuardPlugin
version: "${internalVersion}"
depend: [WorldEdit]
api-version: "26.2"
api-version: "26.3"
folia-supported: true
@@ -597,11 +597,14 @@ public final class RegionCommands extends RegionCommandsBase {
if (value != null) {
// Set the flag if [value] was given even if [-g group] was given as well
try {
value = setFlag(existing, foundFlag, sender, value).toString();
Object parsedValue = setFlag(existing, foundFlag, sender, value);
value = parsedValue == null ? null : parsedValue.toString();
} catch (InvalidFlagFormat e) {
throw new CommandException(e.getMessage());
}
}
if (value != null) {
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + regionId + "' to '" + value + "'.");
}
@@ -65,6 +65,7 @@ public abstract class ConfigurationManager {
"#\r\n";
public boolean useRegionsCreatureSpawnEvent;
public boolean useRegionsPreCreatureSpawnEvent;
public boolean activityHaltToggle = false;
public boolean useGodPermission;
public boolean useGodGroup;
@@ -56,6 +56,7 @@ public abstract class YamlConfigurationManager extends ConfigurationManager {
migrateRegionsToUuid = config.getBoolean("regions.uuid-migration.perform-on-next-start", true);
keepUnresolvedNames = config.getBoolean("regions.uuid-migration.keep-names-that-lack-uuids", true);
useRegionsCreatureSpawnEvent = config.getBoolean("regions.use-creature-spawn-event", true);
useRegionsPreCreatureSpawnEvent = config.getBoolean("regions.use-pre-creature-spawn-event", false);
disableDefaultBypass = config.getBoolean("regions.disable-bypass-by-default", false);
announceBypassStatus = config.getBoolean("regions.announce-bypass-status", false);
@@ -161,11 +161,12 @@ public class Session {
}
/**
* Re-initialize the session.
* Restore handler-managed state and then re-initialize the session.
*
* @param player The player
*/
public void resetState(LocalPlayer player) {
uninitialize(player);
initialize(player);
needRefresh.set(true);
}
@@ -41,14 +41,14 @@ public interface SessionManager {
boolean hasBypass(LocalPlayer player, World world);
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information for all players.
* Restore handler-managed state, re-initialize handlers, and clear
* "last position," "last state," etc. information for all players.
*/
void resetAllStates();
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information.
* Restore handler-managed state, re-initialize handlers, and clear
* "last position," "last state," etc. information.
*
* @param player The player
*/