Compare commits

...
41 Commits
Author SHA1 Message Date
tr7zw 61fd8669f0 Prepare Tag 2.2.0 2019-12-31 15:23:28 +01:00
tr7zw aa54a91c40 clean pom 2019-12-31 15:18:21 +01:00
tr7zw d97a050e1a Fix bug in nbtcompound to ItemStack method, added simple ItemStack getter/setter 2019-12-31 01:36:23 +01:00
tr7zw 8479479c84 Handle async bstats init
Fixes #59
2019-12-30 15:50:52 +01:00
tr7zw 6129125dd9 Add toString to lists 2019-12-30 12:00:39 +01:00
tr7zw 43baa7c2ef Detect future Versions, real version checking 2019-12-30 01:28:45 +01:00
tr7zw c6cbc3b309 Fix build 2019-12-30 00:14:02 +01:00
tr7zw 39fd158c56 Add update check 2019-12-29 20:13:11 +01:00
tr7zw 2202dc38e0 Lists fix previous, but not sure how correct it compared to how it should work 2019-12-29 19:14:17 +01:00
tr7zw 656b7caff2 Fix List's Iterator/ListIterator off-by-one Error
List Iterator's previous is probably still broken
2019-12-29 19:01:20 +01:00
tr7zw 0918f25716 Remove debug message 2019-12-26 01:49:58 +01:00
tr7zw 662ad04a5e Removed custom toString (now uses asNBTString), CompList AddCompound got a helper method for auto copy 2019-12-26 01:45:02 +01:00
tr7zw daf684931f More stacked list tests, fix java 11 javadoc 2019-12-26 01:16:32 +01:00
tr7zw 99b5775855 Merge pull request #58 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.2.1
Bump maven-source-plugin from 3.2.0 to 3.2.1
2019-12-23 13:04:57 +01:00
dependabot-preview[bot] 87a6fce52f Bump maven-source-plugin from 3.2.0 to 3.2.1
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.0...maven-source-plugin-3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 05:20:46 +00:00
tr7zw 0a46bce99c Fix javadoc 2019-12-23 01:42:35 +01:00
tr7zw a1a3c0be33 Make CompoundLists extend NBTCompounds, so now they feature all methods
This took way to long...........
2019-12-23 00:09:19 +01:00
tr7zw bbf5064a15 fuuuu 2019-12-21 21:49:31 +01:00
tr7zw 437c69b7f4 Wups setAccessible 2019-12-21 21:23:23 +01:00
tr7zw ede8ebba6b Trying to fix Reflections for Java 11+
This is related to #50
2019-12-21 18:23:15 +01:00
tr7zw 54d1ed019f Throw exception on NBT-Injector use without enableing it
Fixes #51
2019-12-21 16:14:33 +01:00
tr7zw 4491709645 Bump version to 2.2.0-SNAPSHOT 2019-12-21 16:07:11 +01:00
tr7zw 34abb0aefb Merge pull request #57 from SoSeDiK/injector
Injector: Updated fields' names for 1.15 support
2019-12-21 15:59:00 +01:00
SoSeDiK 2522edac6b Updated fields' names for 1.15 support 2019-12-20 23:03:04 +02:00
tr7zw f64ac8e3ac 1.15 update, 2.2.1 2019-12-13 19:27:04 +01:00
tr7zw 5d3188a813 Merge branch 'master' of https://github.com/tr7zw/Item-NBT-API 2019-12-13 18:27:32 +01:00
tr7zw fc85d7f4ec Add 1.15 to testing 2019-12-13 18:26:09 +01:00
tr7zw 6063f8a27d Merge pull request #54 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.2.0
Bump maven-source-plugin from 3.1.0 to 3.2.0
2019-11-04 10:33:33 +01:00
dependabot-preview[bot] f203a0c8bc Bump maven-source-plugin from 3.1.0 to 3.2.0
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.1.0...maven-source-plugin-3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-04 08:59:27 +00:00
tr7zw 0bec8d4025 Merge pull request #48 from tr7zw/e3ndr-readme-update
Update README.md
2019-10-17 20:17:09 +02:00
Ender 56abfad7a1 Update README.md 2019-10-17 12:37:15 -05:00
tr7zw e96ae3227e Merge pull request #47 from tr7zw/github-completebuild
Try full build + on pull_request
2019-10-09 15:10:47 +02:00
tr7zw b727e33227 Try full build + on pull_request 2019-10-09 14:50:06 +02:00
tr7zw be13f4bd5e Fix snapshot build 2019-10-09 11:03:02 +02:00
tr7zw 18d03036a9 Add missing Entity mappings for 1.14 2019-10-07 16:48:53 +02:00
tr7zw edeb9051e7 Fix dependency 2019-10-07 16:32:56 +02:00
tr7zw 5b17a25c23 Change to 2.1.1-SNAPSHOT 2019-10-07 16:30:44 +02:00
tr7zw 9f8208347b Merge pull request #45 from tr7zw/GithubActionsBuild
Update maven.yml
2019-10-01 10:05:52 +02:00
tr7zw 6e3ab1fb7e Update maven.yml 2019-10-01 10:02:04 +02:00
tr7zw 7587df8ef2 Forgot to increment version in MetricsLite. Sadly to late now 2019-09-24 01:44:38 +02:00
tr7zw e769113e51 2.1.0 update
Update to 2.1.0:
- Fixed 1.12/11 invisible mobs
- Fixed an NBTInjector exception that could happen in 1.13.2
- If reflections where unable to get their hook, a NPE was thrown because the logger wasn't yet initialized
- The NBTInjector won't enable by default, enable it during onLoad if you want to use it
- Prevent /reload when the NBTInjector is enabled to prevent currupt serverstates
2019-09-23 20:44:20 +02:00
27 changed files with 1577 additions and 1256 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
name: Java CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn --file pom.xml
+3 -2
View File
@@ -1,8 +1,9 @@
# Item-NBT-API
Add custom NBT tags to Items without NMS!
Add custom NBT tags to Items without NMS!<br/>
[Server Owner/Developer Wiki](https://github.com/tr7zw/Item-NBT-API/wiki)
### 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)
### 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)
[![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)
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
</parent>
<artifactId>item-nbt-api</artifactId>
@@ -3,6 +3,8 @@ package de.tr7zw.changeme.nbtapi;
import java.io.Serializable;
import java.util.Set;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -23,6 +25,11 @@ public class NBTCompound {
this.parent = owner;
}
protected void saveCompound(){
if(parent != null)
parent.saveCompound();
}
/**
* @return The Compound name
*/
@@ -56,6 +63,7 @@ public class NBTCompound {
*/
public void mergeCompound(NBTCompound comp) {
NBTReflectionUtil.mergeOtherNBTCompound(this, comp);
saveCompound();
}
/**
@@ -66,6 +74,7 @@ public class NBTCompound {
*/
public void setString(String key, String value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_STRING, key, value);
saveCompound();
}
/**
@@ -90,6 +99,7 @@ public class NBTCompound {
*/
public void setInteger(String key, Integer value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_INT, key, value);
saveCompound();
}
/**
@@ -110,6 +120,7 @@ public class NBTCompound {
*/
public void setDouble(String key, Double value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_DOUBLE, key, value);
saveCompound();
}
/**
@@ -130,6 +141,7 @@ public class NBTCompound {
*/
public void setByte(String key, Byte value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_BYTE, key, value);
saveCompound();
}
/**
@@ -150,6 +162,7 @@ public class NBTCompound {
*/
public void setShort(String key, Short value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_SHORT, key, value);
saveCompound();
}
/**
@@ -170,6 +183,7 @@ public class NBTCompound {
*/
public void setLong(String key, Long value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_LONG, key, value);
saveCompound();
}
/**
@@ -190,6 +204,7 @@ public class NBTCompound {
*/
public void setFloat(String key, Float value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_FLOAT, key, value);
saveCompound();
}
/**
@@ -210,6 +225,7 @@ public class NBTCompound {
*/
public void setByteArray(String key, byte[] value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_BYTEARRAY, key, value);
saveCompound();
}
/**
@@ -230,6 +246,7 @@ public class NBTCompound {
*/
public void setIntArray(String key, int[] value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_INTARRAY, key, value);
saveCompound();
}
/**
@@ -250,10 +267,12 @@ public class NBTCompound {
*/
public void setBoolean(String key, Boolean value) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_BOOLEAN, key, value);
saveCompound();
}
protected void set(String key, Object val) {
NBTReflectionUtil.set(this, key, val);
saveCompound();
}
/**
@@ -274,6 +293,7 @@ public class NBTCompound {
*/
public void setObject(String key, Object value) {
NBTReflectionUtil.setObject(this, key, value);
saveCompound();
}
/**
@@ -286,6 +306,28 @@ public class NBTCompound {
public <T> T getObject(String key, Class<T> type) {
return NBTReflectionUtil.getObject(this, key, type);
}
/**
* Save an ItemStack as a compound under a given key
*
* @param key
* @param item
*/
public void setItemStack(String key, ItemStack item){
removeKey(key);
addCompound(key).mergeCompound(NBTItem.convertItemtoNBT(item));
}
/**
* Get an ItemStack that was saved at the given key
*
* @param key
* @return
*/
public ItemStack getItemStack(String key){
NBTCompound comp = getCompound(key);
return NBTItem.convertNBTtoItem(comp);
}
/**
* @param key
@@ -303,6 +345,7 @@ public class NBTCompound {
*/
public void removeKey(String key) {
NBTReflectionUtil.remove(this, key);
saveCompound();
}
/**
@@ -325,6 +368,7 @@ public class NBTCompound {
NBTCompound comp = getCompound(name);
if(comp == null)
throw new NbtApiException("Error while adding Compound, got null!");
saveCompound();
return comp;
}
@@ -346,7 +390,9 @@ public class NBTCompound {
* @return The retrieved String List
*/
public NBTList<String> getStringList(String name) {
return NBTReflectionUtil.getList(this, name, NBTType.NBTTagString, String.class);
NBTList<String> list = NBTReflectionUtil.getList(this, name, NBTType.NBTTagString, String.class);
saveCompound();
return list;
}
/**
@@ -354,7 +400,9 @@ public class NBTCompound {
* @return The retrieved Integer List
*/
public NBTList<Integer> getIntegerList(String name) {
return NBTReflectionUtil.getList(this, name, NBTType.NBTTagInt, Integer.class);
NBTList<Integer> list = NBTReflectionUtil.getList(this, name, NBTType.NBTTagInt, Integer.class);
saveCompound();
return list;
}
/**
@@ -362,7 +410,9 @@ public class NBTCompound {
* @return The retrieved Compound List
*/
public NBTCompoundList getCompoundList(String name) {
return (NBTCompoundList) NBTReflectionUtil.getList(this, name, NBTType.NBTTagCompound, NBTListCompound.class);
NBTCompoundList list = (NBTCompoundList) NBTReflectionUtil.getList(this, name, NBTType.NBTTagCompound, NBTListCompound.class);
saveCompound();
return list;
}
/**
@@ -380,19 +430,22 @@ public class NBTCompound {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
/*StringBuilder result = new StringBuilder();
for (String key : getKeys()) {
result.append(toString(key));
}
return result.toString();
return result.toString();*/
return asNBTString();
}
/**
* @deprecated Just use toString()
* @param key
* @return A string representation of the given key
*/
@Deprecated
public String toString(String key) {
StringBuilder result = new StringBuilder();
/*StringBuilder result = new StringBuilder();
NBTCompound compound = this;
while (compound.getParent() != null) {
result.append(" ");
@@ -402,12 +455,15 @@ public class NBTCompound {
return this.getCompound(key).toString();
} else {
return result + "-" + key + ": " + getContent(key) + System.lineSeparator();
}
}*/
return asNBTString();
}
/**
* @deprecated Just use toString()
* @return A json valid nbt string for this Compound
*/
@Deprecated
public String asNBTString() {
Object comp = NBTReflectionUtil.gettoCompount(getCompound(), this);
if (comp == null)
@@ -24,6 +24,17 @@ public class NBTCompoundList extends NBTList<NBTListCompound> {
* @return The added {@link NBTListCompound}
*/
public NBTListCompound addCompound() {
return (NBTListCompound) addCompound(null);
}
/**
* Adds a copy of the Compound to the end of the List and returns it.
* When null is given, a new Compound will be created
*
* @param comp
* @return
*/
public NBTCompound addCompound(NBTCompound comp) {
try {
Object compound = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) {
@@ -31,7 +42,12 @@ public class NBTCompoundList extends NBTList<NBTListCompound> {
} else {
ReflectionMethod.LEGACY_LIST_ADD.run(listObject, compound);
}
return new NBTListCompound(this, compound);
getParent().saveCompound();
NBTListCompound listcomp = new NBTListCompound(this, compound);
if(comp != null){
listcomp.mergeCompound(comp);
}
return listcomp;
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@@ -40,25 +56,15 @@ public class NBTCompoundList extends NBTList<NBTListCompound> {
/**
* Adds a new Compound to the end of the List.
*
* @param empty This has to be null!
*
* @deprecated Please use addCompound!
* @param empty
* @return True, if compound was added
*/
@Override
@Deprecated
public boolean add(NBTListCompound empty) {
if (empty != null) {
throw new NotImplementedException("You need to pass null! ListCompounds from other lists won't work.");
}
try {
Object compound = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) {
ReflectionMethod.LIST_ADD.run(listObject, 0, compound);
} else {
ReflectionMethod.LEGACY_LIST_ADD.run(listObject, compound);
}
return true;
} catch (Exception ex) {
throw new NbtApiException(ex);
}
return addCompound(empty) != null;
}
@Override
@@ -73,6 +79,7 @@ public class NBTCompoundList extends NBTList<NBTListCompound> {
} else {
ReflectionMethod.LEGACY_LIST_ADD.run(listObject, compound);
}
super.getParent().saveCompound();
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@@ -1,5 +1,6 @@
package de.tr7zw.changeme.nbtapi;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
@@ -20,10 +21,12 @@ public class NBTIntegerList extends NBTList<Integer> {
@Override
protected Object asTag(Integer object) {
try {
return ClassWrapper.NMS_NBTTAGINT.getClazz().getConstructor(int.class).newInstance(object);
Constructor<?> con = ClassWrapper.NMS_NBTTAGINT.getClazz().getDeclaredConstructor(int.class);
con.setAccessible(true);
return con.newInstance(object);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw new NbtApiException("Error while wrapping the Oject " + object + " to it's NMS object!", e);
throw new NbtApiException("Error while wrapping the Object " + object + " to it's NMS object!", e);
}
}
@@ -31,6 +31,20 @@ public abstract class NBTList<T> implements List<T> {
this.type = type;
this.listObject = list;
}
/**
* @return Name of this list-compound
*/
public String getName(){
return listName;
}
/**
* @return The Compound's parent Object
*/
public NBTCompound getParent() {
return parent;
}
protected void save() {
parent.set(listName, listObject);
@@ -208,7 +222,7 @@ public abstract class NBTList<T> implements List<T> {
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index = 0;
private int index = -1;
@Override
public boolean hasNext() {
@@ -234,7 +248,7 @@ public abstract class NBTList<T> implements List<T> {
final NBTList<T> list = this;
return new ListIterator<T>() {
int index = startIndex;
int index = startIndex - 1;
@Override
public void add(T e) {
@@ -248,7 +262,7 @@ public abstract class NBTList<T> implements List<T> {
@Override
public boolean hasPrevious() {
return index > 0;
return index >= 0 && index <= size();
}
@Override
@@ -265,7 +279,9 @@ public abstract class NBTList<T> implements List<T> {
@Override
public T previous() {
return get(--index);
if (!hasPrevious())
throw new NoSuchElementException("Id: " + (index - 1));
return get(index--);
}
@Override
@@ -318,4 +334,10 @@ public abstract class NBTList<T> implements List<T> {
return list;
}
@Override
public String toString() {
return listObject.toString();
}
}
@@ -1,9 +1,5 @@
package de.tr7zw.changeme.nbtapi;
import java.util.Set;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
/**
* Cut down version of the {@link NBTCompound} for inside
* {@link NBTCompoundList} This Compound implementation is missing the ability
@@ -13,144 +9,34 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
* @author tr7zw
*
*/
public class NBTListCompound {
public class NBTListCompound extends NBTCompound {
private NBTList<?> owner;
private Object compound;
protected NBTListCompound(NBTList<?> parent, Object obj) {
super(null, null);
owner = parent;
compound = obj;
}
/**
* String setter
*
* @param key
* @param value
*/
public void setString(String key, String value) {
if (value == null) {
remove(key);
return;
}
try {
compound.getClass().getMethod("setString", String.class, String.class).invoke(compound, key, value);
owner.save();
} catch (Exception ex) {
throw new NbtApiException(ex);
}
public NBTList<?> getListParent() {
return owner;
}
/**
* int setter
*
* @param key
* @param value
*/
public void setInteger(String key, int value) {
try {
compound.getClass().getMethod("setInt", String.class, int.class).invoke(compound, key, value);
owner.save();
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@Override
public Object getCompound() {
return compound;
}
/**
* int getter
*
* @param value
* @return Saved value or NMS fallback
*/
public int getInteger(String value) {
try {
return (int) compound.getClass().getMethod("getInt", String.class).invoke(compound, value);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@Override
protected void setCompound(Object compound) {
this.compound = compound;
}
/**
* double setter
*
* @param key
* @param value
*/
public void setDouble(String key, double value) {
try {
compound.getClass().getMethod("setDouble", String.class, double.class).invoke(compound, key, value);
owner.save();
} catch (Exception ex) {
throw new NbtApiException(ex);
}
}
/**
* double getter
*
* @param key
* @return Saved value or NMS fallback
*/
public double getDouble(String key) {
try {
return (double) compound.getClass().getMethod("getDouble", String.class).invoke(compound, key);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
}
/**
* String getter
*
* @param key
* @return Saved value or NMS fallback
*/
public String getString(String key) {
try {
return (String) compound.getClass().getMethod("getString", String.class).invoke(compound, key);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
}
/**
* Checks for a given key
*
* @param key
* @return true if the Compound has this key, else false
*/
public boolean hasKey(String key) {
try {
return (boolean) compound.getClass().getMethod("hasKey", String.class).invoke(compound, key);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
}
/**
* @return Set containing all keys
*/
@SuppressWarnings("unchecked")
public Set<String> getKeys() {
try {
return (Set<String>) ReflectionMethod.LISTCOMPOUND_GET_KEYS.run(compound);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
}
/**
* Removes a key from the Compound
*
* @param key
*/
public void remove(String key) {
try {
compound.getClass().getMethod("remove", String.class).invoke(compound, key);
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@Override
protected void saveCompound() {
owner.save();
}
}
@@ -99,10 +99,11 @@ public class NBTReflectionUtil {
*/
public static Object convertNBTCompoundtoNMSItem(NBTCompound nbtcompound) {
try {
Object nmsComp = gettoCompount(nbtcompound.getCompound(), nbtcompound);
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_11_R1.getVersionId()) {
return ObjectCreator.NMS_COMPOUNDFROMITEM.getInstance(nbtcompound.getCompound());
return ObjectCreator.NMS_COMPOUNDFROMITEM.getInstance(nmsComp);
} else {
return ReflectionMethod.NMSITEM_CREATESTACK.run(null, nbtcompound.getCompound());
return ReflectionMethod.NMSITEM_CREATESTACK.run(null, nmsComp);
}
} catch (Exception e) {
throw new NbtApiException("Exception while converting NBTCompound to NMS ItemStack!", e);
@@ -1,5 +1,6 @@
package de.tr7zw.changeme.nbtapi;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
@@ -29,10 +30,12 @@ public class NBTStringList extends NBTList<String> {
@Override
protected Object asTag(String object) {
try {
return ClassWrapper.NMS_NBTTAGSTRING.getClazz().getConstructor(String.class).newInstance(object);
Constructor<?> con = ClassWrapper.NMS_NBTTAGSTRING.getClazz().getDeclaredConstructor(String.class);
con.setAccessible(true);
return con.newInstance(object);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw new NbtApiException("Error while wrapping the Oject " + object + " to it's NMS object!", e);
throw new NbtApiException("Error while wrapping the Object " + object + " to it's NMS object!", e);
}
}
@@ -1,377 +1,387 @@
package de.tr7zw.changeme.nbtapi.utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Timer;
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;
/**
* bStats collects some data for plugin authors.
* <p>
* Check out https://bStats.org/ to learn more about bStats!
*
* This class is modified by tr7zw to work when the api is shaded into other peoples plugins.
*/
public class ApiMetricsLite {
private static final String PLUGINNAME = "ItemNBTAPI"; // DO NOT CHANGE THE NAME! else it won't link the data on bStats
private static final String PLUGINVERSION = "2.0.0"; // In case you fork the nbt-api for internal use in your network, plugins and so on, you *may* add that to the version here. (2.x.x-Timolia or something like that?)
// Not sure how good of an idea that is, so maybe just leave it as is ¯\_(ツ)_/¯
// The version of this bStats class
public static final int B_STATS_VERSION = 1;
// The version of the NBT-Api bStats
public static final int NBT_BSTATS_VERSION = 1;
// The url to which the data is sent
private static final String URL = "https://bStats.org/submitData/bukkit";
// Is bStats enabled on this server?
private boolean enabled;
// Should failed requests be logged?
private static boolean logFailedRequests;
// Should the sent data be logged?
private static boolean logSentData;
// Should the response text be logged?
private static boolean logResponseStatusText;
// The uuid of the server
private static String serverUUID;
// The plugin
private Plugin plugin;
/**
* Class constructor.
*
*/
public ApiMetricsLite() {
// The register method just uses any enabled plugin it can find to register. This *shouldn't* cause any problems, since the plugin isn't used any other way.
// Register our service
for(Plugin plug : Bukkit.getPluginManager().getPlugins()) {
plugin = plug;
if(plugin != null)
break;
}
if(plugin == null) {
return;// Didn't find any plugin that could work
}
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
// Check if the config file exists
if (!config.isSet("serverUuid")) {
// Add default values
config.addDefault("enabled", true);
// Every server gets it's unique random id.
config.addDefault("serverUuid", UUID.randomUUID().toString());
// Should failed request be logged?
config.addDefault("logFailedRequests", false);
// Should the sent data be logged?
config.addDefault("logSentData", false);
// Should the response text be logged?
config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config.options().header(
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
"To honor their work, you should not disable it.\n" +
"This has nearly no effect on the server performance!\n" +
"Check out https://bStats.org/ to learn more :)"
).copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) { }
}
// Load the data
serverUUID = config.getString("serverUuid");
logFailedRequests = config.getBoolean("logFailedRequests", false);
enabled = config.getBoolean("enabled", true);
logSentData = config.getBoolean("logSentData", false);
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
if (enabled) {
boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("NBT_BSTATS_VERSION"); // Create only one instance of the nbt-api bstats.
return;
} catch (NoSuchFieldException ignored) { }
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
found = true; // We aren't the first
break;
} catch (NoSuchFieldException ignored) { }
}
// Register our service
Bukkit.getServicesManager().register(ApiMetricsLite.class, this, plugin, ServicePriority.Normal);
if (!found) {
logger.info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
// We are the first!
startSubmitting();
}
}
}
/**
* Checks if bStats is enabled.
*
* @return Whether bStats is enabled or not.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!plugin.isEnabled()) { // Plugin was disabled
timer.cancel();
return;
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, () -> submitData());
}
}, 1000l * 60l * 5l, 1000l * 60l * 30l);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
*
* @return The plugin specific data.
*/
public JsonObject getPluginData() {
JsonObject data = new JsonObject();
data.addProperty("pluginName", PLUGINNAME); // Append the name of the plugin
data.addProperty("pluginVersion", PLUGINVERSION); // Append the version of the plugin
data.add("customCharts", new JsonArray());
return data;
}
/**
* Gets the server specific data.
*
* @return The server specific data.
*/
private JsonObject getServerData() {
// Minecraft specific data
int playerAmount;
try {
// Around MC 1.8 the return type was changed to a collection from an array,
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
}
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
String bukkitVersion = Bukkit.getVersion();
String bukkitName = Bukkit.getName();
// OS/Java specific data
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject();
data.addProperty("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount);
data.addProperty("onlineMode", onlineMode);
data.addProperty("bukkitVersion", bukkitVersion);
data.addProperty("bukkitName", bukkitName);
data.addProperty("javaVersion", javaVersion);
data.addProperty("osName", osName);
data.addProperty("osArch", osArch);
data.addProperty("osVersion", osVersion);
data.addProperty("coreCount", coreCount);
return data;
}
/**
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JsonObject data = getServerData();
JsonArray pluginData = new JsonArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try {
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
if (plugin instanceof JsonObject) {
pluginData.add((JsonObject) plugin);
} else { // old bstats version compatibility
try {
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
jsonStringGetter.setAccessible(true);
String jsonString = (String) jsonStringGetter.invoke(plugin);
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
pluginData.add(object);
}
} catch (ClassNotFoundException e) {
// minecraft version 1.14+
if (logFailedRequests) {
logger.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);
}
continue; // continue looping since we cannot do any other thing.
}
}
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
}
}
} catch (NoSuchFieldException ignored) { }
}
data.add("plugins", pluginData);
// Create a new thread for the connection to the bStats server
new Thread(new Runnable() {
@Override
public void run() {
try {
// Send the data
sendData(plugin, data);
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
logger.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);
}
}
}
}).start();
}
/**
* Sends the data to the bStats server.
*
* @param plugin Any plugin. It's just used to get a logger instance.
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(Plugin plugin, JsonObject data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null!");
}
if (Bukkit.isPrimaryThread()) {
throw new IllegalAccessException("This method must not be called from the main thread!");
}
if (logSentData) {
System.out.println("[NBTAPI][BSTATS] Sending data to bStats: " + data.toString());
// Not using the plugins logger since the plugin isn't the plugin containing the NBT-Api most of the time
//plugin.getLogger().info("Sending data to bStats: " + data.toString());
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
// Add headers
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
// Send data
connection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
bufferedReader.close();
if (logResponseStatusText) {
logger.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());
}
}
/**
* Gzips the given String.
*
* @param str The string to gzip.
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return new byte[0];
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
return outputStream.toByteArray();
}
}
package de.tr7zw.changeme.nbtapi.utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Timer;
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;
/**
* bStats collects some data for plugin authors.
* <p>
* Check out https://bStats.org/ to learn more about bStats!
*
* This class is modified by tr7zw to work when the api is shaded into other peoples plugins.
*/
public class ApiMetricsLite {
private static final String PLUGINNAME = "ItemNBTAPI"; // DO NOT CHANGE THE NAME! else it won't link the data on bStats
// The version of this bStats class
public static final int B_STATS_VERSION = 1;
// The version of the NBT-Api bStats
public static final int NBT_BSTATS_VERSION = 1;
// The url to which the data is sent
private static final String URL = "https://bStats.org/submitData/bukkit";
// Is bStats enabled on this server?
private boolean enabled;
// Should failed requests be logged?
private static boolean logFailedRequests;
// Should the sent data be logged?
private static boolean logSentData;
// Should the response text be logged?
private static boolean logResponseStatusText;
// The uuid of the server
private static String serverUUID;
// The plugin
private Plugin plugin;
/**
* Class constructor.
*
*/
public ApiMetricsLite() {
// The register method just uses any enabled plugin it can find to register. This *shouldn't* cause any problems, since the plugin isn't used any other way.
// Register our service
for(Plugin plug : Bukkit.getPluginManager().getPlugins()) {
plugin = plug;
if(plugin != null)
break;
}
if(plugin == null) {
return;// Didn't find any plugin that could work
}
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
// Check if the config file exists
if (!config.isSet("serverUuid")) {
// Add default values
config.addDefault("enabled", true);
// Every server gets it's unique random id.
config.addDefault("serverUuid", UUID.randomUUID().toString());
// Should failed request be logged?
config.addDefault("logFailedRequests", false);
// Should the sent data be logged?
config.addDefault("logSentData", false);
// Should the response text be logged?
config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config.options().header(
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
"To honor their work, you should not disable it.\n" +
"This has nearly no effect on the server performance!\n" +
"Check out https://bStats.org/ to learn more :)"
).copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) { }
}
// Load the data
serverUUID = config.getString("serverUuid");
logFailedRequests = config.getBoolean("logFailedRequests", false);
enabled = config.getBoolean("enabled", true);
logSentData = config.getBoolean("logSentData", false);
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
if (enabled) {
boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("NBT_BSTATS_VERSION"); // Create only one instance of the nbt-api bstats.
return;
} catch (NoSuchFieldException ignored) { }
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
found = true; // We aren't the first
break;
} catch (NoSuchFieldException ignored) { }
}
boolean fFound = found;
// Register our service
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!");
// We are the first!
startSubmitting();
}
}else{
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!");
// We are the first!
startSubmitting();
}
});
}
}
}
/**
* Checks if bStats is enabled.
*
* @return Whether bStats is enabled or not.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!plugin.isEnabled()) { // Plugin was disabled
timer.cancel();
return;
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, () -> submitData());
}
}, 1000l * 60l * 5l, 1000l * 60l * 30l);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
*
* @return The plugin specific data.
*/
public JsonObject getPluginData() {
JsonObject data = new JsonObject();
data.addProperty("pluginName", PLUGINNAME); // Append the name of the plugin
data.addProperty("pluginVersion", MinecraftVersion.VERSION); // Append the version of the plugin
data.add("customCharts", new JsonArray());
return data;
}
/**
* Gets the server specific data.
*
* @return The server specific data.
*/
private JsonObject getServerData() {
// Minecraft specific data
int playerAmount;
try {
// Around MC 1.8 the return type was changed to a collection from an array,
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
}
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
String bukkitVersion = Bukkit.getVersion();
String bukkitName = Bukkit.getName();
// OS/Java specific data
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject();
data.addProperty("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount);
data.addProperty("onlineMode", onlineMode);
data.addProperty("bukkitVersion", bukkitVersion);
data.addProperty("bukkitName", bukkitName);
data.addProperty("javaVersion", javaVersion);
data.addProperty("osName", osName);
data.addProperty("osArch", osArch);
data.addProperty("osVersion", osVersion);
data.addProperty("coreCount", coreCount);
return data;
}
/**
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JsonObject data = getServerData();
JsonArray pluginData = new JsonArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try {
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
if (plugin instanceof JsonObject) {
pluginData.add((JsonObject) plugin);
} else { // old bstats version compatibility
try {
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
jsonStringGetter.setAccessible(true);
String jsonString = (String) jsonStringGetter.invoke(plugin);
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
pluginData.add(object);
}
} catch (ClassNotFoundException e) {
// minecraft version 1.14+
if (logFailedRequests) {
logger.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);
}
continue; // continue looping since we cannot do any other thing.
}
}
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
}
}
} catch (NoSuchFieldException ignored) { }
}
data.add("plugins", pluginData);
// Create a new thread for the connection to the bStats server
new Thread(new Runnable() {
@Override
public void run() {
try {
// Send the data
sendData(plugin, data);
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
logger.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);
}
}
}
}).start();
}
/**
* Sends the data to the bStats server.
*
* @param plugin Any plugin. It's just used to get a logger instance.
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(Plugin plugin, JsonObject data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null!");
}
if (Bukkit.isPrimaryThread()) {
throw new IllegalAccessException("This method must not be called from the main thread!");
}
if (logSentData) {
System.out.println("[NBTAPI][BSTATS] Sending data to bStats: " + data.toString());
// Not using the plugins logger since the plugin isn't the plugin containing the NBT-Api most of the time
//plugin.getLogger().info("Sending data to bStats: " + data.toString());
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
// Add headers
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
// Send data
connection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
bufferedReader.close();
if (logResponseStatusText) {
logger.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());
}
}
/**
* Gzips the given String.
*
* @param str The string to gzip.
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return new byte[0];
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
return outputStream.toByteArray();
}
}
@@ -25,16 +25,21 @@ public enum MinecraftVersion {
MC1_12_R1(1121),
MC1_13_R1(1131),
MC1_13_R2(1132),
MC1_14_R1(1141);
MC1_14_R1(1141),
MC1_15_R1(1151);
private static MinecraftVersion version;
private static Boolean hasGsonSupport;
private static boolean bStatsDisabled = false;
private static boolean disablePackageWarning = false;
private static boolean updateCheckDisabled = false;
/**
* Logger used by the api
*/
public static final Logger logger = Logger.getLogger("NBTAPI");
// NBT-API Version
protected static final String VERSION = "2.2.0";
private final int versionId;
@@ -82,6 +87,12 @@ public enum MinecraftVersion {
} catch (Exception ex) {
logger.log(Level.WARNING, "[NBTAPI] Error enabeling Metrics!", ex);
}
try {
if(!updateCheckDisabled)
VersionChecker.checkForUpdates();
} catch (Exception ex) {
logger.log(Level.WARNING, "[NBTAPI] Error while checking for updates!", ex);
}
// Maven's Relocate is clever and changes strings, too. So we have to use this
// little "trick" ... :D (from bStats)
final String defaultPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'c', 'h',
@@ -126,6 +137,14 @@ public enum MinecraftVersion {
public static void disableBStats() {
bStatsDisabled = true;
}
/**
* Disables the update check. Uses Spiget to get the current version and
* prints a warning when outdated.
*/
public static void disableUpdateCheck() {
updateCheckDisabled = true;
}
/**
* Forcefully disables the log message for plugins not shading the API to
@@ -0,0 +1,53 @@
package de.tr7zw.changeme.nbtapi.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import de.tr7zw.changeme.nbtapi.NbtApiException;
public final class ReflectionUtil {
private static Field field_modifiers;
static {
try {
field_modifiers = Field.class.getDeclaredField("modifiers");
field_modifiers.setAccessible(true);
} catch (NoSuchFieldException ex) {
try {
// This hacky workaround is for newer jdk versions 11+?
Method fieldGetter = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
fieldGetter.setAccessible(true);
Field[] fields = (Field[]) fieldGetter.invoke(Field.class, false);
for (Field f : fields)
if (f.getName().equals("modifiers")) {
field_modifiers = f;
field_modifiers.setAccessible(true);
break;
}
} catch (Exception e) {
throw new NbtApiException(e);
}
}
if (field_modifiers == null) {
throw new NbtApiException("Unable to init the modifiers Field.");
}
}
public static Field makeNonFinal(Field field) throws IllegalArgumentException, IllegalAccessException {
int mods = field.getModifiers();
if (Modifier.isFinal(mods)) {
field_modifiers.set(field, mods & ~Modifier.FINAL);
}
return field;
}
public static void setFinal(Object obj, Field field, Object newValue)
throws IllegalArgumentException, IllegalAccessException {
field.setAccessible(true);
field = makeNonFinal(field);
field.set(obj, newValue);
}
}
@@ -0,0 +1,106 @@
package de.tr7zw.changeme.nbtapi.utils;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.tr7zw.changeme.nbtapi.NBTItem;
/**
* This class uses the Spiget API to check for updates
*
*/
public class VersionChecker {
private static final String USER_AGENT = "nbt-api Version check";
private static final String REQUEST_URL = "https://api.spiget.org/v2/resources/7939/versions?size=100";
protected static void checkForUpdates() throws Exception {
URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("User-Agent", USER_AGENT);// Set
// User-Agent
// If you're not sure if the request will be successful,
// you need to check the response code and use #getErrorStream if it
// returned an error code
InputStream inputStream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
// This could be either a JsonArray or JsonObject
JsonElement element = new JsonParser().parse(reader);
if (element.isJsonArray()) {
// Is JsonArray
JsonArray updates = (JsonArray) element;
JsonObject latest = (JsonObject) updates.get(updates.size() - 1);
int versionDifference = getVersionDifference(latest.get("name").getAsString());
if (versionDifference == -1) { // Outdated
MinecraftVersion.logger.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
+ "' Newest Version: " + latest.get("name").getAsString() + "'");
MinecraftVersion.logger.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!");
} 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
+ "' Newest Version: " + latest.get("name").getAsString() + "'");
}
} else {
// wut?!
MinecraftVersion.logger.log(Level.WARNING,
"[NBTAPI] Error when looking for Updates! Got non Json Array: '" + element.toString() + "'");
}
}
// -1 = we are outdated
// 0 = up to date
// 1 = using a future version
// This method is only able to compare the Format 0.0.0(-SNAPSHOT)
private static int getVersionDifference(String version) {
String current = MinecraftVersion.VERSION;
if (current.equals(version))
return 0;
String pattern = "\\.";
if (current.split(pattern).length != 3 || version.split(pattern).length != 3)
return -1;
int curMaj = Integer.parseInt(current.split(pattern)[0]);
int curMin = Integer.parseInt(current.split(pattern)[1]);
String curPatch = current.split(pattern)[2];
int relMaj = Integer.parseInt(version.split(pattern)[0]);
int relMin = Integer.parseInt(version.split(pattern)[1]);
String relPatch = version.split(pattern)[2];
if (curMaj < relMaj)
return -1;
if (curMaj > relMaj)
return 1;
if (curMin < relMin)
return -1;
if (curMin > relMin)
return 1;
int curPatchN = Integer.parseInt(curPatch.split("-")[0]);
int relPatchN = Integer.parseInt(relPatch.split("-")[0]);
if (curPatchN < relPatchN)
return -1;
if (curPatchN > relPatchN)
return 1;
if (!relPatch.contains("-") && curPatch.contains("-"))
return -1; // Release has no - but we do = We use a Snapshot of the
// release
if (relPatch.contains("-") && curPatch.contains("-"))
return 0; // Release and cur are Snapshots/alpha/beta
return 1;
}
}
@@ -1,183 +1,182 @@
package de.tr7zw.changeme.nbtapi.utils.nmsmappings;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.logging.Level;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger;
/**
* This class caches method reflections, keeps track of method name changes between versions and allows early checking for problems
*
* @author tr7zw
*
*/
@SuppressWarnings("javadoc")
public enum ReflectionMethod {
COMPOUND_SET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, float.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setFloat")),
COMPOUND_SET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setString")),
COMPOUND_SET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setInt")),
COMPOUND_SET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByteArray")),
COMPOUND_SET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setIntArray")),
COMPOUND_SET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, long.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setLong")),
COMPOUND_SET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, short.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setShort")),
COMPOUND_SET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByte")),
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_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_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_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")),
COMPOUND_GET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getInt")),
COMPOUND_GET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByteArray")),
COMPOUND_GET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getIntArray")),
COMPOUND_GET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getLong")),
COMPOUND_GET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getShort")),
COMPOUND_GET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByte")),
COMPOUND_GET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getDouble")),
COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getBoolean")),
COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getCompound")),
NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTag")),
NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "save")),
NMSITEM_CREATESTACK(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_10_R1, new Since(MinecraftVersion.MC1_7_R4, "createStack")),
COMPOUND_REMOVE_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "remove")),
COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "hasKey")),
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d")), //FIXME: No Spigot mapping!
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_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")),
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")),
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")),
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(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_12_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(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")),
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")), //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_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")),
REGISTRY_SET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class, Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "a")), //FIXME: No Spigot mapping!
REGISTRY_GET_INVERSE (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "b")), //FIXME: No Spigot mapping!
REGISTRYMATERIALS_KEYSET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "keySet")),
REGISTRYMATERIALS_GET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTKEY.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "get")),
;
private MinecraftVersion removedAfter;
private Since targetVersion;
private Method method;
private boolean loaded = false;
private boolean compatible = false;
private String methodName = null;
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;
compatible = true;
Since target = methodnames[0];
for(Since s : methodnames){
if(s.version.getVersionId() <= server.getVersionId() && target.version.getVersionId() < s.version.getVersionId())
target = s;
}
targetVersion = target;
try{
method = targetClass.getMethod(targetVersion.name, args);
method.setAccessible(true);
loaded = true;
methodName = targetVersion.name;
}catch(NullPointerException | NoSuchMethodException | SecurityException ex){
logger.log(Level.SEVERE, "Unable to find the method '" + targetVersion.name + "' in '" + targetClass.getSimpleName() + "'", ex);
}
}
ReflectionMethod(Class<?> targetClass, Class<?>[] args, MinecraftVersion addedSince, Since... methodnames){
this(targetClass, args, addedSince, null, methodnames);
}
/**
* Runs the method on a given target object using the given args.
*
* @param target
* @param args
* @return Value returned by the method
*/
public Object run(Object target, Object... args){
try{
return method.invoke(target, args);
}catch(Exception ex){
throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded + ".", ex);
}
}
/**
* @return The MethodName, used in this Minecraft Version
*/
public String getMethodName() {
return methodName;
}
/**
* @return Has this method been linked
*/
public boolean isLoaded() {
return loaded;
}
/**
* @return Is this method available in this Minecraft Version
*/
public boolean isCompatible() {
return compatible;
}
protected static class Since{
public final MinecraftVersion version;
public final String name;
public Since(MinecraftVersion version, String name) {
this.version = version;
this.name = name;
}
}
}
package de.tr7zw.changeme.nbtapi.utils.nmsmappings;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
/**
* This class caches method reflections, keeps track of method name changes between versions and allows early checking for problems
*
* @author tr7zw
*
*/
@SuppressWarnings("javadoc")
public enum ReflectionMethod {
COMPOUND_SET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, float.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setFloat")),
COMPOUND_SET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setString")),
COMPOUND_SET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setInt")),
COMPOUND_SET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByteArray")),
COMPOUND_SET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setIntArray")),
COMPOUND_SET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, long.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setLong")),
COMPOUND_SET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, short.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setShort")),
COMPOUND_SET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByte")),
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_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_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_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")),
COMPOUND_GET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getInt")),
COMPOUND_GET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByteArray")),
COMPOUND_GET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getIntArray")),
COMPOUND_GET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getLong")),
COMPOUND_GET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getShort")),
COMPOUND_GET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByte")),
COMPOUND_GET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getDouble")),
COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getBoolean")),
COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getCompound")),
NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTag")),
NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "save")),
NMSITEM_CREATESTACK(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_10_R1, new Since(MinecraftVersion.MC1_7_R4, "createStack")),
COMPOUND_REMOVE_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "remove")),
COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "hasKey")),
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d"), new Since(MinecraftVersion.MC1_15_R1, "e")), //FIXME: No Spigot mapping!
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_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")),
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")),
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")),
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(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_12_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(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")),
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")), //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_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")),
REGISTRY_SET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class, Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "a")), //FIXME: No Spigot mapping!
REGISTRY_GET_INVERSE (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "b")), //FIXME: No Spigot mapping!
REGISTRYMATERIALS_KEYSET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "keySet")),
REGISTRYMATERIALS_GET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTKEY.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "get")),
;
private MinecraftVersion removedAfter;
private Since targetVersion;
private Method method;
private boolean loaded = false;
private boolean compatible = false;
private String methodName = null;
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;
compatible = true;
Since target = methodnames[0];
for(Since s : methodnames){
if(s.version.getVersionId() <= server.getVersionId() && target.version.getVersionId() < s.version.getVersionId())
target = s;
}
targetVersion = target;
try{
method = targetClass.getMethod(targetVersion.name, args);
method.setAccessible(true);
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
}
}
ReflectionMethod(Class<?> targetClass, Class<?>[] args, MinecraftVersion addedSince, Since... methodnames){
this(targetClass, args, addedSince, null, methodnames);
}
/**
* Runs the method on a given target object using the given args.
*
* @param target
* @param args
* @return Value returned by the method
*/
public Object run(Object target, Object... args){
if(method == null)
throw new NbtApiException("Method not loaded! '" + this + "'");
try{
return method.invoke(target, args);
}catch(Exception ex){
throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded + ", Enum: " + this, ex);
}
}
/**
* @return The MethodName, used in this Minecraft Version
*/
public String getMethodName() {
return methodName;
}
/**
* @return Has this method been linked
*/
public boolean isLoaded() {
return loaded;
}
/**
* @return Is this method available in this Minecraft Version
*/
public boolean isCompatible() {
return compatible;
}
protected static class Since{
public final MinecraftVersion version;
public final String name;
public Since(MinecraftVersion version, String name) {
this.version = version;
this.name = name;
}
}
}
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
</parent>
<artifactId>item-nbt-api-plugin</artifactId>
<packaging>jar</packaging>
@@ -12,13 +12,13 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>nbt-injector</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -73,11 +73,11 @@
</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.1,1.14.2,1.14.3 -->
<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.1,1.14.2,1.14.3</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 -->
<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</versions>
<works>Success! This version of NBT-API</works>
<error>WARNING! This version of NBT-API</error>
<filename>item-nbt-api-plugin-2.0.0.jar</filename>
<filename>item-nbt-api-plugin-${project.version}.jar</filename>
<foldername>item-nbt-plugin</foldername>
</configuration>
</plugin>
@@ -1,148 +1,155 @@
package de.tr7zw.nbtapi.plugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import org.bukkit.plugin.java.JavaPlugin;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
import de.tr7zw.nbtapi.plugin.tests.NBTFileTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.GetterSetterTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.ListTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.MergeTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.RemovingKeys;
import de.tr7zw.nbtapi.plugin.tests.compounds.SubCompoundsTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.TypeTest;
import de.tr7zw.nbtapi.plugin.tests.entities.EntityCustomNbtTest;
import de.tr7zw.nbtapi.plugin.tests.entities.EntityTest;
import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemConvertionTest;
import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTTest;
import de.tr7zw.nbtinjector.NBTInjector;
public class NBTAPI extends JavaPlugin {
private boolean compatible = true;
private ArrayList<de.tr7zw.nbtapi.plugin.tests.Test> apiTests = new ArrayList<>();
private static NBTAPI instance;
public static NBTAPI getInstance() {
return instance;
}
@Override
public void 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;
}
// NBTCompounds
apiTests.add(new GetterSetterTest());
apiTests.add(new TypeTest());
apiTests.add(new RemovingKeys());
apiTests.add(new ListTest());
apiTests.add(new SubCompoundsTest());
apiTests.add(new MergeTest());
// Items
apiTests.add(new ItemConvertionTest());
apiTests.add(new EmptyItemTest());
// Entity
apiTests.add(new EntityTest());
apiTests.add(new EntityCustomNbtTest());
// Tiles
apiTests.add(new TilesCustomNBTTest());
// Files
apiTests.add(new NBTFileTest());
}
@Override
public void onEnable() {
instance = this; // NOSONAR
// new MetricsLite(this); The metrics moved into the API
getLogger().info("Checking bindings...");
MinecraftVersion.getVersion();
getLogger().info("Gson:");
MinecraftVersion.hasGsonSupport();
getLogger().info("Classes:");
boolean classUnlinked = false;
for (ClassWrapper c : ClassWrapper.values()) {
if (c.isEnabled() && c.getClazz() == null) {
getLogger().warning(c.name() + " did not find it's class!");
compatible = false;
classUnlinked = true;
}
}
if (!classUnlinked)
getLogger().info("All Classes where able to link!");
getLogger().info("Methods:");
boolean methodUnlinked = false;
for (ReflectionMethod method : ReflectionMethod.values()) {
if (method.isCompatible() && !method.isLoaded()) {
getLogger().warning(method.name() + " did not find the method!");
compatible = false;
methodUnlinked = true;
}
}
if (!methodUnlinked)
getLogger().info("All Methods where able to link!");
getLogger().info("Running NBT reflection test...");
Map<de.tr7zw.nbtapi.plugin.tests.Test, Exception> results = new HashMap<>();
for (de.tr7zw.nbtapi.plugin.tests.Test test : apiTests) {
try {
test.test();
results.put(test, null);
} catch (Exception ex) {
results.put(test, ex);
getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex);
} catch (Throwable th) { // NOSONAR
getLogger().log(Level.SEVERE, "Servere error during '" + test.getClass().getSimpleName() + "' test!");
getLogger().warning(
"WARNING! This version of Item-NBT-API seems to be broken with your Spigot version! Canceled the other tests!");
throw th;
}
}
for (Entry<de.tr7zw.nbtapi.plugin.tests.Test, Exception> entry : results.entrySet()) {
if (entry.getValue() != null)
compatible = false;
getLogger().info(entry.getKey().getClass().getSimpleName() + ": "
+ (entry.getValue() == null ? "Ok" : entry.getValue().getMessage()));
}
String checkMessage = "Plugins that don't check properly may throw Exeptions, crash or have unexpected behaviors!";
if (compatible) {
getLogger().info("Success! This version of NBT-API is compatible with your server.");
} else {
getLogger().warning(
"WARNING! This version of NBT-API seems to be broken with your Spigot version! " + checkMessage);
}
}
/**
* @return True if all selfchecks succeeded
*/
public boolean isCompatible() {
return compatible;
}
}
package de.tr7zw.nbtapi.plugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
import de.tr7zw.nbtapi.plugin.tests.NBTFileTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.ForEachTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.GetterSetterTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.ListTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.MergeTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.RemovingKeys;
import de.tr7zw.nbtapi.plugin.tests.compounds.SubCompoundsTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.TypeTest;
import de.tr7zw.nbtapi.plugin.tests.entities.EntityCustomNbtTest;
import de.tr7zw.nbtapi.plugin.tests.entities.EntityTest;
import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemConvertionTest;
import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTTest;
import de.tr7zw.nbtinjector.NBTInjector;
public class NBTAPI extends JavaPlugin {
private boolean compatible = true;
private ArrayList<de.tr7zw.nbtapi.plugin.tests.Test> apiTests = new ArrayList<>();
private static NBTAPI instance;
public static NBTAPI getInstance() {
return instance;
}
@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;
}*/
// NBTCompounds
apiTests.add(new GetterSetterTest());
apiTests.add(new TypeTest());
apiTests.add(new RemovingKeys());
apiTests.add(new ListTest());
apiTests.add(new SubCompoundsTest());
apiTests.add(new MergeTest());
apiTests.add(new ForEachTest());
// Items
apiTests.add(new ItemConvertionTest());
apiTests.add(new EmptyItemTest());
// Entity
apiTests.add(new EntityTest());
apiTests.add(new EntityCustomNbtTest());
// Tiles
apiTests.add(new TilesCustomNBTTest());
// Files
apiTests.add(new NBTFileTest());
}
@Override
public void onEnable() {
instance = this; // NOSONAR
// new MetricsLite(this); The metrics moved into the API
getLogger().info("Adding listeners...");
Bukkit.getPluginManager().registerEvents(new ReloadListener(), this);
getLogger().info("Checking bindings...");
MinecraftVersion.getVersion();
getLogger().info("Gson:");
MinecraftVersion.hasGsonSupport();
getLogger().info("Classes:");
boolean classUnlinked = false;
for (ClassWrapper c : ClassWrapper.values()) {
if (c.isEnabled() && c.getClazz() == null) {
getLogger().warning(c.name() + " did not find it's class!");
compatible = false;
classUnlinked = true;
}
}
if (!classUnlinked)
getLogger().info("All Classes where able to link!");
getLogger().info("Methods:");
boolean methodUnlinked = false;
for (ReflectionMethod method : ReflectionMethod.values()) {
if (method.isCompatible() && !method.isLoaded()) {
getLogger().warning(method.name() + " did not find the method!");
compatible = false;
methodUnlinked = true;
}
}
if (!methodUnlinked)
getLogger().info("All Methods where able to link!");
getLogger().info("Running NBT reflection test...");
Map<de.tr7zw.nbtapi.plugin.tests.Test, Exception> results = new HashMap<>();
for (de.tr7zw.nbtapi.plugin.tests.Test test : apiTests) {
try {
test.test();
results.put(test, null);
} catch (Exception ex) {
results.put(test, ex);
getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex);
} catch (Throwable th) { // NOSONAR
getLogger().log(Level.SEVERE, "Servere error during '" + test.getClass().getSimpleName() + "' test!");
getLogger().warning(
"WARNING! This version of Item-NBT-API seems to be broken with your Spigot version! Canceled the other tests!");
throw th;
}
}
for (Entry<de.tr7zw.nbtapi.plugin.tests.Test, Exception> entry : results.entrySet()) {
if (entry.getValue() != null)
compatible = false;
getLogger().info(entry.getKey().getClass().getSimpleName() + ": "
+ (entry.getValue() == null ? "Ok" : entry.getValue().getMessage()));
}
String checkMessage = "Plugins that don't check properly may throw Exeptions, crash or have unexpected behaviors!";
if (compatible) {
getLogger().info("Success! This version of NBT-API is compatible with your server.");
} else {
getLogger().warning(
"WARNING! This version of NBT-API seems to be broken with your Spigot version! " + checkMessage);
}
}
/**
* @return True if all selfchecks succeeded
*/
public boolean isCompatible() {
return compatible;
}
}
@@ -0,0 +1,42 @@
package de.tr7zw.nbtapi.plugin;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import de.tr7zw.nbtinjector.NBTInjector;
/**
* This listener class tries to prevent people from reloading while the NBTInjector is enabled.
*
* @author tr7zw
*
*/
public class ReloadListener implements Listener{
/**
* Console handler
*
* @param event
*/
@EventHandler
public void onCommand(org.bukkit.event.server.ServerCommandEvent event) {
if(event.getCommand().toLowerCase().startsWith("reload") && NBTInjector.isInjected()) {
event.setCancelled(true);
event.getSender().sendMessage("[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!");
}
}
/**
* Player handler
*
* @param event
*/
@EventHandler
public void onCommand(org.bukkit.event.player.PlayerCommandPreprocessEvent event) {
if(event.getMessage().toLowerCase().startsWith("/reload") && NBTInjector.isInjected()) {
event.setCancelled(true);
event.getPlayer().sendMessage("[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!");
}
}
}
@@ -0,0 +1,50 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import java.util.ListIterator;
import de.tr7zw.changeme.nbtapi.NBTCompoundList;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTListCompound;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
/**
* Test requested by TAU on Discord
*
*/
public class ForEachTest implements Test {
@SuppressWarnings("unused")
@Override
public void test() throws Exception {
NBTContainer comp = new NBTContainer();
NBTCompoundList compList = comp.getCompoundList("testkey");
if (compList != null) {
compList.addCompound().setInteger("id", 1);
compList.addCompound().setInteger("id", 2);
compList.addCompound().setInteger("id", 3);
int count = 0;
for (NBTListCompound listComp : compList) {
count++;
}
if(count != compList.size())
throw new NbtApiException("For loop did not get all Entries!");
count = 0;
ListIterator<NBTListCompound> lit = compList.listIterator();
while(lit.hasNext()){
lit.next();
count++;
}
if(count != compList.size())
throw new NbtApiException("ListIterator did not get all Entries!");
count = 0;
while(lit.hasPrevious()){
lit.previous();
count++;
}
if(count != compList.size())
throw new NbtApiException("ListIterator previous did not get all Entries!");
}
}
}
@@ -2,10 +2,12 @@ package de.tr7zw.nbtapi.plugin.tests.compounds;
import java.util.Arrays;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTCompoundList;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTList;
import de.tr7zw.changeme.nbtapi.NBTListCompound;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
@@ -34,19 +36,30 @@ public class ListTest implements Test {
lcomp.setInteger("int1", 42);
lcomp.setString("test1", "test1");
lcomp.setString("test2", "test2");
lcomp.remove("test1");
lcomp.removeKey("test1");
NBTCompound subsubcomp = lcomp.addCompound("listsubkey");
subsubcomp.setString("deep", "String");
subsubcomp.getCompoundList("deeplist").addCompound().setString("test", "test");
subsubcomp.getCompoundList("clonelist").addCompound(comp);
taglist = null;
lcomp = null;
subsubcomp = null;
taglist = comp.getCompoundList("complist");
if (taglist.size() == 1) {
lcomp = taglist.get(0);
if (lcomp.getKeys().size() != 3) {
if (lcomp.getKeys().size() != 4) {
throw new NbtApiException("Wrong key amount in Taglist (" + lcomp.getKeys().size() + ")!");
} else if (!(lcomp.getDouble("double1") == 0.3333 && lcomp.getInteger("int1") == 42
&& lcomp.getString("test2").equals("test2") && !lcomp.hasKey("test1"))) {
throw new NbtApiException("One key in the Taglist changed! The Item-NBT-API may not work!");
} else if(lcomp.getCompound("listsubkey") == null || !"String".equals(lcomp.getCompound("listsubkey").getString("deep"))){
throw new NbtApiException("The Compound nested in the listcompound was not correct! The Item-NBT-API may not work!");
} else if(lcomp.getCompound("listsubkey").getType("deep") != NBTType.NBTTagString){
throw new NbtApiException("The nested key's type wasn't correct! The Item-NBT-API may not work!");
} else if(lcomp.getCompound("listsubkey").getType("deeplist") != NBTType.NBTTagList){
throw new NbtApiException("The nested list's type wasn't correct '" + lcomp.getCompound("listsubkey").getType("deeplist") + "'! The Item-NBT-API may not work!");
}
} else {
throw new NbtApiException("Taglist is empty! The Item-NBT-API may not work!");
@@ -1,40 +1,41 @@
package de.tr7zw.nbtapi.plugin.tests.entities;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Monster;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
import de.tr7zw.nbtinjector.NBTInjector;
public class EntityCustomNbtTest implements Test {
@Override
public void test() throws Exception {
if (!Bukkit.getWorlds().isEmpty()) {
World world = Bukkit.getWorlds().get(0);
try {
if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) {
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
ent = NBTInjector.patchEntity(ent);
NBTCompound comp = NBTInjector.getNbtData(ent);
comp.setString("Hello", "World");
NBTEntity nbtent = new NBTEntity(ent);
if (!nbtent.asNBTString().contains("__extraData:{Hello:\"World\"}")) {
throw new NbtApiException("Custom Data did not save to the Entity!");
}
comp.removeKey("Hello");
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTEntities!", ex);
}
}
}
}
package de.tr7zw.nbtapi.plugin.tests.entities;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Monster;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
import de.tr7zw.nbtinjector.NBTInjector;
public class EntityCustomNbtTest implements Test {
@Override
public void test() throws Exception {
if(!NBTInjector.isInjected())return;
if (!Bukkit.getWorlds().isEmpty()) {
World world = Bukkit.getWorlds().get(0);
try {
if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) {
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
ent = NBTInjector.patchEntity(ent);
NBTCompound comp = NBTInjector.getNbtData(ent);
comp.setString("Hello", "World");
NBTEntity nbtent = new NBTEntity(ent);
if (!nbtent.asNBTString().contains("__extraData:{Hello:\"World\"}")) {
throw new NbtApiException("Custom Data did not save to the Entity!");
}
comp.removeKey("Hello");
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTEntities!", ex);
}
}
}
}
@@ -25,6 +25,11 @@ public class ItemConvertionTest implements Test {
ItemStack rebuild = NBTItem.convertNBTtoItem(new NBTContainer(nbt));
if (!item.isSimilar(rebuild))
throw new NbtApiException("Rebuilt item did not match the original!");
NBTContainer cont = new NBTContainer();
cont.setItemStack("testItem", item);
if(!cont.getItemStack("testItem").isSimilar(item))
throw new NbtApiException("Rebuilt item did not match the original!");
}
}
@@ -1,39 +1,40 @@
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.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
import de.tr7zw.nbtinjector.NBTInjector;
public class TilesCustomNBTTest 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);
NBTCompound comp = NBTInjector.getNbtData(block.getState());
comp.setString("Foo", "Bar");
if (!new NBTTileEntity(block.getState()).asNBTString().contains("__extraData:{Foo:\"Bar\"}")) {
block.setType(Material.AIR);
throw new NbtApiException("Custom Data did not save to the Tile!");
}
block.setType(Material.AIR);
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
}
}
}
}
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.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
import de.tr7zw.nbtinjector.NBTInjector;
public class TilesCustomNBTTest implements Test {
@Override
public void test() throws Exception {
if(!NBTInjector.isInjected())return;
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);
NBTCompound comp = NBTInjector.getNbtData(block.getState());
comp.setString("Foo", "Bar");
if (!new NBTTileEntity(block.getState()).asNBTString().contains("__extraData:{Foo:\"Bar\"}")) {
block.setType(Material.AIR);
throw new NbtApiException("Custom Data did not save to the Tile!");
}
block.setType(Material.AIR);
}
} catch (Exception ex) {
throw new NbtApiException("Wasn't able to use NBTTiles!", ex);
}
}
}
}
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
</parent>
<artifactId>nbt-injector</artifactId>
<packaging>jar</packaging>
@@ -12,13 +12,13 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
<version>3.26.0-GA</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -1,277 +1,288 @@
package de.tr7zw.nbtinjector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
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;
/**
* Contains the internal methods for different Minecraft Versions of injecting
* the Entities/Tiles
*
* @author tr7zw
*
*/
@SuppressWarnings("unchecked")
public class InternalInjectors {
private static final List<String> skippingEntities = Arrays.asList("minecraft:player", "minecraft:fishing_bobber",
"minecraft:lightning_bolt"); // These are broken/won't work, used by 1.14+
private static final Map<String, String> classMappings = new HashMap<>();
static {
classMappings.put("minecraft:wandering_trader", "VillagerTrader");
classMappings.put("minecraft:trader_llama", "LlamaTrader");
classMappings.put("minecraft:area_effect_cloud", "AreaEffectCloud");
classMappings.put("minecraft:donkey", "HorseDonkey");
classMappings.put("minecraft:ender_dragon", "EnderDragon");
classMappings.put("minecraft:skeleton_horse", "HorseSkeleton");
classMappings.put("minecraft:fireball", "LargeFireball");
classMappings.put("minecraft:mule", "HorseMule");
classMappings.put("minecraft:zombie_horse", "HorseZombie");
classMappings.put("minecraft:mooshroom", "MushroomCow");
classMappings.put("minecraft:wither_skeleton", "SkeletonWither");
classMappings.put("minecraft:snow_golem", "Snowman");
classMappings.put("minecraft:polar_bear", "PolarBear");
classMappings.put("minecraft:magma_cube", "MagmaCube");
classMappings.put("minecraft:armor_stand", "ArmorStand");
classMappings.put("minecraft:elder_guardian", "GuardianElder");
classMappings.put("minecraft:zombie_pigman", "PigZombie");
classMappings.put("minecraft:giant", "GiantZombie");
classMappings.put("minecraft:zombie_villager", "ZombieVillager");
classMappings.put("minecraft:husk", "ZombieHusk");
classMappings.put("minecraft:iron_golem", "IronGolem");
classMappings.put("minecraft:tropical_fish", "TropicalFish");
classMappings.put("minecraft:stray", "SkeletonStray");
classMappings.put("minecraft:illusioner", "IllagerIllusioner");
classMappings.put("minecraft:pufferfish", "PufferFish");
classMappings.put("minecraft:cave_spider", "CaveSpider");
}
/**
* Hidden constructor
*/
private InternalInjectors() {
}
protected static void entity1v10Below(ClassPool classPool) throws ReflectiveOperationException {
for (Map.Entry<String, Class<?>> entry : new HashSet<>(Entity.getCMap().entrySet())) {
try {
if (INBTWrapper.class.isAssignableFrom(entry.getValue())) {
continue;
} // Already injected
int entityId = Entity.getFMap().get(entry.getValue());
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, entry.getValue(), "__extraData");
Entity.getCMap().put(entry.getKey(), wrapped);
Entity.getDMap().put(wrapped, entry.getKey());
Entity.getEMap().put(entityId, wrapped);
Entity.getFMap().put(wrapped, entityId);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + entry.getKey(), e);
}
}
}
protected static void entity1v12Below(ClassPool classPool) throws ReflectiveOperationException {
Object registry = Entity.getRegistry();
Map<Object, Object> inverse = new HashMap<>();
Set<?> it = new HashSet<>((Set<?>) ReflectionMethod.REGISTRY_KEYSET.run(registry));
for (Object mckey : it) {
Class<?> tileclass = (Class<?>) ReflectionMethod.REGISTRY_GET.run(registry, mckey);
inverse.put(tileclass, mckey);
try {
if (INBTWrapper.class.isAssignableFrom(tileclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, tileclass, "__extraData");
ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped);
inverse.put(wrapped, mckey);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
Field inverseField = registry.getClass().getDeclaredField("b");
NBTInjector.setFinal(registry, inverseField, inverse);
}
protected static void entity1v13Below(ClassPool classPool) throws ReflectiveOperationException {
Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry));
for (Object mckey : registryentries) {
Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey);
Field supplierField = entityTypesObj.getClass().getDeclaredField("aT");
Field classField = entityTypesObj.getClass().getDeclaredField("aS");
classField.setAccessible(true);
supplierField.setAccessible(true);
Function<Object, Object> function = (Function<Object, Object>) supplierField.get(entityTypesObj);
Class<?> nmsclass = (Class<?>) classField.get(entityTypesObj);
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData");
NBTInjector.setFinal(entityTypesObj, classField, wrapped);
NBTInjector.setFinal(entityTypesObj, supplierField, new Function<Object, Object>() {
@Override
public Object apply(Object t) {
try {
return wrapped.getConstructor(ClassWrapper.NMS_WORLD.getClazz()).newInstance(t);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error while creating custom entity instance! ", ex);
return function.apply(t);// Fallback to the original one
}
}
});
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
protected static void entity1v14(ClassPool classPool) throws ReflectiveOperationException {
Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry));
for (Object mckey : registryentries) {
if (skippingEntities.contains(mckey.toString())) {
logger.info("Skipping, won't be able add NBT to '" + mckey + "' entities!");
continue;
}
Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey);
Field creatorField = entityTypesObj.getClass().getDeclaredField("aZ");
creatorField.setAccessible(true);
Object creator = creatorField.get(entityTypesObj);
Method createEntityMethod = creator.getClass().getMethod("create", ClassWrapper.NMS_ENTITYTYPES.getClazz(),
ClassWrapper.NMS_WORLD.getClazz());
createEntityMethod.setAccessible(true);
Class<?> nmsclass = null;
try {
nmsclass = createEntityMethod.invoke(creator, entityTypesObj, null).getClass();
} catch (Exception ignore) {
// ignore
}
if (nmsclass == null) {
String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
String name = mckey.toString().replace("minecraft:", "");
name = name.substring(0, 1).toUpperCase() + name.substring(1);
name = "Entity" + name;
if (classMappings.containsKey(mckey.toString()))
name = "Entity" + classMappings.get(mckey.toString());
try {
nmsclass = Class.forName("net.minecraft.server." + version + "." + name);
} catch (Exception ignore) {
logger.info("Not found: " + "net.minecraft.server." + version + "." + name);
// ignore
}
}
if (nmsclass == null) {
logger.info(
"Wasn't able to create an Entity instace, won't be able add NBT to '" + mckey + "' entities!");
continue;
}
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData");
NBTInjector.setFinal(entityTypesObj, creatorField,
ClassGenerator.createEntityTypeWrapper(classPool, wrapped).newInstance());
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
protected static void tile1v10Below(ClassPool classPool) throws ReflectiveOperationException {
for (Map.Entry<String, Class<?>> entry : new HashSet<>(TileEntity.getFMap().entrySet())) {
try {
if (INBTWrapper.class.isAssignableFrom(entry.getValue())) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, entry.getValue(), "__extraData");
TileEntity.getFMap().put(entry.getKey(), wrapped);
TileEntity.getGMap().put(wrapped, entry.getKey());
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + entry.getKey(), e);
}
}
}
protected static void tile1v12Below(ClassPool classPool) throws ReflectiveOperationException {
Object registry = TileEntity.getRegistry();
Map<Object, Object> inverse = new HashMap<>();
Set<?> it = new HashSet<>((Set<?>) ReflectionMethod.REGISTRY_KEYSET.run(registry));
for (Object mckey : it) {
Class<?> tileclass = (Class<?>) ReflectionMethod.REGISTRY_GET.run(registry, mckey);
inverse.put(tileclass, mckey);
try {
if (INBTWrapper.class.isAssignableFrom(tileclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, tileclass, "__extraData");
ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped);
inverse.put(wrapped, mckey);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
Field inverseField = registry.getClass().getDeclaredField("b");
NBTInjector.setFinal(registry, inverseField, inverse);
}
protected static void tile1v13(ClassPool classPool) throws ReflectiveOperationException {
Object tileRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("BLOCK_ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(tileRegistry));
for (Object mckey : registryentries) {
Object tileEntityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(tileRegistry, mckey);
String supplierFieldName = "A";
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId())
supplierFieldName = "H";
Field supplierField = tileEntityTypesObj.getClass().getDeclaredField(supplierFieldName);
supplierField.setAccessible(true);
Supplier<Object> supplier = (Supplier<Object>) supplierField.get(tileEntityTypesObj);
Class<?> nmsclass = supplier.get().getClass();
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, nmsclass, "__extraData");
NBTInjector.setFinal(tileEntityTypesObj, supplierField, new Supplier<Object>() {
@Override
public Object get() {
try {
return wrapped.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
logger.log(Level.SEVERE, "Error while creating custom tile instance! ", e);
return supplier.get(); // Use the original one as fallback
}
}
});
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
}
package de.tr7zw.nbtinjector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.ReflectionUtil;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
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;
/**
* Contains the internal methods for different Minecraft Versions of injecting
* the Entities/Tiles
*
* @author tr7zw
*
*/
@SuppressWarnings("unchecked")
public class InternalInjectors {
private static final List<String> skippingEntities = Arrays.asList("minecraft:player", "minecraft:fishing_bobber",
"minecraft:lightning_bolt"); // These are broken/won't work, used by 1.14+
private static final Map<String, String> classMappings = new HashMap<>();
static {
classMappings.put("minecraft:wandering_trader", "VillagerTrader");
classMappings.put("minecraft:trader_llama", "LlamaTrader");
classMappings.put("minecraft:area_effect_cloud", "AreaEffectCloud");
classMappings.put("minecraft:donkey", "HorseDonkey");
classMappings.put("minecraft:ender_dragon", "EnderDragon");
classMappings.put("minecraft:skeleton_horse", "HorseSkeleton");
classMappings.put("minecraft:fireball", "LargeFireball");
classMappings.put("minecraft:mule", "HorseMule");
classMappings.put("minecraft:zombie_horse", "HorseZombie");
classMappings.put("minecraft:mooshroom", "MushroomCow");
classMappings.put("minecraft:wither_skeleton", "SkeletonWither");
classMappings.put("minecraft:snow_golem", "Snowman");
classMappings.put("minecraft:polar_bear", "PolarBear");
classMappings.put("minecraft:magma_cube", "MagmaCube");
classMappings.put("minecraft:armor_stand", "ArmorStand");
classMappings.put("minecraft:elder_guardian", "GuardianElder");
classMappings.put("minecraft:zombie_pigman", "PigZombie");
classMappings.put("minecraft:giant", "GiantZombie");
classMappings.put("minecraft:zombie_villager", "ZombieVillager");
classMappings.put("minecraft:husk", "ZombieHusk");
classMappings.put("minecraft:iron_golem", "IronGolem");
classMappings.put("minecraft:tropical_fish", "TropicalFish");
classMappings.put("minecraft:stray", "SkeletonStray");
classMappings.put("minecraft:illusioner", "IllagerIllusioner");
classMappings.put("minecraft:pufferfish", "PufferFish");
classMappings.put("minecraft:cave_spider", "CaveSpider");
classMappings.put("minecraft:item_frame", "ItemFrame");
classMappings.put("minecraft:leash_knot", "Leash");
}
/**
* Hidden constructor
*/
private InternalInjectors() {
}
protected static void entity1v10Below(ClassPool classPool) throws ReflectiveOperationException {
for (Map.Entry<String, Class<?>> entry : new HashSet<>(Entity.getCMap().entrySet())) {
try {
if (INBTWrapper.class.isAssignableFrom(entry.getValue())) {
continue;
} // Already injected
int entityId = Entity.getFMap().get(entry.getValue());
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, entry.getValue(), "__extraData");
Entity.getCMap().put(entry.getKey(), wrapped);
Entity.getDMap().put(wrapped, entry.getKey());
Entity.getEMap().put(entityId, wrapped);
Entity.getFMap().put(wrapped, entityId);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + entry.getKey(), e);
}
}
}
protected static void entity1v12Below(ClassPool classPool) throws ReflectiveOperationException {
Object registry = Entity.getRegistry();
Map<Object, Object> inverse = new HashMap<>();
Set<?> it = new HashSet<>((Set<?>) ReflectionMethod.REGISTRY_KEYSET.run(registry));
Object registryId = Entity.getRegistryId(registry);
for (Object mckey : it) {
Class<?> entclass = (Class<?>) ReflectionMethod.REGISTRY_GET.run(registry, mckey);
inverse.put(entclass, mckey);
try {
if (INBTWrapper.class.isAssignableFrom(entclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, entclass, "__extraData");
ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped);
inverse.put(wrapped, mckey);
int id = (int) registryId.getClass().getMethod("getId", new Class[] {Object.class}).invoke(registryId, entclass);
registryId.getClass().getMethod("a", new Class[] {Object.class, int.class}).invoke(registryId, wrapped, id);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
Field inverseField = registry.getClass().getDeclaredField("b");
ReflectionUtil.setFinal(registry, inverseField, inverse);
}
protected static void entity1v13Below(ClassPool classPool) throws ReflectiveOperationException {
Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry));
for (Object mckey : registryentries) {
Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey);
Field supplierField = entityTypesObj.getClass().getDeclaredField("aT");
Field classField = entityTypesObj.getClass().getDeclaredField("aS");
classField.setAccessible(true);
supplierField.setAccessible(true);
Function<Object, Object> function = (Function<Object, Object>) supplierField.get(entityTypesObj);
Class<?> nmsclass = (Class<?>) classField.get(entityTypesObj);
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData");
ReflectionUtil.setFinal(entityTypesObj, classField, wrapped);
ReflectionUtil.setFinal(entityTypesObj, supplierField, new Function<Object, Object>() {
@Override
public Object apply(Object t) {
try {
return wrapped.getConstructor(ClassWrapper.NMS_WORLD.getClazz()).newInstance(t);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error while creating custom entity instance! ", ex);
return function.apply(t);// Fallback to the original one
}
}
});
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
protected static void entity1v14(ClassPool classPool) throws ReflectiveOperationException {
Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry));
for (Object mckey : registryentries) {
if (skippingEntities.contains(mckey.toString())) {
logger.info("Skipping, won't be able add NBT to '" + mckey + "' entities!");
continue;
}
Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey);
String creatorFieldName = "aZ";
if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_15_R1.getVersionId())
creatorFieldName = "ba";
Field creatorField = entityTypesObj.getClass().getDeclaredField(creatorFieldName);
creatorField.setAccessible(true);
Object creator = creatorField.get(entityTypesObj);
Method createEntityMethod = creator.getClass().getMethod("create", ClassWrapper.NMS_ENTITYTYPES.getClazz(),
ClassWrapper.NMS_WORLD.getClazz());
createEntityMethod.setAccessible(true);
Class<?> nmsclass = null;
try {
nmsclass = createEntityMethod.invoke(creator, entityTypesObj, null).getClass();
} catch (Exception ignore) {
// ignore
}
if (nmsclass == null) {
String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
String name = mckey.toString().replace("minecraft:", "");
name = name.substring(0, 1).toUpperCase() + name.substring(1);
name = "Entity" + name;
if (classMappings.containsKey(mckey.toString()))
name = "Entity" + classMappings.get(mckey.toString());
try {
nmsclass = Class.forName("net.minecraft.server." + version + "." + name);
} catch (Exception ignore) {
logger.info("Not found: " + "net.minecraft.server." + version + "." + name);
// ignore
}
}
if (nmsclass == null) {
logger.info(
"Wasn't able to create an Entity instace, won't be able add NBT to '" + mckey + "' entities!");
continue;
}
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData");
ReflectionUtil.setFinal(entityTypesObj, creatorField,
ClassGenerator.createEntityTypeWrapper(classPool, wrapped).newInstance());
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
protected static void tile1v10Below(ClassPool classPool) throws ReflectiveOperationException {
for (Map.Entry<String, Class<?>> entry : new HashSet<>(TileEntity.getFMap().entrySet())) {
try {
if (INBTWrapper.class.isAssignableFrom(entry.getValue())) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, entry.getValue(), "__extraData");
TileEntity.getFMap().put(entry.getKey(), wrapped);
TileEntity.getGMap().put(wrapped, entry.getKey());
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + entry.getKey(), e);
}
}
}
protected static void tile1v12Below(ClassPool classPool) throws ReflectiveOperationException {
Object registry = TileEntity.getRegistry();
Map<Object, Object> inverse = new HashMap<>();
Set<?> it = new HashSet<>((Set<?>) ReflectionMethod.REGISTRY_KEYSET.run(registry));
for (Object mckey : it) {
Class<?> tileclass = (Class<?>) ReflectionMethod.REGISTRY_GET.run(registry, mckey);
inverse.put(tileclass, mckey);
try {
if (INBTWrapper.class.isAssignableFrom(tileclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, tileclass, "__extraData");
ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped);
inverse.put(wrapped, mckey);
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
Field inverseField = registry.getClass().getDeclaredField("b");
ReflectionUtil.setFinal(registry, inverseField, inverse);
}
protected static void tile1v13(ClassPool classPool) throws ReflectiveOperationException {
Object tileRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("BLOCK_ENTITY_TYPE").get(null);
Set<?> registryentries = new HashSet<>((Set<?>) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(tileRegistry));
for (Object mckey : registryentries) {
Object tileEntityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(tileRegistry, mckey);
String supplierFieldName = "A";
if (MinecraftVersion.getVersion().getVersionId() == MinecraftVersion.MC1_14_R1.getVersionId())
supplierFieldName = "H";
else if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_15_R1.getVersionId())
supplierFieldName = "I";
Field supplierField = tileEntityTypesObj.getClass().getDeclaredField(supplierFieldName);
supplierField.setAccessible(true);
Supplier<Object> supplier = (Supplier<Object>) supplierField.get(tileEntityTypesObj);
Class<?> nmsclass = supplier.get().getClass();
try {
if (INBTWrapper.class.isAssignableFrom(nmsclass)) {
continue;
} // Already injected
Class<?> wrapped = ClassGenerator.wrapTileEntity(classPool, nmsclass, "__extraData");
ReflectionUtil.setFinal(tileEntityTypesObj, supplierField, new Supplier<Object>() {
@Override
public Object get() {
try {
return wrapped.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
logger.log(Level.SEVERE, "Error while creating custom tile instance! ", e);
return supplier.get(); // Use the original one as fallback
}
}
});
} catch (Exception e) {
throw new NbtApiException("Exception while injecting " + mckey, e);
}
}
}
}
@@ -2,7 +2,6 @@ package de.tr7zw.nbtinjector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -36,6 +35,10 @@ public class NBTInjector {
}
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!"
+ " Check the Wiki/Pluginpage for more information!";
/**
* Replaces the vanilla classes with Wrapped classes that support custom NBT.
@@ -44,6 +47,8 @@ public class NBTInjector {
* this method so it's class gets Wrapped.
*/
public static void inject() {
if(isInjected)return;
isInjected = true;
try {
ClassPool classPool = ClassPool.getDefault();
logger.info("[NBTINJECTOR] Injecting Entity classes...");
@@ -70,6 +75,10 @@ public class NBTInjector {
}
}
public static boolean isInjected() {
return isInjected;
}
private static NBTCompound getNbtData(Object object) {
if (object instanceof INBTWrapper) {
return ((INBTWrapper) object).getNbtData();
@@ -98,6 +107,7 @@ public class NBTInjector {
if (entity == null) {
return null;
}
if(!isInjected)throw new NbtApiException(NOT_INJECTED_MESSAGE);
try {
Object ent = NBTReflectionUtil.getNMSEntity(entity);
if (!(ent instanceof INBTWrapper)) {// Replace Entity with custom one
@@ -109,7 +119,7 @@ public class NBTInjector {
String id = "";
if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_10_R1.getVersionId()) {
id = Entity.getBackupMap().get(ent.getClass());
} else if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_13_R1.getVersionId()) {
} else if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_13_R2.getVersionId()) {
id = ReflectionMethod.REGISTRY_GET_INVERSE.run(Entity.getRegistry(), ent.getClass()).toString();
} else {
id = (String) ReflectionMethod.NMS_ENTITY_GETSAVEID.run(ent);
@@ -145,6 +155,7 @@ public class NBTInjector {
if (entity == null) {
return null;
}
if(!isInjected)throw new NbtApiException(NOT_INJECTED_MESSAGE);
try {
Object ent = NBTReflectionUtil.getNMSEntity(entity);
if (!(ent instanceof INBTWrapper)) {
@@ -169,6 +180,7 @@ public class NBTInjector {
if (tile == null) {
return null;
}
if(!isInjected)throw new NbtApiException(NOT_INJECTED_MESSAGE);
try {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
Object cworld = ClassWrapper.CRAFT_WORLD.getClazz().cast(tile.getWorld());
@@ -205,17 +217,6 @@ public class NBTInjector {
}
}
protected static void setFinal(Object obj, Field field, Object newValue)
throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(obj, newValue);
}
private static Field getAccessable(Field field) {
field.setAccessible(true);
return field;
@@ -245,6 +246,10 @@ public class NBTInjector {
static Object getRegistry() throws ReflectiveOperationException {
return getAccessable(ClassWrapper.NMS_ENTITYTYPES.getClazz().getDeclaredField("b")).get(null);
}
static Object getRegistryId(Object reg) throws ReflectiveOperationException {
return getAccessable(reg.getClass().getDeclaredField("a")).get(reg);
}
static Map<Class<?>, String> getBackupMap() throws ReflectiveOperationException {
return backupMap;
+6 -3
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
<packaging>pom</packaging>
<modules>
<module>item-nbt-api</module>
@@ -34,7 +34,7 @@
<url>https://repo.codemc.org/repository/maven-public/</url>
<layout>default</layout>
</repository>
<!-- CodeMC NMS -->
<!-- CodeMC NMS -->
<repository>
<id>codemc-nms-repo</id>
<url>https://repo.codemc.org/repository/nms/</url>
@@ -65,7 +65,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -87,6 +87,9 @@
</goals>
</execution>
</executions>
<configuration>
<source>8</source>
</configuration>
</plugin>
<plugin>
<groupId>com.github.ekryd.sortpom</groupId>