Compare commits

...
46 Commits
Author SHA1 Message Date
tr7zw 442a6e935b 2.7.0 Release 2020-12-29 23:36:41 +01:00
tr7zw 2213ab879d Update pom.xml 2020-12-29 23:26:00 +01:00
tr7zw 00c2ce951b Reimplement equals method to hopefully be better than before, add getListType method 2020-12-29 23:12:21 +01:00
tr7zw 60d8101b9f Add NBTBlock for 1.16.4 2020-12-29 20:06:59 +01:00
tr7zw ef56b44629 Add NBTChunk and NBTPersistentDataContainer 2020-12-29 18:56:44 +01:00
tr7zw 5859276c11 Add getOrCreateCompound and clearify the javadoc of addCompound 2020-12-29 17:24:09 +01:00
tr7zw f588e6fec9 Start using maven vars for the version. Start NBT-Crafting 2020-12-29 17:06:13 +01:00
tr7zw 413b0f38f4 Update pom.xml 2020-12-29 16:53:04 +01:00
tr7zw a40eb5b4b4 Start work on 2.7.0-SNAPSHOT 2020-12-29 16:51:30 +01:00
tr7zw a4deb2a1ee Release 2.6.1 to fix the spigotmc/curseforge situation 2020-12-20 18:40:07 +01:00
tr7zw feaf59998f Putting the src versions of the spigot/curseforge page text into the repo 2020-12-08 21:40:13 +01:00
tr7zw cc1a88cdc8 Update README.md 2020-12-08 21:17:33 +01:00
tr7zw b58215d4bf Merge pull request #108 from LoneDev6/patch-2
Update .all-contributorsrc
2020-12-08 21:15:53 +01:00
tr7zw 689c354443 Bump to 2.6.1-SNAPSHOT 2020-12-08 21:15:23 +01:00
LoneDev ff3a7c3add Update .all-contributorsrc
Added "Code" icon to user LoneDev6
2020-11-30 12:53:42 +01:00
tr7zw 7d76d3c342 2.6.0 Release 2020-11-03 18:15:20 +01:00
tr7zw 2107d6f53d Fix >= != >, update readme 2020-11-03 18:02:52 +01:00
tr7zw f3e912723b Add 1.16.4 Fixes #106 , Fix issue with the version fallback for unknown future versions 2020-11-03 17:47:53 +01:00
tr7zw 47f29234e3 Fix loggers, allow replacement of the nbt-api logger for shaded plugins. Fixes #99 somewhat 2020-10-28 18:31:30 +01:00
tr7zw bd1ebac035 Bump to 2.6.0-SNAPSHOT 2020-10-28 18:12:20 +01:00
tr7zw ea9ccdc077 Add Stargazers graph 2020-10-12 10:53:18 +02:00
tr7zw f2d13e9b4e Bump Year 2020-09-28 21:11:31 +00:00
tr7zw 17c689699d Change to 2.5.0 Release 2020-08-14 10:04:52 +02:00
tr7zw c8110b0637 Merge pull request #100 from LoneDev6/master
Update MinecraftVersion.java to 1.16.2
2020-08-14 10:04:16 +02:00
tr7zw 2daec88667 Merge branch 'master' into master 2020-08-14 09:48:33 +02:00
tr7zw 01aec6c272 Bump versions to 2.5.0-SNAPSHOT, add 1.16.2 to unit test 2020-08-14 09:44:45 +02:00
LoneDev6 b74ba362c8 Update MinecraftVersion.java 2020-08-12 13:52:12 +02:00
tr7zw 65a86027ba Update ReflectionMethod.java 2020-08-03 18:15:34 +02:00
tr7zw 580c07fc3f Apply isntead of merge so removeing tags works 2020-07-11 19:43:05 +02:00
tr7zw c38ca2cb35 Add direct apply mode
Fixes #49
2020-07-11 18:44:22 +02:00
tr7zw 1ebd2a8ed1 Add Config file
Fixes #79
2020-07-11 18:13:51 +02:00
tr7zw 19300566c2 More 1.7.10 fixes, add 1.7.10 to unit test 2020-07-10 18:45:40 +02:00
tr7zw 6b6783e7c6 Block the NBTInjector from even trying to load in invalid versions, fixed 1.7.10 getType 2020-07-10 17:55:26 +02:00
tr7zw 7e5b5a1ff4 Fix loading in 1.7.10 2020-07-10 17:11:07 +02:00
tr7zw ff50036688 Merge branch 'master' of https://github.com/tr7zw/Item-NBT-API 2020-07-10 16:37:47 +02:00
tr7zw 7c0b63d0e3 Bump to 2.5.0-SNAPSHOT since the API will change compared to 2.4.1 2020-07-10 16:37:45 +02:00
tr7zw 8f4dad62bd Merge pull request #89 from tr7zw/dependabot/maven/com.github.ekryd.sortpom-sortpom-maven-plugin-2.12.0
Bump sortpom-maven-plugin from 2.11.0 to 2.12.0
2020-07-10 16:35:46 +02:00
tr7zw 6667682c6c Merge pull request #92 from brandonwamboldt/fix-91
Use the correct TILEENTITY_SET_NBT method on pre-1.1.6 versions
2020-07-10 16:35:25 +02:00
Brandon Wamboldt 0123652cc7 Use the correct TILEENTITY_SET_NBT method on pre-1.1.6 versions
Fixes #91
2020-07-10 09:41:36 -03:00
dependabot-preview[bot] 0d9c200e88 Bump sortpom-maven-plugin from 2.11.0 to 2.12.0
Bumps [sortpom-maven-plugin](https://github.com/Ekryd/sortpom) from 2.11.0 to 2.12.0.
- [Release notes](https://github.com/Ekryd/sortpom/releases)
- [Commits](https://github.com/Ekryd/sortpom/compare/sortpom-parent-2.11.0...sortpom-parent-2.12.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-03 05:29:48 +00:00
tr7zw ab3c52ada1 Merge pull request #88 from SoSeDiK/apply
Implement utility methods for merging NBT
2020-06-30 11:12:55 +02:00
tr7zw 443fb2d3c0 Fix potential issue with 1.7.10 2020-06-28 16:24:24 +02:00
SoSeDiK 0de8279b4b Implement utility methods for merging NBT 2020-06-27 06:48:04 +03:00
tr7zw 003e015d1d Merge pull request #87 from stijnb1234/master
ReflectionMethod cleanup
2020-06-25 17:01:12 +02:00
tr7zw b5dc20683f Bump to 2.4.2-SNAPSHOT for future development 2020-06-25 17:00:47 +02:00
Stijn Bannink bda2845a79 ReflectionMethod cleanup 2020-06-25 16:58:18 +02:00
41 changed files with 1111 additions and 164 deletions

No files matched your search

+1
View File
@@ -139,6 +139,7 @@
"avatar_url": "https://www.spigotmc.org/data/avatars/l/88/88296.jpg?1563463602",
"profile": "https://www.spigotmc.org/members/lonedev.88296",
"contributions": [
"code",
"ideas",
"financial"
],
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 tr7zw
Copyright (c) 2020 tr7zw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+9 -4
View File
@@ -5,16 +5,21 @@ Add custom NBT tags to Items/Tiles/Entities without NMS! Modify NBT and store it
### Build/Maven/Sonar Status
[![Build Status](https://ci.codemc.org/buildStatus/icon?job=Tr7zw%2FItem-NBT-API)](https://ci.codemc.org/job/Tr7zw/job/Item-NBT-API/)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=ncloc)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)
[![Discord](https://img.shields.io/discord/342814924310970398?color=%237289DA&label=Discord&logo=discord&logoColor=white)](https://discordapp.com/invite/yk4caxM)
[![Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2Ftr7zw%2Fpledges&style=for-the-badge)](https://www.patreon.com/tr7zw)
[![Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dtr7zw%26type%3Dpatrons&style=for-the-badge)](https://www.patreon.com/tr7zw)
### SpigotMC Status
[![Version](https://badges.spiget.org/resources/version/Version-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![Rating](https://badges.spiget.org/resources/rating/Rating-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![Rating](https://badges.spiget.org/resources/downloads/SpigotDownloads-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![bStats Servers](https://img.shields.io/bstats/servers/1058.svg?color=green&label=OnlineServers&style=plastic)](https://bstats.org/plugin/bukkit/ItemNBTAPI)[![bStats Players](https://img.shields.io/bstats/players/1058.svg?color=green&label=OnlinePlayers&style=plastic)](https://bstats.org/plugin/bukkit/ItemNBTAPI)[![All Contributors](https://img.shields.io/badge/all_contributors-13-green.svg?style=plastic)](#contributors-%e2%9c%a8)
[![bStats Stats](https://bstats.org/signatures/bukkit/ItemNBTAPI.svg)](https://bstats.org/plugin/bukkit/ItemNBTAPI)
## 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).
### bStats
[![bStats Stats](https://bstats.org/signatures/bukkit/ItemNBTAPI.svg)](https://bstats.org/plugin/bukkit/ItemNBTAPI)
### Github Stargazers
<img src="https://starchart.cc/tr7zw/Item-NBT-API.svg" alt="stargazers" width="800"/>
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -36,7 +41,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/MrDienns"><img src="https://avatars3.githubusercontent.com/u/15938901?s=460&v=4" width="100px;" alt=""/><br /><sub><b>Dennis van der Veeke</b></sub></a><br /><a href="https://tr7zw.dev/donate/" title="Financial Support">💵</a></td>
<td align="center"><a href="https://github.com/iGabyTM"><img src="https://avatars2.githubusercontent.com/u/32105478?s=460&v=4" width="100px;" alt=""/><br /><sub><b>Gabriel Dumitru</b></sub></a><br /><a href="#discord-iGabyTM" title="Discord help">🤝</a></td>
<td align="center"><a href="https://github.com/TauCubed"><img src="https://avatars0.githubusercontent.com/u/35522873?s=460&v=4" width="100px;" alt=""/><br /><sub><b>TauCubed</b></sub></a><br /><a href="#discord-TauCubed" title="Discord help">🤝</a></td>
<td align="center"><a href="https://www.spigotmc.org/members/lonedev.88296"><img src="https://www.spigotmc.org/data/avatars/l/88/88296.jpg?1563463602" width="100px;" alt=""/><br /><sub><b>LoneDev</b></sub></a><br /><a href="https://www.spigotmc.org/threads/nbt-api.70503/page-7#post-3652832" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://tr7zw.dev/donate/" title="Financial Support">💵</a></td>
<td align="center"><a href="https://www.spigotmc.org/members/lonedev.88296"><img src="https://www.spigotmc.org/data/avatars/l/88/88296.jpg?1563463602" width="100px;" alt=""/><br /><sub><b>LoneDev</b></sub></a><br /><a href="https://github.com/tr7zw/Item-NBT-API/commits?author=LoneDev" title="Code">💻</a> <a href="https://www.spigotmc.org/threads/nbt-api.70503/page-7#post-3652832" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://tr7zw.dev/donate/" title="Financial Support">💵</a></td>
<td align="center"><a href="https://www.spigotmc.org/members/gc.25090"><img src="https://www.spigotmc.org/data/avatars/l/25/25090.jpg?1502396477" width="100px;" alt=""/><br /><sub><b>GC.</b></sub></a><br /><a href="https://tr7zw.dev/donate/" title="Financial Support">💵</a></td>
<td align="center"><a href="https://www.spigotmc.org/members/peaches_mlg100.194338/"><img src="https://www.spigotmc.org/data/avatars/l/194/194338.jpg?1561235996" width="100px;" alt=""/><br /><sub><b>Peaches_MLG</b></sub></a><br /><a href="https://tr7zw.dev/donate/" title="Financial Support">💵</a></td>
</tr>
+17
View File
@@ -0,0 +1,17 @@
# (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.
[Server Owner/Developer Wiki](https://github.com/tr7zw/Item-NBT-API/wiki)
### Build/Maven/Sonar Status
[![Build Status](https://github.com/tr7zw/Item-NBT-API/workflows/Java%20CI/badge.svg)](https://ci.codemc.org/job/Tr7zw/job/Item-NBT-API/)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=ncloc)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)[![](https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent)
Discord:[![Discord](https://img.shields.io/discord/342814924310970398?color=%237289DA&label=Discord&logo=discord&logoColor=white)](https://discordapp.com/invite/yk4caxM)
[![Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dtr7zw%26type%3Dpatrons&style=for-the-badge)](https://www.patreon.com/tr7zw)
### SpigotMC Status
[![Version](https://badges.spiget.org/resources/version/Version-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![Rating](https://badges.spiget.org/resources/rating/Rating-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![Rating](https://badges.spiget.org/resources/downloads/SpigotDownloads-yellow-7939.svg)](https://www.spigotmc.org/resources/item-entity-tile-nbt-api.7939/)[![bStats Servers](https://img.shields.io/bstats/servers/1058.svg?color=green&label=OnlineServers&style=plastic)](https://bstats.org/plugin/bukkit/ItemNBTAPI)[![bStats Players](https://img.shields.io/bstats/players/1058.svg?color=green&label=OnlinePlayers&style=plastic)](https://bstats.org/plugin/bukkit/ItemNBTAPI)
## 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).
### bStats
[![bStats Stats](https://bstats.org/signatures/bukkit/ItemNBTAPI.svg)](https://bstats.org/plugin/bukkit/ItemNBTAPI)
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
</parent>
<artifactId>item-nbt-api</artifactId>
@@ -0,0 +1,26 @@
package de.tr7zw.changeme.nbtapi;
import org.bukkit.block.Block;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
public class NBTBlock {
private final Block block;
private final NBTChunk nbtChunk;
public NBTBlock(Block block) {
this.block = block;
if(!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R3)) {
throw new NbtApiException("NBTBlock is only working for 1.16.4+!");
}
nbtChunk = new NBTChunk(block.getChunk());
}
public NBTCompound getData() {
return nbtChunk.getPersistentDataContainer().getOrCreateCompound("blocks").getOrCreateCompound(block.getX() + "_" + block.getY() + "_" + block.getZ());
}
}
@@ -0,0 +1,30 @@
package de.tr7zw.changeme.nbtapi;
import org.bukkit.Chunk;
import de.tr7zw.annotations.FAUtil;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.annotations.AvaliableSince;
import de.tr7zw.changeme.nbtapi.utils.annotations.CheckUtil;
public class NBTChunk {
private final Chunk chunk;
public NBTChunk(Chunk chunk) {
this.chunk = chunk;
}
/**
* Gets the NBTCompound used by spigots PersistentDataAPI. This method is only
* available for 1.16.4+!
*
* @return NBTCompound containing the data of the PersistentDataAPI
*/
@AvaliableSince(version = MinecraftVersion.MC1_16_R3)
public NBTCompound getPersistentDataContainer() {
FAUtil.check(this::getPersistentDataContainer, CheckUtil::isAvaliable);
return new NBTPersistentDataContainer(chunk.getPersistentDataContainer());
}
}
@@ -2,6 +2,8 @@ package de.tr7zw.changeme.nbtapi;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
@@ -544,7 +546,7 @@ public class NBTCompound {
}
/**
* Creates a subCompound
* Creates a subCompound, or returns it if already provided
*
* @param name Key to use
* @return The subCompound Object
@@ -582,6 +584,16 @@ public class NBTCompound {
readLock.unlock();
}
}
/**
* The same as addCompound, just with a name that better reflects what it does
*
* @param name
* @return
*/
public NBTCompound getOrCreateCompound(String name) {
return addCompound(name);
}
/**
* @param name
@@ -657,6 +669,23 @@ public class NBTCompound {
writeLock.unlock();
}
}
/**
* Returns the type of the list, null if not a list
*
* @param name
* @return
*/
public NBTType getListType(String name) {
try {
readLock.lock();
if (getType(name) != NBTType.NBTTagList)
return null;
return NBTReflectionUtil.getListType(this, name);
} finally {
readLock.unlock();
}
}
/**
* @param name
@@ -681,8 +710,12 @@ public class NBTCompound {
public NBTType getType(String name) {
try {
readLock.lock();
if (MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4)
return null;
if (MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4) {
Object nbtbase = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET, name);
if(nbtbase == null)
return null;
return NBTType.valueOf((byte)ReflectionMethod.COMPOUND_OWN_TYPE.run(nbtbase));
}
Object o = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET_TYPE, name);
if (o == null)
return null;
@@ -750,8 +783,7 @@ public class NBTCompound {
}
/**
* Uses the nbt-string to match this compound with another object. This allows
* two "technically" different Compounds to match, if they have the same content
* Does a deep compare to check if everything is the same
*/
@Override
public boolean equals(Object obj) {
@@ -759,7 +791,49 @@ public class NBTCompound {
return true;
if (obj == null)
return false;
return toString().equals(obj.toString());
if(obj instanceof NBTCompound) {
NBTCompound other = (NBTCompound) obj;
if(getKeys().equals(other.getKeys())) {
for(String key : getKeys()) {
if(!isEqual(this, other, key)) {
return false;
}
return true;
}
}
}
return false;
}
protected static boolean isEqual(NBTCompound compA, NBTCompound compB, String key) {
if(compA.getType(key) != compB.getType(key))return false;
switch(compA.getType(key)) {
case NBTTagByte:
return compA.getByte(key).equals(compB.getByte(key));
case NBTTagByteArray:
return Arrays.equals(compA.getByteArray(key), compB.getByteArray(key));
case NBTTagCompound:
return compA.getCompound(key).equals(compB.getCompound(key));
case NBTTagDouble:
return compA.getDouble(key).equals(compB.getDouble(key));
case NBTTagEnd:
return true; //??
case NBTTagFloat:
return compA.getFloat(key).equals(compB.getFloat(key));
case NBTTagInt:
return compA.getInteger(key).equals(compB.getInteger(key));
case NBTTagIntArray:
return Arrays.equals(compA.getIntArray(key), compB.getIntArray(key));
case NBTTagList:
return NBTReflectionUtil.getEntry(compA, key).toString().equals(NBTReflectionUtil.getEntry(compB, key).toString()); // Just string compare the 2 lists
case NBTTagLong:
return compA.getLong(key).equals(compB.getLong(key));
case NBTTagShort:
return compA.getShort(key).equals(compB.getShort(key));
case NBTTagString:
return compA.getString(key).equals(compB.getString(key));
}
return false;
}
}
@@ -49,15 +49,7 @@ public class NBTEntity extends NBTCompound {
@AvaliableSince(version = MinecraftVersion.MC1_14_R1)
public NBTCompound getPersistentDataContainer() {
FAUtil.check(this::getPersistentDataContainer, CheckUtil::isAvaliable);
if (hasKey("BukkitValues")) {
return getCompound("BukkitValues");
} else {
NBTContainer container = new NBTContainer();
container.addCompound("BukkitValues").setString("__nbtapi",
"Marker to make the PersistentDataContainer have content");
mergeCompound(container);
return getCompound("BukkitValues");
}
return new NBTPersistentDataContainer(ent.getPersistentDataContainer());
}
}
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -15,6 +16,8 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
public class NBTItem extends NBTCompound {
private ItemStack bukkitItem;
private boolean directApply;
private ItemStack originalSrcStack = null;
/**
* Constructor for NBTItems. The ItemStack will be cloned!
@@ -22,11 +25,27 @@ public class NBTItem extends NBTCompound {
* @param item
*/
public NBTItem(ItemStack item) {
this(item, false);
}
/**
* Constructor for NBTItems. The ItemStack will be cloned! If directApply is true,
* all changed will be mapped to the original item. Changes to the NBTItem will overwrite changes done
* to the original item in that case.
*
* @param item
* @param directApply
*/
public NBTItem(ItemStack item, boolean directApply) {
super(null, null);
if (item == null || item.getType() == Material.AIR) {
throw new NullPointerException("ItemStack can't be null/Air!");
}
this.directApply = directApply;
bukkitItem = item.clone();
if(directApply) {
this.originalSrcStack = item;
}
}
@Override
@@ -41,6 +60,58 @@ public class NBTItem extends NBTCompound {
bukkitItem = (ItemStack) ReflectionMethod.ITEMSTACK_BUKKITMIRROR.run(null, stack);
}
/**
* Apply stored NBT tags to the provided ItemStack.
* <p>
* Note: This will completely override current item's {@link ItemMeta}.
* If you still want to keep the original item's NBT tags, see
* {@link #mergeNBT(ItemStack)} and {@link #mergeCustomNBT(ItemStack)}.
*
* @param item ItemStack that should get the new NBT data
*/
public void applyNBT(ItemStack item) {
if (item == null || item.getType() == Material.AIR) {
throw new NullPointerException("ItemStack can't be null/Air!");
}
NBTItem nbti = new NBTItem(new ItemStack(item.getType()));
nbti.mergeCompound(this);
item.setItemMeta(nbti.getItem().getItemMeta());
}
/**
* Merge all NBT tags to the provided ItemStack.
*
* @param item ItemStack that should get the new NBT data
*/
public void mergeNBT(ItemStack item) {
NBTItem nbti = new NBTItem(item);
nbti.mergeCompound(this);
item.setItemMeta(nbti.getItem().getItemMeta());
}
/**
* Merge only custom (non-vanilla) NBT tags to the provided ItemStack.
*
* @param item ItemStack that should get the new NBT data
*/
public void mergeCustomNBT(ItemStack item) {
if (item == null || item.getType() == Material.AIR) {
throw new NullPointerException("ItemStack can't be null/Air!");
}
ItemMeta meta = item.getItemMeta();
NBTReflectionUtil.getUnhandledNBTTags(meta).putAll(NBTReflectionUtil.getUnhandledNBTTags(bukkitItem.getItemMeta()));
item.setItemMeta(meta);
}
/**
* Remove all custom (non-vanilla) NBT tags from the NBTItem.
*/
public void clearCustomNBT() {
ItemMeta meta = bukkitItem.getItemMeta();
NBTReflectionUtil.getUnhandledNBTTags(meta).clear();
bukkitItem.setItemMeta(meta);
}
/**
* @return The modified ItemStack
*/
@@ -84,4 +155,11 @@ public class NBTItem extends NBTCompound {
NBTReflectionUtil.convertNBTCompoundtoNMSItem(comp));
}
@Override
protected void saveCompound() {
if(directApply) {
applyNBT(originalSrcStack);
}
}
}
@@ -0,0 +1,31 @@
package de.tr7zw.changeme.nbtapi;
import java.util.Map;
import org.bukkit.persistence.PersistentDataContainer;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
public class NBTPersistentDataContainer extends NBTCompound {
private final PersistentDataContainer container;
protected NBTPersistentDataContainer(PersistentDataContainer container) {
super(null, null);
this.container = container;
}
@Override
public Object getCompound() {
return ReflectionMethod.CRAFT_PERSISTENT_DATA_CONTAINER_TO_TAG.run(container);
}
@Override
protected void setCompound(Object compound) {
@SuppressWarnings("unchecked")
Map<Object, Object> map = (Map<Object, Object>) ReflectionMethod.CRAFT_PERSISTENT_DATA_CONTAINER_GET_MAP.run(container);
map.clear();
ReflectionMethod.CRAFT_PERSISTENT_DATA_CONTAINER_PUT_ALL.run(container, compound);
}
}
@@ -3,12 +3,15 @@ package de.tr7zw.changeme.nbtapi;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
import java.util.Set;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.meta.ItemMeta;
import de.tr7zw.changeme.nbtapi.utils.GsonWrapper;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
@@ -25,6 +28,17 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
*/
public class NBTReflectionUtil {
private static Field field_unhandledTags = null;
static {
try {
field_unhandledTags = ClassWrapper.CRAFT_METAITEM.getClazz().getDeclaredField("unhandledTags");
field_unhandledTags.setAccessible(true);
} catch (NoSuchFieldException e) {
}
}
/**
* Hidden constructor
*/
@@ -146,6 +160,21 @@ public class NBTReflectionUtil {
}
}
/**
* Gets a live copy of non-vanilla NBT tags.
*
* @param meta ItemMeta from which tags should be retrieved
* @return Map containing unhandled (custom) NBT tags
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> getUnhandledNBTTags(ItemMeta meta) {
try {
return (Map<String, Object>) field_unhandledTags.get(meta);
} catch (Exception e) {
throw new NbtApiException("Exception while getting unhandled tags from ItemMeta!", e);
}
}
/**
* Gets the Vanilla NBT Compound from a given NMS Entity
*
@@ -188,10 +217,15 @@ public class NBTReflectionUtil {
*/
public static Object getTileEntityNBTTagCompound(BlockState tile) {
try {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
Object cworld = ClassWrapper.CRAFT_WORLD.getClazz().cast(tile.getWorld());
Object nmsworld = ReflectionMethod.CRAFT_WORLD_GET_HANDLE.run(cworld);
Object o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
Object o = null;
if(MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4) {
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY_1_7_10.run(nmsworld, tile.getX(), tile.getY(), tile.getZ());
}else {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
}
Object tag = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
Object answer = ReflectionMethod.TILEENTITY_GET_NBT.run(o, tag);
if (answer == null)
@@ -210,10 +244,15 @@ public class NBTReflectionUtil {
*/
public static void setTileEntityNBTTagCompound(BlockState tile, Object comp) {
try {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
Object cworld = ClassWrapper.CRAFT_WORLD.getClazz().cast(tile.getWorld());
Object nmsworld = ReflectionMethod.CRAFT_WORLD_GET_HANDLE.run(cworld);
Object o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
Object o = null;
if(MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4) {
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY_1_7_10.run(nmsworld, tile.getX(), tile.getY(), tile.getZ());
}else {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
}
if(MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_16_R1.getVersionId()) {
Object blockData = ReflectionMethod.TILEENTITY_GET_BLOCKDATA.run(o);
ReflectionMethod.TILEENTITY_SET_NBT.run(o, blockData, comp);
@@ -259,8 +298,9 @@ public class NBTReflectionUtil {
if (nbttag == null) {
nbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp))
if (!valideCompound(comp)) {
return;
}
Object workingtag = gettoCompount(nbttag, comp);
try {
ReflectionMethod.COMPOUND_SET.run(workingtag, name,
@@ -419,6 +459,40 @@ public class NBTReflectionUtil {
throw new NbtApiException("Exception while getting a list with the type '" + type + "'!", ex);
}
}
public static NBTType getListType(NBTCompound comp, String key) {
Object rootnbttag = comp.getCompound();
if (rootnbttag == null) {
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp))
return null;
Object workingtag = gettoCompount(rootnbttag, comp);
try {
Object nbt = ReflectionMethod.COMPOUND_GET.run(workingtag, key);
Field f = nbt.getClass().getDeclaredField("type");
f.setAccessible(true);
return NBTType.valueOf(f.getByte(nbt));
} catch (Exception ex) {
throw new NbtApiException("Exception while getting the list type!", ex);
}
}
public static Object getEntry(NBTCompound comp, String key) {
Object rootnbttag = comp.getCompound();
if (rootnbttag == null) {
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp))
return null;
Object workingtag = gettoCompount(rootnbttag, comp);
try {
Object nbt = ReflectionMethod.COMPOUND_GET.run(workingtag, key);
return nbt;
} catch (Exception ex) {
throw new NbtApiException("Exception while getting an Entry!", ex);
}
}
/**
* Uses Gson to set a {@link Serializable} value in a Compound
@@ -25,7 +25,7 @@ public class NBTTileEntity extends NBTCompound {
*/
public NBTTileEntity(BlockState tile) {
super(null, null);
if (tile == null || !tile.isPlaced()) {
if (tile == null || (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3) && !tile.isPlaced())) {
throw new NullPointerException("Tile can't be null/not placed!");
}
this.tile = tile;
@@ -22,7 +22,8 @@ import java.util.TimerTask;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.getLogger;
/**
* bStats collects some data for plugin authors.
@@ -135,7 +136,7 @@ public class ApiMetricsLite {
if(Bukkit.isPrimaryThread()){
Bukkit.getServicesManager().register(ApiMetricsLite.class, this, plugin, ServicePriority.Normal);
if (!fFound) {
logger.info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
getLogger().info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
// We are the first!
startSubmitting();
}
@@ -143,7 +144,7 @@ public class ApiMetricsLite {
Bukkit.getScheduler().runTask(plugin, () -> {
Bukkit.getServicesManager().register(ApiMetricsLite.class, this, plugin, ServicePriority.Normal);
if (!fFound) {
logger.info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
getLogger().info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
// We are the first!
startSubmitting();
}
@@ -276,7 +277,7 @@ public class ApiMetricsLite {
} catch (ClassNotFoundException e) {
// minecraft version 1.14+
if (logFailedRequests) {
logger.log(Level.WARNING, "[NBTAPI][BSTATS] Encountered exception while posting request!", e);
getLogger().log(Level.WARNING, "[NBTAPI][BSTATS] Encountered exception while posting request!", e);
// Not using the plugins logger since the plugin isn't the plugin containing the NBT-Api most of the time
//this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e);
}
@@ -301,7 +302,7 @@ public class ApiMetricsLite {
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
logger.log(Level.WARNING, "[NBTAPI][BSTATS] Could not submit plugin stats of " + plugin.getName(), e);
getLogger().log(Level.WARNING, "[NBTAPI][BSTATS] Could not submit plugin stats of " + plugin.getName(), e);
// Not using the plugins logger since the plugin isn't the plugin containing the NBT-Api most of the time
//plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
}
@@ -360,7 +361,7 @@ public class ApiMetricsLite {
}
bufferedReader.close();
if (logResponseStatusText) {
logger.info("[NBTAPI][BSTATS] Sent data to bStats and received response: " + builder.toString());
getLogger().info("[NBTAPI][BSTATS] Sent data to bStats and received response: " + builder.toString());
// Not using the plugins logger since the plugin isn't the plugin containing the NBT-Api most of the time
//plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString());
}
@@ -17,7 +17,7 @@ import org.bukkit.Bukkit;
public enum MinecraftVersion {
UNKNOWN(Integer.MAX_VALUE), // Use the newest known mappings
MC1_7_R4(174), MC1_8_R3(183), MC1_9_R1(191), MC1_9_R2(192), MC1_10_R1(1101), MC1_11_R1(1111), MC1_12_R1(1121),
MC1_13_R1(1131), MC1_13_R2(1132), MC1_14_R1(1141), MC1_15_R1(1151), MC1_16_R1(1161);
MC1_13_R1(1131), MC1_13_R2(1132), MC1_14_R1(1141), MC1_15_R1(1151), MC1_16_R1(1161), MC1_16_R2(1162), MC1_16_R3(1163);
private static MinecraftVersion version;
private static Boolean hasGsonSupport;
@@ -27,10 +27,10 @@ public enum MinecraftVersion {
/**
* Logger used by the api
*/
public static final Logger logger = Logger.getLogger("NBTAPI");
private static Logger logger = Logger.getLogger("NBTAPI");
// NBT-API Version
protected static final String VERSION = "2.4.1";
protected static final String VERSION = "2.7.0";
private final int versionId;
@@ -44,6 +44,26 @@ public enum MinecraftVersion {
public int getVersionId() {
return versionId;
}
/**
* Returns true if the current versions is at least the given Version
*
* @param version The minimum version
* @return
*/
public static boolean isAtLeastVersion(MinecraftVersion version) {
return getVersion().getVersionId() >= version.getVersionId();
}
/**
* Returns true if the current versions newer (not equal) than the given version
*
* @param version The minimum version
* @return
*/
public static boolean isNewerThan(MinecraftVersion version) {
return getVersion().getVersionId() > version.getVersionId();
}
/**
* Getter for this servers MinecraftVersion. Also init's bStats and checks the
@@ -73,13 +93,13 @@ public enum MinecraftVersion {
private static void init() {
try {
if (!bStatsDisabled)
if (hasGsonSupport() && !bStatsDisabled)
new ApiMetricsLite();
} catch (Exception ex) {
logger.log(Level.WARNING, "[NBTAPI] Error enabling Metrics!", ex);
}
if (!updateCheckDisabled)
if (hasGsonSupport() && !updateCheckDisabled)
new Thread(() -> {
try {
VersionChecker.checkForUpdates();
@@ -149,5 +169,22 @@ public enum MinecraftVersion {
public static void disablePackageWarning() {
disablePackageWarning = true;
}
/**
* @return Logger used by the NBT-API
*/
public static Logger getLogger() {
return logger;
}
/**
* Replaces the NBT-API logger with a custom implementation.
*
* @param logger The new logger(can not be null!)
*/
public static void replaceLogger(Logger logger) {
if(logger == null)throw new NullPointerException("Logger can not be null!");
MinecraftVersion.logger = logger;
}
}
@@ -42,24 +42,24 @@ public class VersionChecker {
JsonObject latest = (JsonObject) updates.get(updates.size() - 1);
int versionDifference = getVersionDifference(latest.get("name").getAsString());
if (versionDifference == -1) { // Outdated
MinecraftVersion.logger.log(Level.WARNING,
MinecraftVersion.getLogger().log(Level.WARNING,
"[NBTAPI] The NBT-API at '" + NBTItem.class.getPackage() + "' seems to be outdated!");
MinecraftVersion.logger.log(Level.WARNING, "[NBTAPI] Current Version: '" + MinecraftVersion.VERSION
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Current Version: '" + MinecraftVersion.VERSION
+ "' Newest Version: " + latest.get("name").getAsString() + "'");
MinecraftVersion.logger.log(Level.WARNING,
MinecraftVersion.getLogger().log(Level.WARNING,
"[NBTAPI] Please update the nbt-api or the plugin that contains the api!");
} else if (versionDifference == 0) {
MinecraftVersion.logger.log(Level.INFO, "[NBTAPI] The NBT-API seems to be up-to-date!");
MinecraftVersion.getLogger().log(Level.INFO, "[NBTAPI] The NBT-API seems to be up-to-date!");
} else if (versionDifference == 1) {
MinecraftVersion.logger.log(Level.WARNING, "[NBTAPI] The NBT-API at '" + NBTItem.class.getPackage()
+ "' seems to be a future Version, not yet released on Spigot!");
MinecraftVersion.logger.log(Level.WARNING, "[NBTAPI] Current Version: '" + MinecraftVersion.VERSION
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] The NBT-API at '" + NBTItem.class.getPackage()
+ "' seems to be a future Version, not yet released on Spigot/CurseForge!");
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Current Version: '" + MinecraftVersion.VERSION
+ "' Newest Version: " + latest.get("name").getAsString() + "'");
}
} else {
// wut?!
MinecraftVersion.logger.log(Level.WARNING,
MinecraftVersion.getLogger().log(Level.WARNING,
"[NBTAPI] Error when looking for Updates! Got non Json Array: '" + element.toString() + "'");
}
}
@@ -4,7 +4,7 @@ import java.util.logging.Level;
import org.bukkit.Bukkit;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.getLogger;
/**
* Wraps NMS and CRAFT classes
@@ -15,8 +15,10 @@ import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
@SuppressWarnings("javadoc")
public enum ClassWrapper {
CRAFT_ITEMSTACK(PackageWrapper.CRAFTBUKKIT, "inventory.CraftItemStack"),
CRAFT_METAITEM(PackageWrapper.CRAFTBUKKIT, "inventory.CraftMetaItem"),
CRAFT_ENTITY(PackageWrapper.CRAFTBUKKIT, "entity.CraftEntity"),
CRAFT_WORLD(PackageWrapper.CRAFTBUKKIT, "CraftWorld"),
CRAFT_PERSISTENTDATACONTAINER(PackageWrapper.CRAFTBUKKIT, "persistence.CraftPersistentDataContainer", MinecraftVersion.MC1_14_R1, null),
NMS_NBTBASE(PackageWrapper.NMS, "NBTBase"),
NMS_NBTTAGSTRING(PackageWrapper.NMS, "NBTTagString"),
NMS_NBTTAGINT(PackageWrapper.NMS, "NBTTagInt"),
@@ -29,7 +31,7 @@ NMS_NBTTAGLIST(PackageWrapper.NMS, "NBTTagList"),
NMS_NBTCOMPRESSEDSTREAMTOOLS(PackageWrapper.NMS, "NBTCompressedStreamTools"),
NMS_MOJANGSONPARSER(PackageWrapper.NMS, "MojangsonParser"),
NMS_TILEENTITY(PackageWrapper.NMS, "TileEntity"),
NMS_BLOCKPOSITION(PackageWrapper.NMS, "BlockPosition"),
NMS_BLOCKPOSITION(PackageWrapper.NMS, "BlockPosition", MinecraftVersion.MC1_8_R3, null),
NMS_WORLDSERVER(PackageWrapper.NMS, "WorldServer"),
NMS_MINECRAFTSERVER(PackageWrapper.NMS, "MinecraftServer"),
NMS_WORLD(PackageWrapper.NMS, "World"),
@@ -38,9 +40,10 @@ NMS_ENTITYTYPES(PackageWrapper.NMS, "EntityTypes"),
NMS_REGISTRYSIMPLE(PackageWrapper.NMS, "RegistrySimple", MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_12_R1),
NMS_REGISTRYMATERIALS(PackageWrapper.NMS, "RegistryMaterials"),
NMS_IREGISTRY(PackageWrapper.NMS, "IRegistry"),
NMS_MINECRAFTKEY(PackageWrapper.NMS, "MinecraftKey"),
NMS_MINECRAFTKEY(PackageWrapper.NMS, "MinecraftKey", MinecraftVersion.MC1_8_R3, null),
NMS_GAMEPROFILESERIALIZER(PackageWrapper.NMS, "GameProfileSerializer"),
NMS_IBLOCKDATA(PackageWrapper.NMS, "IBlockData")
NMS_IBLOCKDATA(PackageWrapper.NMS, "IBlockData", MinecraftVersion.MC1_8_R3, null),
GAMEPROFILE("com.mojang.authlib.GameProfile", MinecraftVersion.MC1_8_R3)
;
private Class<?> clazz;
@@ -62,7 +65,19 @@ NMS_IBLOCKDATA(PackageWrapper.NMS, "IBlockData")
String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
clazz = Class.forName(packageId.getUri() + "." + version + "." + suffix);
}catch(Exception ex){
logger.log(Level.WARNING, "[NBTAPI] Error while trying to resolve the class '" + suffix + "'!", ex);
getLogger().log(Level.WARNING, "[NBTAPI] Error while trying to resolve the class '" + suffix + "'!", ex);
}
}
ClassWrapper(String path, MinecraftVersion from){
if(from != null && MinecraftVersion.getVersion().getVersionId() < from.getVersionId()) {
return;
}
enabled = true;
try{
clazz = Class.forName(path);
}catch(Exception ex){
getLogger().log(Level.WARNING, "[NBTAPI] Error while trying to resolve the class '" + path + "'!", ex);
}
}
@@ -6,7 +6,7 @@ import java.util.logging.Level;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.getLogger;
/**
* This Enum wraps Constructors for NMS classes
@@ -16,40 +16,41 @@ import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
*/
@SuppressWarnings("javadoc")
public enum ObjectCreator {
NMS_NBTTAGCOMPOUND(null, null, ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),
NMS_BLOCKPOSITION(null, null, ClassWrapper.NMS_BLOCKPOSITION.getClazz(), int.class, int.class, int.class),
NMS_COMPOUNDFROMITEM(MinecraftVersion.MC1_11_R1, null, ClassWrapper.NMS_ITEMSTACK.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),
;
NMS_NBTTAGCOMPOUND(null, null, ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),
NMS_BLOCKPOSITION(null, null, ClassWrapper.NMS_BLOCKPOSITION.getClazz(), int.class, int.class, int.class),
NMS_COMPOUNDFROMITEM(MinecraftVersion.MC1_11_R1, null, ClassWrapper.NMS_ITEMSTACK.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()),;
private Constructor<?> construct;
private Class<?> targetClass;
private Constructor<?> construct;
private Class<?> targetClass;
ObjectCreator(MinecraftVersion from, MinecraftVersion to, Class<?> clazz, Class<?>... args) {
if (clazz == null)
return;
if (from != null && MinecraftVersion.getVersion().getVersionId() < from.getVersionId())
return;
if (to != null && MinecraftVersion.getVersion().getVersionId() > to.getVersionId())
return;
try {
this.targetClass = clazz;
construct = clazz.getDeclaredConstructor(args);
construct.setAccessible(true);
} catch (Exception ex) {
getLogger().log(Level.SEVERE, "Unable to find the constructor for the class '" + clazz.getName() + "'", ex);
}
}
/**
* Creates an Object instance with given args
*
* @param args
* @return Object created
*/
public Object getInstance(Object... args) {
try {
return construct.newInstance(args);
} catch (Exception ex) {
throw new NbtApiException("Exception while creating a new instance of '" + targetClass + "'", ex);
}
}
ObjectCreator(MinecraftVersion from, MinecraftVersion to, Class<?> clazz, Class<?>... args){
if(from != null && MinecraftVersion.getVersion().getVersionId() < from.getVersionId())
return;
if(to != null && MinecraftVersion.getVersion().getVersionId() > to.getVersionId())
return;
try{
this.targetClass = clazz;
construct = clazz.getDeclaredConstructor(args);
construct.setAccessible(true);
}catch(Exception ex){
logger.log(Level.SEVERE, "Unable to find the constructor for the class '" + clazz.getName() + "'", ex);
}
}
/**
* Creates an Object instance with given args
*
* @param args
* @return Object created
*/
public Object getInstance(Object... args){
try{
return construct.newInstance(args);
}catch(Exception ex){
throw new NbtApiException("Exception while creating a new instance of '" + targetClass + "'", ex);
}
}
}
@@ -7,8 +7,6 @@ import java.util.UUID;
import org.bukkit.inventory.ItemStack;
import com.mojang.authlib.GameProfile;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
@@ -32,10 +30,11 @@ public enum ReflectionMethod {
COMPOUND_SET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, double.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setDouble")),
COMPOUND_SET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, boolean.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setBoolean")),
COMPOUND_SET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, UUID.class}, MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "a")),
COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping!
COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a")), //FIXME: No Spigot mapping!
COMPOUND_SET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "set")),
COMPOUND_GET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")),
COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getList")),
COMPOUND_OWN_TYPE(ClassWrapper.NMS_NBTBASE.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTypeId")), // Only needed for 1.7.10 getType
COMPOUND_GET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getFloat")),
COMPOUND_GET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")),
@@ -60,44 +59,45 @@ public enum ReflectionMethod {
COMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")),
LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")),
LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove")),
LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove")),
LIST_SIZE(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "size")),
LIST_SET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_13_R1, "set")),
LIST_SET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_13_R1, "set")),
LEGACY_LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_13_R2, new Since(MinecraftVersion.MC1_7_R4, "add")),
LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "add")),
LIST_GET_STRING(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")),
LIST_GET_COMPOUND(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")),
LIST_GET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "g"), new Since(MinecraftVersion.MC1_9_R1, "h"), new Since(MinecraftVersion.MC1_12_R1, "i"), new Since(MinecraftVersion.MC1_13_R1, "get")),
LIST_GET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get"), new Since(MinecraftVersion.MC1_8_R3, "g"), new Since(MinecraftVersion.MC1_9_R1, "h"), new Since(MinecraftVersion.MC1_12_R1, "i"), new Since(MinecraftVersion.MC1_13_R1, "get")),
ITEMSTACK_SET_TAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTag")),
ITEMSTACK_NMSCOPY(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ItemStack.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asNMSCopy")),
ITEMSTACK_BUKKITMIRROR(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_ITEMSTACK.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asCraftMirror")),
CRAFT_WORLD_GET_HANDLE(ClassWrapper.CRAFT_WORLD.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
NMS_WORLD_GET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTileEntity")),
NMS_WORLD_SET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz(), ClassWrapper.NMS_TILEENTITY.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTileEntity")),
NMS_WORLD_REMOVE_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "t"), new Since(MinecraftVersion.MC1_9_R1, "s"), new Since(MinecraftVersion.MC1_13_R1, "n"), new Since(MinecraftVersion.MC1_14_R1, "removeTileEntity")),
NMS_WORLD_GET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "getTileEntity")),
NMS_WORLD_SET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz(), ClassWrapper.NMS_TILEENTITY.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "setTileEntity")),
NMS_WORLD_REMOVE_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "t"), new Since(MinecraftVersion.MC1_9_R1, "s"), new Since(MinecraftVersion.MC1_13_R1, "n"), new Since(MinecraftVersion.MC1_14_R1, "removeTileEntity")),
NMS_WORLD_GET_TILEENTITY_1_7_10(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{int.class, int.class, int.class}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTileEntity")),
TILEENTITY_LOAD_LEGACY191(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTSERVER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_9_R1, MinecraftVersion.MC1_9_R1, new Since(MinecraftVersion.MC1_9_R1, "a")), //FIXME: No Spigot mapping!
TILEENTITY_LOAD_LEGACY183(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_9_R2, new Since(MinecraftVersion.MC1_8_R3, "c"), new Since(MinecraftVersion.MC1_9_R1, "a"), new Since(MinecraftVersion.MC1_9_R2, "c")), //FIXME: No Spigot mapping!
TILEENTITY_LOAD_LEGACY1121(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_WORLD.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_10_R1, MinecraftVersion.MC1_12_R1, new Since(MinecraftVersion.MC1_10_R1, "a"), new Since(MinecraftVersion.MC1_12_R1, "create")),
TILEENTITY_LOAD_LEGACY1151(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, MinecraftVersion.MC1_15_R1, new Since(MinecraftVersion.MC1_12_R1, "create")),
TILEENTITY_LOAD_LEGACY1151(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, MinecraftVersion.MC1_15_R1, new Since(MinecraftVersion.MC1_12_R1, "create")),
TILEENTITY_LOAD(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_IBLOCKDATA.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "create")),
TILEENTITY_GET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "save")),
TILEENTITY_SET_NBT_LEGACY1151(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_15_R1, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")),
TILEENTITY_GET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "b"), new Since(MinecraftVersion.MC1_9_R1, "save")),
TILEENTITY_SET_NBT_LEGACY1151(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_15_R1, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")),
TILEENTITY_SET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_IBLOCKDATA.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "load")),
TILEENTITY_GET_BLOCKDATA(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "getBlock")),
CRAFT_ENTITY_GET_HANDLE(ClassWrapper.CRAFT_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "f"), new Since(MinecraftVersion.MC1_16_R1, "load")), //FIXME: No Spigot mapping!
NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "e"), new Since(MinecraftVersion.MC1_12_R1, "save")),
NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "f"), new Since(MinecraftVersion.MC1_16_R1, "load")), //FIXME: No Spigot mapping!
NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "e"), new Since(MinecraftVersion.MC1_12_R1, "save")),
NMS_ENTITY_GETSAVEID(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_14_R1,new Since(MinecraftVersion.MC1_14_R1, "getSaveID")),
NBTFILE_READ(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{InputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping!
NBTFILE_WRITE(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), OutputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping!
PARSE_NBT(ClassWrapper.NMS_MOJANGSONPARSER.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "parse")),
REGISTRY_KEYSET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "keySet")),
REGISTRY_GET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "get")),
@@ -108,8 +108,12 @@ public enum ReflectionMethod {
REGISTRYMATERIALS_GETKEY (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_13_R2, new Since(MinecraftVersion.MC1_13_R2, "getKey")),
GAMEPROFILE_DESERIALIZE (ClassWrapper.NMS_GAMEPROFILESERIALIZER.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "deserialize")),
GAMEPROFILE_SERIALIZE (ClassWrapper.NMS_GAMEPROFILESERIALIZER.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), GameProfile.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "serialize")),
;
GAMEPROFILE_SERIALIZE (ClassWrapper.NMS_GAMEPROFILESERIALIZER.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), ClassWrapper.GAMEPROFILE.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "serialize")),
CRAFT_PERSISTENT_DATA_CONTAINER_TO_TAG (ClassWrapper.CRAFT_PERSISTENTDATACONTAINER.getClazz(), new Class[]{}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "toTagCompound")),
CRAFT_PERSISTENT_DATA_CONTAINER_GET_MAP (ClassWrapper.CRAFT_PERSISTENTDATACONTAINER.getClazz(), new Class[]{}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "getRaw")),
CRAFT_PERSISTENT_DATA_CONTAINER_PUT_ALL (ClassWrapper.CRAFT_PERSISTENTDATACONTAINER.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "putAll")),
;
private MinecraftVersion removedAfter;
private Since targetVersion;
@@ -120,9 +124,9 @@ public enum ReflectionMethod {
ReflectionMethod(Class<?> targetClass, Class<?>[] args, MinecraftVersion addedSince, MinecraftVersion removedAfter, Since... methodnames){
this.removedAfter = removedAfter;
MinecraftVersion server = MinecraftVersion.getVersion();
if(server.compareTo(addedSince) < 0 || (this.removedAfter != null && server.getVersionId() > this.removedAfter.getVersionId()))return;
if(!MinecraftVersion.isAtLeastVersion(addedSince) || (this.removedAfter != null && MinecraftVersion.isNewerThan(removedAfter)))return;
compatible = true;
MinecraftVersion server = MinecraftVersion.getVersion();
Since target = methodnames[0];
for(Since s : methodnames){
if(s.version.getVersionId() <= server.getVersionId() && target.version.getVersionId() < s.version.getVersionId())
@@ -135,7 +139,7 @@ public enum ReflectionMethod {
loaded = true;
methodName = targetVersion.name;
}catch(NullPointerException | NoSuchMethodException | SecurityException ex){
System.out.println("[NBTAPI] Unable to find the method '" + targetVersion.name + "' in '" + targetClass.getSimpleName() + "' Enum: " + this); //NOSONAR This gets loaded before the logger is loaded
System.out.println("[NBTAPI] Unable to find the method '" + targetVersion.name + "' in '" + (targetClass == null ? "null" : targetClass.getSimpleName()) + "' Enum: " + this); //NOSONAR This gets loaded before the logger is loaded
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 tr7zw
Copyright (c) 2020 tr7zw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+17 -7
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
</parent>
<artifactId>item-nbt-api-plugin</artifactId>
<packaging>jar</packaging>
@@ -12,19 +12,19 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>nbt-injector</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>nbt-data-api</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -63,7 +63,7 @@
<plugin>
<groupId>de.tr7zw.spigotmc.maven</groupId>
<artifactId>tr-spigotmc-maven-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.0.3-SNAPSHOT</version>
<executions>
<execution>
<id>start-server</id>
@@ -79,8 +79,18 @@
</execution>
</executions>
<configuration>
<!-- 1.8.8-R0.1-SNAPSHOT-latest, 1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest, 1.10.2-R0.1-SNAPSHOT-latest,1.11.2,1.12.2,1.13.2,1.14.4,1.15.1 -->
<versions>1.8.8-R0.1-SNAPSHOT-latest, 1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest, 1.10.2-R0.1-SNAPSHOT-latest,1.11.2,1.12.2,1.13.2,1.14.4,1.15.2,1.16.1</versions>
<!-- 1.8.8-R0.1-SNAPSHOT-latest, 1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest, 1.10.2-R0.1-SNAPSHOT-latest,1.11.2,1.12.2,1.13.2,1.14.4,1.15.1,1.16.1,1.16.2 -->
<versions>
https://yivesmirror.com/files/paper/PaperSpigot-1.8.8-R0.1-SNAPSHOT-latest.jar,
1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest,
1.10.2-R0.1-SNAPSHOT-latest,
1.11.2,
1.12.2,
1.13.2,
1.14.4,
1.15.1,
https://yivesmirror.com/files/paper/Paper-1.16.4-latest.jar
</versions>
<works>Success! This version of NBT-API</works>
<error>WARNING! This version of NBT-API</error>
<filename>item-nbt-api-plugin-${project.version}.jar</filename>
@@ -14,6 +14,8 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
import de.tr7zw.nbtapi.plugin.tests.GameprofileTest;
import de.tr7zw.nbtapi.plugin.tests.NBTFileTest;
import de.tr7zw.nbtapi.plugin.tests.blocks.BlockNBTTest;
import de.tr7zw.nbtapi.plugin.tests.chunks.ChunkNBTPersistentTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.EqualsTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.ForEachTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.GetterSetterTest;
@@ -31,10 +33,13 @@ import de.tr7zw.nbtapi.plugin.tests.injector.EntityCustomNbtInjectorTest;
import de.tr7zw.nbtapi.plugin.tests.injector.MergeTileSubCompoundTest;
import de.tr7zw.nbtapi.plugin.tests.injector.SpawnEntityCustomNbtInjectorTest;
import de.tr7zw.nbtapi.plugin.tests.injector.TilesCustomNBTInjectorTest;
import de.tr7zw.nbtapi.plugin.tests.items.DirectApplyTest;
import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemConvertionTest;
import de.tr7zw.nbtapi.plugin.tests.tiles.TileTest;
import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTPersistentTest;
import de.tr7zw.nbtinjector.NBTInjector;
import de.tr7zw.nbtapi.plugin.tests.items.ItemMergingTest;
public class NBTAPI extends JavaPlugin {
@@ -50,39 +55,72 @@ public class NBTAPI extends JavaPlugin {
@Override
public void onLoad() {
//Disabled by default since 2.1. Enable it yourself by calling NBTInjector.inject(); during onLoad.
/*getLogger().info("Injecting custom NBT");
try {
NBTInjector.inject();
getLogger().info("Injected!");
} catch (Throwable ex) { // NOSONAR
getLogger().log(Level.SEVERE, "Error while Injecting custom Tile/Entity classes!", ex);
compatible = false;
}*/
getConfig().options().copyDefaults(true);
getConfig().addDefault("nbtInjector.enabled", false);
getConfig().addDefault("bStats.enabled", true);
getConfig().addDefault("updateCheck.enabled", true);
saveConfig();
if(!getConfig().getBoolean("bStats.enabled")) {
getLogger().info("bStats disabled");
MinecraftVersion.disableBStats();
}
if(!getConfig().getBoolean("updateCheck.enabled")) {
getLogger().info("Update check disabled");
MinecraftVersion.disableUpdateCheck();
}
//Disabled by default since 2.1. Enable it yourself by calling NBTInjector.inject(); during onLoad/config
if(getConfig().getBoolean("nbtInjector.enabled")) {
getLogger().info("Injecting custom NBT");
try {
NBTInjector.inject();
getLogger().info("Injected!");
} catch (Throwable ex) { // NOSONAR
getLogger().log(Level.SEVERE, "Error while Injecting custom Tile/Entity classes!", ex);
compatible = false;
}
}
// NBTCompounds
apiTests.add(new GetterSetterTest());
apiTests.add(new TypeTest());
apiTests.add(new RemovingKeys());
apiTests.add(new ListTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 list support is not complete at all
apiTests.add(new ListTest());
apiTests.add(new SubCompoundsTest());
apiTests.add(new MergeTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 not a thing
apiTests.add(new MergeTest());
apiTests.add(new ForEachTest());
apiTests.add(new StreamTest());
apiTests.add(new EqualsTest());
apiTests.add(new IteratorTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 list support is not complete at all
apiTests.add(new IteratorTest());
// Items
apiTests.add(new ItemConvertionTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 not a thing
apiTests.add(new ItemConvertionTest());
apiTests.add(new EmptyItemTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) { // 1.7.10 not a thing
apiTests.add(new ItemMergingTest());
apiTests.add(new DirectApplyTest());
}
// Entity
apiTests.add(new EntityTest());
apiTests.add(new EntityCustomNbtPersistentTest());
// Tiles
apiTests.add(new TileTest());
apiTests.add(new TilesCustomNBTPersistentTest());
// Chunks
apiTests.add(new ChunkNBTPersistentTest());
// Blocks
apiTests.add(new BlockNBTTest());
// Files
apiTests.add(new NBTFileTest());
@@ -95,7 +133,8 @@ public class NBTAPI extends JavaPlugin {
apiTests.add(new EntityCustomNbtInjectorTest());
apiTests.add(new SpawnEntityCustomNbtInjectorTest());
apiTests.add(new GameprofileTest());
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3))
apiTests.add(new GameprofileTest());
}
@@ -106,10 +145,10 @@ public class NBTAPI extends JavaPlugin {
getLogger().info("Adding listeners...");
Bukkit.getPluginManager().registerEvents(new ReloadListener(), this);
getLogger().info("Checking bindings...");
MinecraftVersion.getVersion();
getLogger().info("Gson:");
MinecraftVersion.hasGsonSupport();
getLogger().info("Checking bindings...");
MinecraftVersion.getVersion();
boolean classUnlinked = false;
for (ClassWrapper c : ClassWrapper.values()) {
@@ -167,6 +206,9 @@ public class NBTAPI extends JavaPlugin {
} else {
getLogger().warning(
"WARNING! This version of NBT-API seems to be broken with your Spigot version! " + checkMessage);
if(MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4) {
getLogger().warning("1.7.10 is only partally supported! Some thing will not work/are not yet avaliable in 1.7.10!");
}
}
}
@@ -0,0 +1,40 @@
package de.tr7zw.nbtapi.plugin.tests.blocks;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import de.tr7zw.changeme.nbtapi.NBTBlock;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class BlockNBTTest implements Test {
@Override
public void test() throws Exception {
if(MinecraftVersion.getVersion().getVersionId() < MinecraftVersion.MC1_16_R3.getVersionId())return;
if (!Bukkit.getWorlds().isEmpty()) {
World world = Bukkit.getWorlds().get(0);
try {
if (world.getLoadedChunks().length > 1) {
Chunk chunk = world.getLoadedChunks()[0];
Block block = chunk.getBlock(0, 254, 0);
NBTBlock comp = new NBTBlock(block);
comp.getData().removeKey("Too");
if(comp.getData().hasKey("Too")) {
throw new NbtApiException("Unable to remove key from Block!");
}
comp.getData().setString("Too", "Bar");
if (!new NBTBlock(block).getData().getString("Too").equals("Bar")) {
throw new NbtApiException("Custom Data did not save to a Block!");
}
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTBlocks!", ex);
}
}
}
}
@@ -0,0 +1,40 @@
package de.tr7zw.nbtapi.plugin.tests.chunks;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import de.tr7zw.changeme.nbtapi.NBTChunk;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class ChunkNBTPersistentTest implements Test {
@Override
public void test() throws Exception {
if(MinecraftVersion.getVersion().getVersionId() < MinecraftVersion.MC1_16_R3.getVersionId())return;
if (!Bukkit.getWorlds().isEmpty()) {
World world = Bukkit.getWorlds().get(0);
try {
if (world.getLoadedChunks().length > 1) {
Chunk chunk = world.getLoadedChunks()[0];
NBTChunk comp = new NBTChunk(chunk);
NBTCompound persistentData = comp.getPersistentDataContainer();
persistentData.removeKey("Foo");
if(persistentData.hasKey("Foo")) {
throw new NbtApiException("Unable to remove key from Chunk!");
}
persistentData.setString("Foo", "Bar");
if (!new NBTChunk(chunk).getPersistentDataContainer().getString("Foo").equals("Bar")) {
throw new NbtApiException("Custom Data did not save to the Chunk!");
}
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTChunks!", ex);
}
}
}
}
@@ -1,5 +1,7 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import java.util.Arrays;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -17,6 +19,7 @@ public class EqualsTest implements Test{
cont.setString("hello", "world");
cont.setInteger("theAnswer", 42);
cont.addCompound("sub").setString("me", "too");
cont.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
ItemStack item = new ItemStack(Material.STONE);
NBTItem nbti = new NBTItem(item);
NBTCompound customData = nbti.addCompound("customData");
@@ -24,6 +27,7 @@ public class EqualsTest implements Test{
customData.addCompound("sub").setString("me", "too");
customData.setInteger("theAnswer", 42);
customData.setString("hello", "world");
customData.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
if(!customData.equals(cont)) {
throw new NbtApiException("Compounds did not match! " + customData + " " + cont);
}
@@ -67,6 +67,10 @@ public class ListTest implements Test {
} else {
throw new NbtApiException("Taglist is empty! The Item-NBT-API may not work!");
}
if(comp.getListType("complist") != NBTType.NBTTagCompound) {
throw new NbtApiException("complist had the wrong type! The Item-NBT-API may not work!");
}
// Integer
NBTList<Integer> intlist = comp.getIntegerList("inttest");
@@ -77,6 +81,10 @@ public class ListTest implements Test {
} else {
throw new NbtApiException("IntList is not correct! " + Arrays.toString(intlist.toArray(new Integer[0])));
}
if(comp.getListType("inttest") != NBTType.NBTTagInt) {
throw new NbtApiException("inttest had the wrong type! The Item-NBT-API may not work!");
}
// Double
NBTList<Double> doublelist = comp.getDoubleList("doubletest");
@@ -87,6 +95,10 @@ public class ListTest implements Test {
} else {
throw new NbtApiException("DoubleList is not correct! " + Arrays.toString(doublelist.toArray(new Double[0])));
}
if(comp.getListType("doubletest") != NBTType.NBTTagDouble) {
throw new NbtApiException("doubletest had the wrong type! The Item-NBT-API may not work!");
}
// Float
NBTList<Float> floatlist = comp.getFloatList("floattest");
@@ -97,6 +109,10 @@ public class ListTest implements Test {
} else {
throw new NbtApiException("FloatList is not correct! " + Arrays.toString(floatlist.toArray(new Float[0])));
}
if(comp.getListType("floattest") != NBTType.NBTTagFloat) {
throw new NbtApiException("floattest had the wrong type! The Item-NBT-API may not work!");
}
// Long
NBTList<Long> longlist = comp.getLongList("longtest");
@@ -108,6 +124,10 @@ public class ListTest implements Test {
throw new NbtApiException("LongList is not correct! " + Arrays.toString(longlist.toArray(new Long[0])));
}
if(comp.getListType("longtest") != NBTType.NBTTagLong) {
throw new NbtApiException("longtest had the wrong type! The Item-NBT-API may not work!");
}
}
}
@@ -45,6 +45,12 @@ public class SubCompoundsTest implements Test {
|| comp.getBoolean(BOOLEAN_TEST_KEY) == BOOLEAN_TEST_VALUE) {
throw new NbtApiException("One key does not equal the original compound value!");
}
// Using getOrCreateCompound twice
comp.getOrCreateCompound("someName").setString("test", "abc");
if(!comp.getOrCreateCompound("someName").getString("test").equals("abc")) {
throw new NbtApiException("getOrCreateCompound did not return the same compound!");
}
}
}
@@ -1,14 +1,11 @@
package de.tr7zw.nbtapi.plugin.tests.entities;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Monster;
import de.tr7zw.changeme.nbtapi.NBTEntity;
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
@@ -25,23 +22,7 @@ public class EntityTest implements Test {
nbte.setString("INVALIDEKEY", "test");
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTEntities!");
}
try {
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255,
world.getSpawnLocation().getBlockZ());
if (block.getType() == Material.AIR) {
block.setType(Material.CHEST);
NBTTileEntity tile = new NBTTileEntity(block.getState());
tile.setString("Lock", "test");
if (!tile.asNBTString().contains("Lock:\"test\"")) {
block.setType(Material.AIR);
throw new NbtApiException("The Lock wasn't successfully set.");
}
block.setType(Material.AIR);
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
throw new NbtApiException("Wasn't able to use NBTEntities!", ex);
}
}
}
@@ -0,0 +1,22 @@
package de.tr7zw.nbtapi.plugin.tests.items;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class DirectApplyTest implements Test{
@Override
public void test() throws Exception {
ItemStack baseItem = new ItemStack(Material.STONE);
NBTItem nbti = new NBTItem(baseItem, true);
nbti.setString("SomeKey", "SomeValue");
if(!baseItem.equals(nbti.getItem()) || !new NBTItem(baseItem).hasKey("SomeKey")) {
throw new NbtApiException("The item's where not equal!");
}
}
}
@@ -0,0 +1,56 @@
package de.tr7zw.nbtapi.plugin.tests.items;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class ItemMergingTest implements Test {
@Override
public void test() throws Exception {
ItemStack item = new ItemStack(Material.WRITTEN_BOOK);
BookMeta bookMeta = (BookMeta) item.getItemMeta();
bookMeta.setAuthor("Author");
bookMeta.setDisplayName("name");
item.setItemMeta(bookMeta);
NBTItem nbti = new NBTItem(item);
nbti.setString("author", "New Author");
nbti.setString("test", "value");
nbti.mergeCustomNBT(item);
if (!new NBTItem(item).hasKey("test"))
throw new NbtApiException("Couldn't merge custom NBT tag!");
if ("New Author".equals(new NBTItem(item).getString("author")))
throw new NbtApiException("Vanilla NBT tag was merged when shouldn't!");
nbti.setString("test", "New Value");
nbti.mergeNBT(item);
if (!"New Author".equals(new NBTItem(item).getString("author")) || !"New Value".equals(new NBTItem(item).getString("test")))
throw new NbtApiException("Couldn't replace NBT tag while merging!");
ItemStack test = new ItemStack(Material.WRITTEN_BOOK);
nbti.applyNBT(test);
if (!item.isSimilar(test))
throw new NbtApiException("ItemStacks didn't match! " + new NBTItem(item) + " " + new NBTItem(test));
test = new ItemStack(Material.STONE);
nbti.applyNBT(test);
if (!nbti.hasKey("test"))
throw new NbtApiException("Couldn't merge custom NBT tag!");
if (!item.getItemMeta().getDisplayName().equals(test.getItemMeta().getDisplayName()))
throw new NbtApiException("Couldn't merge vanilla NBT tag!");
nbti.setBoolean("remove", true);
nbti.clearCustomNBT();
if (nbti.hasKey("remove"))
throw new NbtApiException("Couldn't clear custom NBT tags!");
if (!nbti.hasKey("author"))
throw new NbtApiException("Vanilla tag was removed!");
}
}
@@ -0,0 +1,42 @@
package de.tr7zw.nbtapi.plugin.tests.tiles;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class TileTest implements Test {
@Override
public void test() throws Exception {
if (!Bukkit.getWorlds().isEmpty()) {
World world = Bukkit.getWorlds().get(0);
try {
Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255,
world.getSpawnLocation().getBlockZ());
if (block.getType() == Material.AIR) {
block.setType(Material.CHEST);
NBTTileEntity tile = new NBTTileEntity(block.getState());
if(tile.getInteger("y") != 255) {
block.setType(Material.AIR);
throw new NbtApiException("The Tile Y pos wasn't correct!");
}
tile.setString("Lock", "test");
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3) && !tile.hasKey("Lock")) {
block.setType(Material.AIR);
throw new NbtApiException("The Lock wasn't successfully set.");
}
block.setType(Material.AIR);
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
}
}
}
}
@@ -26,7 +26,7 @@ public class TilesCustomNBTPersistentTest implements Test {
NBTTileEntity comp = new NBTTileEntity(block.getState());
NBTCompound persistentData = comp.getPersistentDataContainer();
persistentData.setString("Foo", "Bar");
if (!new NBTTileEntity(block.getState()).getPersistentDataContainer().toString().contains("Foo:\"Bar\"")) {
if (!new NBTTileEntity(block.getState()).getPersistentDataContainer().getString("Foo").equals("Bar")) {
block.setType(Material.AIR);
throw new NbtApiException("Custom Data did not save to the Tile!");
}
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 tr7zw
Copyright (c) 2020 tr7zw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
</parent>
<artifactId>nbt-data-api</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 tr7zw
Copyright (c) 2020 tr7zw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
</parent>
<artifactId>nbt-injector</artifactId>
<packaging>jar</packaging>
@@ -12,7 +12,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -179,6 +179,10 @@ public class ClassGenerator {
: "void";
String writeName = ReflectionMethod.TILEENTITY_GET_NBT.getMethodName();
String readName = ReflectionMethod.TILEENTITY_SET_NBT.getMethodName();
if(MinecraftVersion.getVersion().getVersionId() < MinecraftVersion.MC1_16_R1.getVersionId()) {
readName = ReflectionMethod.TILEENTITY_SET_NBT_LEGACY1151.getMethodName();
}
String writeMethod = "public " + writeReturn + " " + writeName + "(NBTTagCompound compound) {\n"
+ " compound = writeExtraCompound(compound);\n"
// + " System.out.println(\"Save: \" +compound);\n"
@@ -22,7 +22,7 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
import de.tr7zw.nbtinjector.NBTInjector.Entity;
import de.tr7zw.nbtinjector.NBTInjector.TileEntity;
import javassist.ClassPool;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
import static de.tr7zw.nbtinjector.NBTInjector.logger;
/**
* Contains the internal methods for different Minecraft Versions of injecting
@@ -34,7 +34,7 @@ public class NBTInjector {
}
static Logger logger = Logger.getLogger("NBTInjector");
protected static Logger logger = Logger.getLogger("NBTInjector");
private static boolean isInjected = false;
private static final String NOT_INJECTED_MESSAGE = "The NBTInjector has not been enabled!\n"
+ "You need to call 'NBTInjector.inject()' during the Method 'onLoad' of your Plugin!"
@@ -48,6 +48,10 @@ public class NBTInjector {
*/
public static void inject() {
if(isInjected)return;
if(MinecraftVersion.getVersion() == MinecraftVersion.MC1_7_R4 || MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
logger.warning("[NBTINJECTOR] The NBT-Injector is not compatibel with this Minecraft Version! For 1.16+ please use the persistent storage API.");
return;
}
isInjected = true;
try {
ClassPool classPool = ClassPool.getDefault();
+5 -4
View File
@@ -3,22 +3,23 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.4.1</version>
<version>${nbt.version}</version>
<packaging>pom</packaging>
<modules>
<module>item-nbt-api</module>
<module>nbt-injector</module>
<module>nbt-data-api</module>
<module>nbt-data-api</module>
<module>item-nbt-plugin</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<nbt.version>2.7.0</nbt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.14.2-R0.1-SNAPSHOT</version>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -115,7 +116,7 @@
<plugin>
<groupId>com.github.ekryd.sortpom</groupId>
<artifactId>sortpom-maven-plugin</artifactId>
<version>2.11.0</version>
<version>2.12.0</version>
<executions>
<execution>
<id>sortpom</id>
+289
View File
@@ -0,0 +1,289 @@
[B][SIZE=6](Item/Entity/Tile) NBT API[/SIZE][/B]
[URL='https://ci.codemc.io/job/Tr7zw/job/Item-NBT-API/'][IMG]https://ci.codemc.org/buildStatus/icon?job=Tr7zw%2FItem-NBT-API[/IMG][/URL] [URL='https://sonarcloud.io/dashboard?id=de.tr7zw%3Aitem-nbt-parent'][IMG]https://sonarcloud.io/api/project_badges/measure?project=de.tr7zw%3Aitem-nbt-parent&metric=ncloc[/IMG][/URL] [URL='https://bstats.org/plugin/bukkit/ItemNBTAPI'][IMG]https://img.shields.io/bstats/servers/1058.svg?color=green&label=OnlineServers&style=plastic[/IMG][/URL] [URL='https://bstats.org/plugin/bukkit/ItemNBTAPI'][IMG]https://img.shields.io/bstats/players/1058.svg?color=green&label=OnlinePlayers&style=plastic[/IMG] [/URL][URL='https://discordapp.com/invite/yk4caxM'][IMG]https://img.shields.io/discord/342814924310970398?color=%237289DA&label=Discord&logo=discord&logoColor=white[/IMG][/URL] [IMG]https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dtr7zw%26type%3Dpatrons&style=for-the-badge[/IMG]
The NBT API allows you to add custom NBT tags to Itemstacks, TileEntities and Entities, or modify excisting ones!
It completely uses reflections to interact with NMS code and works with all the latest versions. On server start the plugin checks all reflections.
Tested on Spigot
[LIST]
[*](1.7*)1.8.8-1.16.4
[*]The NBTInjector will not work with: 1.12.0, 1.12.1, 1.13.0 (Please just update to the final release of your chosen version)
[*]On startup you will get a notification if there is a version problem!
[/LIST]
* 1.7 Notes: Use a 1.7 with R4 (1.7.10), NBTLists may not work, everything using Gson is disabled(Add Gson before the NBTAPI loads, to turn it back on), and you can't get the NBTTypes, because 1.7 is missing this feature. TLDR: 1.7.10 is somewhat broken and not everything might work due to 1.7.10 limitations.
[B]What do I have to do as a server owner?[/B]
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.
[B]Important for version 2.0.0:[/B] Don't reload while using the NBTInjector. 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!
[B]How can I use the API as developer?[/B]
Create the NBT Wrapper:
[CODE]NBTItem nbti = new NBTItem(item);
NBTEntity nbtent = new NBTEntity(zombie); //Only for vanilla tags!
NBTTileEntity tent = new NBTTileEntity(block.getState()); //Only for vanilla tags!
NBTFile file = new NBTFile(new File(getDataFolder(), "test.nbt"));
NBTContainer container = new NBTContainer(json); //Parse in json
[/CODE]
Add/Get/Override NBT tags:
[CODE]//Set
nbti.setString("Stringtest", "Teststring");
nbti.setInteger("Inttest", 42);
nbti.setDouble("Doubletest", 1.5d);
nbti.setBoolean("Booleantest", true);
//More are avaible!
//Get
nbti.getString("Stringtest");
nbti.getInteger("Inttest");
nbti.getDouble("Doubletest");
nbti.getBoolean("Booleantest");
//Get all Tags
nbti.getKeys();
//Check for an tag
nbti.hasKey("Key");
//Remove a tag
nbti.removeKey("Key");
//or
nbti.setString("Stringtest", null);
//Create NBTTagCombounds(Imagine folders)
nbti.addCompound("subtag");
//Get Compound
NBTCompound comp = nbti.getCompound("subtag");
//Get Compound parent(null at root)
comp.getParent();
//Save Objects via Gson
nbti.setObject("myobject", new SimpleJsonTestObject());
//Get Objects
SimpleJsonTestObject simpleObject = nbti.getObject("myobject", SimpleJsonTestObject.class);
//Merge the data from compound A into B (Like the /data merge command)
B.mergeCompound(A);
//Get the nbt as json
comp.asNBTString();
//Access/create lists
nbtent.getCompoundList("Attributes");
nbtent.getStringList("Attributes");
[/CODE]
And finally get back the Bukkit Itemstack(Changes on Tiles/Entities will happen directly):
[CODE]nbti.getItem();[/CODE]
Saving the NBTFile:
[CODE]file.save();[/CODE]
[B]Important note regarding Tiles/Entities
[B]Starting with 1.14+ you can use the getPersistentDataContainer() (for NBT(Tile)-Entity's) to save custom tags. This replaces the now mentioned NBT-Injector.[/B][/B]
Non-vanilla tags can't usually be added to to Tiles/Entities. Thanks to
[URL='https://www.spigotmc.org/members/inventivetalent.6643/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=6643[/IMG][/URL] the NBTAPI now includes a tool called "NBTInjector", that compiles custom (Tile-)Entity classes during runtime to allow custom nbt. The custom data will remain during chunk unloads/server restarts. [B]Data will be lost when chunks get loaded without the NBTAPI loaded! Since 2.1.0 the NBTInjector won't be enabled by default! Please enable it during onLoad with NBTInjector.inject(); if you are using it![/B]
Adding custom nbt to tiles:
[CODE]
NBTCompound comp = NBTInjector.getNbtData(block.getState());
comp.setString("Foo", "Bar");
[/CODE]
Adding custom nbt to entities:
[CODE]
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
ent = NBTInjector.patchEntity(ent); //This needs to be called at least once on the entity to enable custom nbt!
NBTCompound comp = NBTInjector.getNbtData(ent);
comp.setString("Hello", "World");
[/CODE]
[B]Note[/B]: Before NBTInjector.getNbtData can be used on an Entity, NBTInjector.patchEntity has to be used on it at least once. This method will check if the entity is patched, and if not remove the entity and respawn it with the correct class. This destroys the original entity reference(the new one is returned) and the entity will blink once ingame. Bestcase you call this method right when the entity is spawned to prevent unwanted behavior(the blink, entities interacting with the Entity beeing patched like riding/leashes/combat may have problems).
[B]Maven[/B]
(Historicly it was Jitpack. Don't use it anymore!)
NBTApi is hosted and compiled by CodeMC.
[URL='https://ci.codemc.org/job/Tr7zw/job/Item-NBT-API/']JenkinsBuild[/URL] [URL='https://github.com/CodeMC/CI-Documentation']CodeMC-Info[/URL]
[code]<repositories>
...
<!-- CodeMC -->
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
<layout>default</layout>
</repository>
...
</repositories>
[/code]
The API can be used in different ways:
[SPOILER="Normal Plugin dependency"]
Just use the Plugin as Maven dependency and remember to add "NBTAPI" as dependency into the plugin.yml. This way server owners will have to install the api and keep it updated.
[CODE]
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api-plugin</artifactId>
<version>2.6.0</version>
</dependency>
[/CODE]
[/SPOILER]
[SPOILER="Shading the API into your plugin"]
Using this method the API gets copied into your plugin. Server owners don't have to install the API on their own, but you need to keep it updated. Also [B]relocating is required[/B]!
[CODE]
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.6.0</version>
</dependency>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>shade</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<relocations>
<relocation>
<pattern>de.tr7zw.changeme.nbtapi</pattern>
<shadedPattern>YOUR PACKGE WHERE THE API SHOULD END UP</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
[/CODE]
[/SPOILER]
[B]Example Code[/B]
[SPOILER="Zombie that will pickup loot and does 0.5 Hearts of damage"]
[CODE]
Zombie z = (Zombie) b.getWorld().spawnEntity(b.getLocation().add(0, 1, 0), EntityType.ZOMBIE);
NBTEntity nbtent = new NBTEntity(z);
nbtent.setByte("CanPickUpLoot", (byte) 1);
NBTList list = nbtent.getCompoundList("Attributes");
for(int i = 0; i < list.size(); i++){
NBTListCompound lc = list.getCompound(i);
if(lc.getString("Name").equals("generic.attackDamage")){
lc.setDouble("Base", 0.5d);
}
}
[/CODE]
[/SPOILER]
[SPOILER="Simulate the command /data merge entity @e[type=zombie] {Silent:1b,Invulnerable:1b,Glowing:1b,IsBaby:1b}"]
[CODE]
NBTEntity nbtent = new NBTEntity(zombie);
nbtent.mergeCompound(new NBTContainer("{Silent:1b,Invulnerable:1b,Glowing:1b,IsBaby:1b}"));
[/CODE]
[/SPOILER]
[SPOILER="Creating a Head with texture, healthboost and some more tags"]
[CODE]
ItemStack head = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
NBTItem nbti = new NBTItem(head);
NBTCompound disp = nbti.addCompound("display");
disp.setString("Name", "Testitem");
List<String> l = disp.getStringList("Lore");
l.add("Some lore");
NBTCompound skull = nbti.addCompound("SkullOwner");
skull.setString("Name", "tr7zw");
skull.setString("Id", "fce0323d-7f50-4317-9720-5f6b14cf78ea");
NBTListCompound texture = skull.addCompound("Properties").getCompoundList("textures").addCompound();
texture.setString("Signature", "XpRfRz6/vXE6ip7/vq+40H6W70GFB0yjG6k8hG4pmFdnJFR+VQhslE0gXX/i0OAGThcAVSIT+/W1685wUxNofAiy+EhcxGNxNSJkYfOgXEVHTCuugpr+EQCUBI6muHDKms3PqY8ECxdbFTUEuWxdeiJsGt9VjHZMmUukkGhk0IobjQS3hjQ44FiT1tXuUU86oAxqjlKFpXG/iXtpcoXa33IObSI1S3gCKzVPOkMGlHZqRqKKElB54I2Qo4g5CJ+noudIDTzxPFwEEM6XrbM0YBi+SOdRvTbmrlkWF+ndzVWEINoEf++2hkO0gfeCqFqSMHuklMSgeNr/YtFZC5ShJRRv7zbyNF33jZ5DYNVR+KAK9iLO6prZhCVUkZxb1/BjOze6aN7kyN01u3nurKX6n3yQsoQQ0anDW6gNLKzO/mCvoCEvgecjaOQarktl/xYtD4YvdTTlnAlv2bfcXUtc++3UPIUbzf/jpf2g2wf6BGomzFteyPDu4USjBdpeWMBz9PxVzlVpDAtBYClFH/PFEQHMDtL5Q+VxUPu52XlzlUreMHpLT9EL92xwCAwVBBhrarQQWuLjAQXkp3oBdw6hlX6Fj0AafMJuGkFrYzcD7nNr61l9ErZmTWnqTxkJWZfZxmYBsFgV35SKc8rkRSHBNjcdKJZVN4GA+ZQH5B55mi4=");
texture.setString("Value", "eyJ0aW1lc3RhbXAiOjE0OTMwNDkwMTcxNTIsInByb2ZpbGVJZCI6ImZjZTAzMjNkN2Y1MDQzMTc5NzIwNWY2YjE0Y2Y3OGVhIiwicHJvZmlsZU5hbWUiOiJ0cjd6dyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTI3NDZlNWU5OGMwZWRmZTU1YTI3ZGRjNjUxMmJmNjllYzJiYmNlNmM3ZmNhNTQ5YmEzNjZkYThiNTRjZTRkYiJ9fX0=");
NBTCompoundList attribute = nbti.getCompoundList("AttributeModifiers");
NBTListCompound mod1 = attribute.addCompound();
mod1.setInteger("Amount", 10);
mod1.setString("AttributeName", "generic.maxHealth");
mod1.setString("Name", "generic.maxHealth");
mod1.setInteger("Operation", 0);
mod1.setInteger("UUIDLeast", 59664);
mod1.setInteger("UUIDMost", 31453);
nbti.setInteger("HideFlags", 4);
nbti.setBoolean("Unbreakable", true);
head = nbti.getItem();
e.getPlayer().getInventory().addItem(head);
[/CODE]
[/SPOILER]
[SPOILER="Printing the NBT tags"]
[CODE]
Ocelot m = (Ocelot) e.getPlayer().getWorld().spawnEntity(e.getPlayer().getLocation(), EntityType.OCELOT);
NBTEntity ent = new NBTEntity(m);
System.out.println(ent);
[/CODE]
Output:
[CODE]
-AgeLocked: 0b
-HurtByTimestamp: 0
-CatType: 0
-Leashed: 0b
-Health: 10.0f
-Sitting: 0b
-Attributes: [0:{Base:10.0d,Name:"generic.maxHealth"},1:{Base:0.0d,Name:"generic.knockbackResistance"},2:{Base:0.30000001192092896d,Name:"generic.movementSpeed"},3:{Base:0.0d,Name:"generic.armor"},4:{Base:0.0d,Name:"generic.armorToughness"},5:{Base:16.0d,Modifiers:[0:{UUIDMost:-8783172028836920024L,UUIDLeast:-6820414278857408689L,Amount:-0.030166473586416633d,Operation:1,Name:"Random spawn bonus"}],Name:"generic.followRange"}]
-FallFlying: 0b
-LeftHanded: 0b
-ForcedAge: 0
-AbsorptionAmount: 0.0f
-HandItems: [0:{},1:{}]
-ArmorDropChances: [0:0.085f,1:0.085f,2:0.085f,3:0.085f]
-OwnerUUID: ""
-InLove: 0
-DeathTime: 0s
-ArmorItems: [0:{},1:{},2:{},3:{}]
-CanPickUpLoot: 0b
-HandDropChances: [0:0.085f,1:0.085f]
-PersistenceRequired: 0b
-HurtTime: 0s
-Age: 0
[/CODE]
[/SPOILER]
[SPOILER="Locking Chests"]
[CODE] NBTTileEntity tent = new NBTTileEntity(b.getState());
tent.setString("Lock", "test");[/CODE]
[/SPOILER]
[B]More Infos:[/B]
[LIST]
[*][URL]https://www.spigotmc.org/threads/override-base-item-attribute-value.236434/#post-2387235[/URL]
[/LIST]
[B]This API can't be used for:[/B]
[LIST]
[*][I][SIZE=4][S]Adding custom tags to TileEntities/Entities[/S] [/SIZE][/I][SIZE=4]Not true anymore, check the NBTInjector examples above[/SIZE]
[/LIST]
Git: [URL='https://github.com/tr7zw/Item-NBT-API']Github[/URL]
Maven Repo: [URL='https://repo.codemc.org/#browse/browse:maven-public:de%2Ftr7zw%2Fitem-nbt-api-plugin']CodeMC[/URL]
Jenkins: [URL='https://ci.codemc.org/job/Tr7zw/job/Item-NBT-API/']Jenkins[/URL]
Discord server for help: [URL='https://discord.gg/yk4caxM']Discord[/URL]
Feel free to create forks for your need! (Send me a message on [S]Spigot[/S] the Discord server if you want stuff to be added/need help)
Yes you are allowed to integrate the API into your plugin(remember to shade)! (Send me a link to your project so I can check it out ;))
[B][SIZE=5]Projects using the API(That I know of)[/SIZE]
[U][SIZE=4]Plugins[/SIZE][/U][/B]
[URL='https://www.spigotmc.org/resources/crazy-enchantments.16470/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=16470&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/backpacks.45622/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=45622&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/gravy.45288/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=45288&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/interactivebooks.45604/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=45604&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/vouchers.13654/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=13654&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/itemcommands.49543/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=49543&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/comparable-hoppers-2.45058/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=45058&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/nottooexpensive.62680/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=62680&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/papermoney.70361/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=70361&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/blockstackerx-plugin-for-askyblock.71514/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=71514&[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/blockstackerx-recoded.73749/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=73749[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/63020/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=63020&reload[/IMG][/URL]
[URL='https://www.spigotmc.org/resources/72810/'][IMG]https://tr7zw.dev/nbtapi/linkedProjects.php?id=72810&reload[/IMG][/URL]
[U][B]Server/Networks[/B][/U]
[URL='http://Timolia.de'][IMG]http://status.mclive.eu/Timolia.de/timolia.de/25565/banner.png[/IMG][/URL]
[U][B]Other[/B][/U]
- [URL='https://github.com/LogisticsCraft/Logistics-API']Logistics-API[/URL]
If you like this Resource, donate me a Coffee or become a Patreon for cool perks! [URL='https://tr7zw.dev/donate/']Donating[/URL]
[SIZE=4][SIZE=4][U][B]Donators[/B][/U]
[U][B][URL='https://www.spigotmc.org/members/mrdienns.35704/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=35704[/IMG][/URL] [/B][/U]
[U][B][URL='https://www.spigotmc.org/members/mraxetv.27720/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=27720[/IMG][/URL] [/B][/U]
[URL='https://www.spigotmc.org/members/lonedev.88296/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=88296[/IMG][/URL]
[URL='https://www.spigotmc.org/members/gc.25090/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=25090[/IMG][/URL]
[URL='https://www.spigotmc.org/members/peaches_mlg100.194338/'][IMG]https://tr7zw.dev/nbtapi/spigotPeople.php?id=194338[/IMG][/URL][/SIZE][/SIZE]
[IMG]https://bstats.org/signatures/bukkit/ItemNBTAPI.svg[/IMG]