diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 5fef8cc10..22993216e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -8,7 +8,7 @@ body: value: | Thanks for taking the time to fill out this bug report for FastAsyncWorldEdit! Fill out the following form to your best ability to help us fix the problem. Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/fastasyncworldedit-documentation/). - Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://forms.gle/btgdRn9yhGtzEiGW8) form! + Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://github.com/IntellectualSites/FastAsyncWorldEdit/security/policy) GitHub form! - type: dropdown attributes: diff --git a/build.gradle.kts b/build.gradle.kts index 82caafa3f..f1d4bb80e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.6.3") +var rootVersion by extra("2.6.4") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java index 2fcb72225..ae3d91027 100644 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java @@ -202,8 +202,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField("entityManager"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java index 5f8e39940..479df3b1a 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java @@ -199,8 +199,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField("entityManager"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index 887d7a3d3..5af8f2806 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -204,8 +204,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField("entityManager"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "L")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index f39fe98f4..e495a078c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -182,8 +182,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4; @@ -480,6 +492,9 @@ public class BukkitWorld extends AbstractWorld { @Override public void simulateBlockMine(BlockVector3 pt) { + //FAWE start - safe edit region + testCoords(pt); + //FAWE end getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); } @@ -493,6 +508,9 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean canPlaceAt(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState blockState) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { return adapter.canPlaceAt(getWorld(), position, blockState); @@ -505,6 +523,9 @@ public class BukkitWorld extends AbstractWorld { @Override public com.sk89q.worldedit.world.block.BlockState getBlock(BlockVector3 position) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { try { @@ -526,6 +547,9 @@ public class BukkitWorld extends AbstractWorld { @Override public > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end if (worldNativeAccess != null) { try { return worldNativeAccess.setBlock(position, block, sideEffects); @@ -545,6 +569,9 @@ public class BukkitWorld extends AbstractWorld { @Override public BaseBlock getFullBlock(BlockVector3 position) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { return adapter.getFullBlock(BukkitAdapter.adapt(getWorld(), position)); @@ -553,11 +580,25 @@ public class BukkitWorld extends AbstractWorld { } } + private void testCoords(BlockVector3 position) throws FaweException { + if (!Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE) { + return; + } + int x = position.getX(); + int z = position.getZ(); + if (x > 30000000 || z > 30000000 || x < -30000000 || z < -30000000) { + throw FaweCache.OUTSIDE_SAFE_REGION; + } + } + @Override public Set applySideEffects( BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType, SideEffectSet sideEffectSet ) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end if (worldNativeAccess != null) { worldNativeAccess.applySideEffects(position, previousType, sideEffectSet); return Sets.intersection( @@ -571,6 +612,9 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { return adapter.simulateItemUse(getWorld(), position, item, face); @@ -588,6 +632,9 @@ public class BukkitWorld extends AbstractWorld { @SuppressWarnings("deprecation") @Override public BiomeType getBiome(BlockVector3 position) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end if (HAS_3D_BIOMES) { return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ())); } else { @@ -598,6 +645,9 @@ public class BukkitWorld extends AbstractWorld { @SuppressWarnings("deprecation") @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { + //FAWE start - safe edit region + testCoords(position); + //FAWE end if (HAS_3D_BIOMES) { getWorld().setBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ(), BukkitAdapter.adapt(biome)); } else { @@ -626,11 +676,13 @@ public class BukkitWorld extends AbstractWorld { @Override public void refreshChunk(int chunkX, int chunkZ) { + testCoords(BlockVector3.at(chunkX << 4, 0, chunkZ << 4)); getWorld().refreshChunk(chunkX, chunkZ); } @Override public IChunkGet get(int chunkX, int chunkZ) { + testCoords(BlockVector3.at(chunkX << 4, 0, chunkZ << 4)); return WorldEditPlugin.getInstance().getBukkitImplAdapter().get(getWorldChecked(), chunkX, chunkZ); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index a6d035155..af14624df 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -171,52 +171,68 @@ public enum FaweCache implements Trimable { public static final FaweBlockBagException BLOCK_BAG = new FaweBlockBagException(); public static final FaweException MANUAL = new FaweException( Caption.of("fawe.cancel.reason.manual"), - Type.MANUAL + Type.MANUAL, + false ); public static final FaweException NO_REGION = new FaweException( Caption.of("fawe.cancel.reason.no.region"), - Type.NO_REGION + Type.NO_REGION, + false ); public static final FaweException OUTSIDE_REGION = new FaweException( Caption.of( "fawe.cancel.reason.outside.region"), + Type.OUTSIDE_REGION, + true + ); + public static final FaweException OUTSIDE_SAFE_REGION = new FaweException( + Caption.of( + "fawe.cancel.reason.outside.safe.region"), Type.OUTSIDE_REGION ); public static final FaweException MAX_CHECKS = new FaweException( Caption.of("fawe.cancel.reason.max" + ".checks"), - Type.MAX_CHECKS + Type.MAX_CHECKS, + true ); public static final FaweException MAX_CHANGES = new FaweException( Caption.of("fawe.cancel.reason.max" + ".changes"), - Type.MAX_CHANGES + Type.MAX_CHANGES, + false ); public static final FaweException LOW_MEMORY = new FaweException( Caption.of("fawe.cancel.reason.low" + ".memory"), - Type.LOW_MEMORY + Type.LOW_MEMORY, + false ); public static final FaweException MAX_ENTITIES = new FaweException( Caption.of( "fawe.cancel.reason.max.entities"), - Type.MAX_ENTITIES + Type.MAX_ENTITIES, + true ); public static final FaweException MAX_TILES = new FaweException(Caption.of( "fawe.cancel.reason.max.tiles", - Type.MAX_TILES + Type.MAX_TILES, + true )); public static final FaweException MAX_ITERATIONS = new FaweException( Caption.of( "fawe.cancel.reason.max.iterations"), - Type.MAX_ITERATIONS + Type.MAX_ITERATIONS, + true ); public static final FaweException PLAYER_ONLY = new FaweException( Caption.of( "fawe.cancel.reason.player-only"), - Type.PLAYER_ONLY + Type.PLAYER_ONLY, + false ); public static final FaweException ACTOR_REQUIRED = new FaweException( Caption.of( "fawe.cancel.reason.actor-required"), - Type.ACTOR_REQUIRED + Type.ACTOR_REQUIRED, + false ); /* diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 5eba1f01f..90ed792fa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -312,6 +312,12 @@ public class Settings extends Config { " - Any blacklist regions are likely to override any internal allowed regions." }) public boolean WORLDGUARD_REGION_BLACKLIST = false; + @Comment({ + "Restrict all edits to within the safe chunk limits of +/- 30 million blocks", + " - Edits outside this range may induce crashing", + " - Forcefully prevents any edit outside this range" + }) + public boolean RESTRICT_TO_SAFE_RANGE = true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index 15a47d973..24d440c57 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -20,6 +20,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -34,19 +35,46 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; public class LimitExtent extends AbstractDelegateExtent { private final FaweLimit limit; + private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; + private final Consumer onErrorMessage; /** * Create a new instance. * * @param extent the extent + * @param limit the limit */ public LimitExtent(Extent extent, FaweLimit limit) { + this(extent, limit, c -> { + }); + } + + /** + * Create a new instance. + * + * @param extent the extent + * @param limit the limit + * @param onErrorMessage consumer to handle a component generated by exceptions + */ + public LimitExtent(Extent extent, FaweLimit limit, Consumer onErrorMessage) { super(extent); this.limit = limit; + this.onErrorMessage = onErrorMessage; + } + + private void handleException(FaweException e) { + if (e.ignorable() || !limit.MAX_FAILS()) { + throw e; + } + if (!faweExceptionReasonsUsed[e.getType().ordinal()]) { + faweExceptionReasonsUsed[e.getType().ordinal()] = true; + onErrorMessage.accept(e.getComponent()); + } } @Override @@ -55,9 +83,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getEntities(region); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return Collections.emptyList(); } } @@ -68,9 +94,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getEntities(); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return Collections.emptyList(); } } @@ -83,9 +107,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.createEntity(location, entity); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return null; } } @@ -98,9 +120,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.createEntity(location, entity, uuid); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return null; } } @@ -112,9 +132,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { super.removeEntity(x, y, z, uuid); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); } } @@ -124,9 +142,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.regenerateChunk(x, z, type, seed); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } @@ -137,9 +153,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getHighestTerrainBlock(x, z, minY, maxY); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -150,9 +164,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getHighestTerrainBlock(x, z, minY, maxY, filter); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -163,9 +175,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceLayer(x, z, y, minY, maxY); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -176,9 +186,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -189,9 +197,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -202,9 +208,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -215,9 +219,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -237,9 +239,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return minY; } } @@ -386,9 +386,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { filter.applyBlock(block.init(pos)); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); } } return filter; @@ -404,9 +402,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getBlock(position); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BlockTypes.AIR.getDefaultState(); } } @@ -417,9 +413,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getBlock(x, y, z); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BlockTypes.AIR.getDefaultState(); } } @@ -430,9 +424,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getFullBlock(position); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } } @@ -443,9 +435,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getFullBlock(x, y, z); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } } @@ -456,9 +446,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getBiome(position); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BiomeTypes.FOREST; } } @@ -469,9 +457,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.getBiomeType(x, y, z); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return BiomeTypes.FOREST; } } @@ -486,9 +472,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.setBlock(position, block); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } @@ -502,9 +486,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.setBlock(x, y, z, block); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } @@ -516,9 +498,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.setTile(x, y, z, tile); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } @@ -529,9 +509,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.setBiome(position, biome); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } @@ -542,9 +520,7 @@ public class LimitExtent extends AbstractDelegateExtent { try { return super.setBiome(x, y, z, biome); } catch (FaweException e) { - if (e.getType() == FaweException.Type.MANUAL || !limit.MAX_FAILS()) { - throw e; - } + handleException(e); return false; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/exception/FaweException.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/exception/FaweException.java index ff1d7913d..fd74ac5de 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/exception/FaweException.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/exception/FaweException.java @@ -14,6 +14,7 @@ public class FaweException extends RuntimeException { private final Component message; private final Type type; + private final boolean ignorable; /** * New instance. Defaults to {@link FaweException.Type#OTHER}. @@ -33,8 +34,19 @@ public class FaweException extends RuntimeException { * New instance of a given {@link FaweException.Type} */ public FaweException(Component reason, Type type) { + this(reason, type, false); + } + + /** + * New instance of a given {@link FaweException.Type} + * + * @param ignorable if an edit can continue if this exception is caught, e.g. by {@link com.fastasyncworldedit.core.extent.LimitExtent} + * @since TODO + */ + public FaweException(Component reason, Type type, boolean ignorable) { this.message = reason; this.type = type; + this.ignorable = ignorable; } @Override @@ -55,6 +67,15 @@ public class FaweException extends RuntimeException { return type; } + /** + * If an edit can continue if this exception is caught, e.g. by {@link com.fastasyncworldedit.core.extent.LimitExtent} + * + * @since TODO + */ + public boolean ignorable() { + return ignorable; + } + public static FaweException get(Throwable e) { if (e instanceof FaweException) { return (FaweException) e; @@ -80,6 +101,7 @@ public class FaweException extends RuntimeException { MANUAL, NO_REGION, OUTSIDE_REGION, + OUTSIDE_SAFE_REGION, MAX_CHECKS, MAX_CHANGES, LOW_MEMORY, diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index a41d8786b..59427c8ef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -293,7 +293,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (pair == lastPair) { return lastChunk; } - if (!processGet(x, z)) { + if (!processGet(x, z) || (Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE + // if any chunk coord is outside 30 million blocks + && (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000))) { lastPair = pair; lastChunk = NullChunk.getInstance(); return NullChunk.getInstance(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java index 29e82790d..7a74ed8ac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java @@ -110,6 +110,14 @@ public class AsyncPreloader implements Preloader, Runnable { Iterator chunksIter = chunks.iterator(); while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid BlockVector2 chunk = chunksIter.next(); + if (Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE) { + int x = chunk.getX(); + int z = chunk.getZ(); + // if any chunk coord is outside 30 million blocks + if (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000) { + continue; + } + } queueLoad(world, chunk); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index 2512af96c..ead916f45 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -65,16 +65,19 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.eventbus.EventBus; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; /** * A builder-style factory for {@link EditSession EditSessions}. @@ -590,10 +593,17 @@ public final class EditSessionBuilder { } else { relighter = NullRelighter.INSTANCE; } + Consumer onErrorMessage; + if (getActor() != null) { + onErrorMessage = c -> getActor().print(Caption.of("fawe.error.occurred-continuing", c)); + } else { + onErrorMessage = c -> { + }; + } if (limit != null && !limit.isUnlimited() && regionExtent != null) { - this.extent = new LimitExtent(regionExtent, limit); + this.extent = new LimitExtent(regionExtent, limit, onErrorMessage); } else if (limit != null && !limit.isUnlimited()) { - this.extent = new LimitExtent(this.extent, limit); + this.extent = new LimitExtent(this.extent, limit, onErrorMessage); } else if (regionExtent != null) { this.extent = regionExtent; } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index ac3c2d3ac..790f7b6fa 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -134,6 +134,7 @@ "fawe.error.limit.disallowed-block": "Your limit disallows use of block '{0}'", "fawe.error.limit.disallowed-property": "Your limit disallows use of property '{0}'", "fawe.error.region-mask-invalid": "Invalid region mask: {0}", + "fawe.error.occurred-continuing": "Ignorable error occurred during edit: {0}", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", @@ -149,6 +150,7 @@ "fawe.cancel.reason.max.iterations": "Max iterations", "fawe.cancel.reason.outside.level": "Outside world", "fawe.cancel.reason.outside.region": "Outside allowed region (bypass with /wea, or disable `region-restrictions` in config.yml)", + "fawe.cancel.reason.outside.safe.region": "Outside safe edit region of +/- 30,000,000 blocks.", "fawe.cancel.reason.no.region": "No allowed region (bypass with /wea, or disable `region-restrictions` in config.yml)", "fawe.cancel.reason.no.region.reason": "No allowed region: {0}", "fawe.cancel.reason.no.region.plot.noworldeditflag": "Plot flag NoWorldeditFlag set",