diff --git a/main/src/main/java/org/minerift/ether/EtherPlugin.java b/main/src/main/java/org/minerift/ether/EtherPlugin.java index b8bb55a..6eb3b89 100644 --- a/main/src/main/java/org/minerift/ether/EtherPlugin.java +++ b/main/src/main/java/org/minerift/ether/EtherPlugin.java @@ -4,6 +4,8 @@ import org.minerift.ether.debug.*; import org.minerift.ether.island.IslandManager; import org.minerift.ether.nms.NMSAccess; +import org.minerift.ether.schematic.pasters.SpongeSchematicPaster; +import org.minerift.ether.schematic.types.SchematicType; import org.minerift.ether.work.WorkQueue; import java.util.logging.Level; diff --git a/main/src/main/java/org/minerift/ether/debug/SchematicDebugCommand.java b/main/src/main/java/org/minerift/ether/debug/SchematicDebugCommand.java index fc8e1b8..02c1306 100644 --- a/main/src/main/java/org/minerift/ether/debug/SchematicDebugCommand.java +++ b/main/src/main/java/org/minerift/ether/debug/SchematicDebugCommand.java @@ -8,9 +8,8 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.minerift.ether.EtherPlugin; -import org.minerift.ether.nms.NMSAccess; import org.minerift.ether.schematic.SchematicFileReadException; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.types.Schematic; import org.minerift.ether.util.BukkitUtils; import org.minerift.ether.util.math.Vec3i; @@ -28,7 +27,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command return false; } - final NMSAccess nmsAccess = EtherPlugin.getInstance().getNMS(); final Player plr = (Player) sender; final Vec3i pos = BukkitUtils.getPosAsVec3i(plr.getLocation()); final String worldName = plr.getWorld().getName(); @@ -43,7 +41,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command // Attempt to paste Schematic.fromFile(file).handle((schem) -> { - schem.paste(pos, worldName); + schem.paste(pos, worldName, SchematicPasteOptions.DEFAULT); plr.sendMessage("Schematic pasted successfully!"); }, this::schemFail); diff --git a/main/src/main/java/org/minerift/ether/island/IslandCreationRoutine.java b/main/src/main/java/org/minerift/ether/island/IslandCreationRoutine.java index 618525f..419c5e6 100644 --- a/main/src/main/java/org/minerift/ether/island/IslandCreationRoutine.java +++ b/main/src/main/java/org/minerift/ether/island/IslandCreationRoutine.java @@ -2,6 +2,7 @@ import com.google.common.base.Preconditions; import org.bukkit.entity.Player; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.types.Schematic; import org.minerift.ether.user.EtherUser; import org.minerift.ether.util.math.Vec3i; @@ -27,7 +28,9 @@ public static Island run(IslandGrid grid, EtherUser user) { // TODO: Paste schematic/structure onto tile File file = null; Vec3i pos = Vec3i.ZERO; - Schematic.fromFile(file).handle((schem) -> schem.paste(pos, plr.getWorld().getName()), (ex) -> { throw new RuntimeException(ex); }); + Schematic.fromFile(file).handle((schem) -> { + schem.paste(pos, plr.getWorld().getName(), SchematicPasteOptions.builder().copyBiomes(true).build()); + }, (ex) -> { throw new RuntimeException(ex); }); // Teleport player diff --git a/main/src/main/java/org/minerift/ether/schematic/SchematicPasteFlags.java b/main/src/main/java/org/minerift/ether/schematic/SchematicPasteFlags.java new file mode 100644 index 0000000..e30c48b --- /dev/null +++ b/main/src/main/java/org/minerift/ether/schematic/SchematicPasteFlags.java @@ -0,0 +1,35 @@ +package org.minerift.ether.schematic; + +@Deprecated +public class SchematicPasteFlags { + + public static final byte IGNORE_AIR_BLOCKS = 1; + public static final byte WITH_BIOMES = 2; + public static final byte WITH_ENTITIES = 4; + + public static SchematicPasteFlags of(int flags) { + return new SchematicPasteFlags(flags); + } + + public static SchematicPasteFlags of(int flag, int ... flags) { + for(int f : flags) { + flag |= f; + } + return new SchematicPasteFlags(flag); + } + + private final int flags; + private SchematicPasteFlags(int flags) { + this.flags = flags; + } + + public void has(int flag, Runnable callback) { + if(has(flag)) { + callback.run(); + } + } + + public boolean has(int flag) { + return (flags & flag) != 0; + } +} diff --git a/main/src/main/java/org/minerift/ether/schematic/SchematicPasteOptions.java b/main/src/main/java/org/minerift/ether/schematic/SchematicPasteOptions.java new file mode 100644 index 0000000..0a73c37 --- /dev/null +++ b/main/src/main/java/org/minerift/ether/schematic/SchematicPasteOptions.java @@ -0,0 +1,81 @@ +package org.minerift.ether.schematic; + +import org.minerift.ether.util.math.Vec3i; + +public class SchematicPasteOptions { + + /** + * Default SchematicPasteOptions with no changes. + * Everything is defaulted to false or 0. + */ + public static final SchematicPasteOptions EMPTY_DEFAULT; + + /** + * Preferred default SchematicPasteOptions. + * Will copy biomes and entities with zero offset and no ignored air blocks. + */ + public static final SchematicPasteOptions DEFAULT; + + static { + EMPTY_DEFAULT = SchematicPasteOptions.builder().build(); + DEFAULT = SchematicPasteOptions.builder() + .copyBiomes(true) + .copyEntities(true) + .build(); + } + + public final boolean copyBiomes; + public final boolean copyEntities; + public final boolean ignoreAirBlocks; + public final Vec3i offset; + + private SchematicPasteOptions(SchematicPasteOptions.Builder builder) { + this.copyBiomes = builder.copyBiomes; + this.copyEntities = builder.copyEntities; + this.ignoreAirBlocks = builder.ignoreAirBlocks; + this.offset = builder.offset; + } + + public static SchematicPasteOptions.Builder builder() { + return new Builder(); + } + + public static class Builder { + private boolean copyBiomes; + private boolean copyEntities; + private boolean ignoreAirBlocks; + private Vec3i offset; + + private Builder() { + this.copyBiomes = false; + this.copyEntities = false; + this.ignoreAirBlocks = false; + this.offset = Vec3i.ZERO; + } + + public Builder copyBiomes(boolean val) { + this.copyBiomes = val; + return this; + } + + public Builder copyEntities(boolean val) { + this.copyEntities = val; + return this; + } + + public Builder ignoreAirBlocks(boolean val) { + this.ignoreAirBlocks = val; + return this; + } + + public Builder setOffset(Vec3i val) { + this.offset = val; + return this; + } + + public SchematicPasteOptions build() { + return new SchematicPasteOptions(this); + } + } + +} diff --git a/main/src/main/java/org/minerift/ether/schematic/pasters/ISchematicPaster.java b/main/src/main/java/org/minerift/ether/schematic/pasters/ISchematicPaster.java index b82419d..90daced 100644 --- a/main/src/main/java/org/minerift/ether/schematic/pasters/ISchematicPaster.java +++ b/main/src/main/java/org/minerift/ether/schematic/pasters/ISchematicPaster.java @@ -1,8 +1,9 @@ package org.minerift.ether.schematic.pasters; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.types.Schematic; import org.minerift.ether.util.math.Vec3i; public interface ISchematicPaster { - void paste(S schem, Vec3i pos, String worldName); + void paste(S schem, Vec3i pos, String worldName, SchematicPasteOptions options); } diff --git a/main/src/main/java/org/minerift/ether/schematic/pasters/SpongeSchematicPaster.java b/main/src/main/java/org/minerift/ether/schematic/pasters/SpongeSchematicPaster.java index 1be64a4..3ad7a86 100644 --- a/main/src/main/java/org/minerift/ether/schematic/pasters/SpongeSchematicPaster.java +++ b/main/src/main/java/org/minerift/ether/schematic/pasters/SpongeSchematicPaster.java @@ -6,13 +6,14 @@ import org.bukkit.block.Biome; import org.minerift.ether.EtherPlugin; import org.minerift.ether.nms.NMSAccess; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.types.SpongeSchematic; import org.minerift.ether.util.math.Vec3i; public class SpongeSchematicPaster implements ISchematicPaster { @Override - public void paste(SpongeSchematic schem, Vec3i pos, String worldName) { + public void paste(SpongeSchematic schem, Vec3i pos, String worldName, SchematicPasteOptions options) { final World world = Bukkit.getWorld(worldName); Preconditions.checkNotNull(world, String.format("World %s could not be found!", worldName)); @@ -21,25 +22,30 @@ public void paste(SpongeSchematic schem, Vec3i pos, String worldName) { final Vec3i.Mutable worldPasteLoc = pos.asMutable(); worldPasteLoc.add(schem.getOffset()); - schem.getBlocks().forEach(block -> block.getPos().add(worldPasteLoc)); - schem.getBiomes().forEach(biome -> biome.getPos().add(worldPasteLoc)); - schem.getEntities().forEach(entity -> entity.getPos().add(worldPasteLoc)); + // TODO: ignore air blocks based on options // Lazily set blocks + schem.getBlocks().forEach(block -> block.getPos().add(worldPasteLoc)); // translate to proper pos final NMSAccess nmsAccess = EtherPlugin.getInstance().getNMS(); nmsAccess.setBlocksAsyncLazy(schem.getBlocks(), world); // Set biomes - schem.getBiomes().forEach(biomeArchetype -> { - final Biome biome = biomeArchetype.getBiome(); - final Vec3i biomePos = biomeArchetype.getPos(); - world.setBiome(biomePos.getX(), biomePos.getY(), biomePos.getZ(), biome); - }); - - // Place entities - /*schem.getEntities().forEach(entityArchetype -> { - nmsAccess.spawnEntity(entityArchetype, world); - });*/ + if(options.copyBiomes) { + schem.getBiomes().forEach(biomeArchetype -> { + biomeArchetype.getPos().add(worldPasteLoc); // translate to proper pos + final Biome biome = biomeArchetype.getBiome(); + final Vec3i biomePos = biomeArchetype.getPos(); + world.setBiome(biomePos.getX(), biomePos.getY(), biomePos.getZ(), biome); + }); + } + + if(options.copyEntities) { + schem.getEntities().forEach(entity -> entity.getPos().add(worldPasteLoc)); // translate to proper pos + // TODO: Place entities + /*schem.getEntities().forEach(entityArchetype -> { + nmsAccess.spawnEntity(entityArchetype, world); + });*/ + } } } diff --git a/main/src/main/java/org/minerift/ether/schematic/pasters/WESchematicPaster.java b/main/src/main/java/org/minerift/ether/schematic/pasters/WESchematicPaster.java index fae554d..f017bca 100644 --- a/main/src/main/java/org/minerift/ether/schematic/pasters/WESchematicPaster.java +++ b/main/src/main/java/org/minerift/ether/schematic/pasters/WESchematicPaster.java @@ -8,29 +8,37 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.ClipboardHolder; import org.bukkit.Bukkit; import org.bukkit.World; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.types.WorldEditSchematic; import org.minerift.ether.util.math.Vec3i; public class WESchematicPaster implements ISchematicPaster { @Override - public void paste(WorldEditSchematic schem, Vec3i pos, String worldName) { + public void paste(WorldEditSchematic schem, Vec3i pos, String worldName, SchematicPasteOptions options) { final World world = Bukkit.getWorld(worldName); Preconditions.checkNotNull(world, String.format("World %s could not be found!", worldName)); try(EditSession editSession = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) { - Clipboard clipboard = schem.getClipboard(); - ClipboardHolder holder = new ClipboardHolder(clipboard); + final Clipboard clipboard = schem.getClipboard(); + final ClipboardHolder holder = new ClipboardHolder(clipboard); + + final Vec3i.Mutable vecTo = options.offset.asMutable(); + vecTo.add(pos); + + final BlockVector3 to = BlockVector3.at(vecTo.getX(), vecTo.getY(), vecTo.getZ()); + Operation operation = holder.createPaste(editSession) - .to(clipboard.getOrigin().add(pos.getX(), pos.getY(), pos.getZ())) - .copyBiomes(false) - .copyEntities(true) - .ignoreAirBlocks(true) + .to(to) + .copyBiomes(options.copyBiomes) + .copyEntities(options.copyEntities) + .ignoreAirBlocks(options.ignoreAirBlocks) .build(); Operations.completeLegacy(operation); diff --git a/main/src/main/java/org/minerift/ether/schematic/readers/sponge/SpongeSchematicReader.java b/main/src/main/java/org/minerift/ether/schematic/readers/sponge/SpongeSchematicReader.java index e2b7d9a..c379bf8 100644 --- a/main/src/main/java/org/minerift/ether/schematic/readers/sponge/SpongeSchematicReader.java +++ b/main/src/main/java/org/minerift/ether/schematic/readers/sponge/SpongeSchematicReader.java @@ -7,16 +7,14 @@ import java.io.File; import java.io.IOException; -import java.util.concurrent.atomic.AtomicReference; public class SpongeSchematicReader implements ISchematicReader { @Override public Result read(File file) { - AtomicReference> result = new AtomicReference<>(new Result<>()); + Result result = new Result<>(); ReaderContext.from(file).handle((ctx) -> { - boolean success = true; try { ReadStages.INIT.read(ctx); ReadStages.METADATA.read(ctx); @@ -24,26 +22,21 @@ public Result read(File file) { ReadStages.BLOCK_STATES.read(ctx); ReadStages.BIOMES.read(ctx); ReadStages.ENTITIES.read(ctx); - } catch (SchematicFileReadException e) { - // Delegate exception to result - result.get().err(e); - success = false; - } - // Set result to new SpongeSchematic - if(success) { - result.get().ok(ctx.builder.build()); - } + result.ok(ctx.builder.build()); - try { ctx.close(); - } catch (IOException e) { - throw new RuntimeException(e); + } catch (SchematicFileReadException ex) { + // Delegate exception to result + result.err(ex); + } catch (IOException ex) { + // Failed to close context; this should be notified + throw new RuntimeException(ex); } }, - // Handle context error - (ex) -> result.get().err(ex)); + // Delegate context error to result + result::err); - return result.get(); + return result; } } diff --git a/main/src/main/java/org/minerift/ether/schematic/types/Schematic.java b/main/src/main/java/org/minerift/ether/schematic/types/Schematic.java index 925da2c..1d2f7c5 100644 --- a/main/src/main/java/org/minerift/ether/schematic/types/Schematic.java +++ b/main/src/main/java/org/minerift/ether/schematic/types/Schematic.java @@ -3,6 +3,7 @@ import com.google.common.base.Preconditions; import org.minerift.ether.EtherPlugin; import org.minerift.ether.schematic.SchematicFileReadException; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.util.Result; import org.minerift.ether.util.math.Vec3i; @@ -27,10 +28,12 @@ static Result fromFile(File file) { SchematicType getType(); - void paste(Vec3i pos, String worldName); + void paste(Vec3i pos, String worldName, SchematicPasteOptions options); int getWidth(); int getHeight(); int getLength(); + Vec3i getOffset(); + } diff --git a/main/src/main/java/org/minerift/ether/schematic/types/SpongeSchematic.java b/main/src/main/java/org/minerift/ether/schematic/types/SpongeSchematic.java index c38ebcb..f14b794 100644 --- a/main/src/main/java/org/minerift/ether/schematic/types/SpongeSchematic.java +++ b/main/src/main/java/org/minerift/ether/schematic/types/SpongeSchematic.java @@ -1,5 +1,6 @@ package org.minerift.ether.schematic.types; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.pasters.SpongeSchematicPaster; import org.minerift.ether.util.math.Vec3i; import org.minerift.ether.world.BiomeArchetype; @@ -40,22 +41,26 @@ public SchematicType getType() { } @Override - public void paste(Vec3i pos, String worldName) { - getType().getPaster(SpongeSchematicPaster.class).paste(this, pos, worldName); + public void paste(Vec3i pos, String worldName, SchematicPasteOptions options) { + getType().getPaster(SpongeSchematicPaster.class).paste(this, pos, worldName, options); } + @Override public int getWidth() { return width; } + @Override public int getHeight() { return height; } + @Override public int getLength() { return length; } + @Override public Vec3i getOffset() { return offset; } diff --git a/main/src/main/java/org/minerift/ether/schematic/types/WorldEditSchematic.java b/main/src/main/java/org/minerift/ether/schematic/types/WorldEditSchematic.java index e5e9a47..d3595f5 100644 --- a/main/src/main/java/org/minerift/ether/schematic/types/WorldEditSchematic.java +++ b/main/src/main/java/org/minerift/ether/schematic/types/WorldEditSchematic.java @@ -1,6 +1,8 @@ package org.minerift.ether.schematic.types; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import org.minerift.ether.schematic.SchematicPasteOptions; import org.minerift.ether.schematic.pasters.WESchematicPaster; import org.minerift.ether.util.math.Vec3i; @@ -22,8 +24,8 @@ public SchematicType getType() { } @Override - public void paste(Vec3i pos, String worldName) { - getType().getPaster(WESchematicPaster.class).paste(this, pos, worldName); + public void paste(Vec3i pos, String worldName, SchematicPasteOptions options) { + getType().getPaster(WESchematicPaster.class).paste(this, pos, worldName, options); } @Override @@ -40,4 +42,10 @@ public int getHeight() { public int getLength() { return clipboard.getDimensions().getZ(); } + + @Override + public Vec3i getOffset() { + final BlockVector3 offset = clipboard.getOrigin(); + return new Vec3i(offset.getX(), offset.getY(), offset.getZ()); + } } diff --git a/main/src/main/java/org/minerift/ether/util/nbt/NBTSectionView.java b/main/src/main/java/org/minerift/ether/util/nbt/NBTSectionView.java index 19ea43d..0eb0daa 100644 --- a/main/src/main/java/org/minerift/ether/util/nbt/NBTSectionView.java +++ b/main/src/main/java/org/minerift/ether/util/nbt/NBTSectionView.java @@ -65,6 +65,7 @@ public Optional readArray(String name, Class valueType, Function clazz) { for(NBTTagType type : values()) { @@ -28,25 +29,20 @@ public static NBTTagType getTagType(Class clazz) { } public static NBTTagType getTagType(int id) { - for(NBTTagType type : values()) { - if(id == type.getId()) { - return type; - } - } - throw new IllegalArgumentException(String.format("Invalid tag id (%d)", id)); + final NBTTagType[] types = NBTTagType.values(); + Preconditions.checkArgument(id < types.length, String.format("Invalid tag id (%d)", id)); + return types[id]; } - private int id; - private String name; - private Class clazz; - NBTTagType(int id, String name, Class clazz) { - this.id = id; + private final String name; + private final Class clazz; + NBTTagType(String name, Class clazz) { this.name = name; this.clazz = clazz; } public int getId() { - return id; + return ordinal(); } public String getName() {