JEFF Media Developer Blog

Java & Spigot development

Menu
  • Blog
  • Main Website
  • Privacy Policy
Menu

Persistent Data Container: the better alternative to NBT Tags

Posted on October 9, 2021October 9, 2021 by mfnalex

or: Why you should NEVER use NBT tags again!

Spigot 1.14.1 added the biggest improvement that (in my opinion) ever made it into the Bukkit API: The Persistent Data Container (PDC). It can be used to store custom data on Entities, TileEntities, and ItemStacks. Using a bit of math, it can also be used to store custom data inside blocks.

Advantages over NBT

  • No need to use dirty NMS classes – PDC is part of the API (and has been for years)!
  • You can store any type of data inside PDCs
  • The data is actually persistent, unlike for example NBT tags on TileEntities

Where can PDC be used?

All Entities, TileEntities and ItemMetas implement the PersistentDataHolder interface, meaning they provide a PersistentDataContainer using the getPersistentDataContainer() method. That means you can store ANY kind and amount of data inside, for example

  • Mobs
  • Players
  • Vehicles like Minecarts and Boats
  • Other Entities like ArmorStands, Arrows, ShulkerBullets, AreaEffectClouds, …
  • TileEntities like Chests, ShulkerBoxes, Beacons, Beehives, …
  • Chunks (in 1.16.3 and later)
  • and even every Block (with a bit of Math by using the Chunk instead)

Introduction to NamespacedKeys

Using PDCs is pretty straightforward. Data in a PDC is stored similar to a HashMap, with the Key being a NamespacedKey. They are used so that two plugins that store a value of the same name are not conflicting with each other. The best way to create a NamespacedKey is by providing an instance of your plugin, and a name for your key, like this:

NamespacedKey myKey = new NamespacedKey(myPlugin, "myKey");

It’s also possible to create keys using a name instead of the plugin instance, but you should always use the plugin instance when you can.

Since you probably need the same NamespacedKey more than once, you should store them somewhere – e.g. as public static final fields in your main class. That also avoids you having to debug disgusting errors that resulted by typos in the “myKey” String above, as you always only have to write out every key name once.

How to use PDC

Let’s imagine you have a Player object, and you want to store a simple String inside, like their real life surname. First, we have to get their PDC:

PersistentDataContainer pdc = player.getPersistentDataContainer();

To store data inside, we have to tell the API what kind of PersistentDataType it is. The SpigotAPI already provides PersistentDataType implementations for most primitives (byte, short, integer, float, double, long), some primitive arrays (byte array, integer array, long array), Strings, nested PersistentDataContainers, and arrays of nested PersistentDataContainers.

Obviously, we’re going to use the String datatype:

String surname = "Alex";
PersistentDataContainer pdc = player.getPersistentDataContainer();
NamespacedKey surnameKey = new NamespacedKey(myPlugin, "surname");
pdc.set(surnameKey, PersistentDataType.STRING, surname);

We can now easily retrieve the value again:

String surname = pdc.get(surnameKey, PersistentDataType.STRING);

But how can I use it on ItemStacks?

ItemStack’s do NOT have a PersistentDataContainer – but ItemMeta does. So, simply get the ItemStack’s ItemMeta, store it, do your stuff, and then set the ItemMeta back to the ItemStack. Like this:

ItemMeta meta = myItemStack.getItemMeta();
meta.getPersistentDataContainer().set(someNamespacedKey, PersistentDataType.INTEGER, 1337);
myItemStack.setItemMeta(meta);

How is this better than NBT tags in any way?

It’s better than NBT tags in every single way, except for the one.

  • The PDC is part of the Spigot API.
    • That avoids the usage of dirty NMS code
    • It also means your plugin doesn’t break when NMS code changes on every update
    • It also avoids the usage of any NBTAPI plugins that might be already abandoned on the next NMS release
  • Two plugins don’t have conflicts when both use an identical called key name
    • But you can still explicitly access other plugin’s PDC key/values
  • It allows you to easily create your own DataTypes, see below
  • PersistentDataContainer values are actually persistent, unlike for example custom NBT tags on TileEntities

The only disadvantage I that indeed exists, is that it does NOT allow you to access vanilla NBT tags. HOWEVER, in modern Minecraft versions, there basically is no need to do so because everything that can be done with NBT tags can be done through the API (when I’m not mistaken).

Custom DataTypes

Imagine you want to save an ItemStack inside a Player object instead of just a String. No problem, you can easily create your own PersistentDataType. I have already made a tiny library for that, you can find it here on SpigotMC and here on GitHub.

But how can I save data inside Blocks?

If your block’s BlockState is an instance of TileEntity, you can simply use the TileEntitiy’s PersistentDataContainer. For all other blocks, I made a tiny library for this purpose, too. You can find it here on SpigotMC and here on GitHub.

Join my Discord Server for feedback or support. Just check out the channel #programming-help 🙂

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Recent Posts

  • Why IntelliJ complains about your pom.xml file
  • How to make maven automatically put your plugin’s .jar into your test server’s plugins folder
  • Use Consumers when spawning custom entities
  • Java’s init blocks
  • Bukkit vs. Spigot-API vs. CraftBukkit vs. Spigot

Recent Comments

  1. mfnalex on NMS: Use Mojang mappings for your Spigot plugins with Maven
  2. fisher on NMS: Use Mojang mappings for your Spigot plugins with Maven
  3. stromectol no prescription on Obfuscate plugins using allatori
  4. pharmacy uk on Obfuscate plugins using allatori
  5. mfnalex on Obfuscate plugins using allatori

Archives

  • February 2023
  • January 2023
  • October 2022
  • August 2022
  • March 2022
  • December 2021
  • October 2021
  • August 2021
©2023 JEFF Media Developer Blog
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
Cookie SettingsAccept All
Manage consent

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
CookieDurationDescription
cookielawinfo-checkbox-analytics11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional11 monthsThe cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytics
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
Others
Other uncategorized cookies are those that are being analyzed and have not been classified into a category as yet.
SAVE & ACCEPT