From f58078e8a0188748c6eefbb1a9c16bba069ff85e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 14 Aug 2024 20:02:08 +0200 Subject: [PATCH] implement dynamic tile entities --- .../iris/core/commands/CommandObject.java | 6 +- .../com/volmit/iris/core/nms/INMSBinding.java | 12 +- .../iris/core/nms/v1X/NMSBinding1X.java | 19 +- .../com/volmit/iris/core/service/TreeSVC.java | 2 +- .../com/volmit/iris/core/service/WandSVC.java | 15 +- .../volmit/iris/engine/framework/Engine.java | 7 +- .../placer/HeightmapObjectPlacer.java | 2 +- .../framework/placer/WorldObjectPlacer.java | 6 +- .../iris/engine/mantle/EngineMantle.java | 4 +- .../iris/engine/mantle/MantleWriter.java | 2 +- .../iris/engine/object/IObjectPlacer.java | 2 +- .../iris/engine/object/IrisBlockData.java | 16 +- .../engine/object/IrisMaterialPalette.java | 4 +- .../volmit/iris/engine/object/IrisObject.java | 26 ++- .../volmit/iris/engine/object/TileBanner.java | 120 ------------- .../volmit/iris/engine/object/TileData.java | 136 +++++++-------- .../volmit/iris/engine/object/TileSign.java | 109 ------------ .../iris/engine/object/TileSpawner.java | 91 ---------- .../volmit/iris/util/matter/TileWrapper.java | 27 --- .../volmit/iris/util/matter/WorldMatter.java | 7 +- .../iris/util/matter/slices/TileMatter.java | 41 +---- .../iris/core/nms/v1_19_R1/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_19_R2/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_19_R3/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_20_R1/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_20_R2/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_20_R3/NMSBinding.java | 122 +++++++++---- .../iris/core/nms/v1_20_R4/NMSBinding.java | 163 ++++++++++++------ .../iris/core/nms/v1_21_R1/NMSBinding.java | 131 ++++++++++---- 29 files changed, 876 insertions(+), 804 deletions(-) delete mode 100644 core/src/main/java/com/volmit/iris/engine/object/TileBanner.java delete mode 100644 core/src/main/java/com/volmit/iris/engine/object/TileSign.java delete mode 100644 core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java delete mode 100644 core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java 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 830068de7..c5cdd74b6 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 @@ -117,10 +117,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 b2441dfd6..a82f6cbef 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 @@ -28,10 +28,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; @@ -41,13 +38,16 @@ import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import java.awt.*; +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 8ce6caba8..351f82d52 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 @@ -32,6 +32,7 @@ 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.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.entity.Dolphin; @@ -61,16 +62,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) { @@ -105,11 +117,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/service/TreeSVC.java b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java index 72b5593c4..c9ee3c62f 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 84fd9d372..d5a57d77d 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 @@ -59,7 +59,7 @@ 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", "100")); + private static final int BLOCKS_PER_TICK = Integer.parseInt(System.getProperty("iris.blocks_per_tick", "1000")); private static ItemStack dust; private static ItemStack wand; @@ -84,19 +84,6 @@ public class WandSVC implements IrisService { Cuboid c = new Cuboid(f[0], f[1]); IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); - if (Bukkit.isPrimaryThread()) { - 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); - } - - return s; - } - var it = c.iterator(); var latch = new CountDownLatch(1); new SR() { 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 13e1d2b6a..708f04e6d 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; @@ -283,10 +282,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat } getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.s(() -> { - getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, tile) -> { + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), 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()); }); })); getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> { 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 c2c7e0f30..b228eb00f 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 16968eee5..9cec98218 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 @@ -119,9 +119,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 187b41685..4b6e334c6 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 @@ -107,8 +107,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 265e29c56..b43b72f27 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 d14f1e2f6..3a7a89a38 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 b926883a1..722d52ddc 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 b5d899158..830af6457 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 cb85b0d66..bed5dac35 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 deleted file mode 100644 index 5c6b486a2..000000000 --- a/core/src/main/java/com/volmit/iris/engine/object/TileBanner.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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 7dd5722f2..a8d94f7da 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,73 +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); @@ -105,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 deleted file mode 100644 index 119ec3378..000000000 --- a/core/src/main/java/com/volmit/iris/engine/object/TileSign.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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 deleted file mode 100644 index 20a6654d0..000000000 --- a/core/src/main/java/com/volmit/iris/engine/object/TileSpawner.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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/util/matter/TileWrapper.java b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java deleted file mode 100644 index 3758a30ca..000000000 --- a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 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 4b5eb59fe..0061d7f05 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 dee68e1c0..47a1b9e1d 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 058e4046d..5006cf247 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 @@ -10,11 +10,17 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; 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; @@ -22,6 +28,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; @@ -30,6 +38,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -54,8 +63,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; @@ -127,55 +134,106 @@ 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(); } @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 f5f778002..2c2a607b9 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 @@ -10,11 +10,17 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; 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; @@ -22,6 +28,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; @@ -30,6 +38,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -55,8 +64,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; @@ -128,55 +135,106 @@ 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(); } @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 0cbf158bd..54255fc60 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 @@ -10,11 +10,17 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; 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; @@ -22,6 +28,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; @@ -30,6 +38,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -55,8 +64,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; @@ -129,55 +136,106 @@ 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(); } @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 cb8323009..e5c94ee3b 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 @@ -17,20 +17,23 @@ 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 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.nbt.*; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; +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; 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; @@ -44,6 +47,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; @@ -54,6 +59,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.entity.EntityType; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import sun.misc.Unsafe; @@ -67,6 +73,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; @@ -132,55 +139,106 @@ 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(); } @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 9d073f4a7..cffaa4631 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 @@ -10,17 +10,25 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; 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_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; @@ -30,6 +38,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -55,8 +64,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; @@ -130,55 +137,106 @@ 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(); } @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 7334bb040..b87111e71 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 @@ -10,17 +10,25 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; 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; @@ -30,6 +38,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -55,8 +64,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; @@ -130,55 +137,106 @@ 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(); } @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 4b407ef18..38ecf8406 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 @@ -1,24 +1,35 @@ package com.volmit.iris.core.nms.v1_20_R4; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Vector; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +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.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.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.chunk.status.ChunkStatus; import org.bukkit.*; import org.bukkit.block.Biome; @@ -26,6 +37,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; @@ -35,6 +49,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -49,19 +64,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; @@ -134,55 +141,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 @@ -422,13 +483,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 1455b09e1..e9a0dd865 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 @@ -8,18 +8,20 @@ import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Vector; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +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.level.ChunkMap; import net.minecraft.world.item.component.CustomData; 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 org.bukkit.*; @@ -28,6 +30,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; @@ -37,6 +41,7 @@ import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; 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; @@ -62,8 +67,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; @@ -136,55 +139,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