implement dynamic tile entities

This commit is contained in:
Julian Krings 2024-08-14 20:02:08 +02:00
parent b6457e47e6
commit f58078e8a0
29 changed files with 876 additions and 804 deletions

View File

@ -117,10 +117,8 @@ public class CommandObject implements DecreeExecutor {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
BlockState state = world.getBlockAt(xx, yy, zz).getState(); tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
tile.toBukkitTry(state);
state.update();
} }
@Override @Override

View File

@ -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.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Chunk; import org.bukkit.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -41,13 +38,16 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.awt.*; import java.awt.*;
import java.awt.Color;
public interface INMSBinding { public interface INMSBinding {
boolean hasTile(Material material);
boolean hasTile(Location l); boolean hasTile(Location l);
CompoundTag serializeTile(Location location); KMap<String, Object> serializeTile(Location location);
void deserializeTile(CompoundTag s, Location newPosition); void deserializeTile(KMap<String, Object> s, Location newPosition);
CompoundTag serializeEntity(Entity location); CompoundTag serializeEntity(Entity location);

View File

@ -32,6 +32,7 @@ import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
@ -61,16 +62,27 @@ public class NMSBinding1X implements INMSBinding {
return false; return false;
} }
@Override
public boolean hasTile(Material material) {
return false;
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return false; return false;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { public KMap<String, Object> serializeTile(Location location) {
return null; return null;
} }
@Override
public void deserializeTile(KMap<String, Object> s, Location newPosition) {
}
@Override @Override
public void injectBiomesFromMantle(Chunk e, Mantle mantle) { public void injectBiomesFromMantle(Chunk e, Mantle mantle) {
@ -105,11 +117,6 @@ public class NMSBinding1X implements INMSBinding {
return Color.GREEN; return Color.GREEN;
} }
@Override
public void deserializeTile(CompoundTag s, Location newPosition) {
}
@Override @Override
public CompoundTag serializeEntity(Entity location) { public CompoundTag serializeEntity(Entity location) {
return null; return null;

View File

@ -183,7 +183,7 @@ public class TreeSVC implements IrisService {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
} }

View File

@ -59,7 +59,7 @@ import java.util.concurrent.CountDownLatch;
public class WandSVC implements IrisService { public class WandSVC implements IrisService {
private static final Particle CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT"); 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 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 dust;
private static ItemStack wand; private static ItemStack wand;
@ -84,19 +84,6 @@ public class WandSVC implements IrisService {
Cuboid c = new Cuboid(f[0], f[1]); Cuboid c = new Cuboid(f[0], f[1]);
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); 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 it = c.iterator();
var latch = new CountDownLatch(1); var latch = new CountDownLatch(1);
new SR() { new SR() {

View File

@ -53,7 +53,6 @@ import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterCavern; import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.matter.MatterUpdate; 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.matter.slices.container.JigsawPieceContainer;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst; 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().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(); int betterY = y + getWorld().minHeight();
if (!TileData.setTileState(c.getBlock(x, betterY, z), tile.getData())) 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.getData().getTileId()); 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(() -> { getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> {

View File

@ -79,7 +79,7 @@ public class HeightmapObjectPlacer implements IObjectPlacer {
return oplacer.isDebugSmartBore(); return oplacer.isDebugSmartBore();
} }
public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData<? extends TileState> param1TileData) { public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData param1TileData) {
oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData); oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData);
} }

View File

@ -119,9 +119,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
BlockState state = world.getBlockAt(xx, yy + world.getMinHeight(), zz).getState(); tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz));
tile.toBukkitTry(state);
state.update();
} }
} }

View File

@ -107,8 +107,8 @@ public interface EngineMantle extends IObjectPlacer {
} }
@Override @Override
default void setTile(int x, int y, int z, TileData<? extends TileState> d) { default void setTile(int x, int y, int z, TileData d) {
getMantle().set(x, y, z, new TileWrapper(d)); getMantle().set(x, y, z, d);
} }
@Override @Override

View File

@ -206,7 +206,7 @@ public class MantleWriter implements IObjectPlacer {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
getEngineMantle().setTile(xx, yy, zz, tile); getEngineMantle().setTile(xx, yy, zz, tile);
} }

View File

@ -44,7 +44,7 @@ public interface IObjectPlacer {
boolean isDebugSmartBore(); boolean isDebugSmartBore();
void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile); void setTile(int xx, int yy, int zz, TileData tile);
Engine getEngine(); Engine getEngine();
} }

View File

@ -21,6 +21,7 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant; 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.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList; 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. //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")) { var type = getBlockData(data).getMaterial();
TileSpawner spawner = new TileSpawner(); if (!INMS.get().hasTile(type))
String name = (String) data.get("entitySpawn"); return null;
if (name.contains(":")) return new TileData().setMaterial(type).setProperties(this.data);
name = name.split(":")[1];
spawner.setEntityType(EntityType.fromName(name));
return spawner;
}
return null;
} }
private String keyify(String dat) { private String keyify(String dat) {

View File

@ -64,11 +64,11 @@ public class IrisMaterialPalette {
return getLayerGenerator(rng, rdata).fit(getBlockData(rdata), x / zoom, y / zoom, z / zoom); return getLayerGenerator(rng, rdata).fit(getBlockData(rdata), x / zoom, y / zoom, z / zoom);
} }
public Optional<TileData<?>> getTile(RNG rng, double x, double y, double z, IrisData rdata) { public Optional<TileData> getTile(RNG rng, double x, double y, double z, IrisData rdata) {
if (getBlockData(rdata).isEmpty()) if (getBlockData(rdata).isEmpty())
return Optional.empty(); 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(); return tile != null ? Optional.of(tile) : Optional.empty();
} }

View File

@ -84,7 +84,7 @@ public class IrisObject extends IrisRegistrant {
@Setter @Setter
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>(); protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
private KMap<BlockVector, BlockData> blocks; private KMap<BlockVector, BlockData> blocks;
private KMap<BlockVector, TileData<? extends TileState>> states; private KMap<BlockVector, TileData> states;
@Getter @Getter
@Setter @Setter
private int w; 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))); d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
} }
KMap<BlockVector, TileData<? extends TileState>> dx = new KMap<>(); KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getBlocks().keySet()) { for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); 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 { } else {
BlockData data = block.getBlockData(); BlockData data = block.getBlockData();
getBlocks().put(v, data); getBlocks().put(v, data);
TileData<? extends TileState> state = TileData.getTileState(block); TileData state = TileData.getTileState(block);
if (state != null) { if (state != null) {
Iris.info("Saved State " + v); Iris.info("Saved State " + v);
getStates().put(v, state); getStates().put(v, state);
@ -802,7 +802,7 @@ public class IrisObject extends IrisRegistrant {
for (BlockVector g : getBlocks().keySet()) { for (BlockVector g : getBlocks().keySet()) {
BlockData d; BlockData d;
TileData<? extends TileState> tile = null; TileData tile = null;
try { try {
d = getBlocks().get(g); d = getBlocks().get(g);
@ -842,11 +842,9 @@ public class IrisObject extends IrisRegistrant {
else else
data = newData; data = newData;
if (newData.getMaterial() == Material.SPAWNER) { Optional<TileData> t = j.getReplace().getTile(rng, x, y, z, rdata);
Optional<TileData<?>> t = j.getReplace().getTile(rng, x, y, z, rdata); if (t.isPresent()) {
if (t.isPresent()) { tile = t.get();
tile = t.get();
}
} }
} }
} }
@ -1044,7 +1042,7 @@ public class IrisObject extends IrisRegistrant {
spinx, spiny, spinz)); spinx, spiny, spinz));
} }
KMap<BlockVector, TileData<? extends TileState>> dx = new KMap<>(); KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getStates().keySet()) { for (BlockVector i : getStates().keySet()) {
dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i)); 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)) { if (getStates().containsKey(i)) {
Iris.info(Objects.requireNonNull(states.get(i)).toString()); Iris.info(Objects.requireNonNull(states.get(i)).toString());
BlockState st = b.getState(); Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
Objects.requireNonNull(getStates().get(i)).toBukkitTry(st);
st.update();
} }
} }
} }
@ -1075,7 +1071,7 @@ public class IrisObject extends IrisRegistrant {
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
if (getStates().containsKey(i)) { 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; return blocks;
} }
public synchronized KMap<BlockVector, TileData<? extends TileState>> getStates() { public synchronized KMap<BlockVector, TileData> getStates() {
return states; return states;
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Banner> {
public static final int id = 2;
private List<Pattern> 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<CompoundTag> listTag = (ListTag<CompoundTag>) 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;
};
}
}

View File

@ -18,9 +18,14 @@
package com.volmit.iris.engine.object; 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.Iris;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.nbt.tag.CompoundTag; 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.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.TileState; import org.bukkit.block.TileState;
@ -29,73 +34,70 @@ import org.bukkit.block.data.BlockData;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@Data
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public interface TileData<T extends TileState> extends Cloneable { @Accessors(chain = true)
public class TileData implements Cloneable {
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
static final KList<TileData<? extends TileState>> registry = setup(); private Material material = null;
private KMap<String, Object> properties = new KMap<>();
static KList<TileData<? extends TileState>> setup() { public static boolean setTileState(Block block, TileData data) {
KList<TileData<? extends TileState>> registry = new KList<>();
registry.add(new TileSign());
registry.add(new TileSpawner());
registry.add(new TileBanner());
return registry;
}
static TileData<? extends TileState> read(DataInputStream s) throws IOException {
try {
int id = s.readShort();
@SuppressWarnings("unchecked") TileData<? extends TileState> 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<? extends TileState> data) {
if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData())) if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData()))
return data.toBukkitTry(block.getState()); return data.toBukkitTry(block);
return false; return false;
} }
static TileData<? extends TileState> getTileState(Block block) { public static TileData getTileState(Block block) {
for (TileData<? extends TileState> i : registry) { if (!INMS.get().hasTile(block.getType()))
BlockData data = block.getBlockData(); return null;
return new TileData().fromBukkit(block);
if (i.isApplicable(data)) {
try {
@SuppressWarnings("unchecked") TileData<? extends TileState> s = i.getClass().getConstructor().newInstance();
s.fromBukkitTry(block.getState());
return s;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
}
return null;
} }
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 { try {
//noinspection unchecked //noinspection unchecked
toBukkit((T) t); toBukkit(block);
t.update(); return true;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
public boolean fromBukkitTry(Block block) {
try {
//noinspection unchecked
fromBukkit(block);
return true; return true;
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
@ -105,24 +107,16 @@ public interface TileData<T extends TileState> extends Cloneable {
return false; return false;
} }
default boolean fromBukkitTry(BlockState t) { public void toBinary(DataOutputStream out) throws IOException {
try { out.writeUTF(material == null ? "" : material.getKey().toString());
//noinspection unchecked out.writeUTF(gson.toJson(properties));
fromBukkit((T) t);
return true;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
} }
CompoundTag toNBT(CompoundTag parent); @Override
public TileData clone() {
void toBinary(DataOutputStream out) throws IOException; var clone = new TileData();
clone.material = material;
void fromBinary(DataInputStream in) throws IOException; clone.properties = properties.copy(); //TODO make a deep copy
return clone;
TileData<T> clone(); }
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Sign> {
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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<CreatureSpawner> {
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<CompoundTag> potentials = (ListTag<CompoundTag>) 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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.util.matter;
import com.volmit.iris.engine.object.TileData;
import lombok.Data;
@Data
public class TileWrapper {
private final TileData<?> data;
}

View File

@ -19,6 +19,7 @@
package com.volmit.iris.util.matter; package com.volmit.iris.util.matter;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.data.Cuboid; import com.volmit.iris.util.data.Cuboid;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -33,8 +34,8 @@ public class WorldMatter {
matter.slice(MatterEntityGroup.class).writeInto(at); matter.slice(MatterEntityGroup.class).writeInto(at);
} }
if (matter.hasSlice(TileWrapper.class)) { if (matter.hasSlice(TileData.class)) {
matter.slice(TileWrapper.class).writeInto(at); matter.slice(TileData.class).writeInto(at);
} }
} }
@ -45,7 +46,7 @@ public class WorldMatter {
s.getHeader().setAuthor(author); s.getHeader().setAuthor(author);
s.slice(BlockData.class).readFrom(c.getLowerNE()); s.slice(BlockData.class).readFrom(c.getLowerNE());
s.slice(MatterEntityGroup.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(); s.trimSlices();
return s; return s;

View File

@ -18,13 +18,9 @@
package com.volmit.iris.util.matter.slices; 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.engine.object.TileData;
import com.volmit.iris.util.data.palette.Palette; import com.volmit.iris.util.data.palette.Palette;
import com.volmit.iris.util.matter.Sliced; 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.Location;
import org.bukkit.World; import org.bukkit.World;
@ -34,47 +30,28 @@ import java.io.IOException;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Sliced @Sliced
public class TileMatter extends RawMatter<TileWrapper> { public class TileMatter extends RawMatter<TileData> {
public TileMatter() { public TileMatter() {
this(1, 1, 1); this(1, 1, 1);
} }
public TileMatter(int width, int height, int depth) { public TileMatter(int width, int height, int depth) {
super(width, height, depth, TileWrapper.class); super(width, height, depth, TileData.class);
registerWriter(World.class, (w, d, x, y, z) -> { registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d));
CompoundTag tag = commonNbt(x, y, z, d.getData().getTileId()); registerReader(World.class, (w, x, y, z) -> TileData.getTileState(w.getBlockAt(new Location(w, x, y, z))));
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);
});
} }
@Override @Override
public Palette<TileWrapper> getGlobalPalette() { public Palette<TileData> getGlobalPalette() {
return null; return null;
} }
public void writeNode(TileWrapper b, DataOutputStream dos) throws IOException { public void writeNode(TileData b, DataOutputStream dos) throws IOException {
b.getData().toBinary(dos); b.toBinary(dos);
} }
public TileWrapper readNode(DataInputStream din) throws IOException { public TileData readNode(DataInputStream din) throws IOException {
return new TileWrapper(TileData.read(din)); return 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;
} }
} }

View File

@ -10,11 +10,17 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; 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.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; 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.CraftServer;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; 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.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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -54,8 +63,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.TagParser;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -127,55 +134,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -10,11 +10,17 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; 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.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; 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.CraftServer;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; 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.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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -55,8 +64,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.TagParser;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -128,55 +135,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -10,11 +10,17 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; 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.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; 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.CraftServer;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; 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.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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -55,8 +64,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.TagParser;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -129,55 +136,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -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.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.mca.palette.*;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.scheduling.J;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.*;
import net.minecraft.nbt.TagParser; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.commands.data.BlockDataAccessor;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Block; 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.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess; 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.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; 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.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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; 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.entity.EntityType;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import sun.misc.Unsafe; import sun.misc.Unsafe;
@ -67,6 +73,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -132,55 +139,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -10,17 +10,25 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; 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.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; 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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -55,8 +64,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; 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.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -130,55 +137,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -10,17 +10,25 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; 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.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; 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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -55,8 +64,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; 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.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -130,55 +137,106 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata();
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); if (tag instanceof CollectionTag<?> collection) {
tag.write(dos); KList<Object> list = new KList<>();
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); for (Object i : collection) {
} catch (Throwable ex) { if (i instanceof net.minecraft.nbt.Tag t)
ex.printStackTrace(); list.add(convertFromTag(t, depth + 1, maxDepth));
else list.add(i);
}
return list;
} }
if (tag instanceof net.minecraft.nbt.CompoundTag compound) {
KMap<String, Object> map = new KMap<>();
return null; for (String key : compound.getAllKeys()) {
} var child = compound.get(key);
if (child == null) continue;
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { var value = convertFromTag(child, depth + 1, maxDepth);
try { if (value == null) continue;
ByteArrayOutputStream boas = new ByteArrayOutputStream(); map.put(key, value);
NBTUtil.write(tag, boas, false); }
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); return map;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
} }
if (tag instanceof NumericTag numeric)
return null; return numeric.getAsNumber();
return tag.getAsString();
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override

View File

@ -1,24 +1,35 @@
package com.volmit.iris.core.nms.v1_20_R4; package com.volmit.iris.core.nms.v1_20_R4;
import java.awt.Color; 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.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.*;
import java.util.List;
import java.util.Optional;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.datapack.DataVersion; 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.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.item.component.CustomData;
import net.minecraft.world.level.LevelReader; 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 net.minecraft.world.level.chunk.status.ChunkStatus;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; 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.CraftChunk;
import org.bukkit.craftbukkit.v1_20_R4.CraftServer; import org.bukkit.craftbukkit.v1_20_R4.CraftServer;
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; 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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; 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.mantle.Mantle;
import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.matter.MatterBiomeInject; 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.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.mca.palette.*;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import it.unimi.dsi.fastutil.objects.Object2IntMap; 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.core.registries.Registries;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.TagParser;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -134,55 +141,109 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(registry());
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); return switch (tag) {
tag.write(dos); case CollectionTag<?> collection -> {
dos.close(); KList<Object> list = new KList<>();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
} catch (Throwable ex) {
ex.printStackTrace();
}
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<String, Object> map = new KMap<>();
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { for (String key : compound.getAllKeys()) {
try { var child = compound.get(key);
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (child == null) continue;
NBTUtil.write(tag, boas, false); var value = convertFromTag(child, depth + 1, maxDepth);
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); if (value == null) continue;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din); map.put(key, value);
din.close(); }
return c; yield map;
} catch (Throwable e) { }
e.printStackTrace(); case NumericTag numeric -> numeric.getAsNumber();
} default -> tag.getAsString();
};
return null;
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override
@ -422,13 +483,13 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public MCAPaletteAccess createPalette() { public MCAPaletteAccess createPalette() {
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> { MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId"); Field cf = IdMapper.class.getDeclaredField("tToId");
Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT"); Field df = IdMapper.class.getDeclaredField("idToT");
Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId"); Field bf = IdMapper.class.getDeclaredField("nextId");
cf.setAccessible(true); cf.setAccessible(true);
df.setAccessible(true); df.setAccessible(true);
bf.setAccessible(true); bf.setAccessible(true);
net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY; IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
int b = bf.getInt(blockData); int b = bf.getInt(blockData);
Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData); Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData);
List<BlockState> d = (List<BlockState>) df.get(blockData); List<BlockState> d = (List<BlockState>) df.get(blockData);

View File

@ -8,18 +8,20 @@ import java.io.DataOutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Iterator; import java.util.*;
import java.util.List;
import java.util.Optional;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.util.scheduling.J;
import net.minecraft.core.component.DataComponents; 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.server.level.ChunkMap;
import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.LevelReader; 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.ChunkStatus;
import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.chunk.status.WorldGenContext;
import org.bukkit.*; 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.CraftChunk;
import org.bukkit.craftbukkit.v1_21_R1.CraftServer; import org.bukkit.craftbukkit.v1_21_R1.CraftServer;
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; 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.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_21_R1.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; 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.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -62,8 +67,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; 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.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -136,55 +139,109 @@ public class NMSBinding implements INMSBinding {
return type.getDeclaredClasses()[ordinal]; return type.getDeclaredClasses()[ordinal];
} }
@Override
public boolean hasTile(Material material) {
return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material));
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { @SuppressWarnings("unchecked")
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); public KMap<String, Object> serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false);
if (e == null) { if (e == null) {
return null; return null;
} }
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(registry());
return convert(tag); return (KMap<String, Object>) convertFromTag(tag, 0, 64);
} }
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { @Contract(value = "null, _, _ -> null", pure = true)
try { private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (tag == null || depth > maxDepth) return null;
DataOutputStream dos = new DataOutputStream(boas); return switch (tag) {
tag.write(dos); case CollectionTag<?> collection -> {
dos.close(); KList<Object> list = new KList<>();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
} catch (Throwable ex) {
ex.printStackTrace();
}
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<String, Object> map = new KMap<>();
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { for (String key : compound.getAllKeys()) {
try { var child = compound.get(key);
ByteArrayOutputStream boas = new ByteArrayOutputStream(); if (child == null) continue;
NBTUtil.write(tag, boas, false); var value = convertFromTag(child, depth + 1, maxDepth);
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); if (value == null) continue;
net.minecraft.nbt.CompoundTag c = NbtIo.read(din); map.put(key, value);
din.close(); }
return c; yield map;
} catch (Throwable e) { }
e.printStackTrace(); case NumericTag numeric -> numeric.getAsNumber();
} default -> tag.getAsString();
};
return null;
} }
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(KMap<String, Object> map, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); 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 @Override