Skip to content

Commit

Permalink
Update examples
Browse files Browse the repository at this point in the history
  • Loading branch information
SoSeDiK committed Jun 15, 2024
1 parent f8b8e6a commit 6f287c2
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 29 deletions.
108 changes: 85 additions & 23 deletions wiki/Example-Usages.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,122 @@
## Set a skull's skin

// TODO broken link

#### We will be using [this head](https://minecraft-heads.com/custom-heads/food%20&%20drinks/28194-cup-of-soda) as example.
#### 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 and below
// 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 -> {
final ReadWriteNBT skullOwnerCompound = nbt.getOrCreateCompound("SkullOwner");
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());

// 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);
});

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
// TODO 1.20.5+ example
// TODO A note/example about alternative in Paper API?
```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 = (Zombie) world.spawnEntity(location, EntityType.ZOMBIE);
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.setByte("CanPickUpLoot", (byte) 1);
nbt.setBoolean("CanPickUpLoot", true);

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);
}

// 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);
});

// TODO is this valid in newer versions?
// 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
// TODO
// 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);
```

12 changes: 6 additions & 6 deletions wiki/Using-the-NBT-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ nbt.getOrCreateCompound("subtag"); // Get or create a subtag

```java
// Parse Mojang-Json string to nbt
ReadWriteNBT nbt = NBT.parseNBT("{Silent:1b,Invulnerable:1b,Glowing:1b,IsBaby:1b}");
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
Expand Down Expand Up @@ -202,6 +202,11 @@ NBT.modify(entity, nbt -> {

For reading/storing custom data on tiles/entities, you should use methods that end with PersistentData.

> [!IMPORTANT]
> When working with tile 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"));
Expand All @@ -212,11 +217,6 @@ NBT.modifyPersistentData(entity, nbt -> {
});
```

> [!IMPORTANT]
> When working with tile 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.
>
> [!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.
>
Expand Down

0 comments on commit 6f287c2

Please sign in to comment.