diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java index 137255911..98343d02d 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java @@ -118,10 +118,8 @@ public class CommandObject implements DecreeExecutor { } @Override - public void setTile(int xx, int yy, int zz, TileData tile) { - BlockState state = world.getBlockAt(xx, yy, zz).getState(); - tile.toBukkitTry(state); - state.update(); + public void setTile(int xx, int yy, int zz, TileData tile) { + tile.toBukkitTry(world.getBlockAt(xx, yy, zz)); } @Override diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index de2ca1b8c..b50b14c54 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -31,10 +31,7 @@ import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; +import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; @@ -43,15 +40,17 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; -import java.awt.*; import java.io.File; +import java.awt.Color; public interface INMSBinding { + boolean hasTile(Material material); + boolean hasTile(Location l); - CompoundTag serializeTile(Location location); + KMap serializeTile(Location location); - void deserializeTile(CompoundTag s, Location newPosition); + void deserializeTile(KMap s, Location newPosition); CompoundTag serializeEntity(Entity location); diff --git a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index 13833ad82..de6477aba 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -41,6 +41,7 @@ import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; import net.bytebuddy.matcher.ElementMatchers; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Biome; @@ -72,16 +73,27 @@ public class NMSBinding1X implements INMSBinding { return false; } + @Override + public boolean hasTile(Material material) { + return false; + } + @Override public boolean hasTile(Location l) { return false; } @Override - public CompoundTag serializeTile(Location location) { + public KMap serializeTile(Location location) { return null; } + @Override + public void deserializeTile(KMap s, Location newPosition) { + + } + + @Override public void injectBiomesFromMantle(Chunk e, Mantle mantle) { @@ -131,11 +143,6 @@ public class NMSBinding1X implements INMSBinding { return Color.GREEN; } - @Override - public void deserializeTile(CompoundTag s, Location newPosition) { - - } - @Override public CompoundTag serializeEntity(Entity location) { return null; diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/ModesSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/ModesSFG.java index f34dc9d58..e1eb57931 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/ModesSFG.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/ModesSFG.java @@ -66,16 +66,17 @@ public class ModesSFG { if (IrisSettings.get().getSafeguard().ignoreBootMode) { Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process."); } else { - Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set ignoreBootMode to true if you wish to proceed."); - Iris.info(C.DARK_RED + "Shutting down server in " + C.UNDERLINE + "" + C.DARK_RED + "50 Seconds"); - try { - Thread.sleep(50000); - Bukkit.shutdown(); - } catch (Exception ignored) { + Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed."); + while (true) { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + // no + } } } + Iris.info(""); } - Iris.info(""); } public static void warning() { diff --git a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java index d283c3610..81542f56e 100644 --- a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java @@ -183,7 +183,7 @@ public class TreeSVC implements IrisService { } @Override - public void setTile(int xx, int yy, int zz, TileData tile) { + public void setTile(int xx, int yy, int zz, TileData tile) { } diff --git a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java index 689aca287..b1ba81544 100644 --- a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java @@ -34,6 +34,7 @@ import com.volmit.iris.util.misc.E; import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.SR; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; @@ -52,10 +53,12 @@ import org.bukkit.util.Vector; import java.awt.Color; import java.util.ArrayList; import java.util.Objects; +import java.util.concurrent.CountDownLatch; public class WandSVC implements IrisService { private static final Particle CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT"); private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST"); + private static final int BLOCKS_PER_TICK = Integer.parseInt(System.getProperty("iris.blocks_per_tick", "1000")); private static ItemStack dust; private static ItemStack wand; @@ -79,14 +82,29 @@ public class WandSVC implements IrisService { Location[] f = getCuboid(p); Cuboid c = new Cuboid(f[0], f[1]); IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); - for (Block b : c) { - if (b.getType().equals(Material.AIR)) { - continue; - } - BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector(); - s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b); - } + var it = c.iterator(); + var latch = new CountDownLatch(1); + new SR() { + @Override + public void run() { + for (int i = 0; i < BLOCKS_PER_TICK; i++) { + if (!it.hasNext()) { + cancel(); + latch.countDown(); + return; + } + + var b = it.next(); + if (b.getType().equals(Material.AIR)) + continue; + + BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector(); + s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b); + } + } + }; + latch.await(); return s; } catch (Throwable e) { diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index f27dd5973..1dffbfbfb 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -299,7 +299,7 @@ public class IrisEngine implements Engine { @Override public IrisEngineData getEngineData() { - return engineData.aquire(() -> { + var ret = engineData.aquire(() -> { //TODO: Method this file File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json"); @@ -327,6 +327,11 @@ public class IrisEngine implements Engine { return new IrisEngineData(); }); + if (ret == null) { + Iris.error("Failed to load Engine Data! (How did this happen?)"); + return new IrisEngineData(); + } + return ret; } @Override diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 303ee47f1..977c7e2d5 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -53,7 +53,6 @@ import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterCavern; import com.volmit.iris.util.matter.MatterUpdate; -import com.volmit.iris.util.matter.TileWrapper; import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; @@ -282,10 +281,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat var mc = getMantle().getMantle().getChunk(c.getX(), c.getZ()); mc.raiseFlag(MantleFlag.TILE, () -> J.s(() -> { - mc.iterate(TileWrapper.class, (x, y, z, tile) -> { + mc.iterate(TileData.class, (x, y, z, tile) -> { int betterY = y + getWorld().minHeight(); - if (!TileData.setTileState(c.getBlock(x, betterY, z), tile.getData())) - Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getData().getTileId()); + if (!TileData.setTileState(c.getBlock(x, betterY, z), tile)) + Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getMaterial().name()); }); })); if (mc.isFlagged(MantleFlag.CUSTOM_ACTIVE)) { diff --git a/core/src/main/java/com/volmit/iris/engine/framework/placer/HeightmapObjectPlacer.java b/core/src/main/java/com/volmit/iris/engine/framework/placer/HeightmapObjectPlacer.java index 7e14bd095..987968c19 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/placer/HeightmapObjectPlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/placer/HeightmapObjectPlacer.java @@ -79,7 +79,7 @@ public class HeightmapObjectPlacer implements IObjectPlacer { return oplacer.isDebugSmartBore(); } - public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData param1TileData) { + public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData param1TileData) { oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData); } diff --git a/core/src/main/java/com/volmit/iris/engine/framework/placer/WorldObjectPlacer.java b/core/src/main/java/com/volmit/iris/engine/framework/placer/WorldObjectPlacer.java index edf690cb4..ea0d28ce4 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/placer/WorldObjectPlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/placer/WorldObjectPlacer.java @@ -139,9 +139,7 @@ public class WorldObjectPlacer implements IObjectPlacer { } @Override - public void setTile(int xx, int yy, int zz, TileData tile) { - BlockState state = world.getBlockAt(xx, yy + world.getMinHeight(), zz).getState(); - tile.toBukkitTry(state); - state.update(); + public void setTile(int xx, int yy, int zz, TileData tile) { + tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz)); } } diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index 2c258c81f..f642d5a5b 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -106,8 +106,8 @@ public interface EngineMantle extends IObjectPlacer { } @Override - default void setTile(int x, int y, int z, TileData d) { - getMantle().set(x, y, z, new TileWrapper(d)); + default void setTile(int x, int y, int z, TileData d) { + getMantle().set(x, y, z, d); } @Override diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java index 6dd388941..52c136c21 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java @@ -206,7 +206,7 @@ public class MantleWriter implements IObjectPlacer { } @Override - public void setTile(int xx, int yy, int zz, TileData tile) { + public void setTile(int xx, int yy, int zz, TileData tile) { getEngineMantle().setTile(xx, yy, zz, tile); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java index 251c5db52..b1f02e00e 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java @@ -44,7 +44,7 @@ public interface IObjectPlacer { boolean isDebugSmartBore(); - void setTile(int xx, int yy, int zz, TileData tile); + void setTile(int xx, int yy, int zz, TileData tile); Engine getEngine(); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java index c0d3a8cb0..d54b75b0f 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; @@ -196,17 +197,12 @@ public class IrisBlockData extends IrisRegistrant { }); } - public TileData tryGetTile() { + public TileData tryGetTile(IrisData data) { //TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities. - if (data.containsKey("entitySpawn")) { - TileSpawner spawner = new TileSpawner(); - String name = (String) data.get("entitySpawn"); - if (name.contains(":")) - name = name.split(":")[1]; - spawner.setEntityType(EntityType.fromName(name)); - return spawner; - } - return null; + var type = getBlockData(data).getMaterial(); + if (!INMS.get().hasTile(type)) + return null; + return new TileData().setMaterial(type).setProperties(this.data); } private String keyify(String dat) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisMaterialPalette.java b/core/src/main/java/com/volmit/iris/engine/object/IrisMaterialPalette.java index 7a9dc3d5d..034816457 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisMaterialPalette.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisMaterialPalette.java @@ -64,11 +64,11 @@ public class IrisMaterialPalette { return getLayerGenerator(rng, rdata).fit(getBlockData(rdata), x / zoom, y / zoom, z / zoom); } - public Optional> getTile(RNG rng, double x, double y, double z, IrisData rdata) { + public Optional getTile(RNG rng, double x, double y, double z, IrisData rdata) { if (getBlockData(rdata).isEmpty()) return Optional.empty(); - TileData tile = getBlockData(rdata).size() == 1 ? palette.get(0).tryGetTile() : palette.getRandom(rng).tryGetTile(); + TileData tile = getBlockData(rdata).size() == 1 ? palette.get(0).tryGetTile(rdata) : palette.getRandom(rng).tryGetTile(rdata); return tile != null ? Optional.of(tile) : Optional.empty(); } 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 0b57ed692..50eee93ee 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 @@ -84,7 +84,7 @@ public class IrisObject extends IrisRegistrant { @Setter protected transient AtomicCache aabb = new AtomicCache<>(); private KMap blocks; - private KMap> states; + private KMap states; @Getter @Setter private int w; @@ -434,7 +434,7 @@ public class IrisObject extends IrisRegistrant { d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); } - KMap> dx = new KMap<>(); + KMap dx = new KMap<>(); for (BlockVector i : getBlocks().keySet()) { d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); @@ -476,7 +476,7 @@ public class IrisObject extends IrisRegistrant { } else { BlockData data = block.getBlockData(); getBlocks().put(v, data); - TileData state = TileData.getTileState(block); + TileData state = TileData.getTileState(block); if (state != null) { Iris.info("Saved State " + v); getStates().put(v, state); @@ -802,7 +802,7 @@ public class IrisObject extends IrisRegistrant { for (BlockVector g : getBlocks().keySet()) { BlockData d; - TileData tile = null; + TileData tile = null; try { d = getBlocks().get(g); @@ -842,11 +842,9 @@ public class IrisObject extends IrisRegistrant { else data = newData; - if (newData.getMaterial() == Material.SPAWNER) { - Optional> t = j.getReplace().getTile(rng, x, y, z, rdata); - if (t.isPresent()) { - tile = t.get(); - } + Optional t = j.getReplace().getTile(rng, x, y, z, rdata); + if (t.isPresent()) { + tile = t.get(); } } } @@ -1044,7 +1042,7 @@ public class IrisObject extends IrisRegistrant { spinx, spiny, spinz)); } - KMap> dx = new KMap<>(); + KMap dx = new KMap<>(); for (BlockVector i : getStates().keySet()) { dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i)); @@ -1062,9 +1060,7 @@ public class IrisObject extends IrisRegistrant { if (getStates().containsKey(i)) { Iris.info(Objects.requireNonNull(states.get(i)).toString()); - BlockState st = b.getState(); - Objects.requireNonNull(getStates().get(i)).toBukkitTry(st); - st.update(); + Objects.requireNonNull(getStates().get(i)).toBukkitTry(b); } } } @@ -1075,7 +1071,7 @@ public class IrisObject extends IrisRegistrant { b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); if (getStates().containsKey(i)) { - Objects.requireNonNull(getStates().get(i)).toBukkitTry(b.getState()); + Objects.requireNonNull(getStates().get(i)).toBukkitTry(b); } } } @@ -1084,7 +1080,7 @@ public class IrisObject extends IrisRegistrant { return blocks; } - public synchronized KMap> getStates() { + public synchronized KMap getStates() { return states; } diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileBanner.java b/core/src/main/java/com/volmit/iris/engine/object/TileBanner.java index b18e69c5f..e69de29bb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileBanner.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileBanner.java @@ -1,129 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2024 Arcane Arts (Volmit Software) - * - * 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 . - */ - -package com.volmit.iris.engine.object; - -import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.nbt.tag.ListTag; -import lombok.Data; -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.bukkit.block.Banner; -import org.bukkit.block.banner.Pattern; -import org.bukkit.block.banner.PatternType; -import org.bukkit.block.data.BlockData; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -@Data -public class TileBanner implements TileData { - public static final int id = 2; - - private List patterns = new ArrayList<>(); - private DyeColor baseColor; - - @Override - public String getTileId() { - return "minecraft:banner"; - } - - @Override - public boolean isApplicable(BlockData data) { - return isBanner(data.getMaterial()); - } - - @Override - public void toBukkit(Banner banner) { - banner.setPatterns(patterns); - banner.setBaseColor(baseColor); - } - - @Override - public void fromBukkit(Banner banner) { - this.patterns = banner.getPatterns(); - this.baseColor = banner.getBaseColor(); - } - - @SuppressWarnings("MethodDoesntCallSuperMethod") - @Override - public TileBanner clone() { - TileBanner ts = new TileBanner(); - ts.setBaseColor(getBaseColor()); - ts.setPatterns(getPatterns()); - return ts; - } - - @Override - public void toBinary(DataOutputStream out) throws IOException { - out.writeShort(id); - out.writeByte(baseColor.ordinal()); - out.writeByte(patterns.size()); - for (Pattern p : patterns) { - out.writeByte(p.getColor().ordinal()); - out.writeByte(p.getPattern().ordinal()); - } - } - - @Override - public void fromBinary(DataInputStream in) throws IOException { - baseColor = DyeColor.values()[in.readByte()]; - int listSize = in.readByte(); - patterns = new ArrayList<>(); - - for (int i = 0; i < listSize; i++) { - DyeColor color = DyeColor.values()[in.readByte()]; - PatternType type = PatternType.values()[in.readByte()]; - patterns.add(new Pattern(color, type)); - } - } - - @SuppressWarnings("deprecation") - @Override - public CompoundTag toNBT(CompoundTag tag) { - @SuppressWarnings("unchecked") ListTag listTag = (ListTag) ListTag.createUnchecked(CompoundTag.class); - for (Pattern p : patterns) { - CompoundTag pattern = new CompoundTag(); - pattern.putString("Pattern", p.getPattern().getIdentifier()); - pattern.putByte("Color", p.getColor().getDyeData()); - listTag.add(pattern); - } - tag.put("Patterns", listTag); - return tag; - } - - public boolean isBanner(Material material) { - return switch (material) { - case RED_BANNER, RED_WALL_BANNER, ORANGE_BANNER, ORANGE_WALL_BANNER, - YELLOW_BANNER, YELLOW_WALL_BANNER, LIME_BANNER, - LIME_WALL_BANNER, GREEN_BANNER, GREEN_WALL_BANNER, CYAN_BANNER, - CYAN_WALL_BANNER, LIGHT_BLUE_BANNER, LIGHT_BLUE_WALL_BANNER, - BLUE_BANNER, BLUE_WALL_BANNER, PURPLE_BANNER, - PURPLE_WALL_BANNER, MAGENTA_BANNER, MAGENTA_WALL_BANNER, - PINK_BANNER, PINK_WALL_BANNER, WHITE_BANNER, WHITE_WALL_BANNER, - LIGHT_GRAY_BANNER, LIGHT_GRAY_WALL_BANNER, GRAY_BANNER, - GRAY_WALL_BANNER, - BLACK_BANNER, BLACK_WALL_BANNER, BROWN_BANNER, - BROWN_WALL_BANNER -> true; - default -> false; - }; - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileData.java b/core/src/main/java/com/volmit/iris/engine/object/TileData.java index e0991c5ba..d4119d940 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileData.java @@ -18,9 +18,14 @@ package com.volmit.iris.engine.object; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.nbt.tag.CompoundTag; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.util.collection.KMap; +import lombok.Data; +import lombok.experimental.Accessors; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.TileState; @@ -29,74 +34,70 @@ import org.bukkit.block.data.BlockData; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; +@Data @SuppressWarnings("ALL") -public interface TileData extends Cloneable { +@Accessors(chain = true) +public class TileData implements Cloneable { + private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create(); - static final KList> registry = setup(); + private Material material = null; + private KMap properties = new KMap<>(); - static KList> setup() { - KList> registry = new KList<>(); - - registry.add(new TileSign()); - registry.add(new TileSpawner()); - registry.add(new TileBanner()); - - return registry; - } - - static TileData read(DataInputStream s) throws IOException { - try { - int id = s.readShort(); - @SuppressWarnings("unchecked") TileData d = registry.get(id).getClass().getConstructor().newInstance(); - d.fromBinary(s); - return d; - } catch (InvocationTargetException | InstantiationException | - IllegalAccessException | - NoSuchMethodException e) { - throw new IOException("Failed to create TileData instance due to missing type registrar!"); - } - } - - static boolean setTileState(Block block, TileData data) { + public static boolean setTileState(Block block, TileData data) { if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData())) - return data.toBukkitTry(block.getState()); + return data.toBukkitTry(block); return false; } - static TileData getTileState(Block block) { - for (TileData i : registry) { - BlockData data = block.getBlockData(); - - if (i.isApplicable(data)) { - try { - @SuppressWarnings("unchecked") TileData s = i.getClass().getConstructor().newInstance(); - s.fromBukkitTry(block.getState()); - return s; - } catch (Throwable e) { - Iris.reportError(e); - e.printStackTrace(); - } - } - } - - return null; + public static TileData getTileState(Block block) { + if (!INMS.get().hasTile(block.getType())) + return null; + return new TileData().fromBukkit(block); } - String getTileId(); + public static TileData read(DataInputStream in) throws IOException { + TileData d = new TileData(); + d.material = Material.matchMaterial(in.readUTF()); + d.properties = gson.fromJson(in.readUTF(), KMap.class); + return d; + } - boolean isApplicable(BlockData data); + public boolean isApplicable(BlockData data) { + return material != null && data.getMaterial() == material; + } - void toBukkit(T t); + public void toBukkit(Block block) { + if (material == null) throw new IllegalStateException("Material not set"); + if (block.getType() != material) + throw new IllegalStateException("Material mismatch: " + block.getType() + " vs " + material); + INMS.get().deserializeTile(properties, block.getLocation()); + } - void fromBukkit(T t); + public TileData fromBukkit(Block block) { + if (material != null && block.getType() != material) + throw new IllegalStateException("Material mismatch: " + block.getType() + " vs " + material); + if (material == null) material = block.getType(); + properties = INMS.get().serializeTile(block.getLocation()); + return this; + } - default boolean toBukkitTry(BlockState t) { + public boolean toBukkitTry(Block block) { try { //noinspection unchecked - toBukkit((T) t); - t.update(); + toBukkit(block); + return true; + } catch (Throwable e) { + Iris.reportError(e); + } + + return false; + } + + public boolean fromBukkitTry(Block block) { + try { + //noinspection unchecked + fromBukkit(block); return true; } catch (Throwable e) { Iris.reportError(e); @@ -106,24 +107,16 @@ public interface TileData extends Cloneable { return false; } - default boolean fromBukkitTry(BlockState t) { - try { - //noinspection unchecked - fromBukkit((T) t); - return true; - } catch (Throwable e) { - Iris.reportError(e); - - } - - return false; + public void toBinary(DataOutputStream out) throws IOException { + out.writeUTF(material == null ? "" : material.getKey().toString()); + out.writeUTF(gson.toJson(properties)); } - CompoundTag toNBT(CompoundTag parent); - - void toBinary(DataOutputStream out) throws IOException; - - void fromBinary(DataInputStream in) throws IOException; - - TileData clone(); + @Override + public TileData clone() { + var clone = new TileData(); + clone.material = material; + clone.properties = properties.copy(); //TODO make a deep copy + return clone; + } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileSign.java b/core/src/main/java/com/volmit/iris/engine/object/TileSign.java index 10c192778..e69de29bb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileSign.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileSign.java @@ -1,109 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2024 Arcane Arts (Volmit Software) - * - * 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 . - */ - -package com.volmit.iris.engine.object; - -import com.volmit.iris.util.nbt.tag.CompoundTag; -import lombok.Data; -import org.bukkit.DyeColor; -import org.bukkit.block.Sign; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.type.WallSign; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -@Data -public class TileSign implements TileData { - public static final int id = 0; - private String line1; - private String line2; - private String line3; - private String line4; - private DyeColor dyeColor; - - @Override - public String getTileId() { - return "minecraft:sign"; - } - - @Override - public boolean isApplicable(BlockData data) { - return data instanceof org.bukkit.block.data.type.Sign || data instanceof WallSign; - } - - @Override - public void toBukkit(Sign t) { - t.setLine(0, line1); - t.setLine(1, line2); - t.setLine(2, line3); - t.setLine(3, line4); - t.setColor(dyeColor); - } - - @Override - public void fromBukkit(Sign sign) { - line1 = sign.getLine(0); - line2 = sign.getLine(1); - line3 = sign.getLine(2); - line4 = sign.getLine(3); - dyeColor = sign.getColor(); - } - - @SuppressWarnings("MethodDoesntCallSuperMethod") - @Override - public TileSign clone() { - TileSign ts = new TileSign(); - ts.setDyeColor(getDyeColor()); - ts.setLine1(getLine1()); - ts.setLine2(getLine2()); - ts.setLine3(getLine3()); - ts.setLine4(getLine4()); - return ts; - } - - @Override - public void toBinary(DataOutputStream out) throws IOException { - out.writeShort(id); - out.writeUTF(line1); - out.writeUTF(line2); - out.writeUTF(line3); - out.writeUTF(line4); - out.writeByte(dyeColor.ordinal()); - } - - @Override - public void fromBinary(DataInputStream in) throws IOException { - line1 = in.readUTF(); - line2 = in.readUTF(); - line3 = in.readUTF(); - line4 = in.readUTF(); - dyeColor = DyeColor.values()[in.readByte()]; - } - - @Override - public CompoundTag toNBT(CompoundTag tag) { - tag.putString("Text1", line1); - tag.putString("Text2", line2); - tag.putString("Text3", line3); - tag.putString("Text4", line4); - tag.putString("Color", dyeColor.name().toLowerCase()); - return tag; - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java b/core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java index b113b398a..e69de29bb 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java +++ b/core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java @@ -1,91 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2024 Arcane Arts (Volmit Software) - * - * 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 . - */ - -package com.volmit.iris.engine.object; - -import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.nbt.tag.ListTag; -import lombok.Data; -import org.bukkit.Material; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.EntityType; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -@Data -public class TileSpawner implements TileData { - - public static final int id = 1; - - private EntityType entityType; - - @Override - public String getTileId() { - return "minecraft:mob_spawner"; - } - - @Override - public boolean isApplicable(BlockData data) { - return data.getMaterial() == Material.SPAWNER; - } - - @Override - public void toBukkit(CreatureSpawner t) { - t.setSpawnedType(entityType); - } - - @Override - public void fromBukkit(CreatureSpawner sign) { - entityType = sign.getSpawnedType(); - } - - @SuppressWarnings("MethodDoesntCallSuperMethod") - @Override - public TileSpawner clone() { - TileSpawner ts = new TileSpawner(); - ts.setEntityType(getEntityType()); - return ts; - } - - @Override - public void toBinary(DataOutputStream out) throws IOException { - out.writeShort(id); - out.writeShort(entityType.ordinal()); - } - - @Override - public void fromBinary(DataInputStream in) throws IOException { - entityType = EntityType.values()[in.readShort()]; - } - - @Override - public CompoundTag toNBT(CompoundTag parent) { - @SuppressWarnings("unchecked") ListTag potentials = (ListTag) ListTag.createUnchecked(CompoundTag.class); - CompoundTag t = new CompoundTag(); - CompoundTag ent = new CompoundTag(); - ent.putString("id", entityType.getKey().toString()); - t.put("Entity", ent); - t.putInt("Weight", 1); - potentials.add(t); - parent.put("SpawnPotentials", potentials); - return parent; - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 0bb4b27c2..f6eeb1b5c 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -129,9 +129,9 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @EventHandler public void onWorldInit(WorldInitEvent event) { try { - if (!initialized) { - world.setRawWorldSeed(event.getWorld().getSeed()); - if (world.name().equals(event.getWorld().getName())) { + if (initialized || !world.name().equals(event.getWorld().getName())) + return; + world.setRawWorldSeed(event.getWorld().getSeed()); Engine engine = getEngine(event.getWorld()); if (engine == null) { Iris.warn("Failed to get Engine!"); @@ -152,8 +152,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld())); initialized = true; - } - } + } } catch (Throwable e) { e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java index f3c84fbae..e69de29bb 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java +++ b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java @@ -1,27 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2024 Arcane Arts (Volmit Software) - * - * 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 . - */ - -package com.volmit.iris.util.matter; - -import com.volmit.iris.engine.object.TileData; -import lombok.Data; - -@Data -public class TileWrapper { - private final TileData data; -} diff --git a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java index 7ab3a7b5e..3c2126c1d 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.matter; import com.volmit.iris.Iris; +import com.volmit.iris.engine.object.TileData; import com.volmit.iris.util.data.Cuboid; import org.bukkit.Location; import org.bukkit.block.data.BlockData; @@ -33,8 +34,8 @@ public class WorldMatter { matter.slice(MatterEntityGroup.class).writeInto(at); } - if (matter.hasSlice(TileWrapper.class)) { - matter.slice(TileWrapper.class).writeInto(at); + if (matter.hasSlice(TileData.class)) { + matter.slice(TileData.class).writeInto(at); } } @@ -45,7 +46,7 @@ public class WorldMatter { s.getHeader().setAuthor(author); s.slice(BlockData.class).readFrom(c.getLowerNE()); s.slice(MatterEntityGroup.class).readFrom(c.getLowerNE()); - s.slice(TileWrapper.class).readFrom(c.getLowerNE()); + s.slice(TileData.class).readFrom(c.getLowerNE()); s.trimSlices(); return s; diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java index fb1f427d1..008901590 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java @@ -18,13 +18,9 @@ package com.volmit.iris.util.matter.slices; -import com.volmit.iris.Iris; -import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.object.TileData; import com.volmit.iris.util.data.palette.Palette; import com.volmit.iris.util.matter.Sliced; -import com.volmit.iris.util.matter.TileWrapper; -import com.volmit.iris.util.nbt.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.World; @@ -34,47 +30,28 @@ import java.io.IOException; @SuppressWarnings("rawtypes") @Sliced -public class TileMatter extends RawMatter { +public class TileMatter extends RawMatter { public TileMatter() { this(1, 1, 1); } public TileMatter(int width, int height, int depth) { - super(width, height, depth, TileWrapper.class); - registerWriter(World.class, (w, d, x, y, z) -> { - CompoundTag tag = commonNbt(x, y, z, d.getData().getTileId()); - INMS.get().deserializeTile(d.getData().toNBT(d.getData().toNBT(tag)), new Location(w, x, y, z)); - Iris.warn("S: " + tag); - }); - registerReader(World.class, (w, x, y, z) -> { - TileData d = TileData.getTileState(w.getBlockAt(new Location(w, x, y, z))); - if (d == null) - return null; - return new TileWrapper(d); - }); + super(width, height, depth, TileData.class); + registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d)); + registerReader(World.class, (w, x, y, z) -> TileData.getTileState(w.getBlockAt(new Location(w, x, y, z)))); } @Override - public Palette getGlobalPalette() { + public Palette getGlobalPalette() { return null; } - public void writeNode(TileWrapper b, DataOutputStream dos) throws IOException { - b.getData().toBinary(dos); + public void writeNode(TileData b, DataOutputStream dos) throws IOException { + b.toBinary(dos); } - public TileWrapper readNode(DataInputStream din) throws IOException { - return new TileWrapper(TileData.read(din)); - } - - private CompoundTag commonNbt(int x, int y, int z, String mobId) { - CompoundTag tag = new CompoundTag(); - tag.putInt("x", x); - tag.putInt("y", y); - tag.putInt("z", z); - tag.putBoolean("keepPacked", false); - tag.putString("id", mobId); - return tag; + public TileData readNode(DataInputStream din) throws IOException { + return TileData.read(din); } } diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java index 534249887..c0fc93aa9 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java @@ -35,9 +35,14 @@ import java.util.stream.Collectors; import com.google.gson.JsonNull; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import com.volmit.iris.core.nms.container.IPackRepository; import com.volmit.iris.util.io.IO; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.EntityBlock; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -70,6 +75,8 @@ import org.bukkit.craftbukkit.v1_19_R1.CraftChunk; import org.bukkit.craftbukkit.v1_19_R1.CraftServer; import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; @@ -79,6 +86,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -103,8 +111,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; @@ -178,50 +184,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -236,8 +249,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java index f26dc77c4..776790845 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Map; import java.util.Vector; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -37,7 +38,12 @@ import com.google.gson.JsonNull; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.IPackRepository; import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.EntityBlock; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -70,6 +76,8 @@ import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; import org.bukkit.craftbukkit.v1_19_R2.CraftServer; import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; @@ -79,6 +87,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -104,8 +113,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; @@ -179,50 +186,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -237,8 +251,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java index 80bf8efe4..fca8f5290 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java @@ -35,9 +35,14 @@ import java.util.stream.Collectors; import com.google.gson.JsonNull; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import com.volmit.iris.core.nms.container.IPackRepository; import com.volmit.iris.util.io.IO; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.EntityBlock; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -70,6 +75,8 @@ import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; @@ -79,6 +86,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -104,8 +112,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; @@ -180,50 +186,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -238,8 +251,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index 96c936f72..7bf4acf65 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -48,6 +48,7 @@ import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; +import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; @@ -60,11 +61,12 @@ import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.LevelReader; @@ -74,6 +76,7 @@ import net.minecraft.world.RandomSequences; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; @@ -91,6 +94,8 @@ import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; @@ -100,6 +105,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import sun.misc.Unsafe; @@ -182,50 +188,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -240,8 +253,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index 8e6b49f0f..5333e7bf5 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -35,6 +35,10 @@ import java.util.stream.Collectors; import com.google.gson.JsonNull; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import com.volmit.iris.core.nms.container.IPackRepository; import com.volmit.iris.util.io.IO; import net.minecraft.server.commands.DataPackCommand; @@ -64,12 +68,15 @@ import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.level.block.EntityBlock; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; @@ -81,6 +88,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -106,8 +114,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -183,50 +189,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -241,8 +254,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 11d05f5c7..6ead57bf4 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -24,6 +24,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; @@ -70,13 +71,20 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.EntityBlock; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; @@ -87,6 +95,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -112,8 +121,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -191,50 +198,57 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + if (tag instanceof CollectionTag collection) { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + return list; } + if (tag instanceof net.minecraft.nbt.CompoundTag compound) { + KMap map = new KMap<>(); - return null; - } - - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + return map; } - - return null; + if (tag instanceof NumericTag numeric) + return numeric.getAsNumber(); + return tag.getAsString(); } private RegistryAccess getRegistryAccess(World world) { @@ -249,8 +263,52 @@ public class NMSBinding implements INMSBinding { } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + if (object instanceof Map map) { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof List list) { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + return tag; + } + if (object instanceof Byte number) return ByteTag.valueOf(number); + if (object instanceof Short number) return ShortTag.valueOf(number); + if (object instanceof Integer number) return IntTag.valueOf(number); + if (object instanceof Long number) return LongTag.valueOf(number); + if (object instanceof Float number) return FloatTag.valueOf(number); + if (object instanceof Double number) return DoubleTag.valueOf(number); + if (object instanceof String string) return StringTag.valueOf(string); + return EndTag.INSTANCE; } @Override diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java index 357eea584..d0d1bf862 100644 --- a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java @@ -54,14 +54,32 @@ import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.MappedRegistry; import net.minecraft.core.RegistrationInfo; +import com.volmit.iris.util.nbt.tag.CompoundTag; +import com.volmit.iris.util.scheduling.J; +import net.minecraft.core.*; +import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.GsonHelper; import net.minecraft.world.RandomSequences; +import net.minecraft.nbt.*; +import net.minecraft.nbt.ByteTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.EndTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.LongTag; +import net.minecraft.nbt.ShortTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.commands.data.DataCommands; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; @@ -73,6 +91,9 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R4.CraftChunk; import org.bukkit.craftbukkit.v1_20_R4.CraftServer; import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockType; import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; @@ -83,6 +104,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -97,19 +119,11 @@ import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.matter.MatterBiomeInject; -import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; -import com.volmit.iris.util.nbt.tag.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -184,55 +198,109 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(registry()); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); - } + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + return switch (tag) { + case CollectionTag collection -> { + KList list = new KList<>(); - return null; - } + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + yield list; + } + case net.minecraft.nbt.CompoundTag compound -> { + KMap map = new KMap<>(); - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); - } - - return null; + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + yield map; + } + case NumericTag numeric -> numeric.getAsNumber(); + default -> tag.getAsString(); + }; } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + return switch (object) { + case Map map -> { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + yield tag; + } + case List list -> { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + yield tag; + } + case Byte number -> ByteTag.valueOf(number); + case Short number -> ShortTag.valueOf(number); + case Integer number -> IntTag.valueOf(number); + case Long number -> LongTag.valueOf(number); + case Float number -> FloatTag.valueOf(number); + case Double number -> DoubleTag.valueOf(number); + case String string -> StringTag.valueOf(string); + default -> EndTag.INSTANCE; + }; } @Override @@ -472,13 +540,13 @@ public class NMSBinding implements INMSBinding { @Override public MCAPaletteAccess createPalette() { MCAIdMapper registry = registryCache.aquireNasty(() -> { - Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId"); - Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT"); - Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId"); + Field cf = IdMapper.class.getDeclaredField("tToId"); + Field df = IdMapper.class.getDeclaredField("idToT"); + Field bf = IdMapper.class.getDeclaredField("nextId"); cf.setAccessible(true); df.setAccessible(true); bf.setAccessible(true); - net.minecraft.core.IdMapper blockData = Block.BLOCK_STATE_REGISTRY; + IdMapper blockData = Block.BLOCK_STATE_REGISTRY; int b = bf.getInt(blockData); Object2IntMap c = (Object2IntMap) cf.get(blockData); List d = (List) df.get(blockData); diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 9f2de1446..27d9908c7 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -50,7 +50,11 @@ import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; +import com.volmit.iris.util.scheduling.J; import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.progress.ChunkProgressListener; @@ -59,6 +63,7 @@ import net.minecraft.world.RandomSequences; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.DimensionType; @@ -71,6 +76,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_21_R1.CraftChunk; import org.bukkit.craftbukkit.v1_21_R1.CraftServer; import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_21_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; @@ -81,6 +88,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -102,8 +110,6 @@ import com.volmit.iris.util.nbt.tag.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; @@ -178,55 +184,109 @@ public class NMSBinding implements INMSBinding { return type.getDeclaredClasses()[ordinal]; } + @Override + public boolean hasTile(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + @Override public boolean hasTile(Location l) { return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; } @Override - public CompoundTag serializeTile(Location location) { - BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); if (e == null) { return null; } - net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); - return convert(tag); + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(registry()); + return (KMap) convertFromTag(tag, 0, 64); } - private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(boas); - tag.write(dos); - dos.close(); - return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); - } catch (Throwable ex) { - ex.printStackTrace(); - } + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + return switch (tag) { + case CollectionTag collection -> { + KList list = new KList<>(); - return null; - } + for (Object i : collection) { + if (i instanceof net.minecraft.nbt.Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + yield list; + } + case net.minecraft.nbt.CompoundTag compound -> { + KMap map = new KMap<>(); - private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { - try { - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - NBTUtil.write(tag, boas, false); - DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); - net.minecraft.nbt.CompoundTag c = NbtIo.read(din); - din.close(); - return c; - } catch (Throwable e) { - e.printStackTrace(); - } - - return null; + for (String key : compound.getAllKeys()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + yield map; + } + case NumericTag numeric -> numeric.getAsNumber(); + default -> tag.getAsString(); + }; } @Override - public void deserializeTile(CompoundTag c, Location pos) { - ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(tag.merge(accessor.getData())); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + return switch (object) { + case Map map -> { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + yield tag; + } + case List list -> { + var tag = new net.minecraft.nbt.ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + yield tag; + } + case Byte number -> ByteTag.valueOf(number); + case Short number -> ShortTag.valueOf(number); + case Integer number -> IntTag.valueOf(number); + case Long number -> LongTag.valueOf(number); + case Float number -> FloatTag.valueOf(number); + case Double number -> DoubleTag.valueOf(number); + case String string -> StringTag.valueOf(string); + default -> EndTag.INSTANCE; + }; } @Override