diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index 212b1551f..ba83c5862 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -244,6 +244,7 @@ public static class IrisSettingsGenerator { public boolean preventLeafDecay = true; public boolean useMulticore = false; public boolean offsetNoiseTypes = false; + public boolean useShrinkWrapFix = false; public boolean earlyCustomBlocks = false; } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 5b0ab41cf..76fbd50c4 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.commands; +import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -31,6 +32,7 @@ import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.engine.object.IrisJigsawPiece; import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.context.IrisContext; @@ -45,6 +47,7 @@ import com.volmit.iris.util.format.Form; import com.volmit.iris.util.io.CountingDataInputStream; import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.TectonicPlate; import com.volmit.iris.util.math.M; import com.volmit.iris.util.matter.Matter; @@ -52,11 +55,17 @@ import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.SneakyThrows; import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockOutputStream; import net.jpountz.lz4.LZ4FrameInputStream; import net.jpountz.lz4.LZ4FrameOutputStream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOCase; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang.RandomStringUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; @@ -67,10 +76,13 @@ import java.net.NetworkInterface; import java.nio.file.Files; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -92,6 +104,52 @@ public void Sentry() { Iris.reportError(new Exception("This is a test")); } + @Decree(description = "Dev cmd to fix all the broken objects caused by faulty shrinkwarp") + public void unfuckAllObjects( + @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "null") + IrisDimension type + ) { + if (type == null) { + sender().sendMessage("Type cant be null?"); + return; + } + var ps = PrecisionStopwatch.start(); + IrisData dm = IrisData.get(Iris.instance.getDataFolder("packs", type.getLoadKey())); + + ConcurrentHashMap cache = new ConcurrentHashMap<>(); + dm.getJigsawPieceLoader().streamAll().parallel().forEach(irisJigsawPiece -> { + try { + cache.put(dm.getObjectLoader().load(irisJigsawPiece.getObject()).getLoadFile().getPath(), irisJigsawPiece); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + AtomicInteger size = new AtomicInteger(dm.getObjectLoader().getPossibleKeys().length); + sender().sendMessage("Found " + size + " objects in " + type.getFolderName()); + var gson = new Gson(); + dm.getObjectLoader().streamAll().parallel().forEach(o -> { + try { + o.shrinkwrap(); + if (cache.containsKey(o.getLoadFile().getPath())) { + var piece = cache.get(o.getLoadFile().getPath()); + piece.getConnectors().forEach(connector -> connector.setPosition(o.applyRecentering(connector.getPosition()))); + IO.writeAll(piece.getLoadFile(), new JSONObject(gson.toJson(piece)).toString(4)); + } + o.write(o.getLoadFile()); + size.getAndDecrement(); + Iris.debug("Processed: " + o.getLoadKey() + ", Left: " + size.get()); + } catch (Exception e) { + Iris.info("Failed to process: " + o.getLoadKey()); + e.printStackTrace(); + } + + }); + ps.end(); + sender().sendMessage("Took: " + Form.duration(ps.getMillis())); + sender().sendMessage(size + " Failed"); + } + @Decree(description = "Test") public void mantle(@Param(defaultValue = "false") boolean plate, @Param(defaultValue = "21474836474") String name) throws Throwable { var base = Iris.instance.getDataFile("dump", "pv." + name + ".ttp.lz4b.bin"); diff --git a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java index 2b20693be..5b3fb36a4 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java +++ b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java @@ -65,10 +65,10 @@ public JigsawEditor(Player player, IrisJigsawPiece piece, IrisObject object, Fil editors.get(player).close(); } - editors.put(player, this); if (object == null) { throw new RuntimeException("Object is null! " + piece.getObject()); } + editors.put(player, this); this.object = object; this.player = player; origin = player.getLocation().clone().add(0, 7, 0); diff --git a/core/src/main/java/com/volmit/iris/core/project/IrisProject.java b/core/src/main/java/com/volmit/iris/core/project/IrisProject.java index 7e753f5c0..ec9578b24 100644 --- a/core/src/main/java/com/volmit/iris/core/project/IrisProject.java +++ b/core/src/main/java/com/volmit/iris/core/project/IrisProject.java @@ -225,7 +225,7 @@ public void open(VolmitSender sender, long seed, Consumer onDone) throws sender.sendMessage("Can't find dimension: " + getName()); return; } else if (sender.isPlayer()) { - sender.player().setGameMode(GameMode.SPECTATOR); + J.s(() -> sender.player().setGameMode(GameMode.SPECTATOR)); } try { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java index 2dafd3156..6f4eb14ae 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java @@ -2,6 +2,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.engine.object.*; +import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.nbt.io.NBTUtil; @@ -19,9 +20,7 @@ import org.bukkit.util.FileUtil; import org.bukkit.util.Vector; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; +import java.io.*; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -39,13 +38,14 @@ public static void convertSchematics(VolmitSender sender) { sender.sendMessage("No schematic files to convert found in " + folder.getAbsolutePath()); return; } + var stopwatch = PrecisionStopwatch.start(); ExecutorService executorService = Executors.newFixedThreadPool(1); executorService.submit(() -> { for (File schem : fileList) { try { PrecisionStopwatch p = PrecisionStopwatch.start(); boolean largeObject = false; - NamedTag tag = null; + NamedTag tag; try { tag = NBTUtil.read(schem); } catch (IOException e) { @@ -61,7 +61,7 @@ public static void convertSchematics(VolmitSender sender) { int i = -1; int mv = objW * objH * objD; AtomicInteger v = new AtomicInteger(0); - if (mv > 500_000) { + if (mv > 2_000_000) { largeObject = true; Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); Iris.info(C.GRAY + "- It may take a while"); @@ -82,14 +82,16 @@ public static void convertSchematics(VolmitSender sender) { blockmap.put(blockId, bd); } + boolean isBytes = ((IntTag) compound.get("PaletteMax")).getValue() < 128; ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData"); byte[] originalBlockArray = byteArray.getValue(); - + var din = new DataInputStream(new ByteArrayInputStream(originalBlockArray)); IrisObject object = new IrisObject(objW, objH, objD); for (int h = 0; h < objH; h++) { for (int d = 0; d < objD; d++) { for (int w = 0; w < objW; w++) { - BlockData bd = blockmap.get(Byte.toUnsignedInt(originalBlockArray[v.get()])); + int blockIndex = isBytes ? din.read() & 0xFF : Varint.readUnsignedVarInt(din); + BlockData bd = blockmap.get(blockIndex); if (!bd.getMaterial().isAir()) { object.setUnsigned(w, h, d, bd); } @@ -128,7 +130,8 @@ public static void convertSchematics(VolmitSender sender) { Iris.reportError(e); } } - sender.sendMessage(C.GRAY + "converted: " + fileList.length); + stopwatch.end(); + sender.sendMessage(C.GRAY + "converted: " + fileList.length + " in " + Form.duration(stopwatch.getMillis())); }); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java index fb6a85d4e..f6274518a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.engine.data.cache.AtomicCache; @@ -81,6 +82,7 @@ public class IrisObject extends IrisRegistrant { protected transient IrisLock lock = new IrisLock("Preloadcache"); @Setter protected transient AtomicCache aabb = new AtomicCache<>(); + private Vector3i shrinkOffset; private KMap blocks; private KMap states; @Getter @@ -102,6 +104,7 @@ public IrisObject(int w, int h, int d) { this.w = w; this.h = h; this.d = d; + shrinkOffset = new Vector3i(0, 0, 0); center = new Vector3i(w / 2, h / 2, d / 2); } @@ -498,9 +501,23 @@ public void write(File file, VolmitSender sender) throws IOException { out.close(); } + /** + * Shrinks the structure's bounding box to fit exactly around existing blocks + * and re-centers them around the new center point. + */ public void shrinkwrap() { - BlockVector min = new BlockVector(); - BlockVector max = new BlockVector(); + shrinkwrap(false); + } + + /** + * Shrinks the structure's bounding box to fit exactly around existing blocks + * and re-centers them around the new center point. + * + * @param legacy If true, preserves old behavior where blocks are not recentered + */ + public void shrinkwrap(boolean legacy) { + BlockVector min = new BlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + BlockVector max = new BlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); for (BlockVector i : getBlocks().keySet()) { min.setX(Math.min(min.getX(), i.getX())); @@ -514,9 +531,46 @@ public void shrinkwrap() { w = max.getBlockX() - min.getBlockX() + 1; h = max.getBlockY() - min.getBlockY() + 1; d = max.getBlockZ() - min.getBlockZ() + 1; + + if (!legacy || IrisSettings.get().getGenerator().useShrinkWrapFix) { + KMap tb = new KMap<>(); + KMap tt = new KMap<>(); + + int dx = -Math.floorDiv(w, 2) - min.getBlockX(); + int dy = -Math.floorDiv(h, 2) - min.getBlockY(); + int dz = -Math.floorDiv(d, 2) - min.getBlockZ(); + shrinkOffset = new Vector3i(dx, dy, dz); + + for (var entry : blocks.entrySet()) { + tb.put(applyRecentering(entry.getKey()), entry.getValue()); + } + for (var entry : states.entrySet()) { + tt.put(applyRecentering(entry.getKey()), entry.getValue()); + } + + blocks = tb; + states = tt; + } + center = new Vector3i(w / 2, h / 2, d / 2); } + public Vector3i applyRecentering(Vector3i vec) { + return new Vector3i( + vec.getBlockX() + shrinkOffset.getBlockX(), + vec.getBlockY() + shrinkOffset.getBlockY(), + vec.getBlockZ() + shrinkOffset.getBlockZ() + ); + } + + public IrisPosition applyRecentering(IrisPosition pos) { + return new IrisPosition( + pos.getX() + shrinkOffset.getBlockX(), + pos.getY() + shrinkOffset.getBlockY(), + pos.getZ() + shrinkOffset.getBlockZ() + ); + } + public void clean() { KMap d = new KMap<>(); @@ -1011,6 +1065,8 @@ public int place(int x, int yv, int z, IObjectPlacer oplacer, IrisObjectPlacemen boolean place = !data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR) && !wouldReplace; if (data instanceof IrisCustomData || place) { + + placer.set(xx, yy, zz, data); if (tile != null) { placer.setTile(xx, yy, zz, tile); @@ -1152,7 +1208,7 @@ public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) { blocks = d; states = dx; - shrinkwrap(); + shrinkwrap(true); } public void place(Location at) { diff --git a/core/src/main/java/com/volmit/iris/util/data/B.java b/core/src/main/java/com/volmit/iris/util/data/B.java index 982df8d2d..fa401fa44 100644 --- a/core/src/main/java/com/volmit/iris/util/data/B.java +++ b/core/src/main/java/com/volmit/iris/util/data/B.java @@ -360,6 +360,7 @@ public static boolean canPlaceOnto(Material mat, Material onto) { public static boolean isFoliagePlantable(BlockData d) { return d.getMaterial().equals(Material.GRASS_BLOCK) + || d.getMaterial().equals(Material.MOSS_BLOCK) || d.getMaterial().equals(Material.ROOTED_DIRT) || d.getMaterial().equals(Material.DIRT) || d.getMaterial().equals(Material.COARSE_DIRT) @@ -368,6 +369,7 @@ public static boolean isFoliagePlantable(BlockData d) { public static boolean isFoliagePlantable(Material d) { return d.equals(Material.GRASS_BLOCK) + || d.equals(Material.MOSS_BLOCK) || d.equals(Material.DIRT) || d.equals(TALL_GRASS) || d.equals(TALL_SEAGRASS) diff --git a/core/src/main/java/com/volmit/iris/util/matter/Matter.java b/core/src/main/java/com/volmit/iris/util/matter/Matter.java index 0fe0dca0c..d6233d46c 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/Matter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/Matter.java @@ -81,7 +81,7 @@ static long convert(File folder) { static Matter from(IrisObject object) { object.clean(); - object.shrinkwrap(); + object.shrinkwrap(true); BlockVector min = new BlockVector(); Matter m = new IrisMatter(Math.max(object.getW(), 1) + 1, Math.max(object.getH(), 1) + 1, Math.max(object.getD(), 1) + 1);