diff --git a/README.md b/README.md
index 8fbe9fd11..5a41acb2b 100644
--- a/README.md
+++ b/README.md
@@ -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
@@ -15,7 +15,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
diff --git a/curseforge.md b/curseforge.md
index 217ab406c..a019b8c0b 100644
--- a/curseforge.md
+++ b/curseforge.md
@@ -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:[![Discord](https://img.shields.io/discord/342814924310970398?color=%237
## 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
diff --git a/wiki/Converting-Minecraft-Objects-to-NBT-and-Strings.md b/wiki/Converting-Minecraft-Objects-to-NBT-and-Strings.md
deleted file mode 100644
index 775f41219..000000000
--- a/wiki/Converting-Minecraft-Objects-to-NBT-and-Strings.md
+++ /dev/null
@@ -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.itemStackFromNBT(nbt);
-ItemStack[] itemStacks = NBT.itemStackArrayFromNBT(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.gameProfileFromNBT(nbt);
-```
-
diff --git a/wiki/Example-Usages.md b/wiki/Example-Usages.md
new file mode 100644
index 000000000..12a504e3a
--- /dev/null
+++ b/wiki/Example-Usages.md
@@ -0,0 +1,122 @@
+## 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
+NBTFile levelNbtFile = new NBTFile(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;
+}
+
+NBTFile playerNbtFile = new NBTFile(playerFile);
+
+// Change player's health
+float health = playerNbtFile.getFloat("Health");
+playerNbtFile.setFloat("Health", health + 5);
+```
+
diff --git a/wiki/FAQ.md b/wiki/FAQ.md
new file mode 100644
index 000000000..b79fab5b5
--- /dev/null
+++ b/wiki/FAQ.md
@@ -0,0 +1,26 @@
+## 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.
+
+If you're using Minecraft 1.14+, you should switch to the persistent storage API instead.
+
+In versions prior to 1.14, 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).
diff --git a/wiki/Home.md b/wiki/Home.md
index 3cd554ca0..8c8d4453c 100644
--- a/wiki/Home.md
+++ b/wiki/Home.md
@@ -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 [![Discord](https://img.shields.io/discord/342814924310970398?color=%237289DA&label=Discord&logo=discord&logoColor=white)](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/Set-a-skull's-skin-using-NBT-API) to familiarize yourself with the API.
+
+Full Javadoc can be found [here](https://tr7zw.github.io/Item-NBT-API/v2-api/)!
diff --git a/wiki/Merging-Compounds-(Copy-the-data-from-one-onto-another-compound).md b/wiki/Merging-Compounds-(Copy-the-data-from-one-onto-another-compound).md
deleted file mode 100644
index b8992bcc2..000000000
--- a/wiki/Merging-Compounds-(Copy-the-data-from-one-onto-another-compound).md
+++ /dev/null
@@ -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}"));
-});
-```
-
diff --git a/wiki/Plugins.md b/wiki/Plugins.md
index 24df57fd0..0f428780a 100644
--- a/wiki/Plugins.md
+++ b/wiki/Plugins.md
@@ -1,6 +1,4 @@
-## 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)
@@ -8,3 +6,6 @@ Want your plugin added to this list? Submit a PR editing this file located in `~
- [SkBee](https://github.com/ShaneBeee/SkBee/)
- [Monumenta](https://github.com/TeamMonumenta/monumenta-plugins-public/)
+___
+
+Want your plugin added to this list? Submit a PR editing this file located in `~/wiki/Plugins.md`!
diff --git a/wiki/Set-a-skull's-skin-using-NBT-API.md b/wiki/Set-a-skull's-skin-using-NBT-API.md
deleted file mode 100644
index 6967d9286..000000000
--- a/wiki/Set-a-skull's-skin-using-NBT-API.md
+++ /dev/null
@@ -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);
-});
-```
-
diff --git a/wiki/Using-Gradle.md b/wiki/Using-Gradle.md
index dd1b9d1e2..512f6f660 100644
--- a/wiki/Using-Gradle.md
+++ b/wiki/Using-Gradle.md
@@ -1,12 +1,17 @@
+To start using NB-API, you either need to depend on its plugin version, or shade (include) it inside your plugin.
+
+> [!IMPORTANT]
+> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
+
# Option 1) NBT-API as a dependency
-Add the following Entries to your Gradle build at the correct location:
+Add the following entries to your Gradle build at the correct locations:
```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 {
@@ -19,7 +24,7 @@ repositories {
}
```
-Finally, add the API as dependency to your ``plugin.yml``
+Add the API as dependency to your ``plugin.yml``:
```yml
depend: [NBTAPI]
@@ -38,7 +43,6 @@ plugins {
```
The latest version of the shadow plugin can be found [here](https://github.com/johnrengelman/shadow/releases).
-
Add NBT-API to your dependencies:
@@ -46,7 +50,10 @@ Add NBT-API to your dependencies:
implementation("de.tr7zw:item-nbt-api: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))
+
+> [!WARNING]
+> Make sure you're using ``item-nbt-api`` as ``artifactId``, never shade the ``-plugin`` artifact!
```groovy
repositories {
@@ -59,7 +66,7 @@ repositories {
}
```
-After this you can add the shadowjar configuration to relocate the api package:
+After this you can add the shadowJar configuration to relocate the API package:
```groovy
shadowJar {
@@ -67,7 +74,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 {
diff --git a/wiki/Using-Maven.md b/wiki/Using-Maven.md
index 61313bcaa..b8de94259 100644
--- a/wiki/Using-Maven.md
+++ b/wiki/Using-Maven.md
@@ -1,6 +1,11 @@
+To start using NB-API, you either need to depend on its plugin version, or shade (include) it inside your plugin.
+
+> [!IMPORTANT]
+> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
+
# Option 1) NBT-API as a dependency
-Add the following Entries to your pom at the correct location:
+Add the following entries to your pom at the correct locations:
```xml
@@ -11,7 +16,7 @@ Add the following Entries to your pom at the correct location:
```
-(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
@@ -26,7 +31,7 @@ Add the following Entries to your pom at the correct location:
```
-Add the API as dependency to your plugin.yml
+Add the API as dependency to your ``plugin.yml``:
```yaml
depend: [NBTAPI]
@@ -34,39 +39,16 @@ depend: [NBTAPI]
# Option 2) Shading the NBT-API into your plugin
-Add the following Entries to your pom at the correct location:
+To include NBT-API directly in your plugin, you can use the maven shade plugin.
-```xml
-
- de.tr7zw
- item-nbt-api
- VERSION
-
-```
-
-(Get the current Version from [here](https://modrinth.com/plugin/nbtapi/versions))
-
-**IMPORTANT: This is not the same ``artifactId`` as using it as dependency! Never shade the ``-plugin`` artifact!**
-
-```xml
-
-...
-
-
-codemc-repo
-https://repo.codemc.io/repository/maven-public/
-default
-
-...
-
-```
+Add the plugin to the build configuration, as shown here:
```xml
org.apache.maven.plugins
maven-shade-plugin
- 3.4.1
+ 3.6.0
shade
@@ -88,7 +70,9 @@ Add the following Entries to your pom at the correct location:
```
-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
@@ -97,3 +81,31 @@ Example:
```
+Then, add NBT-API to your dependencies by including the following entries to your pom at the correct locations:
+
+```xml
+
+ 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!
+
+```xml
+
+...
+
+
+codemc-repo
+https://repo.codemc.io/repository/maven-public/
+default
+
+...
+
+```
+
diff --git a/wiki/Using-the-NBT-API.md b/wiki/Using-the-NBT-API.md
index be1281ff1..3b996c15b 100644
--- a/wiki/Using-the-NBT-API.md
+++ b/wiki/Using-the-NBT-API.md
@@ -1,88 +1,423 @@
-## 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. Make sure to explore the Javadoc, 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
+// 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 Mojang-Json string to nbt
+ReadWriteNBT nbt = NBT.parseNBT("{Health:20.0f,Motion:[0.0d,10.0d,0.0d],Silent:1b}");
+// Get the NBT back as a Mojang-Json string (works with any NBT object)
+String json = nbt.toString();
+// Turn back into nbt again
+ReadWriteNBT nbt2 = NBT.parseNBT(json);
+```
+
+#### 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
-// Setting data on ItemStacks/Entities/BlockEntities
+// 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 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
+ReadWriteNBTCompoundList nbtList = nbt.getOrCreateCompound("foo").getCompoundList("other_key");
+ReadWriteNBT nbtListEntry = addCompound();
+nbtListEntry.setBoolean("bar", true);
+
+// 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
+
+```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!
+});
+
+// Reading data
+NBT.get(itemStack, nbt -> {
+ String stringTest = nbt.getString("Stringtest");
+ int intTest = nbt.getOrDefault("Inttest", 0);
+ // Do more stuff
});
-// Getting data from ItemStacks
-String string = NBT.get(itemStack, nbt -> nbt.getString("Stringtest"));
+
+// 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;
+});
+
// 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((meta, readOnlyNbt) -> { // Do not modify the nbt while modifying the meta!
meta.setDisplayName("Kills: " + readOnlyNbt.getOrDefault("kills", 0));
});
- //Do more stuff
+ // Do more stuff
});
+```
-// Gameprofile to NBT
-ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
-// NBT to Gameprofile
-GameProfile profile = NBT.nbtToGameProfile(nbt);
-// ItemStack to NBT
+###### 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+!
+NBT.modifyComponents(item, nbt -> {
+ nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
+});
+```
+
+### Working with (block-)entities
+
+Working with entities and block entities is similar to working 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
+
+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 since 1.16.4, and NBT-API allows you to do so by using ``NBTChunk``:
+
+```java
+ReadWriteNBT nbt = new NBTChunk(chunk).getPersistentDataContainer();
+```
+
+Similarly, there is ``NBTBlock``, which allows you to store block data inside chunk's data.
+
+```java
+// Block's data will be stored in Chunk's data in "blocks.x_y_z" subtag
+ReadWriteNBT nbt = new NBTBlock(block).getData();
+```
+
+**However**, keep in mind that this data is linked only to the location, and if the block gets broken/changed/exploded/moved/etc., the data will still be on that location unless manually cleared/moved!
+
+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
+
+```java
+// Creating nbt file
+// NBTFile will automatically create the file if it does not exist
+NBTFile file = new NBTFile(new File("directory"), "test.nbt"); // Will be created at ./directory/test.nbt
+// Setting data
+file.setString("foo", "bar");
+// Saving file
+file.save();
+
+// Alternatively, you may use helper methods in NBTFile class
+// To read the file without creating it if does not exist:
+ReadWriteNBT nbt = NBTFile.readFrom(file);
+// To save nbt to the file:
+NBTFile.saveTo(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 (Mojang-Json)
+
+#### 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.itemStackFromNBT(nbt);
-// ItemStack Array to NBT
ReadWriteNBT nbt = NBT.itemStackArrayToNBT(itemStacks);
-// NBT to ItemStack Array
+// Restoring
+ItemStack itemStack = NBT.itemStackFromNBT(nbt);
ItemStack[] itemStacks = NBT.itemStackArrayFromNBT(nbt);
-// Creating a new NBT tag
-ReadWriteNBT nbt = NBT.createNBTObject();
-// Parsing a Mojang-Json String to NBT
+// Reminder (NBT <-> String)
+String json = nbt.toString();
ReadWriteNBT nbt = NBT.parseNBT(json);
+```
+
+#### (Block-)Entities
+```java
+// 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);
+});
```
-## Old style of creating a NBT Wrapper
+#### Game profiles
```java
-NBTItem nbti = new NBTItem(ItemStack);
+// Saving
+ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
+// Restoring
+GameProfile profile = NBT.gameProfileFromNBT(nbt);
+```
-NBTEntity nbtent = new NBTEntity(Entity); // Vanilla tags only!
+### Interface proxies
-NBTTileEntity tent = new NBTTileEntity(block.getState()); // Vanilla tags only!
+You may define your own interfaces extending ``NBTProxy`` to create wrappers around nbt.
-NBTFile file = new NBTFile(new File("directory"), "test.nbt")); // Will be created at ./directory/test.nbt
+Methods starting with ``has``/``get``/``set`` will be interpreted as their respective calls.
-NBTContainer container = new NBTContainer(json); // Parse in json
+```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();
-NBTContainer container = new NBTContainer(); // Empty NBTCompound
+ // Also supported
+ default void addKill() {
+ setKills(getKills() + 1);
+ }
+}
```
-## Using the wrapper(NBTCompound/)
+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
-//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!
+interface TestInterface extends NBTProxy {
+ // Will get PointsInterface from data in "other" key
+ @NBTTarget(type = Type.GET, value = "other")
+ PointsInterface getOtherInterface();
+}
-//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!
+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
-//Get
-nbti.getString("Stringtest");
-nbti.getInteger("Inttest");
-nbti.getDouble("Doubletest");
-nbti.getBoolean("Booleantest");
-nbti.getKeys(); //Get all Tags
-nbti.hasTag("Key");
-nbti.removeKey("Key");
+If you need to support custom data types that aren't available in ``NBTHandlers``, you can write your own by creating a new ``NBTHandler``.
-nbti.getOrCreateCompound("subtag"); // Get or create a subtag
+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.
-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
+### Data fixer utils
+
+``DataFixerUtil`` allows updating nbt from versions since 1.12.2 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.
diff --git a/wiki/Zombie-that-can-pick-up-loot-and-does-0.5-hearths-of-damage.md b/wiki/Zombie-that-can-pick-up-loot-and-does-0.5-hearths-of-damage.md
deleted file mode 100644
index ba170e120..000000000
--- a/wiki/Zombie-that-can-pick-up-loot-and-does-0.5-hearths-of-damage.md
+++ /dev/null
@@ -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);
- }
- }
-});
-```
-
diff --git a/wiki/_Footer.md b/wiki/_Footer.md
index cec3c3a1e..16bed66bc 100644
--- a/wiki/_Footer.md
+++ b/wiki/_Footer.md
@@ -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)
diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md
index c5f4c674f..17c45a218 100644
--- a/wiki/_Sidebar.md
+++ b/wiki/_Sidebar.md
@@ -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))
-
-### Items
-
-* [Set a skull's skin using NBT API](https://github.com/tr7zw/Item-NBT-API/wiki/Set-a-skull's-skin-using-NBT-API)
+* [Basics](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#basics-overview)
+* [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-(block-)entities)
+* [Blocks](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#working-with-blocks)
-### Entities
+### Extras
-* [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-converter-utils)