PlotSquared/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java

829 lines
36 KiB
Java
Raw Normal View History

/*
* PlotSquared, a land and world management plugin for Minecraft.
* Copyright (C) IntellectualSites <https://intellectualsites.com>
* Copyright (C) IntellectualSites team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2020-04-15 21:26:54 +02:00
package com.plotsquared.core.util;
2016-02-23 05:11:28 +01:00
2020-10-08 13:27:23 +02:00
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParseException;
import com.google.inject.Inject;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.PlotSquared;
2020-04-16 06:14:33 +02:00
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.generator.ClassicPlotWorld;
2020-09-11 13:59:40 +02:00
import com.plotsquared.core.inject.factory.ProgressSubscriberFactory;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.location.Location;
2020-09-11 13:59:40 +02:00
import com.plotsquared.core.player.PlotPlayer;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.schematic.Schematic;
import com.plotsquared.core.queue.QueueCoordinator;
import com.plotsquared.core.util.net.AbstractDelegateOutputStream;
2020-04-30 12:01:52 +02:00
import com.plotsquared.core.util.task.RunnableVal;
2020-04-15 21:26:54 +02:00
import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.YieldRunnable;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
2019-11-04 20:55:55 +01:00
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
2019-11-04 18:44:23 +01:00
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
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.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
2021-08-18 11:58:18 +02:00
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
2018-08-10 17:01:10 +02:00
2019-11-04 18:44:23 +01:00
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
2019-11-04 18:44:23 +01:00
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
2016-02-23 05:11:28 +01:00
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
2019-11-04 18:44:23 +01:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
2019-11-04 18:44:23 +01:00
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
2019-11-04 18:44:23 +01:00
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
2018-12-06 18:01:33 +01:00
import java.util.stream.Collectors;
2016-02-23 05:11:28 +01:00
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public abstract class SchematicHandler {
2018-08-10 17:01:10 +02:00
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SchematicHandler.class.getSimpleName());
2020-10-08 13:27:23 +02:00
private static final Gson GSON = new Gson();
2016-02-23 05:11:28 +01:00
public static SchematicHandler manager;
2020-07-10 22:12:37 +02:00
private final WorldUtil worldUtil;
2020-10-09 17:34:59 +02:00
private final ProgressSubscriberFactory subscriberFactory;
private boolean exportAll = false;
2020-07-10 22:12:37 +02:00
@Inject
public SchematicHandler(final @NonNull WorldUtil worldUtil, @NonNull ProgressSubscriberFactory subscriberFactory) {
2020-07-10 22:12:37 +02:00
this.worldUtil = worldUtil;
2020-10-09 17:34:59 +02:00
this.subscriberFactory = subscriberFactory;
2020-07-10 22:12:37 +02:00
}
@Deprecated(forRemoval = true, since = "6.0.0")
public static void upload(
@Nullable UUID uuid,
final @Nullable String file,
final @NonNull String extension,
final @Nullable RunnableVal<OutputStream> writeTask,
final @NonNull RunnableVal<URL> whenDone
) {
if (writeTask == null) {
TaskManager.runTask(whenDone);
return;
}
final String filename;
final String website;
if (uuid == null) {
uuid = UUID.randomUUID();
website = Settings.Web.URL + "upload.php?" + uuid;
filename = "plot." + extension;
} else {
website = Settings.Web.URL + "save.php?" + uuid;
filename = file + '.' + extension;
}
final URL url;
try {
url = new URL(Settings.Web.URL + "?key=" + uuid + "&type=" + extension);
} catch (MalformedURLException e) {
e.printStackTrace();
whenDone.run();
return;
}
TaskManager.runTaskAsync(() -> {
try {
String boundary = Long.toHexString(System.currentTimeMillis());
URLConnection con = new URL(website).openConnection();
con.setDoOutput(true);
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
try (OutputStream output = con.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true)) {
String CRLF = "\r\n";
writer.append("--").append(boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=").append(StandardCharsets.UTF_8.displayName()).append(CRLF);
String param = "value";
writer.append(CRLF).append(param).append(CRLF).flush();
writer.append("--").append(boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"").append(filename)
.append(String.valueOf('"')).append(CRLF);
writer.append("Content-Type: ").append(URLConnection.guessContentTypeFromName(filename)).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF).flush();
writeTask.value = new AbstractDelegateOutputStream(output) {
@Override
public void close() {
} // Don't close
};
writeTask.run();
output.flush();
writer.append(CRLF).flush();
writer.append("--").append(boundary).append("--").append(CRLF).flush();
}
String content;
try (Scanner scanner = new Scanner(con.getInputStream()).useDelimiter("\\A")) {
content = scanner.next().trim();
}
if (!content.startsWith("<")) {
}
int responseCode = ((HttpURLConnection) con).getResponseCode();
if (responseCode == 200) {
whenDone.value = url;
}
TaskManager.runTask(whenDone);
} catch (IOException e) {
e.printStackTrace();
TaskManager.runTask(whenDone);
}
});
}
public boolean exportAll(
Collection<Plot> collection,
final File outputDir,
final String namingScheme,
final Runnable ifSuccess
) {
2016-03-29 01:30:55 +02:00
if (this.exportAll) {
2016-02-23 05:11:28 +01:00
return false;
}
if (collection.isEmpty()) {
return false;
}
2016-03-29 01:30:55 +02:00
this.exportAll = true;
2016-03-14 07:18:04 +01:00
final ArrayList<Plot> plots = new ArrayList<>(collection);
2021-01-08 13:59:33 +01:00
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
2016-02-23 05:11:28 +01:00
if (plots.isEmpty()) {
2016-03-29 01:30:55 +02:00
SchematicHandler.this.exportAll = false;
2016-02-23 05:11:28 +01:00
TaskManager.runTask(ifSuccess);
return;
}
2016-03-29 01:30:55 +02:00
Iterator<Plot> i = plots.iterator();
2016-02-23 05:11:28 +01:00
final Plot plot = i.next();
i.remove();
2020-05-19 23:05:36 +02:00
final String owner;
if (plot.hasOwner()) {
owner = plot.getOwnerAbs().toString();
} else {
owner = "unknown";
2016-02-23 05:11:28 +01:00
}
2020-05-19 23:05:36 +02:00
2016-02-23 05:11:28 +01:00
final String name;
if (namingScheme == null) {
2020-07-24 17:24:53 +02:00
name = plot.getId().getX() + ";" + plot.getId().getY() + ',' + plot.getArea() + ',' + owner;
2016-02-23 05:11:28 +01:00
} else {
2020-07-24 17:24:53 +02:00
name = namingScheme.replaceAll("%id%", plot.getId().toString()).replaceAll("%idx%", plot.getId().getX() + "")
.replaceAll("%idy%", plot.getId().getY() + "").replaceAll("%world%", plot.getArea().toString());
2016-02-23 05:11:28 +01:00
}
2016-02-23 05:11:28 +01:00
final String directory;
if (outputDir == null) {
directory = Settings.Paths.SCHEMATICS;
2016-02-23 05:11:28 +01:00
} else {
directory = outputDir.getAbsolutePath();
2016-02-23 05:11:28 +01:00
}
2016-02-23 05:11:28 +01:00
final Runnable THIS = this;
getCompoundTag(plot)
.whenComplete((compoundTag, throwable) -> {
if (compoundTag != null) {
TaskManager.runTaskAsync(() -> {
boolean result = save(compoundTag, directory + File.separator + name + ".schem");
if (!result) {
LOGGER.error("Failed to save {}", plot.getId());
}
TaskManager.runTask(THIS);
});
}
});
2016-02-23 05:11:28 +01:00
}
});
return true;
}
2016-02-23 05:11:28 +01:00
/**
2016-03-29 01:30:55 +02:00
* Paste a schematic.
2016-02-23 05:11:28 +01:00
*
* @param schematic the schematic object to paste
* @param plot plot to paste in
* @param xOffset offset x to paste it from plot origin
* @param yOffset offset y to paste it from plot origin
* @param zOffset offset z to paste it from plot origin
* @param autoHeight if to automatically choose height to paste from
2020-09-11 13:59:40 +02:00
* @param actor the actor pasting the schematic
* @param whenDone task to run when schematic is pasted
2016-02-23 05:11:28 +01:00
*/
public void paste(
final Schematic schematic,
final Plot plot,
final int xOffset,
final int yOffset,
final int zOffset,
final boolean autoHeight,
final PlotPlayer<?> actor,
final RunnableVal<Boolean> whenDone
) {
if (whenDone != null) {
whenDone.value = false;
}
if (schematic == null) {
TaskManager.runTask(whenDone);
return;
}
try {
BlockVector3 dimension = schematic.getClipboard().getDimensions();
final int WIDTH = dimension.getX();
final int LENGTH = dimension.getZ();
final int HEIGHT = dimension.getY();
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
final int worldHeight = plot.getArea().getMaxGenHeight() - plot.getArea().getMinGenHeight() + 1;
// Validate dimensions
CuboidRegion region = plot.getLargestRegion();
boolean sizeMismatch =
((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
> worldHeight);
if (!Settings.Schematics.PASTE_MISMATCHES && sizeMismatch) {
actor.sendMessage(TranslatableCaption.of("schematics.schematic_size_mismatch"));
TaskManager.runTask(whenDone);
return;
}
// block type and data arrays
final Clipboard blockArrayClipboard = schematic.getClipboard();
// Calculate the optimal height to paste the schematic at
final int y_offset_actual;
if (autoHeight) {
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
if (HEIGHT >= worldHeight) {
y_offset_actual = yOffset;
} else {
PlotArea pw = plot.getArea();
if (pw instanceof ClassicPlotWorld) {
y_offset_actual = yOffset + pw.getMinBuildHeight() + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
} else {
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
y_offset_actual = yOffset + pw.getMinBuildHeight() + this.worldUtil
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
region.getMinimumPoint().getZ() + 1
);
}
}
} else {
y_offset_actual = yOffset;
}
2020-07-09 22:28:46 +02:00
final int p1x;
final int p1z;
final int p2x;
final int p2z;
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
final QueueCoordinator queue = plot.getArea().getQueue();
2016-02-23 05:11:28 +01:00
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
for (int ry = 0; ry < Math.min(worldHeight, HEIGHT); ry++) {
int yy = y_offset_actual + ry;
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
if (yy > plot.getArea().getMaxGenHeight() || yy < plot.getArea().getMinGenHeight()) {
continue;
}
for (int rz = 0; rz < blockArrayClipboard.getDimensions().getZ(); rz++) {
for (int rx = 0; rx < blockArrayClipboard.getDimensions().getX(); rx++) {
int xx = p1x + rx;
int zz = p1z + 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);
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
BiomeType biome = blockArrayClipboard.getBiome(loc);
queue.setBiome(xx, yy, zz, biome);
}
}
2016-02-23 05:11:28 +01:00
}
if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) {
queue.addProgressSubscriber(subscriberFactory.createWithActor(actor));
}
Implement extended world heights from Y-64 to Y319 #3473 (#3473) * Begin to implement extended world heights: - Implemented in Bukkit module (and where required in Core module) * Implement extended world heights into core module * Add min gen height to setup, * Default gen/build heights based on minecraft version * Few fixes * Fix up queues * Address comments * Make road schematic stuff slightly more efficient by sharing queues * Minor fixes, don't overlay error many times for the same y * Fix incorrect schematic paste height, undo changes to HybridUtils * Overhall regenallroads method to make it work, make sure BukkitChunkCoordinator can/will finish * Process chunks in order when regenerating all roads * Address comments * Address comments * Ground level//bedrock is at min gen height - Add comment on == rather than <= being used - It's because it's only checking for the bedrock layer being broken if that's disabled * Fix offset for min build height in SchematicHandler * Better javadoc Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com> * Address inclusivity issues for max world height * Javadocs/comments/deprecation * Use world min/max heights if present in QueueCoordinator * Address some deprecations for regions and biome setting * Add a count for chunks we're currently trying to load to not skip chunks at the end of a queue's edit * Use minGenHeight + 1 rather than build height in AugmentedUtils * Create utility method for layer index in GenChunk * Correct height in HybridUtils, also use minGenHeight + 1 * Don't magically split to 128 height in regeneration * Add utility methods for world height in QueueCoordinator * Clean up ClassicPlotManager road creation/removal * Start generation at min gen height if bedrock is disabled * min gen height is set in PlotArea * Add note on schem y normalisation * Improve plot getVolume method readability * Don't overly extend height when regenerating road region * y index utility method in ChunknQueueCoordinator * Layer index utility method in LocalChunk * Use version min/max heights if world not present in QueueCoordinator * Fix min -> max * Don't allow players to modify outside build height when using plot set / schematics. - Also fixes schematic height issues * Remove debug * Address comments * Switch loadingChunks to AtomicInteger to be safe (in case of multi-threaded) * Fix "security" issue that was already present * Ensure sign isn't physicsed Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
2022-03-05 19:03:39 +01:00
if (whenDone != null) {
whenDone.value = true;
queue.setCompleteTask(whenDone);
}
queue.enqueue();
} catch (Exception e) {
e.printStackTrace();
TaskManager.runTask(whenDone);
}
2016-02-23 05:11:28 +01:00
}
2016-03-29 01:30:55 +02:00
2020-07-24 17:24:53 +02:00
public abstract boolean restoreTile(QueueCoordinator queue, CompoundTag tag, int x, int y, int z);
2016-02-23 05:11:28 +01:00
/**
* Get a schematic
*
* @param name to check
* @return schematic if found, else null
* @throws UnsupportedFormatException thrown if schematic format is unsupported
2016-02-23 05:11:28 +01:00
*/
public Schematic getSchematic(String name) throws UnsupportedFormatException {
2020-07-24 17:24:53 +02:00
File parent = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS);
2016-02-23 05:11:28 +01:00
if (!parent.exists()) {
if (!parent.mkdir()) {
throw new RuntimeException("Could not create schematic parent directory");
}
}
if (!name.endsWith(".schem") && !name.endsWith(".schematic")) {
name = name + ".schem";
}
2020-07-24 17:24:53 +02:00
File file = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS + File.separator + name);
if (!file.exists()) {
2020-07-24 17:24:53 +02:00
file = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS + File.separator + name);
}
2016-02-23 05:11:28 +01:00
return getSchematic(file);
}
2018-08-10 17:01:10 +02:00
2018-12-06 18:01:33 +01:00
/**
* Get an immutable collection containing all schematic names
*
* @return Immutable collection with schematic names
*/
public Collection<String> getSchematicNames() {
2020-07-24 17:24:53 +02:00
final File parent = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS);
2018-12-06 18:01:33 +01:00
final List<String> names = new ArrayList<>();
if (parent.exists()) {
2020-07-24 17:24:53 +02:00
final String[] rawNames = parent.list((dir, name) -> name.endsWith(".schematic") || name.endsWith(".schem"));
2018-12-06 18:01:33 +01:00
if (rawNames != null) {
final List<String> transformed = Arrays.stream(rawNames)
//.map(rawName -> rawName.substring(0, rawName.length() - 10))
.collect(Collectors.toList());
2018-12-06 18:01:33 +01:00
names.addAll(transformed);
}
}
return Collections.unmodifiableList(names);
}
2016-02-23 05:11:28 +01:00
/**
* Get a schematic
*
* @param file to check
* @return schematic if found, else null
* @throws UnsupportedFormatException thrown if schematic format is unsupported
2016-02-23 05:11:28 +01:00
*/
public Schematic getSchematic(File file) throws UnsupportedFormatException {
2016-02-23 05:11:28 +01:00
if (!file.exists()) {
return null;
}
ClipboardFormat format = ClipboardFormats.findByFile(file);
if (format != null) {
try (ClipboardReader reader = format.getReader(new FileInputStream(file))) {
2019-11-04 20:55:55 +01:00
Clipboard clip = reader.read();
return new Schematic(clip);
} catch (IOException e) {
e.printStackTrace();
}
} else {
2020-07-24 17:24:53 +02:00
throw new UnsupportedFormatException("This schematic format is not recognised or supported.");
2016-02-23 05:11:28 +01:00
}
return null;
}
2016-03-29 01:30:55 +02:00
public Schematic getSchematic(@NonNull URL url) {
2016-02-23 05:11:28 +01:00
try {
2019-09-08 20:02:45 +02:00
ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
InputStream inputStream = Channels.newInputStream(readableByteChannel);
return getSchematic(inputStream);
2016-02-23 05:11:28 +01:00
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
2016-03-29 01:30:55 +02:00
public Schematic getSchematic(@NonNull InputStream is) {
2016-02-23 05:11:28 +01:00
try {
2020-07-24 17:24:53 +02:00
SpongeSchematicReader schematicReader = new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
2019-11-04 20:55:55 +01:00
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException ignored) {
try {
2020-07-24 17:24:53 +02:00
MCEditSchematicReader schematicReader = new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
2019-11-04 20:55:55 +01:00
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e) {
e.printStackTrace();
}
2016-02-23 05:11:28 +01:00
}
return null;
}
2016-03-29 01:30:55 +02:00
/**
* The legacy web interface is deprecated for removal in favor of Arkitektonika.
*/
@Deprecated(forRemoval = true, since = "TODO")
2016-03-29 01:30:55 +02:00
public List<String> getSaves(UUID uuid) {
2020-10-08 13:27:23 +02:00
String rawJSON;
2016-02-23 05:11:28 +01:00
try {
String website = Settings.Web.URL + "list.php?" + uuid.toString();
2016-03-29 01:30:55 +02:00
URL url = new URL(website);
URLConnection connection = new URL(url.toString()).openConnection();
2016-02-23 05:11:28 +01:00
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
2020-07-24 17:24:53 +02:00
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
rawJSON = reader.lines().collect(Collectors.joining());
2016-02-23 05:11:28 +01:00
}
2020-10-08 13:27:23 +02:00
JsonArray array = GSON.fromJson(rawJSON, JsonArray.class);
2016-03-29 01:30:55 +02:00
List<String> schematics = new ArrayList<>();
2020-10-08 13:27:23 +02:00
for (int i = 0; i < array.size(); i++) {
String schematic = array.get(i).getAsString();
2016-02-23 05:11:28 +01:00
schematics.add(schematic);
}
return schematics;
2020-10-08 13:27:23 +02:00
} catch (JsonParseException | IOException e) {
2016-02-23 05:11:28 +01:00
e.printStackTrace();
}
return null;
}
2018-08-10 17:01:10 +02:00
@Deprecated(forRemoval = true, since = "6.0.0")
public void upload(final CompoundTag tag, UUID uuid, String file, RunnableVal<URL> whenDone) {
2016-02-23 05:11:28 +01:00
if (tag == null) {
TaskManager.runTask(whenDone);
return;
2016-02-23 05:11:28 +01:00
}
upload(uuid, file, "schem", new RunnableVal<>() {
@Override
public void run(OutputStream output) {
2020-07-24 17:24:53 +02:00
try (NBTOutputStream nos = new NBTOutputStream(new GZIPOutputStream(output, true))) {
nos.writeNamedTag("Schematic", tag);
} catch (IOException e1) {
e1.printStackTrace();
}
2016-02-23 05:11:28 +01:00
}
}, whenDone);
2016-02-23 05:11:28 +01:00
}
2018-08-10 17:01:10 +02:00
2016-02-23 05:11:28 +01:00
/**
2016-03-29 01:30:55 +02:00
* Saves a schematic to a file path.
2016-02-23 05:11:28 +01:00
*
* @param tag to save
* @param path to save in
* @return {@code true} if succeeded
2016-02-23 05:11:28 +01:00
*/
2016-03-29 01:30:55 +02:00
public boolean save(CompoundTag tag, String path) {
2016-02-23 05:11:28 +01:00
if (tag == null) {
return false;
}
try {
File tmp = FileUtils.getFile(PlotSquared.platform().getDirectory(), path);
2016-02-23 05:11:28 +01:00
tmp.getParentFile().mkdirs();
2020-07-24 17:24:53 +02:00
try (NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(new FileOutputStream(tmp)))) {
nbtStream.writeNamedTag("Schematic", tag);
2016-02-23 05:11:28 +01:00
}
2016-04-28 22:38:51 +02:00
} catch (FileNotFoundException e) {
e.printStackTrace();
2016-03-29 01:30:55 +02:00
} catch (IOException e) {
2016-02-23 05:11:28 +01:00
e.printStackTrace();
return false;
}
return true;
}
2018-08-10 17:01:10 +02:00
private void writeSchematicData(
final @NonNull Map<String, Tag> schematic,
final @NonNull Map<String, Integer> palette,
final @NonNull Map<String, Integer> biomePalette,
final @NonNull List<CompoundTag> tileEntities,
final @NonNull ByteArrayOutputStream buffer,
final @NonNull ByteArrayOutputStream biomeBuffer
) {
schematic.put("PaletteMax", new IntTag(palette.size()));
Map<String, Tag> paletteTag = new HashMap<>();
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
schematic.put("Palette", new CompoundTag(paletteTag));
schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities));
if (biomeBuffer.size() == 0 || biomePalette.size() == 0) {
return;
}
schematic.put("BiomePaletteMax", new IntTag(biomePalette.size()));
Map<String, Tag> biomePaletteTag = new HashMap<>();
biomePalette.forEach((key, value) -> biomePaletteTag.put(key, new IntTag(value)));
schematic.put("BiomePalette", new CompoundTag(biomePaletteTag));
schematic.put("BiomeData", new ByteArrayTag(biomeBuffer.toByteArray()));
}
@NonNull
private Map<String, Tag> initSchematic(short width, short height, short length) {
Map<String, Tag> schematic = new HashMap<>();
schematic.put("Version", new IntTag(2));
schematic.put(
"DataVersion",
new IntTag(WorldEdit
.getInstance()
.getPlatformManager()
.queryCapability(Capability.WORLD_EDITING)
.getDataVersion())
);
Map<String, Tag> metadata = new HashMap<>();
metadata.put("WEOffsetX", new IntTag(0));
metadata.put("WEOffsetY", new IntTag(0));
metadata.put("WEOffsetZ", new IntTag(0));
schematic.put("Metadata", new CompoundTag(metadata));
schematic.put("Width", new ShortTag(width));
schematic.put("Height", new ShortTag(height));
schematic.put("Length", new ShortTag(length));
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
schematic.put("Offset", new IntArrayTag(new int[]{0, 0, 0,}));
return schematic;
}
/**
* Get the given plot as {@link CompoundTag} matching the Sponge schematic format.
*
* @param plot The plot to get the contents from.
* @return a {@link CompletableFuture} that provides the created {@link CompoundTag}.
*/
public CompletableFuture<CompoundTag> getCompoundTag(final @NonNull Plot plot) {
return getCompoundTag(Objects.requireNonNull(plot.getWorldName()), plot.getRegions());
}
/**
* Get the contents of the given regions in the given world as {@link CompoundTag}
* matching the Sponge schematic format.
*
* @param worldName The world to get the contents from.
* @param regions The regions to get the contents from.
* @return a {@link CompletableFuture} that provides the created {@link CompoundTag}.
*/
public @NonNull CompletableFuture<CompoundTag> getCompoundTag(
final @NonNull String worldName,
final @NonNull Set<CuboidRegion> regions
) {
CompletableFuture<CompoundTag> completableFuture = new CompletableFuture<>();
TaskManager.runTaskAsync(() -> {
World world = this.worldUtil.getWeWorld(worldName);
// All positions
CuboidRegion aabb = RegionUtil.getAxisAlignedBoundingBox(regions);
aabb.setWorld(world);
RegionIntersection intersection = new RegionIntersection(new ArrayList<>(regions));
final int width = aabb.getWidth();
int height = aabb.getHeight();
final int length = aabb.getLength();
final boolean multipleRegions = regions.size() > 1;
Map<String, Tag> schematic = initSchematic((short) width, (short) height, (short) length);
Map<String, Integer> palette = new HashMap<>();
Map<String, Integer> biomePalette = new HashMap<>();
List<CompoundTag> tileEntities = new ArrayList<>();
ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length);
ByteArrayOutputStream biomeBuffer = new ByteArrayOutputStream(width * length);
// Queue
2021-01-08 13:59:33 +01:00
TaskManager.runTaskAsync(() -> {
final BlockVector3 minimum = aabb.getMinimumPoint();
final BlockVector3 maximum = aabb.getMaximumPoint();
final int minX = minimum.getX();
final int minZ = minimum.getZ();
final int minY = minimum.getY();
final int maxX = maximum.getX();
final int maxZ = maximum.getZ();
final int maxY = maximum.getY();
final Runnable yTask = new YieldRunnable() {
int currentY = minY;
int currentX = minX;
int currentZ = minZ;
@Override
public void run() {
long start = System.currentTimeMillis();
int lastBiome = 0;
for (; currentY <= maxY; currentY++) {
int relativeY = currentY - minY;
for (; currentZ <= maxZ; currentZ++) {
int relativeZ = currentZ - minZ;
for (; currentX <= maxX; currentX++) {
// if too much time was spent here, we yield this task
// note that current(X/Y/Z) aren't incremented, so the same position
// as *right now* will be visited again
if (System.currentTimeMillis() - start > 40) {
this.yield();
return;
}
int relativeX = currentX - minX;
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);
if (block.getNbtData() != null) {
Map<String, Tag> values = new HashMap<>();
for (Map.Entry<String, Tag> entry : block.getNbtData().getValue().entrySet()) {
values.put(entry.getKey(), entry.getValue());
}
// Positions are kept in NBT, we don't want that.
values.remove("x");
values.remove("y");
values.remove("z");
values.put("Id", new StringTag(block.getNbtId()));
// Remove 'id' if it exists. We want 'Id'.
// Do this after we get "getNbtId" cos otherwise "getNbtId" doesn't work.
// Dum.
values.remove("id");
values.put("Pos", new IntArrayTag(new int[]{relativeX, relativeY, relativeZ}));
tileEntities.add(new CompoundTag(values));
}
String blockKey = block.toImmutableState().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;
}
BlockVector2 pt = BlockVector2.at(currentX, currentZ);
BiomeType biome = aabb.getWorld().getBiome(pt);
String biomeStr = biome.getId();
int biomeId;
if (biomePalette.containsKey(biomeStr)) {
biomeId = lastBiome = biomePalette.get(biomeStr);
} else {
biomeId = lastBiome = biomePalette.size();
biomePalette.put(biomeStr, biomeId);
}
while ((biomeId & -128) != 0) {
biomeBuffer.write(biomeId & 127 | 128);
biomeId >>>= 7;
}
biomeBuffer.write(biomeId);
}
currentX = minX; // reset manually as not using local variable
}
currentZ = minZ; // reset manually as not using local variable
}
TaskManager.runTaskAsync(() -> {
writeSchematicData(schematic, palette, biomePalette, tileEntities, buffer, biomeBuffer);
completableFuture.complete(new CompoundTag(schematic));
});
}
};
yTask.run();
});
});
return completableFuture;
2016-02-23 05:11:28 +01:00
}
2018-08-10 17:01:10 +02:00
public static class UnsupportedFormatException extends Exception {
2016-02-23 05:11:28 +01:00
/**
* Throw with a message.
2018-08-10 17:01:10 +02:00
*
* @param message the message
2016-02-23 05:11:28 +01:00
*/
public UnsupportedFormatException(String message) {
super(message);
2016-02-23 05:11:28 +01:00
}
/**
* Throw with a message and a cause.
2018-08-10 17:01:10 +02:00
*
* @param message the message
* @param cause the cause
2016-02-23 05:11:28 +01:00
*/
public UnsupportedFormatException(String message, Throwable cause) {
super(message, cause);
2016-02-23 05:11:28 +01:00
}
2016-02-23 05:11:28 +01:00
}
}