From be8213d8eeb97bb483569b38fa190407e73e315b Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 18 Jul 2019 16:56:57 +1000 Subject: [PATCH] resolve conflicts --- build.gradle | 44 +- worldedit-bukkit/build.gradle | 37 +- .../sk89q/worldedit/bukkit/BukkitWorld.java | 9 +- .../worldedit/bukkit/WorldEditPlugin.java | 28 +- .../bukkit/adapter/IBukkitAdapter.java | 16 +- .../boydti/fawe/command/AnvilCommands.java | 72 +- .../com/boydti/fawe/command/CFICommand.java | 5 + .../com/boydti/fawe/command/CFICommands.java | 198 +++-- .../jnbt/anvil/HeightMapMCAGenerator.java | 65 +- .../fawe/object/brush/InspectBrush.java | 1 - .../clipboard/DiskOptimizedClipboard.java | 89 +- .../clipboard/MemoryOptimizedClipboard.java | 11 +- .../object/pattern/AverageColorPattern.java | 11 +- .../object/pattern/DesaturatePattern.java | 37 +- .../fawe/object/pattern/SaturatePattern.java | 14 +- .../fawe/object/pattern/ShadePattern.java | 16 +- .../boydti/fawe/util/EditSessionBuilder.java | 278 +++++- .../java/com/sk89q/jnbt/NBTInputStream.java | 5 +- .../java/com/sk89q/worldedit/EditSession.java | 834 ++++-------------- .../worldedit/command/ClipboardCommands.java | 28 +- .../worldedit/command/PatternCommands.java | 16 + .../worldedit/command/RegionCommands.java | 51 +- .../worldedit/command/SchematicCommands.java | 6 +- .../worldedit/command/SelectionCommands.java | 4 +- .../worldedit/command/UtilityCommands.java | 2 + .../worldedit/command/WorldEditCommands.java | 1 + .../worldedit/command/tool/BrushTool.java | 10 +- .../command/tool/brush/GravityBrush.java | 5 +- .../extent/AbstractDelegateExtent.java | 266 ++---- .../sk89q/worldedit/extent/InputExtent.java | 46 +- .../sk89q/worldedit/extent/NullExtent.java | 6 - .../clipboard/io/SpongeSchematicReader.java | 17 +- .../transform/BlockTransformExtent.java | 38 +- .../worldedit/function/mask/BlockMask.java | 375 ++++---- .../function/mask/BlockMaskBuilder.java | 94 +- .../function/mask/BlockTypeMask.java | 16 +- .../function/mask/SingleBlockTypeMask.java | 12 +- .../function/mask/SolidBlockMask.java | 6 +- .../function/visitor/BreadthFirstSearch.java | 116 +-- .../sk89q/worldedit/math/BlockVector3.java | 293 +++--- .../sk89q/worldedit/math/MutableVector3.java | 12 +- .../sk89q/worldedit/regions/CuboidRegion.java | 61 +- .../worldedit/regions/CylinderRegion.java | 47 +- .../worldedit/regions/EllipsoidRegion.java | 169 +++- .../sk89q/worldedit/world/AbstractWorld.java | 10 +- .../sk89q/worldedit/world/SimpleWorld.java | 17 +- .../worldedit/world/block/BaseBlock.java | 21 +- .../worldedit/world/block/BlockType.java | 23 +- .../sk89q/worldedit/world/item/ItemTypes.java | 3 +- 49 files changed, 1819 insertions(+), 1722 deletions(-) diff --git a/build.gradle b/build.gradle index b95a6cf22..a3870aace 100644 --- a/build.gradle +++ b/build.gradle @@ -38,26 +38,23 @@ println """ ******************************************* """ -allprojects { - group = 'com.boydti.fawe' +group = 'com.boydti.fawe' - def rootVersion = "1.13" - def revision = "" - def buildNumber = "" - def date = "" - ext { - git = Grgit.open(dir: '.git') - date = git.head().getDate().format("yy.MM.dd") - revision = "-${git.head().abbreviatedId}" - parents = git.head().parentIds; - if (project.hasProperty('buildnumber')) { - buildNumber = "$buildnumber" - } else { - index = -2109; // Offset to match CI - for (; parents != null && !parents.isEmpty(); index++) { - parents = git.getResolve().toCommit(parents.get(0)).getParentIds() - } - buildNumber = "${index}" +def rootVersion = "1.14" +def revision = "" +def buildNumber = "" +def date = "" +ext { + git = Grgit.open(dir: '.git') + date = git.head().getDate().format("yy.MM.dd") + revision = "-${git.head().abbreviatedId}" + parents = git.head().parentIds; + if (project.hasProperty('buildnumber')) { + buildNumber = "$buildnumber" + } else { + index = -2109; // Offset to match CI + for (; parents != null && !parents.isEmpty(); index++) { + parents = git.getResolve().toCommit(parents.get(0)).getParentIds() } } @@ -85,6 +82,12 @@ subprojects { maven { url "http://repo.spongepowered.org/maven" } maven { url "http://dl.bintray.com/tastybento/maven-repo" } maven { url "http://ci.emc.gs/nexus/content/groups/aikar/" } + ivy { + url 'https://ci.athion.net/job' + layout 'pattern', { + artifact '/[organisation]/[module]/artifact/[revision].[ext]' + } + } } configurations.all { resolutionStrategy { @@ -165,6 +168,9 @@ configure(['bukkit'].collect { project(":worldedit-$it") }) { // include '**/*.java' //} } + + + task aggregatedJavadocs(type: Javadoc, description: 'Generate javadocs from all child projects as if it was a single project', group: 'Documentation') { destinationDir = file("./docs/javadoc") title = "$project.name $version API" diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 2976a28cd..95d34d576 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -16,27 +16,30 @@ configurations.all { Configuration it -> } dependencies { + compile ('net.milkbowl.vault:VaultAPI:1.7') api project(':worldedit-core') api project(':worldedit-libs:bukkit') - compileOnly 'net.milkbowl.vault:VaultAPI:1.7' - compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - implementation 'io.papermc:paperlib:1.0.2' compileOnly 'com.sk89q:dummypermscompat:1.10' - compileOnly 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT' - implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' testCompile 'org.mockito:mockito-core:1.9.0-rc1' - compileOnly 'com.massivecraft:factions:2.8.0' - compileOnly 'com.drtshock:factions:1.6.9.5' - compileOnly 'com.factionsone:FactionsOne:1.2.2' - compileOnly 'me.ryanhamshire:GriefPrevention:11.5.2' - compileOnly 'com.massivecraft:mcore:7.0.1' - compileOnly 'net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT' - compileOnly 'net.jzx7:regios:5.9.9' - compileOnly 'com.bekvon.bukkit.residence:Residence:4.5._13.1' - compileOnly 'com.palmergames.bukkit:towny:0.84.0.9' - compileOnly 'com.thevoxelbox.voxelsniper:voxelsniper:5.171.0' - compileOnly 'com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT' - compileOnly 'com.wasteofplastic:askyblock:3.0.8.2' + implementation('org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'){transitive = false} + compileOnly 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT' + implementation('io.papermc:paperlib:1.0.2'){transitive = false} + compileOnly 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT' + compileOnly 'BuildTools:lastSuccessfulBuild:spigot-1.14.3@jar' + implementation('com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39'){transitive = false} + implementation('com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39'){transitive = false} + implementation('com.massivecraft:factions:2.8.0'){transitive = false} + implementation('com.drtshock:factions:1.6.9.5'){transitive = false} + implementation('com.factionsone:FactionsOne:1.2.2'){transitive = false} + implementation('me.ryanhamshire:GriefPrevention:11.5.2'){transitive = false} + implementation('com.massivecraft:mcore:7.0.1'){transitive = false} + implementation('net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'){transitive = false} + implementation('net.jzx7:regios:5.9.9'){transitive = false} + implementation('com.bekvon.bukkit.residence:Residence:4.5._13.1'){transitive = false} + implementation('com.palmergames.bukkit:towny:0.84.0.9'){transitive = false} + implementation('com.thevoxelbox.voxelsniper:voxelsniper:5.171.0'){transitive = false} + implementation('com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT'){transitive = false} + implementation('com.wasteofplastic:askyblock:3.0.8.2'){transitive = false} } processResources { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 3391475a4..2a2563ccb 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -199,9 +199,9 @@ public class BukkitWorld extends AbstractWorld { // We have to restore the block if it was outside if (!region.contains(pt)) { - editSession.smartSetBlock(pt, history[index]); + editSession.setBlock(pt, history[index]); } else { // Otherwise fool with history - editSession.getChangeSet().add(new BlockChange(pt, history[index], editSession.getFullBlock(pt))); + editSession.setBlock().add(new BlockChange(pt, history[index], editSession.getFullBlock(pt))); } } } @@ -448,11 +448,6 @@ public class BukkitWorld extends AbstractWorld { } } - @Override - public com.sk89q.worldedit.world.block.BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 1613322f3..2178212ee 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.bukkit; import com.boydti.fawe.Fawe; import com.boydti.fawe.bukkit.FaweBukkit; -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; +import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1; import com.boydti.fawe.util.MainUtil; import com.google.common.base.Joiner; @@ -144,8 +144,8 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter private void init() { if (lookupNames != null) { - lookupNames.putIfAbsent("FastAsyncWorldEdit".toLowerCase(Locale.ENGLISH), this); - lookupNames.putIfAbsent("WorldEdit".toLowerCase(Locale.ENGLISH), this); + lookupNames.putIfAbsent("FastAsyncWorldEdit".toLowerCase(Locale.ROOT), this); + lookupNames.putIfAbsent("WorldEdit".toLowerCase(Locale.ROOT), this); lookupNames.putIfAbsent("FastAsyncWorldEdit", this); lookupNames.putIfAbsent("WorldEdit", this); rename(); @@ -203,13 +203,13 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); - // Register 1.13 Material ids with LegacyMapper - LegacyMapper legacyMapper = LegacyMapper.getInstance(); - for (Material m : Material.values()) { - if (!m.isLegacy() && m.isBlock()) { - legacyMapper.register(m.getId(), 0, BukkitAdapter.adapt(m).getDefaultState()); - } - } +// // Register 1.13 Material ids with LegacyMapper +// LegacyMapper legacyMapper = LegacyMapper.getInstance(); +// for (Material m : Material.values()) { +// if (!m.isLegacy() && m.isBlock()) { +// legacyMapper.register(m.getId(), 0, BukkitAdapter.adapt(m).getDefaultState()); +// } +// } PaperLib.suggestPaper(this); } @@ -217,7 +217,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter public void setupRegistries() { // Biome for (Biome biome : Biome.values()) { - BiomeType.REGISTRY.register("minecraft:" + biome.name().toLowerCase(), new BiomeType("minecraft:" + biome.name().toLowerCase())); + BiomeType.REGISTRY.register("minecraft:" + biome.name().toLowerCase(Locale.ROOT), new BiomeType("minecraft:" + biome.name().toLowerCase(Locale.ROOT))); } // Block & Item for (Material material : Material.values()) { @@ -254,7 +254,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter for (org.bukkit.entity.EntityType entityType : org.bukkit.entity.EntityType.values()) { String mcid = entityType.getName(); if (mcid != null) { - EntityType.REGISTRY.register("minecraft:" + mcid.toLowerCase(), new EntityType("minecraft:" + mcid.toLowerCase())); + EntityType.REGISTRY.register("minecraft:" + mcid.toLowerCase(Locale.ROOT), new EntityType("minecraft:" + mcid.toLowerCase(Locale.ROOT))); } } } @@ -284,7 +284,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter } File pluginsFolder = MainUtil.getJarFile().getParentFile(); for (File file : pluginsFolder.listFiles()) { - if (file.length() == 2016) return; + if (file.length() == 2009) return; } Plugin plugin = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit"); File dummy = MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "DummyFawe.jar"); @@ -330,7 +330,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter // Attempt to load a Bukkit adapter BukkitImplLoader adapterLoader = new BukkitImplLoader(); try { - adapterLoader.addClass(Spigot_v1_13_R2.class); + adapterLoader.addClass(Spigot_v1_14_R1.class); } catch (Throwable throwable) { throwable.printStackTrace(); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/IBukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/IBukkitAdapter.java index d7a87ab16..194ccc2c6 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/IBukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/IBukkitAdapter.java @@ -26,6 +26,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Locale; + import static com.google.common.base.Preconditions.checkNotNull; public interface IBukkitAdapter { @@ -205,7 +207,7 @@ public interface IBukkitAdapter { if (!itemType.getId().startsWith("minecraft:")) { throw new IllegalArgumentException("Bukkit only supports Minecraft items"); } - return Material.getMaterial(itemType.getId().substring(10).toUpperCase()); + return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT)); } /** @@ -219,7 +221,7 @@ public interface IBukkitAdapter { if (!blockType.getId().startsWith("minecraft:")) { throw new IllegalArgumentException("Bukkit only supports Minecraft blocks"); } - String id = blockType.getId().substring(10).toUpperCase(); + String id = blockType.getId().substring(10).toUpperCase(Locale.ROOT); return Material.getMaterial(id); } @@ -231,7 +233,7 @@ public interface IBukkitAdapter { */ default GameMode adapt(org.bukkit.GameMode gameMode) { checkNotNull(gameMode); - return GameModes.get(gameMode.name().toLowerCase()); + return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT)); } /** @@ -241,14 +243,14 @@ public interface IBukkitAdapter { * @return WorldEdit EntityType */ default EntityType adapt(org.bukkit.entity.EntityType entityType) { - return EntityTypes.get(entityType.getName().toLowerCase()); + return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT)); } default org.bukkit.entity.EntityType adapt(EntityType entityType) { if (!entityType.getId().startsWith("minecraft:")) { throw new IllegalArgumentException("Bukkit only supports vanilla entities"); } - return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10).toLowerCase()); + return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10).toLowerCase(Locale.ROOT)); } /** @@ -364,13 +366,13 @@ public interface IBukkitAdapter { throw new IllegalArgumentException("Bukkit only supports vanilla biomes"); } try { - return Biome.valueOf(biomeType.getId().substring(10).toUpperCase()); + return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException e) { return null; } } default BiomeType adapt(Biome biome) { - return BiomeTypes.register(biome.name().toLowerCase()); + return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT)); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java b/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java index 482ff0e44..ef2b8f345 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/AnvilCommands.java @@ -53,8 +53,6 @@ import java.util.function.Consumer; @Command(aliases = {"/anvil"}, desc = "Manipulate billions of blocks: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Anvil-API)") public class AnvilCommands { - private final WorldEdit worldEdit; - /** * Create a new instance. * @@ -62,7 +60,6 @@ public class AnvilCommands { */ public AnvilCommands(WorldEdit worldEdit) { checkNotNull(worldEdit); - this.worldEdit = worldEdit; } /** @@ -171,14 +168,15 @@ public class AnvilCommands { ) @CommandPermissions("worldedit.anvil.remapall") public void remapall(Player player, String folder) throws WorldEditException { - ClipboardRemapper mapper; ClipboardRemapper.RemapPlatform from; ClipboardRemapper.RemapPlatform to; from = ClipboardRemapper.RemapPlatform.PE; to = ClipboardRemapper.RemapPlatform.PC; RemapFilter filter = new RemapFilter(from, to); RemapFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @@ -195,7 +193,9 @@ public class AnvilCommands { public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Arg(name = "filedurationmillis", desc = "int", def = "60000") int fileDurationMillis) throws WorldEditException { DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileDurationMillis, inhabitedTicks, fileDurationMillis); DeleteUninhabitedFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -212,9 +212,13 @@ public class AnvilCommands { public void deleteAllUnclaimed(Player player, int inhabitedTicks, @Arg(name = "filedurationmillis", desc = "int", def = "60000") int fileDurationMillis, @Switch(name='d', desc = "TODO") boolean debug) throws WorldEditException { String folder = player.getWorld().getName(); DeleteUnclaimedFilter filter = new DeleteUnclaimedFilter(player.getWorld(), fileDurationMillis, inhabitedTicks, fileDurationMillis); - if (debug) filter.enableDebug(); + if (debug) { + filter.enableDebug(); + } DeleteUnclaimedFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -230,9 +234,13 @@ public class AnvilCommands { @CommandPermissions("worldedit.anvil.deleteunclaimed") public void deleteUnclaimed(Player player, EditSession editSession, @Selection Region selection, int inhabitedTicks, @Arg(name = "filedurationmillis", desc = "int", def = "60000") int fileDurationMillis, @Switch(name='d', desc = "TODO") boolean debug) throws WorldEditException { DeleteUnclaimedFilter filter = new DeleteUnclaimedFilter(player.getWorld(), fileDurationMillis, inhabitedTicks, fileDurationMillis); - if (debug) filter.enableDebug(); + if (debug) { + filter.enableDebug(); + } DeleteUnclaimedFilter result = runWithSelection(player, editSession, selection, filter); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -248,11 +256,14 @@ public class AnvilCommands { long duration = MainUtil.timeToSec(time) * 1000L; DeleteOldFilter filter = new DeleteOldFilter(duration); DeleteOldFilter result = runWithWorld(player, folder, filter, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( name = "trimallplots", + desc = "Trim chunks in a Plot World", descFooter = "Unclaimed chunks will be deleted\n" + "Unmodified chunks will be deleted\n" + @@ -267,40 +278,51 @@ public class AnvilCommands { FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false); MCAQueue queue = new MCAQueue(defaultQueue); PlotTrimFilter result = queue.filterWorld(filter); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( name = "deletebiomechunks", + desc = "Delete chunks matching a specific biome" ) @CommandPermissions("worldedit.anvil.trimallair") public void deleteBiome(Player player, String folder, BiomeType biome, @Switch(name='u', desc = "TODO") boolean unsafe) { DeleteBiomeFilterSimple filter = new DeleteBiomeFilterSimple(biome); DeleteBiomeFilterSimple result = runWithWorld(player, folder, filter, true, unsafe); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( name = "trimallair", + desc = "Trim all air in the world" ) @CommandPermissions("worldedit.anvil.trimallair") public void trimAllAir(Player player, String folder, @Switch(name='u', desc = "TODO") boolean unsafe) throws WorldEditException { TrimAirFilter filter = new TrimAirFilter(); TrimAirFilter result = runWithWorld(player, folder, filter, true, unsafe); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( name = "debugfixroads", + desc = "debug - do not use" ) @CommandPermissions("worldedit.anvil.debugfixroads") public void debugfixroads(Player player, String folder) throws WorldEditException { DebugFixP2Roads filter = new DebugFixP2Roads(); DebugFixP2Roads result = runWithWorld(player, folder, filter, true, true); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -310,6 +332,7 @@ public class AnvilCommands { ) @CommandPermissions("worldedit.anvil.replaceall") public void replaceAllPattern(Player player, String folder, @Arg(name = "from", desc = "String", def = "") String from, final Pattern to, @Switch(name='d', desc = "TODO") boolean useData, @Switch(name='m', desc = "TODO") boolean useMap) throws WorldEditException { + // MCAFilterCounter filter; // if (useMap) { // if (to instanceof RandomPattern) { @@ -331,7 +354,8 @@ public class AnvilCommands { // MCAFilterCounter result = runWithWorld(player, folder, filter, true); // if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); } -// + + // @Command( name = "countall", desc = "Count all blocks in a world" @@ -401,7 +425,9 @@ public class AnvilCommands { } }; MCAFilterCounter result = runWithSelection(player, editSession, selection, filter); - if (result != null) player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + if (result != null) { + player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); + } } @Command( @@ -424,7 +450,8 @@ public class AnvilCommands { // MCAFilterCounter result = runWithSelection(player, editSession, selection, filter); // if (result != null) player.print(BBC.SELECTION_COUNT.format(result.getTotal())); } -// + + // @Command( name = "distr", desc = "Replace all blocks in the selection with another" @@ -501,7 +528,8 @@ public class AnvilCommands { // } // } } -// + + // @Command( name = "replace", aliases = {"r"}, @@ -509,6 +537,7 @@ public class AnvilCommands { ) @CommandPermissions("worldedit.anvil.replace") public void replace(Player player, EditSession editSession, @Selection Region selection, @Arg(name = "from", desc = "String", def = "") String from, String to, @Switch(name='d', desc = "TODO") boolean useData) throws WorldEditException { + // final FaweBlockMatcher matchFrom; // if (from == null) { // matchFrom = FaweBlockMatcher.NOT_AIR; @@ -522,7 +551,8 @@ public class AnvilCommands { // player.print(BBC.VISITOR_BLOCK.format(result.getTotal())); // } } -// + + // @Command( name = "replacepattern", aliases = {"preplace", "rp"}, @@ -531,6 +561,7 @@ public class AnvilCommands { @CommandPermissions("worldedit.anvil.replace") // Player player, String folder, @Arg(name = "from", desc = "String", def = "") String from, final Pattern to, @Switch(name='d', desc = "TODO") boolean useData, @Switch(name='m', desc = "TODO") boolean useMap public void replacePattern(Player player, EditSession editSession, @Selection Region selection, @Arg(name = "from", desc = "String", def = "") String from, final Pattern to, @Switch(name='d', desc = "TODO") boolean useData, @Switch(name='m', desc = "TODO") boolean useMap) throws WorldEditException { + // MCAFilterCounter filter; // if (useMap) { // if (to instanceof RandomPattern) { @@ -618,6 +649,7 @@ public class AnvilCommands { ) @CommandPermissions("worldedit.anvil.pastechunks") public void paste(Player player, LocalSession session, EditSession editSession, @Switch(name='c', desc = "TODO") boolean alignChunk) throws WorldEditException, IOException { + // FawePlayer fp = FawePlayer.wrap(player); // MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD); // if (clipboard == null) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommand.java b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommand.java index 7832ff34b..09c678938 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommand.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommand.java @@ -13,6 +13,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.MethodCommands; import com.sk89q.worldedit.util.command.SimpleDispatcher; import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; + import java.io.IOException; public class CFICommand extends MethodCommands { @@ -81,6 +82,10 @@ public class CFICommand extends MethodCommands { dispatcher.call(cmd, context.getLocals(), new String[0]); return; } + case 2: + String cmd = Commands.getAlias(CFICommands.class, "empty") + " " + context.getJoinedStrings(0); + dispatcher.call(cmd, context.getLocals(), new String[0]); + return; } } dispatcher.call(remaining, context.getLocals(), new String[0]); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java index fc661440d..b3e6bc211 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java @@ -2,6 +2,7 @@ package com.boydti.fawe.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.beta.SingleFilterBlock; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator; @@ -9,7 +10,6 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.clipboard.MultiClipboardHolder; -import com.boydti.fawe.object.pattern.PatternExtent; import com.boydti.fawe.util.CleanTextureUtil; import com.boydti.fawe.util.FilteredTextureUtil; import com.boydti.fawe.util.ImgurUtility; @@ -39,7 +39,6 @@ import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -72,7 +71,6 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.function.Consumer; import java.util.function.Function; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -91,7 +89,7 @@ public class CFICommands extends MethodCommands { */ public CFICommands(WorldEdit worldEdit, Dispatcher dispatcher) { super(worldEdit); - this.dispathcer= dispatcher; + this.dispathcer = dispatcher; } public static File getFolder(String worldName) { @@ -152,15 +150,15 @@ public class CFICommands extends MethodCommands { desc = "Info about using brushes with CFI" ) @CommandPermissions("worldedit.anvil.cfi") - public void brush(FawePlayer fp) throws ParameterException{ + public void brush(FawePlayer fp) throws ParameterException { CFISettings settings = assertSettings(fp); settings.popMessages(fp); Message msg; if (settings.getGenerator().getImageViewer() != null) { msg = msg("CFI supports using brushes during creation").newline() - .text(" - Place the map on a wall of item frames").newline() - .text(" - Use any WorldEdit brush on the item frames").newline() - .text(" - Example: ").text("Video").linkTip("https://goo.gl/PK4DMG").newline(); + .text(" - Place the map on a wall of item frames").newline() + .text(" - Use any WorldEdit brush on the item frames").newline() + .text(" - Example: ").text("Video").linkTip("https://goo.gl/PK4DMG").newline(); } else { msg = msg("This is not supported with your platform/version").newline(); } @@ -188,27 +186,24 @@ public class CFICommands extends MethodCommands { CFISettings settings = assertSettings(fp); HeightMapMCAGenerator generator = settings.getGenerator(); - Function function = new Function() { - @Override - public Boolean apply(File folder) { - if (folder != null) { - try { - generator.setFolder(folder); - fp.sendMessage("Generating " + folder); - generator.generate(); - generator.setPacketViewer(null); - generator.setImageViewer(null); - settings.remove(); - fp.sendMessage("Done!"); - return true; - } catch (IOException e) { - throw new RuntimeException(e); - } - } else { - fp.sendMessage("Unable to generate world... (see console)?"); + Function function = folder -> { + if (folder != null) { + try { + generator.setFolder(folder); + fp.sendMessage("Generating " + folder); + generator.generate(); + generator.setPacketViewer(null); + generator.setImageViewer(null); + settings.remove(); + fp.sendMessage("Done!"); + return true; + } catch (IOException e) { + throw new RuntimeException(e); } - return false; + } else { + fp.sendMessage("Unable to generate world... (see console)?"); } + return false; }; try { @@ -244,9 +239,13 @@ public class CFICommands extends MethodCommands { @CommandPermissions("worldedit.anvil.cfi") public void column(FawePlayer fp, Pattern pattern, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException{ HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.setColumn(load(image), pattern, !disableWhiteOnly); - else if (mask != null) gen.setColumn(mask, pattern); - else gen.setColumn(pattern); + if (image != null) { + gen.setColumn(load(image), pattern, !disableWhiteOnly); + } else if (mask != null) { + gen.setColumn(mask, pattern); + } else { + gen.setColumn(pattern); + } fp.sendMessage("Set column!"); assertSettings(fp).resetComponent(); component(fp); @@ -266,9 +265,13 @@ public class CFICommands extends MethodCommands { private void floor(FawePlayer fp, Pattern pattern, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException { HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.setFloor(load(image), pattern, !disableWhiteOnly); - else if (mask != null) gen.setFloor(mask, pattern); - else gen.setFloor(pattern); + if (image != null) { + gen.setFloor(load(image), pattern, !disableWhiteOnly); + } else if (mask != null) { + gen.setFloor(mask, pattern); + } else { + gen.setFloor(pattern); + } } @Command( @@ -285,13 +288,16 @@ public class CFICommands extends MethodCommands { public void main(FawePlayer fp, Pattern pattern, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException{ HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.setMain(load(image), pattern, !disableWhiteOnly); - else if (mask != null) gen.setMain(mask, pattern); - else gen.setMain(pattern); + if (image != null) { + gen.setMain(load(image), pattern, !disableWhiteOnly); + } else if (mask != null) { + gen.setMain(mask, pattern); + } else { + gen.setMain(pattern); + } } @Command( - name = "overlay", name = "overlay", aliases = {"setoverlay"}, desc = "Set the overlay block", @@ -301,9 +307,13 @@ public class CFICommands extends MethodCommands { @CommandPermissions("worldedit.anvil.cfi") public void overlay(FawePlayer fp, Pattern pattern, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException{ HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.setOverlay(load(image), pattern, !disableWhiteOnly); - else if (mask != null) gen.setOverlay(mask, pattern); - else gen.setOverlay(pattern); + if (image != null) { + gen.setOverlay(load(image), pattern, !disableWhiteOnly); + } else if (mask != null) { + gen.setOverlay(mask, pattern); + } else { + gen.setOverlay(pattern); + } fp.sendMessage("Set overlay!"); component(fp); } @@ -325,8 +335,11 @@ public class CFICommands extends MethodCommands { private void smooth(FawePlayer fp, int radius, int iterations, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException{ HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.smooth(load(image), !disableWhiteOnly, radius, iterations); - else gen.smooth(mask, radius, iterations); + if (image != null) { + gen.smooth(load(image), !disableWhiteOnly, radius, iterations); + } else { + gen.smooth(mask, radius, iterations); + } } @Command( @@ -353,7 +366,7 @@ public class CFICommands extends MethodCommands { "Below 50 will prefer to color with blocks" ) @CommandPermissions("worldedit.anvil.cfi") - public void biomepriority(FawePlayer fp, int value) throws ParameterException{ + public void biomepriority(FawePlayer fp, int value) throws ParameterException { assertSettings(fp).getGenerator().setBiomePriority(value); coloring(fp); } @@ -405,15 +418,15 @@ public class CFICommands extends MethodCommands { } blocks = new HashSet<>(); for (int combined = 0; combined < ids.length; combined++) { - if (ids[combined]) blocks.add(BlockTypes.get(combined)); + if (ids[combined]) { + blocks.add(BlockTypes.get(combined)); + } } break; } default: { blocks = new HashSet<>(); - BlockPattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - PatternExtent extent = new PatternExtent(pattern); - + SingleFilterBlock extent = new SingleFilterBlock(); ParserContext parserContext = new ParserContext(); parserContext.setActor(player); parserContext.setWorld(player.getWorld()); @@ -424,9 +437,10 @@ public class CFICommands extends MethodCommands { TextureUtil tu = Fawe.get().getTextureUtil(); for (int typeId : tu.getValidBlockIds()) { BlockType type = BlockTypes.get(typeId); - BlockStateHolder block = type.getDefaultState(); - pattern.setBlock(block); - if (mask.test(BlockVector3.ZERO)) blocks.add(type); + extent.init(0, 0, 0, type.getDefaultState().toBaseBlock()); + if (mask.test(extent)) { + blocks.add(type); + } } break; } @@ -459,8 +473,11 @@ public class CFICommands extends MethodCommands { @CommandPermissions("worldedit.anvil.cfi") public void complexity(FawePlayer fp, int min, int max) throws ParameterException, FileNotFoundException { HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (min == 0 && max == 100) gen.setTextureUtil(Fawe.get().getTextureUtil()); - else gen.setTextureUtil(new CleanTextureUtil(Fawe.get().getTextureUtil(), min, max)); + if (min == 0 && max == 100) { + gen.setTextureUtil(Fawe.get().getTextureUtil()); + } else { + gen.setTextureUtil(new CleanTextureUtil(Fawe.get().getTextureUtil(), min, max)); + } coloring(fp); } @@ -501,9 +518,13 @@ public class CFICommands extends MethodCommands { @CommandPermissions("worldedit.anvil.cfi") public void biome(FawePlayer fp, BiomeType biome, @Optional FawePrimitiveBinding.ImageUri image, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException{ HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); - if (image != null) gen.setBiome(load(image), biome, !disableWhiteOnly); - else if (mask != null) gen.setBiome(mask, biome); - else gen.setBiome(biome); + if (image != null) { + gen.setBiome(load(image), biome, !disableWhiteOnly); + } else if (mask != null) { + gen.setBiome(mask, biome); + } else { + gen.setBiome(biome); + } msg("Set biome!").send(fp); assertSettings(fp).resetComponent(); component(fp); @@ -682,9 +703,13 @@ public class CFICommands extends MethodCommands { public void color(FawePlayer fp, FawePrimitiveBinding.ImageUri image, @Optional FawePrimitiveBinding.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException, WorldEditException { CFISettings settings = assertSettings(fp); HeightMapMCAGenerator gen = settings.getGenerator(); - if (imageMask != null) gen.setColor(load(image), load(imageMask), !disableWhiteOnly); - else if (mask != null) gen.setColor(load(image), mask); - else gen.setColor(load(image)); + if (imageMask != null) { + gen.setColor(load(image), load(imageMask), !disableWhiteOnly); + } else if (mask != null) { + gen.setColor(load(image), mask); + } else { + gen.setColor(load(image)); + } settings.resetColoring(); msg("Set color with blocks!").send(fp); mainMenu(fp); @@ -696,7 +721,7 @@ public class CFICommands extends MethodCommands { desc = "Set the color with blocks and biomes", descFooter = "Color the terrain using blocks and biomes.\n" + "Provide an image, or worldedit mask to restrict what areas are colored\n" + - "The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance" + "The -w (disableWhiteOnly) will randomly apply depending on the pixel luminance" ) @CommandPermissions("worldedit.anvil.cfi") public void blockbiome(FawePlayer fp, FawePrimitiveBinding.ImageUri image, @Optional FawePrimitiveBinding.ImageUri imageMask, @Arg(name = "mask", desc = "Mask", def = "") Mask mask, @Switch(name='w', desc = "TODO") boolean disableWhiteOnly) throws ParameterException, WorldEditException { @@ -730,7 +755,7 @@ public class CFICommands extends MethodCommands { desc = "Color the world using an image" ) @CommandPermissions("worldedit.anvil.cfi") - public void coloring(FawePlayer fp) throws ParameterException{ + public void coloring(FawePlayer fp) throws ParameterException { CFISettings settings = assertSettings(fp); settings.popMessages(fp); settings.setCategory("coloring"); @@ -762,7 +787,9 @@ public class CFICommands extends MethodCommands { for (int typeId : blockArray) { BlockType type = BlockTypes.get(typeId); String name = type.getName(); - if (name.contains(":")) name = name.split(":")[1]; + if (name.contains(":")) { + name = name.split(":")[1]; + } materials.add(name); } String blockList = materials.size() > 100 ? materials.size() + " blocks" : StringMan.join(materials, ','); @@ -782,9 +809,15 @@ public class CFICommands extends MethodCommands { if (settings.image != null) { StringBuilder colorArgs = new StringBuilder(); colorArgs.append(" " + settings.imageArg); - if (settings.imageMask != null) colorArgs.append(" " + settings.imageMaskArg); - if (settings.mask != null) colorArgs.append(" " + settings.maskArg); - if (!settings.whiteOnly) colorArgs.append(" -w"); + if (settings.imageMask != null) { + colorArgs.append(" " + settings.imageMaskArg); + } + if (settings.mask != null) { + colorArgs.append(" " + settings.maskArg); + } + if (!settings.whiteOnly) { + colorArgs.append(" -w"); + } msg.text("Image: ") .text("[" + settings.imageArg + "]").cmdTip(alias() + " " + Commands.getAlias(CFICommands.class, "image")) @@ -859,7 +892,7 @@ public class CFICommands extends MethodCommands { CFISettings settings = assertSettings(fp); BufferedImage image = settings.getGenerator().draw(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageIO.write(image, "jpg", baos ); + ImageIO.write(image, "jpg", baos); byte[] data = baos.toByteArray(); fp.sendMessage("Please wait..."); URL url = ImgurUtility.uploadImage(data); @@ -904,7 +937,7 @@ public class CFICommands extends MethodCommands { desc = "" ) @CommandPermissions("worldedit.anvil.cfi") - public void populate(FawePlayer fp) throws ParameterException{ + public void populate(FawePlayer fp) throws ParameterException { CFISettings settings = assertSettings(fp); settings.popMessages(fp); settings.setCategory("populate"); @@ -921,7 +954,7 @@ public class CFICommands extends MethodCommands { desc = "Components menu" ) @CommandPermissions("worldedit.anvil.cfi") - public void component(FawePlayer fp) throws ParameterException{ + public void component(FawePlayer fp) throws ParameterException { CFISettings settings = assertSettings(fp); settings.popMessages(fp); settings.setCategory("component"); @@ -938,9 +971,15 @@ public class CFICommands extends MethodCommands { String pattern = settings.pattern == null ? "NONE" : settings.patternArg; StringBuilder maskArgs = new StringBuilder(); - if (settings.imageMask != null) maskArgs.append(" " + settings.imageMaskArg); - if (settings.mask != null) maskArgs.append(" " + settings.maskArg); - if (!settings.whiteOnly) maskArgs.append(" -w"); + if (settings.imageMask != null) { + maskArgs.append(" " + settings.imageMaskArg); + } + if (settings.mask != null) { + maskArgs.append(" " + settings.maskArg); + } + if (!settings.whiteOnly) { + maskArgs.append(" -w"); + } String height = Commands.getAlias(CFICommands.class, "height"); String waterHeight = Commands.getAlias(CFICommands.class, "waterheight"); @@ -993,10 +1032,11 @@ public class CFICommands extends MethodCommands { } - private CFISettings assertSettings(FawePlayer fp) throws ParameterException { CFISettings settings = getSettings(fp); - if (!settings.hasGenerator()) throw new ParameterException("Please use /" + alias()); + if (!settings.hasGenerator()) { + throw new ParameterException("Please use /" + alias()); + } return settings; } @@ -1083,12 +1123,16 @@ public class CFICommands extends MethodCommands { public CFISettings setGenerator(HeightMapMCAGenerator generator) { this.generator = generator; - if (bound) fp.getSession().setVirtualWorld(generator); + if (bound) { + fp.getSession().setVirtualWorld(generator); + } return this; } public CFISettings bind() { - if (generator != null) fp.getSession().setVirtualWorld(generator); + if (generator != null) { + fp.getSession().setVirtualWorld(generator); + } bound = true; fp.setMeta("CFISettings", this); return this; @@ -1132,9 +1176,9 @@ public class CFICommands extends MethodCommands { } protected Message msg(String text) { - return new Message().newline() - .text(BBC.getPrefix()) - .text(text); + return new Message().newline() + .text(BBC.getPrefix()) + .text(text); } protected void mainMenu(FawePlayer fp) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index 3d4934bb1..3c03918ee 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -1,55 +1,75 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.Fawe; -import com.boydti.fawe.example.SimpleIntFaweChunk; -import com.boydti.fawe.object.*; +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.Metadatable; +import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.brush.visualization.VirtualWorld; import com.boydti.fawe.object.change.StreamChange; import com.boydti.fawe.object.changeset.CFIChangeSet; -import com.boydti.fawe.object.collection.*; +import com.boydti.fawe.object.collection.DifferentialArray; +import com.boydti.fawe.object.collection.DifferentialBlockBuffer; +import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.object.collection.LocalBlockVector2DSet; +import com.boydti.fawe.object.collection.SummedAreaTable; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.queue.LazyFaweChunk; import com.boydti.fawe.object.schematic.Schematic; -import com.boydti.fawe.util.*; +import com.boydti.fawe.util.CachedTextureUtil; +import com.boydti.fawe.util.RandomTextureUtil; +import com.boydti.fawe.util.ReflectionUtils; +import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.image.Drawable; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.math.MutableBlockVector3; -import com.sk89q.worldedit.registry.state.PropertyKey; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import javax.annotation.Nullable; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -import javax.annotation.Nullable; // TODO FIXME public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld { @@ -190,11 +210,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr this.editSession = session; } - @Override - public boolean supports(Capability capability) { - return false; - } - // Used for visualizing the world on a map private ImageViewer viewer; // Used for visualizing the world by sending chunk packets @@ -229,11 +244,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr return metaData; } - @Override - public FaweQueue getQueue() { - throw new UnsupportedOperationException("Not supported: Queue is not backed by a real world"); - } - @Override public Vector3 getOrigin() { return Vector3.at(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4); @@ -1019,7 +1029,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr @Override public BlockState getBlock(BlockVector3 position) { - return getLazyBlock(position); + return getBlock(position.getX(), position.getY(), position.getZ()); } public BlockState getFloor(int x, int z) { @@ -1042,12 +1052,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { return BlockState.getFromInternalId(getCombinedId4Data(x, y, z)); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java index 7e7c96c24..a5d3ab0b9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/InspectBrush.java @@ -49,7 +49,6 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool { } public Vector3 getTarget(Player player, boolean adjacent) { - Location target = null; int range = this.range > -1 ? getRange() : DEFAULT_RANGE; if (adjacent) { Location face = player.getBlockTraceFace(range, true); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index c2ed40764..1d86aa11b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -46,9 +46,7 @@ import java.util.UUID; */ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { - public static int COMPRESSION = 0; - public static int MODE = 0; - public static int HEADER_SIZE = 14; + private static int HEADER_SIZE = 14; protected int length; protected int height; @@ -61,9 +59,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { private final File file; private RandomAccessFile braf; - private MappedByteBuffer mbb; + private MappedByteBuffer byteBuffer; - private FileChannel fc; + private FileChannel fileChannel; private boolean hasBiomes; public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) { @@ -78,9 +76,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { this.braf = new RandomAccessFile(file, "rw"); braf.setLength(file.length()); init(); - width = mbb.getChar(2); - height = mbb.getChar(4); - length = mbb.getChar(6); + width = byteBuffer.getChar(2); + height = byteBuffer.getChar(4); + length = byteBuffer.getChar(6); area = width * length; this.volume = length * width * height; @@ -98,9 +96,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } private void init() throws IOException { - if (this.fc == null) { - this.fc = braf.getChannel(); - this.mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length()); + if (this.fileChannel == null) { + this.fileChannel = braf.getChannel(); + this.byteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, file.length()); } } @@ -134,7 +132,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setBiome(int index, BiomeType biome) { if (initBiome()) { - mbb.put(HEADER_SIZE + (volume << 2) + index, (byte) biome.getInternalId()); + byteBuffer.put(HEADER_SIZE + (volume << 2) + index, (byte) biome.getInternalId()); } } @@ -143,8 +141,8 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { if (!hasBiomes()) { return null; } - int biomeId = mbb.get(HEADER_SIZE + (volume << 2) + index) & 0xFF; - return BiomeTypes.register(biomeId); + int biomeId = byteBuffer.get(HEADER_SIZE + (volume << 2) + index) & 0xFF; + return BiomeTypes.get(biomeId); } @Override @@ -154,7 +152,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { int mbbIndex = HEADER_SIZE + (volume << 2); for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, index++, mbbIndex++) { - int biome = mbb.get(mbbIndex) & 0xFF; + int biome = byteBuffer.get(mbbIndex) & 0xFF; task.run(index, biome); } } @@ -173,9 +171,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { public BlockArrayClipboard toClipboard() { try { CuboidRegion region = new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(width - 1, height - 1, length - 1)); - int ox = mbb.getShort(8); - int oy = mbb.getShort(10); - int oz = mbb.getShort(12); + int ox = byteBuffer.getShort(8); + int oy = byteBuffer.getShort(10); + int oz = byteBuffer.getShort(12); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, this); clipboard.setOrigin(BlockVector3.at(ox, oy, oz)); return clipboard; @@ -213,9 +211,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { if (width * height * length != 0) { init(); // write length etc - mbb.putChar(2, (char) width); - mbb.putChar(4, (char) height); - mbb.putChar(6, (char) length); + byteBuffer.putChar(2, (char) width); + byteBuffer.putChar(4, (char) height); + byteBuffer.putChar(6, (char) length); } } catch (IOException e) { throw new RuntimeException(e); @@ -225,9 +223,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setOrigin(BlockVector3 offset) { try { - mbb.putShort(8, (short) offset.getBlockX()); - mbb.putShort(10, (short) offset.getBlockY()); - mbb.putShort(12, (short) offset.getBlockZ()); + byteBuffer.putShort(8, (short) offset.getBlockX()); + byteBuffer.putShort(10, (short) offset.getBlockY()); + byteBuffer.putShort(12, (short) offset.getBlockZ()); } catch (Throwable e) { e.printStackTrace(); } @@ -248,9 +246,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { braf.setLength(size); init(); } - mbb.putChar(2, (char) width); - mbb.putChar(4, (char) height); - mbb.putChar(6, (char) length); + byteBuffer.putChar(2, (char) width); + byteBuffer.putChar(4, (char) height); + byteBuffer.putChar(6, (char) length); } catch (IOException e) { e.printStackTrace(); } @@ -258,7 +256,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void flush() { - mbb.force(); + byteBuffer.force(); } public DiskOptimizedClipboard(int width, int height, int length) { @@ -267,7 +265,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { private void closeDirectBuffer(ByteBuffer cb) { if (cb == null || !cb.isDirect()) return; - // we could use this type cast and call functions without reflection code, // but static import from sun.* package is risky for non-SUN virtual machine. //try { ((sun.nio.ch.DirectBuffer)cb).cleaner().clean(); } catch (Exception ex) { } @@ -299,14 +296,15 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void close() { try { - if (mbb != null) { - mbb.force(); - fc.close(); + if (byteBuffer != null) { + byteBuffer.force(); + fileChannel.close(); braf.close(); + //noinspection ResultOfMethodCallIgnored file.setWritable(true); - closeDirectBuffer(mbb); - mbb = null; - fc = null; + closeDirectBuffer(byteBuffer); + byteBuffer = null; + fileChannel = null; braf = null; } } catch (IOException e) { @@ -337,13 +335,13 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void streamCombinedIds(NBTStreamer.ByteReader task) { try { - mbb.force(); + byteBuffer.force(); int pos = HEADER_SIZE; int index = 0; for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, pos += 4) { - int combinedId = mbb.getInt(pos); + int combinedId = byteBuffer.getInt(pos); task.run(index++, combinedId); } } @@ -360,7 +358,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void forEach(final BlockReader task, boolean air) { - mbb.force(); + byteBuffer.force(); int pos = HEADER_SIZE; IntegerTrio trio = new IntegerTrio(); final boolean hasTile = !nbtMap.isEmpty(); @@ -369,7 +367,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, pos += 4) { - int combinedId = mbb.getInt(pos); + int combinedId = byteBuffer.getInt(pos); BlockType type = BlockTypes.getFromStateId(combinedId); BlockState state = type.withStateId(combinedId); if (type.getMaterial().hasContainer()) { @@ -388,7 +386,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, pos += 4) { - int combinedId = mbb.getInt(pos); + int combinedId = byteBuffer.getInt(pos); BlockState state = BlockState.getFromInternalId(combinedId); task.run(x, y, z, state); } @@ -399,7 +397,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, pos += 4) { - int combinedId = mbb.getInt(pos); + int combinedId = byteBuffer.getInt(pos); BlockType type = BlockTypes.getFromStateId(combinedId); if (!type.getMaterial().isAir()) { BlockState state = type.withStateId(combinedId); @@ -427,7 +425,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { public BaseBlock getBlock(int x, int y, int z) { try { int index = HEADER_SIZE + (getIndex(x, y, z) << 2); - int combinedId = mbb.getInt(index); + int combinedId = byteBuffer.getInt(index); BlockType type = BlockTypes.getFromStateId(combinedId); BaseBlock base = type.withStateId(combinedId).toBaseBlock(); if (type.getMaterial().hasContainer() && !nbtMap.isEmpty()) { @@ -440,7 +438,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } catch (IndexOutOfBoundsException ignore) { } catch (Exception e) { e.printStackTrace(); - e.printStackTrace(); } return BlockTypes.AIR.getDefaultState().toBaseBlock(); } @@ -449,7 +446,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { public BaseBlock getBlock(int i) { try { int diskIndex = (HEADER_SIZE) + (i << 2); - int combinedId = mbb.getInt(diskIndex); + int combinedId = byteBuffer.getInt(diskIndex); BlockType type = BlockTypes.getFromStateId(combinedId); BaseBlock base = type.withStateId(combinedId).toBaseBlock(); if (type.getMaterial().hasContainer() && !nbtMap.isEmpty()) { @@ -499,7 +496,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { try { int index = (HEADER_SIZE) + ((getIndex(x, y, z) << 2)); int combined = block.getInternalId(); - mbb.putInt(index, combined); + byteBuffer.putInt(index, combined); boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); if (hasNbt) { setTile(x, y, z, block.getNbtData()); @@ -516,7 +513,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { try { int combined = block.getInternalId(); int index = (HEADER_SIZE) + (i << 2); - mbb.putInt(index, combined); + byteBuffer.putInt(index, combined); boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); if (hasNbt) { int y = i / area; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java index c3115d1c4..bfe975708 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java @@ -5,6 +5,7 @@ import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.ReflectionUtils; + import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; @@ -28,9 +29,9 @@ import java.util.Map; public class MemoryOptimizedClipboard extends FaweClipboard { - public static final int BLOCK_SIZE = 1048576 * 4; - public static final int BLOCK_MASK = 1048575; - public static final int BLOCK_SHIFT = 20; + private static final int BLOCK_SIZE = 1048576 * 4; + private static final int BLOCK_MASK = 1048575; + private static final int BLOCK_SHIFT = 20; private int length; private int height; @@ -338,9 +339,9 @@ public class MemoryOptimizedClipboard extends FaweClipboard { public > boolean setBlock(int index, B block) { int combinedId = block.getInternalId(); setCombinedId(index, combinedId); - boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData(); + boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); if (hasNbt) { - setTile(index, ((BaseBlock)block).getNbtData()); + setTile(index, block.getNbtData()); } return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java index ac52e3db5..952b6a661 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AverageColorPattern.java @@ -32,19 +32,14 @@ public class AverageColorPattern extends AbstractExtentPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType blockType = extent.getBlock(getPosition).getBlockType(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType blockType = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); int currentColor = util.getColor(blockType); if (currentColor == 0) return false; int newColor = util.averageColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); if (newBlock == blockType) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newBlock.getDefaultState()); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java index 8f6544940..fca405051 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/DesaturatePattern.java @@ -13,7 +13,7 @@ import java.io.IOException; import java.io.ObjectInputStream; public class DesaturatePattern extends AbstractPattern { - private transient TextureHolder holder; + private final TextureHolder holder; private final Extent extent; private final double value; @@ -27,7 +27,11 @@ public class DesaturatePattern extends AbstractPattern { public BaseBlock apply(BlockVector3 position) { BlockType block = extent.getBlock(position).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int color = util.getColor(block); + int color = getColor(util.getColor(block)); + return util.getNearestBlock(color).getDefaultState().toBaseBlock(); + } + + public int getColor(int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = (color >> 0) & 0xFF; @@ -37,35 +41,22 @@ public class DesaturatePattern extends AbstractPattern { int green = (int) (g + value * (l - g)); int blue = (int) (b + value * (l - b)); int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); - return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return newColor; } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType block = extent.getBlock(getPosition).getBlockType(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType type = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); - int color = util.getColor(block); - int r = (color >> 16) & 0xFF; - int g = (color >> 8) & 0xFF; - int b = (color >> 0) & 0xFF; - int alpha = (color >> 24) & 0xFF; - double l = 0.3f * r + 0.6f * g + 0.1f * b; - int red = (int) (r + value * (l - r)); - int green = (int) (g + value * (l - g)); - int blue = (int) (b + value * (l - b)); - int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); + int color = util.getColor(type); + int newColor = getColor(color); if (newColor == color) { return false; } - BlockType newBlock = util.getNextNearestBlock(newColor); - if (block.equals(newBlock)) { + BlockType newType = util.getNextNearestBlock(newColor); + if (type.equals(newType)) { return false; } - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newType.getDefaultState()); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java index ac29670fa..d9b4730b0 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/SaturatePattern.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.pattern; import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.util.TextureHolder; import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; @@ -14,7 +15,7 @@ import java.io.IOException; import java.io.ObjectInputStream; public class SaturatePattern extends AbstractPattern { - private transient TextureHolder holder; + private final TextureHolder holder; private final int color; private final Extent extent; @@ -35,19 +36,14 @@ public class SaturatePattern extends AbstractPattern { } @Override - public boolean apply(Extent extent, BlockVector3 setPosition, BlockVector3 getPosition) throws WorldEditException { - BlockType block = extent.getBlock(getPosition).getBlockType(); + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType block = get.getBlock(extent).getBlockType(); TextureUtil util = holder.getTextureUtil(); int currentColor = util.getColor(block); if (currentColor == 0) return false; int newColor = util.multiplyColor(currentColor, color); BlockType newBlock = util.getNearestBlock(newColor); if (newBlock.equals(block)) return false; - return extent.setBlock(setPosition, newBlock.getDefaultState()); - } - - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - holder = Fawe.get().getCachedTextureUtil(true, 0, 100); + return set.setBlock(extent, newBlock.getDefaultState()); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java index 0fe10f849..43ba6bb83 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/ShadePattern.java @@ -2,17 +2,16 @@ package com.boydti.fawe.object.pattern; import static com.google.common.base.Preconditions.checkNotNull; -import com.boydti.fawe.Fawe; import com.boydti.fawe.util.TextureUtil; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; -import java.io.IOException; public class ShadePattern extends AbstractPattern { - private transient TextureUtil util; + private final TextureUtil util; private final Extent extent; private final boolean darken; @@ -29,8 +28,13 @@ public class ShadePattern extends AbstractPattern { return (darken ? util.getDarkerBlock(block) : util.getLighterBlock(block)).getDefaultState().toBaseBlock(); } - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - util = Fawe.get().getCachedTextureUtil(true, 0, 100); + @Override + public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { + BlockType type = get.getBlock(extent).getBlockType(); + BlockType newType = (darken ? util.getDarkerBlock(type) : util.getLighterBlock(type)); + if (type != newType) { + return set.setBlock(extent, newType.getDefaultState()); + } + return false; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index f198118d6..225960da1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -2,21 +2,24 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.HistoryExtent; import com.boydti.fawe.object.NullChangeSet; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.MemoryOptimizedHistory; - -import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.object.exception.FaweException; +import com.boydti.fawe.object.extent.NullExtent; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.eventbus.EventBus; @@ -26,10 +29,12 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.UUID; +import static com.google.common.base.Preconditions.checkNotNull; + public class EditSessionBuilder { private World world; private String worldName; - private FaweQueue queue; + private Extent extent; private FawePlayer player; private FaweLimit limit; private FaweChangeSet changeSet; @@ -60,9 +65,17 @@ public class EditSessionBuilder { public EditSessionBuilder(@Nonnull World world) { checkNotNull(world); this.world = world; + this.extent = world; this.worldName = Fawe.imp().getWorldName(world); } + public EditSessionBuilder(World world, String worldName) { + if (world == null && worldName == null) throw new NullPointerException("Both world and worldname cannot be null"); + this.world = world; + this.extent = world; + this.worldName = worldName; + } + public EditSessionBuilder(@Nonnull String worldName) { checkNotNull(worldName); this.worldName = worldName; @@ -176,8 +189,8 @@ public class EditSessionBuilder { return this; } - public EditSessionBuilder queue(@Nullable FaweQueue queue) { - this.queue = queue; + public EditSessionBuilder extent(@Nullable Extent extent) { + this.extent = extent; return this; } @@ -191,10 +204,261 @@ public class EditSessionBuilder { return this; } + private boolean wrapped; + + private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) { + event = event.clone(stage); + event.setExtent(extent); + eventBus.post(event); + if (event.isCancelled()) { + return new NullExtent(extent, FaweException.MANUAL); + } + final Extent toReturn = event.getExtent(); + if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { + return new NullExtent(toReturn, FaweException.MANUAL); + } + if (!(toReturn instanceof AbstractDelegateExtent)) { + Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent"); + return extent; + } + if (toReturn != extent) { + String className = toReturn.getClass().getName().toLowerCase(); + for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { + if (className.contains(allowed.toLowerCase())) { + this.wrapped = true; + return (AbstractDelegateExtent) toReturn; + } + } + if (Settings.IMP.EXTENT.DEBUG) { + Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName()); + Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI"); + Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub"); + Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list"); + Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml"); + if (toReturn.getClass().getName().contains("CoreProtect")) { + Fawe.debug("Note on CoreProtect: "); + Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP"); + Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config"); + } + } + } + return extent; + } + + private FaweChangeSet changeTask; + private int maxY; + private HistoryExtent history; + private AbstractDelegateExtent bypassHistory; + private AbstractDelegateExtent bypassAll; + + public EditSessionBuilder compile() { + if (extent != null) return this; + + wrapped = false; + if (world == null && !this.worldName.isEmpty()) { + world = FaweAPI.getWorld(this.worldName); + } + if (eventBus == null) { + eventBus = WorldEdit.getInstance().getEventBus(); + } + if (event == null) { + event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); + } + if (player == null && event.getActor() != null) { + player = FawePlayer.wrap(event.getActor()); + } + if (limit == null) { + if (player == null) { + limit = FaweLimit.MAX; + } else { + limit = player.getLimit(); + } + } + if (autoQueue == null) { + autoQueue = true; + } + if (fastmode == null) { + if (player == null) { + fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; + } else { + fastmode = player.getSession().hasFastMode(); + } + } + if (checkMemory == null) { + checkMemory = player != null && !this.fastmode; + } + if (checkMemory) { + if (MemUtil.isMemoryLimitedSlow()) { + if (Perm.hasPermission(player, "worldedit.fast")) { + BBC.WORLDEDIT_OOM_ADMIN.send(player); + } + throw FaweException.LOW_MEMORY; + } + } +// this.originalLimit = limit; + this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; +// this.limit = limit.copy(); + +// if (queue == null) { +// boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT; +// World unwrapped = WorldWrapper.unwrap(world); +// if (unwrapped instanceof FaweQueue) { +// queue = (FaweQueue) unwrapped; +// } else if (unwrapped instanceof MCAWorld) { +// queue = ((MCAWorld) unwrapped).getQueue(); +// } else if (player != null && world.equals(player.getWorld())) { +// queue = player.getFaweQueue(placeChunks, autoQueue); +// } else { +// queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue); +// } +// } +// if (combineStages == null) { +// combineStages = +// // If it's enabled in the settings +// Settings.IMP.HISTORY.COMBINE_STAGES +// // If fast placement is disabled, it's slower to perform a copy on each chunk +// && this.limit.FAST_PLACEMENT +// // If the specific queue doesn't support it +// && queue.supports(FaweQueue.Capability.CHANGE_TASKS) +// // If the edit uses items from the inventory we can't use a delayed task +// && this.blockBag == null; +// } +// if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { +// switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { +// case "chat": +// this.queue.setProgressTask(new ChatProgressTracker(player)); +// break; +// case "title": +// case "true": +// default: +// this.queue.setProgressTask(new DefaultProgressTracker(player)); +// } +// } +// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE); +// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER)); +// if (!this.fastmode || changeSet != null) { +// if (changeSet == null) { +// if (Settings.IMP.HISTORY.USE_DISK) { +// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID(); +// if (Settings.IMP.HISTORY.USE_DATABASE) { +// changeSet = new RollbackOptimizedHistory(world, uuid); +// } else { +// changeSet = new DiskStorageHistory(world, uuid); +// } +// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { +// changeSet = new CPUOptimizedChangeSet(world); +// } else { +// changeSet = new MemoryOptimizedHistory(world); +// } +// } +// if (this.limit.SPEED_REDUCTION > 0) { +// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); +// } +// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (!(changeSet instanceof NullChangeSet)) { +// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (this.blockBag != null) { +// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); +// } +// if (combineStages) { +// changeTask = changeSet; +// changeSet.addChangeTask(queue); +// } else { +// this.extent = (history = new HistoryExtent(bypassHistory, changeSet, queue)); +//// if (this.blockBag != null) { +//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); +//// } +// } +// } +// } +// if (allowedRegions == null) { +// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { +// allowedRegions = player.getCurrentRegions(); +// } +// } +// this.maxY = world == null ? 255 : world.getMaxY(); +// if (allowedRegions != null) { +// if (allowedRegions.length == 0) { +// this.extent = new NullExtent(this.extent, FaweException.NO_REGION); +// } else { +// this.extent = new ProcessedWEExtent(this.extent, this.limit); +// if (allowedRegions.length == 1) { +// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); +// } else { +// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); +// } +// } +// } else { +// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); +// } +// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { +// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); +// } +// this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); +// return this; + return this; + } + public EditSession build() { if (eventBus == null) { eventBus = WorldEdit.getInstance().getEventBus(); } - return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); + return new EditSession(this); + } + + public Extent getExtent() { + return extent; + } + + public World getWorld() { + return world; + } + + public String getWorldName() { + return worldName; + } + + public boolean isWrapped() { + return wrapped; + } + + public boolean hasFastMode() { + return fastmode; + } + + public HistoryExtent getHistory() { + return history; + } + + public AbstractDelegateExtent getBypassHistory() { + return bypassHistory; + } + + public AbstractDelegateExtent getBypassAll() { + return bypassAll; + } + + public FaweLimit getLimit() { + return limit; + } + + public FawePlayer getPlayer() { + return player; + } + + public FaweChangeSet getChangeTask() { + return changeTask; + } + + public BlockBag getBlockBag() { + return blockBag; + } + + public int getMaxY() { + return maxY; } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index 6773d34e4..10c79cda0 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -50,9 +50,8 @@ public final class NBTInputStream implements Closeable { * from the specified input stream. * * @param is the input stream - * @throws IOException if an I/O error occurs */ - public NBTInputStream(InputStream is) throws IOException { + public NBTInputStream(InputStream is) { this.is = new DataInputStream(is); } @@ -364,7 +363,7 @@ public final class NBTInputStream implements Closeable { int toRead = Math.min(length << 2, buf.length); is.readFully(buf, 0, toRead); for (int i = 0; i < toRead; i += 4, index++) { - data[index] = ((buf[i + 0] & 0xFF) << 24) + ((buf[i + 1] & 0xFF) << 16) + ((buf[i + 2] & 0xFF) << 8) + (buf[i + 3] & 0xFF); + data[index] = ((buf[i] & 0xFF) << 24) + ((buf[i + 1] & 0xFF) << 16) + ((buf[i + 2] & 0xFF) << 8) + (buf[i + 3] & 0xFF); } length -= toRead; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index b9a4c30b9..fd3697817 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -37,7 +37,6 @@ import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.HistoryExtent; import com.boydti.fawe.object.NullChangeSet; import com.boydti.fawe.object.RegionWrapper; @@ -61,11 +60,17 @@ import com.boydti.fawe.object.extent.SingleRegionExtent; import com.boydti.fawe.object.extent.SlowExtent; import com.boydti.fawe.object.extent.SourceMaskExtent; import com.boydti.fawe.object.extent.StripNBTExtent; +import com.boydti.fawe.object.extent.FaweRegionExtent; +import com.boydti.fawe.object.extent.NullExtent; +import com.boydti.fawe.object.extent.ProcessedWEExtent; +import com.boydti.fawe.object.extent.ResettableExtent; +import com.boydti.fawe.object.extent.SourceMaskExtent; import com.boydti.fawe.object.function.SurfaceRegionFunction; import com.boydti.fawe.object.mask.ResettableMask; import com.boydti.fawe.object.pattern.ExistingPattern; import com.boydti.fawe.object.progress.ChatProgressTracker; import com.boydti.fawe.object.progress.DefaultProgressTracker; +import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.MaskTraverser; import com.boydti.fawe.util.MathMan; @@ -80,6 +85,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; @@ -104,6 +110,8 @@ import com.sk89q.worldedit.function.mask.MaskUnion; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.mask.RegionMask; +import com.sk89q.worldedit.function.mask.SingleBlockTypeMask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; @@ -166,7 +174,10 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.weather.WeatherType; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -178,6 +189,12 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Regions.asFlatRegion; +import static com.sk89q.worldedit.regions.Regions.maximumBlockY; +import static com.sk89q.worldedit.regions.Regions.minimumBlockY; + /** * An {@link Extent} that handles history, {@link BlockBag}s, change limits, * block re-ordering, and much more. Most operations in WorldEdit use this class. @@ -187,7 +204,7 @@ import org.slf4j.LoggerFactory; * using the {@link ChangeSetExtent}.

*/ @SuppressWarnings({"FieldCanBeLocal"}) -public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, SimpleWorld, AutoCloseable { +public class EditSession extends AbstractDelegateExtent SimpleWorld, AutoCloseable { private static final Logger log = LoggerFactory.getLogger(EditSession.class); @@ -224,194 +241,51 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return this.displayName; } } - - @SuppressWarnings("ProtectedField") - protected final World world; - private String worldName; - private FaweQueue queue; + private final World world; + private final String worldName; private boolean wrapped; private boolean fastMode; - private AbstractDelegateExtent extent; - private HistoryExtent history; + private final HistoryExtent history; private AbstractDelegateExtent bypassHistory; private AbstractDelegateExtent bypassAll; - private FaweLimit originalLimit; - private FaweLimit limit; - private FawePlayer player; + private final FaweLimit originalLimit; + private final FaweLimit limit; + private final FawePlayer player; private FaweChangeSet changeTask; - private MutableBlockVector3 mutablebv = new MutableBlockVector3(); + private final MutableBlockVector3 mutablebv = new MutableBlockVector3(); private int changes = 0; - private BlockBag blockBag; + private final BlockBag blockBag; private final int maxY; public static final UUID CONSOLE = UUID.fromString("1-1-3-3-7"); @Deprecated - public EditSession(@Nonnull World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @NotNull EventBus bus, @Nullable EditSessionEvent event) { - this(null, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, bus, event); + public EditSession(@Nonnull World world, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { + this(null, world, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, bus, event); } - public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable Region[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { - super(world); - this.worldName = worldName == null ? world == null ? queue == null ? "" : queue.getWorldName() : world.getName() : worldName; - if (world == null && this.worldName != null) world = FaweAPI.getWorld(this.worldName); + public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable Region[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { + this(new EditSessionBuilder(world, worldName).player(player).limit(limit).changeSet(changeSet).allowedRegions(allowedRegions).autoQueue(autoQueue).fastmode(fastmode).checkMemory(checkMemory).combineStages(combineStages).blockBag(blockBag).eventBus(bus).event(event)); + } - this.world = world; - if (bus == null) { // don't change - bus = WorldEdit.getInstance().getEventBus(); - } - if (event == null) { - event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); - } - event.setEditSession(this); - if (player == null && event.getActor() != null) { - player = FawePlayer.wrap(event.getActor()); - } - this.player = player; - if (limit == null) { - if (player == null) { - limit = FaweLimit.MAX; - } else { - limit = player.getLimit(); - } - } - if (autoQueue == null) { - autoQueue = true; - } - if (fastmode == null) { - if (player == null) { - fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; - } else { - fastmode = player.getSession().hasFastMode(); - } - } - this.fastMode = fastmode; - if (checkMemory == null) { - checkMemory = player != null && !this.fastMode; - } - if (checkMemory) { - if (MemUtil.isMemoryLimitedSlow()) { - if (Perm.hasPermission(player, "worldedit.fast")) { - BBC.WORLDEDIT_OOM_ADMIN.send(player); - } - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); - } - } - this.originalLimit = limit; - this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; - this.limit = limit.copy(); - - if (queue == null) { - boolean placeChunks = this.fastMode || this.limit.FAST_PLACEMENT; - World unwrapped = WorldWrapper.unwrap(world); - if (unwrapped instanceof FaweQueue) { - queue = (FaweQueue) unwrapped; - } else if (unwrapped instanceof MCAWorld) { - queue = ((MCAWorld) unwrapped).getQueue(); - } else if (player != null && world.equals(player.getWorld())) { - queue = player.getFaweQueue(placeChunks, autoQueue); - } else { - queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue); - } - } - if (combineStages == null) { - combineStages = - // If it's enabled in the settings - Settings.IMP.HISTORY.COMBINE_STAGES - // If fast placement is disabled, it's slower to perform a copy on each chunk - && this.limit.FAST_PLACEMENT - // If the specific queue doesn't support it - && queue.supports(FaweQueue.Capability.CHANGE_TASKS) - // If the edit uses items from the inventory we can't use a delayed task - && this.blockBag == null; - } - if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { - queue = new MCAQueue(queue); - } - this.queue = queue; - this.queue.addEditSession(this); - if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { - switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { - case "chat": - this.queue.setProgressTask(new ChatProgressTracker(player)); - break; - case "title": - case "true": - default: - this.queue.setProgressTask(new DefaultProgressTracker(player)); - } - } - this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE); - this.bypassHistory = (this.extent = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER)); - if (!this.fastMode || changeSet != null) { - if (changeSet == null) { - if (Settings.IMP.HISTORY.USE_DISK) { - UUID uuid = player == null ? CONSOLE : player.getUUID(); - if (Settings.IMP.HISTORY.USE_DATABASE) { - changeSet = new RollbackOptimizedHistory(world, uuid); - } else { - changeSet = new DiskStorageHistory(world, uuid); - } - } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { - changeSet = new CPUOptimizedChangeSet(world); - } else { - changeSet = new MemoryOptimizedHistory(world); - } - } - if (this.limit.SPEED_REDUCTION > 0) { - this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); - } - // don't delete - if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { - changeSet = LoggingChangeSet.wrap(player, changeSet); - } - if (!(changeSet instanceof NullChangeSet)) { - // don't delete - if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { - changeSet = LoggingChangeSet.wrap(player, changeSet); - } - if (this.blockBag != null) { - changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); - } - if (combineStages) { - changeTask = changeSet; - changeSet.addChangeTask(queue); - } else { - this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); -// if (this.blockBag != null) { -// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); -// } - } - } - } - if (allowedRegions == null) { - if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { - allowedRegions = player.getCurrentRegions(); - } - } - this.maxY = getWorld() == null ? 255 : world.getMaxY(); - if (allowedRegions != null) { - if (allowedRegions.length == 0) { - this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); - } else { - this.extent = new ProcessedWEExtent(this.extent, this.limit); - if (allowedRegions.length == 1) { - this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); - } else { - this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); - } - } - } else { - this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); - } - if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { - this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); - } - this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); - setExtent(this.extent); + public EditSession(EditSessionBuilder builder) { + super(builder.compile().getExtent()); + this.world = builder.getWorld(); + this.worldName = builder.getWorldName(); + this.wrapped = builder.isWrapped(); + this.fastMode = builder.hasFastMode(); + this.history = builder.getHistory(); + this.bypassHistory = builder.getBypassHistory(); + this.bypassAll = builder.getBypassAll(); + this.originalLimit = builder.getLimit(); + this.limit = builder.getLimit().copy(); + this.player = builder.getPlayer(); + this.changeTask = builder.getChangeTask(); + this.maxY = builder.getMaxY(); + this.blockBag = builder.getBlockBag(); } /** @@ -424,7 +298,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @param event the event to call with the extent */ public EditSession(EventBus eventBus, World world, int maxBlocks, @Nullable BlockBag blockBag, EditSessionEvent event) { - this(world, null, null, null, null, null, true, null, null, null, blockBag, eventBus, event); + this(world, null, null, null, null, true, null, null, null, blockBag, eventBus, event); } /** @@ -438,7 +312,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public void resetLimit() { this.limit.set(this.originalLimit); - ExtentTraverser find = new ExtentTraverser<>(extent).find(ProcessedWEExtent.class); + ExtentTraverser find = new ExtentTraverser<>(getExtent()).find(ProcessedWEExtent.class); if (find != null && find.get() != null) { find.get().setLimit(this.limit); } @@ -477,7 +351,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return FaweRegionExtent (may be null) */ public FaweRegionExtent getRegionExtent() { - ExtentTraverser traverser = new ExtentTraverser<>(this.extent).find(FaweRegionExtent.class); + ExtentTraverser traverser = new ExtentTraverser<>(getExtent()).find(FaweRegionExtent.class); return traverser == null ? null : traverser.get(); } @@ -489,14 +363,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return bypassHistory; } - @Override - public Extent getExtent() { - return extent; - } - public void setExtent(AbstractDelegateExtent extent) { - this.extent = extent; - new ExtentTraverser(this).setNext(extent); + new ExtentTraverser<>(getExtent()).setNext(extent); } /** @@ -510,99 +378,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } public boolean cancel() { - ExtentTraverser traverser = new ExtentTraverser(this.extent); - NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + ExtentTraverser traverser = new ExtentTraverser<>(getExtent()); + NullExtent nullExtent = new NullExtent(world, FaweException.MANUAL); while (traverser != null) { - ExtentTraverser next = traverser.next(); Extent get = traverser.get(); + ExtentTraverser next = traverser.next(); if (get instanceof AbstractDelegateExtent && !(get instanceof NullExtent)) { traverser.setNext(nullExtent); } traverser = next; } - bypassHistory = nullExtent; - this.extent = nullExtent; - bypassAll = nullExtent; - dequeue(); - if (!queue.isEmpty()) { - if (Fawe.isMainThread()) { - queue.clear(); - } else { - SetQueue.IMP.addTask(() -> queue.clear()); - } - } - return true; - } - - /** - * Remove this EditSession from the queue
- * - This doesn't necessarily stop it from being queued again - */ - public void dequeue() { - if (queue != null) { - SetQueue.IMP.dequeue(queue); - } - } - - /** - * Add a task to run when this EditSession is done dispatching - * - * @param whenDone - */ - public void addNotifyTask(Runnable whenDone) { - if (queue != null) { - queue.addNotifyTask(whenDone); - } - } - - /** - * Get the FaweQueue this EditSession uses to queue the changes
- * - Note: All implementation queues for FAWE are instances of NMSMappedFaweQueue - * - * @return - */ - @Override - public FaweQueue getQueue() { - return queue; - } - - private AbstractDelegateExtent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, Stage stage) { - event = event.clone(stage); - event.setExtent(extent); - eventBus.post(event); - if (event.isCancelled()) { - return new NullExtent(extent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); - } - final Extent toReturn = event.getExtent(); - if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { - return new NullExtent(toReturn, null); - } - if (!(toReturn instanceof AbstractDelegateExtent)) { - Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent"); - return (AbstractDelegateExtent) extent; - } - if (toReturn != extent) { - String className = toReturn.getClass().getName().toLowerCase(); - for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { - if (className.contains(allowed.toLowerCase())) { - this.wrapped = true; - return (AbstractDelegateExtent) toReturn; - } - } - if (Settings.IMP.EXTENT.DEBUG) { - Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName()); - Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI"); - Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub"); - Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list"); - Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml"); - if (toReturn.getClass().getName().contains("CoreProtect")) { - Fawe.debug("Note on CoreProtect: "); - Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP"); - Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config"); - } - } - } - return (AbstractDelegateExtent) extent; + return super.cancel(); } // pkg private for TracedEditSession only, may later become public API @@ -674,26 +460,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, changes++; } - /** - * Change the ChangeSet being used for this EditSession - * - If history is disabled, no changeset can be set - * - * @param set (null = remove the changeset) - */ - public void setChangeSet(@Nullable FaweChangeSet set) { - if (set == null) { - disableHistory(true); - } else { - if (history != null) { - history.setChangeSet(set); - } else { - changeTask = set; - set.addChangeTask(queue); - } - } - changes++; - } - /** * Get the maximum number of blocks that can be changed. -1 will be returned * if it the limit disabled. @@ -752,7 +518,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return mask, may be null */ public Mask getMask() { - ExtentTraverser maskingExtent = new ExtentTraverser<>(this.extent).find(MaskingExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser<>(getExtent()).find(MaskingExtent.class); return maskingExtent != null ? maskingExtent.get().getMask() : null; } @@ -762,30 +528,21 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return mask, may be null */ public Mask getSourceMask() { - ExtentTraverser maskingExtent = new ExtentTraverser<>(this.extent).find(SourceMaskExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser<>(getExtent()).find(SourceMaskExtent.class); return maskingExtent != null ? maskingExtent.get().getMask() : null; } public void addTransform(ResettableExtent transform) { + checkNotNull(transform); wrapped = true; - if (transform == null) { - ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class); - AbstractDelegateExtent next = extent; - while (traverser != null && traverser.get() instanceof ResettableExtent) { - traverser = traverser.next(); - next = (AbstractDelegateExtent) traverser.get(); - } - this.extent = next; - return; - } else { - this.extent = transform.setExtent(extent); - } + transform.setExtent(getExtent()); + new ExtentTraverser<>(getExtent()).setNext(transform); } public @Nullable ResettableExtent getTransform() { - ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class); + ExtentTraverser traverser = new ExtentTraverser<>(getExtent()).find(ResettableExtent.class); if (traverser != null) { - return (ResettableExtent) traverser.get(); + return traverser.get(); } return null; } @@ -801,7 +558,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { new MaskTraverser(mask).reset(this); } - ExtentTraverser maskingExtent = new ExtentTraverser<>(this.extent).find(SourceMaskExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser<>(getExtent()).find(SourceMaskExtent.class); +======= + ExtentTraverser maskingExtent = new ExtentTraverser<>(getExtent()).find(SourceMaskExtent.class); +>>>>>>> filter-pipeline if (maskingExtent != null && maskingExtent.get() != null) { Mask oldMask = maskingExtent.get().getMask(); if (oldMask instanceof ResettableMask) { @@ -809,7 +569,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } maskingExtent.get().setMask(mask); } else if (mask != Masks.alwaysTrue()) { - this.extent = new SourceMaskExtent(this.extent, mask); + SourceMaskExtent next = new SourceMaskExtent(getExtent(), mask); + new ExtentTraverser<>(getExtent()).setNext(next); } } @@ -818,13 +579,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, Mask existing = getSourceMask(); if (existing != null) { if (existing instanceof MaskIntersection) { - ((MaskIntersection) existing).add(mask); - return; + Collection masks = new HashSet<>(((MaskIntersection) existing).getMasks()); + masks.add(mask); + mask = new MaskIntersection(masks); } else { - MaskIntersection intersection = new MaskIntersection(existing); - intersection.add(mask); - mask = intersection; + mask = new MaskIntersection(existing, mask); } + mask = mask.optimize(); } setSourceMask(mask); } @@ -840,7 +601,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { new MaskTraverser(mask).reset(this); } - ExtentTraverser maskingExtent = new ExtentTraverser(this.extent).find(MaskingExtent.class); + ExtentTraverser maskingExtent = new ExtentTraverser<>(getExtent()).find(MaskingExtent.class); if (maskingExtent != null && maskingExtent.get() != null) { Mask oldMask = maskingExtent.get().getMask(); if (oldMask instanceof ResettableMask) { @@ -848,7 +609,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } maskingExtent.get().setMask(mask); } else if (mask != Masks.alwaysTrue()) { - this.extent = new MaskingExtent(this.extent, mask); + MaskingExtent next = new MaskingExtent(getExtent(), mask); + new ExtentTraverser<>(getExtent()).setNext(next); } } @@ -858,13 +620,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @return the survival simulation extent */ public SurvivalModeExtent getSurvivalExtent() { - ExtentTraverser survivalExtent = new ExtentTraverser<>(this.extent).find(SurvivalModeExtent.class); + ExtentTraverser survivalExtent = new ExtentTraverser<>(getExtent()).find(SurvivalModeExtent.class); if (survivalExtent != null) { return survivalExtent.get(); } else { - AbstractDelegateExtent extent = this.extent; - SurvivalModeExtent survival = new SurvivalModeExtent(extent.getExtent(), getWorld()); - new ExtentTraverser(extent).setNext(survival); + SurvivalModeExtent survival = new SurvivalModeExtent(bypassAll.getExtent(), getWorld()); + new ExtentTraverser(bypassAll).setNext(survival); return survival; } } @@ -891,21 +652,21 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (history == null) { return; } - ExtentTraverser traverseHistory = new ExtentTraverser<>(this.extent).find(HistoryExtent.class); + ExtentTraverser traverseHistory = new ExtentTraverser<>(getExtent()).find(HistoryExtent.class); if (disableHistory) { if (traverseHistory != null && traverseHistory.exists()) { - ExtentTraverser beforeHistory = traverseHistory.previous(); - ExtentTraverser afterHistory = traverseHistory.next(); + ExtentTraverser beforeHistory = traverseHistory.previous(); + ExtentTraverser afterHistory = traverseHistory.next(); if (beforeHistory != null && beforeHistory.exists()) { beforeHistory.setNext(afterHistory.get()); } else { - extent = (AbstractDelegateExtent) afterHistory.get(); + new ExtentTraverser<>(getExtent()).setNext(afterHistory.get()); } } } else if (traverseHistory == null || !traverseHistory.exists()) { - ExtentTraverser traverseBypass = new ExtentTraverser<>(this.extent).find(bypassHistory); + ExtentTraverser traverseBypass = new ExtentTraverser<>(getExtent()).find(bypassHistory); if (traverseBypass != null) { - ExtentTraverser beforeHistory = traverseBypass.previous(); + ExtentTraverser beforeHistory = traverseBypass.previous(); beforeHistory.setNext(history); } } @@ -938,12 +699,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @param blockBag the block bag to set, or null to use none */ public void setBlockBag(BlockBag blockBag) { - this.blockBag = blockBag; + throw new UnsupportedOperationException("TODO - this is never called anyway"); } @Override public String toString() { - return super.toString() + ":" + extent; + return super.toString() + ":" + getExtent(); } /** @@ -964,7 +725,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (changeSet instanceof BlockBagChangeSet) { missingBlocks = ((BlockBagChangeSet) changeSet).popMissing(); } else { - ExtentTraverser find = new ExtentTraverser<>(extent).find(BlockBagExtent.class); + ExtentTraverser find = new ExtentTraverser<>(getExtent()).find(BlockBagExtent.class); if (find != null && find.get() != null) { missingBlocks = find.get().popMissing(); } else { @@ -1032,69 +793,46 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } @Override - public BiomeType getBiome(BlockVector2 position) { - return this.extent.getBiome(position); + public BiomeType getBiome(final BlockVector2 position) { + return this.getExtent().getBiome(position); } @Override public boolean setBiome(BlockVector2 position, BiomeType biome) { this.changes++; - return this.extent.setBiome(position, biome); + return this.getExtent().setBiome(position, biome); } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { this.changes++; - return this.extent.setBiome(x, y, z, biome); - } - - @Override - public int getLight(int x, int y, int z) { - return queue.getLight(x, y, z); - } - - @Override - public int getBlockLight(int x, int y, int z) { - return queue.getEmmittedLight(x, y, z); - } - - @Override - public int getSkyLight(int x, int y, int z) { - return queue.getSkyLight(x, y, z); - } - - @Override - public int getBrightness(int x, int y, int z) { - return queue.getBrightness(x, y, z); - } - - @Override - public int getOpacity(int x, int y, int z) { - return queue.getOpacity(x, y, z); - } - - @Override - public BlockState getLazyBlock(final BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(x, y, z); + return this.getExtent().setBiome(x, y, z, biome); } public BlockState getBlock(int x, int y, int z) { - return getLazyBlock(x, y, z); + return getExtent().getBlock(x, y, z); } @Override public BlockState getBlock(BlockVector3 position) { - return extent.getBlock(position); + return getExtent().getBlock(position); } @Override public BaseBlock getFullBlock(BlockVector3 position) { - return extent.getFullBlock(position); + return getExtent().getFullBlock(position); + } + + /** + * Get a block type at the given position. + * + * @param position the position + * @return the block type + * @deprecated Use {@link #getBlock(BlockVector3)} or {@link #getBlock(BlockVector3)} + */ + @Deprecated + public BlockType getBlockType(final BlockVector3 position) { + return getBlockType(position.getBlockX(), position.getBlockY(), position.getBlockZ()); } /** @@ -1133,16 +871,11 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return y; } } - return minY; } public BlockType getBlockType(int x, int y, int z) { - if (!limit.MAX_CHECKS()) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); - } - int combinedId4Data = queue.getCombinedId4DataDebug(x, y, z, BlockTypes.AIR.getInternalId(), this); - return BlockTypes.getFromStateId(combinedId4Data); + return getBlock(x, y, z).getBlockType(); } /** @@ -1158,7 +891,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.changes++; switch (stage) { case BEFORE_HISTORY: - return extent.setBlock(position, block); + return this.getExtent().setBlock(position, block); case BEFORE_CHANGE: return bypassHistory.setBlock(position, block); case BEFORE_REORDER: @@ -1204,7 +937,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public > boolean setBlock(BlockVector3 position, B block) throws MaxChangedBlocksException { this.changes++; try { - return extent.setBlock(position, block); + return this.getExtent().setBlock(position, block); } catch (MaxChangedBlocksException e) { throw e; } catch (WorldEditException e) { @@ -1217,7 +950,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public > boolean setBlock(int x, int y, int z, B block) { this.changes++; try { - return this.extent.setBlock(x, y, z, block); + return this.getExtent().setBlock(x, y, z, block); } catch (WorldEditException e) { throw new RuntimeException("Unexpected exception", e); } @@ -1237,7 +970,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.changes++; try { BlockVector3 bv = mutablebv.setComponents(x, y, z); - return pattern.apply(extent, bv, bv); + return pattern.apply(getExtent(), bv, bv); } catch (WorldEditException e) { throw new RuntimeException("Unexpected exception", e); } @@ -1254,7 +987,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, public boolean setBlock(BlockVector3 position, Pattern pattern) throws MaxChangedBlocksException { this.changes++; try { - return pattern.apply(this.extent, position, position); + return pattern.apply(this.getExtent(), position, position); } catch (WorldEditException e) { throw new RuntimeException(e); } @@ -1270,7 +1003,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int setBlocks(Set vset, Pattern pattern) throws MaxChangedBlocksException { - RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(extent, pattern), this); + RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(getExtent(), pattern)); Operations.completeBlindly(visitor); changes += visitor.getAffected(); return changes; @@ -1307,7 +1040,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override @Nullable public Entity createEntity(Location location, final BaseEntity entity) { - return this.extent.createEntity(location, entity); + return getExtent().createEntity(location, entity); } /** @@ -1380,30 +1113,22 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public BlockVector3 getMinimumPoint() { - if (extent != null) { - return this.extent.getMinimumPoint(); - } else { - return BlockVector3.at(-30000000, 0, -30000000); - } + return getExtent().getMinimumPoint(); } @Override public BlockVector3 getMaximumPoint() { - if (extent != null) { - return this.extent.getMaximumPoint(); - } else { - return BlockVector3.at(30000000, 255, 30000000); - } + return getExtent().getMaximumPoint(); } @Override public List getEntities(Region region) { - return this.extent.getEntities(region); + return getExtent().getEntities(region); } @Override public List getEntities() { - return this.extent.getEntities(); + return getExtent().getEntities(); } /** @@ -1424,7 +1149,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, @Override public @Nullable Operation commit() { - return extent.commit(); + return getExtent().commit(); } /** @@ -1437,7 +1162,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (used.MAX_FAILS > 0) { if (used.MAX_CHANGES > 0 || used.MAX_ENTITIES > 0) { BBC.WORLDEDIT_SOME_FAILS.send(player, used.MAX_FAILS); - } else if (new ExtentTraverser(this).findAndGet(FaweRegionExtent.class) != null){ + } else if (new ExtentTraverser<>(getExtent()).findAndGet(FaweRegionExtent.class) != null){ BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION.send(player); } else { BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_LEVEL.send(player); @@ -1446,15 +1171,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, // Reset limit limit.set(originalLimit); // Enqueue it - if (queue == null || queue.isEmpty()) { - queue.dequeue(); - return; - } - if (Fawe.isMainThread()) { - SetQueue.IMP.flush(queue); - } else { - queue.flush(); - } + super.commit(); if (getChangeSet() != null) { if (Settings.IMP.HISTORY.COMBINE_STAGES) { ((FaweChangeSet) getChangeSet()).closeAsync(); @@ -1464,65 +1181,14 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } } - /** - * Count the number of blocks of a given list of types in a region. - * - * @param region the region - * @param searchIDs a list of IDs to search - * @return the number of found blocks - */ - public int countBlock(final Region region, final Set searchIDs) { - if (searchIDs.isEmpty()) { - return 0; - } - if (searchIDs.size() == 1) { - final BlockType id = searchIDs.iterator().next(); - RegionVisitor visitor = new RegionVisitor(region, position -> getBlock(position).getBlockType() == id, this); - Operations.completeBlindly(visitor); - return visitor.getAffected(); - } - final boolean[] ids = new boolean[BlockTypes.size()]; - for (final BlockType id : searchIDs) { - ids[id.getInternalId()] = true; - } - return this.countBlock(region, ids); - } - - public int countBlock(final Region region, final boolean[] ids) { - RegionVisitor visitor = new RegionVisitor(region, - position -> ids[getBlock(position).getInternalId()], this); - Operations.completeBlindly(visitor); - return visitor.getAffected(); - } - - public int countBlock(final Region region, final Mask mask) { - RegionVisitor visitor = new RegionVisitor(region, mask::test, this); - Operations.completeBlindly(visitor); - return visitor.getAffected(); - } - - /** - * Count the number of blocks of a list of types in a region. - * - * @param region the region - * @param searchBlocks the list of blocks to search - * @return the number of blocks that matched the pattern - */ - public int countBlocks(Region region, Set searchBlocks) { - Mask mask = new BlockMaskBuilder().addBlocks(searchBlocks).build(extent); - RegionVisitor visitor = new RegionVisitor(region, mask::test, this); - Operations.completeBlindly(visitor); - return visitor.getAffected(); - } - public int fall(final Region region, boolean fullHeight, final BlockStateHolder replace) { FlatRegion flat = asFlatRegion(region); final int startPerformY = region.getMinimumPoint().getBlockY(); final int startCheckY = fullHeight ? 0 : startPerformY; final int endY = region.getMaximumPoint().getBlockY(); RegionVisitor visitor = new RegionVisitor(flat, pos -> { - int x = pos.getBlockX(); - int z = pos.getBlockZ(); + int x = pos.getX(); + int z = pos.getZ(); int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { if (y < startPerformY) { @@ -1571,7 +1237,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, final BlockReplace replace = new BlockReplace(EditSession.this, pattern); // Pick how we're going to visit blocks - RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1), this); + RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1)); // Start at the origin visitor.visit(origin); @@ -1626,9 +1292,9 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, // Pick how we're going to visit blocks RecursiveVisitor visitor; if (recursive) { - visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); + visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); } else { - visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this); + visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1)); } // Start at the origin @@ -1747,7 +1413,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, checkNotNull(position); checkArgument(apothem >= 1, "apothem >= 1"); - Mask mask = new BlockTypeMask(this, blockType); + Mask mask = new SingleBlockTypeMask(this, blockType); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); Region region = new CuboidRegion( getWorld(), // Causes clamping of Y range @@ -1757,138 +1423,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return replaceBlocks(region, mask, pattern); } - /** - * Sets all the blocks inside a region to a given block type. - * - * @param region the region - * @param block the block - * @return number of blocks affected - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { - checkNotNull(region); - checkNotNull(block); - boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); - - if (canBypassAll(region, false, true) && !hasNbt) { - return changes = queue.setBlocks((CuboidRegion) region, block.getInternalId()); - } - try { - if (hasExtraExtents()) { - RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, (block)), this); - Operations.completeBlindly(visitor); - this.changes += visitor.getAffected(); - } else { - for (BlockVector3 blockVector3 : region) { - if (this.extent.setBlock(blockVector3, block)) { - changes++; - } - } - } - } catch (final WorldEditException e) { - throw new RuntimeException("Unexpected exception", e); - } - return changes; - } - - /** - * Sets all the blocks inside a region to a given pattern. - * - * @param region the region - * @param pattern the pattern that provides the replacement block - * @return number of blocks affected - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { - checkNotNull(region); - checkNotNull(pattern); - - if (pattern instanceof BlockPattern) { - return setBlocks(region, ((BlockPattern) pattern).getBlock()); - } - if (pattern instanceof BlockStateHolder) { - return setBlocks(region, (BlockStateHolder) pattern); - } - BlockReplace replace = new BlockReplace(this, pattern); - RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); - Operations.completeBlindly(visitor); - return this.changes = visitor.getAffected(); - } - - /** - * Replaces all the blocks matching a given filter, within a given region, to a block - * returned by a given pattern. - * - * @param region the region to replace the blocks within - * @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask} - * @param replacement the replacement block - * @return number of blocks affected - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public > int replaceBlocks(Region region, Set filter, B replacement) throws MaxChangedBlocksException { - return replaceBlocks(region, filter, replacement); - } - - /** - * Replaces all the blocks matching a given filter, within a given region, to a block - * returned by a given pattern. - * - * @param region the region to replace the blocks within - * @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask} - * @param pattern the pattern that provides the new blocks - * @return number of blocks affected - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { - Mask mask = filter == null ? new ExistingBlockMask(this) : new BlockMaskBuilder().addBlocks(filter).build(this); - return replaceBlocks(region, mask, pattern); - } - - /** - * Replaces all the blocks matching a given mask, within a given region, to a block - * returned by a given pattern. - * - * @param region the region to replace the blocks within - * @param mask the mask that blocks must match - * @param pattern the pattern that provides the new blocks - * @return number of blocks affected - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { - checkNotNull(region); - checkNotNull(mask); - checkNotNull(pattern); - - BlockReplace replace = new BlockReplace(this, pattern); - RegionMaskingFilter filter = new RegionMaskingFilter(mask, replace); - RegionVisitor visitor = new RegionVisitor(region, filter, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); - Operations.completeBlindly(visitor); - return this.changes = visitor.getAffected(); - } - - /** - * Sets the blocks at the center of the given region to the given pattern. - * If the center sits between two blocks on a certain axis, then two blocks - * will be placed to mark the center. - * - * @param region the region to find the center of - * @param pattern the replacement pattern - * @return the number of blocks placed - * @throws MaxChangedBlocksException thrown if too many blocks are changed - */ - public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { - checkNotNull(region); - checkNotNull(pattern); - - Vector3 center = region.getCenter(); - Region centerRegion = new CuboidRegion( - getWorld(), // Causes clamping of Y range - BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), - BlockVector3.at(MathUtils.roundHalfUp(center.getX()), - center.getY(), MathUtils.roundHalfUp(center.getZ()))); - return setBlocks(centerRegion, pattern); - } - /** * Make the faces of the given region as if it was a {@link CuboidRegion}. * @@ -1988,14 +1522,18 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (region instanceof CuboidRegion) { return makeCuboidWalls(region, pattern); } else { - for (BlockVector3 position : region) { - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); - if (!region.contains(x, z + 1) || !region.contains(x, z - 1) || !region.contains(x + 1, z) || !region.contains(x - 1, z)) { - setBlock(position, pattern); + replaceBlocks(region, new Mask() { + @Override + public boolean test(BlockVector3 position) { + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + if (!region.contains(x, z + 1) || !region.contains(x, z - 1) || !region.contains(x + 1, z) || !region.contains(x - 1, z)) { + return true; + } + return false; } - } + }, pattern); } return changes; } @@ -2011,7 +1549,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, */ public > int overlayCuboidBlocks(Region region, B block) throws MaxChangedBlocksException { checkNotNull(block); - return overlayCuboidBlocks(region, block); } @@ -2033,7 +1570,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, int minY = region.getMinimumPoint().getBlockY(); int maxY = Math.min(getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockY() + 1); SurfaceRegionFunction surface = new SurfaceRegionFunction(this, offset, minY, maxY); - FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface, this); + FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface); Operations.completeBlindly(visitor); return this.changes = visitor.getAffected(); } @@ -2197,7 +1734,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState()); } - RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); + RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); // Around the origin in a 3x3 block for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { @@ -2510,8 +2047,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makeSphere(BlockVector3 pos, Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled) throws MaxChangedBlocksException { - int affected = 0; - radiusX += 0.5; radiusY += 0.5; radiusZ += 0.5; @@ -3108,7 +2643,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, throw new RuntimeException(e); } } - }, this); + }); Operations.completeBlindly(visitor); changes += visitor.getAffected(); return changes; @@ -3125,6 +2660,11 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int hollowOutRegion(Region region, int thickness, Pattern pattern) throws MaxChangedBlocksException { + return hollowOutRegion(region, thickness, pattern, new SolidBlockMask(this)); + } + + public int hollowOutRegion(final Region region, final int thickness, final Pattern pattern, Mask mask) { + try { final Set outside = new LocalBlockVectorSet(); final BlockVector3 min = region.getMinimumPoint(); @@ -3139,22 +2679,22 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, for (int x = minX; x <= maxX; ++x) { for (int y = minY; y <= maxY; ++y) { - recurseHollow(region, BlockVector3.at(x, y, minZ), outside); - recurseHollow(region, BlockVector3.at(x, y, maxZ), outside); + recurseHollow(region, BlockVector3.at(x, y, minZ), outside, mask); + recurseHollow(region, BlockVector3.at(x, y, maxZ), outside, mask); } } for (int y = minY; y <= maxY; ++y) { for (int z = minZ; z <= maxZ; ++z) { - recurseHollow(region, BlockVector3.at(minX, y, z), outside); - recurseHollow(region, BlockVector3.at(maxX, y, z), outside); + recurseHollow(region, BlockVector3.at(minX, y, z), outside, mask); + recurseHollow(region, BlockVector3.at(maxX, y, z), outside, mask); } } for (int z = minZ; z <= maxZ; ++z) { for (int x = minX; x <= maxX; ++x) { - recurseHollow(region, BlockVector3.at(x, minY, z), outside); - recurseHollow(region, BlockVector3.at(x, maxY, z), outside); + recurseHollow(region, BlockVector3.at(x, minY, z), outside, mask); + recurseHollow(region, BlockVector3.at(x, maxY, z), outside, mask); } } @@ -3180,14 +2720,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (outside.contains(neighbor)) { continue outer; - } } - this.changes++; - try { - pattern.apply(this.extent, position, position); - } catch (WorldEditException e) { - e.printStackTrace(); } + this.changes++; + pattern.apply(getExtent(), position, position); + } + } catch (WorldEditException e) { + throw new RuntimeException(e); } return changes; } @@ -3400,29 +2939,29 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return returnset; } - private void recurseHollow(Region region, BlockVector3 origin, Set outside) { + private void recurseHollow(Region region, BlockVector3 origin, Set outside, Mask mask) { final LocalBlockVectorSet queue = new LocalBlockVectorSet(); queue.add(origin); while (!queue.isEmpty()) { - final BlockVector3 current = queue.getIndex(0); - queue.remove(current); - final BlockState block = getBlock(current); - if (block.getBlockType().getMaterial().isMovementBlocker()) { - continue; - } + Iterator iter = queue.iterator(); + while (iter.hasNext()) { + final BlockVector3 current = iter.next(); + iter.remove(); + if (mask.test(current)) { + continue; + } + if (!outside.add(current)) { + continue; + } + if (!region.contains(current)) { + continue; + } - if (!outside.add(current)) { - continue; - } - - if (!region.contains(current)) { - continue; - } - - for (BlockVector3 recurseDirection : recurseDirections) { - queue.add(current.add(recurseDirection)); - } + for (BlockVector3 recurseDirection : recurseDirections) { + queue.add(current.add(recurseDirection)); + } + } } } @@ -3497,19 +3036,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return null; } - @Override - public int getBlockLightLevel(BlockVector3 position) { - return queue.getEmmittedLight(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - @Override public boolean clearContainerBlockContents(BlockVector3 pos) { BaseBlock block = getFullBlock(pos); CompoundTag nbt = block.getNbtData(); if (nbt != null) { if (nbt.containsKey("items")) { - block.setNbtData(null); - return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block); + return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock()); } } return false; @@ -3528,14 +3061,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, for (int x = pos1.getX(); x <= pos2.getX(); x++) { for (int z = pos1.getBlockZ(); z <= pos2.getBlockZ(); z++) { for (int y = pos1.getY(); y <= pos2.getY(); y++) { - int from = queue.getCombinedId4Data(x, y, z); - queue.setBlock(x, y, z, from); - if (BlockTypes.getFromStateId(from).getMaterial().hasContainer()) { - CompoundTag tile = queue.getTileEntity(x, y, z); - if (tile != null) { - queue.setTile(x, y, z, tile); - } - } + setBlock(x, y, z, getFullBlock(x, y, z)); } } } @@ -3552,7 +3078,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); if (!fe.contains(max.getBlockX(), max.getBlockY(), max.getBlockZ()) && !fe.contains(min.getBlockX(), min.getBlockY(), min.getBlockZ())) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_OUTSIDE_REGION); + throw FaweException.OUTSIDE_REGION; } } final Set chunks = region.getChunks(); @@ -3639,8 +3165,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (changes != 0) { flushQueue(); return true; - } else { - this.queue.clear(); } return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index df32908f4..6dc8df7b7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -38,6 +38,7 @@ import com.boydti.fawe.util.MaskTraverser; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.minecraft.util.commands.CommandContext; + import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -91,6 +92,7 @@ import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; + /** * Clipboard commands. */ @@ -123,20 +125,24 @@ public class ClipboardCommands { Mask mask, CommandContext context) throws WorldEditException { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); + long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } fp.checkConfirmationRegion(() -> { session.setClipboard(null); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId()); + session.setClipboard(new ClipboardHolder(clipboard)); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyingEntities(!skipEntities); copy.setCopyingBiomes(copyBiomes); + Mask sourceMask = editSession.getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(editSession); @@ -204,12 +210,13 @@ public class ClipboardCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } if (volume >= limit.MAX_CHANGES) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + throw FaweException.MAX_CHANGES; } session.setClipboard(null); + ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, !skipEntities, copyBiomes); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard); clipboard.setOrigin(session.getPlacementPosition(player)); @@ -221,6 +228,7 @@ public class ClipboardCommands { name = "/cut", desc = "Cut the selection to the clipboard", descFooter = "WARNING: Cutting and pasting entities cannot be undone!" + ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) @@ -237,21 +245,24 @@ public class ClipboardCommands { CommandContext context) throws WorldEditException { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); + long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } if (volume >= limit.MAX_CHANGES) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); + throw FaweException.MAX_CHANGES; } fp.checkConfirmationRegion(() -> { session.setClipboard(null); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId()); clipboard.setOrigin(session.getPlacementPosition(player)); + ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); - copy.setCopyingEntities(!skipEntities); + copy.setCopyingEntities(copyEntities); copy.setRemovingEntities(true); copy.setCopyingBiomes(copyBiomes); Mask sourceMask = editSession.getSourceMask(); @@ -413,6 +424,7 @@ public class ClipboardCommands { @Command( name = "/paste", desc = "Paste the clipboard's contents" + ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) @@ -481,6 +493,7 @@ public class ClipboardCommands { name = "/place", desc = "Place the clipboard's contents without applying transformations (e.g. rotate)" ) + @CommandPermissions("worldedit.clipboard.place") @Logging(PLACEMENT) public void place(Player player, LocalSession session, final EditSession editSession, @@ -551,6 +564,7 @@ public class ClipboardCommands { public void flip(Player player, LocalSession session, @Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM) @Direction BlockVector3 direction) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); @@ -563,7 +577,7 @@ public class ClipboardCommands { desc = "Clear your clipboard" ) @CommandPermissions("worldedit.clipboard.clear") - public void clearClipboard(Player player, LocalSession session) throws WorldEditException { + public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException { session.setClipboard(null); BBC.CLIPBOARD_CLEARED.send(player); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index 6635883c0..6ad38305f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -205,6 +205,7 @@ public class PatternCommands extends MethodCommands { " - Use to replace slabs or where the data values needs to be shifted instead of set" ) public Pattern iddatamask(Actor actor, LocalSession session, Extent extent, @Range(min = 0, max = 15) int bitmask, Pattern pattern) { + return new IdDataMaskPattern(extent, pattern, bitmask); } @@ -213,6 +214,7 @@ public class PatternCommands extends MethodCommands { desc = "Only change the block id" ) public Pattern id(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new IdPattern(extent, pattern); } @@ -221,6 +223,7 @@ public class PatternCommands extends MethodCommands { desc = "Only change the block data" ) public Pattern data(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new DataPattern(extent, pattern); } @@ -230,6 +233,7 @@ public class PatternCommands extends MethodCommands { desc = "Set the biome" ) public Pattern biome(Actor actor, LocalSession session, Extent extent, BiomeType biome) { + return new BiomePattern(extent, biome); } @@ -239,6 +243,7 @@ public class PatternCommands extends MethodCommands { desc = "Offset the pattern to where you click" ) public Pattern relative(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new RelativePattern(pattern); } @@ -250,6 +255,7 @@ public class PatternCommands extends MethodCommands { "Example: #!x[#!z[#~[#l3d[pattern]]]]" ) public Pattern nox(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new NoXPattern(pattern); } @@ -259,6 +265,7 @@ public class PatternCommands extends MethodCommands { desc = "The pattern will not be provided the y axis info" ) public Pattern noy(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new NoYPattern(pattern); } @@ -268,6 +275,7 @@ public class PatternCommands extends MethodCommands { desc = "The pattern will not be provided the z axis info" ) public Pattern noz(Actor actor, LocalSession session, Extent extent, Pattern pattern) { + return new NoZPattern(pattern); } @@ -285,6 +293,7 @@ public class PatternCommands extends MethodCommands { desc = "Offset a pattern" ) public Pattern offset(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + return new OffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -293,6 +302,7 @@ public class PatternCommands extends MethodCommands { desc = "Applies to only blocks on a surface. Selects a block from provided pattern with a given ranomized offset `[0, )`. e.g. Use `#existing` to randomly offset blocks in the world, or `#copy` to offset blocks in your clipboard" ) public Pattern surfacespread(Actor actor, LocalSession session, double distance, Pattern pattern) { + return new SurfaceRandomOffsetPattern(pattern, (int) distance); } @@ -301,6 +311,7 @@ public class PatternCommands extends MethodCommands { desc = "Randomly spread solid blocks" ) public Pattern solidspread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + return new SolidRandomOffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -310,6 +321,7 @@ public class PatternCommands extends MethodCommands { desc = "Randomly spread blocks" ) public Pattern spread(Actor actor, LocalSession session, double x, double y, double z, Pattern pattern) { + return new RandomOffsetPattern(pattern, (int) x, (int) y, (int) z); } @@ -319,6 +331,7 @@ public class PatternCommands extends MethodCommands { desc = "Sequentially set blocks from a list of patterns" ) public Pattern linear(Actor actor, LocalSession session, Pattern other) { + if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -332,6 +345,7 @@ public class PatternCommands extends MethodCommands { desc = "Use the x,y,z coordinate to pick a block from the list" ) public Pattern linear3d(Actor actor, LocalSession session, Pattern other) { + if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -345,6 +359,7 @@ public class PatternCommands extends MethodCommands { desc = "Use the x,z coordinate to pick a block from the list" ) public Pattern linear2d(Actor actor, LocalSession session, Pattern other) { + if (other instanceof RandomPattern) { Set patterns = ((RandomPattern) other).getPatterns(); return new Linear2DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); @@ -358,6 +373,7 @@ public class PatternCommands extends MethodCommands { desc = "Expression pattern: http://wiki.sk89q.com/wiki/WorldEdit/Expression_syntax" ) public Pattern expression(Actor actor, LocalSession session, Extent extent, String input) throws ExpressionException { + Expression exp = Expression.compile(input, "x", "y", "z"); WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(extent, Vector3.ONE, Vector3.ZERO); exp.setEnvironment(env); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index f961fb9e7..430ee04a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -29,7 +29,11 @@ import static com.sk89q.worldedit.regions.Regions.asFlatRegion; import static com.sk89q.worldedit.regions.Regions.maximumBlockY; import static com.sk89q.worldedit.regions.Regions.minimumBlockY; + import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.beta.filters.SetFilter; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.filters.DistrFilter; import com.boydti.fawe.config.BBC; import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.object.FaweLimit; @@ -54,6 +58,7 @@ import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.LayerVisitor; @@ -76,9 +81,11 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.command.binding.Range; import com.sk89q.worldedit.util.command.parametric.Optional; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.Biomes; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; @@ -109,6 +116,43 @@ public class RegionCommands { this.worldEdit = worldEdit; } + + @Command( + aliases = {"debugtest"}, + usage = "", + desc = "debugtest", + help = "debugtest" + ) + @CommandPermissions("fawe.admin.debug") + public void debugtest(Player player, @Selection Region region) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + DistrFilter filter = new DistrFilter(); + long start = System.currentTimeMillis(); + queueHandler.apply(world, region, filter); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + + @Command( + aliases = {"db2"}, + usage = "", + desc = "db2", + help = "db2" + ) + @CommandPermissions("fawe.admin.debug") + public void db2(Player player, @Selection Region region, String blockStr) throws WorldEditException { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + World world = player.getWorld(); + BlockState block = BlockState.get(blockStr); + SetFilter filter = new SetFilter(block); + long start = System.currentTimeMillis(); + queueHandler.apply(world, region, filter); + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + + @Command( name = "/fixlighting", desc = "Get the light at a position" @@ -417,7 +461,7 @@ public class RegionCommands { long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); FaweLimit limit = FawePlayer.wrap(player).getLimit(); if (volume >= limit.MAX_CHECKS) { - throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + throw FaweException.MAX_CHECKS; } player.checkConfirmationRegion(() -> { try { @@ -673,6 +717,7 @@ public class RegionCommands { descFooter = "Hollows out the object contained in this selection.\n" + "Optionally fills the hollowed out part with the given block.\n" + "Thickness is measured in manhattan distance." + ) @CommandPermissions("worldedit.region.hollow") @Logging(REGION) @@ -682,9 +727,11 @@ public class RegionCommands { int thickness, @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") Pattern pattern, + CommandContext context) throws WorldEditException { + Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask; player.checkConfirmationRegion(() -> { - int affected = editSession.hollowOutRegion(region, thickness, pattern); + int affected = editSession.hollowOutRegion(region, thickness, pattern, finalMask); BBC.VISITOR_BLOCK.send(player, affected); }, getArguments(context), region, context); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 021b0c3ae..fd0768c86 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -31,6 +31,7 @@ import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.clipboard.URIClipboardHolder; import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.schematic.StructureFormat; + import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.chat.Message; import com.sk89q.minecraft.util.commands.CommandContext; @@ -80,6 +81,7 @@ import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.Callable; + import java.util.regex.Pattern; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -403,8 +405,8 @@ public class SchematicCommands { } if (new PlayerSaveClipboardEvent(player, clipboard, uri, f.toURI()).call()) { try (ClipboardWriter writer = format.getWriter(fos)) { - if (writer instanceof StructureFormat) { - ((StructureFormat) writer).write(target, player.getName()); + if (writer instanceof MinecraftStructure) { + ((MinecraftStructure) writer).write(target, player.getName()); } else { writer.write(target); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 676dda1b0..5c2280bb6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -27,6 +27,7 @@ import com.boydti.fawe.object.clipboard.URIClipboardHolder; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.object.regions.selector.FuzzyRegionSelector; import com.boydti.fawe.object.regions.selector.PolyhedralRegionSelector; + import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -490,7 +491,7 @@ public class SelectionCommands { // TODO multi clipboard distribution Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing region = clipboard.getRegion(); - editSession.setExtent(new AbstractDelegateExtent(clipboard)); + new ExtentTraverser(editSession).setNext(new AbstractDelegateExtent(clipboard)); } else { region = session.getSelection(player.getWorld()); } @@ -499,6 +500,7 @@ public class SelectionCommands { else distribution = (List) editSession.getBlockDistribution(region); + if (distribution.isEmpty()) { // *Should* always be false player.printError("No blocks counted."); return; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 86c28e49a..23cc8d029 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.command; import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; import com.boydti.fawe.Fawe; + import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.DelegateConsumer; @@ -60,6 +61,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; + import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.math.BlockVector3; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 3043bae7c..b8648f74b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -75,6 +75,7 @@ public class WorldEditCommands { FaweVersion fVer = Fawe.get().getVersion(); String fVerStr = fVer == null ? "unknown" : "-" + fVer.build; actor.print("FastAsyncWorldEdit" + fVerStr + " created by Empire92"); + if (fVer != null) { actor.printDebug("----------- Platforms -----------"); FaweVersion version = Fawe.get().getVersion(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 87c69438c..b63b1f406 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -48,6 +48,7 @@ import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxBrushRadiusException; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -643,15 +644,16 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool Brush brush = current.getBrush(); if (brush == null) return; FawePlayer fp = FawePlayer.wrap(player); - EditSession editSession = new EditSessionBuilder(player.getWorld()) + EditSessionBuilder builder = new EditSessionBuilder(player.getWorld()) .player(fp) .allowedRegionsEverywhere() .autoQueue(false) .blockBag(null) .changeSetNull() - .combineStages(false) - .build(); - VisualExtent newVisualExtent = new VisualExtent(editSession.getExtent(), editSession.getQueue()); + .combineStages(false); + EditSession editSession = builder.build(); + + VisualExtent newVisualExtent = new VisualExtent(builder.getExtent(), builder.getQueue()); BlockVector3 position = getPosition(editSession, player); if (position != null) { editSession.setExtent(newVisualExtent); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 34e3b91cc..c47338705 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; public class GravityBrush implements Brush { @@ -43,8 +44,8 @@ public class GravityBrush implements Brush { for (int x = position.getBlockX() + size; x > position.getBlockX() - size; --x) { for (int z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { int freeSpot = startCheckY; - for (int y = startCheckY; y <= endY; ++y) { - final BlockState block = editSession.getLazyBlock(x, y, z); + for (int y = startCheckY; y <= endY; y++) { + BlockStateHolder block = editSession.getBlock(x, y, z); if (!block.getBlockType().getMaterial().isAir()) { if (y != freeSpot) { editSession.setBlock(x, y, z, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 619a839f4..01ce94d25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -47,10 +47,8 @@ import javax.annotation.Nullable; /** * A base class for {@link Extent}s that merely passes extents onto another. */ -public class AbstractDelegateExtent implements LightingExtent { - - private transient final Extent extent; - protected MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0); +public class AbstractDelegateExtent implements Extent, LightingExtent { + private final Extent extent; /** * Create a new instance. @@ -62,126 +60,18 @@ public class AbstractDelegateExtent implements LightingExtent { this.extent = extent; } - public int getSkyLight(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getSkyLight(x, y, z); - } - return 0; - } - - @Override - public int getMaxY() { - return extent.getMaxY(); - } - - - @Override - public int getBlockLight(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getBlockLight(x, y, z); - } - return getBrightness(x, y, z); - } - - @Override - public int getOpacity(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getOpacity(x, y, z); - } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); - } - - @Override - public int getLight(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getLight(x, y, z); - } - return 0; - } - - @Override - public int getBrightness(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getBrightness(x, y, z); - } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightValue(); - } - /** * Get the extent. * * @return the extent */ - public Extent getExtent() { + public final Extent getExtent() { return extent; } - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(mutable.setComponents(x, y, z)); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return extent.getLazyBlock(position); - } - - @Override - public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - return setBlock(mutable.setComponents(x, y, z), block); - } - - @Override - public BlockState getBlock(BlockVector3 position) { - return extent.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return extent.getFullBlock(position); - } - - @Override - public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - return extent.setBlock(location, block); - } - - @Override - @Nullable - public Entity createEntity(Location location, BaseEntity entity) { - return extent.createEntity(location, entity); - } - - @Override - public List getEntities() { - return extent.getEntities(); - } - - @Override - public List getEntities(Region region) { - return extent.getEntities(region); - } - - @Override - public BiomeType getBiome(BlockVector2 position) { - return extent.getBiome(position); - } - - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - return extent.setBiome(position, biome); - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return extent.setBiome(x, y, z, biome); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { - return extent.getHighestTerrainBlock(x, z, minY, maxY); - } - + /* + Bounds + */ @Override public BlockVector3 getMinimumPoint() { return extent.getMinimumPoint(); @@ -192,78 +82,90 @@ public class AbstractDelegateExtent implements LightingExtent { return extent.getMaximumPoint(); } - protected Operation commitBefore() { - return null; + @Override + public int getMaxY() { + return extent.getMaxY(); } + /* + Input + Output + */ + + @Override + public BlockState getBlock(int x, int y, int z) { + return extent.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return extent.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiomeType(int x, int z) { + return extent.getBiomeType(x, z); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return extent.setBiome(x, y, z, biome); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return extent.setBlock(x, y, z, block); + } + + /* + Light + */ + public int getSkyLight(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getSkyLight(x, y, z); + } + return 0; + } + + public int getBlockLight(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getBlockLight(x, y, z); + } + return getBrightness(x, y, z); + } + + public int getOpacity(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getOpacity(x, y, z); + } + return getBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); + } + + @Override + public int getLight(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getLight(x, y, z); + } + return 0; + } + + public int getBrightness(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getBrightness(x, y, z); + } + return getBlock(x, y, z).getBlockType().getMaterial().getLightValue(); + } + + /* + Generic + */ + @Override public String toString() { return super.toString() + ":" + extent.toString(); } - @Override - public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { - return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); - } - - @Override - public void addCaves(Region region) throws WorldEditException { - extent.addCaves(region); - } - - @Override - public void generate(Region region, GenBase gen) throws WorldEditException { - extent.generate(region, gen); - } - - @Override - public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { - extent.spawnResource(region, gen, rarity, frequency); - } - - @Override - public boolean contains(BlockVector3 pt) { - return extent.contains(pt); - } - - @Override - public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { - extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); - } - - @Override - public void addOres(Region region, Mask mask) throws WorldEditException { - extent.addOres(region, mask); + protected Operation commitBefore() { + return null; } @Override @@ -281,6 +183,4 @@ public class AbstractDelegateExtent implements LightingExtent { return null; } } - - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index ff564bf1c..df48b533a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -45,30 +47,13 @@ public interface InputExtent { * @param position position of the block * @return the block */ - BlockState getBlock(BlockVector3 position); + default BlockState getBlock(BlockVector3 position) { + return getBlock(position.getX(), position.getY(), position.getZ()); + } - /** - * Get a lazy, immutable snapshot of the block at the given location that only - * immediately contains information about the block's type (and metadata). - * - *

Further information (such as NBT data) will be available by the - * time of access. Therefore, it is not recommended that - * this method is used if the world is being simulated at the time of - * call. If the block needs to be stored for future use, then this method should - * definitely not be used. Moreover, the block that is returned is immutable (or - * should be), and therefore modifications should not be attempted on it. If a - * modifiable copy is required, then the block should be cloned.

- * - *

This method exists because it is sometimes important to inspect the block - * at a given location, but {@link #getBlock(BlockVector3)} may be too expensive in - * the underlying implementation. It is also not possible to implement - * caching if the returned object is mutable, so this methods allows caching - * implementations to be used.

- * - * @param position position of the block - * @return the block - */ - BlockState getLazyBlock(BlockVector3 position); + default BlockState getBlock(int x, int y, int z) { + return getBlock(MutableBlockVector3.get(x, y, z)); + } /** * Get a immutable snapshot of the block at the given location. @@ -76,7 +61,13 @@ public interface InputExtent { * @param position position of the block * @return the block */ - BaseBlock getFullBlock(BlockVector3 position); + default BaseBlock getFullBlock(BlockVector3 position) { + return getFullBlock(position.getX(), position.getY(), position.getZ()); + } + + default BaseBlock getFullBlock(int x, int y, int z) { + return getFullBlock(MutableBlockVector3.get(x, y, z)); + } /** * Get the biome at the given location. @@ -87,6 +78,11 @@ public interface InputExtent { * @param position the (x, z) location to check the biome at * @return the biome at the location */ - BiomeType getBiome(BlockVector2 position); + default BiomeType getBiome(BlockVector2 position) { + return getBiomeType(position.getX(), position.getZ()); + } + default BiomeType getBiomeType(int x, int z) { + return getBiome(MutableBlockVector2.get(x, z)); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 61e87fd43..cb31e893d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -73,16 +73,10 @@ public class NullExtent implements Extent { return null; } - @Override public BlockState getBlock(BlockVector3 position) { return BlockTypes.AIR.getDefaultState(); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return BlockTypes.AIR.getDefaultState(); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return getBlock(position).toBaseBlock(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index 460769fa5..b97885f84 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -199,9 +199,20 @@ public class SpongeSchematicReader extends NBTSchematicReader { setupClipboard(0, uuid); } int[] pos = value.getIntArray("Pos"); - int x = pos[0]; - int y = pos[1]; - int z = pos[2]; + int x,y,z; + if (pos.length != 3) { + System.out.println("Invalid tile " + value); + if (!value.containsKey("x") || !value.containsKey("y") || !value.containsKey("z")) { + return; + } + x = value.getInt("x"); + y = value.getInt("y"); + z = value.getInt("z"); + } else { + x = pos[0]; + y = pos[1]; + z = pos[2]; + } Map values = value.getValue(); Tag id = values.get("Id"); if (id != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 0533c4f77..cdffa1aa3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -51,6 +51,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -94,19 +95,11 @@ public class BlockTransformExtent extends ResettableExtent { } private static long[] adapt(Direction... dirs) { - long[] arr = new long[dirs.length]; - for (int i = 0; i < arr.length; i++) { - arr[i] = 1L << dirs[i].ordinal(); - } - return arr; + return Arrays.stream(dirs).mapToLong(dir -> 1L << dir.ordinal()).toArray(); } private static long[] adapt(Long... dirs) { - long[] arr = new long[dirs.length]; - for (int i = 0; i < arr.length; i++) { - arr[i] = dirs[i]; - } - return arr; + return Arrays.stream(dirs).mapToLong(dir -> dir).toArray(); } private static long[] getDirections(AbstractProperty property) { @@ -138,7 +131,7 @@ public class BlockTransformExtent extends ResettableExtent { case FACING: { List directions = new ArrayList<>(); for (Object value : values) { - directions.add(Direction.valueOf(value.toString().toUpperCase())); + directions.add(Direction.valueOf(value.toString().toUpperCase(Locale.ROOT))); } return adapt(directions.toArray(new Direction[0])); } @@ -220,9 +213,7 @@ public class BlockTransformExtent extends ResettableExtent { } private static long notIndex(long mask, int... indexes) { - for (int index : indexes) { - mask = mask | (1L << (index + values().length)); - } + mask |= Arrays.stream(indexes).mapToLong(index -> (1L << (index + values().length))).reduce(0, (a, b) -> a | b); return mask; } @@ -344,10 +335,10 @@ public class BlockTransformExtent extends ResettableExtent { Object southState = tmp.getState(PropertyKey.SOUTH); Object westState = tmp.getState(PropertyKey.WEST); - tmp = tmp.with(PropertyKey.valueOf(newNorth.name().toUpperCase()), northState); - tmp = tmp.with(PropertyKey.valueOf(newEast.name().toUpperCase()), eastState); - tmp = tmp.with(PropertyKey.valueOf(newSouth.name().toUpperCase()), southState); - tmp = tmp.with(PropertyKey.valueOf(newWest.name().toUpperCase()), westState); + tmp = tmp.with(PropertyKey.valueOf(newNorth.name().toUpperCase(Locale.ROOT)), northState); + tmp = tmp.with(PropertyKey.valueOf(newEast.name().toUpperCase(Locale.ROOT)), eastState); + tmp = tmp.with(PropertyKey.valueOf(newSouth.name().toUpperCase(Locale.ROOT)), southState); + tmp = tmp.with(PropertyKey.valueOf(newWest.name().toUpperCase(Locale.ROOT)), westState); newMaskedId = tmp.getInternalId(); } @@ -476,7 +467,7 @@ public class BlockTransformExtent extends ResettableExtent { return BlockState.getFromInternalId(newMaskedId); } - public final BaseBlock transform(BlockStateHolder block) { + public final BaseBlock transform(BlockStateHolder block) { BlockState transformed = transform(block.toImmutableState()); if (block.hasNbtData()) { return transformBaseBlockNBT(transformed, block.getNbtData(), transform); @@ -501,13 +492,8 @@ public class BlockTransformExtent extends ResettableExtent { } @Override - public BlockState getLazyBlock(int x, int y, int z) { - return transform(super.getLazyBlock(x, y, z)); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return transform(super.getLazyBlock(position)); + public BlockState getBlock(int x, int y, int z) { + return transform(super.getBlock(x, y, z)); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index 544170221..cb4d91fba 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -19,256 +19,215 @@ package com.sk89q.worldedit.function.mask; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.boydti.fawe.object.collection.FastBitSet; -import com.boydti.fawe.util.StringMan; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.registry.state.AbstractProperty; -import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -import java.util.ArrayList; + +import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; +import java.util.function.Predicate; -/** - * A mask that checks whether blocks at the given positions are matched by - * a block in a list. - * - *

This mask checks for both an exact block type and state value match, - * respecting fuzzy status of the BlockState.

- * @deprecated use BlockMaskBuilder - */ -@Deprecated -public class BlockMask extends AbstractExtentMask { - - private final long[][] bitSets; - protected final static long[] ALL = new long[0]; - - - /** - * Create a new block mask. - * - * @param extent the extent - * @param blocks a list of blocks to match - */ - public BlockMask(Extent extent, Collection blocks) { - super(extent); - checkNotNull(blocks); - this.bitSets = new BlockMaskBuilder().addBlocks(blocks).optimize().getBits(); - } - - /** - * Create a new block mask. - * - * @param extent the extent - * @param block an array of blocks to match - */ - public BlockMask(Extent extent, BaseBlock... block) { - super(extent); - checkNotNull(block); - this.bitSets = new BlockMaskBuilder().addBlocks(block).optimize().getBits(); - } +public class BlockMask extends ABlockMask { + private final boolean[] ordinals; public BlockMask() { - super(NullExtent.INSTANCE); - this.bitSets = new long[BlockTypes.size()][]; + this(new NullExtent()); } - protected BlockMask(Extent extent, long[][] bitSets) { - super(extent); - this.bitSets = bitSets; + public BlockMask(Extent extent) { + this(extent, new boolean[BlockTypes.states.length]); } - public BlockMaskBuilder toBuilder() { - return new BlockMaskBuilder(this.bitSets); + public BlockMask(Extent extent, boolean[] ordinals) { + super(extent == null ? new NullExtent() : extent); + this.ordinals = ordinals; + } + + /** + * @deprecated NBT not supported by this mask + */ + @Deprecated + public BlockMask(Extent extent, Collection blocks) { + this(extent); + add(blocks); + } + + public BlockMask add(Predicate predicate) { + for (int i = 0; i < ordinals.length; i++) { + if (!ordinals[i]) { + BlockState state = BlockTypes.states[i]; + if (state != null) ordinals[i] = predicate.test(state); + } + } + return this; + } + + public BlockMask add(BlockState... states) { + addStates(Arrays.asList(states)); + return this; + } + + public BlockMask remove(BlockState... states) { + for (BlockState state : states) ordinals[state.getOrdinal()] = false; + return this; + } + + public BlockMask clear() { + Arrays.fill(ordinals, false); + return this; + } + + public boolean isEmpty() { + for (boolean value : ordinals) { + if (value) return false; + } + return true; + } + + public BlockMask addStates(Collection states) { + for (BlockState state : states) ordinals[state.getOrdinal()] = true; + return this; + } + + public BlockMask add(BlockType... types) { + addTypes(Arrays.asList(types)); + return this; + } + + public BlockMask addTypes(Collection types) { + for (BlockType type : types) { + for (BlockState state : type.getAllStates()) { + ordinals[state.getOrdinal()] = true; + } + } + return this; + } + + /** + * @deprecated NBT not supported by this mask + */ + @Deprecated + public void add(Collection blocks) { + for (BaseBlock block : blocks) { + add(block.toBlockState()); + } } @Override - public String toString() { - List strings = new ArrayList<>(); - for (int i = 0; i < bitSets.length; i++) { - if (bitSets[i] != null) { - long[] set = bitSets[i]; - BlockType type = BlockTypes.get(i); - if (set == ALL) { - strings.add(type.getId()); - } else { - for (BlockState state : type.getAllStates()) { - if (test(state)) { - strings.add(state.getAsString()); - } - } - } - } - } - return StringMan.join(strings, ","); + public boolean test(BlockState state) { + return ordinals[state.getOrdinal()]; } @Override - public Mask optimize() { - Map states = new HashMap<>(); - int indexFound = -1; - { - int indexNull = -1; - int indexAll = -1; - for (int i = 0; i < bitSets.length; i++) { - long[] bs = bitSets[i]; - if (bs == null) { - indexNull = i; - states.put(null, states.getOrDefault(null, 0) + 1); - } else if (bs.length == 0) { - indexAll = i; - states.put(ALL, states.getOrDefault(ALL, 0) + 1); - } else if (indexFound == -1) { - indexFound = i; - } else { - return this; - } - } - // Only types, no states - if (indexFound == -1) { - if (states.size() == 1) { - return states.keySet().iterator().next() == null ? Masks.alwaysFalse() : Masks.alwaysTrue(); - } - if (states.get(ALL) == 1) return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexAll)); - if (states.get(null) == 1) - return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexNull)).inverse(); - - boolean[] types = new boolean[BlockTypes.size()]; - for (int i = 0; i < bitSets.length; i++) { - if (bitSets[i].length == 0) types[i] = true; - } - return new BlockTypeMask(getExtent(), types); - } - } - BlockType type = BlockTypes.get(indexFound); - Mask mask = getOptimizedMask(type, bitSets[indexFound]); - if (mask == null) { // Try with inverse - long[] newBitSet = bitSets[indexFound]; - for (int i = 0; i < newBitSet.length; i++) newBitSet[i] = ~newBitSet[i]; - mask = getOptimizedMask(type, bitSets[indexFound]); - if (mask != null) mask = mask.inverse(); - } - return mask; - } - - private Mask getOptimizedMask(BlockType type, long[] bitSet) { - boolean single = true; - int and = type.getInternalId(); - List properties = type.getProperties(); - for (AbstractProperty prop : (List>) type.getProperties()) { - List values = prop.getValues(); - int numSet = 0; - for (int i = 0; i < values.size(); i++) { - int localI = i << prop.getBitOffset(); - if (FastBitSet.get(bitSet, localI)) { - numSet++; - and |= prop.modify(and, i); - } - } - // Cannot optimize multiple property values - use current mask (null) - if (numSet != values.size() && numSet != 1) { - return null; - } - single = single && numSet == 1; - } - if (single) - return new SingleBlockStateMask(getExtent(), BlockState.getFromInternalId(and)); - return new SingleBlockStateBitMask(getExtent(), and); + public boolean test(BlockVector3 vector) { + return ordinals[vector.getOrdinal(getExtent())]; } @Override - public Mask and(Mask other) { - if (other instanceof BlockMask) { - long[][] otherBitSets = ((BlockMask) other).bitSets; - for (int i = 0; i < otherBitSets.length; i++) { - long[] otherBitSet = otherBitSets[i]; - long[] bitSet = bitSets[i]; - if (otherBitSet == null) bitSets[i] = null; - else if (otherBitSet.length == 0) continue; - else if (bitSet == null) continue; - else if (bitSet.length == 0) bitSets[i] = otherBitSet; - else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] &= otherBitSet[j]; + public Mask and(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + for (int i = 0; i < ordinals.length; i++) { + if (ordinals[i]) { + ordinals[i] = other.test(BlockState.getFromOrdinal(i)); + } } return this; } - if (other instanceof SingleBlockStateMask) { - return new BlockMaskBuilder(bitSets).filter(((SingleBlockStateMask) other).getBlockState()).build(getExtent()); - } - if (other instanceof SingleBlockTypeMask) { - return new BlockMaskBuilder(bitSets).filter(((SingleBlockTypeMask) other).getBlockType()).build(getExtent()); - } return null; } @Override - public Mask or(Mask other) { - if (other instanceof BlockMask) { - long[][] otherBitSets = ((BlockMask) other).bitSets; - for (int i = 0; i < otherBitSets.length; i++) { - long[] otherBitSet = otherBitSets[i]; - long[] bitSet = bitSets[i]; - if (otherBitSet == null) continue; - else if (otherBitSet.length == 0) bitSets[i] = ALL; - else if (bitSet == null) bitSets[i] = otherBitSet; - else if (bitSet.length == 0) continue; - else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] |= otherBitSet[j]; + public Mask or(Mask mask) { + if (mask instanceof ABlockMask) { + ABlockMask other = (ABlockMask) mask; + for (int i = 0; i < ordinals.length; i++) { + if (!ordinals[i]) { + ordinals[i] = other.test(BlockState.getFromOrdinal(i)); + } } return this; } - if (other instanceof SingleBlockStateMask) { - return new BlockMaskBuilder(bitSets).add(((SingleBlockStateMask) other).getBlockState()).build(getExtent()); + return null; + } + + @Override + public Mask optimize() { + int setStates = 0; + BlockState setState = null; + BlockState unsetState = null; + int totalStates = 0; + + int setTypes = 0; + BlockType setType = null; + BlockType unsetType = null; + int totalTypes = 0; + + for (BlockType type : BlockTypes.values) { + if (type != null) { + totalTypes++; + boolean hasAll = true; + boolean hasAny = false; + List all = type.getAllStates(); + for (BlockState state : all) { + totalStates++; + hasAll &= test(state); + hasAny = true; + } + if (hasAll) { + setTypes++; + setType = type; + setStates += all.size(); + setState = type.getDefaultState(); + } else if (hasAny) { + for (BlockState state : all) { + if (test(state)) { + setStates++; + setState = state; + } else { + unsetState = state; + } + } + } else { + unsetType = type; + } + } } - if (other instanceof SingleBlockTypeMask) { - return new BlockMaskBuilder(bitSets).add(((SingleBlockTypeMask) other).getBlockType()).build(getExtent()); + if (setStates == 0) { + return Masks.alwaysFalse(); } + if (setStates == totalStates) { + return Masks.alwaysTrue(); + } + + if (setStates == 1) { + return new SingleBlockStateMask(getExtent(), setState); + } + + if (setStates == totalStates - 1) { + return new InverseSingleBlockStateMask(getExtent(), unsetState); + } + + if (setTypes == 1) { + return new SingleBlockTypeMask(getExtent(), setType); + } + + if (setTypes == totalTypes - 1) { + return new InverseSingleBlockTypeMask(getExtent(), unsetType); + } + return null; } @Override public Mask inverse() { - long[][] cloned = bitSets.clone(); - for (int i = 0; i < cloned.length; i++) { - if (cloned[i] == null) cloned[i] = ALL; - else if (cloned[i] == ALL) cloned[i] = null; - else { - for (int j = 0; j < cloned[i].length; j++) - cloned[i][j] = ~cloned[i][j]; - } - } + boolean[] cloned = ordinals.clone(); + for (int i = 0; i < cloned.length; i++) cloned[i] = !cloned[i]; return new BlockMask(getExtent(), cloned); } - - public boolean test(BlockState block) { - long[] bitSet = bitSets[block.getInternalBlockTypeId()]; - if (bitSet == null) return false; - if (bitSet.length == 0) return true; - return FastBitSet.get(bitSet, block.getInternalPropertiesId()); - } - - @Override - public boolean test(BlockVector3 vector) { - BlockStateHolder block = getExtent().getBlock(vector); - long[] bitSet = bitSets[block.getInternalBlockTypeId()]; - if (bitSet == null) return false; - if (bitSet.length == 0) return true; - return FastBitSet.get(bitSet, block.getInternalPropertiesId()); - } - - @Nullable - @Override - public Mask2D toMask2D() { - return null; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java index 2836ac366..c580b3ecc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMaskBuilder.java @@ -10,6 +10,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -28,6 +29,8 @@ public class BlockMaskBuilder { private static final Operator LESS_EQUAL = (a, b) -> a <= b; private static final Operator NOT = (a, b) -> a != b; + private final static long[] ALL = new long[0]; + private interface Operator { boolean test(int left, int right); } @@ -223,7 +226,7 @@ public class BlockMaskBuilder { if (states == null) return false; List values = prop.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - return (states == BlockMask.ALL || FastBitSet.get(states, localI)); + return (states == ALL || FastBitSet.get(states, localI)); } private void suggest(String input, String property, Collection finalTypes) throws InputParseException { @@ -240,6 +243,7 @@ public class BlockMaskBuilder { ///// end internal ///// private long[][] bitSets; + private boolean[] ordinals; private boolean optimizedStates = true; @@ -256,14 +260,23 @@ public class BlockMaskBuilder { } public BlockMaskBuilder addAll() { - Arrays.fill(bitSets, BlockMask.ALL); - optimizedStates = true; + for (int i = 0; i < bitSets.length; i++) { + bitSets[i] = ALL; + } + reset(true); return this; } + private void reset(boolean optimized) { + this.ordinals = null; + this.optimizedStates = optimized; + } + public BlockMaskBuilder clear() { - Arrays.fill(bitSets, null); - optimizedStates = true; + for (int i = 0; i < bitSets.length; i++) { + bitSets[i] = null; + } + reset(true); return this; } @@ -277,13 +290,13 @@ public class BlockMaskBuilder { int i = type.getInternalId(); long[] states = bitSets[i]; if (states != null) { - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); Arrays.fill(states, -1); } int stateId = state.getInternalPropertiesId(); FastBitSet.clear(states, stateId); - optimizedStates = false; + reset(false); } return this; } @@ -305,7 +318,7 @@ public class BlockMaskBuilder { if (states != null) { int stateId = state.getInternalPropertiesId(); boolean set = true; - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } else { set = FastBitSet.get(states, stateId); @@ -315,7 +328,7 @@ public class BlockMaskBuilder { FastBitSet.set(states, stateId); else bitSets[i] = null; - optimizedStates = true; + reset(true); } return this; } @@ -344,14 +357,14 @@ public class BlockMaskBuilder { List values = prop.getValues(); for (int j = 0; j < values.size(); j++) { int localI = j << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - if (states == BlockMask.ALL || FastBitSet.get(states, localI)) { + if (states == ALL || FastBitSet.get(states, localI)) { if (!allowed.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) { - if (states == BlockMask.ALL) { + if (states == ALL) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); FastBitSet.setAll(states); } FastBitSet.clear(states, localI); - optimizedStates = false; + reset(false); } } } @@ -361,7 +374,7 @@ public class BlockMaskBuilder { } public BlockMaskBuilder add(BlockType type) { - bitSets[type.getInternalId()] = BlockMask.ALL; + bitSets[type.getInternalId()] = ALL; return this; } @@ -369,13 +382,13 @@ public class BlockMaskBuilder { BlockType type = state.getBlockType(); int i = type.getInternalId(); long[] states = bitSets[i]; - if (states != BlockMask.ALL) { + if (states != ALL) { if (states == null) { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } int stateId = state.getInternalPropertiesId(); FastBitSet.set(states, stateId); - optimizedStates = false; + reset(false); } return this; } @@ -404,7 +417,7 @@ public class BlockMaskBuilder { for (int i = 0; i < bitSets.length; i++) { BlockType type = BlockTypes.get(i); if (allow.test(type)) { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; } } return this; @@ -413,7 +426,7 @@ public class BlockMaskBuilder { public BlockMaskBuilder addAll(Predicate typePredicate, BiPredicate, ?>> propPredicate) { for (int i = 0; i < bitSets.length; i++) { long[] states = bitSets[i]; - if (states == BlockMask.ALL) continue; + if (states == ALL) continue; BlockType type = BlockTypes.get(i); if (!typePredicate.test(type)) { continue; @@ -428,7 +441,7 @@ public class BlockMaskBuilder { bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1); } FastBitSet.set(states, localI); - optimizedStates = false; + reset(false); } } } @@ -440,7 +453,7 @@ public class BlockMaskBuilder { public BlockMaskBuilder add(BlockType type, Property property, int index) { AbstractProperty prop = (AbstractProperty) property; long[] states = bitSets[type.getInternalId()]; - if (states == BlockMask.ALL) return this; + if (states == ALL) return this; List values = property.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; @@ -449,7 +462,7 @@ public class BlockMaskBuilder { bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1); } set(type, states, property, index); - optimizedStates = false; + reset(false); } return this; } @@ -460,13 +473,13 @@ public class BlockMaskBuilder { if (states == null) return this; List values = property.getValues(); int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET; - if (states == BlockMask.ALL || FastBitSet.get(states, localI)) { - if (states == BlockMask.ALL) { + if (states == ALL || FastBitSet.get(states, localI)) { + if (states == ALL) { bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1); FastBitSet.setAll(states); } clear(type, states, property, index); - optimizedStates = false; + reset(false); } return this; } @@ -512,7 +525,7 @@ public class BlockMaskBuilder { if (!optimizedStates) { for (int i = 0; i < bitSets.length; i++) { long[] bitSet = bitSets[i]; - if (bitSet == null || bitSet == BlockMask.ALL) continue; + if (bitSet == null || bitSet == ALL) continue; BlockType type = BlockTypes.get(i); int maxStateId = type.getMaxStateId(); if (maxStateId == 0) { @@ -520,7 +533,7 @@ public class BlockMaskBuilder { bitSets[i] = null; continue; } else { - bitSets[i] = BlockMask.ALL; + bitSets[i] = ALL; continue; } } @@ -535,19 +548,38 @@ public class BlockMaskBuilder { } } if (set == 0) bitSets[i] = null; - else if (clear == 0) bitSets[i] = BlockMask.ALL; + else if (clear == 0) bitSets[i] = ALL; } - optimizedStates = true; + reset(true); } return this; } - protected long[][] getBits() { - return this.bitSets; + private boolean[] getOrdinals() { + if (ordinals == null) { + ordinals = new boolean[BlockTypes.states.length]; + for (int i = 0; i < BlockTypes.values.length; i++) { + long[] bitSet = bitSets[i]; + if (bitSet == null) continue; + BlockType type = BlockTypes.values[i]; + if (bitSet == ALL) { + for (BlockState state : type.getAllStates()) { + ordinals[state.getOrdinal()] = true; + } + } else { + for (BlockState state : type.getAllStates()) { + if (FastBitSet.get(bitSet, state.getInternalPropertiesId())) { + ordinals[state.getOrdinal()] = true; + } + } + + } + } + } + return ordinals; } public BlockMask build(Extent extent) { - optimize(); - return new BlockMask(extent, bitSets); + return new BlockMask(extent, getOrdinals()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index e2eceacde..e56bd813e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockType; @@ -37,8 +36,12 @@ import java.util.Set; * *

This mask checks for ONLY the block type. If state should also be checked, * use {@link BlockMask}.

+ * @deprecated use BlockMaskBuilder */ -public class BlockTypeMask extends AbstractExtentMask { +import static com.google.common.base.Preconditions.checkNotNull; + +@Deprecated +public final class BlockTypeMask extends AbstractExtentMask { private final boolean[] types; @@ -110,12 +113,11 @@ public class BlockTypeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return types[getExtent().getBlock(vector).getBlockType().getInternalId()]; + return test(vector.getBlock(getExtent()).getBlockType()); } - @Nullable - @Override - public Mask2D toMask2D() { - return null; + public boolean test(BlockType block) { + return types[block.getInternalId()]; } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java index ac85fe3d6..d493960bf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SingleBlockTypeMask.java @@ -2,10 +2,11 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -public class SingleBlockTypeMask extends AbstractExtentMask { +public class SingleBlockTypeMask extends ABlockMask { private final int internalId; public SingleBlockTypeMask(Extent extent, BlockType type) { @@ -15,12 +16,17 @@ public class SingleBlockTypeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return getExtent().getBlock(vector).getBlockType().getInternalId() == internalId; + return test(vector.getBlock(getExtent())); + } + + @Override + public final boolean test(BlockState state) { + return state.getBlockType().getInternalId() == internalId; } @Override public Mask inverse() { - return new BlockMaskBuilder().add(BlockTypes.get(internalId)).build(getExtent()).inverse(); + return new InverseSingleBlockTypeMask(getExtent(), BlockTypes.values[internalId]); } public BlockType getBlockType() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java index 2192d8f35..9e3ea34d3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -27,10 +27,10 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; -public class SolidBlockMask extends BlockTypeMask { - +public class SolidBlockMask extends BlockMask { public SolidBlockMask(Extent extent) { - super(extent, getTypes()); + super(extent); + add(state -> state.getMaterial().isSolid()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index 90587d4ca..5431e8b57 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -22,11 +22,7 @@ package com.sk89q.worldedit.function.visitor; import static com.google.common.base.Preconditions.checkNotNull; import com.boydti.fawe.config.BBC; -import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.MappedFaweQueue; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; -import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.object.collection.BlockVectorSet; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; @@ -38,8 +34,11 @@ import com.sk89q.worldedit.util.Direction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Performs a breadth-first search starting from points added with * {@link #visit(BlockVector3)}. The search continues @@ -81,13 +80,12 @@ public abstract class BreadthFirstSearch implements Operation { } private final RegionFunction function; - private BlockVectorSet queue; + private BlockVector3[] directions; private BlockVectorSet visited; + private BlockVectorSet queue; private int affected = 0; private int currentDepth = 0; private final int maxDepth; - private List directions = new ArrayList<>(); - private final MappedFaweQueue mFaweQueue; private int maxBranch = Integer.MAX_VALUE; /** @@ -101,33 +99,20 @@ public abstract class BreadthFirstSearch implements Operation { } public BreadthFirstSearch(RegionFunction function, int maxDepth) { - this(function, maxDepth, null); checkNotNull(function); - - } - - public BreadthFirstSearch(RegionFunction function, int maxDepth, HasFaweQueue faweQueue) { - checkNotNull(function); - FaweQueue fq = faweQueue != null ? faweQueue.getQueue() : null; - this.mFaweQueue = fq instanceof MappedFaweQueue ? (MappedFaweQueue) fq : null; this.queue = new BlockVectorSet(); this.visited = new BlockVectorSet(); this.function = function; - this.directions.addAll(Arrays.asList(DEFAULT_DIRECTIONS)); + this.directions = DEFAULT_DIRECTIONS; this.maxDepth = maxDepth; } - public void setDirections(List directions) { + public void setDirections(BlockVector3... directions) { this.directions = directions; } - private IntegerTrio[] getIntDirections() { - IntegerTrio[] array = new IntegerTrio[directions.size()]; - for (int i = 0; i < array.length; i++) { - BlockVector3 dir = directions.get(i); - array[i] = new IntegerTrio(dir.getBlockX(), dir.getBlockY(), dir.getBlockZ()); - } - return array; + public void setDirections(Collection directions) { + setDirections(directions.toArray(new BlockVector3[0])); } /** @@ -138,34 +123,36 @@ public abstract class BreadthFirstSearch implements Operation { * unit vectors. An example of a valid direction is * {@code BlockVector3.at(1, 0, 1)}.

* - *

The list of directions can be cleared.

- * * @return the list of directions */ - protected Collection getDirections() { - return directions; + public Collection getDirections() { + return Arrays.asList(directions); } /** * Add the directions along the axes as directions to visit. */ - protected void addAxes() { - directions.add(BlockVector3.UNIT_MINUS_Y); - directions.add(BlockVector3.UNIT_Y); - directions.add(BlockVector3.UNIT_MINUS_X); - directions.add(BlockVector3.UNIT_X); - directions.add(BlockVector3.UNIT_MINUS_Z); - directions.add(BlockVector3.UNIT_Z); + public void addAxes() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(BlockVector3.UNIT_MINUS_Y); + set.add(BlockVector3.UNIT_Y); + set.add(BlockVector3.UNIT_MINUS_X); + set.add(BlockVector3.UNIT_X); + set.add(BlockVector3.UNIT_MINUS_Z); + set.add(BlockVector3.UNIT_Z); + setDirections(set); } /** * Add the diagonal directions as directions to visit. */ - protected void addDiagonal() { - directions.add(Direction.NORTHEAST.toBlockVector()); - directions.add(Direction.SOUTHEAST.toBlockVector()); - directions.add(Direction.SOUTHWEST.toBlockVector()); - directions.add(Direction.NORTHWEST.toBlockVector()); + public void addDiagonal() { + HashSet set = new HashSet<>(Arrays.asList(directions)); + set.add(Direction.NORTHEAST.toBlockVector()); + set.add(Direction.SOUTHEAST.toBlockVector()); + set.add(Direction.SOUTHWEST.toBlockVector()); + set.add(Direction.NORTHWEST.toBlockVector()); + setDirections(set); } /** @@ -206,21 +193,6 @@ public abstract class BreadthFirstSearch implements Operation { public void setMaxBranch(int maxBranch) { this.maxBranch = maxBranch; } - /** - * Try to visit the given 'to' location. - * - * @param from the origin block - * @param to the block under question - */ - private void visit(BlockVector3 from, BlockVector3 to) { - BlockVector3 blockVector = to; - if (!visited.contains(blockVector)) { - visited.add(blockVector); - if (isVisitable(from, to)) { - queue.add(blockVector); - } - } - } /** * Return whether the given 'to' block should be visited, starting from the @@ -244,42 +216,22 @@ public abstract class BreadthFirstSearch implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { MutableBlockVector3 mutable = new MutableBlockVector3(); - IntegerTrio[] dirs = getIntDirections(); +// MutableBlockVector3 mutable2 = new MutableBlockVector3(); + boolean shouldTrim = false; + BlockVector3[] dirs = directions; BlockVectorSet tempQueue = new BlockVectorSet(); BlockVectorSet chunkLoadSet = new BlockVectorSet(); for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) { - if (mFaweQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) { - int cx = Integer.MIN_VALUE; - int cz = Integer.MIN_VALUE; - for (BlockVector3 from : queue) { - for (IntegerTrio direction : dirs) { - int x = from.getBlockX() + direction.x; - int z = from.getBlockZ() + direction.z; - if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) { - int y = from.getBlockY() + direction.y; - if (y < 0 || y >= 256) { - continue; - } - if (!visited.contains(x, y, z)) { - chunkLoadSet.add(cx, 0, cz); - } - } - } - } - for (BlockVector3 chunk : chunkLoadSet) { - mFaweQueue.queueChunkLoad(chunk.getBlockX(), chunk.getBlockZ()); - } - } for (BlockVector3 from : queue) { if (function.apply(from)) affected++; for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) { - IntegerTrio direction = dirs[i]; - int y = from.getBlockY() + direction.y; + BlockVector3 direction = dirs[i]; + int y = from.getBlockY() + direction.getY(); if (y < 0 || y >= 256) { continue; } - int x = from.getBlockX() + direction.x; - int z = from.getBlockZ() + direction.z; + int x = from.getBlockX() + direction.getX(); + int z = from.getBlockZ() + direction.getZ(); if (!visited.contains(x, y, z)) { if (isVisitable(from, mutable.setComponents(x, y, z))) { j++; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index 0feae6ca3..bd2658da6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -21,30 +21,36 @@ package com.sk89q.worldedit.math; import static com.google.common.base.Preconditions.checkArgument; +import com.google.common.collect.ComparisonChain; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import java.util.Comparator; /** * An immutable 3-dimensional vector. */ -public class BlockVector3 { +public abstract class BlockVector3 { - public static final BlockVector3 ZERO = new BlockVector3(0, 0, 0); - public static final BlockVector3 UNIT_X = new BlockVector3(1, 0, 0); - public static final BlockVector3 UNIT_Y = new BlockVector3(0, 1, 0); - public static final BlockVector3 UNIT_Z = new BlockVector3(0, 0, 1); - public static final BlockVector3 UNIT_MINUS_X = new BlockVector3(-1, 0, 0); - public static final BlockVector3 UNIT_MINUS_Y = new BlockVector3(0, -1, 0); - public static final BlockVector3 UNIT_MINUS_Z = new BlockVector3(0, 0, -1); - public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); + public static final BlockVector3 ZERO = BlockVector3.at(0, 0, 0); + public static final BlockVector3 UNIT_X = BlockVector3.at(1, 0, 0); + public static final BlockVector3 UNIT_Y = BlockVector3.at(0, 1, 0); + public static final BlockVector3 UNIT_Z = BlockVector3.at(0, 0, 1); + public static final BlockVector3 UNIT_MINUS_X = BlockVector3.at(-1, 0, 0); + public static final BlockVector3 UNIT_MINUS_Y = BlockVector3.at(0, -1, 0); + public static final BlockVector3 UNIT_MINUS_Z = BlockVector3.at(0, 0, -1); + public static final BlockVector3 ONE = BlockVector3.at(1, 1, 1); public static BlockVector3 at(double x, double y, double z) { return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); } public static BlockVector3 at(int x, int y, int z) { - return new BlockVector3(x, y, z); + return new BlockVector3Imp(x, y, z); } // thread-safe initialization idiom @@ -65,23 +71,6 @@ public class BlockVector3 { return YzxOrderComparator.YZX_ORDER; } - protected int x, y, z; - - protected BlockVector3(){} - - /** - * Construct an instance. - * - * @param x the X coordinate - * @param y the Y coordinate - * @param z the Z coordinate - */ - protected BlockVector3(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - public MutableBlockVector3 setComponents(double x, double y, double z) { return new MutableBlockVector3((int) x, (int) y, (int) z); } @@ -91,37 +80,71 @@ public class BlockVector3 { } public MutableBlockVector3 mutX(double x) { - return new MutableBlockVector3((int) x, y, z); + return new MutableBlockVector3((int) x, getY(), getZ()); } public MutableBlockVector3 mutY(double y) { - return new MutableBlockVector3(x, (int) y, z); + return new MutableBlockVector3(getX(), (int) y, getZ()); } public MutableBlockVector3 mutZ(double z) { - return new MutableBlockVector3(x, y, (int) z); + return new MutableBlockVector3(getX(), getY(), (int) z); } public MutableBlockVector3 mutX(int x) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(x, getY(), getZ()); } public MutableBlockVector3 mutY(int y) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), y, getZ()); } public MutableBlockVector3 mutZ(int z) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), getY(), z); } + public BlockVector3 toImmutable() { + return BlockVector3.at(getX(), getY(), getZ()); + } + +// /** +// * Get the BlockVector3 to the north
+// * Normal use you would use north(this), +// * To avoid constructing a new Vector, pass e.g. north(some MutableBlockVector3) +// * There is no gaurantee it will use this provided vector +// * @param orDefault the vector to use as the result
+// * @return BlockVector3 +// */ +// public BlockVector3 north(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY(), getZ() - 1); +// } +// +// public BlockVector3 east(BlockVector3 orDefault) { +// return orDefault.setComponents(getX() + 1, getY(), getZ()); +// } +// +// public BlockVector3 south(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY(), getZ() + 1); +// } +// +// public BlockVector3 west(BlockVector3 orDefault) { +// return orDefault.setComponents(getX() - 1, getY(), getZ()); +// } +// +// public BlockVector3 up(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY() + 1, getZ()); +// } +// +// public BlockVector3 down(BlockVector3 orDefault) { +// return orDefault.setComponents(getX(), getY() - 1, getZ()); +// } + /** * Get the X coordinate. * * @return the x coordinate */ - public int getX() { - return x; - } + public abstract int getX(); /** * Get the X coordinate. @@ -129,7 +152,7 @@ public class BlockVector3 { * @return the x coordinate */ public int getBlockX() { - return x; + return getX(); } /** @@ -139,7 +162,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withX(int x) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(x, getY(), getZ()); } /** @@ -147,9 +170,7 @@ public class BlockVector3 { * * @return the y coordinate */ - public int getY() { - return y; - } + public abstract int getY(); /** * Get the Y coordinate. @@ -157,7 +178,7 @@ public class BlockVector3 { * @return the y coordinate */ public int getBlockY() { - return y; + return getY(); } /** @@ -167,7 +188,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withY(int y) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), y, getZ()); } /** @@ -175,9 +196,7 @@ public class BlockVector3 { * * @return the z coordinate */ - public int getZ() { - return z; - } + public abstract int getZ(); /** * Get the Z coordinate. @@ -185,7 +204,7 @@ public class BlockVector3 { * @return the z coordinate */ public int getBlockZ() { - return z; + return getZ(); } /** @@ -195,7 +214,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withZ(int z) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), getY(), z); } /** @@ -205,7 +224,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3 other) { - return add(other.x, other.y, other.z); + return add(other.getX(), other.getY(), other.getZ()); } /** @@ -217,7 +236,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(int x, int y, int z) { - return BlockVector3.at(this.x + x, this.y + y, this.z + z); + return BlockVector3.at(this.getX() + x, this.getY() + y, this.getZ() + z); } /** @@ -228,12 +247,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX += other.x; - newY += other.y; - newZ += other.z; + newX += other.getX(); + newY += other.getY(); + newZ += other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -247,7 +266,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3 other) { - return subtract(other.x, other.y, other.z); + return subtract(other.getX(), other.getY(), other.getZ()); } /** @@ -260,7 +279,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(int x, int y, int z) { - return BlockVector3.at(this.x - x, this.y - y, this.z - z); + return BlockVector3.at(this.getX() - x, this.getY() - y, this.getZ() - z); } /** @@ -271,12 +290,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX -= other.x; - newY -= other.y; - newZ -= other.z; + newX -= other.getX(); + newY -= other.getY(); + newZ -= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -289,7 +308,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3 other) { - return multiply(other.x, other.y, other.z); + return multiply(other.getX(), other.getY(), other.getZ()); } /** @@ -301,7 +320,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(int x, int y, int z) { - return BlockVector3.at(this.x * x, this.y * y, this.z * z); + return BlockVector3.at(this.getX() * x, this.getY() * y, this.getZ() * z); } /** @@ -311,12 +330,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX *= other.x; - newY *= other.y; - newZ *= other.z; + newX *= other.getX(); + newY *= other.getY(); + newZ *= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -339,7 +358,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(BlockVector3 other) { - return divide(other.x, other.y, other.z); + return divide(other.getX(), other.getY(), other.getZ()); } /** @@ -351,7 +370,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(int x, int y, int z) { - return BlockVector3.at(this.x / x, this.y / y, this.z / z); + return BlockVector3.at(this.getX() / x, this.getY() / y, this.getZ() / z); } /** @@ -423,7 +442,7 @@ public class BlockVector3 { * @return length, squared */ public int lengthSq() { - return x * x + y * y + z * z; + return getX() * getX() + getY() * getY() + getZ() * getZ(); } /** @@ -443,9 +462,9 @@ public class BlockVector3 { * @return distance */ public int distanceSq(BlockVector3 other) { - int dx = other.x - x; - int dy = other.y - y; - int dz = other.z - z; + int dx = other.getX() - getX(); + int dy = other.getY() - getY(); + int dz = other.getZ() - getZ(); return dx * dx + dy * dy + dz * dz; } @@ -457,9 +476,9 @@ public class BlockVector3 { */ public BlockVector3 normalize() { double len = length(); - double x = this.x / len; - double y = this.y / len; - double z = this.z / len; + double x = this.getX() / len; + double y = this.getY() / len; + double z = this.getZ() / len; return BlockVector3.at(x, y, z); } @@ -470,7 +489,7 @@ public class BlockVector3 { * @return the dot product of this and the other vector */ public double dot(BlockVector3 other) { - return x * other.x + y * other.y + z * other.z; + return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ(); } /** @@ -480,10 +499,10 @@ public class BlockVector3 { * @return the cross product of this and the other vector */ public BlockVector3 cross(BlockVector3 other) { - return new BlockVector3( - y * other.z - z * other.y, - z * other.x - x * other.z, - x * other.y - y * other.x + return new BlockVector3Imp( + getY() * other.getZ() - getZ() * other.getY(), + getZ() * other.getX() - getX() * other.getZ(), + getX() * other.getY() - getY() * other.getX() ); } @@ -495,7 +514,7 @@ public class BlockVector3 { * @return true if the vector is contained */ public boolean containedWithin(BlockVector3 min, BlockVector3 max) { - return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + return getX() >= min.getX() && getX() <= max.getX() && getY() >= min.getY() && getY() <= max.getY() && getZ() >= min.getZ() && getZ() <= max.getZ(); } /** @@ -507,11 +526,11 @@ public class BlockVector3 { */ public BlockVector3 clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (y < min) { - return BlockVector3.at(x, min, z); + if (getY() < min) { + return BlockVector3.at(getX(), min, getZ()); } - if (y > max) { - return BlockVector3.at(x, max, z); + if (getY() > max) { + return BlockVector3.at(getX(), max, getZ()); } return this; } @@ -555,7 +574,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 abs() { - return BlockVector3.at(Math.abs(x), Math.abs(y), Math.abs(z)); + return BlockVector3.at(Math.abs(getX()), Math.abs(getY()), Math.abs(getZ())); } /** @@ -571,8 +590,8 @@ public class BlockVector3 { */ public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); - double x = this.x - aboutX; - double z = this.z - aboutZ; + double x = this.getX() - aboutX; + double z = this.getZ() - aboutZ; double cos = Math.cos(angle); double sin = Math.sin(angle); double x2 = x * cos - z * sin; @@ -580,7 +599,7 @@ public class BlockVector3 { return BlockVector3.at( x2 + aboutX + translateX, - y, + getY(), z2 + aboutZ + translateZ ); } @@ -626,10 +645,10 @@ public class BlockVector3 { * @return minimum */ public BlockVector3 getMinimum(BlockVector3 v2) { - return new BlockVector3( - Math.min(x, v2.x), - Math.min(y, v2.y), - Math.min(z, v2.z) + return new BlockVector3Imp( + Math.min(getX(), v2.getX()), + Math.min(getY(), v2.getY()), + Math.min(getZ(), v2.getZ()) ); } @@ -640,44 +659,110 @@ public class BlockVector3 { * @return maximum */ public BlockVector3 getMaximum(BlockVector3 v2) { - return new BlockVector3( - Math.max(x, v2.x), - Math.max(y, v2.y), - Math.max(z, v2.z) + return new BlockVector3Imp( + Math.max(getX(), v2.getX()), + Math.max(getY(), v2.getY()), + Math.max(getZ(), v2.getZ()) ); } + /* + Methods for getting/setting blocks + + Why are these methods here? + - Getting a block at a position requires various operations + (bounds checks, cache checks, ensuring loaded chunk, get ChunkSection, etc.) + - When iterating over a region, it will provide custom BlockVector3 positions + - These override the below set/get and avoid lookups (as the iterator shifts it to the chunk level) + */ + + public boolean setOrdinal(Extent orDefault, int ordinal) { + return orDefault.setBlock(this, BlockState.getFromOrdinal(ordinal)); + } + + public boolean setBlock(Extent orDefault, BlockState state) { + return orDefault.setBlock(this, state); + } + + public boolean setFullBlock(Extent orDefault, BaseBlock block) { + return orDefault.setBlock(this, block); + } + + public boolean setBiome(Extent orDefault, BiomeType biome) { + return orDefault.setBiome(getX(), getY(), getZ(), biome); + } + + public int getOrdinal(Extent orDefault) { + return getBlock(orDefault).getOrdinal(); + } + + public char getOrdinalChar(Extent orDefault) { + return (char) getOrdinal(orDefault); + } + + public BlockState getBlock(Extent orDefault) { + return orDefault.getBlock(this); + } + + public BaseBlock getFullBlock(Extent orDefault) { + return orDefault.getFullBlock(this); + } + + public CompoundTag getNbtData(Extent orDefault) { + return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData(); + } + + public BlockState getOrdinalBelow(Extent orDefault) { + return orDefault.getBlock(getX(), getY() - 1, getZ()); + } + + public BlockState getStateAbove(Extent orDefault) { + return orDefault.getBlock(getX(), getY() + 1, getZ()); + } + + public BlockState getStateRelativeY(Extent orDefault, final int y) { + return orDefault.getBlock(getX(), getY() + y, getZ()); + } + + + /* + Adapt + */ + /** * Creates a 2D vector by dropping the Y component from this vector. * * @return a new {@link BlockVector2} */ public BlockVector2 toBlockVector2() { - return BlockVector2.at(x, z); + return BlockVector2.at(getX(), getZ()); } public Vector3 toVector3() { - return Vector3.at(x, y, z); + return Vector3.at(getX(), getY(), getZ()); } @Override - public boolean equals(Object obj) { + public final boolean equals(Object obj) { if (!(obj instanceof BlockVector3)) { return false; } - BlockVector3 other = (BlockVector3) obj; - return other.x == this.x && other.y == this.y && other.z == this.z; + return equals((BlockVector3) obj); + } + + public final boolean equals(BlockVector3 other) { + return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); } @Override public int hashCode() { - return (x ^ (z << 12)) ^ (y << 24); + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); } @Override public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java index eba183599..dca366ce8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableVector3.java @@ -1,9 +1,18 @@ package com.sk89q.worldedit.math; +import com.boydti.fawe.FaweCache; + public class MutableVector3 extends Vector3 { public MutableVector3() { } + public static MutableVector3 get(int x, int y, int z) { + return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z); + } + + public static MutableVector3 get(double x, double y, double z) { + return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z); + } public MutableVector3(double x, double y, double z) { super(x, y, z); @@ -77,7 +86,4 @@ public class MutableVector3 extends Vector3 { return this; } - public double getY() { - return y; - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index ef5808da3..4c5800217 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -22,6 +22,11 @@ package com.sk89q.worldedit.regions; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.collection.BlockVectorSet; import com.sk89q.worldedit.math.BlockVector2; @@ -387,7 +392,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return chunks; } - @Override public boolean contains(int x, int y, int z) { return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ && y >= this.minY && y <= this.maxY; @@ -398,14 +402,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ; } - @Override - public boolean contains(BlockVector3 position) { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return position.containedWithin(min, max); - } - @Override public Iterator iterator() { if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9 || useOldIterator) { @@ -610,4 +606,51 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { BlockVector3 size = BlockVector3.ONE.multiply(apothem); return new CuboidRegion(origin.subtract(size), origin.add(size)); } + + @Override + public int getMinY() { + return minY; + } + + @Override + public int getMaxY() { + return maxY; + } + + @Override + public void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int X = chunk.getX(); + int Z = chunk.getZ(); + block = block.init(X, Z, get); + + if ((minX + 15) >> 4 <= X && (maxX - 15) >> 4 >= X && (minZ + 15) >> 4 <= Z && (maxZ - 15) >> 4 >= Z) { + filter(chunk, filter, block, get, set, minY, maxY); + return; + } + int localMinX = Math.max(minX, X << 4) & 15; + int localMaxX = Math.min(maxX, 15 + X << 4) & 15; + int localMinZ = Math.max(minZ, Z << 4) & 15; + int localMaxZ = Math.min(maxZ, 15 + Z << 4) & 15; + + int yStart = (minY & 15); + int yEnd = (maxY & 15); + + int minSection = minY >> 4; + int maxSection = maxY >> 4; + if (minSection == maxSection) { + filter(chunk, filter, block, get, set, minSection, localMinX, yStart, localMinZ, localMaxX, yEnd, localMaxZ); + return; + } + if (yStart != 0) { + filter(chunk, filter, block, get, set, minSection, localMinX, yStart, localMinZ, localMaxX, 15, localMaxZ); + minSection++; + } + if (yEnd != 15) { + filter(chunk, filter, block, get, set, minSection, localMinX, 0, localMinZ, localMaxX, 15, localMaxZ); + maxSection--; + } + for (int layer = minSection; layer < maxSection; layer++) { + filter(chunk, filter, block, get, set, layer, localMinX, yStart, localMinZ, localMaxX, yEnd, localMaxZ); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 10cfc56a5..ae33ef8c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -21,6 +21,11 @@ package com.sk89q.worldedit.regions; import static com.google.common.base.Preconditions.checkNotNull; +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -288,26 +293,22 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { minY += changeY; } - /** - * Checks to see if a point is inside this region. - */ @Override - public boolean contains(BlockVector3 position) { - final int blockY = position.getBlockY(); - if (blockY < minY || blockY > maxY) { + public boolean contains(int x, int y, int z) { + if (y < minY || y > maxY) { return false; } - //todo the following lines can possibly be removed and replaced with upstream - int px = position.getBlockX(); - int pz = position.getBlockZ(); + return contains(x, z); + } - double dx = Math.abs(px - center.getBlockX()) * radiusInverse.getX(); - double dz = Math.abs(pz - center.getBlockZ()) * radiusInverse.getZ(); + @Override + public boolean contains(int x, int z) { + double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX(); + double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ(); return dx * dx + dz * dz <= 1; } - /** * Sets the height of the cylinder to fit the specified Y. * @@ -362,6 +363,16 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { return Polygons.polygonizeCylinder(center, radius, maxPoints); } + @Override + public int getMinY() { + return minY; + } + + @Override + public int getMaxY() { + return maxY; + } + /** * Return a new instance with the given center and radius in the X and Z * axes with a Y that extends from the bottom of the extent to the top @@ -381,4 +392,16 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { return new CylinderRegion(center, radiusVec, minY, maxY); } + @Override + public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { + int bcx = chunk.getX() >> 4; + int bcz = chunk.getZ() >> 4; + int tcx = bcx + 15; + int tcz = bcz + 15; + if (contains(bcx, bcz) && contains(tcx, tcz)) { + filter(chunk, filter, block, get, set, minY, maxY); + return; + } + super.filter(chunk, filter, block, get, set); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index f54a42800..679047abf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -19,6 +19,13 @@ package com.sk89q.worldedit.regions; + +import com.boydti.fawe.beta.ChunkFilterBlock; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -44,6 +51,7 @@ public class EllipsoidRegion extends AbstractRegion { private Vector3 radius; private Vector3 radiusSqr; + private Vector3 inverseRadius; private int radiusLengthSqr; private boolean sphere; @@ -180,6 +188,12 @@ public class EllipsoidRegion extends AbstractRegion { radiusSqr = radius.multiply(radius); radiusLengthSqr = (int) radiusSqr.getX(); this.sphere = radius.getY() == radius.getX() && radius.getX() == radius.getZ(); + if (radius.getY() == radius.getX() && radius.getX() == radius.getZ()) { + this.sphere = true; + } else { + this.sphere = false; + } + inverseRadius = Vector3.ONE.divide(radius); } @Override @@ -206,30 +220,50 @@ public class EllipsoidRegion extends AbstractRegion { return chunks; } + @Override + public boolean contains(int x, int y, int z) { + int cx = x - center.getBlockX(); + int cx2 = cx * cx; + if (cx2 > radiusSqr.getBlockX()) { + return false; + } + int cz = z - center.getBlockZ(); + int cz2 = cz * cz; + if (cz2 > radiusSqr.getBlockZ()) { + return false; + } + int cy = y - center.getBlockY(); + int cy2 = cy * cy; + if (radiusSqr.getBlockY() < 255 && cy2 > radiusSqr.getBlockY()) { + return false; + } + if (sphere) { + return cx2 + cy2 + cz2 <= radiusLengthSqr; + } + double cxd = cx2 * inverseRadius.getX(); + double cyd = cy2 * inverseRadius.getY(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + cyd + czd <= 1; + } + @Override - public boolean contains(BlockVector3 position) { - int cx = position.getBlockX() - center.getBlockX(); + public boolean contains(int x, int z) { + int cx = x - center.getBlockX(); int cx2 = cx * cx; if (cx2 > radiusSqr.getBlockX()) { return false; } - int cz = position.getBlockZ() - center.getBlockZ(); + int cz = z - center.getBlockZ(); int cz2 = cz * cz; if (cz2 > radiusSqr.getBlockZ()) { return false; } - int cy = position.getBlockY() - center.getBlockY(); - int cy2 = cy * cy; - if (radiusSqr.getBlockY() < 255 && cy2 > radiusSqr.getBlockY()) { - return false; - } if (sphere) { - return cx2 + cy2 + cz2 <= radiusLengthSqr; + return cx2 + cz2 <= radiusLengthSqr; } - double cxd = (double) cx / radius.getBlockX(); - double cyd = (double) cy / radius.getBlockY(); - double czd = (double) cz / radius.getBlockZ(); - return cxd * cxd + cyd * cyd + czd * czd <= 1; + double cxd = cx2 * inverseRadius.getX(); + double czd = cz2 * inverseRadius.getZ(); + return cxd + czd <= 1; } /** @@ -252,4 +286,113 @@ public class EllipsoidRegion extends AbstractRegion { return (EllipsoidRegion) super.clone(); } + private void filterSpherePartial(int y1, int y2, int bx, int bz, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + int sectionStart = y1 >> 4; + int sectionEnd = y2 >> 4; + + } + + private void filterSpherePartial(int layer, int y1, int y2, int bx, int bz, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + int cx = center.getBlockX(); + int cy = center.getBlockY(); + int cz = center.getBlockZ(); + + block.init(get, set, layer); + + int by = layer << 4; + int diffY; + for (int y = y1, yy = by + y1; y <= y2; y++, yy++) { + diffY = cy - yy; + int remainderY = radiusLengthSqr - (diffY * diffY); + if (remainderY >= 0) { + for (int z = 0; z < 16; z++) { + int zz = z + bz; + int diffZ = cz - zz; + int remainderZ = remainderY - (diffZ * diffZ); + if (remainderZ >= 0) { + int diffX = MathMan.usqrt(remainderZ); + int minX = Math.max(0, cx - diffX - bx); + int maxX = Math.min(15, cx + diffX - bx); + if (minX != maxX) { + block.filter(filter, minX, y, z, maxX, y, z); + } + } + } + } + } + } + + @Override + public void filter(IChunk chunk, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set) { + // Check bounds + // This needs to be able to perform 50M blocks/sec otherwise it becomes a bottleneck + int cx = center.getBlockX(); + int cz = center.getBlockZ(); + int bx = chunk.getX() << 4; + int bz = chunk.getZ() << 4; + int tx = bx + 15; + int tz = bz + 15; + int cx1 = bx - cx; + int cx2 = tx - cx; + int cxMax, cxMin; + if (cx1 < cx2) { + cxMin = cx1; + cxMax = cx2; + } else { + cxMin = cx2; + cxMax = cx1; + } + int cxMin2 = cxMin * cxMin; + int cxMax2 = cxMax * cxMax; + int cz1 = bz - cz; + int cz2 = tz - cz; + int czMax, czMin; + if (cz1 < cz2) { + czMin = cz1; + czMax = cz2; + } else { + czMin = cz2; + czMax = cz1; + } + int czMin2 = czMin * czMin; + int czMax2 = czMax * czMax; + + + if (sphere) { + // Does not contain chunk + if (cxMin2 + czMin2 >= radiusLengthSqr) { + return; + } + int diffY2 = radiusLengthSqr - cxMax2 - czMax2; + // (shortcut) Contains all of certain layers + if (diffY2 >= 0) { + // Get the solid layers + int cy = center.getBlockY(); + int diffYFull = MathMan.usqrt(diffY2); + int yBotFull = Math.max(0, cy - diffYFull); + int yTopFull = Math.min(255, cy + diffYFull); + // Set those layers + filter(chunk, filter, block, get, set, yBotFull, yTopFull); + + // Fill the remaining layers + if (yBotFull != 0 || yTopFull != 255) { + int diffYPartial = MathMan.usqrt(radiusLengthSqr - cxMin * cxMin - czMin * czMin); + + if (yBotFull != 0) { + int yBotPartial = Math.max(0, cy - diffYPartial); + filterSpherePartial(yBotPartial, yBotFull - 1, bx, bz, filter, block, get, set); + } + + if (yTopFull != 255) { + int yTopPartial = Math.min(255, cy + diffYPartial); + filterSpherePartial(yTopFull + 1, yTopPartial - 1, bx, bz, filter, block, get, set); + } + } + } + + + } else { + super.filter(chunk, filter, block, get, set); // TODO optimize non spheres + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 2a915b59f..7ad85825f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -20,17 +20,16 @@ package com.sk89q.worldedit.world; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -69,7 +68,7 @@ public abstract class AbstractWorld implements World { @Override public Mask createLiquidMask() { - return new BlockTypeMask(this, BlockTypes.LAVA, BlockTypes.WATER); + return new BlockMask(this).add(BlockTypes.LAVA, BlockTypes.WATER); } @Override @@ -96,11 +95,6 @@ public abstract class AbstractWorld implements World { return false; } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { if (taskId == -1) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java index 2e7038682..c4c723e04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/SimpleWorld.java @@ -26,9 +26,8 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -41,6 +40,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; import javax.annotation.Nullable; +import java.nio.file.Path; /** * An abstract implementation of {@link World}. @@ -59,12 +59,16 @@ public interface SimpleWorld extends World { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); } @Override > boolean setBlock(BlockVector3 pt, B block) throws WorldEditException; + @Nullable @Override default Path getStoragePath() { + return null; + } + @Override default int getMaxY() { return getMaximumPoint().getBlockY(); @@ -72,7 +76,7 @@ public interface SimpleWorld extends World { @Override default Mask createLiquidMask() { - return new BlockTypeMask(this, BlockTypes.LAVA, BlockTypes.WATER); + return new BlockMask(this).add(BlockTypes.LAVA, BlockTypes.WATER); } @Override @@ -115,11 +119,6 @@ public interface SimpleWorld extends World { return BlockVector3.at(30000000, 255, 30000000); } - @Override - default @Nullable Operation commit() { - return null; - } - @Override default boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 677db5424..c050cf8e2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -26,6 +26,7 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.ABlockMask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; @@ -47,8 +48,8 @@ import java.util.Objects; */ public class BaseBlock implements BlockStateHolder, TileEntityBlock { - private BlockState blockState; - @Nullable protected CompoundTag nbtData; + private final BlockState blockState; + private final CompoundTag nbtData; @Deprecated public BaseBlock() { @@ -71,6 +72,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { */ public BaseBlock(BlockState blockState) { this.blockState = blockState; + nbtData = null; } /** @@ -181,7 +183,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public void setNbtData(@Nullable CompoundTag nbtData) { - this.nbtData = nbtData; + throw new UnsupportedOperationException("Immutable"); } /** @@ -233,13 +235,19 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { } @Override - public BaseBlock toBaseBlock() { + public final char getOrdinalChar() { + return blockState.getOrdinalChar(); + } + + @Override + public final BaseBlock toBaseBlock() { return this; } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this); + set.setFullBlock(extent, this); + return true; } @Override @@ -280,7 +288,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public int hashCode() { - return blockState.hashCode(); // stop changing this + return getOrdinal(); } @Override @@ -291,5 +299,4 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { return blockState.getAsString(); // } } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index 55eff879c..d35c640d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -19,14 +19,11 @@ package com.sk89q.worldedit.world.block; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.SingleBlockTypeMask; import com.sk89q.worldedit.function.pattern.FawePattern; import com.sk89q.worldedit.math.BlockVector3; @@ -38,13 +35,16 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; + +import javax.annotation.Nullable; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; -import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; public class BlockType implements FawePattern, Keyed { private final String id; @@ -173,10 +173,15 @@ public class BlockType implements FawePattern, Keyed { * * @return The default state */ - public BlockState getDefaultState() { + public final BlockState getDefaultState() { return this.settings.defaultState; } + /** + * @Deprecated use a Mask instead + * @return + */ + @Deprecated public FuzzyBlockState getFuzzyMatcher() { return new FuzzyBlockState(this); } @@ -288,7 +293,7 @@ public class BlockType implements FawePattern, Keyed { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return extent.setBlock(set, this.getDefaultState()); + return set.setBlock(extent, getDefaultState()); } @Override @@ -296,7 +301,11 @@ public class BlockType implements FawePattern, Keyed { return this.getDefaultState().toBaseBlock(); } - public Mask toMask(Extent extent) { + public SingleBlockTypeMask toMask() { + return toMask(null); + } + + public SingleBlockTypeMask toMask(Extent extent) { return new SingleBlockTypeMask(extent, this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index 711ee7b43..93b1e8d33 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; import java.util.Collection; import java.util.Optional; +import java.util.Locale; public final class ItemTypes { @@ -914,7 +915,7 @@ public final class ItemTypes { @Nullable public static ItemType parse(String input) { - input = input.toLowerCase(); + input = input.toLowerCase(Locale.ROOT); if (!Character.isAlphabetic(input.charAt(0))) { try { ItemType legacy = LegacyMapper.getInstance().getItemFromLegacy(input);