mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-25 22:56:45 +01:00
Allow over/undersizes schematics to be saved and pasted (#2944)
Co-authored-by: NotMyFault <mc.cache@web.de>
This commit is contained in:
parent
01dd2d8097
commit
4c0bc79e49
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,84 +281,104 @@ public abstract class SchematicHandler {
|
|||||||
final boolean autoHeight,
|
final boolean autoHeight,
|
||||||
final PlotPlayer<?> actor,
|
final PlotPlayer<?> actor,
|
||||||
final RunnableVal<Boolean> whenDone) {
|
final RunnableVal<Boolean> whenDone) {
|
||||||
|
if (whenDone != null) {
|
||||||
TaskManager.runTask(() -> {
|
whenDone.value = false;
|
||||||
if (whenDone != null) {
|
}
|
||||||
whenDone.value = false;
|
if (schematic == null) {
|
||||||
}
|
TaskManager.runTask(whenDone);
|
||||||
if (schematic == null) {
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
BlockVector3 dimension = schematic.getClipboard().getDimensions();
|
||||||
|
final int WIDTH = dimension.getX();
|
||||||
|
final int LENGTH = dimension.getZ();
|
||||||
|
final int HEIGHT = dimension.getY();
|
||||||
|
// 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
|
||||||
|
> 256);
|
||||||
|
if (!Settings.Schematics.PASTE_MISMATCHES && sizeMismatch) {
|
||||||
|
actor.sendMessage(TranslatableCaption.of("schematics.schematic_size_mismatch"));
|
||||||
TaskManager.runTask(whenDone);
|
TaskManager.runTask(whenDone);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
// block type and data arrays
|
||||||
BlockVector3 dimension = schematic.getClipboard().getDimensions();
|
final Clipboard blockArrayClipboard = schematic.getClipboard();
|
||||||
final int WIDTH = dimension.getX();
|
// Calculate the optimal height to paste the schematic at
|
||||||
final int LENGTH = dimension.getZ();
|
final int y_offset_actual;
|
||||||
final int HEIGHT = dimension.getY();
|
if (autoHeight) {
|
||||||
// Validate dimensions
|
if (HEIGHT >= 256) {
|
||||||
CuboidRegion region = plot.getLargestRegion();
|
|
||||||
if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
|
|
||||||
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT > 256)) {
|
|
||||||
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) {
|
|
||||||
if (HEIGHT >= 256) {
|
|
||||||
y_offset_actual = yOffset;
|
|
||||||
} else {
|
|
||||||
PlotArea pw = plot.getArea();
|
|
||||||
if (pw instanceof ClassicPlotWorld) {
|
|
||||||
y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
|
|
||||||
} else {
|
|
||||||
y_offset_actual = yOffset + 1 + this.worldUtil
|
|
||||||
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
|
|
||||||
region.getMinimumPoint().getZ() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
y_offset_actual = yOffset;
|
y_offset_actual = yOffset;
|
||||||
}
|
} else {
|
||||||
|
PlotArea pw = plot.getArea();
|
||||||
final Location pos1 = Location
|
if (pw instanceof ClassicPlotWorld) {
|
||||||
.at(plot.getWorldName(), region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
|
y_offset_actual = yOffset + pw.getMinBuildHeight() + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
|
||||||
|
} else {
|
||||||
final int p1x = pos1.getX();
|
y_offset_actual = yOffset + 1 + this.worldUtil
|
||||||
final int p1z = pos1.getZ();
|
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
|
||||||
// Paste schematic here
|
region.getMinimumPoint().getZ() + 1);
|
||||||
final QueueCoordinator queue = plot.getArea().getQueue();
|
|
||||||
|
|
||||||
for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) {
|
|
||||||
int yy = y_offset_actual + ry;
|
|
||||||
if (yy > 255) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
for (int rz = 0; rz <= blockArrayClipboard.getDimensions().getZ(); rz++) {
|
}
|
||||||
for (int rx = 0; rx < blockArrayClipboard.getDimensions().getX(); rx++) {
|
} else {
|
||||||
int xx = p1x + rx;
|
y_offset_actual = yOffset;
|
||||||
int zz = p1z + rz;
|
}
|
||||||
BaseBlock id = blockArrayClipboard.getFullBlock(BlockVector3.at(rx, ry, rz));
|
|
||||||
queue.setBlock(xx, yy, zz, id);
|
final int p1x;
|
||||||
if (ry == 0) {
|
final int p1z;
|
||||||
BiomeType biome = blockArrayClipboard.getBiome(BlockVector3.at(rx, ry, rz));
|
final int p2x;
|
||||||
queue.setBiome(xx, yy, zz, biome);
|
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();
|
||||||
|
|
||||||
|
for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) {
|
||||||
|
int yy = y_offset_actual + ry;
|
||||||
|
if (yy > 255 || yy < 0) {
|
||||||
|
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);
|
||||||
|
if (ry == 0) {
|
||||||
|
BiomeType biome = blockArrayClipboard.getBiome(loc);
|
||||||
|
queue.setBiome(xx, yy, zz, biome);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) {
|
|
||||||
queue.addProgressSubscriber(subscriberFactory.createWithActor(actor));
|
|
||||||
}
|
|
||||||
queue.setCompleteTask(whenDone);
|
|
||||||
queue.enqueue();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
TaskManager.runTask(whenDone);
|
|
||||||
}
|
}
|
||||||
});
|
if (actor != null && Settings.QUEUE.NOTIFY_PROGRESS) {
|
||||||
|
queue.addProgressSubscriber(subscriberFactory.createWithActor(actor));
|
||||||
|
}
|
||||||
|
whenDone.value = true;
|
||||||
|
queue.setCompleteTask(whenDone);
|
||||||
|
queue.enqueue();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
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,73 +637,43 @@ 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 int minX = minimum.getX();
|
||||||
final BlockVector3 maximum = region.getMaximumPoint();
|
final int minZ = minimum.getZ();
|
||||||
|
final int minY = minimum.getY();
|
||||||
|
|
||||||
final int minX = minimum.getX();
|
final int maxX = maximum.getX();
|
||||||
final int minZ = minimum.getZ();
|
final int maxZ = maximum.getZ();
|
||||||
final int minY = minimum.getY();
|
final int maxY = maximum.getY();
|
||||||
|
|
||||||
final int maxX = maximum.getX();
|
final Runnable yTask = new YieldRunnable() {
|
||||||
final int maxZ = maximum.getZ();
|
int currentY = minY;
|
||||||
final int maxY = maximum.getY();
|
int currentX = minX;
|
||||||
|
int currentZ = minZ;
|
||||||
|
|
||||||
final Runnable yTask = new YieldRunnable() {
|
@Override
|
||||||
int currentY = minY;
|
public void run() {
|
||||||
int currentX = minX;
|
long start = System.currentTimeMillis();
|
||||||
int currentZ = minZ;
|
int lastBiome = 0;
|
||||||
@Override public void run() {
|
for (; currentY <= maxY; currentY++) {
|
||||||
long start = System.currentTimeMillis();
|
int relativeY = currentY - minY;
|
||||||
for (; currentY <= maxY; currentY++) {
|
for (; currentZ <= maxZ; currentZ++) {
|
||||||
int relativeY = currentY - minY;
|
int relativeZ = currentZ - minZ;
|
||||||
for (; currentZ <= maxZ; currentZ++) {
|
for (; currentX <= maxX; currentX++) {
|
||||||
int relativeZ = currentZ - minZ;
|
// if too much time was spent here, we yield this task
|
||||||
for (; currentX <= maxX; currentX++) {
|
// note that current(X/Y/Z) aren't incremented, so the same position
|
||||||
// if too much time was spent here, we yield this task
|
// as *right now* will be visited again
|
||||||
// note that current(X/Y/Z) aren't incremented, so the same position
|
if (System.currentTimeMillis() - start > 40) {
|
||||||
// as *right now* will be visited again
|
this.yield();
|
||||||
if (System.currentTimeMillis() - start > 40) {
|
return;
|
||||||
this.yield();
|
}
|
||||||
return;
|
int relativeX = currentX - minX;
|
||||||
}
|
BlockVector3 point = BlockVector3.at(currentX, currentY, currentZ);
|
||||||
int relativeX = currentX - minX;
|
if (multipleRegions && !intersection.contains(point)) {
|
||||||
BlockVector3 point = BlockVector3.at(currentX, currentY, currentZ);
|
String blockKey = BlockTypes.AIR.getDefaultState().getAsString();
|
||||||
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;
|
int blockId;
|
||||||
if (palette.containsKey(blockKey)) {
|
if (palette.containsKey(blockKey)) {
|
||||||
blockId = palette.get(blockKey);
|
blockId = palette.get(blockKey);
|
||||||
@ -686,7 +681,6 @@ public abstract class SchematicHandler {
|
|||||||
blockId = palette.size();
|
blockId = palette.size();
|
||||||
palette.put(blockKey, palette.size());
|
palette.put(blockKey, palette.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((blockId & -128) != 0) {
|
while ((blockId & -128) != 0) {
|
||||||
buffer.write(blockId & 127 | 128);
|
buffer.write(blockId & 127 | 128);
|
||||||
blockId >>>= 7;
|
blockId >>>= 7;
|
||||||
@ -696,31 +690,83 @@ public abstract class SchematicHandler {
|
|||||||
if (relativeY > 0) {
|
if (relativeY > 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BlockVector2 pt = BlockVector2.at(currentX, currentZ);
|
|
||||||
BiomeType biome = aabb.getWorld().getBiome(pt);
|
// Write the last biome if we're not getting it from the plot;
|
||||||
String biomeStr = biome.getId();
|
int biomeId = lastBiome;
|
||||||
int biomeId;
|
|
||||||
if (biomePalette.containsKey(biomeStr)) {
|
|
||||||
biomeId = biomePalette.get(biomeStr);
|
|
||||||
} else {
|
|
||||||
biomeId = biomePalette.size();
|
|
||||||
biomePalette.put(biomeStr, biomeId);
|
|
||||||
}
|
|
||||||
while ((biomeId & -128) != 0) {
|
while ((biomeId & -128) != 0) {
|
||||||
biomeBuffer.write(biomeId & 127 | 128);
|
biomeBuffer.write(biomeId & 127 | 128);
|
||||||
biomeId >>>= 7;
|
biomeId >>>= 7;
|
||||||
}
|
}
|
||||||
biomeBuffer.write(biomeId);
|
biomeBuffer.write(biomeId);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
currentX = minX; // reset manually as not using local variable
|
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);
|
||||||
}
|
}
|
||||||
currentZ = minZ; // reset manually as not using local variable
|
currentX = minX; // reset manually as not using local variable
|
||||||
}
|
}
|
||||||
regionTask.run();
|
currentZ = minZ; // reset manually as not using local variable
|
||||||
}
|
}
|
||||||
};
|
TaskManager.runTaskAsync(() -> {
|
||||||
yTask.run();
|
writeSchematicData(schematic, palette, biomePalette, tileEntities, buffer, biomeBuffer);
|
||||||
}
|
completableFuture.complete(new CompoundTag(schematic));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
yTask.run();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return completableFuture;
|
return completableFuture;
|
||||||
|
@ -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>",
|
||||||
|
Loading…
Reference in New Issue
Block a user