mirror of
https://github.com/tr7zw/Item-NBT-API.git
synced 2026-11-04 16:50:12 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bdddc134a | ||
|
|
733b871c09 | ||
|
|
bc48239fdd | ||
|
|
f182204b2f | ||
|
|
a424ce1e85 | ||
|
|
c881566c14 | ||
|
|
2d6aa142de | ||
|
|
cc1436cd09 | ||
|
|
4506dd37da | ||
|
|
bbc02e1299 | ||
|
|
ca9d5ad140 | ||
|
|
25c82a5ad0 | ||
|
|
17d40445d2 | ||
|
|
47ad3591df | ||
|
|
b3652ecf7d | ||
|
|
46a9116613 | ||
|
|
5776be4a35 |
No files matched your search
@@ -1,13 +1,14 @@
|
||||
# Item-NBT-API
|
||||
|
||||
[](https://modrinth.com/plugin/nbtapi)
|
||||
[](https://discordapp.com/invite/yk4caxM)
|
||||
|
||||
Add custom NBT tags to Items/Tiles/Entities without NMS! Modify NBT and store it in Files, other NBT, or as String in yaml/json/SQL/Redis.
|
||||
[Server Owner/Developer Wiki](https://github.com/tr7zw/Item-NBT-API/wiki)
|
||||
|
||||
### Build/Maven/Sonar Status
|
||||
|
||||
[](https://ci.codemc.org/job/Tr7zw/job/Item-NBT-API/)[](https://sonarcloud.io/summary/overall?id=tr7zw_Item-NBT-API)[](https://sonarcloud.io/summary/overall?id=tr7zw_Item-NBT-API)[](https://sonarcloud.io/summary/overall?id=tr7zw_Item-NBT-API)
|
||||
[](https://discordapp.com/invite/yk4caxM)
|
||||
[](https://www.patreon.com/tr7zw)
|
||||
|
||||
### SpigotMC Status
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
|
||||
@@ -9,6 +9,9 @@ import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.CheckUtil;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -727,4 +730,204 @@ public class NBT {
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads block‑specific data that was previously stored in the chunk's
|
||||
* persistent data container.
|
||||
* <p>
|
||||
* The data is stored inside the {@code blocks} compound of the chunk's
|
||||
* persistent data container, using a key formed as {@code X_Y_Z} where
|
||||
* X, Y, Z are the block's coordinates.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param block the block whose stored data is to be read
|
||||
* @param consumer the consumer that receives a {@link ReadableNBT} view of the data
|
||||
*/
|
||||
public static void readChunkPDC(Block block, Consumer<ReadableNBT> consumer) {
|
||||
processBlockChunkPDC(block, false, nbt -> {
|
||||
consumer.accept(nbt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads block‑specific data from the chunk's persistent data container and
|
||||
* applies a function to produce a result.
|
||||
* <p>
|
||||
* The data is stored inside the {@code blocks} compound of the chunk's
|
||||
* persistent data container, using a key formed as {@code X_Y_Z} where
|
||||
* X, Y, Z are the block's coordinates.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param block the block whose stored data is to be read
|
||||
* @param function the function that processes the {@link ReadableNBT} and
|
||||
* returns a value
|
||||
* @param <T> the type of the returned value
|
||||
* @return the result of the function applied to the data
|
||||
*/
|
||||
public static <T> T readAndGetChunkPDC(Block block, Function<ReadableNBT, T> function) {
|
||||
return processBlockChunkPDC(block, false, function::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies block‑specific data stored in the chunk's persistent data container.
|
||||
* <p>
|
||||
* The data is stored inside the {@code blocks} compound of the chunk's
|
||||
* persistent data container, using a key formed as {@code X_Y_Z} where
|
||||
* X, Y, Z are the block's coordinates.
|
||||
* <p>
|
||||
* <b>Caution:</b> the data remains even if the block is broken, replaced, moved,
|
||||
* or exploded, etc. You should manually remove the data when it is no longer needed.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param block the block whose data is to be modified
|
||||
* @param consumer the consumer that receives the {@link ReadWriteNBT} and
|
||||
* applies modifications
|
||||
*/
|
||||
public static void modifyChunkPDC(Block block, Consumer<ReadWriteNBT> consumer) {
|
||||
processBlockChunkPDC(block, true, nbt -> {
|
||||
consumer.accept(nbt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies block‑specific data in the chunk's persistent data container and
|
||||
* returns a result computed from the modified data.
|
||||
* <p>
|
||||
* The data is stored inside the {@code blocks} compound of the chunk's
|
||||
* persistent data container, using a key formed as {@code X_Y_Z} where
|
||||
* X, Y, Z are the block's coordinates.
|
||||
* <p>
|
||||
* <b>Caution:</b> the data remains even if the block is broken, replaced, moved,
|
||||
* or exploded, etc. You should manually remove the data when it is no longer needed.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param block the block whose data is to be modified
|
||||
* @param function the function that receives the {@link ReadWriteNBT}, modifies
|
||||
* it, and returns a value
|
||||
* @param <T> the type of the returned value
|
||||
* @return the result of the function after modification
|
||||
*/
|
||||
public static <T> T modifyAndGetChunkPDC(Block block, Function<ReadWriteNBT, T> function) {
|
||||
return processBlockChunkPDC(block, true, function::apply);
|
||||
}
|
||||
|
||||
private static <T> T processBlockChunkPDC(Block block, boolean createIfAbsent, Function<NBTCompound, T> action) {
|
||||
CheckUtil.assertAvailable(MinecraftVersion.MC1_16_R3);
|
||||
|
||||
String blockKey = block.getX() + "_" + block.getY() + "_" + block.getZ();
|
||||
|
||||
NBTCompound chunkData = new NBTPersistentDataContainer(block.getChunk().getPersistentDataContainer(), !createIfAbsent);
|
||||
|
||||
NBTCompound blocksData = createIfAbsent
|
||||
? chunkData.getOrCreateCompound("blocks")
|
||||
: chunkData.getCompound("blocks");
|
||||
|
||||
NBTCompound blockData;
|
||||
if (createIfAbsent) {
|
||||
blockData = blocksData.getOrCreateCompound(blockKey);
|
||||
} else {
|
||||
blockData = blocksData == null ? null : blocksData.getCompound(blockKey);
|
||||
if (blockData == null) {
|
||||
blockData = new NBTContainer().setReadOnly(true);
|
||||
}
|
||||
}
|
||||
|
||||
T result = action.apply(blockData);
|
||||
|
||||
if (createIfAbsent) {
|
||||
if (blockData.isEmpty()) {
|
||||
blocksData.removeKey(blockKey);
|
||||
}
|
||||
if (blocksData.isEmpty()) {
|
||||
chunkData.removeKey("blocks");
|
||||
}
|
||||
}
|
||||
|
||||
if (result instanceof ReadableNBT || result instanceof ReadableNBTList<?>) {
|
||||
throw new NbtApiException("Tried returning part of the NBT to outside of the NBT scope!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the chunk's persistent data container.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param chunk the chunk whose persistent data is to be read
|
||||
* @param consumer the consumer that receives a {@link ReadableNBT} view of the data
|
||||
*/
|
||||
public static void readChunkPDC(Chunk chunk, Consumer<ReadableNBT> consumer) {
|
||||
processChunkPDC(chunk, false, nbt -> {
|
||||
consumer.accept(nbt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the chunk's persistent data container and applies a function to produce a result.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param chunk the chunk whose persistent data is to be read
|
||||
* @param function the function that processes the {@link ReadableNBT} and
|
||||
* returns a value
|
||||
* @param <T> the type of the returned value
|
||||
* @return the result of the function applied to the data
|
||||
*/
|
||||
public static <T> T readAndGetChunkPDC(Chunk chunk, Function<ReadableNBT, T> function) {
|
||||
return processChunkPDC(chunk, false, function::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the chunk's persistent data container.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param chunk the chunk whose persistent data is to be modified
|
||||
* @param consumer the consumer that receives the {@link ReadWriteNBT} and
|
||||
* applies modifications
|
||||
*/
|
||||
public static void modifyChunkPDC(Chunk chunk, Consumer<ReadWriteNBT> consumer) {
|
||||
processChunkPDC(chunk, true, nbt -> {
|
||||
consumer.accept(nbt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the chunk's persistent data container and returns a result computed from the modified data.
|
||||
* <p>
|
||||
* <b>Minecraft version:</b> this method requires <b>1.16.4 or newer</b>.
|
||||
*
|
||||
* @param chunk the chunk whose persistent data is to be modified
|
||||
* @param function the function that receives the {@link ReadWriteNBT}, modifies
|
||||
* it, and returns a value
|
||||
* @param <T> the type of the returned value
|
||||
* @return the result of the function after modification
|
||||
*/
|
||||
public static <T> T modifyAndGetChunkPDC(Chunk chunk, Function<ReadWriteNBT, T> function) {
|
||||
return processChunkPDC(chunk, true, function::apply);
|
||||
}
|
||||
|
||||
private static <T> T processChunkPDC(Chunk chunk, boolean createIfAbsent, Function<NBTCompound, T> action) {
|
||||
CheckUtil.assertAvailable(MinecraftVersion.MC1_16_R3);
|
||||
|
||||
NBTCompound chunkData = new NBTPersistentDataContainer(chunk.getPersistentDataContainer(), !createIfAbsent);
|
||||
|
||||
T result = action.apply(chunkData);
|
||||
|
||||
if (result instanceof ReadableNBT || result instanceof ReadableNBTList<?>) {
|
||||
throw new NbtApiException("Tried returning part of the NBT to outside of the NBT scope!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,16 +7,17 @@ import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
/**
|
||||
* Helper class to store NBT data to Block Locations. Use getData() to get the
|
||||
* NBT instance. Important notes:
|
||||
*
|
||||
* <p>
|
||||
* - Non BlockEntities can not have NBT data. This stores the data to the chunk
|
||||
* instead!
|
||||
*
|
||||
* <p>
|
||||
* - The data is really just on the location. If the block gets
|
||||
* broken/changed/exploded/moved etc., the data is still on that location!
|
||||
*
|
||||
* @author tr7zw
|
||||
*
|
||||
* @deprecated use methods in {@link NBT} class to read/modify block's NBT
|
||||
*/
|
||||
@Deprecated
|
||||
public class NBTBlock {
|
||||
|
||||
private final Block block;
|
||||
@@ -30,6 +31,13 @@ public class NBTBlock {
|
||||
nbtChunk = new NBTChunk(block.getChunk());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block NBT data stored within the chunk's PDC.
|
||||
*
|
||||
* @return block NBT data
|
||||
* @deprecated use methods in {@link NBT} class to read/modify block's NBT
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTCompound getData() {
|
||||
return nbtChunk.getPersistentDataContainer().getOrCreateCompound("blocks")
|
||||
.getOrCreateCompound(block.getX() + "_" + block.getY() + "_" + block.getZ());
|
||||
|
||||
@@ -5,6 +5,12 @@ import org.bukkit.Chunk;
|
||||
import de.tr7zw.changeme.nbtapi.utils.CheckUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
|
||||
/**
|
||||
* Helper class to store NBT data to {@link Chunk}'s PDC (persistent data container).
|
||||
*
|
||||
* @deprecated use methods in {@link NBT} class to read/modify chunk's nbt
|
||||
*/
|
||||
@Deprecated
|
||||
public class NBTChunk {
|
||||
|
||||
private final Chunk chunk;
|
||||
|
||||
@@ -11,7 +11,11 @@ public class NBTPersistentDataContainer extends NBTCompound {
|
||||
private final PersistentDataContainer container;
|
||||
|
||||
public NBTPersistentDataContainer(PersistentDataContainer container) {
|
||||
super(null, null);
|
||||
this(container, false);
|
||||
}
|
||||
|
||||
protected NBTPersistentDataContainer(PersistentDataContainer container, boolean readOnly) {
|
||||
super(null, null, readOnly);
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,15 @@ public interface ReadableNBT {
|
||||
*/
|
||||
Set<String> getKeys();
|
||||
|
||||
/**
|
||||
* Checks whether this NBT is empty (has no stored data).
|
||||
*
|
||||
* @return whether this NBT is empty
|
||||
*/
|
||||
default boolean isEmpty() {
|
||||
return getKeys().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return The Compound instance or null
|
||||
@@ -274,7 +283,7 @@ public interface ReadableNBT {
|
||||
* {@code Boolean, Byte, Short, Integer, Long, Float, Double, byte[], int[], long[]},
|
||||
* {@link String}, {@link UUID}, and {@link Enum}
|
||||
*
|
||||
* @param key Path key, seperated by '.'. For example: "foo.bar.baz". Dots can
|
||||
* @param key Path key, separated by '.'. For example: "foo.bar.baz". Dots can
|
||||
* be escaped with a backslash.
|
||||
* @param type data type
|
||||
* @param <T> value type
|
||||
@@ -290,7 +299,7 @@ public interface ReadableNBT {
|
||||
* {@code Boolean, Byte, Short, Integer, Long, Float, Double, byte[], int[], long[]},
|
||||
* {@link String}, {@link UUID}, and {@link Enum}
|
||||
*
|
||||
* @param key Path key, seperated by '.'. For example: "foo.bar.baz".
|
||||
* @param key Path key, separated by '.'. For example: "foo.bar.baz".
|
||||
* Dots can be escaped with a backslash.
|
||||
* @param defaultValue default non-null value
|
||||
* @param <T> value type
|
||||
@@ -302,7 +311,7 @@ public interface ReadableNBT {
|
||||
* Returns the resolved Compound if exists, or null.
|
||||
* <p>
|
||||
*
|
||||
* @param key Path key, seperated by '.'. For example: "foo.bar.baz". Dots can
|
||||
* @param key Path key, separated by '.'. For example: "foo.bar.baz". Dots can
|
||||
* be escaped with a backslash.
|
||||
* @return The resolved value if exists, or null.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,8 @@ public class DataFixerUtil {
|
||||
public static final int VERSION1_21R6 = 4554;
|
||||
public static final int VERSION1_21R7 = 4671;
|
||||
public static final int VERSION_26_1 = 4786;
|
||||
public static final int VERSION_26_2 = 4903;
|
||||
public static final int VERSION_26_3 = 5023;
|
||||
// There was a mixup between version numbers and revisions, kept for compatibility, use the above revision numbers
|
||||
@Deprecated
|
||||
public static final int VERSION1_12_2 = 1343;
|
||||
@@ -102,7 +104,11 @@ public class DataFixerUtil {
|
||||
* @return
|
||||
*/
|
||||
public static int getCurrentVersion() {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC26_1)) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC26_3)) {
|
||||
return VERSION_26_3;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC26_2)) {
|
||||
return VERSION_26_2;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC26_1)) {
|
||||
return VERSION_26_1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R7)) {
|
||||
return VERSION1_21R7;
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -31,7 +32,8 @@ public enum MinecraftVersion {
|
||||
MC1_16_R3(1163), MC1_17_R1(1171), MC1_18_R1(1181, true), MC1_18_R2(1182, true), MC1_19_R1(1191, true),
|
||||
MC1_19_R2(1192, true), MC1_19_R3(1193, true), MC1_20_R1(1201, true), MC1_20_R2(1202, true), MC1_20_R3(1203, true),
|
||||
MC1_20_R4(1204, true), MC1_21_R1(1211, true), MC1_21_R2(1212, true), MC1_21_R3(1213, true), MC1_21_R4(1214, true),
|
||||
MC1_21_R5(1215, true), MC1_21_R6(1216, true), MC1_21_R7(1217, true), MC26_1(2601, true);
|
||||
MC1_21_R5(1215, true), MC1_21_R6(1216, true), MC1_21_R7(1217, true), MC26_1(260100, true), MC26_2(260200, true),
|
||||
MC26_3(260300, true);
|
||||
|
||||
private static MinecraftVersion version;
|
||||
private static Boolean hasGsonSupport;
|
||||
@@ -48,7 +50,7 @@ public enum MinecraftVersion {
|
||||
private static Logger logger = Logger.getLogger("NBTAPI");
|
||||
|
||||
// NBT-API Version
|
||||
protected static final String VERSION = "2.15.6";
|
||||
protected static final String VERSION = "2.16.1";
|
||||
|
||||
private final int versionId;
|
||||
private final boolean mojangMapping;
|
||||
@@ -76,6 +78,8 @@ public enum MinecraftVersion {
|
||||
this.put("1.21.10", MC1_21_R6);
|
||||
this.put("1.21.11", MC1_21_R7);
|
||||
this.put("26.1", MC26_1);
|
||||
this.put("26.2", MC26_2);
|
||||
this.put("26.3", MC26_3);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -157,8 +161,22 @@ public enum MinecraftVersion {
|
||||
} catch (Exception ex) {
|
||||
logger.info("[NBTAPI] Found Minecraft: " + Bukkit.getServer().getBukkitVersion().split("-")[0]
|
||||
+ "! Trying to find NMS support");
|
||||
version = VERSION_TO_REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0],
|
||||
MinecraftVersion.UNKNOWN);
|
||||
version = VERSION_TO_REVISION.get(Bukkit.getServer().getBukkitVersion().split("-")[0]);
|
||||
if (version == null) {
|
||||
// check for modern versions with the new versioning scheme, also the new paper version format
|
||||
String versionString = Bukkit.getServer().getBukkitVersion().split("-")[0].split(".build")[0];
|
||||
for (Entry<String, MinecraftVersion> entry : VERSION_TO_REVISION.entrySet()) {
|
||||
if (versionString.startsWith(entry.getKey()) && version == null) {
|
||||
version = entry.getValue();
|
||||
// pick the highest revision that matches the version string, in case 26.1.3 is somehow different to 26.1
|
||||
} else if (versionString.startsWith(entry.getKey()) && entry.getValue().getVersionId() > version.getVersionId()) {
|
||||
version = entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version == null) {
|
||||
version = UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (version != UNKNOWN) {
|
||||
logger.info("[NBTAPI] NMS support '" + version.name() + "' loaded!");
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@ public class Forge1710Mappings {
|
||||
methodMap.put("COMPOUND_MERGE", "merge");// Only present on Crucible
|
||||
methodMap.put("COMPOUND_SET", "func_74782_a");
|
||||
methodMap.put("COMPOUND_GET", "func_74781_a");
|
||||
methodMap.put("COMPOUND_GET_LIST", "func_150295_c");
|
||||
methodMap.put("COMPOUND_OWN_TYPE", "func_74732_a");
|
||||
methodMap.put("COMPOUND_GET_LIST_LEGACY", "func_150295_c");
|
||||
methodMap.put("COMPOUND_OWN_TYPE_LEGACY", "func_74732_a");
|
||||
methodMap.put("COMPOUND_GET_FLOAT", "func_74760_g");
|
||||
methodMap.put("COMPOUND_GET_STRING", "func_74779_i");
|
||||
methodMap.put("COMPOUND_GET_INT", "func_74762_e");
|
||||
|
||||
+12
-1
@@ -175,7 +175,8 @@ public enum ReflectionMethod {
|
||||
ITEMSTACK_NMSCOPY(ClassWrapper.CRAFT_ITEMSTACK, new Class[] { ItemStack.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "asNMSCopy")),
|
||||
ITEMSTACK_BUKKITMIRROR(ClassWrapper.CRAFT_ITEMSTACK, new Class[] { ClassWrapper.NMS_ITEMSTACK.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asCraftMirror")),
|
||||
MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, resolveItemStackBukkitMirrorMethodName())),
|
||||
|
||||
CRAFT_WORLD_GET_HANDLE(ClassWrapper.CRAFT_WORLD, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
|
||||
@@ -413,6 +414,16 @@ public enum ReflectionMethod {
|
||||
this(targetClass, args, addedSince, null, methodnames);
|
||||
}
|
||||
|
||||
private static String resolveItemStackBukkitMirrorMethodName() {
|
||||
try {
|
||||
ClassWrapper.CRAFT_ITEMSTACK.getClazz().getDeclaredMethod("asCraftMirror",
|
||||
ClassWrapper.NMS_ITEMSTACK.getClazz());
|
||||
return "asCraftMirror";
|
||||
} catch (NullPointerException | NoSuchMethodException | SecurityException ignored) {
|
||||
return "asBukkitMirror";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the method on a given target object using the given args.
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</parent>
|
||||
<artifactId>item-nbt-api-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -12,7 +12,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+56
-19
@@ -1,40 +1,77 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.blocks;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTBlock;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockNBTTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (MinecraftVersion.getVersion().getVersionId() < MinecraftVersion.MC1_16_R3.getVersionId())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
if (world.getLoadedChunks().length > 1) {
|
||||
Chunk chunk = world.getLoadedChunks()[0];
|
||||
Block block = chunk.getBlock(0, 254, 0);
|
||||
NBTBlock comp = new NBTBlock(block);
|
||||
comp.getData().removeKey("Too");
|
||||
if (comp.getData().hasTag("Too")) {
|
||||
throw new NbtApiException("Unable to remove key from Block!");
|
||||
}
|
||||
comp.getData().setString("Too", "Bar");
|
||||
if (!new NBTBlock(block).getData().getString("Too").equals("Bar")) {
|
||||
throw new NbtApiException("Custom Data did not save to a Block!");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTBlocks!", ex);
|
||||
|
||||
List<World> loadedWorlds = Bukkit.getWorlds();
|
||||
if (loadedWorlds.isEmpty())
|
||||
return;
|
||||
|
||||
World world = loadedWorlds.get(0);
|
||||
Chunk[] loadedChunks = world.getLoadedChunks();
|
||||
if (loadedChunks.length == 0)
|
||||
return;
|
||||
|
||||
try {
|
||||
Chunk chunk = loadedChunks[0];
|
||||
Block block = chunk.getBlock(0, 254, 0);
|
||||
String blockKey = block.getX() + "_" + block.getY() + "_" + block.getZ();
|
||||
|
||||
NBT.modifyChunkPDC(block, nbt -> nbt.setString("Too", "Bar"));
|
||||
boolean storedDataPresent = NBT.readAndGetChunkPDC(chunk, nbt -> {
|
||||
if (!nbt.hasTag("blocks", NBTType.NBTTagCompound)) return false;
|
||||
|
||||
ReadableNBT blocksNbt = nbt.getCompound("blocks");
|
||||
if (blocksNbt == null || !blocksNbt.hasTag(blockKey, NBTType.NBTTagCompound)) return false;
|
||||
|
||||
ReadableNBT blockNbt = blocksNbt.getCompound(blockKey);
|
||||
return blockNbt != null && blockNbt.hasTag("Too", NBTType.NBTTagString) && "Bar".equals(blockNbt.getString("Too"));
|
||||
});
|
||||
if (!storedDataPresent) {
|
||||
throw new NbtApiException("Custom Data did not save to a Block!");
|
||||
}
|
||||
if (!NBT.readAndGetChunkPDC(block, nbt -> nbt.hasTag("Too"))) {
|
||||
throw new NbtApiException("Custom Data did not save to a Block!");
|
||||
}
|
||||
|
||||
boolean blockHadOnlyTestKey = NBT.readAndGetChunkPDC(block, nbt -> nbt.getKeys().size() == 1);
|
||||
boolean chunkHadOnlyOneBlock = NBT.readAndGetChunkPDC(chunk, nbt -> nbt.getCompound("blocks").getKeys().size() == 1);
|
||||
|
||||
NBT.modifyChunkPDC(block, nbt -> nbt.removeKey("Too"));
|
||||
|
||||
if (NBT.readAndGetChunkPDC(block, nbt -> nbt.hasTag("Too"))) {
|
||||
throw new NbtApiException("Unable to remove key from Block!");
|
||||
}
|
||||
|
||||
if (chunkHadOnlyOneBlock) {
|
||||
if (NBT.readAndGetChunkPDC(chunk, nbt -> nbt.hasTag("blocks"))) {
|
||||
throw new NbtApiException("Chunk data wasn't cleaned up (hanging \"blocks\" compound)!");
|
||||
}
|
||||
} else if (blockHadOnlyTestKey) {
|
||||
if (NBT.readAndGetChunkPDC(chunk, nbt -> nbt.getCompound("blocks").hasTag(blockKey))) {
|
||||
throw new NbtApiException("Chunk data wasn't cleaned up (hanging block location compound)!");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTBlocks!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
-20
@@ -1,40 +1,46 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.chunks;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTChunk;
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChunkNBTPersistentTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (MinecraftVersion.getVersion().getVersionId() < MinecraftVersion.MC1_16_R3.getVersionId())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
if (world.getLoadedChunks().length > 1) {
|
||||
Chunk chunk = world.getLoadedChunks()[0];
|
||||
NBTChunk comp = new NBTChunk(chunk);
|
||||
NBTCompound persistentData = comp.getPersistentDataContainer();
|
||||
persistentData.removeKey("Foo");
|
||||
if (persistentData.hasTag("Foo")) {
|
||||
throw new NbtApiException("Unable to remove key from Chunk!");
|
||||
}
|
||||
persistentData.setString("Foo", "Bar");
|
||||
if (!new NBTChunk(chunk).getPersistentDataContainer().getString("Foo").equals("Bar")) {
|
||||
throw new NbtApiException("Custom Data did not save to the Chunk!");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTChunks!", ex);
|
||||
|
||||
List<World> loadedWorlds = Bukkit.getWorlds();
|
||||
if (loadedWorlds.isEmpty())
|
||||
return;
|
||||
|
||||
World world = loadedWorlds.get(0);
|
||||
Chunk[] loadedChunks = world.getLoadedChunks();
|
||||
if (loadedChunks.length == 0)
|
||||
return;
|
||||
|
||||
Chunk chunk = loadedChunks[0];
|
||||
try {
|
||||
NBT.modifyChunkPDC(chunk, nbt -> nbt.setString("Foo", "Bar"));
|
||||
if (!NBT.readAndGetChunkPDC(chunk, nbt -> nbt.hasTag("Foo", NBTType.NBTTagString) && "Bar".equals(nbt.getString("Foo")))) {
|
||||
throw new NbtApiException("Custom Data did not save to the Chunk!");
|
||||
}
|
||||
|
||||
NBT.modifyChunkPDC(chunk, nbt -> nbt.removeKey("Foo"));
|
||||
if (NBT.readAndGetChunkPDC(chunk, nbt -> nbt.hasTag("Foo"))) {
|
||||
throw new NbtApiException("Unable to remove key from Chunk!");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTChunks!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</parent>
|
||||
<artifactId>mappings-parser</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -12,7 +12,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>nbt-data-api</artifactId>
|
||||
@@ -14,7 +14,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</parent>
|
||||
<artifactId>nbt-injector</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -12,7 +12,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
<packaging>pom</packaging>
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
<organization>
|
||||
@@ -88,7 +88,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.15.0</version>
|
||||
<version>3.16.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
|
||||
@@ -112,7 +112,7 @@ Just use the Plugin as Maven dependency and remember to add "NBTAPI" as dependen
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api-plugin</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</dependency>
|
||||
[/CODE]
|
||||
[/SPOILER]
|
||||
@@ -122,7 +122,7 @@ Using this method the API gets copied into your plugin. Server owners don't have
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.15.6</version>
|
||||
<version>2.16.1</version>
|
||||
</dependency>
|
||||
...
|
||||
<plugins>
|
||||
|
||||
@@ -306,20 +306,26 @@ You can store data in block entities (block entities like chest, furnace, etc.)
|
||||
|
||||
Thus, you have to use your own block data storage to store custom block data.
|
||||
|
||||
You can store data inside Chunks since 1.16.4, and NBT-API allows you to do so by using ``NBTChunk``:
|
||||
You can store data inside Chunks using their PDC (Persistent Data Container) since Minecraft **1.16.4**. The NBT‑API provides read and modify methods in the `NBT` class to interact with it:
|
||||
|
||||
```java
|
||||
ReadWriteNBT nbt = new NBTChunk(chunk).getPersistentDataContainer();
|
||||
// Read the entire PDC or a specific value
|
||||
NBT.readChunkPDC(chunk, nbt -> { /* ... */ });
|
||||
String str = NBT.readAndGetChunkPDC(chunk, nbt -> nbt.getOrNull("key", String.class));
|
||||
```
|
||||
|
||||
Similarly, there is ``NBTBlock``, which allows you to store block data inside chunk's data.
|
||||
For convenience, you can also pass Blocks into `NBT#read/modify[AndGet]ChunkPDC` methods to store block data inside Chunk's PDC.
|
||||
Blocks are stored inside their chunk's PDC under a `blocks` compound, using the block's location (`X_Y_Z`) as the key for a subcompound.
|
||||
|
||||
```java
|
||||
// Block's data will be stored in Chunk's data in "blocks.x_y_z" subtag
|
||||
ReadWriteNBT nbt = new NBTBlock(block).getData();
|
||||
// Modify and retrieve data for a specific block
|
||||
boolean bool = NBT.modifyAndGetChunkPDC(block, nbt -> {
|
||||
nbt.setString("owner_name", "Player123");
|
||||
return nbt.getOrDefault("key", false);
|
||||
});
|
||||
```
|
||||
|
||||
**However**, keep in mind that this data is linked only to the location, and if the block gets broken/changed/exploded/moved/etc., the data will still be on that location unless manually cleared/moved!
|
||||
**However**, keep in mind that the block's data is linked only to the location, and if the block gets broken/changed/exploded/moved/etc., the data will still be on that location unless manually cleared/moved!
|
||||
|
||||
Moreover, since the data is stored inside a Chunk, this will increase the chunk's size on the disk.
|
||||
|
||||
|
||||
Reference in new issue
Block a user