Add Persistent Data Container Support #8327
Draft
+433
−36
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
PDCs have long been the supported and intended way for Bukkit plugins to store custom data on items, entities, and more. Skript has never had support for this (barring one ill-fated attempt) and users have turned to SkBee (via NBTAPI) to access custom data storage instead. This is less than ideal as the NBT access, while incredibly useful and versatile, is not the intended way of doing this and can lead to slower performance or weird jank at times.
In addition, Paper is deprecating the metadata api and directs users to PDC instead, so Skript very much needs an API for PDC to support this migration.
Solution
The current form of this PR allows access to a single level of PDC tags (ie, it does not currently support nesting tags like how SkBee supports nested nbt tags:
compound tag "tag" of {nbt}orstring tag "parent;child" of {nbt}. This could be added, but I would like to limit that to a later PR as it would require a lot more surrounding support, like a compound pdc type, conditions and expressions to act on the compounds, and details about whether these would be copies or directly editable references.The syntax is currently
Users do not have to supply a specific data type to access, Skript will iterate over the possible types until it finds one that fits. If they do supply a type, Skript will only attempt that type and will return nothing if the type does not match. Setting the tags works similarly. Skript will determine the type itself, unless told otherwise.
When setting "representable" types (int, long, double, string, float...) which are directly representable in PDC, Skript will use the PDC tag type, resulting in something like
{"namespace:key": 5L}. This means you should be able to access 3rd-party PDC data without issue.When dealing with more complex types, Skript will leverage its existing serialization methods that are used for variable saving. Any type that can be saved in a variable should be savable in PDC. This isn't fully functional yet and there are issues I have to iron out and safety rails to put in. However, for what does work, the process is as follows:
Skript will serialize the object into Fields, using the normal serializer registered for the type. As an example, offline players consist of a single Field,
uuid, which contains a UUID object. UUID objects are serialized into 2 Fields,leastSignificantBitsandmostSignificantBits, both being Longs.The PDC serializer will take this Fields object and recursively map it to PDC types. For offline players, this means the player object becomes a TAG_CONTAINER that contains 2 tags.
"skript:type", which contains the type's codename as a String, and"skript:uuid", which contains the "uuid" Field of this type. The 'type' tag allows Skript to know what type to deserialize this as.Since the only field in the Fields is a UUID, the value will be another TAG_CONTAINER, with a 'type' of "uuid" and a two 'value' fields for the UUID. That contains 2 Long tags, one for the LSB and one for the MSB.
This method of serialization is much less space efficient than just serializing the data to a base 64 string, for example, but provides the user a much better understanding of what exactly is stored and allows them to actually debug issues with stored data.
Testing Completed
In progress.
Supporting Information
Many more safety rails need to be added (like detecting if serialization is really possible before trying, and actually getting all the types working)
Completes: #8188
Related: none
AI assistance: Some lines were auto-completed by Github Copilot.