Skip to content

Inventory Paths

Conorsmine edited this page Aug 8, 2023 · 2 revisions

PDM tries to have any and all inventories accessible if need be. To achieve this, PDM implements a system of Inventory paths. These are paths determined by the NBT structure of the player. Creating paths might be overwhelming at first, that's why PDM provide 3 common Inventory paths:

  • inv - The main inventory of the player
  • ec - The ender chest of the player
  • baubles - The baubles inventory used in many modpacks

Separator String

In a later chapter you will need to know what the "separator" is. Fancy name, but it just means a few characters you put in the Inventory Path so PDM knows how to traverse the players NBT.
The "separator" can be found in the "config.yml" file in the PDM plugin folder. Make sure it is a squeeze of characters which is NOT in any of the "keys" of the NBT!
PDM uses "##" as a default.

NBT Structure

Here is a short explanation of how PDM treats NBT.

There are 3 NBT types, in the case of PDM:

  • primitives: Simple key-value pairs; E.g. "HurtByTimestamp": 302511
  • compounds: These "encapsulate" other NBT types; E.g. "bukkit": { "newLevel": 0, "newExp": 0 }
  • lists: These are a collection of other NBT types; E.g. "Attributes": [ {"Base": 200.0, "Name": "generic.maxHealth"}, "primitive": 404 ]

NBT Example

Here is now an example of some NBT:
{"HurtTime": 0s, "SelectedItemSlot": 2, "SpawnWorld": "world", "WorldUUIDLeast": -5483029771699406563L, "Inventory": [ {"Slot": 4b, "id": "minecraft:diamond", "Count": 100b, "Damage": 0s} ]}

This might seem overwhelming, but let us go through it bit by bit.
Firstly, we want to get the "top-level keys" from this NBT. All this means is to get the "keys" that are not inside other NBT types:

  • "HurtTime"
  • "SelectedItemSlot"
  • "SpawnWorld"
  • "WorldUUIDLeast"
  • "Inventory"

Everything else is in some NBT type.
So we can imagine the NBT having roughly this shape:

┏━━ HurtTime             (Primitive)
┣━━ SelectedItemSlot     (Primitive)
┣━━ SpawnWorld           (Primitive)
┣━━ WorldUUIDLeast       (Primitive)
┗━━ Inventory            (List)

Next, we do the same with every non-primitive NBT type. In the above-shown example, this would be "Inventory".
Lists are a bit special and should be viewed as a Compound with a "key" equal to its index; Then the NBT would look like this:
"Inventory": [ {"Slot": 4b, "id": "minecraft:diamond", "Count": 100b, "Damage": 0s} ]
=> "Inventory": { "0": {"Slot": 4b, "id": "minecraft:diamond", "Count": 100b, "Damage": 0s} }
So following the first step again, it should look something like this:

┏━━ HurtTime             (Primitive)
┣━━ SelectedItemSlot     (Primitive)
┣━━ SpawnWorld           (Primitive)
┣━━ WorldUUIDLeast       (Primitive)
┗━━ Inventory            (List)
    ┗━━ [0]              (Compound)

It might be hard to see why "[0]" is a Compound, but looking back at the original NBT you can see, that the "Inventories" List contains the following NBT:
{"Slot": 4b, "id": "minecraft:diamond", "Count": 100b, "Damage": 0s}, which is a Compound.

Now we follow the first step again and get the following:

┏━━ HurtTime             (Primitive)
┣━━ SelectedItemSlot     (Primitive)
┣━━ SpawnWorld           (Primitive)
┣━━ WorldUUIDLeast       (Primitive)
┗━━ Inventory            (List)
    ┗━━ [0]              (Compound)
         ┣━━ Slot        (Primitive)
         ┣━━ id          (Primitive)
         ┣━━ Count       (Primitive)
         ┗━━ Damage      (Primitive)

That is it, we have now turned the NBT into a tree-like graph.

PDM Inventory Path Syntax

Now that we have entangled the NBT into something more readable we can start finding the data you want!

PDM Inventory Paths should always "point" towards where the item NBT Compound is! Not the item "id"!
However, there is no need to specify every index of an inventory; E.g. the NBT we converted into a tree-like graph, it would be very annoying, sometimes even impossible, to create a path to every item NBT Compound.
That is why you can "point" towards where all the items NBT Compounds are stored.

Long story short, create Inventory Paths to the "container" with all the item NBT Compounds in it, instead of every item NBT Compound individually.

Inventory Path Syntax

The syntax for the Inventory Paths is very simple:
As a general rule of thumb just remember, to add other separator between everything.
The only exception to this is Lists!
If you want to denote a specific index of a List, you use square brackets with the index in them: "[0]".
E.g.: "Inventory[0]"
Otherwise, you just write the "key" of the NBT Compound;
E.g.: "bukkit##newLevel"

Inventory Path Example

Let us take this NBT again.
We want PDM to recognise all items in the "Inventory" List; For this, we have to "point" or rather create an Inventory Path that'll tell PDM to look there. In the graph we made, we can see that the "Inventory" NBT is a "top-level compound".
So it has the following Inventory Path: "Inventory"

I know, very underwhelming for all the work and text you just read through...
But now, just for the sake of argument, the "Slot" NBT has an item NBT Comound which you want to "point" to. No problem, hopefully!
So, first, we write down: "Slot", as that is where the item NBT Compound is. Now we work backwards...
The "Slot" NBT is in the "[0]" NBT Compound, so we prefix our current Inventory Path with that, adding the separator in between!
=> "[0]##Slot"
Now we repeat this until there is no NBT Compound left, which in this case is only "Inventory":
=> "Inventory[0]##Slot"

Do note that there is no separator between Lists and their index values as explained in the syntax section!

Clone this wiki locally