mirror of
https://github.com/tr7zw/Item-NBT-API.git
synced 2026-11-04 16:50:12 -05:00
Compare commits
240
Commits
proxyPrototype
...
2.16.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d6aa142de | ||
|
|
cc1436cd09 | ||
|
|
4506dd37da | ||
|
|
bbc02e1299 | ||
|
|
ca9d5ad140 | ||
|
|
25c82a5ad0 | ||
|
|
17d40445d2 | ||
|
|
47ad3591df | ||
|
|
b3652ecf7d | ||
|
|
46a9116613 | ||
|
|
5776be4a35 | ||
|
|
9fbee68966 | ||
|
|
b277f0b01d | ||
|
|
e4793a0d46 | ||
|
|
7c34542b86 | ||
|
|
856bf5ed6d | ||
|
|
123da87a3a | ||
|
|
f3d7545c6b | ||
|
|
3b29fe399e | ||
|
|
c368318bb6 | ||
|
|
c1473dfa97 | ||
|
|
a360ca50f4 | ||
|
|
8b1ca8447e | ||
|
|
b66353d0d0 | ||
|
|
5bec1371d2 | ||
|
|
8cbb6af964 | ||
|
|
309455ecfc | ||
|
|
22c0b0385b | ||
|
|
bc6bd56ce9 | ||
|
|
fcdf0929f9 | ||
|
|
e1c6ce2575 | ||
|
|
2fcc1d82ab | ||
|
|
eec2c0980e | ||
|
|
3ddf3e53dc | ||
|
|
70d5ab12eb | ||
|
|
a63e9ba8f4 | ||
|
|
d8a59d6383 | ||
|
|
943c7d23d6 | ||
|
|
6c70ce2ccc | ||
|
|
c1b7854fbb | ||
|
|
f9f1c204b6 | ||
|
|
789f1fea96 | ||
|
|
0e40144f09 | ||
|
|
1c6315e014 | ||
|
|
91f345adf2 | ||
|
|
71783a8dc9 | ||
|
|
5d06ae9275 | ||
|
|
835fdf48cd | ||
|
|
31d77d25f9 | ||
|
|
6cb08ac919 | ||
|
|
08a92ac06c | ||
|
|
6bcd00d114 | ||
|
|
bc93986392 | ||
|
|
aa646e35ae | ||
|
|
1054d16996 | ||
|
|
9351a86774 | ||
|
|
56a43d246b | ||
|
|
2b895fd4ef | ||
|
|
8f8bbfd034 | ||
|
|
df231c2324 | ||
|
|
b068284b6e | ||
|
|
9e9b85f46a | ||
|
|
3baed4b1e7 | ||
|
|
432b40b3bc | ||
|
|
fdf3638948 | ||
|
|
b240e888cd | ||
|
|
ccc096e2d4 | ||
|
|
35f541d3db | ||
|
|
d4ee3b998c | ||
|
|
2902dca5a5 | ||
|
|
1c1e3c8664 | ||
|
|
7f8f021ced | ||
|
|
98ed1850f6 | ||
|
|
764e01503d | ||
|
|
43d8e2a351 | ||
|
|
689cd4fa3b | ||
|
|
c8f68f8b3b | ||
|
|
e52ba209e6 | ||
|
|
418f5bea07 | ||
|
|
1392e72a8a | ||
|
|
dc39d1d8ef | ||
|
|
a974142a55 | ||
|
|
f014e71020 | ||
|
|
da6be72d29 | ||
|
|
d9a93e9306 | ||
|
|
ba374fe69c | ||
|
|
aa35ee8333 | ||
|
|
3bb0bdd74c | ||
|
|
f3af749b11 | ||
|
|
d81c2b4e8e | ||
|
|
94192feb8f | ||
|
|
af3d9c8502 | ||
|
|
ae98859524 | ||
|
|
70f0bb62f9 | ||
|
|
505e172955 | ||
|
|
d2b2b6a506 | ||
|
|
e2e8aad70a | ||
|
|
4874366e30 | ||
|
|
d2de90ee25 | ||
|
|
a0f93e575e | ||
|
|
b339c9e9c2 | ||
|
|
3425a6672d | ||
|
|
67616266da | ||
|
|
b08e4aa12f | ||
|
|
27411e90da | ||
|
|
73776cfec4 | ||
|
|
bd674e31c0 | ||
|
|
3405ffe0a3 | ||
|
|
f1317bcb04 | ||
|
|
4a32343b95 | ||
|
|
3de6ed83eb | ||
|
|
e5bdce73ea | ||
|
|
410e88a35b | ||
|
|
e3142b4869 | ||
|
|
243a5c2bcd | ||
|
|
045c710366 | ||
|
|
4cd118671f | ||
|
|
d86c91f2e6 | ||
|
|
f8736c8188 | ||
|
|
b3aec54205 | ||
|
|
0f926998f6 | ||
|
|
3a44a5e989 | ||
|
|
30b931945c | ||
|
|
88d8629541 | ||
|
|
00ae0448f4 | ||
|
|
ce26e180e6 | ||
|
|
c939105e45 | ||
|
|
2079123a42 | ||
|
|
31b17fe9c9 | ||
|
|
b565902006 | ||
|
|
5280ba82a2 | ||
|
|
522f732ed1 | ||
|
|
ac84a4d69a | ||
|
|
d7e18c1cb6 | ||
|
|
ffa612634a | ||
|
|
739682122b | ||
|
|
2e20af40e5 | ||
|
|
e6527515be | ||
|
|
e6f33a35ae | ||
|
|
39801ada18 | ||
|
|
75fab7622a | ||
|
|
33eef1bcf1 | ||
|
|
877a42fd06 | ||
|
|
0a7e560e2e | ||
|
|
174728a681 | ||
|
|
79ba1dd275 | ||
|
|
25c59b0eae | ||
|
|
0057d3f2e8 | ||
|
|
59c67a3f0b | ||
|
|
3ec606ae21 | ||
|
|
ff0a94f279 | ||
|
|
53216d3b7d | ||
|
|
7cf23201ce | ||
|
|
fe1d586f44 | ||
|
|
956ef15a1d | ||
|
|
ed867749f8 | ||
|
|
88fbc0140e | ||
|
|
82e52267b8 | ||
|
|
c16548ff4e | ||
|
|
cf30cf996e | ||
|
|
633433d6d0 | ||
|
|
153c72818a | ||
|
|
4798880a53 | ||
|
|
1f149dbae4 | ||
|
|
8570c6f77e | ||
|
|
30f75e0714 | ||
|
|
af7a6b0a1c | ||
|
|
c0a9197113 | ||
|
|
e14dd4f82a | ||
|
|
198dbfabae | ||
|
|
8bd49db49b | ||
|
|
caf1d7cd98 | ||
|
|
027f2a2edd | ||
|
|
b74b0b852e | ||
|
|
6ea6ab7e13 | ||
|
|
372225626c | ||
|
|
2483f9b947 | ||
|
|
fdc16aad69 | ||
|
|
c723eef68b | ||
|
|
03299012ac | ||
|
|
eabf0a9696 | ||
|
|
9367942b54 | ||
|
|
167487e6ab | ||
|
|
6395dd1964 | ||
|
|
d3ef690f2e | ||
|
|
012f32dca9 | ||
|
|
0b8d5b153c | ||
|
|
246e3fa38e | ||
|
|
19777de6d4 | ||
|
|
3afd9df2ae | ||
|
|
2cb16ed0c4 | ||
|
|
ac64acf271 | ||
|
|
85cc13a817 | ||
|
|
75c8575b5b | ||
|
|
67557d5f94 | ||
|
|
330fb7711c | ||
|
|
e7f48c72bd | ||
|
|
3eefb1d315 | ||
|
|
a37a2c6729 | ||
|
|
e42fad0761 | ||
|
|
eee2dfa181 | ||
|
|
4728449294 | ||
|
|
ccd78d1b00 | ||
|
|
83bea69710 | ||
|
|
87fd1ee8ee | ||
|
|
af0528328f | ||
|
|
86c802e2db | ||
|
|
7bf91d0510 | ||
|
|
aed5af12a2 | ||
|
|
dd6e9e8312 | ||
|
|
42871b6c06 | ||
|
|
4ad7a172a0 | ||
|
|
6f112c0130 | ||
|
|
5a948f017a | ||
|
|
f5a1b21761 | ||
|
|
4af722752e | ||
|
|
af3b7a49d0 | ||
|
|
189ff2f369 | ||
|
|
ddf8ab3c9b | ||
|
|
a8a81eee83 | ||
|
|
fb384784f0 | ||
|
|
256abbc500 | ||
|
|
dc333ae25a | ||
|
|
d18adb459d | ||
|
|
bc914b73bc | ||
|
|
60172ea2a7 | ||
|
|
7b30c1533e | ||
|
|
a1c90658f3 | ||
|
|
0b0fdeaa60 | ||
|
|
d989797453 | ||
|
|
c70aefe670 | ||
|
|
7d0fc09470 | ||
|
|
427113e6f0 | ||
|
|
20ae1cb178 | ||
|
|
83b011fafa | ||
|
|
3affeee151 | ||
|
|
06da2114ad | ||
|
|
a3efdc622b | ||
|
|
9b60978af6 | ||
|
|
598db19d8d |
No files matched your search
@@ -8,7 +8,7 @@ updates:
|
||||
ignore:
|
||||
- dependency-name: com.github.ekryd.sortpom:sortpom-maven-plugin
|
||||
versions:
|
||||
- 2.13.1
|
||||
- 2.13.3-SNAPSHOT
|
||||
- 2.14.0
|
||||
- 2.14.1
|
||||
- 2.15.0
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: Copy artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p artifacts/v2-api && cp -r item-nbt-api/target/apidocs/* artifacts/v2-api
|
||||
mkdir -p artifacts/v2-api && cp -r item-nbt-api/target/reports/apidocs/* artifacts/v2-api
|
||||
mkdir -p artifacts/v2-plugin && cp -r item-nbt-plugin/target/apidocs/* artifacts/v2-plugin
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 - 2021, tr7zw
|
||||
Copyright (c) 2015 - 2024, tr7zw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Item-NBT-API
|
||||
|
||||
Add custom NBT tags to Items/Tiles/Entities without NMS! Modify NBT and store it Files, other NBT or as String in yaml/json/SQL/Redis.
|
||||
[](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
|
||||
|
||||
@@ -15,7 +16,7 @@ Add custom NBT tags to Items/Tiles/Entities without NMS! Modify NBT and store it
|
||||
|
||||
## Getting started
|
||||
|
||||
Import the API [using Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Maven), then check out the [basic usage](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API) or code examples like [working with Skulls](https://github.com/tr7zw/Item-NBT-API/wiki/Set-a-skull's-skin-using-NBT-API).
|
||||
Import the API using [Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Maven) or [Gradle](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Gradle), then check out the [basic usage](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API) or code examples like [working with Skulls](https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages#set-a-skulls-skin).
|
||||
|
||||
### bStats
|
||||
|
||||
@@ -24,3 +25,12 @@ Import the API [using Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Ma
|
||||
### Github Stargazers
|
||||
|
||||
<img src="https://starchart.cc/tr7zw/Item-NBT-API.svg" alt="stargazers" width="800"/>
|
||||
|
||||
### Supported by YourKit
|
||||
|
||||

|
||||
YourKit supports open source projects with innovative and intelligent tools
|
||||
for monitoring and profiling Java and .NET applications.
|
||||
YourKit is the creator of <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>,
|
||||
<a href="https://www.yourkit.com/.net/profiler/">YourKit .NET Profiler</a>,
|
||||
and <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>.
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# (Item-)NBT-API
|
||||
|
||||
Add custom NBT tags to Items/Tiles/Entities without NMS! Modify NBT and store it Files, other NBT or as String in yaml/json/SQL/Redis.
|
||||
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
|
||||
@@ -14,7 +14,7 @@ Discord:[, then check out the [basic usage](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API) or code examples like [working with Skulls](https://github.com/tr7zw/Item-NBT-API/wiki/Set-a-skull's-skin-using-NBT-API).
|
||||
Import the API using [Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Maven) or [Gradle](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Gradle), then check out the [basic usage](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API) or code examples like [working with Skulls](https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages#set-a-skulls-skin).
|
||||
|
||||
### bStats
|
||||
|
||||
|
||||
+24
-3
@@ -5,12 +5,27 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>datafixerupper</artifactId>
|
||||
<version>4.0.26</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install javadoc:javadoc</defaultGoal>
|
||||
<resources>
|
||||
@@ -23,9 +38,15 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>de.tr7zw.changeme.nbtapi.utils.metrics</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>LICENSE</resource>
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package de.tr7zw.changeme.nbtapi;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
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;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteItemNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableItemNBT;
|
||||
@@ -18,6 +26,9 @@ import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.NBTProxy;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.ProxyBuilder;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
/**
|
||||
* General utility class for a clean and simple nbt access.
|
||||
@@ -25,12 +36,52 @@ import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList;
|
||||
* @author tr7zw
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class NBT {
|
||||
|
||||
private NBT() {
|
||||
// No instances of NBT. Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for shaded versions to preload and check the API during
|
||||
* onEnable. This method does not throw an exception and instead logs them. Will
|
||||
* return false if something fundamentally is wrong and the NBTAPI is in a non
|
||||
* functioning state. The shading plugin then needs to handle this. Note:
|
||||
* Calling this method during onLoad will cause an failure, so please wait till
|
||||
* onEnable.
|
||||
*
|
||||
* @return true if everything went fine
|
||||
*/
|
||||
public static boolean preloadApi() {
|
||||
try {
|
||||
// boiled down version of the plugin selfcheck without tests
|
||||
if (MinecraftVersion.getVersion() == MinecraftVersion.UNKNOWN) {
|
||||
NbtApiException.confirmedBroken = true;
|
||||
return false;
|
||||
}
|
||||
for (ClassWrapper c : ClassWrapper.values()) {
|
||||
if (c.isEnabled() && c.getClazz() == null) {
|
||||
NbtApiException.confirmedBroken = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (ReflectionMethod method : ReflectionMethod.values()) {
|
||||
if (method.isCompatible() && !method.isLoaded()) {
|
||||
NbtApiException.confirmedBroken = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// not settings NbtApiException.confirmedBroken = false, as no actual tests were done.
|
||||
// This just means the version was found, and all reflections seem to work.
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
NbtApiException.confirmedBroken = true;
|
||||
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error during the selfcheck!", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a read only instance of the items NBT. This method is slightly slower
|
||||
* than calling NBT.get due to having to create a copy of the ItemStack, but
|
||||
@@ -156,9 +207,9 @@ public class NBT {
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes a block entity and a function that takes a ReadableNBT and returns
|
||||
* a generic type T, and returns the result of the function, applied to the
|
||||
* block entities persistent data container
|
||||
* It takes a block entity and a function that takes a ReadableNBT and returns a
|
||||
* generic type T, and returns the result of the function, applied to the block
|
||||
* entities persistent data container
|
||||
*
|
||||
* @param blockState The block state of the block you want to get the data from.
|
||||
* @param getter A function that takes a ReadableNBT and returns a value of
|
||||
@@ -226,6 +277,77 @@ public class NBT {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes an ItemStack and a Consumer<ReadWriteNBT>, and then applies
|
||||
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
|
||||
* This method is quite expensive, so don't overuse it.
|
||||
*
|
||||
* @param item The item you want to modify the components of
|
||||
* @param consumer The consumer that will be used to modify the components.
|
||||
*/
|
||||
public static void modifyComponents(ItemStack item, Consumer<ReadWriteNBT> consumer) {
|
||||
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
throw new NbtApiException("This method only works for 1.20.5+!");
|
||||
}
|
||||
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
|
||||
consumer.accept(nbti.getOrCreateCompound("components"));
|
||||
ItemStack tmp = NBT.itemStackFromNBT(nbti);
|
||||
item.setItemMeta(tmp.getItemMeta());
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes an ItemStack and a Consumer<ReadWriteNBT>, and then applies
|
||||
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
|
||||
* This method is quite expensive, so don't overuse it.
|
||||
*
|
||||
* @param item The item you want to modify the components of
|
||||
* @param function The consumer that will be used to modify the components.
|
||||
* @return The return type is the same as the return type of the function.
|
||||
*/
|
||||
public static <T> T modifyComponents(ItemStack item, Function<ReadWriteNBT, T> function) {
|
||||
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
throw new NbtApiException("This method only works for 1.20.5+!");
|
||||
}
|
||||
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
|
||||
T ret = function.apply(nbti.getOrCreateCompound("components"));
|
||||
ItemStack tmp = NBT.itemStackFromNBT(nbti);
|
||||
item.setItemMeta(tmp.getItemMeta());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes an ItemStack and a Consumer<ReadWriteNBT>, and then applies
|
||||
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
|
||||
* This method is quite expensive, try to cache the results/use it smartly.
|
||||
*
|
||||
* @param item The item you want to read the components of
|
||||
* @param consumer The consumer that will be used to read the components.
|
||||
*/
|
||||
public static void getComponents(ItemStack item, Consumer<ReadableNBT> consumer) {
|
||||
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
throw new NbtApiException("This method only works for 1.20.5+!");
|
||||
}
|
||||
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
|
||||
consumer.accept(nbti.getOrCreateCompound("components"));
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes an ItemStack and a Consumer<ReadWriteNBT>, and then applies
|
||||
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
|
||||
* This method is quite expensive, try to cache the results/use it smartly.
|
||||
*
|
||||
* @param item The item you want to read the components of
|
||||
* @param function The consumer that will be used to read the components.
|
||||
* @return The return type is the same as the return type of the function.
|
||||
*/
|
||||
public static <T> T getComponents(ItemStack item, Function<ReadableNBT, T> function) {
|
||||
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
throw new NbtApiException("This method only works for 1.20.5+!");
|
||||
}
|
||||
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
|
||||
return function.apply(nbti.getOrCreateCompound("components"));
|
||||
}
|
||||
|
||||
/**
|
||||
* It takes an entity and a function that takes a ReadWriteNBT and applies the
|
||||
* function to the entity
|
||||
@@ -410,12 +532,70 @@ public class NBT {
|
||||
* It takes a nbt json string, and returns a ReadWriteNBT object
|
||||
*
|
||||
* @param nbtString The NBT string to parse.
|
||||
* @return A new NBTContainer object.
|
||||
* @return A new ReadWriteNBT object.
|
||||
*/
|
||||
public static ReadWriteNBT parseNBT(String nbtString) {
|
||||
return new NBTContainer(nbtString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in an NBT stream and returns a ReadWriteNBT object
|
||||
*
|
||||
* @param stream The NBT stream to read.
|
||||
* @return A new ReadWriteNBT object.
|
||||
*/
|
||||
public static ReadWriteNBT readNBT(InputStream stream) {
|
||||
return new NBTContainer(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for other developers using NMS. Allows to wrap any
|
||||
* net.minecraft.nbt.CompoundTag to a NBTAPI ReadWriteNBT object.
|
||||
*
|
||||
* @param nmsNbtTag Needs to be a valid net.minecraft.nbt.CompoundTag
|
||||
* @return A new ReadWriteNBT object.
|
||||
*/
|
||||
public static ReadWriteNBT wrapNMSTag(Object nmsNbtTag) {
|
||||
return new NBTContainer(nmsNbtTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NBTFileHandle that uses @param file to store its data. If this file
|
||||
* exists, the data will be loaded, otherwise a new file gets created.
|
||||
*
|
||||
* @param file
|
||||
* @throws IOException
|
||||
*/
|
||||
public static NBTFileHandle getFileHandle(File file) throws IOException {
|
||||
return new NBTFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads NBT data from the provided file.
|
||||
* <p>
|
||||
* Returns an empty tag if the file does not exist.
|
||||
*
|
||||
* @param file file to read
|
||||
* @return ReadWriteNBT of the files data
|
||||
* @throws IOException exception
|
||||
*/
|
||||
public static ReadWriteNBT readFile(File file) throws IOException {
|
||||
return NBTFile.readFrom(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves NBT data to the provided file.
|
||||
* <p>
|
||||
* Will fully override the file if it already exists.
|
||||
*
|
||||
* @param file file
|
||||
* @param nbt NBT data
|
||||
* @throws IOException exception
|
||||
*/
|
||||
public static void writeFile(File file, ReadWriteNBT nbt) throws IOException {
|
||||
NBTFile.saveTo(file, (NBTCompound) nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a read only proxy class for NBT, given an annotated interface.
|
||||
*
|
||||
@@ -550,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;
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
@@ -19,6 +20,8 @@ import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.CheckUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.PathUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.UUIDUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.PathUtil.PathSegment;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.Forge1710Mappings;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
@@ -97,12 +100,15 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
return readOnlyCache;
|
||||
}
|
||||
Object rootnbttag = getCompound();
|
||||
if (rootnbttag instanceof Optional<?>) {
|
||||
rootnbttag = ((Optional<Object>) rootnbttag).orElse(null);
|
||||
}
|
||||
if (rootnbttag == null) {
|
||||
return null;
|
||||
}
|
||||
if (!NBTReflectionUtil.valideCompound(this))
|
||||
if (!NBTReflectionUtil.validCompound(this))
|
||||
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
|
||||
Object workingtag = NBTReflectionUtil.gettoCompount(rootnbttag, this);
|
||||
Object workingtag = NBTReflectionUtil.getToCompount(rootnbttag, this);
|
||||
if (readOnly) {
|
||||
this.readOnlyCache = workingtag;
|
||||
}
|
||||
@@ -195,10 +201,6 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getContent(String key) {
|
||||
return NBTReflectionUtil.getContent(this, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter
|
||||
*
|
||||
@@ -660,7 +662,9 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
public void setUUID(String key, UUID value) {
|
||||
try {
|
||||
writeLock.lock();
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
setIntArray(key, UUIDUtil.uuidToIntArray(value));
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_UUID, key, value);
|
||||
} else {
|
||||
setString(key, value.toString());
|
||||
@@ -681,10 +685,13 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
public UUID getUUID(String key) {
|
||||
try {
|
||||
readLock.lock();
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)
|
||||
&& getType(key) == NBTType.NBTTagIntArray) {
|
||||
NBTType type = getType(key);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4) && type == NBTType.NBTTagIntArray) {
|
||||
return UUIDUtil.uuidFromIntArray(getIntArray(key));
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)
|
||||
&& type == NBTType.NBTTagIntArray) {
|
||||
return (UUID) NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET_UUID, key);
|
||||
} else if (getType(key) == NBTType.NBTTagString) {
|
||||
} else if (type == NBTType.NBTTagString) {
|
||||
try {
|
||||
return UUID.fromString(getString(key));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -789,7 +796,7 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
if (getType(name) != NBTType.NBTTagCompound)
|
||||
return null;
|
||||
NBTCompound next = new NBTCompound(this, name, readOnly);
|
||||
if (NBTReflectionUtil.valideCompound(next))
|
||||
if (NBTReflectionUtil.validCompound(next))
|
||||
return next;
|
||||
return null;
|
||||
} finally {
|
||||
@@ -1063,38 +1070,205 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
|
||||
@Override
|
||||
public <T> T resolveOrNull(String key, Class<?> type) {
|
||||
List<String> keys = PathUtil.splitPath(key);
|
||||
List<PathSegment> keys = PathUtil.splitPath(key);
|
||||
NBTCompound tag = this;
|
||||
for (int i = 0; i < keys.size() - 1; i++) {
|
||||
tag = tag.getCompound(keys.get(i));
|
||||
if (tag == null) {
|
||||
return null;
|
||||
PathSegment segment = keys.get(i);
|
||||
if (!segment.hasIndex()) {
|
||||
tag = tag.getCompound(segment.getPath());
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (tag.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& tag.getListType(segment.getPath()) == NBTType.NBTTagCompound) {
|
||||
NBTCompoundList list = tag.getCompoundList(segment.getPath());
|
||||
if (segment.getIndex() >= 0) {
|
||||
tag = list.get(segment.getIndex());
|
||||
} else {
|
||||
tag = list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tag.getOrNull(keys.get(keys.size() - 1), type);
|
||||
PathSegment segment = keys.get(keys.size() - 1);
|
||||
if (!segment.hasIndex()) {
|
||||
return tag.getOrNull(segment.getPath(), type);
|
||||
} else {
|
||||
return getIndexedValue(tag, segment, (Class<T>)type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T resolveOrDefault(String key, T defaultValue) {
|
||||
List<String> keys = PathUtil.splitPath(key);
|
||||
List<PathSegment> keys = PathUtil.splitPath(key);
|
||||
NBTCompound tag = this;
|
||||
for (int i = 0; i < keys.size() - 1; i++) {
|
||||
tag = tag.getCompound(keys.get(i));
|
||||
if (tag == null) {
|
||||
return defaultValue;
|
||||
PathSegment segment = keys.get(i);
|
||||
if (!segment.hasIndex()) {
|
||||
tag = tag.getCompound(segment.getPath());
|
||||
if (tag == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
} else {
|
||||
if (tag.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& tag.getListType(segment.getPath()) == NBTType.NBTTagCompound) {
|
||||
NBTCompoundList list = tag.getCompoundList(segment.getPath());
|
||||
if (segment.getIndex() >= 0) {
|
||||
tag = list.get(segment.getIndex());
|
||||
} else {
|
||||
tag = list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tag.getOrDefault(keys.get(keys.size() - 1), defaultValue);
|
||||
PathSegment segment = keys.get(keys.size() - 1);
|
||||
if (!segment.hasIndex()) {
|
||||
return tag.getOrDefault(segment.getPath(), defaultValue);
|
||||
} else {
|
||||
return getIndexedValue(tag, segment, (Class<T>)defaultValue.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: before I'm even done writing this method, this sucks. Needs refactoring at some point
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getIndexedValue(NBTCompound comp, PathSegment segment, Class<T> type) {
|
||||
if (type == String.class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagString) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getStringList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<String> list = comp.getStringList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == int.class || type == Integer.class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagInt) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getIntegerList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<Integer> list = comp.getIntegerList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
} else if(comp.getType(segment.getPath()) == NBTType.NBTTagIntArray) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
int[] array = comp.getIntArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Integer) array[segment.getIndex()];
|
||||
}
|
||||
} else {
|
||||
int[] array = comp.getIntArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Integer) array[array.length + segment.getIndex()];
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == long.class || type == Long.class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagLong) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getLongList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<Long> list = comp.getLongList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
} else if(comp.getType(segment.getPath()) == NBTType.NBTTagLongArray) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
long[] array = comp.getLongArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Long) array[segment.getIndex()];
|
||||
}
|
||||
} else {
|
||||
long[] array = comp.getLongArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Long) array[array.length + segment.getIndex()];
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == float.class || type == Float.class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagFloat) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getFloatList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<Float> list = comp.getFloatList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == double.class || type == Double.class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagDouble) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getDoubleList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<Double> list = comp.getDoubleList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == int[].class) {
|
||||
if (comp.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& comp.getListType(segment.getPath()) == NBTType.NBTTagIntArray) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
return (T) comp.getIntArrayList(segment.getPath()).get(segment.getIndex());
|
||||
} else {
|
||||
List<int[]> list = comp.getIntArrayList(segment.getPath());
|
||||
return (T) list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
if (type == byte.class || type == Byte.class) {
|
||||
if(comp.getType(segment.getPath()) == NBTType.NBTTagByteArray) {
|
||||
if (segment.getIndex() >= 0) {
|
||||
byte[] array = comp.getByteArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Byte) array[segment.getIndex()];
|
||||
}
|
||||
} else {
|
||||
byte[] array = comp.getByteArray(segment.getPath());
|
||||
if(array != null) {
|
||||
return (T)(Byte) array[array.length + segment.getIndex()];
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NbtApiException("No fitting list/array found for " + segment.getPath() + " of type " + type);
|
||||
}
|
||||
throw new NbtApiException("Unable to get indexed value for type " + type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadWriteNBT resolveCompound(String key) {
|
||||
List<String> keys = PathUtil.splitPath(key);
|
||||
List<PathSegment> keys = PathUtil.splitPath(key);
|
||||
NBTCompound tag = this;
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
tag = tag.getCompound(keys.get(i));
|
||||
if (tag == null) {
|
||||
return null;
|
||||
PathSegment segment = keys.get(i);
|
||||
if (!segment.hasIndex()) {
|
||||
tag = tag.getCompound(segment.getPath());
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (tag.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& tag.getListType(segment.getPath()) == NBTType.NBTTagCompound) {
|
||||
NBTCompoundList list = tag.getCompoundList(segment.getPath());
|
||||
if (segment.getIndex() >= 0) {
|
||||
tag = list.get(segment.getIndex());
|
||||
} else {
|
||||
tag = list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
@@ -1102,12 +1276,25 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
|
||||
@Override
|
||||
public ReadWriteNBT resolveOrCreateCompound(String key) {
|
||||
List<String> keys = PathUtil.splitPath(key);
|
||||
List<PathSegment> keys = PathUtil.splitPath(key);
|
||||
NBTCompound tag = this;
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
tag = tag.getOrCreateCompound(keys.get(i));
|
||||
if (tag == null) {
|
||||
return null;
|
||||
PathSegment segment = keys.get(i);
|
||||
if (!segment.hasIndex()) {
|
||||
tag = tag.getOrCreateCompound(segment.getPath());
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (tag.getType(segment.getPath()) == NBTType.NBTTagList
|
||||
&& tag.getListType(segment.getPath()) == NBTType.NBTTagCompound) {
|
||||
NBTCompoundList list = tag.getCompoundList(segment.getPath());
|
||||
if (segment.getIndex() >= 0) {
|
||||
tag = list.get(segment.getIndex());
|
||||
} else {
|
||||
tag = list.get(list.size() + segment.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
@@ -1166,7 +1353,13 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
Object nbtbase = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET, name);
|
||||
if (nbtbase == null)
|
||||
return null;
|
||||
return NBTType.valueOf((byte) ReflectionMethod.COMPOUND_OWN_TYPE.run(nbtbase));
|
||||
return NBTType.valueOf((byte) ReflectionMethod.COMPOUND_OWN_TYPE_LEGACY.run(nbtbase));
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
Object o = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET, name);
|
||||
if (o == null)
|
||||
return null;
|
||||
return NBTType.fromName((String)ReflectionMethod.TAGTYPE_GET_NAME.run(ReflectionMethod.TAGTYPE_OWN_TYPE.run(o)));
|
||||
}
|
||||
Object o = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET_TYPE, name);
|
||||
if (o == null)
|
||||
@@ -1283,7 +1476,107 @@ public class NBTCompound implements ReadWriteNBT {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean isEqual(NBTCompound compA, NBTCompound compB, String key) {
|
||||
@Override
|
||||
public NBTCompound extractDifference(ReadableNBT other) {
|
||||
if (this == other)
|
||||
return new NBTContainer();
|
||||
|
||||
if (other instanceof NBTCompound) {
|
||||
return saveDiff(new NBTContainer(), this, (NBTCompound) other);
|
||||
} else {
|
||||
throw new NbtApiException("Unknown NBT object: " + other);
|
||||
}
|
||||
}
|
||||
|
||||
private static NBTCompound saveDiff(NBTCompound saveTo, NBTCompound compA, NBTCompound compB) {
|
||||
for (String key : compA.getKeys()) {
|
||||
saveDiff(saveTo, compA, compB, key);
|
||||
}
|
||||
return saveTo;
|
||||
}
|
||||
|
||||
private static void saveDiff(NBTCompound saveTo, NBTCompound compA, NBTCompound compB, String key) {
|
||||
boolean typeMismatch = compA.getType(key) != compB.getType(key);
|
||||
switch (compA.getType(key)) {
|
||||
case NBTTagByte:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setByte(key, compA.getByte(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagByteArray:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setByteArray(key, compA.getByteArray(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagCompound: {
|
||||
NBTCompound tmp1 = compA.getCompound(key);
|
||||
if (tmp1 == null) return;
|
||||
if (typeMismatch) {
|
||||
saveTo.addCompound(key).mergeCompound(tmp1);
|
||||
} else {
|
||||
NBTCompound tmp2 = compB.getCompound(key);
|
||||
if (tmp2 == null) {
|
||||
saveTo.addCompound(key).mergeCompound(tmp1);
|
||||
return;
|
||||
}
|
||||
NBTCompound tmpDiff = tmp1.extractDifference(tmp2);
|
||||
if (!tmpDiff.getKeys().isEmpty()) {
|
||||
saveTo.addCompound(key).mergeCompound(tmpDiff);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case NBTTagDouble:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setDouble(key, compA.getDouble(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagEnd:
|
||||
return; // ??
|
||||
case NBTTagFloat:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setFloat(key, compA.getFloat(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagInt:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setInteger(key, compA.getInteger(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagIntArray:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setIntArray(key, compA.getIntArray(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagList:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.set(key, NBTReflectionUtil.getEntry(compA, key));
|
||||
}
|
||||
return;
|
||||
case NBTTagLong:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setLong(key, compA.getLong(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagShort:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setShort(key, compA.getShort(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagString:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setString(key, compA.getString(key));
|
||||
}
|
||||
return;
|
||||
case NBTTagLongArray:
|
||||
if (typeMismatch || !isEqual(compA, compB, key)) {
|
||||
saveTo.setLongArray(key, compA.getLongArray(key));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEqual(NBTCompound compA, NBTCompound compB, String key) {
|
||||
if (compA.getType(key) != compB.getType(key))
|
||||
return false;
|
||||
switch (compA.getType(key)) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
@@ -56,7 +57,8 @@ public class NBTCompoundList extends NBTList<ReadWriteNBT> implements ReadWriteN
|
||||
}
|
||||
}
|
||||
|
||||
public NBTCompound addCompound(ReadWriteNBT comp) {
|
||||
@Override
|
||||
public ReadWriteNBT addCompound(ReadableNBT comp) {
|
||||
if (comp instanceof NBTCompound) {
|
||||
return addCompound((NBTCompound) comp);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ public class NBTContainer extends NBTCompound {
|
||||
|
||||
/**
|
||||
* Creates an empty, standalone NBTCompound
|
||||
*
|
||||
* @deprecated use {@link NBT#createNBTObject()}
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTContainer() {
|
||||
super(null, null);
|
||||
nbt = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
@@ -31,11 +34,13 @@ public class NBTContainer extends NBTCompound {
|
||||
* Takes in any NMS Compound to wrap it
|
||||
*
|
||||
* @param nbt
|
||||
* @deprecated Use NBT.wrapNMSTag
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTContainer(Object nbt) {
|
||||
super(null, null);
|
||||
if (nbt == null) {
|
||||
throw new NullPointerException("The NBT-Object can't be null!");
|
||||
nbt = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().isAssignableFrom(nbt.getClass())) {
|
||||
throw new NbtApiException("The object '" + nbt.getClass() + "' is not a valid NBT-Object!");
|
||||
@@ -47,7 +52,9 @@ public class NBTContainer extends NBTCompound {
|
||||
* Reads in a NBT InputStream
|
||||
*
|
||||
* @param inputsteam
|
||||
* @deprecated Use NBT.readNBT
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTContainer(InputStream inputsteam) {
|
||||
super(null, null);
|
||||
this.nbt = NBTReflectionUtil.readNBT(inputsteam);
|
||||
@@ -58,7 +65,9 @@ public class NBTContainer extends NBTCompound {
|
||||
* {@link NbtApiException} in case something goes wrong.
|
||||
*
|
||||
* @param nbtString
|
||||
* @deprecated Use NBT.parseNBT
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTContainer(String nbtString) {
|
||||
super(null, null);
|
||||
if (nbtString == null) {
|
||||
|
||||
@@ -40,8 +40,11 @@ public class NBTEntity extends NBTCompound {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated: Please use the NBT class
|
||||
*
|
||||
* @param entity Any valid Bukkit Entity
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTEntity(Entity entity) {
|
||||
super(null, null);
|
||||
if (entity == null) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
|
||||
|
||||
/**
|
||||
@@ -12,7 +13,7 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
|
||||
* @author tr7zw
|
||||
*
|
||||
*/
|
||||
public class NBTFile extends NBTCompound {
|
||||
public class NBTFile extends NBTCompound implements NBTFileHandle {
|
||||
|
||||
private final File file;
|
||||
private Object nbt;
|
||||
@@ -23,7 +24,9 @@ public class NBTFile extends NBTCompound {
|
||||
*
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* @deprecated Use NBT.getFileHandle(file)
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTFile(File file) throws IOException {
|
||||
super(null, null);
|
||||
if (file == null) {
|
||||
@@ -43,6 +46,7 @@ public class NBTFile extends NBTCompound {
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void save() throws IOException {
|
||||
try {
|
||||
getWriteLock().lock();
|
||||
@@ -55,6 +59,7 @@ public class NBTFile extends NBTCompound {
|
||||
/**
|
||||
* @return The File used to store the data
|
||||
*/
|
||||
@Override
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
@@ -77,7 +82,9 @@ public class NBTFile extends NBTCompound {
|
||||
* @param file file to read
|
||||
* @return NBTCompound holding file's nbt data
|
||||
* @throws IOException exception
|
||||
* @deprecated Use NBT.readFile(file)
|
||||
*/
|
||||
@Deprecated
|
||||
public static NBTCompound readFrom(File file) throws IOException {
|
||||
if (!file.exists())
|
||||
return new NBTContainer();
|
||||
@@ -92,7 +99,9 @@ public class NBTFile extends NBTCompound {
|
||||
* @param file file
|
||||
* @param nbt NBT data
|
||||
* @throws IOException exception
|
||||
* @deprecated Use NBT.writeFile(file, nbt)
|
||||
*/
|
||||
@Deprecated
|
||||
public static void saveTo(File file, NBTCompound nbt) throws IOException {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
|
||||
@@ -2,6 +2,8 @@ package de.tr7zw.changeme.nbtapi;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.GameprofileUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
@@ -13,7 +15,11 @@ public class NBTGameProfile {
|
||||
* @param profile
|
||||
* @return A NBTContainer with all the GameProfile data
|
||||
*/
|
||||
@Deprecated
|
||||
public static NBTCompound toNBT(GameProfile profile) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return (NBTCompound) GameprofileUtil.writeGameProfile(NBT.createNBTObject(), profile);
|
||||
}
|
||||
return new NBTContainer(ReflectionMethod.GAMEPROFILE_SERIALIZE.run(null,
|
||||
ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance(), profile));
|
||||
}
|
||||
@@ -24,9 +30,13 @@ public class NBTGameProfile {
|
||||
* @param compound Has to contain GameProfile data
|
||||
* @return The reconstructed GameProfile
|
||||
*/
|
||||
@Deprecated
|
||||
public static GameProfile fromNBT(NBTCompound compound) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return GameprofileUtil.readGameProfile(compound);
|
||||
}
|
||||
return (GameProfile) ReflectionMethod.GAMEPROFILE_DESERIALIZE.run(null,
|
||||
NBTReflectionUtil.gettoCompount(compound.getCompound(), compound));
|
||||
NBTReflectionUtil.getToCompount(compound.getCompound(), compound));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteItemNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
@@ -32,10 +33,13 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Constructor for NBTItems. The ItemStack will be cloned!
|
||||
* Constructor for NBTItems. The ItemStack will be cloned! Deprecated: Please
|
||||
* use the NBT class to work with items. It's up to 400% faster and provides
|
||||
* less ways to mess up code.
|
||||
*
|
||||
* @param item
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTItem(ItemStack item) {
|
||||
this(item, false);
|
||||
}
|
||||
@@ -130,11 +134,11 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
}
|
||||
if (ClassWrapper.CRAFT_ITEMSTACK.getClazz().isAssignableFrom(originalSrcStack.getClass())) {
|
||||
Object nmsStack = NBTReflectionUtil.getCraftItemHandle(originalSrcStack);
|
||||
ReflectionMethod.ITEMSTACK_SET_TAG.run(nmsStack, cachedCompound);
|
||||
NBTReflectionUtil.setItemStackCompound(nmsStack, cachedCompound);
|
||||
bukkitItem = originalSrcStack;
|
||||
} else {
|
||||
Object stack = ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, bukkitItem);
|
||||
ReflectionMethod.ITEMSTACK_SET_TAG.run(stack, cachedCompound);
|
||||
NBTReflectionUtil.setItemStackCompound(stack, cachedCompound);
|
||||
bukkitItem = (ItemStack) ReflectionMethod.ITEMSTACK_BUKKITMIRROR.run(null, stack);
|
||||
originalSrcStack.setItemMeta(bukkitItem.getItemMeta());
|
||||
}
|
||||
@@ -168,10 +172,10 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
}
|
||||
if (ClassWrapper.CRAFT_ITEMSTACK.getClazz().isAssignableFrom(bukkitItem.getClass())) {
|
||||
Object nmsStack = NBTReflectionUtil.getCraftItemHandle(bukkitItem);
|
||||
ReflectionMethod.ITEMSTACK_SET_TAG.run(nmsStack, compound);
|
||||
NBTReflectionUtil.setItemStackCompound(nmsStack, compound);
|
||||
} else {
|
||||
Object stack = ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, bukkitItem);
|
||||
ReflectionMethod.ITEMSTACK_SET_TAG.run(stack, compound);
|
||||
NBTReflectionUtil.setItemStackCompound(stack, compound);
|
||||
bukkitItem = (ItemStack) ReflectionMethod.ITEMSTACK_BUKKITMIRROR.run(null, stack);
|
||||
}
|
||||
}
|
||||
@@ -185,6 +189,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
*
|
||||
* @param item ItemStack that should get the new NBT data
|
||||
*/
|
||||
@Deprecated
|
||||
public void applyNBT(ItemStack item) {
|
||||
if (item == null || item.getType() == Material.AIR) {
|
||||
throw new NullPointerException("ItemStack can't be null/Air! This is not a NBTAPI bug!");
|
||||
@@ -199,6 +204,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
*
|
||||
* @param item ItemStack that should get the new NBT data
|
||||
*/
|
||||
@Deprecated
|
||||
public void mergeNBT(ItemStack item) {
|
||||
NBTItem nbti = new NBTItem(item);
|
||||
nbti.mergeCompound(this);
|
||||
@@ -210,10 +216,18 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
*
|
||||
* @param item ItemStack that should get the new NBT data
|
||||
*/
|
||||
@Deprecated
|
||||
public void mergeCustomNBT(ItemStack item) {
|
||||
if (item == null || item.getType() == Material.AIR) {
|
||||
throw new NullPointerException("ItemStack can't be null/Air!");
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
// 1.20.5+ doesn't have any vanilla tags
|
||||
NBT.modify(item, nbt -> {
|
||||
nbt.mergeCompound(this);
|
||||
});
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
NBTReflectionUtil.getUnhandledNBTTags(meta)
|
||||
.putAll(NBTReflectionUtil.getUnhandledNBTTags(bukkitItem.getItemMeta()));
|
||||
@@ -225,7 +239,12 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
*
|
||||
* @return true when custom tags are present
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean hasCustomNbtData() {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
// 1.20.5+ doesn't have any vanilla tags
|
||||
return hasNBTData();
|
||||
}
|
||||
finalizeChanges();
|
||||
ItemMeta meta = bukkitItem.getItemMeta();
|
||||
return !NBTReflectionUtil.getUnhandledNBTTags(meta).isEmpty();
|
||||
@@ -234,8 +253,14 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
/**
|
||||
* Remove all custom (non-vanilla) NBT tags from the NBTItem.
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearCustomNBT() {
|
||||
finalizeChanges();
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
// 1.20.5+ doesn't have any vanilla tags
|
||||
setCompound(null);
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = bukkitItem.getItemMeta();
|
||||
NBTReflectionUtil.getUnhandledNBTTags(meta).clear();
|
||||
bukkitItem.setItemMeta(meta);
|
||||
@@ -254,7 +279,8 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the item has NBT data.
|
||||
* Returns true if the item has NBT data. This needs to be checked before
|
||||
* calling methods like remove, otherwise the value might be wrong!
|
||||
*
|
||||
* @return Does the ItemStack have a NBTCompound.
|
||||
*/
|
||||
@@ -279,6 +305,10 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
bukkitItem.setItemMeta(meta);
|
||||
updateCachedCompound();
|
||||
if (directApply) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
throw new NbtApiException(
|
||||
"Direct apply mode meta changes don't work anymore in 1.20.5+. Please switch to the modern NBT.modify sytnax!");
|
||||
}
|
||||
applyNBT(originalSrcStack);
|
||||
}
|
||||
}
|
||||
@@ -312,6 +342,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
* @param item
|
||||
* @return Standalone {@link NBTContainer} with the Item's data
|
||||
*/
|
||||
@Deprecated
|
||||
public static NBTContainer convertItemtoNBT(ItemStack item) {
|
||||
return NBTReflectionUtil.convertNMSItemtoNBTCompound(ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, item));
|
||||
}
|
||||
@@ -324,6 +355,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
* @return ItemStack using the {@link NBTCompound}'s data
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public static ItemStack convertNBTtoItem(NBTCompound comp) {
|
||||
return (ItemStack) ReflectionMethod.ITEMSTACK_BUKKITMIRROR.run(null,
|
||||
NBTReflectionUtil.convertNBTCompoundtoNMSItem(comp));
|
||||
@@ -337,6 +369,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
* @param items
|
||||
* @return Standalone {@link NBTContainer} with the Item's data
|
||||
*/
|
||||
@Deprecated
|
||||
public static NBTContainer convertItemArraytoNBT(ItemStack[] items) {
|
||||
NBTContainer container = new NBTContainer();
|
||||
container.setInteger("size", items.length);
|
||||
@@ -365,6 +398,7 @@ public class NBTItem extends NBTCompound implements ReadWriteItemNBT {
|
||||
* @return ItemStack[] using the {@link NBTCompound}'s data
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public static ItemStack[] convertNBTtoItemArray(NBTCompound comp) {
|
||||
if (!comp.hasTag("size")) {
|
||||
return null;
|
||||
|
||||
@@ -304,8 +304,8 @@ public abstract class NBTList<T> implements List<T>, ReadWriteNBTList<T> {
|
||||
try {
|
||||
parent.getWriteLock().lock();
|
||||
int size = size();
|
||||
int id = -1;
|
||||
while ((id = indexOf(o)) != -1) {
|
||||
int id = indexOf(o);
|
||||
if (id != -1) {
|
||||
remove(id);
|
||||
}
|
||||
return size != size();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,21 +6,29 @@ import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.DataFixerUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.GsonWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.changeme.nbtapi.utils.ReflectionUtil;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.CodecHelper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
@@ -36,6 +44,12 @@ public class NBTReflectionUtil {
|
||||
|
||||
private static Field field_unhandledTags = null;
|
||||
private static Field field_handle = null;
|
||||
private static Object type_custom_data = null;
|
||||
private static Object registry_access = null;
|
||||
public static Codec<Object> itemstack_codec = null;
|
||||
public static DynamicOps<Object> nbtOps = null;
|
||||
public static DynamicOps<Object> nbtRegistryOps = null;
|
||||
public static Object problemReporter = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -50,6 +64,28 @@ public class NBTReflectionUtil {
|
||||
} catch (NoSuchFieldException e) {
|
||||
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
try {
|
||||
Field typeField = ReflectionUtil.getMappedField(ClassWrapper.NMS_DATACOMPONENTS.getClazz(), "net.minecraft.core.component.DataComponents#CUSTOM_DATA");
|
||||
type_custom_data = typeField.get(null);
|
||||
} catch (Exception e) {
|
||||
MinecraftVersion.getLogger().log(Level.WARNING,
|
||||
"Unable to find DataComponents#CUSTOM_DATA, NBTApi will not be able to read/write custom data on 1.20+",
|
||||
e);
|
||||
}
|
||||
try {
|
||||
Object nmsServer = ReflectionMethod.NMSSERVER_GETSERVER.run(Bukkit.getServer());
|
||||
registry_access = ReflectionMethod.NMSSERVER_GETREGISTRYACCESS.run(nmsServer);
|
||||
itemstack_codec = (Codec<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_ITEMSTACK.getClazz(), "net.minecraft.world.item.ItemStack#CODEC").get(null);
|
||||
nbtOps = (DynamicOps<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_NBTOPS.getClazz(), "net.minecraft.nbt.NbtOps#INSTANCE").get(null);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
nbtRegistryOps = (DynamicOps<Object>) ReflectionMethod.GET_SERIALIZATION_CONTEXT.run(registry_access, nbtOps);
|
||||
problemReporter = ReflectionUtil.getMappedField(ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), "net.minecraft.util.ProblemReporter#DISCARDING").get(null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +117,12 @@ public class NBTReflectionUtil {
|
||||
*/
|
||||
public static Object readNBT(InputStream stream) {
|
||||
try {
|
||||
return ReflectionMethod.NBTFILE_READ.run(null, stream);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R3)) {
|
||||
return ReflectionMethod.NBTFILE_READV2.run(null, stream,
|
||||
ReflectionMethod.NBTACCOUNTER_CREATE_UNLIMITED.run(null));
|
||||
} else {
|
||||
return ReflectionMethod.NBTFILE_READ.run(null, stream);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
stream.close();
|
||||
@@ -130,6 +171,9 @@ public class NBTReflectionUtil {
|
||||
public static void writeApiNBT(NBTCompound comp, OutputStream stream) {
|
||||
try {
|
||||
Object workingtag = comp.getResolvedObject();
|
||||
if (workingtag == null) {
|
||||
workingtag = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
|
||||
}
|
||||
ReflectionMethod.NBTFILE_WRITE.run(null, workingtag, stream);
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Exception while writing NBT!", e);
|
||||
@@ -145,13 +189,40 @@ public class NBTReflectionUtil {
|
||||
*/
|
||||
public static Object getItemRootNBTTagCompound(Object nmsitem) {
|
||||
try {
|
||||
Object answer = ReflectionMethod.NMSITEM_GETTAG.run(nmsitem);
|
||||
return answer;
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
Object customData = ReflectionMethod.NMSDATACOMPONENTHOLDER_GET.run(nmsitem, type_custom_data);
|
||||
if (customData == null) {
|
||||
return null;
|
||||
}
|
||||
return ReflectionMethod.NMSCUSTOMDATA_GETCOPY.run(customData);
|
||||
} else {
|
||||
Object answer = ReflectionMethod.NMSITEM_GETTAG.run(nmsitem);
|
||||
return answer;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Exception while getting an Itemstack's NBTCompound!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Compound as the Items NBT or CustomData
|
||||
*
|
||||
* @param nmsItem
|
||||
* @param compound
|
||||
*/
|
||||
public static void setItemStackCompound(Object nmsItem, Object compound) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
if (compound == null) {
|
||||
ReflectionMethod.NMSITEM_SET.run(nmsItem, new Object[] { type_custom_data, null });
|
||||
} else {
|
||||
ReflectionMethod.NMSITEM_SET.run(nmsItem, type_custom_data,
|
||||
ObjectCreator.NMS_CUSTOMDATA.getInstance(compound));
|
||||
}
|
||||
} else {
|
||||
ReflectionMethod.ITEMSTACK_SET_TAG.run(nmsItem, compound);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@link NBTCompound} to NMS ItemStacks
|
||||
*
|
||||
@@ -159,15 +230,35 @@ public class NBTReflectionUtil {
|
||||
* @return NMS ItemStack
|
||||
*/
|
||||
public static Object convertNBTCompoundtoNMSItem(NBTCompound nbtcompound) {
|
||||
Object nmsComp = null;
|
||||
try {
|
||||
Object nmsComp = gettoCompount(nbtcompound.getCompound(), nbtcompound);
|
||||
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_11_R1.getVersionId()) {
|
||||
nmsComp = getToCompount(nbtcompound.getCompound(), nbtcompound);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
if (nbtcompound.hasTag("DataVersion", NBTType.NBTTagInt)) {
|
||||
int dataVersion = nbtcompound.getInteger("DataVersion");
|
||||
int currentVersion = DataFixerUtil.getCurrentVersion();
|
||||
if (dataVersion < currentVersion) {
|
||||
nmsComp = DataFixerUtil.fixUpRawItemData(nmsComp, dataVersion, currentVersion);
|
||||
}
|
||||
} else if (nbtcompound.hasTag("tag") || nbtcompound.hasTag("Count")) {
|
||||
nmsComp = DataFixerUtil.fixUpRawItemData(nmsComp, DataFixerUtil.VERSION1_20_4, DataFixerUtil.getCurrentVersion());
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
return CodecHelper.convertNbtToItemStack(nmsComp);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
Optional<Object> opt = (Optional<Object>) ReflectionMethod.NMSITEM_LOAD_MODERN.run(null,
|
||||
registry_access, nmsComp);
|
||||
return opt.orElse(null);
|
||||
} else {
|
||||
return ReflectionMethod.NMSITEM_LOAD.run(null, registry_access, nmsComp);
|
||||
}
|
||||
} else if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_11_R1.getVersionId()) {
|
||||
return ObjectCreator.NMS_COMPOUNDFROMITEM.getInstance(nmsComp);
|
||||
} else {
|
||||
return ReflectionMethod.NMSITEM_CREATESTACK.run(null, nmsComp);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Exception while converting NBTCompound to NMS ItemStack!", e);
|
||||
throw new NbtApiException("Exception while converting NBTCompound to NMS ItemStack! " + nmsComp, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,8 +270,20 @@ public class NBTReflectionUtil {
|
||||
*/
|
||||
public static NBTContainer convertNMSItemtoNBTCompound(Object nmsitem) {
|
||||
try {
|
||||
Object answer = ReflectionMethod.NMSITEM_SAVE.run(nmsitem, ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance());
|
||||
return new NBTContainer(answer);
|
||||
NBTContainer container;
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
container = new NBTContainer(CodecHelper.convertItemStackToNbt(nmsitem));
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
container = new NBTContainer(ReflectionMethod.NMSITEM_SAVE_MODERN.run(nmsitem, registry_access));
|
||||
} else {
|
||||
Object answer = ReflectionMethod.NMSITEM_SAVE.run(nmsitem,
|
||||
ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance());
|
||||
container = new NBTContainer(answer);
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)) {
|
||||
container.setInteger("DataVersion", DataFixerUtil.getCurrentVersion());
|
||||
}
|
||||
return container;
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Exception while converting NMS ItemStack to NBTCompound!", e);
|
||||
}
|
||||
@@ -193,6 +296,7 @@ public class NBTReflectionUtil {
|
||||
* @return Map containing unhandled (custom) NBT tags
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static Map<String, Object> getUnhandledNBTTags(ItemMeta meta) {
|
||||
try {
|
||||
return (Map<String, Object>) field_unhandledTags.get(meta);
|
||||
@@ -210,7 +314,16 @@ public class NBTReflectionUtil {
|
||||
public static Object getEntityNBTTagCompound(Object nmsEntity) {
|
||||
try {
|
||||
Object nbt = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
|
||||
Object answer = ReflectionMethod.NMS_ENTITY_GET_NBT.run(nmsEntity, nbt);
|
||||
Object answer;
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
Object output = ReflectionMethod.NMS_GET_TAG_VALUE_OUTPUT.run(null, problemReporter, registry_access);
|
||||
|
||||
ReflectionMethod.NMS_ENTITY_GET_NBT_1216.run(nmsEntity, output);
|
||||
|
||||
answer = ReflectionMethod.NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND.run(output);
|
||||
} else {
|
||||
answer = ReflectionMethod.NMS_ENTITY_GET_NBT.run(nmsEntity, nbt);
|
||||
}
|
||||
if (answer == null)
|
||||
answer = nbt;
|
||||
return answer;
|
||||
@@ -228,7 +341,14 @@ public class NBTReflectionUtil {
|
||||
*/
|
||||
public static Object setEntityNBTTag(Object nbtTag, Object nmsEntity) {
|
||||
try {
|
||||
ReflectionMethod.NMS_ENTITY_SET_NBT.run(nmsEntity, nbtTag);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
Object valueInputTag = ReflectionMethod.NMS_GET_TAG_VALUE_INPUT.run(null, problemReporter, registry_access, nbtTag);
|
||||
|
||||
ReflectionMethod.NMS_ENTITY_SET_NBT_1216.run(nmsEntity, valueInputTag);
|
||||
} else {
|
||||
ReflectionMethod.NMS_ENTITY_SET_NBT.run(nmsEntity, nbtTag);
|
||||
}
|
||||
|
||||
return nmsEntity;
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Exception while setting the NBTCompound of an Entity", ex);
|
||||
@@ -254,8 +374,21 @@ public class NBTReflectionUtil {
|
||||
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
|
||||
}
|
||||
|
||||
if (o == null) {
|
||||
throw new NbtApiException("The passed BlockState(" + tile.getType()
|
||||
+ ") doesn't point to a BlockEntity. Only BlockEntities like Chest/Signs/Furnance/etc have NBT.");
|
||||
}
|
||||
|
||||
Object answer = null;
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_18_R1)) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
Object output = ReflectionMethod.NMS_GET_TAG_VALUE_OUTPUT.run(null, problemReporter, registry_access);
|
||||
|
||||
ReflectionMethod.TILEENTITY_GET_NBT_1216.run(o, output);
|
||||
|
||||
answer = ReflectionMethod.NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND.run(output);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
answer = ReflectionMethod.TILEENTITY_GET_NBT_1205.run(o, registry_access);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_18_R1)) {
|
||||
answer = ReflectionMethod.TILEENTITY_GET_NBT_1181.run(o);
|
||||
} else {
|
||||
answer = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
|
||||
@@ -288,7 +421,13 @@ public class NBTReflectionUtil {
|
||||
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
|
||||
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
Object valueInput = ReflectionMethod.NMS_GET_TAG_VALUE_INPUT.run(null, problemReporter, registry_access, comp);
|
||||
|
||||
ReflectionMethod.TILEENTITY_SET_NBT_1216.run(o, valueInput);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
ReflectionMethod.TILEENTITY_SET_NBT_1205.run(o, comp, registry_access);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
|
||||
ReflectionMethod.TILEENTITY_SET_NBT.run(o, comp);
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
Object blockData = ReflectionMethod.TILEENTITY_GET_BLOCKDATA.run(o);
|
||||
@@ -311,7 +450,11 @@ public class NBTReflectionUtil {
|
||||
public static Object getSubNBTTagCompound(Object compound, String name) {
|
||||
try {
|
||||
if ((boolean) ReflectionMethod.COMPOUND_HAS_KEY.run(compound, name)) {
|
||||
return ReflectionMethod.COMPOUND_GET_COMPOUND.run(compound, name);
|
||||
Object comp = ReflectionMethod.COMPOUND_GET_COMPOUND.run(compound, name);
|
||||
if (comp instanceof Optional) {
|
||||
return ((Optional<?>) comp).orElse(null);
|
||||
}
|
||||
return comp;
|
||||
} else {
|
||||
throw new NbtApiException("Tried getting invalid compound '" + name + "' from '" + compound + "'!");
|
||||
}
|
||||
@@ -335,10 +478,10 @@ public class NBTReflectionUtil {
|
||||
if (nbttag == null) {
|
||||
nbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!valideCompound(comp)) {
|
||||
if (!validCompound(comp)) {
|
||||
return;
|
||||
}
|
||||
Object workingtag = gettoCompount(nbttag, comp);
|
||||
Object workingtag = getToCompount(nbttag, comp);
|
||||
try {
|
||||
ReflectionMethod.COMPOUND_SET.run(workingtag, name,
|
||||
ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance());
|
||||
@@ -352,27 +495,36 @@ public class NBTReflectionUtil {
|
||||
* Checks if the Compound is correctly linked to it's roots
|
||||
*
|
||||
* @param comp
|
||||
* @return true if this is a valide Compound, else false
|
||||
* @return true if this is a valid Compound, else false
|
||||
*/
|
||||
public static boolean valideCompound(NBTCompound comp) {
|
||||
public static boolean validCompound(NBTCompound comp) {
|
||||
Object root = comp.getCompound();
|
||||
if (root instanceof Optional) {
|
||||
root = ((Optional<?>) root).orElse(null);
|
||||
}
|
||||
if (root == null) {
|
||||
root = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
Object tmp = gettoCompount(root, comp);
|
||||
Object tmp = getToCompount(root, comp);
|
||||
comp.setResolvedObject(tmp);
|
||||
return tmp != null;
|
||||
}
|
||||
|
||||
protected static Object gettoCompount(Object nbttag, NBTCompound comp) {
|
||||
public static Object getToCompount(Object nbttag, NBTCompound comp) {
|
||||
Deque<String> structure = new ArrayDeque<>();
|
||||
while (comp.getParent() != null) {
|
||||
structure.add(comp.getName());
|
||||
comp = comp.getParent();
|
||||
}
|
||||
if (nbttag instanceof Optional) {
|
||||
nbttag = ((Optional<?>) nbttag).orElse(null);
|
||||
}
|
||||
while (!structure.isEmpty()) {
|
||||
String target = structure.pollLast();
|
||||
nbttag = getSubNBTTagCompound(nbttag, target);
|
||||
if (nbttag instanceof Optional) {
|
||||
nbttag = ((Optional<?>) nbttag).orElse(null);
|
||||
}
|
||||
if (nbttag == null) {
|
||||
throw new NbtApiException("Unable to find tag '" + target + "' in " + nbttag);
|
||||
}
|
||||
@@ -395,9 +547,9 @@ public class NBTReflectionUtil {
|
||||
if (rootnbttag == null) {
|
||||
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!valideCompound(comp))
|
||||
if (!validCompound(comp))
|
||||
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
|
||||
Object workingtag = gettoCompount(rootnbttag, comp);
|
||||
Object workingtag = getToCompount(rootnbttag, comp);
|
||||
try {
|
||||
ReflectionMethod.COMPOUND_MERGE.run(workingtag, workingtagSrc);
|
||||
comp.setCompound(rootnbttag);
|
||||
@@ -406,22 +558,6 @@ public class NBTReflectionUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content for a given key inside a Compound
|
||||
*
|
||||
* @param comp
|
||||
* @param key
|
||||
* @return Content saved under this key
|
||||
*/
|
||||
public static String getContent(NBTCompound comp, String key) {
|
||||
Object workingtag = comp.getResolvedObject();
|
||||
try {
|
||||
return ReflectionMethod.COMPOUND_GET.run(workingtag, key).toString();
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Exception while getting the Content for key '" + key + "'!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a key in a {@link NBTCompound} to a given value
|
||||
*
|
||||
@@ -438,10 +574,10 @@ public class NBTReflectionUtil {
|
||||
if (rootnbttag == null) {
|
||||
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!valideCompound(comp)) {
|
||||
if (!validCompound(comp)) {
|
||||
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
|
||||
}
|
||||
Object workingtag = gettoCompount(rootnbttag, comp);
|
||||
Object workingtag = getToCompount(rootnbttag, comp);
|
||||
try {
|
||||
ReflectionMethod.COMPOUND_SET.run(workingtag, key, val);
|
||||
comp.setCompound(rootnbttag);
|
||||
@@ -466,7 +602,18 @@ public class NBTReflectionUtil {
|
||||
workingtag = dummyNBT.getCompound(); // it creates a new ListTag if needed, but its unlinked
|
||||
}
|
||||
try {
|
||||
Object nbt = ReflectionMethod.COMPOUND_GET_LIST.run(workingtag, key, type.getId());
|
||||
Object nbt = null;
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
nbt = ReflectionMethod.COMPOUND_GET_LIST.run(workingtag, key);
|
||||
if (nbt instanceof Optional) {
|
||||
nbt = ((Optional<?>) nbt).orElse(null);
|
||||
}
|
||||
if (nbt == null) {
|
||||
nbt = ClassWrapper.NMS_NBTTAGLIST.getClazz().newInstance();
|
||||
}
|
||||
} else {
|
||||
nbt = ReflectionMethod.COMPOUND_GET_LIST_LEGACY.run(workingtag, key, type.getId());
|
||||
}
|
||||
if (clazz == String.class) {
|
||||
return (NBTList<T>) new NBTStringList(comp, key, type, nbt);
|
||||
} else if (clazz == NBTListCompound.class) {
|
||||
@@ -498,6 +645,26 @@ public class NBTReflectionUtil {
|
||||
}
|
||||
try {
|
||||
Object nbt = ReflectionMethod.COMPOUND_GET.run(workingtag, key);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
if (nbt instanceof Optional) {
|
||||
nbt = ((Optional<?>) nbt).orElse(null);
|
||||
}
|
||||
if (nbt == null) {
|
||||
return NBTType.NBTTagEnd;
|
||||
}
|
||||
if (new NBTStringList(comp, key, NBTType.NBTTagString, nbt).isEmpty()) {
|
||||
return NBTType.NBTTagEnd;
|
||||
}
|
||||
Object compound = ReflectionMethod.LIST_GET.run(nbt, 0);
|
||||
if (compound instanceof Optional) {
|
||||
compound = ((Optional<?>) compound).orElse(null);
|
||||
}
|
||||
if (compound == null) {
|
||||
return NBTType.NBTTagEnd;
|
||||
}
|
||||
return NBTType.fromName((String) ReflectionMethod.TAGTYPE_GET_NAME
|
||||
.run(ReflectionMethod.TAGTYPE_OWN_TYPE.run(compound)));
|
||||
}
|
||||
String fieldname = "type";
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
|
||||
fieldname = "w";
|
||||
@@ -570,11 +737,11 @@ public class NBTReflectionUtil {
|
||||
public static void remove(NBTCompound comp, String key) {
|
||||
Object rootnbttag = comp.getCompound();
|
||||
if (rootnbttag == null) {
|
||||
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!valideCompound(comp))
|
||||
return;
|
||||
Object workingtag = gettoCompount(rootnbttag, comp);
|
||||
}
|
||||
if (!validCompound(comp))
|
||||
return;
|
||||
Object workingtag = getToCompount(rootnbttag, comp);
|
||||
ReflectionMethod.COMPOUND_REMOVE_KEY.run(workingtag, key);
|
||||
comp.setCompound(rootnbttag);
|
||||
}
|
||||
@@ -588,6 +755,9 @@ public class NBTReflectionUtil {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Set<String> getKeys(NBTCompound comp) {
|
||||
Object workingtag = comp.getResolvedObject();
|
||||
if (workingtag == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return (Set<String>) ReflectionMethod.COMPOUND_GET_KEYS.run(workingtag);
|
||||
}
|
||||
|
||||
@@ -608,9 +778,9 @@ public class NBTReflectionUtil {
|
||||
if (rootnbttag == null) {
|
||||
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
|
||||
}
|
||||
if (!valideCompound(comp))
|
||||
if (!validCompound(comp))
|
||||
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
|
||||
Object workingtag = gettoCompount(rootnbttag, comp);
|
||||
Object workingtag = getToCompount(rootnbttag, comp);
|
||||
type.run(workingtag, key, data);
|
||||
comp.setCompound(rootnbttag);
|
||||
}
|
||||
@@ -631,7 +801,41 @@ public class NBTReflectionUtil {
|
||||
if (workingtag == null) {
|
||||
workingtag = dummyNBT.getCompound();
|
||||
}
|
||||
return type.run(workingtag, key);
|
||||
if (workingtag instanceof Optional<?>) {
|
||||
workingtag = ((Optional<Object>) workingtag).orElseGet(() -> dummyNBT.getCompound());
|
||||
}
|
||||
Object obj = type.run(workingtag, key);
|
||||
if (obj instanceof Optional<?>) {
|
||||
return ((Optional<Object>) obj).orElseGet(() -> getDefaultValue(type));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static Object getDefaultValue(ReflectionMethod type) {
|
||||
if (type == ReflectionMethod.COMPOUND_GET_STRING) {
|
||||
return "";
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_BYTE) {
|
||||
return (byte) 0;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_SHORT) {
|
||||
return (short) 0;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_BOOLEAN) {
|
||||
return false;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_INT) {
|
||||
return 0;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_LONG) {
|
||||
return 0L;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_FLOAT) {
|
||||
return 0.0f;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_DOUBLE) {
|
||||
return 0.0d;
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_BYTEARRAY) {
|
||||
return new byte[0];
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_INTARRAY) {
|
||||
return new int[0];
|
||||
} else if (type == ReflectionMethod.COMPOUND_GET_LONGARRAY) {
|
||||
return new long[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Optional;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
@@ -21,7 +22,11 @@ public class NBTStringList extends NBTList<String> {
|
||||
@Override
|
||||
public String get(int index) {
|
||||
try {
|
||||
return (String) ReflectionMethod.LIST_GET_STRING.run(listObject, index);
|
||||
Object ret = ReflectionMethod.LIST_GET_STRING.run(listObject, index);
|
||||
if (ret instanceof Optional<?>) {
|
||||
return ((Optional<String>) ret).orElse("");
|
||||
}
|
||||
return (String) ret;
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException(ex);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class NBTTileEntity extends NBTCompound {
|
||||
* @param tile BlockState from any TileEntity
|
||||
* @param readonly Readonly makes a copy at init, only reading from that copy
|
||||
*/
|
||||
public NBTTileEntity(BlockState tile, boolean readonly) {
|
||||
protected NBTTileEntity(BlockState tile, boolean readonly) {
|
||||
super(null, null);
|
||||
if (tile == null || (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3) && !tile.isPlaced())) {
|
||||
throw new NullPointerException("Tile can't be null/not placed!");
|
||||
@@ -41,8 +41,11 @@ public class NBTTileEntity extends NBTCompound {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated: Please use the NBT class
|
||||
*
|
||||
* @param tile BlockState from any TileEntity
|
||||
*/
|
||||
@Deprecated
|
||||
public NBTTileEntity(BlockState tile) {
|
||||
super(null, null);
|
||||
if (tile == null || (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3) && !tile.isPlaced())) {
|
||||
|
||||
@@ -8,14 +8,16 @@ package de.tr7zw.changeme.nbtapi;
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public enum NBTType {
|
||||
NBTTagEnd(0), NBTTagByte(1), NBTTagShort(2), NBTTagInt(3), NBTTagLong(4), NBTTagFloat(5), NBTTagDouble(6),
|
||||
NBTTagByteArray(7), NBTTagString(8), NBTTagList(9), NBTTagCompound(10), NBTTagIntArray(11), NBTTagLongArray(12);
|
||||
NBTTagEnd(0, ""), NBTTagByte(1, "BYTE"), NBTTagShort(2, "SHORT"), NBTTagInt(3, "INT"), NBTTagLong(4, "LONG"), NBTTagFloat(5, "FLOAT"), NBTTagDouble(6, "DOUBLE"),
|
||||
NBTTagByteArray(7, "BYTE[]"), NBTTagString(8, "STRING"), NBTTagList(9, "LIST"), NBTTagCompound(10, "COMPOUND"), NBTTagIntArray(11, "INT[]"), NBTTagLongArray(12, "LONG[]");
|
||||
|
||||
NBTType(int i) {
|
||||
NBTType(int i, String name) {
|
||||
id = i;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @return Id used by Minecraft internally
|
||||
@@ -23,6 +25,13 @@ public enum NBTType {
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name of the NBTType
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id Internal Minecraft id
|
||||
@@ -35,4 +44,11 @@ public enum NBTType {
|
||||
return NBTType.NBTTagEnd;
|
||||
}
|
||||
|
||||
public static NBTType fromName(String name) {
|
||||
for (NBTType t : values())
|
||||
if (t.getName().equals(name))
|
||||
return t;
|
||||
return NBTType.NBTTagEnd;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,16 +29,6 @@ public class NbtApiException extends RuntimeException {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
* @param enableSuppression
|
||||
* @param writableStackTrace
|
||||
*/
|
||||
public NbtApiException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(generateMessage(message), cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.tr7zw.changeme.nbtapi.iface;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface NBTFileHandle extends ReadWriteNBT {
|
||||
|
||||
/**
|
||||
* Saves the data to the file
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void save() throws IOException;
|
||||
|
||||
/**
|
||||
* @return The File used to store the data
|
||||
*/
|
||||
File getFile();
|
||||
|
||||
}
|
||||
@@ -203,6 +203,10 @@ public interface ReadWriteNBT extends ReadableNBT {
|
||||
|
||||
@Override
|
||||
ReadWriteNBTCompoundList getCompoundList(String name);
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
ReadWriteNBT resolveCompound(String key);
|
||||
|
||||
/**
|
||||
* Remove all keys from this compound
|
||||
|
||||
+9
@@ -10,6 +10,15 @@ public interface ReadWriteNBTCompoundList extends ReadableNBTList<ReadWriteNBT>
|
||||
* @return A new instance of the class.
|
||||
*/
|
||||
ReadWriteNBT addCompound();
|
||||
|
||||
/**
|
||||
* Adds a copy of the Compound to the end of the List and returns it. When null
|
||||
* is given, a new Compound will be created
|
||||
*
|
||||
* @param comp
|
||||
* @return
|
||||
*/
|
||||
ReadWriteNBT addCompound(ReadableNBT comp);
|
||||
|
||||
/**
|
||||
* Removes the element at the specified position in this list
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -344,6 +353,17 @@ public interface ReadableNBT {
|
||||
*/
|
||||
void writeCompound(OutputStream stream);
|
||||
|
||||
/**
|
||||
* Compares this readable nbt to the other one
|
||||
* and returns the difference.
|
||||
* <p>Note: the result will only contain data that is present
|
||||
* in this readable nbt and is missing/different in the provided one.
|
||||
*
|
||||
* @param other other readable nbt
|
||||
* @return difference between readable nbts
|
||||
*/
|
||||
ReadWriteNBT extractDifference(ReadableNBT other);
|
||||
|
||||
/**
|
||||
* @return The NBT as printable NBT-Json.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import com.mojang.datafixers.DSL.TypeReference;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTReflectionUtil;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
public class DataFixerUtil {
|
||||
|
||||
// https://minecraft.wiki/w/Data_version
|
||||
public static final int VERSION1_12R1 = 1343;
|
||||
public static final int VERSION1_16R1 = 2586;
|
||||
public static final int VERSION1_17R1 = 2730;
|
||||
public static final int VERSION1_18R1 = 2975;
|
||||
public static final int VERSION1_19R1 = 3120;
|
||||
public static final int VERSION1_19R3 = 3337;
|
||||
public static final int VERSION1_20R1 = 3465;
|
||||
public static final int VERSION1_20R2 = 3578;
|
||||
public static final int VERSION1_20R3 = 3700;
|
||||
public static final int VERSION1_20R4 = 3837;
|
||||
public static final int VERSION1_21R1 = 3953;
|
||||
public static final int VERSION1_21R2 = 4080;
|
||||
public static final int VERSION1_21R3 = 4189;
|
||||
public static final int VERSION1_21R4 = 4323;
|
||||
public static final int VERSION1_21R5 = 4435;
|
||||
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;
|
||||
// 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;
|
||||
@Deprecated
|
||||
public static final int VERSION1_16_5 = 2586;
|
||||
@Deprecated
|
||||
public static final int VERSION1_17_1 = 2730;
|
||||
@Deprecated
|
||||
public static final int VERSION1_18_2 = 2975;
|
||||
@Deprecated
|
||||
public static final int VERSION1_19_2 = 3120;
|
||||
@Deprecated
|
||||
public static final int VERSION1_19_4 = 3337;
|
||||
@Deprecated
|
||||
public static final int VERSION1_20_1 = 3465;
|
||||
@Deprecated
|
||||
public static final int VERSION1_20_2 = 3578;
|
||||
@Deprecated
|
||||
public static final int VERSION1_20_4 = 3700;
|
||||
@Deprecated
|
||||
public static final int VERSION1_20_5 = 3837;
|
||||
// the 1.21 versions use Revision instead of patch versions, unlike the other above. kept for compatibility
|
||||
@Deprecated
|
||||
public static final int VERSION1_21 = 3953;
|
||||
@Deprecated
|
||||
public static final int VERSION1_21_2 = 4080;
|
||||
@Deprecated
|
||||
public static final int VERSION1_21_3 = 4189;
|
||||
@Deprecated
|
||||
public static final int VERSION1_21_4 = 4323;
|
||||
@Deprecated
|
||||
public static final int VERSION1_21_5 = 4435;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object fixUpRawItemData(Object nbt, int fromVersion, int toVersion)
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
DataFixer dataFixer = (DataFixer) ReflectionMethod.GET_DATAFIXER.run(null);
|
||||
TypeReference itemStackReference = (TypeReference) ReflectionUtil.getMappedField(ClassWrapper.NMS_REFERENCES.getClazz(),"net.minecraft.util.datafix.fixes.References#ITEM_STACK").get(null);
|
||||
DynamicOps<Object> nbtOps = (DynamicOps<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_NBTOPS.getClazz(), "net.minecraft.nbt.NbtOps#INSTANCE").get(null);
|
||||
Dynamic<Object> fixed = dataFixer.update(itemStackReference, new Dynamic<Object>(nbtOps, nbt), fromVersion,
|
||||
toVersion);
|
||||
return fixed.getValue();
|
||||
}
|
||||
|
||||
public static ReadWriteNBT fixUpItemData(ReadWriteNBT nbt, int fromVersion, int toVersion)
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
ReadWriteNBT tag = NBT.wrapNMSTag(fixUpRawItemData(
|
||||
NBTReflectionUtil.getToCompount(((NBTCompound) nbt).getCompound(), ((NBTCompound) nbt)), fromVersion,
|
||||
toVersion));
|
||||
tag.setInteger("DataVersion", toVersion);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static ReadWriteNBT fixUpItemData(ReadWriteNBT nbt, int fromVersion)
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
return fixUpItemData(nbt, fromVersion, getCurrentVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return the closest or exact version number of the current
|
||||
* server. Only contains versions people will reasonably use and will fail with
|
||||
* an exception, when the target version is before 1.12.2. (Assuming no one will
|
||||
* update 1.8 items to 1.11, if so, provide the version numbers to the converter
|
||||
* method directly)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getCurrentVersion() {
|
||||
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;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
return VERSION1_21R6;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
|
||||
return VERSION1_21R5;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
return VERSION1_21R4;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R3)) {
|
||||
return VERSION1_21R3;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R2)) {
|
||||
return VERSION1_21R2;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R1)) {
|
||||
return VERSION1_21R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return VERSION1_20R4;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R3)) {
|
||||
return VERSION1_20R3;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R1)) {
|
||||
return VERSION1_20R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_19_R3)) {
|
||||
return VERSION1_19R3;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_19_R1)) {
|
||||
return VERSION1_19R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_18_R1)) {
|
||||
return VERSION1_18R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
|
||||
return VERSION1_17R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
return VERSION1_16R1;
|
||||
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)) {
|
||||
return VERSION1_12R1;
|
||||
}
|
||||
throw new NbtApiException(
|
||||
"Trying to update data *to* a version before 1.12.2? Something is probably going wrong, contact the plugin author.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList;
|
||||
|
||||
public class GameprofileUtil {
|
||||
|
||||
private static Method GET_NAME = null;
|
||||
private static Method GET_ID = null;
|
||||
private static Method GET_VALUE = null;
|
||||
private static Method GET_SIGNATURE = null;
|
||||
private static Method GET_PROPERTY_NAME = null;
|
||||
private static Method GET_PROPERTIES = null;
|
||||
|
||||
static {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
GET_NAME = GameProfile.class.getDeclaredMethod("name");
|
||||
GET_ID = GameProfile.class.getDeclaredMethod("id");
|
||||
GET_VALUE = com.mojang.authlib.properties.Property.class.getDeclaredMethod("value");
|
||||
GET_SIGNATURE = com.mojang.authlib.properties.Property.class.getDeclaredMethod("signature");
|
||||
GET_PROPERTY_NAME = com.mojang.authlib.properties.Property.class.getDeclaredMethod("name");
|
||||
GET_PROPERTIES = GameProfile.class.getDeclaredMethod("properties");
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GameProfile readGameProfile(ReadableNBT arg) {
|
||||
String string = null;
|
||||
UUID uUID = null;
|
||||
if (arg.hasTag("Name") && arg.getType("Name") == NBTType.NBTTagString) {
|
||||
string = arg.getString("Name");
|
||||
} else if (arg.hasTag("name") && arg.getType("name") == NBTType.NBTTagString) {
|
||||
string = arg.getString("name");
|
||||
}
|
||||
if (arg.hasTag("Id") && arg.getType("Id") == NBTType.NBTTagIntArray && arg.getIntArray("Id").length == 4) {
|
||||
uUID = arg.getUUID("Id");
|
||||
} else if (arg.hasTag("id") && arg.getType("id") == NBTType.NBTTagIntArray
|
||||
&& arg.getIntArray("id").length == 4) {
|
||||
uUID = arg.getUUID("id");
|
||||
}
|
||||
try {
|
||||
GameProfile gameProfile = new GameProfile(uUID, string);
|
||||
if (arg.hasTag("Properties") && arg.getType("Properties") == NBTType.NBTTagCompound) {
|
||||
ReadableNBT compoundTag = arg.getCompound("Properties");
|
||||
for (String string2 : compoundTag.getKeys()) {
|
||||
ReadableNBTList<ReadWriteNBT> listTag = compoundTag.getCompoundList(string);
|
||||
for (int i = 0; i < listTag.size(); ++i) {
|
||||
ReadableNBT compoundTag2 = listTag.get(i);
|
||||
String string3 = compoundTag2.getString("Value");
|
||||
if (compoundTag2.hasTag("Signature")
|
||||
&& compoundTag2.getType("Signature") == NBTType.NBTTagString) {
|
||||
gameProfile.getProperties().put(string2, new com.mojang.authlib.properties.Property(string2,
|
||||
string3, compoundTag2.getString("Signature")));
|
||||
} else {
|
||||
gameProfile.getProperties().put(string2,
|
||||
new com.mojang.authlib.properties.Property(string2, string3));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (arg.getType("properties") == NBTType.NBTTagList) { // 1.20.5+
|
||||
ReadableNBTList<ReadWriteNBT> listTag = arg.getCompoundList("properties");
|
||||
for (int i = 0; i < listTag.size(); ++i) {
|
||||
ReadableNBT compoundTag2 = listTag.get(i);
|
||||
String string2 = compoundTag2.getString("name");
|
||||
String string3 = compoundTag2.getString("value");
|
||||
if (compoundTag2.hasTag("signature")
|
||||
&& compoundTag2.getType("signature") == NBTType.NBTTagString) {
|
||||
gameProfile.getProperties().put(string2, new com.mojang.authlib.properties.Property(string2,
|
||||
string3, compoundTag2.getString("signature")));
|
||||
} else {
|
||||
gameProfile.getProperties().put(string2,
|
||||
new com.mojang.authlib.properties.Property(string2, string3));
|
||||
}
|
||||
}
|
||||
}
|
||||
return gameProfile;
|
||||
} catch (Throwable var11) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadWriteNBT writeGameProfile(ReadWriteNBT arg, GameProfile gameProfile) {
|
||||
String name = getName(gameProfile);
|
||||
if (!(name == null || name.isEmpty())) {
|
||||
String nameKey = MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) ? "name" : "Name";
|
||||
arg.setString(nameKey, getName(gameProfile));
|
||||
}
|
||||
UUID id = getId(gameProfile);
|
||||
if (id != null) {
|
||||
String idKey = MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) ? "id" : "Id";
|
||||
arg.setUUID(idKey, id);
|
||||
}
|
||||
PropertyMap properties = getProperties(gameProfile);
|
||||
if (!properties.isEmpty()) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
ReadWriteNBTCompoundList list = arg.getCompoundList("properties");
|
||||
for (com.mojang.authlib.properties.Property property : properties.values()) {
|
||||
ReadWriteNBT tag = list.addCompound();
|
||||
tag.setString("name", getPropertyName(property));
|
||||
tag.setString("value", getValue(property));
|
||||
if (property.hasSignature()) {
|
||||
tag.setString("signature", getSignature(property));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ReadWriteNBT compoundTag = arg.getOrCreateCompound("Properties");
|
||||
for (String string : gameProfile.getProperties().keySet()) {
|
||||
ReadWriteNBTCompoundList list = compoundTag.getCompoundList(string);
|
||||
for (com.mojang.authlib.properties.Property property : properties.get(string)) {
|
||||
ReadWriteNBT tag = list.addCompound();
|
||||
tag.setString("Value", getValue(property));
|
||||
if (property.hasSignature()) {
|
||||
tag.setString("Signature", getSignature(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
private static String getName(GameProfile profile) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return GET_NAME.invoke(profile).toString();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get GameProfile name via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return profile.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private static UUID getId(GameProfile profile) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return (UUID) GET_ID.invoke(profile);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get GameProfile id via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return profile.getId();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue(com.mojang.authlib.properties.Property property) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return GET_VALUE.invoke(property).toString();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get Property value via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return property.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSignature(com.mojang.authlib.properties.Property property) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return GET_SIGNATURE.invoke(property).toString();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get Property signature via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return property.getSignature();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPropertyName(com.mojang.authlib.properties.Property property) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return GET_PROPERTY_NAME.invoke(property).toString();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get Property name via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return property.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private static PropertyMap getProperties(GameProfile profile) {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
|
||||
try {
|
||||
return (PropertyMap) GET_PROPERTIES.invoke(profile);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw new NbtApiException("Failed to get GameProfile properties via reflection", e);
|
||||
}
|
||||
} else {
|
||||
return profile.getProperties();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,881 +0,0 @@
|
||||
/*
|
||||
* This Metrics class was auto-generated and can be copied into your project if you are
|
||||
* not using a build tool like Gradle or Maven for dependency management.
|
||||
*
|
||||
* IMPORTANT: You are not allowed to modify this class, except changing the package.
|
||||
*
|
||||
* Disallowed modifications include but are not limited to:
|
||||
* - Remove the option for users to opt-out
|
||||
* - Change the frequency for data submission
|
||||
* - Obfuscate the code (every obfuscator should allow you to make an exception for specific files)
|
||||
* - Reformat the code (if you use a linter, add an exception)
|
||||
*
|
||||
* Violations will result in a ban of your plugin and account from bStats.
|
||||
*/
|
||||
package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
private final MetricsBase metricsBase;
|
||||
|
||||
/**
|
||||
* Creates a new Metrics instance.
|
||||
*
|
||||
* @param plugin Your plugin instance.
|
||||
* @param serviceId The id of the service. It can be found at <a
|
||||
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(JavaPlugin plugin, int serviceId) {
|
||||
this.plugin = plugin;
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true);
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
config.addDefault("logFailedRequests", false);
|
||||
config.addDefault("logSentData", false);
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
// Inform the server owners about bStats
|
||||
config
|
||||
.options()
|
||||
.header(
|
||||
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
|
||||
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
|
||||
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
|
||||
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
|
||||
+ "anonymous.")
|
||||
.copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
// Load the data
|
||||
boolean enabled = config.getBoolean("enabled", true);
|
||||
String serverUUID = config.getString("serverUuid");
|
||||
boolean logErrors = config.getBoolean("logFailedRequests", false);
|
||||
boolean logSentData = config.getBoolean("logSentData", false);
|
||||
boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
metricsBase =
|
||||
new MetricsBase(
|
||||
"bukkit",
|
||||
serverUUID,
|
||||
serviceId,
|
||||
enabled,
|
||||
this::appendPlatformData,
|
||||
this::appendServiceData,
|
||||
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
|
||||
plugin::isEnabled,
|
||||
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
|
||||
(message) -> this.plugin.getLogger().log(Level.INFO, message),
|
||||
logErrors,
|
||||
logSentData,
|
||||
logResponseStatusText);
|
||||
}
|
||||
|
||||
/** Shuts down the underlying scheduler service. */
|
||||
public void shutdown() {
|
||||
metricsBase.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
metricsBase.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void appendPlatformData(JsonObjectBuilder builder) {
|
||||
builder.appendField("playerAmount", getPlayerAmount());
|
||||
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
|
||||
builder.appendField("bukkitVersion", Bukkit.getVersion());
|
||||
builder.appendField("bukkitName", Bukkit.getName());
|
||||
builder.appendField("javaVersion", System.getProperty("java.version"));
|
||||
builder.appendField("osName", System.getProperty("os.name"));
|
||||
builder.appendField("osArch", System.getProperty("os.arch"));
|
||||
builder.appendField("osVersion", System.getProperty("os.version"));
|
||||
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
private void appendServiceData(JsonObjectBuilder builder) {
|
||||
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
|
||||
}
|
||||
|
||||
private int getPlayerAmount() {
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed from an array to a collection,
|
||||
// This fixes java.lang.NoSuchMethodError:
|
||||
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
return onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception e) {
|
||||
// Just use the new method if the reflection failed
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetricsBase {
|
||||
|
||||
/** The version of the Metrics class. */
|
||||
public static final String METRICS_VERSION = "3.0.2";
|
||||
|
||||
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private final String platform;
|
||||
|
||||
private final String serverUuid;
|
||||
|
||||
private final int serviceId;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
|
||||
|
||||
private final Consumer<Runnable> submitTaskConsumer;
|
||||
|
||||
private final Supplier<Boolean> checkServiceEnabledSupplier;
|
||||
|
||||
private final BiConsumer<String, Throwable> errorLogger;
|
||||
|
||||
private final Consumer<String> infoLogger;
|
||||
|
||||
private final boolean logErrors;
|
||||
|
||||
private final boolean logSentData;
|
||||
|
||||
private final boolean logResponseStatusText;
|
||||
|
||||
private final Set<CustomChart> customCharts = new HashSet<>();
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Creates a new MetricsBase class instance.
|
||||
*
|
||||
* @param platform The platform of the service.
|
||||
* @param serviceId The id of the service.
|
||||
* @param serverUuid The server uuid.
|
||||
* @param enabled Whether or not data sending is enabled.
|
||||
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all platform-specific data.
|
||||
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all service-specific data.
|
||||
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
|
||||
* used to delegate the data collection to a another thread to prevent errors caused by
|
||||
* concurrency. Can be {@code null}.
|
||||
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
|
||||
* @param errorLogger A consumer that accepts log message and an error.
|
||||
* @param infoLogger A consumer that accepts info log messages.
|
||||
* @param logErrors Whether or not errors should be logged.
|
||||
* @param logSentData Whether or not the sent data should be logged.
|
||||
* @param logResponseStatusText Whether or not the response status text should be logged.
|
||||
*/
|
||||
public MetricsBase(
|
||||
String platform,
|
||||
String serverUuid,
|
||||
int serviceId,
|
||||
boolean enabled,
|
||||
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
|
||||
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
|
||||
Consumer<Runnable> submitTaskConsumer,
|
||||
Supplier<Boolean> checkServiceEnabledSupplier,
|
||||
BiConsumer<String, Throwable> errorLogger,
|
||||
Consumer<String> infoLogger,
|
||||
boolean logErrors,
|
||||
boolean logSentData,
|
||||
boolean logResponseStatusText) {
|
||||
ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(1, task -> new Thread(task, "bStats-Metrics"));
|
||||
// We want delayed tasks (non-periodic) that will execute in the future to be
|
||||
// cancelled when the scheduler is shutdown.
|
||||
// Otherwise, we risk preventing the server from shutting down even when
|
||||
// MetricsBase#shutdown() is called
|
||||
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
this.scheduler = scheduler;
|
||||
this.platform = platform;
|
||||
this.serverUuid = serverUuid;
|
||||
this.serviceId = serviceId;
|
||||
this.enabled = enabled;
|
||||
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
|
||||
this.appendServiceDataConsumer = appendServiceDataConsumer;
|
||||
this.submitTaskConsumer = submitTaskConsumer;
|
||||
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
|
||||
this.errorLogger = errorLogger;
|
||||
this.infoLogger = infoLogger;
|
||||
this.logErrors = logErrors;
|
||||
this.logSentData = logSentData;
|
||||
this.logResponseStatusText = logResponseStatusText;
|
||||
checkRelocation();
|
||||
if (enabled) {
|
||||
// WARNING: Removing the option to opt-out will get your plugin banned from
|
||||
// bStats
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
this.customCharts.add(chart);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
private void startSubmitting() {
|
||||
final Runnable submitTask =
|
||||
() -> {
|
||||
if (!enabled || !checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown();
|
||||
return;
|
||||
}
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept(this::submitData);
|
||||
} else {
|
||||
this.submitData();
|
||||
}
|
||||
};
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven
|
||||
// distribution of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into
|
||||
// the initial and second delay.
|
||||
// WARNING: You must not modify and part of this Metrics class, including the
|
||||
// submit delay or frequency!
|
||||
// WARNING: Modifying this code will get your plugin banned on bStats. Just
|
||||
// don't do it!
|
||||
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
|
||||
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
|
||||
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
|
||||
scheduler.scheduleAtFixedRate(
|
||||
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void submitData() {
|
||||
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder);
|
||||
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder);
|
||||
JsonObjectBuilder.JsonObject[] chartData =
|
||||
customCharts.stream()
|
||||
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(JsonObjectBuilder.JsonObject[]::new);
|
||||
serviceJsonBuilder.appendField("id", serviceId);
|
||||
serviceJsonBuilder.appendField("customCharts", chartData);
|
||||
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
|
||||
baseJsonBuilder.appendField("serverUUID", serverUuid);
|
||||
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
|
||||
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
|
||||
scheduler.execute(
|
||||
() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Could not submit bStats metrics data", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
|
||||
if (logSentData) {
|
||||
infoLogger.accept("Sent bStats metrics data: " + data.toString());
|
||||
}
|
||||
String url = String.format(REPORT_URL, platform);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
|
||||
connection.setDoOutput(true);
|
||||
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (BufferedReader bufferedReader =
|
||||
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
if (logResponseStatusText) {
|
||||
infoLogger.accept("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks that the class was properly relocated. */
|
||||
private void checkRelocation() {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null
|
||||
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this
|
||||
// little "trick" ... :D
|
||||
final String defaultPackage =
|
||||
new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
|
||||
final String examplePackage =
|
||||
new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure no one just copy & pastes the example and uses the wrong
|
||||
// package names
|
||||
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|
||||
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given string.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped string.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()});
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CustomChart {
|
||||
|
||||
private final String chartId;
|
||||
|
||||
protected CustomChart(String chartId) {
|
||||
if (chartId == null) {
|
||||
throw new IllegalArgumentException("chartId must not be null");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
public JsonObjectBuilder.JsonObject getRequestJsonObject(
|
||||
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
|
||||
JsonObjectBuilder builder = new JsonObjectBuilder();
|
||||
builder.appendField("chartId", chartId);
|
||||
try {
|
||||
JsonObjectBuilder.JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
builder.appendField("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
|
||||
}
|
||||
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An extremely simple JSON builder.
|
||||
*
|
||||
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
|
||||
* for its use-case.
|
||||
*/
|
||||
public static class JsonObjectBuilder {
|
||||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
|
||||
private boolean hasAtLeastOneField = false;
|
||||
|
||||
public JsonObjectBuilder() {
|
||||
builder.append("{");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a null field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendNull(String key) {
|
||||
appendFieldUnescaped(key, "null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("JSON value must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int value) {
|
||||
appendFieldUnescaped(key, String.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param object The object.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject object) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("JSON object must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, object.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The string array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values)
|
||||
.map(value -> "\"" + escape(value) + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a field to the object.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param escapedValue The escaped value of the field.
|
||||
*/
|
||||
private void appendFieldUnescaped(String key, String escapedValue) {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("JSON key must not be null");
|
||||
}
|
||||
if (hasAtLeastOneField) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
|
||||
hasAtLeastOneField = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the JSON string and invalidates this builder.
|
||||
*
|
||||
* @return The built JSON string.
|
||||
*/
|
||||
public JsonObject build() {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
JsonObject object = new JsonObject(builder.append("}").toString());
|
||||
builder = null;
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
|
||||
*
|
||||
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
|
||||
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
|
||||
*
|
||||
* @param value The value to escape.
|
||||
* @return The escaped value.
|
||||
*/
|
||||
private static String escape(String value) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '"') {
|
||||
builder.append("\\\"");
|
||||
} else if (c == '\\') {
|
||||
builder.append("\\\\");
|
||||
} else if (c <= '\u000F') {
|
||||
builder.append("\\u000").append(Integer.toHexString(c));
|
||||
} else if (c <= '\u001F') {
|
||||
builder.append("\\u00").append(Integer.toHexString(c));
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A super simple representation of a JSON object.
|
||||
*
|
||||
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
|
||||
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
|
||||
* JsonObject)}.
|
||||
*/
|
||||
public static class JsonObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
private JsonObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,21 @@
|
||||
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;
|
||||
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.DrilldownPie;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
/**
|
||||
* This class acts as the "Brain" of the NBTApi. It contains the main logger for
|
||||
* other classes,registers bStats and checks rather Maven shading was done
|
||||
@@ -21,11 +30,15 @@ public enum MinecraftVersion {
|
||||
MC1_7_R4(174), MC1_8_R3(183), MC1_9_R1(191), MC1_9_R2(192), MC1_10_R1(1101), MC1_11_R1(1111), MC1_12_R1(1121),
|
||||
MC1_13_R1(1131), MC1_13_R2(1132), MC1_14_R1(1141), MC1_15_R1(1151), MC1_16_R1(1161), MC1_16_R2(1162),
|
||||
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_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(260100, true), MC26_2(260200, true);
|
||||
|
||||
private static MinecraftVersion version;
|
||||
private static Boolean hasGsonSupport;
|
||||
private static Boolean isForgePresent;
|
||||
private static Boolean isNeoForgePresent;
|
||||
private static Boolean isFabricPresent;
|
||||
private static Boolean isFoliaPresent;
|
||||
private static boolean bStatsDisabled = false;
|
||||
private static boolean disablePackageWarning = false;
|
||||
@@ -36,11 +49,38 @@ public enum MinecraftVersion {
|
||||
private static Logger logger = Logger.getLogger("NBTAPI");
|
||||
|
||||
// NBT-API Version
|
||||
protected static final String VERSION = "2.12.0-SNAPSHOT";
|
||||
protected static final String VERSION = "2.16.0";
|
||||
|
||||
private final int versionId;
|
||||
private final boolean mojangMapping;
|
||||
|
||||
// TODO: not nice
|
||||
private static final Map<String, MinecraftVersion> VERSION_TO_REVISION = new HashMap<String, MinecraftVersion>() {
|
||||
{
|
||||
this.put("1.20", MC1_20_R1);
|
||||
this.put("1.20.1", MC1_20_R1);
|
||||
this.put("1.20.2", MC1_20_R2);
|
||||
this.put("1.20.3", MC1_20_R3);
|
||||
this.put("1.20.4", MC1_20_R3);
|
||||
this.put("1.20.5", MC1_20_R4);
|
||||
this.put("1.20.6", MC1_20_R4);
|
||||
this.put("1.21", MC1_21_R1);
|
||||
this.put("1.21.1", MC1_21_R1);
|
||||
this.put("1.21.2", MC1_21_R2);
|
||||
this.put("1.21.3", MC1_21_R2);
|
||||
this.put("1.21.4", MC1_21_R3);
|
||||
this.put("1.21.5", MC1_21_R4);
|
||||
this.put("1.21.6", MC1_21_R5);
|
||||
this.put("1.21.7", MC1_21_R5);
|
||||
this.put("1.21.8", MC1_21_R5);
|
||||
this.put("1.21.9", MC1_21_R6);
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
MinecraftVersion(int versionId) {
|
||||
this(versionId, false);
|
||||
}
|
||||
@@ -73,7 +113,11 @@ public enum MinecraftVersion {
|
||||
*/
|
||||
public String getPackageName() {
|
||||
if (this == UNKNOWN) {
|
||||
return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
try {
|
||||
return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
} catch (Exception ex) {
|
||||
// ignore, paper without remap, will fail
|
||||
}
|
||||
}
|
||||
return this.name().replace("MC", "v");
|
||||
}
|
||||
@@ -108,18 +152,36 @@ public enum MinecraftVersion {
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
final String ver = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
logger.info("[NBTAPI] Found Spigot: " + ver + "! Trying to find NMS support");
|
||||
try {
|
||||
final String ver = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
logger.info("[NBTAPI] Found Minecraft: " + ver + "! Trying to find NMS support");
|
||||
version = MinecraftVersion.valueOf(ver.replace("v", "MC"));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
version = MinecraftVersion.UNKNOWN;
|
||||
} catch (Exception ex) {
|
||||
logger.info("[NBTAPI] Found Minecraft: " + Bukkit.getServer().getBukkitVersion().split("-")[0]
|
||||
+ "! Trying to find NMS support");
|
||||
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!");
|
||||
} else {
|
||||
logger.warning("[NBTAPI] This Server-Version(" + ver + ") is not supported by this NBT-API Version("
|
||||
+ VERSION + ") located in " + VersionChecker.getPlugin()
|
||||
logger.warning("[NBTAPI] This Server-Version(" + Bukkit.getServer().getBukkitVersion()
|
||||
+ ") is not supported by this NBT-API Version(" + VERSION + ") located in "
|
||||
+ VersionChecker.getPlugin()
|
||||
+ ". The NBT-API will try to work as good as it can! Some functions may not work!");
|
||||
}
|
||||
init();
|
||||
@@ -131,13 +193,70 @@ public enum MinecraftVersion {
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this
|
||||
// little "trick" ... :D (from bStats)
|
||||
final String defaultPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'c', 'h',
|
||||
'a', 'n', 'g', 'e', 'm', 'e', '.', 'n', 'b', 't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
|
||||
final String reservedPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'n', 'b',
|
||||
't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
|
||||
try {
|
||||
if (hasGsonSupport() && !bStatsDisabled) {
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin(VersionChecker.getPlugin());
|
||||
if (plugin != null && plugin instanceof JavaPlugin) {
|
||||
getLogger()
|
||||
.info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
|
||||
new Metrics((JavaPlugin) plugin, 1058);
|
||||
Metrics metrics = new Metrics((JavaPlugin) plugin, 1058);
|
||||
metrics.addCustomChart(new SimplePie("nbtapi_version", () -> {
|
||||
return VERSION;
|
||||
}));
|
||||
metrics.addCustomChart(new DrilldownPie("nms_version", () -> {
|
||||
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||
Map<String, Integer> entry = new HashMap<>();
|
||||
entry.put(Bukkit.getName(), 1);
|
||||
map.put(getVersion().name(), entry);
|
||||
return map;
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("shaded", () -> {
|
||||
return Boolean.toString(!"NBTAPI".equals(VersionChecker.getPlugin()));
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("server_software", () -> {
|
||||
return Bukkit.getName();
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("parent_plugin", () -> {
|
||||
return VersionChecker.getPluginforBStats();
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("parent_plugin_type", () -> {
|
||||
return VersionChecker.getPluginType();
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("special_environment", () -> {
|
||||
if (isFoliaPresent()) {
|
||||
return "Folia";
|
||||
} else if (isForgePresent()) {
|
||||
return "Forge";
|
||||
} else if (isFabricPresent()) {
|
||||
return "Fabric";
|
||||
} else if (isNeoForgePresent()) {
|
||||
return "NeoForge";
|
||||
} else {
|
||||
return "None";
|
||||
}
|
||||
}));
|
||||
metrics.addCustomChart(new SimplePie("bindings_check", () -> {
|
||||
|
||||
boolean failedBinding = false;
|
||||
for (ClassWrapper c : ClassWrapper.values()) {
|
||||
if (c.isEnabled() && c.getClazz() == null) {
|
||||
failedBinding = true;
|
||||
}
|
||||
}
|
||||
for (ReflectionMethod method : ReflectionMethod.values()) {
|
||||
if (method.isCompatible() && !method.isLoaded()) {
|
||||
failedBinding = true;
|
||||
}
|
||||
}
|
||||
|
||||
return failedBinding ? "Failed" : "Pass";
|
||||
}));
|
||||
} else if (plugin == null) {
|
||||
getLogger().info("[NBTAPI] Unable to create a bStats instance!!");
|
||||
}
|
||||
@@ -154,12 +273,6 @@ public enum MinecraftVersion {
|
||||
logger.log(Level.WARNING, "[NBTAPI] Error while checking for updates! Error: " + ex.getMessage());
|
||||
}
|
||||
}).start();
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this
|
||||
// little "trick" ... :D (from bStats)
|
||||
final String defaultPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'c', 'h',
|
||||
'a', 'n', 'g', 'e', 'm', 'e', '.', 'n', 'b', 't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
|
||||
final String reservedPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'n', 'b',
|
||||
't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
|
||||
if (!disablePackageWarning && MinecraftVersion.class.getPackage().getName().equals(defaultPackage)) {
|
||||
logger.warning(
|
||||
"#########################################- NBTAPI -#########################################");
|
||||
@@ -219,6 +332,22 @@ public enum MinecraftVersion {
|
||||
return hasGsonSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, if Fabric is present
|
||||
*/
|
||||
public static boolean isFabricPresent() {
|
||||
if (isFabricPresent != null) {
|
||||
return isFabricPresent;
|
||||
}
|
||||
try {
|
||||
logger.info("[NBTAPI] Found Fabric: " + Class.forName("net.fabricmc.api.ModInitializer"));
|
||||
isFabricPresent = true;
|
||||
} catch (Exception ex) {
|
||||
isFabricPresent = false;
|
||||
}
|
||||
return isFabricPresent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, if Forge is present
|
||||
*/
|
||||
@@ -236,6 +365,22 @@ public enum MinecraftVersion {
|
||||
}
|
||||
return isForgePresent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, if NeoForge is present
|
||||
*/
|
||||
public static boolean isNeoForgePresent() {
|
||||
if (isNeoForgePresent != null) {
|
||||
return isNeoForgePresent;
|
||||
}
|
||||
try {
|
||||
logger.info("[NBTAPI] Found NeoForge: " + Class.forName("net.neoforged.neoforge.common.NeoForge"));
|
||||
isNeoForgePresent = true;
|
||||
} catch (Exception ex) {
|
||||
isNeoForgePresent = false;
|
||||
}
|
||||
return isNeoForgePresent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True, if Folia is present
|
||||
@@ -245,8 +390,7 @@ public enum MinecraftVersion {
|
||||
return isFoliaPresent;
|
||||
}
|
||||
try {
|
||||
logger.info("[NBTAPI] Found Folia: "
|
||||
+ Class.forName("io.papermc.paper.threadedregions.RegionizedServer"));
|
||||
logger.info("[NBTAPI] Found Folia: " + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"));
|
||||
isFoliaPresent = true;
|
||||
} catch (Exception ex) {
|
||||
isFoliaPresent = false;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
public class NBTJsonUtil {
|
||||
|
||||
/**
|
||||
* 1.20.3-1.21.4 only. Used to convert items into Json, used in Chat Hover Components.
|
||||
*
|
||||
* @param itemStack
|
||||
* @return
|
||||
* @throws NbtApiException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JsonElement itemStackToJson(ItemStack itemStack) {
|
||||
try {
|
||||
Codec<Object> itemStackCodec = (Codec<Object>) ClassWrapper.NMS_ITEMSTACK.getClazz()
|
||||
.getField(MojangToMapping.getMapping().get("net.minecraft.world.item.ItemStack#CODEC")).get(null);
|
||||
Object stack = ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, itemStack);
|
||||
DataResult<JsonElement> result = itemStackCodec.encode(stack, JsonOps.INSTANCE,
|
||||
JsonOps.INSTANCE.emptyMap());
|
||||
Optional<JsonElement> opt = (Optional<JsonElement>) result.getClass().getMethod("result").invoke(result);
|
||||
return opt.orElse(null);
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Error trying to get Json of an ItemStack.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,17 +8,53 @@ import java.util.regex.Pattern;
|
||||
public final class PathUtil {
|
||||
|
||||
private static final Pattern pattern = Pattern.compile("[^\\\\](\\.)");
|
||||
private static final Pattern indexPattern = Pattern.compile(".*\\[(-?[0-9]+)\\]");
|
||||
|
||||
public static List<String> splitPath(String path) {
|
||||
List<String> list = new ArrayList<>();
|
||||
public static List<PathSegment> splitPath(String path) {
|
||||
List<PathSegment> list = new ArrayList<>();
|
||||
Matcher matcher = pattern.matcher(path);
|
||||
int startIndex = 0;
|
||||
while (matcher.find(startIndex)) {
|
||||
list.add(path.substring(startIndex, matcher.end() - 1).replace("\\.", "."));
|
||||
list.add(new PathSegment(path.substring(startIndex, matcher.end() - 1).replace("\\.", ".")));
|
||||
startIndex = matcher.end();
|
||||
}
|
||||
list.add(path.substring(startIndex).replace("\\.", "."));
|
||||
list.add(new PathSegment(path.substring(startIndex).replace("\\.", ".")));
|
||||
return list;
|
||||
}
|
||||
|
||||
public static class PathSegment {
|
||||
|
||||
private final String path;
|
||||
private final Integer index;
|
||||
|
||||
private PathSegment(String path) {
|
||||
Matcher matcher = indexPattern.matcher(path);
|
||||
if (matcher.find()) {
|
||||
this.path = path.substring(0, path.indexOf("["));
|
||||
this.index = Integer.parseInt(matcher.group(1));
|
||||
} else {
|
||||
this.path = path;
|
||||
this.index = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public boolean hasIndex() {
|
||||
return index != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathSegment [path=" + path + ", index=" + index + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +1,24 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
|
||||
|
||||
public final class ReflectionUtil {
|
||||
|
||||
private static Field field_modifiers;
|
||||
|
||||
static {
|
||||
|
||||
public static Field getMappedField(Class<?> clazz, String mapping) {
|
||||
String mojmapName = mapping.split("#")[1];
|
||||
try {
|
||||
field_modifiers = Field.class.getDeclaredField("modifiers");
|
||||
field_modifiers.setAccessible(true);
|
||||
} catch (NoSuchFieldException ex) {
|
||||
try {
|
||||
// This hacky workaround is for newer jdk versions 11+?
|
||||
Method fieldGetter = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
|
||||
fieldGetter.setAccessible(true);
|
||||
Field[] fields = (Field[]) fieldGetter.invoke(Field.class, false);
|
||||
for (Field f : fields)
|
||||
if (f.getName().equals("modifiers")) {
|
||||
field_modifiers = f;
|
||||
field_modifiers.setAccessible(true);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException(e);
|
||||
}
|
||||
return clazz.getField(mojmapName);
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
// not Mojamp, try remapped
|
||||
}
|
||||
if (field_modifiers == null) {
|
||||
throw new NbtApiException("Unable to init the modifiers Field.");
|
||||
try {
|
||||
return clazz.getDeclaredField(MojangToMapping.getMapping().get(mapping));
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Unable to find field " + mapping + " in class " + clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field makeNonFinal(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
int mods = field.getModifiers();
|
||||
if (Modifier.isFinal(mods)) {
|
||||
field_modifiers.set(field, mods & ~Modifier.FINAL);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
public static void setFinal(Object obj, Field field, Object newValue)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
field.setAccessible(true);
|
||||
field = makeNonFinal(field);
|
||||
field.set(obj, newValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -109,7 +109,20 @@ public class VersionChecker {
|
||||
|
||||
protected static String getPlugin() {
|
||||
ClassLoader classLoader = VersionChecker.class.getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream("plugin.yml");
|
||||
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
|
||||
if (inputStream != null) {
|
||||
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
|
||||
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
|
||||
return pluginYml.getString("name");
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This can happen if the paper-plugin.yml is not formatted correctly
|
||||
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading paper-plugin.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
inputStream = classLoader.getResourceAsStream("plugin.yml");
|
||||
|
||||
if (inputStream != null) {
|
||||
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
|
||||
@@ -117,9 +130,67 @@ public class VersionChecker {
|
||||
return pluginYml.getString("name");
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This can happen if the plugin.yml is not formatted correctly
|
||||
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading plugin.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return NBTItem.class.getPackage().getName();
|
||||
}
|
||||
|
||||
protected static String getPluginforBStats() {
|
||||
ClassLoader classLoader = VersionChecker.class.getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
|
||||
if (inputStream != null) {
|
||||
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
|
||||
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
|
||||
return pluginYml.getString("name");
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This can happen if the paper-plugin.yml is not formatted correctly
|
||||
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading paper-plugin.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
inputStream = classLoader.getResourceAsStream("plugin.yml");
|
||||
|
||||
if (inputStream != null) {
|
||||
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
|
||||
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
|
||||
return pluginYml.getString("name");
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This can happen if the plugin.yml is not formatted correctly
|
||||
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading plugin.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return "UnknownPlugin";
|
||||
}
|
||||
|
||||
protected static String getPluginType() {
|
||||
ClassLoader classLoader = VersionChecker.class.getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
}
|
||||
return "PaperPlugin";
|
||||
}
|
||||
|
||||
inputStream = classLoader.getResourceAsStream("plugin.yml");
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
}
|
||||
return "SpigotPlugin";
|
||||
}
|
||||
return "UnknownPlugin";
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -4,6 +4,8 @@ import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.getLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
|
||||
/**
|
||||
@@ -18,9 +20,11 @@ public enum ClassWrapper {
|
||||
CRAFT_METAITEM(PackageWrapper.CRAFTBUKKIT, "inventory.CraftMetaItem", null, null),
|
||||
CRAFT_ENTITY(PackageWrapper.CRAFTBUKKIT, "entity.CraftEntity", null, null),
|
||||
CRAFT_WORLD(PackageWrapper.CRAFTBUKKIT, "CraftWorld", null, null),
|
||||
CRAFT_SERVER(PackageWrapper.CRAFTBUKKIT, "CraftServer", null, null),
|
||||
CRAFT_PERSISTENTDATACONTAINER(PackageWrapper.CRAFTBUKKIT, "persistence.CraftPersistentDataContainer",
|
||||
MinecraftVersion.MC1_14_R1, null),
|
||||
NMS_NBTBASE(PackageWrapper.NMS, "NBTBase", null, null, "net.minecraft.nbt", "net.minecraft.nbt.Tag"),
|
||||
NMS_TAGTYPE(PackageWrapper.NMS, "NBTTagType", MinecraftVersion.MC1_21_R4, null, "net.minecraft.nbt", "net.minecraft.nbt.TagType"),
|
||||
NMS_NBTTAGSTRING(PackageWrapper.NMS, "NBTTagString", null, null, "net.minecraft.nbt",
|
||||
"net.minecraft.nbt.StringTag"),
|
||||
NMS_NBTTAGINT(PackageWrapper.NMS, "NBTTagInt", null, null, "net.minecraft.nbt", "net.minecraft.nbt.IntTag"),
|
||||
@@ -62,6 +66,38 @@ public enum ClassWrapper {
|
||||
"net.minecraft.nbt.NbtUtils"),
|
||||
NMS_IBLOCKDATA(PackageWrapper.NMS, "IBlockData", MinecraftVersion.MC1_8_R3, null,
|
||||
"net.minecraft.world.level.block.state", "net.minecraft.world.level.block.state.BlockState"),
|
||||
NMS_NBTACCOUNTER(PackageWrapper.NMS, "NBTReadLimiter", MinecraftVersion.MC1_20_R3, null, "net.minecraft.nbt",
|
||||
"net.minecraft.nbt.NbtAccounter"),
|
||||
NMS_CUSTOMDATA(PackageWrapper.NMS, "CustomData", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.world.item.component", "net.minecraft.world.item.component.CustomData"),
|
||||
NMS_DATACOMPONENTTYPE(PackageWrapper.NMS, "DataComponentType", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.core.component", "net.minecraft.core.component.DataComponentType"),
|
||||
NMS_DATACOMPONENTS(PackageWrapper.NMS, "DataComponents", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.core.component", "net.minecraft.core.component.DataComponents"),
|
||||
NMS_DATACOMPONENTHOLDER(PackageWrapper.NMS, "DataComponentHolder", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.core.component", "net.minecraft.core.component.DataComponentHolder"),
|
||||
NMS_PROVIDER(PackageWrapper.NMS, "HolderLookup$a", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.core", "net.minecraft.core.HolderLookup$Provider"),
|
||||
NMS_SERVER(PackageWrapper.NMS, "MinecraftServer", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.server", "net.minecraft.server.MinecraftServer"),
|
||||
NMS_DATAFIXERS(PackageWrapper.NMS, "DataConverterRegistry", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.util.datafix", "net.minecraft.util.datafix.DataFixers"),
|
||||
NMS_REFERENCES(PackageWrapper.NMS, "DataConverterTypes", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.util.datafix.fixes", "net.minecraft.util.datafix.fixes.References"),
|
||||
NMS_NBTOPS(PackageWrapper.NMS, "DynamicOpsNBT", MinecraftVersion.MC1_20_R4, null,
|
||||
"net.minecraft.nbt", "net.minecraft.nbt.NbtOps"),
|
||||
NMS_PROBLEM_REPORTER(PackageWrapper.NMS, "ProblemReporter", MinecraftVersion.MC1_21_R5, null,
|
||||
"net.minecraft.util", "net.minecraft.util.ProblemReporter"),
|
||||
NMS_TAG_VALUE_INPUT(PackageWrapper.NMS, "TagValueInput", MinecraftVersion.MC1_21_R5, null,
|
||||
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.TagValueInput"),
|
||||
NMS_VALUE_INPUT(PackageWrapper.NMS, "ValueInput", MinecraftVersion.MC1_21_R5, null,
|
||||
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.ValueInput"),
|
||||
NMS_TAG_VALUE_OUTPUT(PackageWrapper.NMS, "TagValueOutput", MinecraftVersion.MC1_21_R5, null,
|
||||
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.TagValueOutput"),
|
||||
NMS_VALUE_OUTPUT(PackageWrapper.NMS, "ValueOutput", MinecraftVersion.MC1_21_R5, null,
|
||||
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.ValueOutput"),
|
||||
NMS_DYNAMICOPS(PackageWrapper.NONE, "DynamicOps", MinecraftVersion.MC1_21_R5, null,
|
||||
"com.mojang.serialization", "com.mojang.serialization.DynamicOps"),
|
||||
GAMEPROFILE(PackageWrapper.NONE, "com.mojang.authlib.GameProfile", MinecraftVersion.MC1_8_R3, null);
|
||||
|
||||
private Class<?> clazz;
|
||||
@@ -99,7 +135,11 @@ public enum ClassWrapper {
|
||||
} else if (MinecraftVersion.isForgePresent() && MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4
|
||||
&& Forge1710Mappings.getClassMappings().get(this.name()) != null) {
|
||||
clazz = Class.forName(clazzName = Forge1710Mappings.getClassMappings().get(this.name()));
|
||||
} else if (packageId == PackageWrapper.CRAFTBUKKIT) {
|
||||
// this also works for un-remapped Paper 1.20+
|
||||
clazz = Class.forName(Bukkit.getServer().getClass().getPackage().getName() + "." + clazzName);
|
||||
} else {
|
||||
// fallback for old versions pre mojmap and in the nms package
|
||||
String version = MinecraftVersion.getVersion().getPackageName();
|
||||
clazz = Class.forName(packageId.getUri() + "." + version + "." + clazzName);
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils.nmsmappings;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTReflectionUtil;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
|
||||
public class CodecHelper {
|
||||
|
||||
public static Object convertItemStackToNbt(Object itemStack) {
|
||||
Object result = null;
|
||||
try {
|
||||
// FIXME caching, this has 0 exception handling
|
||||
result = NBTReflectionUtil.itemstack_codec.encodeStart(NBTReflectionUtil.nbtRegistryOps, itemStack);
|
||||
Objects.requireNonNull(result);
|
||||
return ((Optional<Object>)result.getClass().getMethod("result").invoke(result)).get();
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Failed to convert ItemStack to NBT. " + result + " " + itemStack, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object convertNbtToItemStack(Object nbt) {
|
||||
Object result = null;
|
||||
try {
|
||||
// FIXME caching, this has 0 exception handling
|
||||
result = NBTReflectionUtil.itemstack_codec.parse(NBTReflectionUtil.nbtRegistryOps, nbt);
|
||||
Objects.requireNonNull(result);
|
||||
return ((Optional<Object>)result.getClass().getMethod("result").invoke(result)).get();
|
||||
} catch (Exception e) {
|
||||
throw new NbtApiException("Failed to convert NBT to ItemStack. " + result + " " + nbt, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+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");
|
||||
|
||||
+228
-3
@@ -1,12 +1,15 @@
|
||||
package de.tr7zw.changeme.nbtapi.utils.nmsmappings;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
|
||||
/**
|
||||
* Temporary solution to hold Mojang to unmapped Spigot mappings.
|
||||
* Note years later: nothing is more permanent than a temporary solution.
|
||||
*
|
||||
* @author tr7zw
|
||||
*
|
||||
@@ -72,7 +75,7 @@ public class MojangToMapping {
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId()", "n");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "q");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#load(net.minecraft.nbt.CompoundTag)", "a");
|
||||
put("net.minecraft.server.level.ServerLevel#getBlockState(net.minecraft.core.BlockPos)", "c_");
|
||||
put("net.minecraft.server.level.ServerLevel#getBlockEntity(net.minecraft.core.BlockPos)", "c_");
|
||||
}
|
||||
|
||||
};
|
||||
@@ -120,11 +123,231 @@ public class MojangToMapping {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_20R2 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_20R1);
|
||||
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bu");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_20R3 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_20R2);
|
||||
|
||||
put("net.minecraft.nbt.NbtIo#readCompressed(java.io.InputStream,net.minecraft.nbt.NbtAccounter)", "a");
|
||||
put("net.minecraft.nbt.NbtAccounter#unlimitedHeap()", "a");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bw");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId()", "p");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "r");
|
||||
put("net.minecraft.world.item.ItemStack#CODEC", "a");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_20R4 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_20R3);
|
||||
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bC");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "n");
|
||||
put("net.minecraft.core.component.DataComponents#CUSTOM_DATA", "b");
|
||||
put("net.minecraft.core.component.DataComponentHolder#get(net.minecraft.core.component.DataComponentType)", "a");
|
||||
put("net.minecraft.world.item.component.CustomData#copyTag()", "c");
|
||||
put("net.minecraft.world.item.ItemStack#set(net.minecraft.core.component.DataComponentType,java.lang.Object)", "b");
|
||||
put("net.minecraft.world.item.ItemStack#save(net.minecraft.core.HolderLookup$Provider)", "a");
|
||||
put("net.minecraft.server.MinecraftServer#registryAccess()", "bc");
|
||||
put("net.minecraft.world.item.ItemStack#parseOptional(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)", "a");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId(net.minecraft.core.HolderLookup$Provider)", "c");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#loadWithComponents(net.minecraft.nbt.CompoundTag,net.minecraft.core.HolderLookup$Provider)", "c");
|
||||
put("net.minecraft.util.datafix.DataFixers#getDataFixer()", "a");
|
||||
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "t");
|
||||
put("net.minecraft.nbt.NbtOps#INSTANCE", "a");
|
||||
put("net.minecraft.world.item.ItemStack#CODEC", "b");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R1 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_20R4);
|
||||
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bD");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R2 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R1);
|
||||
|
||||
put("net.minecraft.server.MinecraftServer#registryAccess()", "ba");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bK");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "m");
|
||||
put("net.minecraft.world.item.ItemStack#CODEC", "a");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R3 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R2);
|
||||
|
||||
put("net.minecraft.world.item.component.CustomData#copyTag()", "d");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R4 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R3);
|
||||
|
||||
put("net.minecraft.nbt.CompoundTag#getShort(java.lang.String)", "d");
|
||||
put("net.minecraft.nbt.CompoundTag#getString(java.lang.String)", "i");
|
||||
put("net.minecraft.nbt.CompoundTag#contains(java.lang.String)", "b");
|
||||
put("net.minecraft.nbt.CompoundTag#getDouble(java.lang.String)", "h");
|
||||
put("net.minecraft.nbt.CompoundTag#getByteArray(java.lang.String)", "j");
|
||||
put("net.minecraft.nbt.CompoundTag#getFloat(java.lang.String)", "g");
|
||||
put("net.minecraft.nbt.CompoundTag#get(java.lang.String)", "a");
|
||||
put("net.minecraft.nbt.CompoundTag#getLong(java.lang.String)", "f");
|
||||
put("net.minecraft.nbt.CompoundTag#getLongArray(java.lang.String)", "l");
|
||||
put("net.minecraft.nbt.CompoundTag#getInt(java.lang.String)", "e");
|
||||
put("net.minecraft.nbt.CompoundTag#getIntArray(java.lang.String)", "k");
|
||||
put("net.minecraft.nbt.CompoundTag#getCompound(java.lang.String)", "m");
|
||||
put("net.minecraft.nbt.CompoundTag#getByte(java.lang.String)", "c");
|
||||
put("net.minecraft.nbt.ListTag#getString(int)", "m");
|
||||
put("net.minecraft.world.entity.Entity#saveWithoutId(net.minecraft.nbt.CompoundTag)", "h");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bI");
|
||||
put("net.minecraft.world.entity.Entity#load(net.minecraft.nbt.CompoundTag)", "i");
|
||||
put("net.minecraft.nbt.Tag#getType()", "c");
|
||||
put("net.minecraft.nbt.TagType#getName()", "a");
|
||||
put("net.minecraft.nbt.CompoundTag#getList(java.lang.String)", "o");
|
||||
put("net.minecraft.world.item.ItemStack#parse(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.Tag)", "a");
|
||||
put("net.minecraft.world.item.ItemStack#CODEC", "b");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R5 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R3);
|
||||
put("net.minecraft.core.HolderLookup$Provider#createSerializationContext(com.mojang.serialization.DynamicOps)", "a");
|
||||
put("net.minecraft.nbt.CompoundTag#getByteArray(java.lang.String)", "j");
|
||||
put("net.minecraft.nbt.CompoundTag#getDouble(java.lang.String)", "h");
|
||||
put("net.minecraft.nbt.CompoundTag#keySet()", "e");
|
||||
put("net.minecraft.nbt.CompoundTag#getLong(java.lang.String)", "f");
|
||||
put("net.minecraft.nbt.CompoundTag#getList(java.lang.String)", "o");
|
||||
put("net.minecraft.nbt.CompoundTag#getInt(java.lang.String)", "e");
|
||||
put("net.minecraft.nbt.CompoundTag#getCompound(java.lang.String)", "m");
|
||||
put("net.minecraft.nbt.CompoundTag#getByte(java.lang.String)", "c");
|
||||
put("net.minecraft.nbt.CompoundTag#getShort(java.lang.String)", "d");
|
||||
put("net.minecraft.nbt.CompoundTag#getIntArray(java.lang.String)", "k");
|
||||
put("net.minecraft.nbt.CompoundTag#get(java.lang.String)", "a");
|
||||
put("net.minecraft.nbt.CompoundTag#getString(java.lang.String)", "i");
|
||||
put("net.minecraft.nbt.CompoundTag#getFloat(java.lang.String)", "g");
|
||||
put("net.minecraft.nbt.CompoundTag#getLongArray(java.lang.String)", "l");
|
||||
put("net.minecraft.nbt.CompoundTag#contains(java.lang.String)", "b");
|
||||
put("net.minecraft.nbt.ListTag#getString(int)", "m");
|
||||
put("net.minecraft.nbt.Tag#getType()", "c");
|
||||
put("net.minecraft.nbt.TagParser#parseCompoundFully(java.lang.String)", "a");
|
||||
put("net.minecraft.nbt.TagType#getName()", "a");
|
||||
put("net.minecraft.world.entity.Entity#load(net.minecraft.world.level.storage.ValueInput)", "e");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bN");
|
||||
put("net.minecraft.world.entity.Entity#saveWithoutId(net.minecraft.world.level.storage.ValueOutput)", "d");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId(net.minecraft.world.level.storage.ValueOutput)", "d");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#loadWithComponents(net.minecraft.world.level.storage.ValueInput)", "b");
|
||||
put("net.minecraft.world.level.storage.TagValueInput#create(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)", "a");
|
||||
put("net.minecraft.world.level.storage.TagValueOutput#createWithContext(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider)", "a");
|
||||
put("net.minecraft.world.level.storage.TagValueOutput#buildResult()", "b");
|
||||
put("net.minecraft.world.item.ItemStack#CODEC", "b");
|
||||
put("net.minecraft.util.ProblemReporter#DISCARDING", "a");
|
||||
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "u");
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R6 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R5);
|
||||
|
||||
put("net.minecraft.server.MinecraftServer#registryAccess()", "bg");
|
||||
put("net.minecraft.world.entity.Entity#load(net.minecraft.world.level.storage.ValueInput)", "d");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "bW");
|
||||
put("net.minecraft.world.item.component.CustomData#copyTag()", "b");
|
||||
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "o");
|
||||
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "v");
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static Map<String, String> MC1_21R7 = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
putAll(MC1_21R6);
|
||||
|
||||
put("net.minecraft.nbt.NbtAccounter#unlimitedHeap()", "c");
|
||||
put("net.minecraft.server.MinecraftServer#registryAccess()", "bc");
|
||||
put("net.minecraft.world.entity.Entity#getEncodeId()", "ca");
|
||||
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "x");
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
public static Map<String, String> getMapping() {
|
||||
// No mappings after 26.1
|
||||
if(MinecraftVersion.getVersion() != MinecraftVersion.UNKNOWN && MinecraftVersion.getVersion().isAtLeastVersion(MinecraftVersion.MC26_1)) {
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
switch (MinecraftVersion.getVersion()) {
|
||||
case MC1_21_R7:
|
||||
return MC1_21R7;
|
||||
case MC1_21_R6:
|
||||
return MC1_21R6;
|
||||
case MC1_21_R5:
|
||||
return MC1_21R5;
|
||||
case MC1_21_R4:
|
||||
return MC1_21R4;
|
||||
case MC1_21_R3:
|
||||
return MC1_21R3;
|
||||
case MC1_21_R2:
|
||||
return MC1_21R2;
|
||||
case MC1_21_R1:
|
||||
return MC1_21R1;
|
||||
case MC1_20_R4:
|
||||
return MC1_20R4;
|
||||
case MC1_20_R3:
|
||||
return MC1_20R3;
|
||||
case MC1_20_R2:
|
||||
return MC1_20R2;
|
||||
case MC1_20_R1:
|
||||
return MC1_20R1;
|
||||
case MC1_19_R3:
|
||||
return MC1_19R2;
|
||||
case MC1_19_R2:
|
||||
return MC1_19R2;
|
||||
case MC1_19_R1:
|
||||
@@ -133,9 +356,11 @@ public class MojangToMapping {
|
||||
return MC1_18R2;
|
||||
case MC1_18_R1:
|
||||
return MC1_18R1;
|
||||
case UNKNOWN:
|
||||
return MC1_21R7; // assume it's a future version, so try the latest known mappings
|
||||
default:
|
||||
return MC1_19R2;// throw new NbtApiException("This version of the NBTAPI is not compatible with
|
||||
// this server version!");
|
||||
// this should never happen, unless a version is forgotten here(like 1.19R3 which uses the 1.19R2 mappings)
|
||||
throw new NbtApiException("No fitting mapping found for version " + MinecraftVersion.getVersion() + ". This is a bug!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -17,8 +17,9 @@ import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.getLogger;
|
||||
@SuppressWarnings("javadoc")
|
||||
public enum ObjectCreator {
|
||||
NMS_NBTTAGCOMPOUND(null, null, ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),
|
||||
NMS_CUSTOMDATA(MinecraftVersion.MC1_20_R4, null, ClassWrapper.NMS_CUSTOMDATA.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),
|
||||
NMS_BLOCKPOSITION(null, null, ClassWrapper.NMS_BLOCKPOSITION.getClazz(), int.class, int.class, int.class),
|
||||
NMS_COMPOUNDFROMITEM(MinecraftVersion.MC1_11_R1, null, ClassWrapper.NMS_ITEMSTACK.getClazz(),
|
||||
NMS_COMPOUNDFROMITEM(MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_20_R3, ClassWrapper.NMS_ITEMSTACK.getClazz(),
|
||||
ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),;
|
||||
|
||||
private Constructor<?> construct;
|
||||
|
||||
+89
-33
@@ -5,6 +5,7 @@ import java.io.OutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -55,7 +56,7 @@ public enum ReflectionMethod {
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setBoolean"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "putBoolean(java.lang.String,boolean)")),
|
||||
COMPOUND_SET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, UUID.class },
|
||||
MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "a"),
|
||||
MinecraftVersion.MC1_16_R1, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_16_R1, "a"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "putUUID(java.lang.String,java.util.UUID)")),
|
||||
COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"),
|
||||
@@ -66,12 +67,18 @@ public enum ReflectionMethod {
|
||||
COMPOUND_GET(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "get"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "get(java.lang.String)")),
|
||||
COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, int.class },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getList"),
|
||||
COMPOUND_GET_LIST_LEGACY(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, int.class },
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_7_R4, "getList"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getList(java.lang.String,int)")),
|
||||
COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_21_R4,
|
||||
new Since(MinecraftVersion.MC1_21_R4, "getList(java.lang.String)")),
|
||||
// Only needed for 1.7.10 getType
|
||||
COMPOUND_OWN_TYPE(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4,
|
||||
COMPOUND_OWN_TYPE_LEGACY(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getTypeId")),
|
||||
TAGTYPE_OWN_TYPE(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_21_R4,
|
||||
new Since(MinecraftVersion.MC1_21_R4, "getType()")),
|
||||
TAGTYPE_GET_NAME(ClassWrapper.NMS_TAGTYPE, new Class[] {}, MinecraftVersion.MC1_21_R4,
|
||||
new Since(MinecraftVersion.MC1_21_R4, "getName()")),
|
||||
|
||||
COMPOUND_GET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getFloat"),
|
||||
@@ -106,17 +113,18 @@ public enum ReflectionMethod {
|
||||
COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getBoolean"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getBoolean(java.lang.String)")),
|
||||
COMPOUND_GET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_16_R1,
|
||||
COMPOUND_GET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_16_R1, MinecraftVersion.MC1_21_R3,
|
||||
new Since(MinecraftVersion.MC1_16_R1, "a"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getUUID(java.lang.String)")),
|
||||
COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getCompound"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getCompound(java.lang.String)")),
|
||||
|
||||
NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
|
||||
|
||||
NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R3,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getTag"), new Since(MinecraftVersion.MC1_18_R1, "getTag()")),
|
||||
NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "save"),
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R3, new Since(MinecraftVersion.MC1_7_R4, "save"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "save(net.minecraft.nbt.CompoundTag)")),
|
||||
NMSITEM_CREATESTACK(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_10_R1, new Since(MinecraftVersion.MC1_7_R4, "createStack")),
|
||||
@@ -127,17 +135,17 @@ public enum ReflectionMethod {
|
||||
COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "hasKey"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "contains(java.lang.String)")),
|
||||
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_8_R3,
|
||||
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_21_R4,
|
||||
new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d"),
|
||||
new Since(MinecraftVersion.MC1_15_R1, "e"), new Since(MinecraftVersion.MC1_16_R1, "d"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getTagType(java.lang.String)")),
|
||||
COMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()"), new Since(MinecraftVersion.MC1_21_R5, "keySet()")),
|
||||
// FIXME ?!?
|
||||
LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
|
||||
// LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
// new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
|
||||
// new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
|
||||
LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST, new Class[] { int.class }, MinecraftVersion.MC1_8_R3,
|
||||
new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "remove(int)")),
|
||||
@@ -162,7 +170,7 @@ public enum ReflectionMethod {
|
||||
new Since(MinecraftVersion.MC1_13_R1, "get"), new Since(MinecraftVersion.MC1_18_R1, "get(int)")),
|
||||
|
||||
ITEMSTACK_SET_TAG(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTag"),
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R3, new Since(MinecraftVersion.MC1_7_R4, "setTag"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "setTag(net.minecraft.nbt.CompoundTag)")),
|
||||
ITEMSTACK_NMSCOPY(ClassWrapper.CRAFT_ITEMSTACK, new Class[] { ItemStack.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "asNMSCopy")),
|
||||
@@ -173,11 +181,7 @@ public enum ReflectionMethod {
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
|
||||
NMS_WORLD_GET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER, new Class[] { ClassWrapper.NMS_BLOCKPOSITION.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "getTileEntity"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getBlockState(net.minecraft.core.BlockPos)")),
|
||||
NMS_WORLD_SET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER,
|
||||
new Class[] { ClassWrapper.NMS_BLOCKPOSITION.getClazz(), ClassWrapper.NMS_TILEENTITY.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_16_R3,
|
||||
new Since(MinecraftVersion.MC1_8_R3, "setTileEntity")),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "getBlockEntity(net.minecraft.core.BlockPos)")),
|
||||
NMS_WORLD_REMOVE_TILEENTITY(ClassWrapper.NMS_WORLDSERVER, new Class[] { ClassWrapper.NMS_BLOCKPOSITION.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_17_R1, new Since(MinecraftVersion.MC1_8_R3, "t"),
|
||||
new Since(MinecraftVersion.MC1_9_R1, "s"), new Since(MinecraftVersion.MC1_13_R1, "n"),
|
||||
@@ -186,11 +190,9 @@ public enum ReflectionMethod {
|
||||
NMS_WORLD_GET_TILEENTITY_1_7_10(ClassWrapper.NMS_WORLDSERVER, new Class[] { int.class, int.class, int.class },
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getTileEntity")),
|
||||
// FIXME: No Spigot mapping!
|
||||
TILEENTITY_LOAD_LEGACY191(ClassWrapper.NMS_TILEENTITY,
|
||||
new Class[] { ClassWrapper.NMS_MINECRAFTSERVER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_9_R1, MinecraftVersion.MC1_9_R1, new Since(MinecraftVersion.MC1_9_R1, "a")),
|
||||
// FIXME: No Spigot mapping!
|
||||
TILEENTITY_LOAD_LEGACY183(ClassWrapper.NMS_TILEENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_9_R2, new Since(MinecraftVersion.MC1_8_R3, "c"),
|
||||
new Since(MinecraftVersion.MC1_9_R1, "a"), new Since(MinecraftVersion.MC1_9_R2, "c")),
|
||||
@@ -207,7 +209,7 @@ public enum ReflectionMethod {
|
||||
TILEENTITY_GET_NBT(ClassWrapper.NMS_TILEENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_17_R1, new Since(MinecraftVersion.MC1_7_R4, "b"),
|
||||
new Since(MinecraftVersion.MC1_9_R1, "save")),
|
||||
TILEENTITY_GET_NBT_1181(ClassWrapper.NMS_TILEENTITY, new Class[] {}, MinecraftVersion.MC1_18_R1,
|
||||
TILEENTITY_GET_NBT_1181(ClassWrapper.NMS_TILEENTITY, new Class[] {}, MinecraftVersion.MC1_18_R1, MinecraftVersion.MC1_20_R3,
|
||||
new Since(MinecraftVersion.MC1_18_R1, "saveWithId()")),
|
||||
TILEENTITY_SET_NBT_LEGACY1151(ClassWrapper.NMS_TILEENTITY,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() }, MinecraftVersion.MC1_7_R4,
|
||||
@@ -217,7 +219,7 @@ public enum ReflectionMethod {
|
||||
new Class[] { ClassWrapper.NMS_IBLOCKDATA.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_16_R1, MinecraftVersion.MC1_16_R3, new Since(MinecraftVersion.MC1_16_R1, "load")),
|
||||
TILEENTITY_SET_NBT(ClassWrapper.NMS_TILEENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_17_R1, new Since(MinecraftVersion.MC1_16_R1, "load"),
|
||||
MinecraftVersion.MC1_17_R1, MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_16_R1, "load"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "load(net.minecraft.nbt.CompoundTag)")),
|
||||
TILEENTITY_GET_BLOCKDATA(ClassWrapper.NMS_TILEENTITY, new Class[] {}, MinecraftVersion.MC1_16_R1,
|
||||
new Since(MinecraftVersion.MC1_16_R1, "getBlock"),
|
||||
@@ -226,19 +228,30 @@ public enum ReflectionMethod {
|
||||
CRAFT_ENTITY_GET_HANDLE(ClassWrapper.CRAFT_ENTITY, new Class[] {}, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
|
||||
NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "f"),
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_7_R4, "f"),
|
||||
new Since(MinecraftVersion.MC1_16_R1, "load"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "load(net.minecraft.nbt.CompoundTag)")),
|
||||
NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "e"),
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_7_R4, "e"),
|
||||
new Since(MinecraftVersion.MC1_12_R1, "save"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "saveWithoutId(net.minecraft.nbt.CompoundTag)")),
|
||||
NMS_ENTITY_GETSAVEID(ClassWrapper.NMS_ENTITY, new Class[] {}, MinecraftVersion.MC1_14_R1,
|
||||
new Since(MinecraftVersion.MC1_14_R1, "getSaveID"), new Since(MinecraftVersion.MC1_18_R1, "getEncodeId()")),
|
||||
|
||||
NBTFILE_READ(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS, new Class[] { InputStream.class },
|
||||
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"),
|
||||
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R2, new Since(MinecraftVersion.MC1_7_R4, "a"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "readCompressed(java.io.InputStream)")),
|
||||
|
||||
NBTFILE_READV2(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS,
|
||||
new Class[] { InputStream.class, ClassWrapper.NMS_NBTACCOUNTER.getClazz() }, MinecraftVersion.MC1_20_R3,
|
||||
new Since(MinecraftVersion.MC1_20_R3,
|
||||
"readCompressed(java.io.InputStream,net.minecraft.nbt.NbtAccounter)")),
|
||||
|
||||
NBTACCOUNTER_CREATE_UNLIMITED(ClassWrapper.NMS_NBTACCOUNTER,
|
||||
new Class[] {}, MinecraftVersion.MC1_20_R3,
|
||||
new Since(MinecraftVersion.MC1_20_R3,
|
||||
"unlimitedHeap()")),
|
||||
|
||||
NBTFILE_WRITE(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), OutputStream.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "a"),
|
||||
@@ -247,15 +260,13 @@ public enum ReflectionMethod {
|
||||
|
||||
PARSE_NBT(ClassWrapper.NMS_MOJANGSONPARSER, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "parse"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "parseTag(java.lang.String)")),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "parseTag(java.lang.String)"), new Since(MinecraftVersion.MC1_21_R5, "parseCompoundFully(java.lang.String)")),
|
||||
REGISTRY_KEYSET(ClassWrapper.NMS_REGISTRYSIMPLE, new Class[] {}, MinecraftVersion.MC1_11_R1,
|
||||
MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "keySet")),
|
||||
REGISTRY_GET(ClassWrapper.NMS_REGISTRYSIMPLE, new Class[] { Object.class }, MinecraftVersion.MC1_11_R1,
|
||||
MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "get")),
|
||||
// FIXME: No Spigot mapping!
|
||||
REGISTRY_SET(ClassWrapper.NMS_REGISTRYSIMPLE, new Class[] { Object.class, Object.class },
|
||||
MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "a")),
|
||||
// FIXME: No Spigot mapping!
|
||||
REGISTRY_GET_INVERSE(ClassWrapper.NMS_REGISTRYMATERIALS, new Class[] { Object.class }, MinecraftVersion.MC1_11_R1,
|
||||
MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "b")),
|
||||
REGISTRYMATERIALS_KEYSET(ClassWrapper.NMS_REGISTRYMATERIALS, new Class[] {}, MinecraftVersion.MC1_13_R1,
|
||||
@@ -266,12 +277,12 @@ public enum ReflectionMethod {
|
||||
MinecraftVersion.MC1_13_R2, MinecraftVersion.MC1_17_R1, new Since(MinecraftVersion.MC1_13_R2, "getKey")),
|
||||
|
||||
GAMEPROFILE_DESERIALIZE(ClassWrapper.NMS_GAMEPROFILESERIALIZER,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() }, MinecraftVersion.MC1_7_R4,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() }, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R3,
|
||||
new Since(MinecraftVersion.MC1_7_R4, "deserialize"),
|
||||
new Since(MinecraftVersion.MC1_18_R1, "readGameProfile(net.minecraft.nbt.CompoundTag)")),
|
||||
GAMEPROFILE_SERIALIZE(ClassWrapper.NMS_GAMEPROFILESERIALIZER,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), ClassWrapper.GAMEPROFILE.getClazz() },
|
||||
MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "serialize"),
|
||||
MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_20_R3, new Since(MinecraftVersion.MC1_8_R3, "serialize"),
|
||||
new Since(MinecraftVersion.MC1_18_R1,
|
||||
"writeGameProfile(net.minecraft.nbt.CompoundTag,com.mojang.authlib.GameProfile)")),
|
||||
|
||||
@@ -281,7 +292,51 @@ public enum ReflectionMethod {
|
||||
MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "getRaw")),
|
||||
CRAFT_PERSISTENT_DATA_CONTAINER_PUT_ALL(ClassWrapper.CRAFT_PERSISTENTDATACONTAINER,
|
||||
new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() }, MinecraftVersion.MC1_14_R1,
|
||||
new Since(MinecraftVersion.MC1_14_R1, "putAll")),;
|
||||
new Since(MinecraftVersion.MC1_14_R1, "putAll")),
|
||||
// 1.20.5+ Stuff
|
||||
NMSDATACOMPONENTHOLDER_GET(ClassWrapper.NMS_DATACOMPONENTHOLDER, new Class[] {ClassWrapper.NMS_DATACOMPONENTTYPE.getClazz()}, MinecraftVersion.MC1_20_R4,
|
||||
new Since(MinecraftVersion.MC1_20_R4, "get(net.minecraft.core.component.DataComponentType)")),
|
||||
NMSCUSTOMDATA_GETCOPY(ClassWrapper.NMS_CUSTOMDATA, new Class[] {}, MinecraftVersion.MC1_20_R4,
|
||||
new Since(MinecraftVersion.MC1_20_R4, "copyTag()")),
|
||||
NMSITEM_SET(ClassWrapper.NMS_ITEMSTACK, new Class[] {ClassWrapper.NMS_DATACOMPONENTTYPE.getClazz(), Object.class}, MinecraftVersion.MC1_20_R4,
|
||||
new Since(MinecraftVersion.MC1_20_R4, "set(net.minecraft.core.component.DataComponentType,java.lang.Object)")),
|
||||
NMSITEM_SAVE_MODERN(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz() },
|
||||
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "save(net.minecraft.core.HolderLookup$Provider)")),
|
||||
NMSITEM_LOAD(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
|
||||
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_20_R4, "parseOptional(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)")),
|
||||
NMSITEM_LOAD_MODERN(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTBASE.getClazz() },
|
||||
MinecraftVersion.MC1_21_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "parse(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.Tag)")),
|
||||
NMSSERVER_GETREGISTRYACCESS(ClassWrapper.NMS_SERVER, new Class[] {},
|
||||
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "registryAccess()")),
|
||||
NMSSERVER_GETSERVER(ClassWrapper.CRAFT_SERVER, new Class[] {},
|
||||
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "getServer()")),
|
||||
TILEENTITY_GET_NBT_1205(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_PROVIDER.getClazz()}, MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4,
|
||||
new Since(MinecraftVersion.MC1_20_R4, "saveWithId(net.minecraft.core.HolderLookup$Provider)")),
|
||||
TILEENTITY_SET_NBT_1205(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz() },
|
||||
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "loadWithComponents(net.minecraft.nbt.CompoundTag,net.minecraft.core.HolderLookup$Provider)")),
|
||||
GET_DATAFIXER(ClassWrapper.NMS_DATAFIXERS, new Class[] {}, MinecraftVersion.MC1_20_R4,
|
||||
new Since(MinecraftVersion.MC1_20_R4, "getDataFixer()")),
|
||||
// 1.21.6 Stuff
|
||||
GET_SERIALIZATION_CONTEXT(ClassWrapper.NMS_PROVIDER, new Class[] {ClassWrapper.NMS_DYNAMICOPS.getClazz()}, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "createSerializationContext(com.mojang.serialization.DynamicOps)")),
|
||||
NMS_GET_TAG_VALUE_INPUT(ClassWrapper.NMS_TAG_VALUE_INPUT, new Class[] {ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "create(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)")),
|
||||
NMS_GET_TAG_VALUE_OUTPUT(ClassWrapper.NMS_TAG_VALUE_OUTPUT, new Class[] {ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz()}, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "createWithContext(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider)")),
|
||||
NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND(ClassWrapper.NMS_TAG_VALUE_OUTPUT, new Class[] {}, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "buildResult()")),
|
||||
NMS_ENTITY_SET_NBT_1216(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_VALUE_INPUT.getClazz() }, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "load(net.minecraft.world.level.storage.ValueInput)")
|
||||
),
|
||||
NMS_ENTITY_GET_NBT_1216(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_VALUE_OUTPUT.getClazz() }, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "saveWithoutId(net.minecraft.world.level.storage.ValueOutput)")),
|
||||
|
||||
TILEENTITY_GET_NBT_1216(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_VALUE_OUTPUT.getClazz()}, MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "saveWithId(net.minecraft.world.level.storage.ValueOutput)")),
|
||||
TILEENTITY_SET_NBT_1216(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_VALUE_INPUT.getClazz() },
|
||||
MinecraftVersion.MC1_21_R5,
|
||||
new Since(MinecraftVersion.MC1_21_R5, "loadWithComponents(net.minecraft.world.level.storage.ValueInput)")),
|
||||
;
|
||||
|
||||
private MinecraftVersion removedAfter;
|
||||
private Since targetVersion;
|
||||
@@ -372,7 +427,8 @@ public enum ReflectionMethod {
|
||||
return method.invoke(target, args);
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded
|
||||
+ ", Enum: " + this + ", Passed Class: " + (target == null ? "null" : target.getClass()), ex);
|
||||
+ ", Enum: " + this + ", Passed Class: " + (target == null ? "null" : target.getClass()) + " Args: " + (args == null ? "null" : Arrays.toString(args)) +
|
||||
" Classes: " + (args == null ? "null" : Arrays.asList(args).stream().map(a -> a == null ? "NULL" : a.getClass().getName()).collect(Collectors.toList())), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package de.tr7zw.changeme.nbtapi.wrapper;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
|
||||
class ProxiedList<E extends NBTProxy> implements ProxyList<E> {
|
||||
|
||||
private final ReadWriteNBTCompoundList nbt;
|
||||
private final Class<E> proxy;
|
||||
|
||||
public ProxiedList(ReadWriteNBTCompoundList nbt, Class<E> proxyClass) {
|
||||
this.nbt = nbt;
|
||||
this.proxy = proxyClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
ReadWriteNBT tag = nbt.get(index);
|
||||
return new ProxyBuilder<E>(tag,proxy).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return nbt.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int index) {
|
||||
nbt.remove(index);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Itr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E addCompound() {
|
||||
ReadWriteNBT tag = nbt.addCompound();
|
||||
return new ProxyBuilder<E>(tag,proxy).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return nbt.isEmpty();
|
||||
}
|
||||
|
||||
private class Itr implements Iterator<E> {
|
||||
/**
|
||||
* Index of element to be returned by subsequent call to next.
|
||||
*/
|
||||
int cursor = 0;
|
||||
|
||||
/**
|
||||
* Index of element returned by most recent call to next or
|
||||
* previous. Reset to -1 if this element is deleted by a call
|
||||
* to remove.
|
||||
*/
|
||||
int lastRet = -1;
|
||||
|
||||
public boolean hasNext() {
|
||||
return cursor != size();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
try {
|
||||
int i = cursor;
|
||||
E next = get(i);
|
||||
lastRet = i;
|
||||
cursor = i + 1;
|
||||
return next;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastRet < 0)
|
||||
throw new IllegalStateException();
|
||||
|
||||
try {
|
||||
ProxiedList.this.remove(lastRet);
|
||||
if (lastRet < cursor)
|
||||
cursor--;
|
||||
lastRet = -1;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi.wrapper;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -64,7 +65,7 @@ public class ProxyBuilder<T extends NBTProxy> implements InvocationHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static Function<Arguments, Object> createFunction(NBTProxy proxy, Method method) {
|
||||
if ("toString".equals(method.getName()) && method.getParameterCount() == 0
|
||||
&& method.getReturnType() == String.class) {
|
||||
@@ -98,13 +99,24 @@ public class ProxyBuilder<T extends NBTProxy> implements InvocationHandler {
|
||||
(Class<NBTProxy>) retType).build();
|
||||
};
|
||||
}
|
||||
if (retType == ProxyList.class) {
|
||||
|
||||
Class<?> parameterType = (Class<?>) ((ParameterizedType) method.getGenericReturnType())
|
||||
.getActualTypeArguments()[0];
|
||||
if (parameterType != null && parameterType.isInterface()
|
||||
&& NBTProxy.class.isAssignableFrom(parameterType)) {
|
||||
return (arguments) -> {
|
||||
return new ProxiedList(arguments.nbt.getCompoundList(fieldName), parameterType);
|
||||
};
|
||||
}
|
||||
}
|
||||
NBTHandler<Object> handler = (NBTHandler<Object>) proxy.getHandler(retType);
|
||||
if (handler != null) {
|
||||
return (arguments) -> handler.get(arguments.nbt, fieldName);
|
||||
}
|
||||
return (arguments) -> arguments.nbt.getOrNull(fieldName, retType);
|
||||
}
|
||||
if(action == Type.HAS) {
|
||||
if (action == Type.HAS) {
|
||||
String fieldName = getNBTName(proxy.getCasing(), method);
|
||||
return (arguments) -> arguments.nbt.hasTag(fieldName);
|
||||
}
|
||||
@@ -116,7 +128,8 @@ public class ProxyBuilder<T extends NBTProxy> implements InvocationHandler {
|
||||
private static Type getAction(Method method) {
|
||||
NBTTarget target = method.getAnnotation(NBTTarget.class);
|
||||
if (target != null) {
|
||||
if (target.type() == Type.HAS && method.getParameterCount() == 0 && method.getReturnType() == boolean.class) {
|
||||
if (target.type() == Type.HAS && method.getParameterCount() == 0
|
||||
&& method.getReturnType() == boolean.class) {
|
||||
return Type.HAS;
|
||||
}
|
||||
if (target.type() == Type.GET && method.getParameterCount() == 0) {
|
||||
@@ -132,7 +145,8 @@ public class ProxyBuilder<T extends NBTProxy> implements InvocationHandler {
|
||||
if (method.getName().startsWith("get") && method.getParameterCount() == 0) {
|
||||
return Type.GET;
|
||||
}
|
||||
if (method.getName().startsWith("has") && method.getParameterCount() == 0 && method.getReturnType() == boolean.class) {
|
||||
if (method.getName().startsWith("has") && method.getParameterCount() == 0
|
||||
&& method.getReturnType() == boolean.class) {
|
||||
return Type.HAS;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.tr7zw.changeme.nbtapi.wrapper;
|
||||
|
||||
public interface ProxyList<T extends NBTProxy> extends Iterable<T> {
|
||||
|
||||
/**
|
||||
* Adds a new compound tag to the current compound tag
|
||||
*
|
||||
* @return A new instance of the class.
|
||||
*/
|
||||
T addCompound();
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this collection. If this collection
|
||||
* contains more than Integer.MAX_VALUE elements, returns Integer.MAX_VALUE.
|
||||
*
|
||||
* @return the number of elements in this collection
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns true if this collection contains no elements.
|
||||
*
|
||||
* @return true if this collection contains no elements
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Get the object with the given id.
|
||||
*
|
||||
* @param id The id of the object to get.
|
||||
* @return The object with the given id.
|
||||
*/
|
||||
T get(int id);
|
||||
|
||||
/**
|
||||
* Removes the element at the specified position in this list
|
||||
*
|
||||
* @param i The index of the element to remove.
|
||||
*/
|
||||
void remove(int i);
|
||||
|
||||
}
|
||||
+15
-22
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
</parent>
|
||||
<artifactId>item-nbt-api-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -12,21 +12,22 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>nbt-injector</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>nbt-data-api</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>datafixerupper</artifactId>
|
||||
<version>4.0.26</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<!-- Overwrite to provided -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
@@ -39,7 +40,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||
<relocations>
|
||||
@@ -47,14 +48,6 @@
|
||||
<pattern>de.tr7zw.changeme.nbtapi</pattern>
|
||||
<shadedPattern>de.tr7zw.nbtapi</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>javassist</pattern>
|
||||
<shadedPattern>de.tr7zw.nbtinjector.javassist</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>de.tr7zw.annotations</pattern>
|
||||
<shadedPattern>de.tr7zw.nbtapi.utils.annotations</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
@@ -19,6 +18,7 @@ import de.tr7zw.nbtapi.plugin.tests.GameprofileTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.NBTFileTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.blocks.BlockNBTTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.chunks.ChunkNBTPersistentTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.CompoundDifferenceTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.EnumTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.EqualsTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.ForEachTest;
|
||||
@@ -34,27 +34,23 @@ import de.tr7zw.nbtapi.plugin.tests.compounds.ResolveTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.StreamTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.SubCompoundsTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.compounds.TypeTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.data.WorldDataTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.entities.EntityCustomNbtPersistentTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.entities.EntityTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.injector.EntityCustomNbtInjectorTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.injector.MergeTileSubCompoundTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.injector.SpawnEntityCustomNbtInjectorTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.injector.TilesCustomNBTInjectorTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.ComponentsTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.DirectApplyMetaTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.DirectApplyTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.ItemConversionTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.tiles.TileTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTPersistentTest;
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.ItemJsonTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.ItemMergingTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.ItemStackConversionTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.proxy.DataItemProxyTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.proxy.SimpleProxyTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.LegacyItemTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.MetaTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.NBTModifyItemTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.items.SmuggleTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.proxy.SimpleProxyTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.tiles.TileTest;
|
||||
import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTPersistentTest;
|
||||
|
||||
public class NBTAPI extends JavaPlugin {
|
||||
|
||||
@@ -71,7 +67,6 @@ public class NBTAPI extends JavaPlugin {
|
||||
public void onLoad() {
|
||||
|
||||
getConfig().options().copyDefaults(true);
|
||||
getConfig().addDefault("nbtInjector.enabled", false);
|
||||
getConfig().addDefault("bStats.enabled", true);
|
||||
getConfig().addDefault("updateCheck.enabled", true);
|
||||
getConfig().addDefault("silentquickstart", false);
|
||||
@@ -89,19 +84,6 @@ public class NBTAPI extends JavaPlugin {
|
||||
MinecraftVersion.enableUpdateCheck();
|
||||
}
|
||||
|
||||
// Disabled by default since 2.1. Enable it yourself by calling
|
||||
// NBTInjector.inject(); during onLoad/config
|
||||
if (getConfig().getBoolean("nbtInjector.enabled")) {
|
||||
getLogger().info("Injecting custom NBT");
|
||||
try {
|
||||
NBTInjector.inject();
|
||||
getLogger().info("Injected!");
|
||||
} catch (Throwable ex) { // NOSONAR
|
||||
getLogger().log(Level.SEVERE, "Error while Injecting custom Tile/Entity classes!", ex);
|
||||
compatible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// NBTCompounds
|
||||
apiTests.add(new GetterSetterTest());
|
||||
apiTests.add(new TypeTest());
|
||||
@@ -118,6 +100,7 @@ public class NBTAPI extends JavaPlugin {
|
||||
apiTests.add(new ForEachTest());
|
||||
apiTests.add(new StreamTest());
|
||||
apiTests.add(new EqualsTest());
|
||||
apiTests.add(new CompoundDifferenceTest());
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 list support is not complete at all
|
||||
apiTests.add(new IteratorTest());
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1))
|
||||
@@ -128,9 +111,15 @@ public class NBTAPI extends JavaPlugin {
|
||||
apiTests.add(new ItemConversionTest());
|
||||
apiTests.add(new ItemStackConversionTest());
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
apiTests.add(new LegacyItemTest());
|
||||
}
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) && !MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
apiTests.add(new ItemJsonTest());
|
||||
}
|
||||
apiTests.add(new ComponentsTest());
|
||||
apiTests.add(new EmptyItemTest());
|
||||
apiTests.add(new SmuggleTest());
|
||||
apiTests.add(new DataItemProxyTest());
|
||||
apiTests.add(new MetaTest());
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) { // 1.7.10 not a thing
|
||||
apiTests.add(new ItemMergingTest());
|
||||
@@ -158,15 +147,6 @@ public class NBTAPI extends JavaPlugin {
|
||||
// Files
|
||||
apiTests.add(new NBTFileTest());
|
||||
|
||||
// Data
|
||||
apiTests.add(new WorldDataTest());
|
||||
|
||||
// Injector
|
||||
apiTests.add(new TilesCustomNBTInjectorTest());
|
||||
apiTests.add(new MergeTileSubCompoundTest());
|
||||
apiTests.add(new EntityCustomNbtInjectorTest());
|
||||
apiTests.add(new SpawnEntityCustomNbtInjectorTest());
|
||||
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3))
|
||||
apiTests.add(new GameprofileTest());
|
||||
|
||||
@@ -181,8 +161,6 @@ public class NBTAPI extends JavaPlugin {
|
||||
VersionChecker.hideOk = true;
|
||||
return;
|
||||
}
|
||||
getLogger().info("Adding listeners...");
|
||||
Bukkit.getPluginManager().registerEvents(new ReloadListener(), this);
|
||||
MinecraftVersion.hasGsonSupport(); // init gson(if it hasn't already)
|
||||
getLogger().info("Checking bindings...");
|
||||
MinecraftVersion.getVersion();
|
||||
@@ -222,7 +200,7 @@ public class NBTAPI extends JavaPlugin {
|
||||
} catch (Exception ex) {
|
||||
results.put(test, ex);
|
||||
getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex);
|
||||
} catch (NoSuchFieldError th) { // NOSONAR
|
||||
} catch (Throwable th) { // NOSONAR
|
||||
getLogger().log(Level.SEVERE, "Servere error during '" + test.getClass().getSimpleName() + "' test!");
|
||||
getLogger().warning(
|
||||
"WARNING! This version of Item-NBT-API seems to be broken with your Spigot version! Canceled the other tests!");
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
|
||||
/**
|
||||
* This listener class tries to prevent people from reloading while the
|
||||
* NBTInjector is enabled.
|
||||
*
|
||||
* @author tr7zw
|
||||
*
|
||||
*/
|
||||
public class ReloadListener implements Listener {
|
||||
|
||||
/**
|
||||
* Console handler
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@EventHandler
|
||||
public void onCommand(org.bukkit.event.server.ServerCommandEvent event) {
|
||||
if (event.getCommand().toLowerCase().startsWith("reload") && NBTInjector.isInjected()) {
|
||||
event.setCancelled(true);
|
||||
event.getSender().sendMessage(
|
||||
"[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Player handler
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@EventHandler
|
||||
public void onCommand(org.bukkit.event.player.PlayerCommandPreprocessEvent event) {
|
||||
if (event.getMessage().toLowerCase().startsWith("/reload") && NBTInjector.isInjected()) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(
|
||||
"[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import java.util.UUID;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTGameProfile;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
|
||||
public class GameprofileTest implements Test {
|
||||
|
||||
@@ -14,10 +14,9 @@ public class GameprofileTest implements Test {
|
||||
public void test() throws Exception {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
GameProfile profile = new GameProfile(uuid, "random");
|
||||
NBTCompound nbt = NBTGameProfile.toNBT(profile);
|
||||
profile = null;
|
||||
profile = NBTGameProfile.fromNBT(nbt);
|
||||
if (profile == null || !profile.getId().equals(uuid)) {
|
||||
ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
|
||||
GameProfile profile2 = NBT.gameProfileFromNBT(nbt);
|
||||
if (profile == null || !profile.equals(profile2)) {
|
||||
throw new NbtApiException("Error when converting a GameProfile from/to NBT!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package de.tr7zw.nbtapi.plugin.tests;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBTFile;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.NBTAPI;
|
||||
|
||||
public class NBTFileTest implements Test {
|
||||
@@ -16,18 +16,18 @@ public class NBTFileTest implements Test {
|
||||
NBTAPI.getInstance().getDataFolder().mkdirs();
|
||||
File testFile = new File(NBTAPI.getInstance().getDataFolder(), "test.nbt");
|
||||
Files.deleteIfExists(testFile.toPath());
|
||||
NBTFile file = new NBTFile(testFile);
|
||||
file.addCompound("testcomp").setString("test1", "ok");
|
||||
NBTCompound comp = file.getCompound("testcomp");
|
||||
NBTFileHandle file = NBT.getFileHandle(testFile);
|
||||
file.getOrCreateCompound("testcomp").setString("test1", "ok");
|
||||
ReadWriteNBT comp = file.getOrCreateCompound("testcomp");
|
||||
if (comp == null) {
|
||||
throw new NbtApiException("Error getting compound!");
|
||||
}
|
||||
comp.setString("test2", "ok");
|
||||
file.setLong("time", System.currentTimeMillis());
|
||||
file.setString("test", "test");
|
||||
NBTCompound chunks = file.addCompound("chunks");
|
||||
NBTCompound chunk = chunks.addCompound("somechunk");
|
||||
NBTCompound block = chunk.addCompound("someblock");
|
||||
ReadWriteNBT chunks = file.getOrCreateCompound("chunks");
|
||||
ReadWriteNBT chunk = chunks.getOrCreateCompound("somechunk");
|
||||
ReadWriteNBT block = chunk.getOrCreateCompound("someblock");
|
||||
block.setString("type", "wool");
|
||||
file.save();
|
||||
|
||||
@@ -35,25 +35,25 @@ public class NBTFileTest implements Test {
|
||||
throw new NbtApiException("SubCompounds did not work!");
|
||||
}
|
||||
|
||||
NBTFile fileLoaded = new NBTFile(testFile);
|
||||
NBTFileHandle fileLoaded = NBT.getFileHandle(testFile);
|
||||
if (!fileLoaded.getString("test").equals("test")) {
|
||||
throw new NbtApiException("Wasn't able to load NBT File with the correct content!");
|
||||
}
|
||||
Files.deleteIfExists(fileLoaded.getFile().toPath());
|
||||
// String
|
||||
String str = fileLoaded.toString();
|
||||
NBTContainer rebuild = new NBTContainer(str);
|
||||
ReadWriteNBT rebuild = NBT.parseNBT(str);
|
||||
if (!str.equals(rebuild.toString())) {
|
||||
throw new NbtApiException("Wasn't able to parse NBT from a String!");
|
||||
}
|
||||
|
||||
NBTCompound dummy = new NBTContainer();
|
||||
ReadWriteNBT dummy = NBT.createNBTObject();
|
||||
dummy.setString("test1", "key1");
|
||||
NBTFile.saveTo(testFile, dummy);
|
||||
dummy = new NBTContainer();
|
||||
NBT.writeFile(testFile, dummy);
|
||||
dummy = NBT.createNBTObject();
|
||||
dummy.setString("test2", "key2");
|
||||
NBTFile.saveTo(testFile, dummy);
|
||||
dummy = NBTFile.readFrom(testFile);
|
||||
NBT.writeFile(testFile, dummy);
|
||||
dummy = NBT.readFile(testFile);
|
||||
if (dummy.hasTag("test1") || !dummy.getString("test2").equals("key2")) {
|
||||
throw new NbtApiException("Wasn't able to save NBT File with the correct content!");
|
||||
}
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class CompoundDifferenceTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ReadWriteNBT nbt1 = NBT.createNBTObject();
|
||||
nbt1.setInteger("intTag", 1);
|
||||
ReadWriteNBT tmp = NBT.createNBTObject();
|
||||
tmp.setInteger("foo", 1);
|
||||
nbt1.getCompoundList("compoundList1").addCompound(tmp);
|
||||
nbt1.setIntArray("intArray", new int[]{1, 2, 3});
|
||||
tmp = NBT.createNBTObject();
|
||||
tmp.setIntArray("foo", new int[]{1, 2, 3});
|
||||
nbt1.getCompoundList("compoundList2").addCompound(tmp);
|
||||
nbt1.getOrCreateCompound("compoundTag").setFloat("floatTag", 20F);
|
||||
nbt1.getOrCreateCompound("compoundTag").setBoolean("booleanTag", true);
|
||||
nbt1.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D));
|
||||
nbt1.getOrCreateCompound("compoundTag").getFloatList("floatList").addAll(Arrays.asList(1F, 2F));
|
||||
nbt1.getOrCreateCompound("compoundTagTwo").setString("stringTag", "string");
|
||||
ReadWriteNBT nbt2 = NBT.createNBTObject();
|
||||
nbt2.setInteger("intTag", 1);
|
||||
tmp = NBT.createNBTObject();
|
||||
tmp.setInteger("foo", 1);
|
||||
nbt2.getCompoundList("compoundList1").addCompound(tmp);
|
||||
nbt2.setInteger("alsoIntTag", 2);
|
||||
tmp = NBT.createNBTObject();
|
||||
tmp.setInteger("foo", 2);
|
||||
nbt2.getCompoundList("compoundList2").addCompound(tmp);
|
||||
nbt2.getOrCreateCompound("compoundTag").setFloat("floatTag", 20F);
|
||||
nbt2.getOrCreateCompound("compoundTag").setBoolean("booleanTag", false);
|
||||
nbt2.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D, 4D));
|
||||
nbt2.getOrCreateCompound("compoundTag").getFloatList("floatList").addAll(Arrays.asList(1F, 2F));
|
||||
nbt2.getOrCreateCompound("compoundTagTwo").setString("stringTag", "string");
|
||||
|
||||
ReadWriteNBT expectedDiff1 = NBT.createNBTObject();
|
||||
tmp = NBT.createNBTObject();
|
||||
tmp.setIntArray("foo", new int[]{1, 2, 3});
|
||||
expectedDiff1.getCompoundList("compoundList2").addCompound(tmp);
|
||||
expectedDiff1.setIntArray("intArray", new int[]{1, 2, 3});
|
||||
expectedDiff1.getOrCreateCompound("compoundTag").setBoolean("booleanTag", true);
|
||||
expectedDiff1.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D));
|
||||
ReadWriteNBT expectedDiff2 = NBT.createNBTObject();
|
||||
tmp = NBT.createNBTObject();
|
||||
tmp.setInteger("foo", 2);
|
||||
expectedDiff2.getCompoundList("compoundList2").addCompound(tmp);
|
||||
expectedDiff2.setInteger("alsoIntTag", 2);
|
||||
expectedDiff2.getOrCreateCompound("compoundTag").setBoolean("booleanTag", false);
|
||||
expectedDiff2.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D, 4D));
|
||||
|
||||
ReadWriteNBT diff1 = nbt1.extractDifference(nbt2);
|
||||
ReadWriteNBT diff2 = nbt2.extractDifference(nbt1);
|
||||
|
||||
if (!expectedDiff1.equals(diff1)) {
|
||||
throw new NbtApiException("Diff1: Compounds did not match! " + expectedDiff1 + " " + diff1);
|
||||
}
|
||||
if (!expectedDiff2.equals(diff2)) {
|
||||
throw new NbtApiException("Diff2: Compounds did not match! " + expectedDiff2 + " " + diff2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class EnumTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTCompound comp = new NBTContainer();
|
||||
ReadWriteNBT comp = NBT.createNBTObject();
|
||||
comp.setEnum("test", NBTType.NBTTagEnd);
|
||||
NBTType type = comp.getEnum("test", NBTType.class);
|
||||
NBTType typeNonNull = comp.getOrNull("test", NBTType.class);
|
||||
|
||||
+18
-18
@@ -5,44 +5,44 @@ import java.util.Arrays;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class EqualsTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTContainer cont = new NBTContainer();
|
||||
ReadWriteNBT cont = NBT.createNBTObject();
|
||||
cont.setString("hello", "world");
|
||||
cont.setInteger("theAnswer", 42);
|
||||
cont.addCompound("sub").setString("me", "too");
|
||||
cont.getOrCreateCompound("sub").setString("me", "too");
|
||||
cont.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
|
||||
ItemStack item = new ItemStack(Material.STONE);
|
||||
NBTItem nbti = new NBTItem(item);
|
||||
NBTCompound customData = nbti.addCompound("customData");
|
||||
// reverse order
|
||||
customData.addCompound("sub").setString("me", "too");
|
||||
customData.setInteger("theAnswer", 42);
|
||||
customData.setString("hello", "world");
|
||||
customData.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
|
||||
if (!customData.equals(cont)) {
|
||||
throw new NbtApiException("Compounds did not match! " + customData + " " + cont);
|
||||
}
|
||||
NBT.modify(item, nbti -> {
|
||||
ReadWriteNBT customData = nbti.getOrCreateCompound("customData");
|
||||
// reverse order
|
||||
customData.getOrCreateCompound("sub").setString("me", "too");
|
||||
customData.setInteger("theAnswer", 42);
|
||||
customData.setString("hello", "world");
|
||||
customData.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
|
||||
if (!customData.equals(cont)) {
|
||||
throw new NbtApiException("Compounds did not match! " + customData + " " + cont);
|
||||
}
|
||||
});
|
||||
|
||||
// empty test
|
||||
|
||||
if (!new NBTContainer().equals(new NBTContainer())) {
|
||||
if (!NBT.createNBTObject().equals(NBT.createNBTObject())) {
|
||||
throw new NbtApiException("Two empty tags did not match!");
|
||||
}
|
||||
|
||||
// not equal test
|
||||
NBTContainer part1 = new NBTContainer();
|
||||
ReadWriteNBT part1 = NBT.createNBTObject();
|
||||
part1.setString("a", "a");
|
||||
part1.setString("b", "b");
|
||||
NBTContainer part2 = new NBTContainer();
|
||||
ReadWriteNBT part2 = NBT.createNBTObject();
|
||||
part2.setString("a", "a");
|
||||
part2.setString("b", "a");
|
||||
if (part1.equals(part2)) {
|
||||
|
||||
+15
-17
@@ -3,24 +3,22 @@ package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBTList;
|
||||
import de.tr7zw.changeme.nbtapi.NBTListCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTList;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ListTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTContainer comp = new NBTContainer();
|
||||
ReadWriteNBT comp = NBT.createNBTObject();
|
||||
|
||||
// Strings
|
||||
NBTList<String> list = comp.getStringList("testlist");
|
||||
ReadWriteNBTList<String> list = comp.getStringList("testlist");
|
||||
list.add("test1");
|
||||
list.add("test2");
|
||||
list.add("test3");
|
||||
@@ -32,14 +30,14 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// Compound
|
||||
NBTCompoundList taglist = comp.getCompoundList("complist");
|
||||
NBTListCompound lcomp = taglist.addCompound();
|
||||
ReadWriteNBTCompoundList taglist = comp.getCompoundList("complist");
|
||||
ReadWriteNBT lcomp = taglist.addCompound();
|
||||
lcomp.setDouble("double1", 0.3333);
|
||||
lcomp.setInteger("int1", 42);
|
||||
lcomp.setString("test1", "test1");
|
||||
lcomp.setString("test2", "test2");
|
||||
lcomp.removeKey("test1");
|
||||
NBTCompound subsubcomp = lcomp.addCompound("listsubkey");
|
||||
ReadWriteNBT subsubcomp = lcomp.getOrCreateCompound("listsubkey");
|
||||
subsubcomp.setString("deep", "String");
|
||||
subsubcomp.getCompoundList("deeplist").addCompound().setString("test", "test");
|
||||
subsubcomp.getCompoundList("clonelist").addCompound(comp);
|
||||
@@ -73,11 +71,11 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
if (comp.getListType("complist") != NBTType.NBTTagCompound) {
|
||||
throw new NbtApiException("complist had the wrong type! The Item-NBT-API may not work!");
|
||||
throw new NbtApiException("complist had the wrong type(" + comp.getListType("complist") + ")! The Item-NBT-API may not work!");
|
||||
}
|
||||
|
||||
// Integer
|
||||
NBTList<Integer> intlist = comp.getIntegerList("inttest");
|
||||
ReadWriteNBTList<Integer> intlist = comp.getIntegerList("inttest");
|
||||
intlist.add(42);
|
||||
intlist.add(69);
|
||||
if (intlist.size() == 2 && intlist.get(0) == 42 && intlist.get(1) == 69) {
|
||||
@@ -91,7 +89,7 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// Double
|
||||
NBTList<Double> doublelist = comp.getDoubleList("doubletest");
|
||||
ReadWriteNBTList<Double> doublelist = comp.getDoubleList("doubletest");
|
||||
doublelist.add(42.23d);
|
||||
doublelist.add(69.69d);
|
||||
if (doublelist.size() == 2 && doublelist.get(0) == 42.23d && doublelist.get(1) == 69.69d) {
|
||||
@@ -106,7 +104,7 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// Float
|
||||
NBTList<Float> floatlist = comp.getFloatList("floattest");
|
||||
ReadWriteNBTList<Float> floatlist = comp.getFloatList("floattest");
|
||||
floatlist.add(42.23f);
|
||||
floatlist.add(69.69f);
|
||||
if (floatlist.size() == 2 && floatlist.get(0) == 42.23f && floatlist.get(1) == 69.69f) {
|
||||
@@ -120,7 +118,7 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// Long
|
||||
NBTList<Long> longlist = comp.getLongList("longtest");
|
||||
ReadWriteNBTList<Long> longlist = comp.getLongList("longtest");
|
||||
longlist.add(1241234124124l);
|
||||
longlist.add(1231454321312l);
|
||||
if (longlist.size() == 2 && longlist.get(0) == 1241234124124l && longlist.get(1) == 1231454321312l) {
|
||||
@@ -134,7 +132,7 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// int[]
|
||||
NBTList<int[]> intArrayList = comp.getIntArrayList("intatest");
|
||||
ReadWriteNBTList<int[]> intArrayList = comp.getIntArrayList("intatest");
|
||||
intArrayList.add(new int[] { 1, 2, 3 });
|
||||
intArrayList.add(new int[] { 4, 2, 0 });
|
||||
if (intArrayList.size() == 2 && Arrays.equals(new int[] { 1, 2, 3 }, intArrayList.get(0))
|
||||
@@ -149,7 +147,7 @@ public class ListTest implements Test {
|
||||
}
|
||||
|
||||
// UUID
|
||||
NBTList<UUID> uuidList = comp.getUUIDList("uuidtest");
|
||||
ReadWriteNBTList<UUID> uuidList = comp.getUUIDList("uuidtest");
|
||||
uuidList.add(UUID.fromString("fce0323d-7f50-4317-9720-5f6b14cf78ea"));
|
||||
uuidList.add(UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6"));
|
||||
if (uuidList.size() == 2 && UUID.fromString("fce0323d-7f50-4317-9720-5f6b14cf78ea").equals(uuidList.get(0))
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ResolveTest implements Test {
|
||||
@@ -22,6 +26,33 @@ public class ResolveTest implements Test {
|
||||
.getInteger("other") != 123) {
|
||||
throw new NbtApiException("Wasn't able to check the value! The Item-NBT-API may not work!");
|
||||
}
|
||||
ReadWriteNBT comp = src.resolveOrCreateCompound("foo.bar.baz");
|
||||
comp.setIntArray("intarray", new int[] {1,2,3,4,5,6});
|
||||
comp.getStringList("strlist").addAll(Arrays.asList("Hello", "World!"));
|
||||
ReadWriteNBTCompoundList list = comp.getCompoundList("somelist");
|
||||
list.addCompound().setInteger("id", 1);
|
||||
list.addCompound().setInteger("id", 2);
|
||||
list.addCompound().setInteger("id", 3);
|
||||
list.addCompound().setInteger("id", 4);
|
||||
list.addCompound().setInteger("id", 5);
|
||||
list.addCompound().setInteger("id", 6);
|
||||
ReadableNBT listEntry = src.resolveCompound("foo.bar.baz.somelist[0]");
|
||||
if(listEntry == null || listEntry.getInteger("id") != 1) {
|
||||
throw new NbtApiException("The value is not what was expected! The Item-NBT-API may not work!");
|
||||
}
|
||||
ReadableNBT lastEntry = src.resolveOrCreateCompound("foo.bar.baz.somelist[-1]");
|
||||
if(lastEntry == null || lastEntry.getInteger("id") != 6) {
|
||||
throw new NbtApiException("The value is not what was expected! The Item-NBT-API may not work!");
|
||||
}
|
||||
if(src.resolveOrDefault("foo.bar.baz.intarray[1]", 0) != 2) {
|
||||
throw new NbtApiException("The value is not what was expected! The Item-NBT-API may not work!");
|
||||
}
|
||||
if(src.resolveOrNull("foo.bar.baz.intarray[2]", Integer.class) != (Integer)3) {
|
||||
throw new NbtApiException("The value is not what was expected! The Item-NBT-API may not work!");
|
||||
}
|
||||
if(!"World!".equals(src.resolveOrNull("foo.bar.baz.strlist[1]", String.class))) {
|
||||
throw new NbtApiException("The value is not what was expected! The Item-NBT-API may not work!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
-3
@@ -3,24 +3,33 @@ package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class StreamTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTContainer base = new NBTContainer();
|
||||
ReadWriteNBT base = NBT.createNBTObject();
|
||||
base.getOrCreateCompound("sub").setString("hello", "world");
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
base.getOrCreateCompound("sub").writeCompound(outStream);
|
||||
byte[] data = outStream.toByteArray();
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
|
||||
NBTContainer container = new NBTContainer(inputStream);
|
||||
ReadWriteNBT container = NBT.readNBT(inputStream);
|
||||
if (!container.toString().equals(base.getOrCreateCompound("sub").toString())) {
|
||||
throw new NbtApiException("Component content did not match! " + base.getCompound("sub") + " " + container);
|
||||
}
|
||||
ItemStack item = new ItemStack(Material.STICK);
|
||||
|
||||
NBT.modify(item, nbt -> {
|
||||
nbt.writeCompound(outStream);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class SubCompoundsTest implements Test {
|
||||
@@ -19,9 +19,9 @@ public class SubCompoundsTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTContainer cont = new NBTContainer();
|
||||
ReadWriteNBT cont = NBT.createNBTObject();
|
||||
|
||||
NBTCompound comp = cont.addCompound(COMP_TEST_KEY);
|
||||
ReadWriteNBT comp = cont.getOrCreateCompound(COMP_TEST_KEY);
|
||||
comp.setString(STRING_TEST_KEY, STRING_TEST_VALUE + "2");
|
||||
comp.setInteger(INT_TEST_KEY, INT_TEST_VALUE * 2);
|
||||
comp.setDouble(DOUBLE_TEST_KEY, DOUBLE_TEST_VALUE * 2);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.compounds;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class TypeTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
NBTCompound comp = new NBTContainer();
|
||||
ReadWriteNBT comp = NBT.createNBTObject();
|
||||
comp.setString("s", "test");
|
||||
comp.setInteger("i", 42);
|
||||
comp.addCompound("c");
|
||||
comp.getOrCreateCompound("c");
|
||||
if (comp.getType("s") != NBTType.NBTTagString || comp.getType("i") != NBTType.NBTTagInt
|
||||
|| comp.getType("c") != NBTType.NBTTagCompound)
|
||||
throw new NbtApiException("One parsed type did not match what it should have been!");
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.data;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.data.NBTData;
|
||||
import de.tr7zw.changeme.nbtapi.data.WorldData;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class WorldDataTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
if (!new File(world.getWorldFolder(), "level.dat").exists())
|
||||
continue;
|
||||
WorldData data = NBTData.getWorldData(world);
|
||||
if (data.getWorldName() == null || data.getSpawnPosition() == null)
|
||||
throw new NbtApiException("Got Null");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+11
-10
@@ -6,8 +6,7 @@ import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Monster;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
@@ -23,14 +22,16 @@ public class EntityCustomNbtPersistentTest implements Test {
|
||||
try {
|
||||
if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) {
|
||||
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
|
||||
NBTEntity nbtEnt = new NBTEntity(ent);
|
||||
NBTCompound comp = nbtEnt.getPersistentDataContainer();
|
||||
comp.setString("Hello", "World");
|
||||
NBTEntity nbtent = new NBTEntity(ent);
|
||||
if (!nbtent.toString().contains("Hello:\"World\"")) {
|
||||
throw new NbtApiException("Custom Data did not save to the Entity!");
|
||||
}
|
||||
comp.removeKey("Hello");
|
||||
NBT.modifyPersistentData(ent, comp -> {
|
||||
comp.setString("Hello", "World");
|
||||
});
|
||||
|
||||
NBT.modifyPersistentData(ent, comp -> {
|
||||
if (!comp.toString().contains("Hello:\"World\"")) {
|
||||
throw new NbtApiException("Custom Data did not save to the Entity!");
|
||||
}
|
||||
comp.removeKey("Hello");
|
||||
});
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Monster;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
|
||||
public class EntityCustomNbtInjectorTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (!NBTInjector.isInjected())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) {
|
||||
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
|
||||
ent = NBTInjector.patchEntity(ent);
|
||||
NBTCompound comp = NBTInjector.getNbtData(ent);
|
||||
comp.setString("Hello", "World");
|
||||
NBTEntity nbtent = new NBTEntity(ent);
|
||||
if (!nbtent.toString().contains("__extraData:{Hello:\"World\"}")) {
|
||||
throw new NbtApiException("Custom Data did not save to the Entity!");
|
||||
}
|
||||
comp.removeKey("Hello");
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTEntities!", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
|
||||
public class MergeTileSubCompoundTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (!NBTInjector.isInjected())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
boolean failed = false;
|
||||
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255,
|
||||
world.getSpawnLocation().getBlockZ());
|
||||
if (block.getType() == Material.AIR) {
|
||||
block.setType(Material.CHEST);
|
||||
NBTCompound comp = NBTInjector.getNbtData(block.getState());
|
||||
comp.addCompound("subcomp").setString("hello", "world");
|
||||
NBTContainer cont = new NBTContainer();
|
||||
cont.mergeCompound(comp.getCompound("subcomp"));
|
||||
if (!(cont.hasTag("hello") && "world".equals(cont.getString("hello")))) {
|
||||
failed = true;
|
||||
}
|
||||
block.setType(Material.AIR);
|
||||
if (failed) {
|
||||
throw new NbtApiException("Data was not correct! " + cont);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
|
||||
public class SpawnEntityCustomNbtInjectorTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (!NBTInjector.isInjected())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
Entity entity = world.spawnEntity(new Location(world, 0, 0, 0), EntityType.ARMOR_STAND);
|
||||
entity = NBTInjector.patchEntity(entity);
|
||||
NBTCompound comp = NBTInjector.getNbtData(entity);
|
||||
comp.setString("Hello", "World");
|
||||
NBTEntity nbtent = new NBTEntity(entity);
|
||||
if (!nbtent.toString().contains("__extraData:{Hello:\"World\"}")) {
|
||||
throw new NbtApiException("Custom Data did not save to the Entity!");
|
||||
}
|
||||
comp.removeKey("Hello");
|
||||
entity.remove();
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTEntities!", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
import de.tr7zw.nbtinjector.NBTInjector;
|
||||
|
||||
public class TilesCustomNBTInjectorTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if (!NBTInjector.isInjected())
|
||||
return;
|
||||
if (!Bukkit.getWorlds().isEmpty()) {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
try {
|
||||
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255,
|
||||
world.getSpawnLocation().getBlockZ());
|
||||
if (block.getType() == Material.AIR) {
|
||||
block.setType(Material.CHEST);
|
||||
NBTCompound comp = NBTInjector.getNbtData(block.getState());
|
||||
comp.setString("Foo", "Bar");
|
||||
if (!new NBTTileEntity(block.getState()).toString().contains("__extraData:{Foo:\"Bar\"}")) {
|
||||
block.setType(Material.AIR);
|
||||
throw new NbtApiException("Custom Data did not save to the Tile!");
|
||||
}
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.items;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ComponentsTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if(!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return;
|
||||
}
|
||||
ItemStack item = new ItemStack(Material.STICK);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("test");
|
||||
item.setItemMeta(meta);
|
||||
String comp = NBT.modifyComponents(item, n -> {
|
||||
return n.toString();
|
||||
});
|
||||
if(!comp.contains("test")) {
|
||||
throw new NbtApiException("ReadComponent didn't work!");
|
||||
}
|
||||
NBT.modifyComponents(item, nbt -> {
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
|
||||
nbt.mergeCompound(NBT.parseNBT("{\"minecraft:custom_name\":[{\"text\":\"foobar\",\"italic\":false}]}"));
|
||||
} else {
|
||||
nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
|
||||
}
|
||||
});
|
||||
if(!item.getItemMeta().getDisplayName().equals("foobar")) {
|
||||
throw new NbtApiException("ModifyComponent didn't work!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -4,22 +4,27 @@ import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class DirectApplyMetaTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return; // skip
|
||||
}
|
||||
ItemStack baseItem = new ItemStack(Material.STONE);
|
||||
NBTItem nbti = new NBTItem(baseItem, true);
|
||||
nbti.setString("SomeKey", "SomeValue");
|
||||
nbti.modifyMeta(this::modifyMeta);
|
||||
|
||||
if (!new NBTItem(baseItem).hasTag("SomeKey") || !"SomeValue".equals(baseItem.getItemMeta().getDisplayName())) {
|
||||
throw new NbtApiException("The item was not modified correctly!");
|
||||
throw new NbtApiException("The item was not modified correctly! " + NBT.itemStackToNBT(baseItem));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ public class EmptyItemTest implements Test {
|
||||
if (nbti.getBoolean("test") == null || nbti.getString("test") == null || nbti.getFloatList("test") == null) {
|
||||
throw new NbtApiException("Getters return null instead of the default value");
|
||||
}
|
||||
if (!nbti.getKeys().isEmpty()) {
|
||||
throw new NbtApiException("getKeys() returned keys!");
|
||||
}
|
||||
nbti.removeKey("test");
|
||||
if (nbti.hasNBTData()) {
|
||||
throw new NbtApiException("Item reported to have data after remove");
|
||||
}
|
||||
nbti.setString("test", "test");
|
||||
if (!nbti.hasNBTData()) {
|
||||
throw new NbtApiException("Item reported to have no data");
|
||||
|
||||
+16
-7
@@ -1,13 +1,15 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.items;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
@@ -19,14 +21,21 @@ public class ItemConversionTest implements Test {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setLore(Lists.newArrayList("Firest Line", "Second Line"));
|
||||
item.setItemMeta(meta);
|
||||
String nbt = NBTItem.convertItemtoNBT(item).toString();
|
||||
if (!nbt.contains("Firest Line") || !nbt.contains("Second Line"))
|
||||
throw new NbtApiException("The Item nbt '" + nbt + "' didn't contain the lore");
|
||||
ItemStack rebuild = NBTItem.convertNBTtoItem(new NBTContainer(nbt));
|
||||
|
||||
ReadWriteNBT nbt = NBT.itemStackToNBT(item);
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)
|
||||
&& !nbt.hasTag("DataVersion", NBTType.NBTTagInt)) {
|
||||
throw new NbtApiException("The item nbt '" + nbt + "' didn't contain the data version");
|
||||
}
|
||||
|
||||
String nbtString = nbt.toString();
|
||||
if (!nbtString.contains("Firest Line") || !nbtString.contains("Second Line"))
|
||||
throw new NbtApiException("The Item nbt '" + nbtString + "' didn't contain the lore");
|
||||
ItemStack rebuild = NBT.itemStackFromNBT(NBT.parseNBT(nbtString));
|
||||
if (!item.isSimilar(rebuild))
|
||||
throw new NbtApiException("Rebuilt item did not match the original!");
|
||||
|
||||
NBTContainer cont = new NBTContainer();
|
||||
ReadWriteNBT cont = NBT.createNBTObject();
|
||||
cont.setItemStack("testItem", item);
|
||||
if (!item.isSimilar(cont.getItemStack("testItem")))
|
||||
throw new NbtApiException("Rebuilt item did not match the original!");
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.items;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.NBTJsonUtil;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ItemJsonTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ItemStack item = new ItemStack(Material.STONE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("test");
|
||||
meta.setUnbreakable(true);
|
||||
item.setItemMeta(meta);
|
||||
JsonElement elem = NBTJsonUtil.itemStackToJson(item);
|
||||
if (elem == null) {
|
||||
throw new NbtApiException("Getting the Json didn't work correctly! " + item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,12 +6,16 @@ import org.bukkit.inventory.meta.BookMeta;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ItemMergingTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return; // skip, there is no vanilla nbt
|
||||
}
|
||||
ItemStack item = new ItemStack(Material.WRITTEN_BOOK);
|
||||
BookMeta bookMeta = (BookMeta) item.getItemMeta();
|
||||
bookMeta.setAuthor("Author");
|
||||
|
||||
+4
-4
@@ -3,9 +3,9 @@ package de.tr7zw.nbtapi.plugin.tests.items;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class ItemStackConversionTest implements Test {
|
||||
@@ -14,8 +14,8 @@ public class ItemStackConversionTest implements Test {
|
||||
public void test() throws Exception {
|
||||
ItemStack[] src = new ItemStack[] { new ItemStack(Material.STONE), new ItemStack(Material.STICK),
|
||||
new ItemStack(Material.AIR), new ItemStack(Material.STONE) };
|
||||
NBTCompound comp = NBTItem.convertItemArraytoNBT(src);
|
||||
ItemStack[] recreated = NBTItem.convertNBTtoItemArray(comp);
|
||||
ReadWriteNBT comp = NBT.itemStackArrayToNBT(src);
|
||||
ItemStack[] recreated = NBT.itemStackArrayFromNBT(comp);
|
||||
if (recreated == null || src.length != recreated.length) {
|
||||
throw new NbtApiException("Size did not match!");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.items;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.DataFixerUtil;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class LegacyItemTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ItemStack item = NBT
|
||||
.itemStackFromNBT(NBT.parseNBT("{id:cobblestone,Count:42,tag:{Enchantments:[{lvl:3,id:unbreaking}]}}"));
|
||||
if (item.getType() != Material.COBBLESTONE || item.getAmount() != 42
|
||||
|| item.getEnchantmentLevel(Enchantment.DURABILITY) != 3) {
|
||||
throw new NbtApiException("1.20 item didn't load correctly! " + item);
|
||||
}
|
||||
ReadWriteNBT nbt = NBT
|
||||
.parseNBT("{id:cobblestone,Count:42,tag:{display:{Name:\"test\"},ench:[{lvl:3,id:34}]}}");
|
||||
nbt = DataFixerUtil.fixUpItemData(nbt, DataFixerUtil.VERSION1_12_2, DataFixerUtil.getCurrentVersion());
|
||||
item = NBT.itemStackFromNBT(nbt);
|
||||
if (item.getType() != Material.COBBLESTONE || item.getAmount() != 42
|
||||
|| item.getEnchantmentLevel(Enchantment.DURABILITY) != 3
|
||||
|| !"test".equals(item.getItemMeta().getDisplayName())) {
|
||||
throw new NbtApiException("1.12.2 item didn't load correctly! " + item);
|
||||
}
|
||||
|
||||
ItemStack item2 = NBT.itemStackFromNBT(NBT.parseNBT("{DataVersion:" + DataFixerUtil.VERSION1_12_2 + ",id:cobblestone,Count:42,tag:{display:{Name:\"test\"},ench:[{lvl:3,id:34}]}}"));
|
||||
if (!item.equals(item2))
|
||||
throw new NbtApiException("Data-fixed 1.12.2 item didn't load correctly! " + item2);
|
||||
|
||||
ReadWriteNBT testNBT = NBT.parseNBT("{id:cobblestone,Count:42,tag:{display:{Name:\"test\"},ench:[{lvl:3,id:34}]},DataVersion:1343}");
|
||||
testNBT = DataFixerUtil.fixUpItemData(testNBT, DataFixerUtil.VERSION1_12R1);
|
||||
if (testNBT.getInteger("DataVersion") != DataFixerUtil.getCurrentVersion())
|
||||
throw new NbtApiException("DataVersion wasn't updated correctly! " + testNBT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,12 +6,16 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class MetaTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
return; // skip
|
||||
}
|
||||
ItemStack item = new ItemStack(Material.STONE);
|
||||
NBT.modify(item, nbt -> {
|
||||
nbt.setInteger("HideFlags", 1);
|
||||
|
||||
+51
-48
@@ -1,48 +1,51 @@
|
||||
package de.tr7zw.nbtapi.plugin.tests.proxy;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.data.proxy.NBTItemMeta;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
public class DataItemProxyTest implements Test {
|
||||
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ItemStack item = new ItemStack(Material.STONE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("Test");
|
||||
item.setItemMeta(meta);
|
||||
NBT.modify(item, NBTItemMeta.class, nmeta -> {
|
||||
nmeta.setCustomModelData(123);
|
||||
nmeta.setUnbreakable(true);
|
||||
if (!nmeta.getDisplayData().getRawName().contains("Test")) {
|
||||
throw new NbtApiException("Raw name didn't containg the expected String: " + nmeta);
|
||||
}
|
||||
ReadWriteNBT container = NBT.createNBTObject();
|
||||
container.setString("foo", "bar");
|
||||
nmeta.setBlockStateTag(container);
|
||||
if (!container.equals(nmeta.getBlockStateTag())) {
|
||||
throw new NbtApiException("BlockStateTag did not match! " + nmeta);
|
||||
}
|
||||
});
|
||||
|
||||
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
meta = item.getItemMeta();
|
||||
if (!meta.hasCustomModelData() || meta.getCustomModelData() != 123) {
|
||||
throw new NbtApiException("Custom Model Data did not match! " + new NBTItem(item));
|
||||
}
|
||||
if (!meta.isUnbreakable()) {
|
||||
throw new NbtApiException("Unbreakable did not set!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//package de.tr7zw.nbtapi.plugin.tests.proxy;
|
||||
//
|
||||
//import org.bukkit.Material;
|
||||
//import org.bukkit.inventory.ItemStack;
|
||||
//import org.bukkit.inventory.meta.ItemMeta;
|
||||
//
|
||||
//import de.tr7zw.changeme.nbtapi.NBT;
|
||||
//import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
//import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
//import de.tr7zw.changeme.nbtapi.data.proxy.NBTItemMeta;
|
||||
//import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
//import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
//import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
//
|
||||
//public class DataItemProxyTest implements Test {
|
||||
//
|
||||
// @Override
|
||||
// public void test() throws Exception {
|
||||
// if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
|
||||
// return; // skip
|
||||
// }
|
||||
// ItemStack item = new ItemStack(Material.STONE);
|
||||
// ItemMeta meta = item.getItemMeta();
|
||||
// meta.setDisplayName("Test");
|
||||
// item.setItemMeta(meta);
|
||||
// NBT.modify(item, NBTItemMeta.class, nmeta -> {
|
||||
// nmeta.setCustomModelData(123);
|
||||
// nmeta.setUnbreakable(true);
|
||||
// if (!nmeta.getDisplayData().getRawName().contains("Test")) {
|
||||
// throw new NbtApiException("Raw name didn't containg the expected String: " + nmeta);
|
||||
// }
|
||||
// ReadWriteNBT container = NBT.createNBTObject();
|
||||
// container.setString("foo", "bar");
|
||||
// nmeta.setBlockStateTag(container);
|
||||
// if (!container.equals(nmeta.getBlockStateTag())) {
|
||||
// throw new NbtApiException("BlockStateTag did not match! " + nmeta);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
|
||||
// meta = item.getItemMeta();
|
||||
// if (!meta.hasCustomModelData() || meta.getCustomModelData() != 123) {
|
||||
// throw new NbtApiException("Custom Model Data did not match! " + new NBTItem(item));
|
||||
// }
|
||||
// if (!meta.isUnbreakable()) {
|
||||
// throw new NbtApiException("Unbreakable did not set!");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
+23
-3
@@ -9,6 +9,7 @@ import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.handler.NBTHandlers;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.NBTProxy;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.NBTTarget;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.ProxyList;
|
||||
import de.tr7zw.changeme.nbtapi.wrapper.NBTTarget.Type;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
|
||||
@@ -18,12 +19,12 @@ public class SimpleProxyTest implements Test {
|
||||
public void test() throws Exception {
|
||||
ItemStack item = new ItemStack(Material.STONE);
|
||||
NBT.modify(item, TestInterface.class, ti -> {
|
||||
if(ti.hasKills()) {
|
||||
if (ti.hasKills()) {
|
||||
throw new NbtApiException("Item reported to have kills before setting data!");
|
||||
}
|
||||
ti.setKills(42);
|
||||
ti.addKill();
|
||||
if(!ti.hasKills()) {
|
||||
if (!ti.hasKills()) {
|
||||
throw new NbtApiException("Item reported to not have kills after setting data!");
|
||||
}
|
||||
if (!"{Kills:43}".equals(ti.toString())) {
|
||||
@@ -49,6 +50,23 @@ public class SimpleProxyTest implements Test {
|
||||
throw new NbtApiException("The handler in the proxy didn't work correctly!");
|
||||
}
|
||||
});
|
||||
NBT.modify(item, TestInterface.class, ti -> {
|
||||
Statistic a = ti.getStatistics().addCompound();
|
||||
a.setPoints(1);
|
||||
a.addPoint();
|
||||
a.addPoint();
|
||||
ti.getStatistics().addCompound();
|
||||
if (ti.getStatistics().size() != 2) {
|
||||
throw new NbtApiException("List size not as expected!");
|
||||
}
|
||||
ti.getStatistics().remove(1);
|
||||
if (ti.getStatistics().size() != 1) {
|
||||
throw new NbtApiException("List size not as expected!");
|
||||
}
|
||||
if (ti.getStatistics().iterator().next().getPoints() != 3) {
|
||||
throw new NbtApiException("Points not as expected!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface TestInterface extends NBTProxy {
|
||||
@@ -59,7 +77,7 @@ public class SimpleProxyTest implements Test {
|
||||
}
|
||||
|
||||
public boolean hasKills();
|
||||
|
||||
|
||||
public void setKills(int amount);
|
||||
|
||||
public int getKills();
|
||||
@@ -77,6 +95,8 @@ public class SimpleProxyTest implements Test {
|
||||
|
||||
public void setItem(ItemStack item);
|
||||
|
||||
public ProxyList<Statistic> getStatistics();
|
||||
|
||||
}
|
||||
|
||||
public interface Statistic extends NBTProxy {
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
@@ -22,8 +23,16 @@ public class TileTest implements Test {
|
||||
try {
|
||||
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 254,
|
||||
world.getSpawnLocation().getBlockZ());
|
||||
if (block.getChunk().isLoaded() && block.getType() == Material.AIR) {
|
||||
if (world.isChunkLoaded(block.getX() >> 4, block.getZ() >> 4) && block.getType() == Material.AIR) {
|
||||
block.setType(Material.CHEST);
|
||||
if (MinecraftVersion.isNewerThan(MinecraftVersion.MC1_21_R1)) {
|
||||
// 1.21 changed the lock logic. So just try to get/set data, dont check for now
|
||||
NBT.modify(block.getState(), nbt -> {
|
||||
nbt.setString("foo", "bar");
|
||||
});
|
||||
block.setType(Material.AIR);
|
||||
return;
|
||||
}
|
||||
NBTTileEntity tile = new NBTTileEntity(block.getState());
|
||||
if (!MinecraftVersion.isNewerThan(MinecraftVersion.MC1_17_R1)) {
|
||||
if (tile.getInteger("y") != 254) {
|
||||
|
||||
+12
-11
@@ -5,8 +5,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NbtApiException;
|
||||
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
|
||||
import de.tr7zw.nbtapi.plugin.tests.Test;
|
||||
@@ -25,16 +24,18 @@ public class TilesCustomNBTPersistentTest implements Test {
|
||||
try {
|
||||
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 250,
|
||||
world.getSpawnLocation().getBlockZ());
|
||||
if (block.getType() == Material.AIR) {
|
||||
if (world.isChunkLoaded(block.getX() >> 4, block.getZ() >> 4) && block.getType() == Material.AIR) {
|
||||
block.setType(Material.CHEST);
|
||||
NBTTileEntity comp = new NBTTileEntity(block.getState());
|
||||
NBTCompound persistentData = comp.getPersistentDataContainer();
|
||||
persistentData.setString("Foo", "Bar");
|
||||
if (!new NBTTileEntity(block.getState()).getPersistentDataContainer().getString("Foo")
|
||||
.equals("Bar")) {
|
||||
block.setType(Material.AIR);
|
||||
throw new NbtApiException("Custom Data did not save to the Tile!");
|
||||
}
|
||||
NBT.modifyPersistentData(block.getState(), persistentData -> {
|
||||
persistentData.setString("Foo", "Bar");
|
||||
});
|
||||
NBT.getPersistentData(block.getState(), persistentData -> {
|
||||
if (!persistentData.getString("Foo").equals("Bar")) {
|
||||
block.setType(Material.AIR);
|
||||
throw new NbtApiException("Custom Data did not save to the Tile!");
|
||||
}
|
||||
return null;
|
||||
});
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
||||
Whitespace-only changes.
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</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.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -3,13 +3,13 @@ package dev.tr7zw.mappingsparser;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
|
||||
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ public class MappingsParser {
|
||||
public static StringBuilder builder = new StringBuilder();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
File input = new File("minecraft_server.1.20.txt");
|
||||
File input = new File("minecraft_server.1.21.9.txt");
|
||||
List<String> lines = Files.readAllLines(input.toPath());
|
||||
|
||||
Map<String, ClassWrapper> classes = new HashMap<>();
|
||||
@@ -40,6 +40,9 @@ public class MappingsParser {
|
||||
ClassWrapper nmsWrapper = null;
|
||||
Map<ReflectionMethod, String> mappedNames = null;
|
||||
for (String line : lines) {
|
||||
if (line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if (!line.startsWith(" ")) {
|
||||
if (nmsWrapper != null && mappedNames != null) {
|
||||
proccessMapping(nmsWrapper, mappedNames);
|
||||
@@ -72,6 +75,33 @@ public class MappingsParser {
|
||||
}
|
||||
// System.out.println(currentClass + ": " + mojangName + " -> " + unmappedName);
|
||||
}
|
||||
for(String type : MojangToMapping.getMapping().keySet()) {
|
||||
if(type.contains("(")) {
|
||||
continue;
|
||||
}
|
||||
// Field
|
||||
String clazz = type.split("#")[0];
|
||||
String fieldName = type.split("#")[1];
|
||||
for (String line : lines) {
|
||||
if (line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if (!line.startsWith(" ")) {
|
||||
currentClass = line.split(" ")[0];
|
||||
continue;
|
||||
}
|
||||
mojangName = line.trim().split(" ")[1];
|
||||
unmappedName = line.trim().split(" ")[3];
|
||||
if (currentClass.equals(clazz) && mojangName.equals(fieldName)) {
|
||||
if (MojangToMapping.getMapping().get(type) == null) {
|
||||
System.out.println("Missing mapping for " + type);
|
||||
} else if (!MojangToMapping.getMapping().get(type)
|
||||
.equals(unmappedName)) {
|
||||
builder.append("put(\"" + type + "\", \"" + unmappedName + "\");\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(builder);
|
||||
}
|
||||
|
||||
@@ -81,6 +111,8 @@ public class MappingsParser {
|
||||
System.out.println(
|
||||
"Missing mapping in class " + nmsWrapper.getMojangName() + " method " + entry.getKey().name());
|
||||
} else {
|
||||
if(!entry.getValue().equals(MojangToMapping.getMapping().get(nmsWrapper.getMojangName() + "#"
|
||||
+ entry.getKey().getSelectedVersionInfo().name)))
|
||||
builder.append("put(\"" + nmsWrapper.getMojangName() + "#"
|
||||
+ entry.getKey().getSelectedVersionInfo().name + "\", \"" + entry.getValue() + "\");\n");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>nbt-data-api</artifactId>
|
||||
@@ -14,7 +14,7 @@
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-parent</artifactId>
|
||||
<version>2.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</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.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</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.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
<organization>
|
||||
@@ -19,8 +19,6 @@
|
||||
</licenses>
|
||||
<modules>
|
||||
<module>item-nbt-api</module>
|
||||
<module>nbt-injector</module>
|
||||
<module>nbt-data-api</module>
|
||||
<module>item-nbt-plugin</module>
|
||||
<module>mappings-parser</module>
|
||||
</modules>
|
||||
@@ -90,7 +88,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.15.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -99,7 +97,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
@@ -112,7 +110,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.12.0</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
</configuration>
|
||||
@@ -141,13 +139,26 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.7.1</version>
|
||||
<configuration>
|
||||
<licenseName>mit</licenseName>
|
||||
<licenseFile>LICENSE</licenseFile>
|
||||
<force>true</force>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>dev.tr7zw.nojitpack.maven</groupId>
|
||||
<artifactId>no-jitpack-maven-plugin</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>antijitpack</id>
|
||||
<goals>
|
||||
<goal>antijitpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
|
||||
@@ -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.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</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.12.0-SNAPSHOT</version>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
...
|
||||
<plugins>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# Converting Minecraft Objects to NBT and Strings
|
||||
|
||||
The basic idea is that you can convert data into different representations:
|
||||
Minecraft Objects <-> NBT <-> String(Mojang-Json)
|
||||
|
||||
## Converting Minecraft Objects into NBT
|
||||
|
||||
```java
|
||||
// Items
|
||||
ReadWriteNBT nbt = NBT.itemStackToNBT(itemStack);
|
||||
ReadWriteNBT nbt = NBT.itemStackArrayToNBT(itemStacks);
|
||||
// Entity
|
||||
NBTEntity nbte = new NBTEntity(entity);
|
||||
// Tiles
|
||||
NBTTileEntity nbtt= new NBTTileEntity(block.getState());
|
||||
// Gameprofiles
|
||||
ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
|
||||
// NBT Files
|
||||
NBTFile file = new NBTFile(testFile);
|
||||
```
|
||||
|
||||
## Converting NBT to a String and the String back to NBT
|
||||
|
||||
```java
|
||||
// to String(works with any NBT object)
|
||||
String str = nbt.toString();
|
||||
// String back to NBT
|
||||
ReadWriteNBT nbt = NBT.parseNBT(json);
|
||||
```
|
||||
|
||||
## Recreating the Minecraft Objects from NBT
|
||||
|
||||
```java
|
||||
// Items
|
||||
ItemStack itemStack = NBT.nbtToItemStack(nbt);
|
||||
ItemStack[] itemStacks = NBT.nbtToItemStackArray(nbt);
|
||||
// Entity/Tiles
|
||||
In general "new NBTEntity(entity).mergeCompound(nbt)", but you might want to remove some data from the nbt first like the Location, uuid and entityId
|
||||
// Gameprofile
|
||||
GameProfile profile = NBT.nbtToGameProfile(nbt);
|
||||
```
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
## Set a skull's skin
|
||||
|
||||
#### We will be using [this head](https://minecraft-heads.com/custom-heads/head/28194-cup-of-soda) as example.
|
||||
|
||||
```java
|
||||
// This is the base64 texture value from the bottom of the previously mentioned website.
|
||||
final String textureValue = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQyY2M5MjAzYzkwYjg5YmRhYzFkZjI4NDE2NzI2NmI5NTNkZmViZjNjNDY5MGE3Y2QwYjE1NzkxYTYyZTU4MiJ9fX0=";
|
||||
|
||||
|
||||
// Creating ItemStack
|
||||
|
||||
// For Minecraft 1.12.2 and below
|
||||
final ItemStack item = new ItemStack(Material.SKULL_ITEM);
|
||||
item.setDurability((short) 3);
|
||||
|
||||
// For Minecraft 1.13 and newer
|
||||
final ItemStack item = new ItemStack(Material.PLAYER_HEAD);
|
||||
|
||||
|
||||
// Applying nbt
|
||||
|
||||
// For Minecraft 1.20.4 and below
|
||||
NBT.modify(item, nbt -> {
|
||||
ReadWriteNBT skullOwnerCompound = nbt.getOrCreateCompound("SkullOwner");
|
||||
|
||||
// The owner UUID. Note that skulls with the same UUID but different textures will misbehave and only one texture will load.
|
||||
// They will share the texture. To avoid this limitation, it is recommended to use a random UUID.
|
||||
skullOwnerCompound.setUUID("Id", UUID.randomUUID());
|
||||
|
||||
skullOwnerCompound.getOrCreateCompound("Properties")
|
||||
.getCompoundList("textures")
|
||||
.addCompound()
|
||||
.setString("Value", textureValue);
|
||||
});
|
||||
|
||||
// Workaround for Minecraft 1.20.5+
|
||||
NBT.modifyComponents(item, nbt -> {
|
||||
ReadWriteNBT profileNbt = nbt.getOrCreateCompound("minecraft:profile");
|
||||
profileNbt.setUUID("id", uuid);
|
||||
ReadWriteNBT propertiesNbt = profileNbt.getCompoundList("properties").addCompound();
|
||||
propertiesNbt.setString("name", "textures");
|
||||
propertiesNbt.setString("value", textureValue);
|
||||
});
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> If you are using Paper API on 1.12.2+, you may use the following code to create textured skulls
|
||||
|
||||
```java
|
||||
SkullMeta meta = (SkullMeta) item.getItemMeta();
|
||||
PlayerProfile playerProfile = Bukkit.createProfile(uuid);
|
||||
playerProfile.setProperty(new ProfileProperty("textures", textureValue));
|
||||
meta.setPlayerProfile(playerProfile);
|
||||
// You can also use item.editMeta(SkullMeta.class, meta -> {}); on 1.17+
|
||||
item.setItemMeta(meta);
|
||||
```
|
||||
|
||||
## Zombie that can pick up loot and does 0.5 hearts of damage
|
||||
|
||||
This code should serve only as a reference, the nbt structure might change between versions.
|
||||
|
||||
```java
|
||||
Zombie zombie = location.getWorld().spawn(location, Zombie.class);
|
||||
|
||||
String attributeName = "minecraft:generic.attack_damage"; // Or generic.attackDamage prior to 1.16
|
||||
double damageValue = 0.5;
|
||||
|
||||
// Modify vanilla data
|
||||
NBT.modify(zombie, nbt -> {
|
||||
nbt.setBoolean("CanPickUpLoot", true);
|
||||
|
||||
ReadWriteNBTCompoundList list = nbt.getCompoundList("Attributes");
|
||||
|
||||
// Check if zombie already has attribute set. If so, modify it
|
||||
for (ReadWriteNBT listEntryNbt : list) {
|
||||
if (!listEntryNbt.getString("Name").equals(attributeName)) continue;
|
||||
|
||||
listEntryNbt.setDouble("Base", damageValue);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Attribute is missing, add it instead
|
||||
ReadWriteNBT listEntryNbt = list.addCompound();
|
||||
listEntryNbt.setString("Name", attributeName);
|
||||
listEntryNbt.setDouble("Base", damageValue);
|
||||
});
|
||||
|
||||
// Modify custom data
|
||||
NBT.modifyPersistentData(zombie, nbt -> {
|
||||
// Let's mark our zombie as a custom one
|
||||
nbt.setBoolean("custom_zombie", true);
|
||||
});
|
||||
```
|
||||
|
||||
## Reading world data
|
||||
|
||||
```java
|
||||
// Get main world's folder
|
||||
File worldDataFolder = Bukkit.getWorlds().getFirst().getWorldFolder();
|
||||
|
||||
// Read level data
|
||||
NBTFileHandle levelNbtFile = NBT.getFileHandle(new File(worldDataFolder, "level.dat"));
|
||||
|
||||
// Obtain world name
|
||||
String worldName = levelNbtFile.resolveOrNull("Data.LevelName", String.class);
|
||||
|
||||
// Read some player's data
|
||||
UUID playerUuid;
|
||||
File playerFile = new File(worldDataFolder, "playerdata/" + playerUuid + ".dat");
|
||||
if (!playerFile.exists()) {
|
||||
// No offline player data for provided uuid
|
||||
return;
|
||||
}
|
||||
|
||||
NBTFileHandle playerNbtFile = NBT.getFileHandle(playerFile);
|
||||
|
||||
// Change player's health
|
||||
float health = playerNbtFile.getFloat("Health");
|
||||
playerNbtFile.setFloat("Health", health + 5);
|
||||
|
||||
// Once finished, save the file
|
||||
playerNbtFile.save();
|
||||
```
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
## Frequently Asked Questions
|
||||
|
||||
### I've updated NBT-API, but it keeps saying that it's outdated
|
||||
|
||||
Some other plugin on your server has a shaded version of NBT-API. Try looking at the logs to find out which plugin is it, or add/remove your plugins until you find a culprit.
|
||||
|
||||
### I've installed NBT-API, but the plugin keeps asking for ItemNBTAPI
|
||||
|
||||
The plugin uses a very outdated version of NBT-API. In this case, download the version 1.8.3 from the versions tab. The outdated "ItemNBTAPI" and "NBTAPI" can be used both at the same time.
|
||||
|
||||
### 1.7 support
|
||||
|
||||
- Use 1.7.10.
|
||||
- NBTLists may not work.
|
||||
- NBTTypes don't work as 1.7.x is missing this feature.
|
||||
- TLDR: 1.7.10 is a bit broken and not everything will work! Also, it's not supported anymore!
|
||||
|
||||
### Where did NBTInjector go?
|
||||
|
||||
The experimental NBTInjector became unsupported since Minecraft 1.14 and was removed in 2.13.0 with Minecraft 1.21 release.
|
||||
|
||||
NBTInjector is incompatible with reloads and may break things, and thus is not recommended.
|
||||
|
||||
See [this wiki section](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#accessing-custom-data) on how to handle custom entity nbt data without NBTInjector.
|
||||
+8
-17
@@ -1,26 +1,17 @@
|
||||
# Welcome to the NBT API wiki
|
||||
# Welcome to the NBT-API wiki
|
||||
|
||||
NBT API has been tested on Spigot
|
||||
1.7.10-1.19+
|
||||
NBT-API supports Spigot and Paper versions starting at 1.8. It runs on 1.7.10 too, but some features might not work (see [1.7 support](https://github.com/tr7zw/Item-NBT-API/wiki/FAQ#17-support)).
|
||||
|
||||
Full JavaDoc can be found [here](https://tr7zw.github.io/Item-NBT-API/v2-api/)!
|
||||
Feel free to seek for support in [](https://discordapp.com/invite/yk4caxM).
|
||||
|
||||
### What do I have to do as a server owner?
|
||||
|
||||
Just download the jar and drop it in the plugins folder. Done.
|
||||
Note that outdated plugins may ask for "ItemNBTAPI". In this case, download version 1.8.3 from the versions tab. The outdated "ItemNBTAPI" and "NBTAPI" can be used at the same time.
|
||||
Just download the jar and drop it in the plugins folder. Done!
|
||||
|
||||
### 1.7 Notes
|
||||
|
||||
* Use 1.7.10
|
||||
* NBTLists may not work
|
||||
* NBTTypes don't work as 1.7.x is missing this feature.
|
||||
* TLDR: 1.7.10 is a bit broken and not everything will work! Also it's not supported anymore!
|
||||
|
||||
### Don't reload the NBT-Injector
|
||||
|
||||
Reloading in general is a horrible thing and it will break the NBTInjector in horrible ways! When updating plugins/changing configs always restart the server normally!
|
||||
You might also want to check out some [plugins that use NBT-API](https://github.com/tr7zw/Item-NBT-API/wiki/Plugins).
|
||||
|
||||
### How can I use the API as a developer?
|
||||
|
||||
See [Using the NBT API](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API)
|
||||
Import the API using [Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Maven) or [Gradle](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Gradle), then see the [basic usage](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API) or code examples like [working with Skulls](https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages#set-a-skulls-skin) to familiarize yourself with the API.
|
||||
|
||||
Full Javadoc can be found [here](https://tr7zw.github.io/Item-NBT-API/v2-api/)!
|
||||
@@ -1,24 +0,0 @@
|
||||
# Merging Compounds
|
||||
|
||||
You can "merge" the data from any given Compound onto some other Compound. This will overwrite tags with the same name.
|
||||
|
||||
Example:
|
||||
|
||||
`Tag1: {Num1:1, Num2:2} Tag2: {Num1:7, Num3:3}`
|
||||
|
||||
After merging Tag2 on Tag1:
|
||||
|
||||
```java
|
||||
tag1.mergeCompound(tag2);
|
||||
```
|
||||
|
||||
`Tag1: {Num1:7, Num2:2, Num3:3} Tag2: {Num1:7, Num3:3}`
|
||||
|
||||
## Simulate the "/data merge" command
|
||||
|
||||
```java
|
||||
NBT.modify(zombie, nbt -> {
|
||||
nbt.mergeCompound(NBT.parseNBT("{Silent:1b,Invulnerable:1b,Glowing:1b,IsBaby:1b}"));
|
||||
});
|
||||
```
|
||||
|
||||
+7
-4
@@ -1,10 +1,13 @@
|
||||
## List of some plugins on Github that utilize NBTAPI
|
||||
|
||||
Want your plugin added to this list? Submit a PR editing this file located in `~/wiki/Plugins.md`!
|
||||
## List of some plugins on GitHub that utilize NBT-API
|
||||
|
||||
- [IllegalStack](https://github.com/dniym/IllegalStack)
|
||||
- [Prison](https://github.com/PrisonTeam/Prison)
|
||||
- [CommandAPI](https://github.com/JorelAli/CommandAPI)
|
||||
- [CommandAPI](https://github.com/CommandAPI/CommandAPI)
|
||||
- [SkBee](https://github.com/ShaneBeee/SkBee/)
|
||||
- [Monumenta](https://github.com/TeamMonumenta/monumenta-plugins-public/)
|
||||
- [SummonFriendlyMobs](https://github.com/ArmyFury/SummonFriendlyMobs)
|
||||
- [EvenMoreFish](https://github.com/Oheers/EvenMoreFish)
|
||||
|
||||
___
|
||||
|
||||
Want your plugin added to this list? Submit a PR editing this file located in `~/wiki/Plugins.md`!
|
||||
@@ -1,29 +0,0 @@
|
||||
### We will be using [this head](https://minecraft-heads.com/custom-heads/food%20&%20drinks/28194-cup-of-soda) as example.
|
||||
|
||||
```java
|
||||
// This is the base64 texture value from the bottom of the previously mentioned website.
|
||||
final String textureValue = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQyY2M5MjAzYzkwYjg5YmRhYzFkZjI4NDE2NzI2NmI5NTNkZmViZjNjNDY5MGE3Y2QwYjE1NzkxYTYyZTU4MiJ9fX0=";
|
||||
|
||||
// Creating ItemStack
|
||||
|
||||
// For Minecraft 1.12 and above
|
||||
final ItemStack item = new ItemStack(Material.SKULL_ITEM);
|
||||
item.setDurability((short) 3);
|
||||
|
||||
// For Minecraft 1.13 and newer
|
||||
final ItemStack item = new ItemStack(Material.PLAYER_HEAD);
|
||||
|
||||
NBT.modify(item, nbt -> {
|
||||
final ReadWriteNBT skullOwnerCompound = nbt.getOrCreateCompound("SkullOwner");
|
||||
|
||||
// The owner UUID. Note that skulls with the same UUID but different textures will misbehave and only one texture will load.
|
||||
// They will share the texture. To avoid this limitation, it is recommended to use a random UUID.
|
||||
skullOwnerCompound.setUUID("Id", UUID.randomUUID());
|
||||
|
||||
skullOwnerCompound.getOrCreateCompound("Properties")
|
||||
.getCompoundList("textures")
|
||||
.addCompound()
|
||||
.setString("Value", textureValue);
|
||||
});
|
||||
```
|
||||
|
||||
+73
-28
@@ -1,53 +1,73 @@
|
||||
# Option 1) NBT-API as a dependency
|
||||
To start using NB-API, you either need to depend on its plugin version, or shade (include) it inside your plugin.
|
||||
|
||||
Add the following Entries to your Gradle build at the correct location:
|
||||
> [!IMPORTANT]
|
||||
> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
|
||||
>
|
||||
> [!IMPORTANT]
|
||||
> Alternative ways of loading the api like Libby are not supported on Discord/Github issues.
|
||||
|
||||
# Option 1) NBT-API as a dependency (recommended)
|
||||
|
||||
Add the following entries to your Gradle build at the correct locations:
|
||||
|
||||
```groovy
|
||||
repositories {
|
||||
...
|
||||
maven {
|
||||
name = "CodeMC"
|
||||
url = uri("https://repo.codemc.io/repository/maven-public/")
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```groovy
|
||||
compileOnly("de.tr7zw:item-nbt-api-plugin:VERSION")
|
||||
```
|
||||
|
||||
(Get the current Version from [here](https://www.spigotmc.org/resources/nbt-api.7939/))
|
||||
(Get the current ``VERSION`` from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
|
||||
```groovy
|
||||
repositories {
|
||||
...
|
||||
maven {
|
||||
name = "CodeMC"
|
||||
url = uri("https://repo.codemc.io/repository/maven-public/")
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Finally, add the API as dependency to your ``plugin.yml``
|
||||
Add the API as dependency to your ``plugin.yml``:
|
||||
|
||||
```yml
|
||||
depend: [NBTAPI]
|
||||
```
|
||||
|
||||
# Option 2) Shading the NBT-API into your plugin
|
||||
Or, if you are using ``paper-plugin.yml``:
|
||||
|
||||
To include NBT-API directly in your plugin, you can use the gradle shadow plugin.
|
||||
```yml
|
||||
dependencies:
|
||||
server:
|
||||
NBTAPI:
|
||||
load: BEFORE
|
||||
required: true
|
||||
join-classpath: true
|
||||
```
|
||||
|
||||
# Option 2) Shading the NBT-API into your plugin (Not recommended)
|
||||
|
||||
> [!WARNING]
|
||||
> Due to the increasing amount of pitfalls in modern Paper, shading is not recommended. Please test with the normal plugin dependency before reporting issues.
|
||||
|
||||
To include NBT-API directly in your plugin, you can use the [Gradle Shadow Plugin](https://gradleup.com/shadow/).
|
||||
|
||||
Create an empty ``.mojang-mapped`` file in the META-INF folder of your plugin for 1.20+ Paper support.
|
||||
|
||||
> [!WARNING]
|
||||
> Not adding this flag will make the shaded api not work on the latest Paper. It might also break other reflections/nms logic!
|
||||
|
||||
Add the plugin to the build configuration, as shown here:
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id("com.github.johnrengelman.shadow") version "VERSION"
|
||||
id("com.gradleup.shadow") version "VERSION"
|
||||
}
|
||||
```
|
||||
|
||||
The latest version of the shadow plugin can be found [here](https://github.com/johnrengelman/shadow/releases).
|
||||
<br/>
|
||||
The latest version of the shadow plugin can be found [here](https://plugins.gradle.org/plugin/com.gradleup.shadow).
|
||||
|
||||
Add NBT-API to your dependencies:
|
||||
|
||||
```groovy
|
||||
implementation("de.tr7zw:item-nbt-api:VERSION")
|
||||
```
|
||||
|
||||
(Get the current Version from [here](https://www.spigotmc.org/resources/nbt-api.7939/))
|
||||
|
||||
```groovy
|
||||
repositories {
|
||||
...
|
||||
@@ -59,7 +79,16 @@ repositories {
|
||||
}
|
||||
```
|
||||
|
||||
After this you can add the shadowjar configuration to relocate the api package:
|
||||
```groovy
|
||||
implementation("de.tr7zw:item-nbt-api:VERSION")
|
||||
```
|
||||
|
||||
(Get the current ``VERSION`` from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
|
||||
> [!WARNING]
|
||||
> Make sure you're using ``item-nbt-api`` as ``artifactId``, never shade the ``-plugin`` artifact!
|
||||
|
||||
After this you can add the shadowJar configuration to relocate the API package:
|
||||
|
||||
```groovy
|
||||
shadowJar {
|
||||
@@ -67,7 +96,7 @@ shadowJar {
|
||||
}
|
||||
```
|
||||
|
||||
If you want to run the shadowJar task when the build task is executed, you can write like this:
|
||||
If you want to run the shadowJar task when the build task is executed, you can use this:
|
||||
|
||||
```groovy
|
||||
build {
|
||||
@@ -75,3 +104,19 @@ build {
|
||||
}
|
||||
```
|
||||
|
||||
###### Initializing NBT-API early
|
||||
|
||||
If you are shading NBT-API, you may call ``NBT.preloadApi()`` during ``onEnable`` to initialize NBT-API early and check whether everything works. If you omit this step, NBT-API will be initialized on the first call to the API.
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (!NBT.preloadApi()) {
|
||||
getLogger().warning("NBT-API wasn't initialized properly, disabling the plugin");
|
||||
getPluginLoader().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
// Load other things
|
||||
}
|
||||
```
|
||||
|
||||
+92
-42
@@ -1,6 +1,27 @@
|
||||
# Option 1) NBT-API as a dependency
|
||||
To start using NB-API, you either need to depend on its plugin version, or shade (include) it inside your plugin.
|
||||
|
||||
Add the following Entries to your pom at the correct location:
|
||||
> [!IMPORTANT]
|
||||
> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
|
||||
>
|
||||
> [!IMPORTANT]
|
||||
> Alternative ways of loading the api like Libby are not supported on Discord/Github issues.
|
||||
|
||||
# Option 1) NBT-API as a dependency (recommended)
|
||||
|
||||
Add the following entries to your pom at the correct locations:
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
...
|
||||
<!-- CodeMC -->
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
...
|
||||
</repositories>
|
||||
```
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
@@ -11,62 +32,45 @@ Add the following Entries to your pom at the correct location:
|
||||
</dependency>
|
||||
```
|
||||
|
||||
(Get the current Version from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
(Get the current ``VERSION`` from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
...
|
||||
<!-- CodeMC -->
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
...
|
||||
</repositories>
|
||||
```
|
||||
|
||||
Add the API as dependency to your plugin.yml
|
||||
Add the API as dependency to your ``plugin.yml``:
|
||||
|
||||
```yaml
|
||||
depend: [NBTAPI]
|
||||
```
|
||||
|
||||
# Option 2) Shading the NBT-API into your plugin
|
||||
Or, if you are using ``paper-plugin.yml``:
|
||||
|
||||
Add the following Entries to your pom at the correct location:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>VERSION</version>
|
||||
</dependency>
|
||||
```yml
|
||||
dependencies:
|
||||
server:
|
||||
NBTAPI:
|
||||
load: BEFORE
|
||||
required: true
|
||||
join-classpath: true
|
||||
```
|
||||
|
||||
(Get the current Version from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
# Option 2) Shading the NBT-API into your plugin (Not recommended)
|
||||
|
||||
**IMPORTANT: This is not the same ``artifactId`` as using it as dependency! Never shade the ``-plugin`` artifact!**
|
||||
> [!WARNING]
|
||||
> Due to the increasing amount of pitfalls in modern Paper, shading is not recommended. Please test with the normal plugin dependency before reporting issues.
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
...
|
||||
<!-- CodeMC -->
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
...
|
||||
</repositories>
|
||||
```
|
||||
To include NBT-API directly in your plugin, you can use the maven shade plugin.
|
||||
|
||||
Create an empty ``.mojang-mapped`` file in the META-INF folder of your plugin for 1.20+ Paper support.
|
||||
|
||||
> [!WARNING]
|
||||
> Not adding this flag will make the shaded api not work on the latest Paper. It might also break other reflections/nms logic!
|
||||
|
||||
Add the plugin to the build configuration, as shown here:
|
||||
|
||||
```xml
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>shade</id>
|
||||
@@ -88,7 +92,9 @@ Add the following Entries to your pom at the correct location:
|
||||
</plugins>
|
||||
```
|
||||
|
||||
Example:
|
||||
The latest version of the shade plugin can be found [here](https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-shade-plugin).
|
||||
|
||||
Replace ``YOUR PACKAGE WHERE THE API SHOULD END UP`` with your own unique package. For example:
|
||||
|
||||
```xml
|
||||
<relocation>
|
||||
@@ -97,3 +103,47 @@ Example:
|
||||
</relocation>
|
||||
```
|
||||
|
||||
Then, add NBT-API to your dependencies by including the following entries to your pom at the correct locations:
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
...
|
||||
<!-- CodeMC -->
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
...
|
||||
</repositories>
|
||||
```
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api</artifactId>
|
||||
<version>VERSION</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
(Get the current ``VERSION`` from [here](https://modrinth.com/plugin/nbtapi/versions))
|
||||
|
||||
> [!WARNING]
|
||||
> Make sure you're using ``item-nbt-api`` as ``artifactId``, never shade the ``-plugin`` artifact!
|
||||
|
||||
###### Initializing NBT-API early
|
||||
|
||||
If you are shading NBT-API, you may call ``NBT.preloadApi()`` during ``onEnable`` to initialize NBT-API early and check whether everything works. If you omit this step, NBT-API will be initialized on the first call to the API.
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (!NBT.preloadApi()) {
|
||||
getLogger().warning("NBT-API wasn't initialized properly, disabling the plugin");
|
||||
getPluginLoader().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
// Load other things
|
||||
}
|
||||
```
|
||||
|
||||
+476
-61
@@ -1,88 +1,503 @@
|
||||
## Using the ``NBT`` class (prefered)
|
||||
## General usage
|
||||
|
||||
### Basics overview
|
||||
|
||||
Most of the things are exposed inside the [NBT](https://tr7zw.github.io/Item-NBT-API/v2-api/de/tr7zw/changeme/nbtapi/NBT.html) class. Your specific use-case might not yet be covered by the wiki, so make sure to explore the [Javadoc](https://tr7zw.github.io/Item-NBT-API/v2-api/), or ask your IDE for suggestions!
|
||||
|
||||
#### Basic getting and setting of data
|
||||
|
||||
[ReadableNBT](https://tr7zw.github.io/Item-NBT-API/v2-api/de/tr7zw/changeme/nbtapi/iface/ReadableNBT.html) and [ReadWriteNBT](https://tr7zw.github.io/Item-NBT-API/v2-api/de/tr7zw/changeme/nbtapi/iface/ReadWriteNBT.html) are used to read/write nbt:
|
||||
|
||||
```java
|
||||
// Setting data on ItemStacks/Entities/BlockEntities
|
||||
// Creating a new empty NBT tag
|
||||
ReadWriteNBT nbt = NBT.createNBTObject();
|
||||
|
||||
// Setting nbt
|
||||
nbt.setString("Stringtest", "Teststring");
|
||||
nbt.setInteger("Inttest", 42);
|
||||
nbt.setDouble("Doubletest", 1.5);
|
||||
nbt.setBoolean("Booleantest", true);
|
||||
// More are available! Ask your IDE, or see Javadoc for suggestions!
|
||||
|
||||
// Getting nbt
|
||||
String s1 = nbt.getString("Stringtest");
|
||||
int i1 = nbt.getInteger("Inttest");
|
||||
double d = nbt.getDouble("Doubletest");
|
||||
boolean b = nbt.getBoolean("Booleantest");
|
||||
// Or, alternatively
|
||||
String s2 = nbt.getOrDefault("Stringtest", "fallback_value");
|
||||
Integer i2 = nbt.getOrNull("Inttest", Integer.class);
|
||||
|
||||
// Keys manipulation
|
||||
nbt.getKeys(); // Get all Tags
|
||||
nbt.hasTag("key"); // Check whether the Tag exists
|
||||
nbt.hasTag("key", NbtType.NBTTagString); // Check whether the Tag exists and matches the type
|
||||
nbt.removeKey("key"); // Remove the Tag
|
||||
NBTType nbtType = nbt.getType("key"); // Get the type of the Tag
|
||||
|
||||
// Subtag compounds
|
||||
nbt.getCompound("subtag"); // Get a subtag, or null
|
||||
nbt.getOrCreateCompound("subtag"); // Get or create a subtag
|
||||
```
|
||||
|
||||
#### Converting NBT to String and the String back to NBT
|
||||
|
||||
```java
|
||||
// Parse SNBT to nbt
|
||||
ReadWriteNBT nbt = NBT.parseNBT("{Health:20.0f,Motion:[0.0d,10.0d,0.0d],Silent:1b}");
|
||||
// Get the NBT back as a SNBT (works with any NBT object)
|
||||
String snbt = nbt.toString();
|
||||
// Turn back into nbt again
|
||||
ReadWriteNBT nbt2 = NBT.parseNBT(snbt);
|
||||
```
|
||||
|
||||
#### Comparing NBT data
|
||||
|
||||
As with other objects in Java, you may compare nbt using `equals`.
|
||||
|
||||
To see what exactly mismatched, you can use `ReadableNBT#extractDifference`:
|
||||
|
||||
```java
|
||||
ReadWriteNBT nbt1 = NBT.parseNBT("{intTag:1,compoundTag:{floatTag:20.0f,booleanTag:1b}},intArray:[I;1,2]");
|
||||
ReadWriteNBT nbt2 = NBT.parseNBT("{intTag:1,compoundTag:{floatTag:20.0f,booleanTag:0b}},intArray:[I;1,2,3],alsoIntTag:2");
|
||||
|
||||
ReadWriteNBT diff1 = nbt1.extractDifference(nbt2);
|
||||
ReadWriteNBT diff2 = nbt2.extractDifference(nbt1);
|
||||
```
|
||||
|
||||
For the example above, `ReadableNBT#toString` will produce:
|
||||
|
||||
diff1: `{compoundTag:{booleanTag:1b},intArray:[I;1,2]}`
|
||||
|
||||
diff2: `{compoundTag:{booleanTag:0b},intArray:[I;1,2,3],alsoIntTag:2}`
|
||||
|
||||
#### Merging Compounds
|
||||
|
||||
You can "merge" the data from any given Compound onto some other Compound. This will overwrite the tags with the same name.
|
||||
|
||||
Example:
|
||||
|
||||
`Tag1: {Num1:1, Num2:2} Tag2: {Num1:7, Num3:3}`
|
||||
|
||||
After merging Tag2 on Tag1:
|
||||
|
||||
```java
|
||||
tag1.mergeCompound(tag2);
|
||||
```
|
||||
|
||||
`Tag1: {Num1:7, Num2:2, Num3:3} Tag2: {Num1:7, Num3:3}`
|
||||
|
||||
#### Resolving data
|
||||
|
||||
To simplify working with deeply nested NBT, resolve methods allow directly getting or working with these nested tags.
|
||||
|
||||
Compounds are separated by dots ``.`` In case you need a ``.`` inside a key, it can be escaped with a backslash ``\``.
|
||||
|
||||
```java
|
||||
// For example, the following code:
|
||||
nbt.resolveOrCreateCompound("foo.bar.baz");
|
||||
// Will get/create the same subtag compound as:
|
||||
nbt.getOrCreateCompound("foo").getOrCreateCompound("bar").getOrCreateCompound("baz");
|
||||
|
||||
// Get compound if exists, or null otherwise
|
||||
nbt.resolveCompound("foo.some.key.baz");
|
||||
|
||||
// Sets foo/bar/baz/test to 42
|
||||
nbt.resolveOrCreateCompound("foo.bar.baz").setInteger("test", 42);
|
||||
|
||||
// Example of a key with a . in it. Sets the key foo/some.key/baz/other to 123
|
||||
nbt.resolveOrCreateCompound("foo.some\\.key.baz").setInteger("other", 123);
|
||||
|
||||
// Similarly, you may also fetch values from nested compounds
|
||||
String s = nbt.resolveOrDefault("foo.bar.Stringtest", "fallback_value");
|
||||
Integer i = nbt.resolveOrNull("foo\\.bar.baz.Inttest", Integer.class);
|
||||
```
|
||||
|
||||
#### Accessing/creating lists and their data
|
||||
|
||||
> [!NOTE]
|
||||
> The lists will be created if they do not exist, there are no setters for lists!
|
||||
|
||||
```java
|
||||
// Get or create a string list
|
||||
ReadWriteNBTList<String> stringList = nbt.getStringList("list_key");
|
||||
stringList.add("value");
|
||||
|
||||
// Get the list type, NBTTagString in this case
|
||||
NBTType type = nbt.getListType("list_key");
|
||||
|
||||
// You can obtain the value back just like with normal Lists
|
||||
nbt.getStringList("list_key").get(0);
|
||||
// Or by fetching it
|
||||
nbt.resolveOrNull("list_key[0]", String.class); // Get the first value in list
|
||||
// You can also use negative number to get the value from the end of the list/array
|
||||
nbt.resolveOrDefault("list_key[-1]", "fallback_value"); // Get the last value in list, or use the default
|
||||
|
||||
|
||||
// NBT compound lists
|
||||
// Get the list (will create it if needed)
|
||||
ReadWriteNBTCompoundList nbtList = nbt.getOrCreateCompound("foo").getCompoundList("other_key");
|
||||
// Add new compound to the list
|
||||
ReadWriteNBT nbtListEntry = nbtList.addCompound();
|
||||
nbtListEntry.setBoolean("bar", true);
|
||||
// Add existing nbt compound to the list
|
||||
ReadWriteNBT otherNbtListEntry = nbtList.addCompound(NBT.parseNBT("{foo_bar:1b}"));
|
||||
|
||||
// You can fetch compounds in lists
|
||||
nbt.resolveCompound("foo.other_key[0]"); // Get the first compound in list, or null
|
||||
nbt.resolveOrCreateCompound("foo.other_key[1]"); // Get the second compound in list, or create it
|
||||
// Or fetch data from them
|
||||
boolean bar = nbt.resolveOrDefault("foo.other_key[0].bar", false);
|
||||
```
|
||||
|
||||
### Working with items
|
||||
|
||||
You can read/write nbt data on items using ``NBT.get``/``NBT.modify`` methods.
|
||||
|
||||
```java
|
||||
// Setting data
|
||||
NBT.modify(itemStack, nbt -> {
|
||||
nbt.setString("Stringtest", "Teststring");
|
||||
nbt.setInteger("Inttest", 42);
|
||||
nbt.setDouble("Doubletest", 1.5d);
|
||||
nbt.setBoolean("Booleantest", true);
|
||||
//More are available! Ask your IDE/Javadocs for suggestions!
|
||||
// More are available! Ask your IDE, or see Javadoc for suggestions!
|
||||
});
|
||||
// Getting data from ItemStacks
|
||||
String string = NBT.get(itemStack, nbt -> nbt.getString("Stringtest"));
|
||||
|
||||
// Reading data
|
||||
NBT.get(itemStack, nbt -> {
|
||||
String stringTest = nbt.getString("Stringtest");
|
||||
int intTest = nbt.getOrDefault("Inttest", 0);
|
||||
// Do more stuff
|
||||
});
|
||||
|
||||
// Getting data
|
||||
String string = NBT.get(itemStack, nbt -> (String) nbt.getString("Stringtest"));
|
||||
|
||||
// Modifying and getting data
|
||||
int someValue = NBT.modify(itemStack, nbt -> {
|
||||
int i = nbt.getOrDefault("key", 0) + 1;
|
||||
nbt.setInteger(i);
|
||||
return i;
|
||||
});
|
||||
```
|
||||
|
||||
###### ItemMeta usage
|
||||
|
||||
> [!WARNING]
|
||||
> Never mix the usage of ItemMeta and NBT.
|
||||
> Setting ItemMeta will override any changes made to item's nbt.
|
||||
|
||||
```java
|
||||
// WRONG, do not do this!
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
meta.setDisplayName("Modified!");
|
||||
NBT.modify(itemStack, nbt -> nbt.setBoolean("modified", true));
|
||||
itemStack.setItemMeta(meta); // Will undo all changes to nbt!
|
||||
|
||||
|
||||
// Correct, both ItemMeta and NBT will be applied
|
||||
NBT.modify(itemStack, nbt -> nbt.setBoolean("modified", true));
|
||||
// Taking ItemMeta snapshot after changes to nbt
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
meta.setDisplayName("Modified!");
|
||||
itemStack.setItemMeta(meta);
|
||||
// If making any further changes with NBT & ItemMeta,
|
||||
// re-take the item's ItemMeta after changing the nbt!
|
||||
```
|
||||
|
||||
Alternatively, you may safely modify ItemMeta inside the NBT scope:
|
||||
|
||||
```java
|
||||
// Updating ItemMeta using NBT
|
||||
NBT.modify(itemStack, nbt -> {
|
||||
nbt.setInteger("kills", nbt.getOrDefault("kills", 0) + 1);
|
||||
nbt.modifyMeta((meta, readOnlyNbt) -> { // do not modify the nbt while modifying the meta!
|
||||
nbt.modifyMeta((readOnlyNbt, meta) -> { // Do not modify the nbt while modifying the meta!
|
||||
meta.setDisplayName("Kills: " + readOnlyNbt.getOrDefault("kills", 0));
|
||||
});
|
||||
//Do more stuff
|
||||
// Do more stuff
|
||||
});
|
||||
```
|
||||
|
||||
###### Changing vanilla item nbt on 1.20.5+
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Since Minecraft 1.20.5 ItemStacks no longer have vanilla nbt during runtime.
|
||||
> Any calls like ``NBT.get`` or ``NBT.modify`` will access only the item's ``custom_data`` component.
|
||||
>
|
||||
> As a workaround, you may use the following code:
|
||||
|
||||
```java
|
||||
// NOTE: This code is only for 1.20.5+!
|
||||
|
||||
// Only reading vanilla data
|
||||
NBT.getComponents(item, nbt -> {
|
||||
if (nbt.hasTag("minecraft:custom_name")) {
|
||||
String customName = nbt.getString("minecraft:custom_name");
|
||||
}
|
||||
});
|
||||
|
||||
// Gameprofile to NBT
|
||||
ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
|
||||
// NBT to Gameprofile
|
||||
GameProfile profile = NBT.nbtToGameProfile(nbt);
|
||||
// ItemStack to NBT
|
||||
// Modifying vanilla data
|
||||
NBT.modifyComponents(item, nbt -> {
|
||||
nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
|
||||
});
|
||||
```
|
||||
|
||||
### Working with entities and block entities
|
||||
|
||||
Working with entities and block entities is similar to working with items.
|
||||
|
||||
#### Accessing vanilla nbt
|
||||
|
||||
The example code for entities is applicable for block entities too.
|
||||
|
||||
```java
|
||||
// Obtain data
|
||||
boolean silent = NBT.get(entity, nbt -> (boolean) nbt.getBoolean("Silent"));
|
||||
// Modify data
|
||||
NBT.modify(entity, nbt -> {
|
||||
nbt.setBoolean("Silent", true);
|
||||
nbt.setByte("CanPickUpLoot", (byte) 1);
|
||||
});
|
||||
```
|
||||
|
||||
#### Accessing custom data
|
||||
|
||||
> [!WARNING]
|
||||
> Persistent data storage for custom (block-)entity nbt is only available in 1.14+.
|
||||
>
|
||||
> If you need to support versions below that, for entities you may use a workaround like storing data inside an item's nbt that the entity is wearing (e.g. having a button in mob's helmet, and storing data on that button).
|
||||
|
||||
For reading/storing custom data on (block-)entities, you should use methods that end with ``PersistentData``.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When working with block entities, make sure that the block entity exists in the world.
|
||||
>
|
||||
> For example, you may not be able to add data to a chest in `BlockPlaceEvent` because the chest hasn't been placed yet. In such case, you can delay your actions by one tick or set the block to chest manually.
|
||||
|
||||
```java
|
||||
// Obtain data
|
||||
boolean test = NBT.getPersistentData(entity, nbt -> (boolean) nbt.getBoolean("custom_key"));
|
||||
// Modify data
|
||||
NBT.modifyPersistentData(entity, nbt -> {
|
||||
nbt.setBoolean("custom_key", true);
|
||||
nbt.setByte("custom_byte", (byte) 1);
|
||||
});
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If you plan to store some data for players, you might also consider using an external storage instead to not clutter the players' data files inside the world folder. Since any data written to the persistent storage is there forever, you can leave redundant data behind when your plugin is removed, but it's perfectly fine to store data in there otherwise.
|
||||
>
|
||||
> Storage solutions like per-player [NBT files](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#nbt-files) might be more than enough (and is basically what vanilla does, but you'll have your own file instead of using the one inside the world). Cache the file's data on join and save on quit/server shutdown, optionally adding auto saving.
|
||||
|
||||
#### Simulate the "/data merge" command
|
||||
|
||||
Applicable for items/block entities/entities/etc.
|
||||
|
||||
```java
|
||||
NBT.modify(zombie, nbt -> {
|
||||
nbt.mergeCompound(NBT.parseNBT("{Silent:1b,Invulnerable:1b,Glowing:1b,IsBaby:1b}"));
|
||||
});
|
||||
```
|
||||
|
||||
### Working with blocks
|
||||
|
||||
You can store data in block entities (block entities like chest, furnace, etc.) using the examples from the section above, but normal blocks do not have the nbt data.
|
||||
|
||||
Thus, you have to use your own block data storage to store custom block data.
|
||||
|
||||
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
|
||||
// Read the entire PDC or a specific value
|
||||
NBT.readChunkPDC(chunk, nbt -> { /* ... */ });
|
||||
String str = NBT.readAndGetChunkPDC(chunk, nbt -> nbt.getOrNull("key", String.class));
|
||||
```
|
||||
|
||||
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
|
||||
// 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 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.
|
||||
|
||||
## Extras
|
||||
|
||||
> [!TIP]
|
||||
> Besides this page, you may also take a look at some code examples at [example usages](https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages).
|
||||
|
||||
### NBT files
|
||||
|
||||
NBTFileHandle allows working with nbt files.
|
||||
|
||||
```java
|
||||
// Will automatically create the file if it does not exist
|
||||
NBTFileHandle nbtFile = NBT.getFileHandle(new File("directory", "test.nbt"));
|
||||
// Setting data
|
||||
nbtFile.setString("foo", "bar");
|
||||
// Saving the file after applying changes
|
||||
nbtFile.save();
|
||||
```
|
||||
|
||||
Alternatively, you may read the nbt file without maintaining the link to it.
|
||||
Unlike NBTFileHandle, the file won't be automatically created if it does not exist.
|
||||
|
||||
```java
|
||||
File file = new File("directory", "test.nbt");
|
||||
// Reading data from file (will return an empty compound if the file does not exist)
|
||||
ReadWriteNBT nbt = NBT.readFile(file);
|
||||
// Saving nbt to file
|
||||
NBT.writeFile(file, nbt);
|
||||
```
|
||||
|
||||
### Converting Minecraft Objects to NBT and Strings
|
||||
|
||||
The basic idea is that you can convert data into different representations:
|
||||
Minecraft Objects <-> NBT <-> String (SNBT)
|
||||
|
||||
#### Items
|
||||
|
||||
While ``NBT.get/modify`` allows you to modify item's direct nbt (or only the ``custom_data`` container since 1.20.5), the ItemStack object nbt represents the item's serialized data. It includes item type, amount and all extra item tags.
|
||||
|
||||
For example, when ``NBT.get`` looks like this:
|
||||
|
||||
`{foo:"bar",points:12,test:1b}`
|
||||
|
||||
The ItemStack object nbt from ``NBT.itemStackToNBT`` may look like this:
|
||||
|
||||
`{components:{"minecraft:custom_data":{foo:"bar",points:12,test:1b}},count:2,id:"minecraft:stone"}`
|
||||
|
||||
Or like this in versions prior to 1.20.5:
|
||||
|
||||
`{Count:2b,id:"minecraft:stone",tag:{foo:"bar",points:12,test:1b}}`
|
||||
|
||||
###### Serializing/deserializing items
|
||||
|
||||
```java
|
||||
// Saving
|
||||
ReadWriteNBT nbt = NBT.itemStackToNBT(itemStack);
|
||||
// NBT to ItemStack
|
||||
ItemStack itemStack = NBT.nbtToItemStack(nbt);
|
||||
// ItemStack Array to NBT
|
||||
ReadWriteNBT nbt = NBT.itemStackArrayToNBT(itemStacks);
|
||||
// NBT to ItemStack Array
|
||||
ItemStack[] itemStacks = NBT.nbtToItemStackArray(nbt);
|
||||
// Creating a new NBT tag
|
||||
ReadWriteNBT nbt = NBT.createNBTObject();
|
||||
// Parsing a Mojang-Json String to NBT
|
||||
ReadWriteNBT nbt = NBT.parseNBT(json);
|
||||
|
||||
// Restoring
|
||||
ItemStack itemStack = NBT.itemStackFromNBT(nbt);
|
||||
ItemStack[] itemStacks = NBT.itemStackArrayFromNBT(nbt);
|
||||
// Reminder (NBT <-> String)
|
||||
String snbt = nbt.toString();
|
||||
ReadWriteNBT nbt = NBT.parseNBT(snbt);
|
||||
```
|
||||
|
||||
## Old style of creating a NBT Wrapper
|
||||
#### Entities and block entities
|
||||
|
||||
```java
|
||||
NBTItem nbti = new NBTItem(ItemStack);
|
||||
|
||||
NBTEntity nbtent = new NBTEntity(Entity); // Vanilla tags only!
|
||||
|
||||
NBTTileEntity tent = new NBTTileEntity(block.getState()); // Vanilla tags only!
|
||||
|
||||
NBTFile file = new NBTFile(new File("directory"), "test.nbt")); // Will be created at ./directory/test.nbt
|
||||
|
||||
NBTContainer container = new NBTContainer(json); // Parse in json
|
||||
|
||||
NBTContainer container = new NBTContainer(); // Empty NBTCompound
|
||||
// Saving
|
||||
ReadWriteNBT entityNbt = NBT.createNBTObject();
|
||||
NBT.get(entity, entityNbt::mergeCompound);
|
||||
// Restoring
|
||||
NBT.modify(entity, nbt -> {
|
||||
// You might also want to filter out entityNbt first,
|
||||
// e.g. remove some data like location, uuid, entityId, etc.
|
||||
nbt.mergeCompound(entityNbt);
|
||||
});
|
||||
```
|
||||
|
||||
## Using the wrapper(NBTCompound/)
|
||||
#### Game profiles
|
||||
|
||||
```java
|
||||
//Set
|
||||
nbti.setString("Stringtest", "Teststring");
|
||||
nbti.setInteger("Inttest", 42);
|
||||
nbti.setDouble("Doubletest", 1.5d);
|
||||
nbti.setBoolean("Booleantest", true);
|
||||
//More are available! Ask your IDE for suggestions! Don't use deprecated methods!
|
||||
|
||||
//Access/create lists
|
||||
nbtent.getCompoundList("Attributes");
|
||||
nbtent.getStringList("Attributes");
|
||||
//The list will be created if it doesn't exist, there is no setter for lists!
|
||||
|
||||
//Get
|
||||
nbti.getString("Stringtest");
|
||||
nbti.getInteger("Inttest");
|
||||
nbti.getDouble("Doubletest");
|
||||
nbti.getBoolean("Booleantest");
|
||||
nbti.getKeys(); //Get all Tags
|
||||
nbti.hasTag("Key");
|
||||
nbti.removeKey("Key");
|
||||
|
||||
nbti.getOrCreateCompound("subtag"); // Get or create a subtag
|
||||
|
||||
NBTCompound comp = nbti.getCompound("subtag"); // Get the tag or null
|
||||
B.mergeCompound(A); // Merge the data from compound A into B (Like the /data merge command)
|
||||
comp.toString(); // Get the nbt as a Mojang-Json string
|
||||
// Saving
|
||||
ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
|
||||
// Restoring
|
||||
GameProfile profile = NBT.gameProfileFromNBT(nbt);
|
||||
```
|
||||
|
||||
### Interface proxies
|
||||
|
||||
You may define your own interfaces extending ``NBTProxy`` to create wrappers around nbt.
|
||||
|
||||
Methods starting with ``has``/``get``/``set`` will be interpreted as their respective calls.
|
||||
|
||||
```java
|
||||
interface TestInterface extends NBTProxy {
|
||||
// Runs: return nbt.hasTag("kills");
|
||||
boolean hasKills();
|
||||
// Runs: nbt.setInteger("kills", amount);
|
||||
void setKills(int amount);
|
||||
// Runs: return nbt.getInteger("kills");
|
||||
int getKills();
|
||||
|
||||
// Also supported
|
||||
default void addKill() {
|
||||
setKills(getKills() + 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Getters are also allowed to return other interfaces extending ``NBTProxy``.
|
||||
|
||||
And by using ``@NBTTarget`` annotation you may have a more gradual control over data. It allows setting the type of the method (``has``/``get``/``set``) and the data key.
|
||||
|
||||
```java
|
||||
interface TestInterface extends NBTProxy {
|
||||
// Will get PointsInterface from data in "other" key
|
||||
@NBTTarget(type = Type.GET, value = "other")
|
||||
PointsInterface getOtherInterface();
|
||||
}
|
||||
|
||||
interface PointsInterface extends NBTProxy {
|
||||
int getPoints();
|
||||
void setPoints(int points);
|
||||
}
|
||||
```
|
||||
|
||||
To support other data types like ItemStacks, you need to override the init method and register appropriate handlers.
|
||||
|
||||
```java
|
||||
interface TestInterface extends NBTProxy {
|
||||
@Override
|
||||
default void init() {
|
||||
registerHandler(ItemStack.class, NBTHandlers.ITEM_STACK);
|
||||
registerHandler(ReadableNBT.class, NBTHandlers.STORE_READABLE_TAG);
|
||||
registerHandler(ReadWriteNBT.class, NBTHandlers.STORE_READWRITE_TAG);
|
||||
}
|
||||
|
||||
ItemStack getItem();
|
||||
void setItem(ItemStack item);
|
||||
|
||||
ReadWriteNBT getBlockStateTag();
|
||||
void setBlockStateTag(ReadableNBT blockState);
|
||||
}
|
||||
```
|
||||
|
||||
``NBTHandlers`` class contains some pre-defined handlers.
|
||||
|
||||
###### Custom handlers
|
||||
|
||||
If you need to support custom data types that aren't available in ``NBTHandlers``, you can write your own by creating a new ``NBTHandler``.
|
||||
|
||||
You can refer to [NBTHandlers](https://github.com/tr7zw/Item-NBT-API/blob/master/item-nbt-api/src/main/java/de/tr7zw/changeme/nbtapi/handler/NBTHandlers.java) class to see how the default implementations are done.
|
||||
|
||||
### Data fixer utils
|
||||
|
||||
``DataFixerUtil`` allows updating nbt from older versions to more recent ones.
|
||||
|
||||
For example, given the input from 1.12.2:
|
||||
|
||||
`{Count:42,id:"cobblestone",tag:{display:{Name:"test"},ench:[{id:34,lvl:3}]}}`
|
||||
|
||||
You can update it to 1.20.6:
|
||||
|
||||
`{components:{"minecraft:custom_name":'{"text":"test"}',"minecraft:enchantments":{levels:{"minecraft:unbreaking":3}}},count:42,id:"minecraft:cobblestone"}`
|
||||
|
||||
By using the following code:
|
||||
|
||||
```java
|
||||
DataFixerUtil.fixUpItemData(nbt, DataFixerUtil.VERSION1_12_2, DataFixerUtil.VERSION1_20_6);
|
||||
```
|
||||
|
||||
You can also use ``DataFixerUtil.getCurrentVersion()`` to update the data to whatever version the server is running.
|
||||
@@ -1,14 +0,0 @@
|
||||
```java
|
||||
Zombie zombie = (Zombie) b.getWorld().spawnEntity(b.getLocation().add(0, 1, 0), EntityType.ZOMBIE);
|
||||
NBT.modify(zombie, nbt -> {
|
||||
nbt.setByte("CanPickUpLoot", (byte) 1);
|
||||
ReadWriteNBTCompoundList list = nbt.getCompoundList("Attributes");
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
ReadWriteNBT lc = list.get(i);
|
||||
if(lc.getString("Name").equals("generic.attackDamage")){
|
||||
lc.setDouble("Base", 0.5d);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
[tr7zw](https://github.com/tr7zw)
|
||||
[SpigotMC](https://www.spigotmc.org/resources/nbt-api.7939/)
|
||||
[Modrinth](https://modrinth.com/plugin/nbtapi)
|
||||
[Bukkit](https://dev.bukkit.org/projects/nbt-api)
|
||||
[Hangar](https://hangar.papermc.io/tr7zw/NBTAPI)
|
||||
[SpigotMC](https://www.spigotmc.org/resources/nbt-api.7939/)
|
||||
[Bukkit](https://dev.bukkit.org/projects/nbt-api)
|
||||
+12
-9
@@ -1,21 +1,24 @@
|
||||
[Home](https://github.com/tr7zw/Item-NBT-API/wiki)
|
||||
|
||||
[Using the NBT API](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API)
|
||||
[Using Maven](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Maven) /
|
||||
[Using Gradle](https://github.com/tr7zw/Item-NBT-API/wiki/Using-Gradle)
|
||||
|
||||
[FAQ](https://github.com/tr7zw/Item-NBT-API/wiki/FAQ)
|
||||
|
||||
## Code Examples
|
||||
|
||||
### General
|
||||
|
||||
* [Converting Minecraft Objects to NBT and Strings](https://github.com/tr7zw/Item-NBT-API/wiki/Converting-Minecraft-Objects-to-NBT-and-Strings)
|
||||
* [Merging Compounds](https://github.com/tr7zw/Item-NBT-API/wiki/Merging-Compounds-(Copy-the-data-from-one-onto-another-compound))
|
||||
* [Basics](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API)
|
||||
* [Items](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#working-with-items)
|
||||
* [Block-Entities/Entities](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#working-with-entities-and-block-entities)
|
||||
* [Blocks](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#working-with-blocks)
|
||||
|
||||
### Items
|
||||
### Extras
|
||||
|
||||
* [Set a skull's skin using NBT API](https://github.com/tr7zw/Item-NBT-API/wiki/Set-a-skull's-skin-using-NBT-API)
|
||||
|
||||
### Entities
|
||||
|
||||
* [Zombie that can pick up loot and does 0.5 hearths of damage](https://github.com/tr7zw/Item-NBT-API/wiki/Zombie-that-can-pick-up-loot-and-does-0.5-hearths-of-damage)
|
||||
* [Example usages](https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages)
|
||||
* [NBT files](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#nbt-files)
|
||||
* [NBT objects](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#converting-minecraft-objects-to-nbt-and-strings)
|
||||
* [Interface proxies](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#interface-proxies)
|
||||
* [Data fixer utils](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#data-fixer-utils)
|
||||
|
||||
Reference in new issue
Block a user