Allow over/undersizes schematics to be saved and pasted (#2944)

Co-authored-by: NotMyFault <mc.cache@web.de>
This commit is contained in:
dordsor21 2021-01-03 22:46:53 +00:00 committed by GitHub
parent 01dd2d8097
commit 4c0bc79e49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 226 additions and 182 deletions

View File

@ -38,7 +38,7 @@ public interface BackupManager {
/** /**
* This will perform an automatic backup of the plot iff the plot has an owner, * This will perform an automatic backup of the plot iff the plot has an owner,
* automatic backups are enabled and the plot is not merged. * automatic backups are enabled.
* Otherwise it will complete immediately. * Otherwise it will complete immediately.
* *
* @param player Player that triggered the backup * @param player Player that triggered the backup
@ -60,7 +60,7 @@ public interface BackupManager {
/** /**
* This will perform an automatic backup of the plot iff the plot has an owner, * This will perform an automatic backup of the plot iff the plot has an owner,
* automatic backups are enabled and the plot is not merged. * automatic backups are enabled.
* Otherwise it will complete immediately. * Otherwise it will complete immediately.
* *
* @param player Player that triggered the backup * @param player Player that triggered the backup

View File

@ -77,7 +77,7 @@ import java.util.concurrent.TimeUnit;
} }
@Override @Nonnull public BackupProfile getProfile(@Nonnull final Plot plot) { @Override @Nonnull public BackupProfile getProfile(@Nonnull final Plot plot) {
if (plot.hasOwner() && !plot.isMerged()) { if (plot.hasOwner()) {
try { try {
return backupProfileCache.get(new PlotCacheKey(plot), () -> this.playerBackupProfileFactory.create(plot.getOwnerAbs(), plot)); return backupProfileCache.get(new PlotCacheKey(plot), () -> this.playerBackupProfileFactory.create(plot.getOwnerAbs(), plot));
} catch (ExecutionException e) { } catch (ExecutionException e) {

View File

@ -99,10 +99,6 @@ public class Download extends SubCommand {
player.sendMessage(TranslatableCaption.of("permission.no_plot_perms")); player.sendMessage(TranslatableCaption.of("permission.no_plot_perms"));
return false; return false;
} }
if (plot.isMerged()) {
player.sendMessage(TranslatableCaption.of("web.plot_merged"));
return false;
}
if (plot.getRunning() > 0) { if (plot.getRunning() > 0) {
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer")); player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
return false; return false;

View File

@ -116,10 +116,6 @@ public class SchematicCmd extends SubCommand {
player.sendMessage(TranslatableCaption.of("error.task_in_process")); player.sendMessage(TranslatableCaption.of("error.task_in_process"));
return false; return false;
} }
if (plot.isMerged()) {
player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_merged"));
return false;
}
final String location = args[1]; final String location = args[1];
this.running = true; this.running = true;
TaskManager.runTaskAsync(() -> { TaskManager.runTaskAsync(() -> {
@ -154,7 +150,7 @@ public class SchematicCmd extends SubCommand {
); );
return; return;
} }
this.schematicHandler.paste(schematic, plot, 0, 1, 0, false, player, new RunnableVal<Boolean>() { this.schematicHandler.paste(schematic, plot, 0, plot.getArea().getMinBuildHeight(), 0, false, player, new RunnableVal<Boolean>() {
@Override public void run(Boolean value) { @Override public void run(Boolean value) {
SchematicCmd.this.running = false; SchematicCmd.this.running = false;
if (value) { if (value) {

View File

@ -403,6 +403,10 @@ public class Settings extends Config {
@Comment( @Comment(
"Whether schematic based road generation should paste schematic on top of roads, or from Y=1") "Whether schematic based road generation should paste schematic on top of roads, or from Y=1")
public static boolean PASTE_ROAD_ON_TOP = true; public static boolean PASTE_ROAD_ON_TOP = true;
@Comment({"If schematics that do not match a plot's size should be pasted anyway",
" - This will still only paste a schematic with a plot's bounds.",
" - If a schematic is too big, it will cut off, and if too small, will not full the plot."})
public static boolean PASTE_MISMATCHES = true;
} }

View File

@ -1735,7 +1735,7 @@ public class Plot {
/** /**
* Gets the top loc of a plot (if mega, returns top loc of that mega plot) - If you would like each plot treated as * Gets the top loc of a plot (if mega, returns top loc of that mega plot) - If you would like each plot treated as
* a small plot use getPlotTopLocAbs(...) * a small plot use {@link #getTopAbs()}
* *
* @return Location top of mega plot * @return Location top of mega plot
*/ */
@ -1754,9 +1754,8 @@ public class Plot {
} }
/** /**
* Gets the bottom location for a plot.<br> * Gets the bot loc of a plot (if mega, returns bot loc of that mega plot) - If you would like each plot treated as
* - Does not respect mega plots<br> * a small plot use {@link #getBottomAbs()}
* - Merged plots, only the road will be considered part of the plot<br>
* *
* @return Location bottom of mega plot * @return Location bottom of mega plot
*/ */
@ -2362,6 +2361,8 @@ public class Plot {
bot = PlotId.of(bot.getX() - 1, bot.getX()); bot = PlotId.of(bot.getX() - 1, bot.getX());
} }
} }
int minHeight = getArea().getMinBuildHeight();
int maxHeight = getArea().getMaxBuildHeight();
Location gtopabs = this.area.getPlotAbs(top).getTopAbs(); Location gtopabs = this.area.getPlotAbs(top).getTopAbs();
Location gbotabs = this.area.getPlotAbs(bot).getBottomAbs(); Location gbotabs = this.area.getPlotAbs(bot).getBottomAbs();
visited.addAll(Lists.newArrayList((Iterable<? extends PlotId>) PlotId.PlotRangeIterator.range(bot, top))); visited.addAll(Lists.newArrayList((Iterable<? extends PlotId>) PlotId.PlotRangeIterator.range(bot, top)));
@ -2372,12 +2373,12 @@ public class Plot {
Location toploc = plot.getExtendedTopAbs(); Location toploc = plot.getExtendedTopAbs();
Location botabs = plot.getBottomAbs(); Location botabs = plot.getBottomAbs();
Location topabs = plot.getTopAbs(); Location topabs = plot.getTopAbs();
BlockVector3 pos1 = BlockVector3.at(botabs.getX(), 0, topabs.getZ() + 1); BlockVector3 pos1 = BlockVector3.at(botabs.getX(), minHeight, topabs.getZ() + 1);
BlockVector3 pos2 = BlockVector3.at(topabs.getX(), Plot.MAX_HEIGHT - 1, toploc.getZ()); BlockVector3 pos2 = BlockVector3.at(topabs.getX(), maxHeight, toploc.getZ());
regions.add(new CuboidRegion(pos1, pos2)); regions.add(new CuboidRegion(pos1, pos2));
if (plot.isMerged(Direction.SOUTHEAST)) { if (plot.isMerged(Direction.SOUTHEAST)) {
pos1 = BlockVector3.at(topabs.getX() + 1, 0, topabs.getZ() + 1); pos1 = BlockVector3.at(topabs.getX() + 1, minHeight, topabs.getZ() + 1);
pos2 = BlockVector3.at(toploc.getX(), Plot.MAX_HEIGHT - 1, toploc.getZ()); pos2 = BlockVector3.at(toploc.getX(), maxHeight, toploc.getZ());
regions.add(new CuboidRegion(pos1, pos2)); regions.add(new CuboidRegion(pos1, pos2));
// intersection // intersection
} }
@ -2391,19 +2392,19 @@ public class Plot {
Location toploc = plot.getExtendedTopAbs(); Location toploc = plot.getExtendedTopAbs();
Location botabs = plot.getBottomAbs(); Location botabs = plot.getBottomAbs();
Location topabs = plot.getTopAbs(); Location topabs = plot.getTopAbs();
BlockVector3 pos1 = BlockVector3.at(topabs.getX() + 1, 0, botabs.getZ()); BlockVector3 pos1 = BlockVector3.at(topabs.getX() + 1, minHeight, botabs.getZ());
BlockVector3 pos2 = BlockVector3.at(toploc.getX(), Plot.MAX_HEIGHT - 1, topabs.getZ()); BlockVector3 pos2 = BlockVector3.at(toploc.getX(), maxHeight, topabs.getZ());
regions.add(new CuboidRegion(pos1, pos2)); regions.add(new CuboidRegion(pos1, pos2));
if (plot.isMerged(Direction.SOUTHEAST)) { if (plot.isMerged(Direction.SOUTHEAST)) {
pos1 = BlockVector3.at(topabs.getX() + 1, 0, topabs.getZ() + 1); pos1 = BlockVector3.at(topabs.getX() + 1, minHeight, topabs.getZ() + 1);
pos2 = BlockVector3.at(toploc.getX(), Plot.MAX_HEIGHT - 1, toploc.getZ()); pos2 = BlockVector3.at(toploc.getX(), maxHeight, toploc.getZ());
regions.add(new CuboidRegion(pos1, pos2)); regions.add(new CuboidRegion(pos1, pos2));
// intersection // intersection
} }
} }
} }
BlockVector3 pos1 = BlockVector3.at(gbotabs.getX(), 0, gbotabs.getZ()); BlockVector3 pos1 = BlockVector3.at(gbotabs.getX(), minHeight, gbotabs.getZ());
BlockVector3 pos2 = BlockVector3.at(gtopabs.getX(), Plot.MAX_HEIGHT - 1, gtopabs.getZ()); BlockVector3 pos2 = BlockVector3.at(gtopabs.getX(), maxHeight, gtopabs.getZ());
regions.add(new CuboidRegion(pos1, pos2)); regions.add(new CuboidRegion(pos1, pos2));
} }
return regions; return regions;

View File

@ -25,12 +25,13 @@
*/ */
package com.plotsquared.core.util; package com.plotsquared.core.util;
import com.google.inject.Inject;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared; import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.generator.ClassicPlotWorld; import com.plotsquared.core.generator.ClassicPlotWorld;
import com.plotsquared.core.inject.factory.ProgressSubscriberFactory; import com.plotsquared.core.inject.factory.ProgressSubscriberFactory;
import com.plotsquared.core.location.Location; import com.plotsquared.core.location.Location;
@ -64,8 +65,12 @@ import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionIntersection;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -90,9 +95,6 @@ import java.net.URLConnection;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -114,7 +116,6 @@ public abstract class SchematicHandler {
private static final Logger logger = LoggerFactory.getLogger("P2/" + SchematicHandler.class.getSimpleName()); private static final Logger logger = LoggerFactory.getLogger("P2/" + SchematicHandler.class.getSimpleName());
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
private static final Path TEMP_DIR = Paths.get("TODO-PATH");
public static SchematicHandler manager; public static SchematicHandler manager;
private final WorldUtil worldUtil; private final WorldUtil worldUtil;
private boolean exportAll = false; private boolean exportAll = false;
@ -280,8 +281,6 @@ public abstract class SchematicHandler {
final boolean autoHeight, final boolean autoHeight,
final PlotPlayer<?> actor, final PlotPlayer<?> actor,
final RunnableVal<Boolean> whenDone) { final RunnableVal<Boolean> whenDone) {
TaskManager.runTask(() -> {
if (whenDone != null) { if (whenDone != null) {
whenDone.value = false; whenDone.value = false;
} }
@ -296,8 +295,12 @@ public abstract class SchematicHandler {
final int HEIGHT = dimension.getY(); final int HEIGHT = dimension.getY();
// Validate dimensions // Validate dimensions
CuboidRegion region = plot.getLargestRegion(); CuboidRegion region = plot.getLargestRegion();
if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || ( boolean sizeMismatch =
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT > 256)) { ((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT
> 256);
if (!Settings.Schematics.PASTE_MISMATCHES && sizeMismatch) {
actor.sendMessage(TranslatableCaption.of("schematics.schematic_size_mismatch"));
TaskManager.runTask(whenDone); TaskManager.runTask(whenDone);
return; return;
} }
@ -311,7 +314,7 @@ public abstract class SchematicHandler {
} else { } else {
PlotArea pw = plot.getArea(); PlotArea pw = plot.getArea();
if (pw instanceof ClassicPlotWorld) { if (pw instanceof ClassicPlotWorld) {
y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT; y_offset_actual = yOffset + pw.getMinBuildHeight() + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
} else { } else {
y_offset_actual = yOffset + 1 + this.worldUtil y_offset_actual = yOffset + 1 + this.worldUtil
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1, .getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
@ -322,27 +325,45 @@ public abstract class SchematicHandler {
y_offset_actual = yOffset; y_offset_actual = yOffset;
} }
final Location pos1 = Location final int p1x;
.at(plot.getWorldName(), region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset); final int p1z;
final int p2x;
final int p1x = pos1.getX(); final int p2z;
final int p1z = pos1.getZ(); final Region allRegion;
if (!sizeMismatch || plot.getRegions().size() == 1) {
p1x = region.getMinimumPoint().getX() + xOffset;
p1z = region.getMinimumPoint().getZ() + zOffset;
p2x = region.getMaximumPoint().getX() + xOffset;
p2z = region.getMaximumPoint().getZ() + zOffset;
allRegion = region;
} else {
Location[] corners = plot.getCorners();
p1x = corners[0].getX() + xOffset;
p1z = corners[0].getZ() + zOffset;
p2x = corners[1].getX() + xOffset;
p2z = corners[1].getZ() + zOffset;
allRegion = new RegionIntersection(null, plot.getRegions().toArray(new CuboidRegion[] {}));
}
// Paste schematic here // Paste schematic here
final QueueCoordinator queue = plot.getArea().getQueue(); final QueueCoordinator queue = plot.getArea().getQueue();
for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) {
int yy = y_offset_actual + ry; int yy = y_offset_actual + ry;
if (yy > 255) { if (yy > 255 || yy < 0) {
continue; continue;
} }
for (int rz = 0; rz <= blockArrayClipboard.getDimensions().getZ(); rz++) { for (int rz = 0; rz <= blockArrayClipboard.getDimensions().getZ(); rz++) {
for (int rx = 0; rx < blockArrayClipboard.getDimensions().getX(); rx++) { for (int rx = 0; rx < blockArrayClipboard.getDimensions().getX(); rx++) {
int xx = p1x + rx; int xx = p1x + rx;
int zz = p1z + rz; int zz = p1z + rz;
BaseBlock id = blockArrayClipboard.getFullBlock(BlockVector3.at(rx, ry, rz)); if (sizeMismatch && (xx < p1x || xx > p2x || zz < p1z || zz > p2z || !allRegion.contains(BlockVector3.at(xx, ry, zz)))) {
continue;
}
BlockVector3 loc = BlockVector3.at(rx, ry, rz);
BaseBlock id = blockArrayClipboard.getFullBlock(loc);
queue.setBlock(xx, yy, zz, id); queue.setBlock(xx, yy, zz, id);
if (ry == 0) { if (ry == 0) {
BiomeType biome = blockArrayClipboard.getBiome(BlockVector3.at(rx, ry, rz)); BiomeType biome = blockArrayClipboard.getBiome(loc);
queue.setBiome(xx, yy, zz, biome); queue.setBiome(xx, yy, zz, biome);
} }
} }
@ -351,13 +372,13 @@ public abstract class SchematicHandler {
if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) { if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) {
queue.addProgressSubscriber(subscriberFactory.createWithActor(actor)); queue.addProgressSubscriber(subscriberFactory.createWithActor(actor));
} }
whenDone.value = true;
queue.setCompleteTask(whenDone); queue.setCompleteTask(whenDone);
queue.enqueue(); queue.enqueue();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
TaskManager.runTask(whenDone); TaskManager.runTask(whenDone);
} }
});
} }
public abstract boolean restoreTile(QueueCoordinator queue, CompoundTag tag, int x, int y, int z); public abstract boolean restoreTile(QueueCoordinator queue, CompoundTag tag, int x, int y, int z);
@ -595,13 +616,17 @@ public abstract class SchematicHandler {
@Nonnull final Set<CuboidRegion> regions) { @Nonnull final Set<CuboidRegion> regions) {
CompletableFuture<CompoundTag> completableFuture = new CompletableFuture<>(); CompletableFuture<CompoundTag> completableFuture = new CompletableFuture<>();
TaskManager.runTaskAsync(() -> { TaskManager.runTaskAsync(() -> {
// Main positions World world = this.worldUtil.getWeWorld(worldName);
// All positions
CuboidRegion aabb = RegionUtil.getAxisAlignedBoundingBox(regions); CuboidRegion aabb = RegionUtil.getAxisAlignedBoundingBox(regions);
aabb.setWorld(this.worldUtil.getWeWorld(worldName)); aabb.setWorld(world);
RegionIntersection intersection = new RegionIntersection(new ArrayList<>(regions));
final int width = aabb.getWidth(); final int width = aabb.getWidth();
int height = aabb.getHeight(); int height = aabb.getHeight();
final int length = aabb.getLength(); final int length = aabb.getLength();
final boolean multipleRegions = regions.size() > 1;
Map<String, Tag> schematic = initSchematic((short) width, (short) height, (short) length); Map<String, Tag> schematic = initSchematic((short) width, (short) height, (short) length);
@ -612,21 +637,9 @@ public abstract class SchematicHandler {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length);
ByteArrayOutputStream biomeBuffer = new ByteArrayOutputStream(width * length); ByteArrayOutputStream biomeBuffer = new ByteArrayOutputStream(width * length);
// Queue // Queue
final ArrayDeque<CuboidRegion> queue = new ArrayDeque<>(regions); TaskManager.runTask(() -> {
TaskManager.runTask(new Runnable() { final BlockVector3 minimum = aabb.getMinimumPoint();
@Override public void run() { final BlockVector3 maximum = aabb.getMaximumPoint();
if (queue.isEmpty()) {
TaskManager.runTaskAsync(() -> {
writeSchematicData(schematic, palette, biomePalette, tileEntities, buffer, biomeBuffer);
completableFuture.complete(new CompoundTag(schematic));
});
return;
}
final Runnable regionTask = this;
CuboidRegion region = queue.poll();
final BlockVector3 minimum = region.getMinimumPoint();
final BlockVector3 maximum = region.getMaximumPoint();
final int minX = minimum.getX(); final int minX = minimum.getX();
final int minZ = minimum.getZ(); final int minZ = minimum.getZ();
@ -640,8 +653,11 @@ public abstract class SchematicHandler {
int currentY = minY; int currentY = minY;
int currentX = minX; int currentX = minX;
int currentZ = minZ; int currentZ = minZ;
@Override public void run() {
@Override
public void run() {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
int lastBiome = 0;
for (; currentY <= maxY; currentY++) { for (; currentY <= maxY; currentY++) {
int relativeY = currentY - minY; int relativeY = currentY - minY;
for (; currentZ <= maxZ; currentZ++) { for (; currentZ <= maxZ; currentZ++) {
@ -656,6 +672,34 @@ public abstract class SchematicHandler {
} }
int relativeX = currentX - minX; int relativeX = currentX - minX;
BlockVector3 point = BlockVector3.at(currentX, currentY, currentZ); BlockVector3 point = BlockVector3.at(currentX, currentY, currentZ);
if (multipleRegions && !intersection.contains(point)) {
String blockKey = BlockTypes.AIR.getDefaultState().getAsString();
int blockId;
if (palette.containsKey(blockKey)) {
blockId = palette.get(blockKey);
} else {
blockId = palette.size();
palette.put(blockKey, palette.size());
}
while ((blockId & -128) != 0) {
buffer.write(blockId & 127 | 128);
blockId >>>= 7;
}
buffer.write(blockId);
if (relativeY > 0) {
continue;
}
// Write the last biome if we're not getting it from the plot;
int biomeId = lastBiome;
while ((biomeId & -128) != 0) {
biomeBuffer.write(biomeId & 127 | 128);
biomeId >>>= 7;
}
biomeBuffer.write(biomeId);
continue;
}
BaseBlock block = aabb.getWorld().getFullBlock(point); BaseBlock block = aabb.getWorld().getFullBlock(point);
if (block.getNbtData() != null) { if (block.getNbtData() != null) {
Map<String, Tag> values = new HashMap<>(); Map<String, Tag> values = new HashMap<>();
@ -701,9 +745,9 @@ public abstract class SchematicHandler {
String biomeStr = biome.getId(); String biomeStr = biome.getId();
int biomeId; int biomeId;
if (biomePalette.containsKey(biomeStr)) { if (biomePalette.containsKey(biomeStr)) {
biomeId = biomePalette.get(biomeStr); biomeId = lastBiome = biomePalette.get(biomeStr);
} else { } else {
biomeId = biomePalette.size(); biomeId = lastBiome = biomePalette.size();
biomePalette.put(biomeStr, biomeId); biomePalette.put(biomeStr, biomeId);
} }
while ((biomeId & -128) != 0) { while ((biomeId & -128) != 0) {
@ -716,11 +760,13 @@ public abstract class SchematicHandler {
} }
currentZ = minZ; // reset manually as not using local variable currentZ = minZ; // reset manually as not using local variable
} }
regionTask.run(); TaskManager.runTaskAsync(() -> {
writeSchematicData(schematic, palette, biomePalette, tileEntities, buffer, biomeBuffer);
completableFuture.complete(new CompoundTag(schematic));
});
} }
}; };
yTask.run(); yTask.run();
}
}); });
}); });
return completableFuture; return completableFuture;

View File

@ -165,6 +165,7 @@
"plotareatype.plot_area_type_partial": "<gray>Vanilla with clusters of plots</gray>", "plotareatype.plot_area_type_partial": "<gray>Vanilla with clusters of plots</gray>",
"schematics.schematic_too_large": "<prefix><red>The plot is too large for this action!</red>", "schematics.schematic_too_large": "<prefix><red>The plot is too large for this action!</red>",
"schematics.schematic_size_mismatch": "<prefix><red>The schematic's size does not match the plot's. If you want to paste anyway, enable schematics.paste-mismatches in settings.yml</red>",
"schematics.schematic_invalid": "<prefix><red>That is not a valid schematic. Reason: </red><gray><reason>.</gray>", "schematics.schematic_invalid": "<prefix><red>That is not a valid schematic. Reason: </red><gray><reason>.</gray>",
"schematics.schematic_invalid_named": "<prefix><red><schemname> is not a valid schematic. Reason: </red><gray><reason>.</gray>", "schematics.schematic_invalid_named": "<prefix><red><schemname> is not a valid schematic. Reason: </red><gray><reason>.</gray>",
"schematics.schematic_paste_merged": "<prefix><red>Schematics cannot be pasted onto merged plots. Please unmerge the plot before performing the paste.</red>", "schematics.schematic_paste_merged": "<prefix><red>Schematics cannot be pasted onto merged plots. Please unmerge the plot before performing the paste.</red>",