Compare commits

...
94 Commits
Author SHA1 Message Date
tr7zw 309455ecfc Merge branch 'master' of https://github.com/tr7zw/Item-NBT-API 2025-12-09 18:44:38 +01:00
tr7zw 22c0b0385b Release 2.15.4 2025-12-09 18:44:30 +01:00
tr7zw bc6bd56ce9 Merge pull request #339 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.4.0
Bump org.apache.maven.plugins:maven-source-plugin from 3.3.1 to 3.4.0
2025-12-09 18:43:18 +01:00
tr7zw fcdf0929f9 Add 1.21.11 support 2025-12-09 18:37:52 +01:00
tr7zw e1c6ce2575 Start 2.15.4-SNAPSHOT 2025-12-09 18:36:41 +01:00
dependabot[bot] 2fcc1d82ab Bump org.apache.maven.plugins:maven-source-plugin from 3.3.1 to 3.4.0
Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.1...maven-source-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-02 02:01:29 +00:00
tr7zw eec2c0980e tag 2.15.3 2025-10-11 17:05:48 +02:00
tr7zw 3ddf3e53dc Add 1.21.10 support 2025-10-04 20:09:20 +02:00
tr7zw 70d5ab12eb Add 1.21.9 spigot support 2025-09-30 19:25:28 +02:00
tr7zw a63e9ba8f4 Add 1.21.9 Paper support, Fix Gameprofile reading/writing 2025-09-30 19:14:54 +02:00
tr7zw d8a59d6383 Merge pull request #335 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.6.1
Bump org.apache.maven.plugins:maven-shade-plugin from 3.6.0 to 3.6.1
2025-09-28 11:53:27 +02:00
tr7zw 943c7d23d6 Merge pull request #336 from tr7zw/dependabot/maven/org.codehaus.mojo-license-maven-plugin-2.7.0
Bump org.codehaus.mojo:license-maven-plugin from 2.6.0 to 2.7.0
2025-09-28 11:53:18 +02:00
tr7zw 6c70ce2ccc Merge pull request #337 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.14.1
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.14.0 to 3.14.1
2025-09-28 11:53:09 +02:00
tr7zw c1b7854fbb Merge pull request #338 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.12.0
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.3 to 3.12.0
2025-09-28 11:52:59 +02:00
tr7zw f9f1c204b6 Start 2.15.3-SNAPSHOT 2025-09-28 11:52:38 +02:00
dependabot[bot] 789f1fea96 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.3 to 3.12.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.11.3 to 3.12.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.3...maven-javadoc-plugin-3.12.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-version: 3.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-22 23:02:47 +00:00
dependabot[bot] 0e40144f09 Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.14.0 to 3.14.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.0...maven-compiler-plugin-3.14.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-version: 3.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-22 23:02:10 +00:00
dependabot[bot] 1c6315e014 Bump org.codehaus.mojo:license-maven-plugin from 2.6.0 to 2.7.0
Bumps [org.codehaus.mojo:license-maven-plugin](https://github.com/mojohaus/license-maven-plugin) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/mojohaus/license-maven-plugin/releases)
- [Commits](https://github.com/mojohaus/license-maven-plugin/compare/2.6.0...2.7.0)

---
updated-dependencies:
- dependency-name: org.codehaus.mojo:license-maven-plugin
  dependency-version: 2.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-22 23:02:05 +00:00
dependabot[bot] 91f345adf2 Bump org.apache.maven.plugins:maven-shade-plugin from 3.6.0 to 3.6.1
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.6.0 to 3.6.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.6.0...v3.6.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-version: 3.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-15 23:09:04 +00:00
tr7zw 71783a8dc9 Release 2.15.2 2025-08-26 21:59:51 +02:00
tr7zw 5d06ae9275 Fix version variables in DataFixerUtil 2025-08-26 21:51:54 +02:00
tr7zw 835fdf48cd Fix codec mapping issue in 1.21.5. Fix #332 2025-08-26 21:35:36 +02:00
tr7zw 31d77d25f9 Merge pull request #333 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.11.3
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.2 to 3.11.3
2025-08-20 21:55:57 +02:00
dependabot[bot] 6cb08ac919 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.2 to 3.11.3
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.11.2 to 3.11.3.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.2...maven-javadoc-plugin-3.11.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-version: 3.11.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-19 10:47:34 +00:00
tr7zw 08a92ac06c 2.15.2-SNAPSHOT, add 1.21.8 2025-07-17 20:29:51 +02:00
tr7zw 6bcd00d114 Bump to 2.15.1 release 2025-07-01 19:42:39 +02:00
tr7zw bc93986392 Merge pull request #328 from patyhank/master
Mark 1.21.7 as supported
2025-07-01 15:01:39 +02:00
蒟蒻 aa646e35ae mark 1.21.7 as supported 2025-07-01 20:51:49 +08:00
tr7zw 1054d16996 Add Spigot 1.21.6 support 2025-06-24 22:18:48 +02:00
tr7zw 9351a86774 Merge pull request #325 from tr7zw/dependabot/maven/org.codehaus.mojo-license-maven-plugin-2.6.0
Bump org.codehaus.mojo:license-maven-plugin from 2.5.0 to 2.6.0
2025-06-24 21:57:11 +02:00
tr7zw 56a43d246b Merge pull request #326 from patyhank/master
[1.21.6] support Entity and BlockEntity
2025-06-24 21:57:01 +02:00
蒟蒻 2b895fd4ef Entity and BlockEntity update to MC1_21_R5 2025-06-24 10:54:47 +08:00
dependabot[bot] 8f8bbfd034 Bump org.codehaus.mojo:license-maven-plugin from 2.5.0 to 2.6.0
Bumps [org.codehaus.mojo:license-maven-plugin](https://github.com/mojohaus/license-maven-plugin) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/mojohaus/license-maven-plugin/releases)
- [Commits](https://github.com/mojohaus/license-maven-plugin/compare/2.5.0...2.6.0)

---
updated-dependencies:
- dependency-name: org.codehaus.mojo:license-maven-plugin
  dependency-version: 2.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 01:45:14 +00:00
tr7zw df231c2324 Fix RegistryOps initialization for MC1_21_R5 and above
Wrapped the initialization of nbtRegistryOps in a version check to ensure it only runs for Minecraft versions MC1_21_R5 and above. This prevents potential errors on earlier versions where the method may not be available.
2025-06-21 13:55:03 +02:00
tr7zw b068284b6e Fix 1.21.6 items with components 2025-06-19 02:26:08 +02:00
tr7zw 9e9b85f46a WIP update to 1.21.6 Paper (here be dragons) 2025-06-18 22:43:03 +02:00
tr7zw 3baed4b1e7 Catch issues with the yml 2025-06-16 18:44:30 +02:00
tr7zw 432b40b3bc Add paper-plugin.yml support. Stat for plugin type 2025-06-06 22:22:56 +02:00
tr7zw fdf3638948 Add new bStats graphs 2025-06-06 21:39:10 +02:00
tr7zw b240e888cd Shade in the Metrics the correct way 2025-06-06 19:33:17 +02:00
tr7zw ccc096e2d4 Start 2.15.1-SNAPSHOT 2025-06-06 19:00:02 +02:00
tr7zw 35f541d3db Tag 2.15.0 2025-04-17 20:30:44 +02:00
tr7zw d4ee3b998c Fix wiki 2025-04-17 19:46:53 +02:00
tr7zw 2902dca5a5 Follow the javadoc of the list#remove method. Fix #293 2025-04-17 19:45:29 +02:00
tr7zw 1c1e3c8664 Remove "json" wording, add more warnings/info 2025-04-17 19:41:27 +02:00
tr7zw 7f8f021ced Merge pull request #321 from SoSeDiK/diff
Add a method to extract difference between two compounds
2025-04-17 19:24:21 +02:00
SoSeDiK 98ed1850f6 Add a method to extract difference between two compounds 2025-04-12 16:18:22 +03:00
tr7zw 764e01503d Merge pull request #320 from SoSeDiK/wiki
Update "Reading world data" wiki example
2025-03-31 19:04:27 +02:00
SoSeDiK 43d8e2a351 Update "Reading world data" wiki example 2025-03-31 19:09:42 +03:00
tr7zw 689cd4fa3b Remove unused code path 2025-03-31 18:03:11 +02:00
tr7zw c8f68f8b3b Merge pull request #319 from SoSeDiK/dataversion
Add DataVersion for itemstack conversions
2025-03-28 10:22:12 +01:00
tr7zw e52ba209e6 Fix mistake 2025-03-25 22:50:44 +01:00
tr7zw 418f5bea07 1.21.5 update, needs a lot of testing 2025-03-25 22:42:01 +01:00
SoSeDiK 1392e72a8a Only run items through the data fixer on MC1_20_R4+ 2025-03-22 00:37:57 +02:00
SoSeDiK dc39d1d8ef Add DataVersion for itemstack conversions 2025-03-21 23:13:50 +02:00
tr7zw a974142a55 Merge pull request #316 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.14.0
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.13.0 to 3.14.0
2025-02-23 10:39:14 +00:00
dependabot[bot] f014e71020 Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.13.0 to 3.14.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.13.0...maven-compiler-plugin-3.14.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-21 23:13:30 +00:00
tr7zw da6be72d29 Merge pull request #313 from SoSeDiK/wiki
Update wiki
2024-12-28 19:11:29 +00:00
SoSeDiK d9a93e9306 Add info about paper-plugin.yml 2024-12-28 15:57:04 +02:00
SoSeDiK ba374fe69c Update gradle shadow plugin info 2024-12-28 15:53:01 +02:00
SoSeDiK aa35ee8333 Fixup modifyMeta example 2024-12-28 15:51:28 +02:00
SoSeDiK 3bb0bdd74c Clarify persistent data storage availability 2024-12-28 15:50:49 +02:00
tr7zw f3af749b11 Merge pull request #309 from tr7zw/dependabot/maven/org.codehaus.mojo-license-maven-plugin-2.5.0
Bump org.codehaus.mojo:license-maven-plugin from 2.4.0 to 2.5.0
2024-12-21 23:44:01 +00:00
tr7zw d81c2b4e8e Merge pull request #311 from FireML/patch-1
Add EvenMoreFish to Plugins.md
2024-12-21 23:43:51 +00:00
tr7zw 94192feb8f Merge pull request #312 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.11.2
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.1 to 3.11.2
2024-12-21 23:43:29 +00:00
tr7zw af3d9c8502 Start 2.14.2-SNAPSHOT 2024-12-22 00:42:03 +01:00
tr7zw ae98859524 Tag 2.14.1 2024-12-16 17:11:16 +01:00
tr7zw 70f0bb62f9 Add Util to get ItemStacks in Json Format for hover components 2024-12-14 21:58:53 +01:00
dependabot[bot] 505e172955 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.1 to 3.11.2
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.11.1 to 3.11.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.1...maven-javadoc-plugin-3.11.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 23:45:07 +00:00
FireML d2b2b6a506 Add EvenMoreFish to Plugins.md, and Update CommandAPI URL 2024-12-08 01:31:10 +00:00
tr7zw e2e8aad70a Merge pull request #310 from ArmyFury/patch-1
Update Plugins.md
2024-12-07 13:17:51 +00:00
ArmyFury 4874366e30 Update Plugins.md
added SummonFriendlyMobs to plugins list
2024-12-07 12:47:39 +05:30
tr7zw d2de90ee25 Add 1.21.4 support 2024-12-03 23:28:21 +01:00
dependabot[bot] a0f93e575e Bump org.codehaus.mojo:license-maven-plugin from 2.4.0 to 2.5.0
Bumps [org.codehaus.mojo:license-maven-plugin](https://github.com/mojohaus/license-maven-plugin) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/mojohaus/license-maven-plugin/releases)
- [Commits](https://github.com/mojohaus/license-maven-plugin/compare/2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: org.codehaus.mojo:license-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-29 23:30:47 +00:00
tr7zw b339c9e9c2 Merge pull request #306 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.11.1
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.10.1 to 3.11.1
2024-11-13 23:54:08 +01:00
tr7zw 3425a6672d Merge pull request #308 from SoSeDiK/wiki-changes
Update wiki
2024-11-13 23:53:54 +01:00
tr7zw 67616266da Start snapshots 2.14.1 2024-11-13 23:53:07 +01:00
SoSeDiK b08e4aa12f Update wiki to reflect some 2.14.0 changes
ItemMeta usage clarifications
2024-11-12 14:28:06 +02:00
dependabot[bot] 27411e90da Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.10.1 to 3.11.1
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.10.1 to 3.11.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.1...maven-javadoc-plugin-3.11.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 23:48:38 +00:00
tr7zw 73776cfec4 Sneak quick fix into release 2024-11-02 15:18:16 +01:00
tr7zw bd674e31c0 Tag 2.14.0 2024-11-02 15:07:50 +01:00
tr7zw 3405ffe0a3 Fix javadoc deploy 2024-11-02 13:24:22 +01:00
tr7zw f1317bcb04 Fix BlockEntity test. Fix #304 2024-11-02 13:06:19 +01:00
tr7zw 4a32343b95 Add 1.21.3 2024-10-28 18:56:04 +01:00
tr7zw 3de6ed83eb Hide NBTFile/NBTContainer fully behind NBT. Update tests to new format. Add missing addCompound(ReadableNBT comp) to ReadWriteNBTCompoundList 2024-10-22 23:45:16 +02:00
tr7zw e5bdce73ea Merge pull request #300 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.10.1
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.10.0 to 3.10.1
2024-10-22 22:42:25 +02:00
tr7zw 410e88a35b Add getComponents methods 2024-10-22 22:39:35 +02:00
tr7zw e3142b4869 Add 1.21.2 support 2024-10-22 22:24:59 +02:00
tr7zw 243a5c2bcd Fix really stupid edge case of writeCompound 2024-10-22 22:08:04 +02:00
dependabot[bot] 045c710366 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.10.0 to 3.10.1
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.0...maven-javadoc-plugin-3.10.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-01 23:20:24 +00:00
tr7zw 4cd118671f Merge pull request #297 from tr7zw/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.10.0
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.8.0 to 3.10.0
2024-08-27 23:03:05 +02:00
dependabot[bot] d86c91f2e6 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.8.0 to 3.10.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.8.0 to 3.10.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.8.0...maven-javadoc-plugin-3.10.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-27 16:08:01 +00:00
tr7zw f8736c8188 Also update old items with "Count" tags 2024-08-27 18:07:27 +02:00
tr7zw b3aec54205 Start 2.13.3-SNAPSHOT 2024-08-27 18:06:56 +02:00
57 changed files with 1637 additions and 1210 deletions

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ updates:
ignore:
- dependency-name: com.github.ekryd.sortpom:sortpom-maven-plugin
versions:
- 2.13.2
- 2.13.3-SNAPSHOT
- 2.14.0
- 2.14.1
- 2.15.0
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- name: Copy artifacts
shell: bash
run: |
mkdir -p artifacts/v2-api && cp -r item-nbt-api/target/apidocs/* artifacts/v2-api
mkdir -p artifacts/v2-api && cp -r item-nbt-api/target/reports/apidocs/* artifacts/v2-api
mkdir -p artifacts/v2-plugin && cp -r item-nbt-plugin/target/apidocs/* artifacts/v2-plugin
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4.4.1
+15 -3
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</parent>
<artifactId>item-nbt-api</artifactId>
@@ -18,6 +18,12 @@
<version>4.0.26</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@@ -32,9 +38,15 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<version>3.6.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>de.tr7zw.changeme.nbtapi.utils.metrics</shadedPattern>
</relocation>
</relocations>
<createDependencyReducedPom>true</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>LICENSE</resource>
@@ -1,5 +1,8 @@
package de.tr7zw.changeme.nbtapi;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
@@ -12,6 +15,7 @@ import org.bukkit.inventory.ItemStack;
import com.mojang.authlib.GameProfile;
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteItemNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadableItemNBT;
@@ -200,9 +204,9 @@ public class NBT {
}
/**
* It takes a block entity and a function that takes a ReadableNBT and returns
* a generic type T, and returns the result of the function, applied to the
* block entities persistent data container
* It takes a block entity and a function that takes a ReadableNBT and returns a
* generic type T, and returns the result of the function, applied to the block
* entities persistent data container
*
* @param blockState The block state of the block you want to get the data from.
* @param getter A function that takes a ReadableNBT and returns a value of
@@ -269,17 +273,17 @@ public class NBT {
nbtEnt.setClosed();
return ret;
}
/**
* It takes an ItemStack and a Consumer&lt;ReadWriteNBT&gt;, and then applies
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
* This method is quiet expensive, so don't overuse it.
* This method is quite expensive, so don't overuse it.
*
* @param item The item you want to modify the components of
* @param consumer The consumer that will be used to modify the components.
*/
public static void modifyComponents(ItemStack item, Consumer<ReadWriteNBT> consumer) {
if(!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
throw new NbtApiException("This method only works for 1.20.5+!");
}
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
@@ -287,18 +291,18 @@ public class NBT {
ItemStack tmp = NBT.itemStackFromNBT(nbti);
item.setItemMeta(tmp.getItemMeta());
}
/**
* It takes an ItemStack and a Consumer&lt;ReadWriteNBT&gt;, and then applies
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
* This method is quiet expensive, so don't overuse it.
* This method is quite expensive, so don't overuse it.
*
* @param item The item you want to modify the components of
* @param function The consumer that will be used to modify the components.
* @return The return type is the same as the return type of the function.
*/
public static <T> T modifyComponents(ItemStack item, Function<ReadWriteNBT, T> function) {
if(!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
throw new NbtApiException("This method only works for 1.20.5+!");
}
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
@@ -308,6 +312,39 @@ public class NBT {
return ret;
}
/**
* It takes an ItemStack and a Consumer&lt;ReadWriteNBT&gt;, and then applies
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
* This method is quite expensive, try to cache the results/use it smartly.
*
* @param item The item you want to read the components of
* @param consumer The consumer that will be used to read the components.
*/
public static void getComponents(ItemStack item, Consumer<ReadableNBT> consumer) {
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
throw new NbtApiException("This method only works for 1.20.5+!");
}
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
consumer.accept(nbti.getOrCreateCompound("components"));
}
/**
* It takes an ItemStack and a Consumer&lt;ReadWriteNBT&gt;, and then applies
* the Consumer to the ItemStacks Components as NBT. This is for 1.20.5+ only.
* This method is quite expensive, try to cache the results/use it smartly.
*
* @param item The item you want to read the components of
* @param function The consumer that will be used to read the components.
* @return The return type is the same as the return type of the function.
*/
public static <T> T getComponents(ItemStack item, Function<ReadableNBT, T> function) {
if (!MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
throw new NbtApiException("This method only works for 1.20.5+!");
}
ReadWriteNBT nbti = NBT.itemStackToNBT(item);
return function.apply(nbti.getOrCreateCompound("components"));
}
/**
* It takes an entity and a function that takes a ReadWriteNBT and applies the
* function to the entity
@@ -492,12 +529,70 @@ public class NBT {
* It takes a nbt json string, and returns a ReadWriteNBT object
*
* @param nbtString The NBT string to parse.
* @return A new NBTContainer object.
* @return A new ReadWriteNBT object.
*/
public static ReadWriteNBT parseNBT(String nbtString) {
return new NBTContainer(nbtString);
}
/**
* Reads in an NBT stream and returns a ReadWriteNBT object
*
* @param stream The NBT stream to read.
* @return A new ReadWriteNBT object.
*/
public static ReadWriteNBT readNBT(InputStream stream) {
return new NBTContainer(stream);
}
/**
* Helper method for other developers using NMS. Allows to wrap any
* net.minecraft.nbt.CompoundTag to a NBTAPI ReadWriteNBT object.
*
* @param nmsNbtTag Needs to be a valid net.minecraft.nbt.CompoundTag
* @return A new ReadWriteNBT object.
*/
public static ReadWriteNBT wrapNMSTag(Object nmsNbtTag) {
return new NBTContainer(nmsNbtTag);
}
/**
* Creates a NBTFileHandle that uses @param file to store its data. If this file
* exists, the data will be loaded, otherwise a new file gets created.
*
* @param file
* @throws IOException
*/
public static NBTFileHandle getFileHandle(File file) throws IOException {
return new NBTFile(file);
}
/**
* Reads NBT data from the provided file.
* <p>
* Returns an empty tag if the file does not exist.
*
* @param file file to read
* @return ReadWriteNBT of the files data
* @throws IOException exception
*/
public static ReadWriteNBT readFile(File file) throws IOException {
return NBTFile.readFrom(file);
}
/**
* Saves NBT data to the provided file.
* <p>
* Will fully override the file if it already exists.
*
* @param file file
* @param nbt NBT data
* @throws IOException exception
*/
public static void writeFile(File file, ReadWriteNBT nbt) throws IOException {
NBTFile.saveTo(file, (NBTCompound) nbt);
}
/**
* Create a read only proxy class for NBT, given an annotated interface.
*
@@ -5,6 +5,7 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
@@ -19,6 +20,7 @@ import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
import de.tr7zw.changeme.nbtapi.utils.CheckUtil;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.PathUtil;
import de.tr7zw.changeme.nbtapi.utils.UUIDUtil;
import de.tr7zw.changeme.nbtapi.utils.PathUtil.PathSegment;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.Forge1710Mappings;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -98,10 +100,13 @@ public class NBTCompound implements ReadWriteNBT {
return readOnlyCache;
}
Object rootnbttag = getCompound();
if (rootnbttag instanceof Optional<?>) {
rootnbttag = ((Optional<Object>) rootnbttag).orElse(null);
}
if (rootnbttag == null) {
return null;
}
if (!NBTReflectionUtil.valideCompound(this))
if (!NBTReflectionUtil.validCompound(this))
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
Object workingtag = NBTReflectionUtil.getToCompount(rootnbttag, this);
if (readOnly) {
@@ -657,7 +662,9 @@ public class NBTCompound implements ReadWriteNBT {
public void setUUID(String key, UUID value) {
try {
writeLock.lock();
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
setIntArray(key, UUIDUtil.uuidToIntArray(value));
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
NBTReflectionUtil.setData(this, ReflectionMethod.COMPOUND_SET_UUID, key, value);
} else {
setString(key, value.toString());
@@ -678,10 +685,13 @@ public class NBTCompound implements ReadWriteNBT {
public UUID getUUID(String key) {
try {
readLock.lock();
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)
&& getType(key) == NBTType.NBTTagIntArray) {
NBTType type = getType(key);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4) && type == NBTType.NBTTagIntArray) {
return UUIDUtil.uuidFromIntArray(getIntArray(key));
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)
&& type == NBTType.NBTTagIntArray) {
return (UUID) NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET_UUID, key);
} else if (getType(key) == NBTType.NBTTagString) {
} else if (type == NBTType.NBTTagString) {
try {
return UUID.fromString(getString(key));
} catch (IllegalArgumentException ex) {
@@ -786,7 +796,7 @@ public class NBTCompound implements ReadWriteNBT {
if (getType(name) != NBTType.NBTTagCompound)
return null;
NBTCompound next = new NBTCompound(this, name, readOnly);
if (NBTReflectionUtil.valideCompound(next))
if (NBTReflectionUtil.validCompound(next))
return next;
return null;
} finally {
@@ -1343,7 +1353,13 @@ public class NBTCompound implements ReadWriteNBT {
Object nbtbase = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET, name);
if (nbtbase == null)
return null;
return NBTType.valueOf((byte) ReflectionMethod.COMPOUND_OWN_TYPE.run(nbtbase));
return NBTType.valueOf((byte) ReflectionMethod.COMPOUND_OWN_TYPE_LEGACY.run(nbtbase));
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
Object o = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET, name);
if (o == null)
return null;
return NBTType.fromName((String)ReflectionMethod.TAGTYPE_GET_NAME.run(ReflectionMethod.TAGTYPE_OWN_TYPE.run(o)));
}
Object o = NBTReflectionUtil.getData(this, ReflectionMethod.COMPOUND_GET_TYPE, name);
if (o == null)
@@ -1460,6 +1476,106 @@ public class NBTCompound implements ReadWriteNBT {
return false;
}
@Override
public NBTCompound extractDifference(ReadableNBT other) {
if (this == other)
return new NBTContainer();
if (other instanceof NBTCompound) {
return saveDiff(new NBTContainer(), this, (NBTCompound) other);
} else {
throw new NbtApiException("Unknown NBT object: " + other);
}
}
private static NBTCompound saveDiff(NBTCompound saveTo, NBTCompound compA, NBTCompound compB) {
for (String key : compA.getKeys()) {
saveDiff(saveTo, compA, compB, key);
}
return saveTo;
}
private static void saveDiff(NBTCompound saveTo, NBTCompound compA, NBTCompound compB, String key) {
boolean typeMismatch = compA.getType(key) != compB.getType(key);
switch (compA.getType(key)) {
case NBTTagByte:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setByte(key, compA.getByte(key));
}
return;
case NBTTagByteArray:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setByteArray(key, compA.getByteArray(key));
}
return;
case NBTTagCompound: {
NBTCompound tmp1 = compA.getCompound(key);
if (tmp1 == null) return;
if (typeMismatch) {
saveTo.addCompound(key).mergeCompound(tmp1);
} else {
NBTCompound tmp2 = compB.getCompound(key);
if (tmp2 == null) {
saveTo.addCompound(key).mergeCompound(tmp1);
return;
}
NBTCompound tmpDiff = tmp1.extractDifference(tmp2);
if (!tmpDiff.getKeys().isEmpty()) {
saveTo.addCompound(key).mergeCompound(tmpDiff);
}
}
return;
}
case NBTTagDouble:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setDouble(key, compA.getDouble(key));
}
return;
case NBTTagEnd:
return; // ??
case NBTTagFloat:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setFloat(key, compA.getFloat(key));
}
return;
case NBTTagInt:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setInteger(key, compA.getInteger(key));
}
return;
case NBTTagIntArray:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setIntArray(key, compA.getIntArray(key));
}
return;
case NBTTagList:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.set(key, NBTReflectionUtil.getEntry(compA, key));
}
return;
case NBTTagLong:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setLong(key, compA.getLong(key));
}
return;
case NBTTagShort:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setShort(key, compA.getShort(key));
}
return;
case NBTTagString:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setString(key, compA.getString(key));
}
return;
case NBTTagLongArray:
if (typeMismatch || !isEqual(compA, compB, key)) {
saveTo.setLongArray(key, compA.getLongArray(key));
}
return;
}
}
private static boolean isEqual(NBTCompound compA, NBTCompound compB, String key) {
if (compA.getType(key) != compB.getType(key))
return false;
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -56,7 +57,8 @@ public class NBTCompoundList extends NBTList<ReadWriteNBT> implements ReadWriteN
}
}
public NBTCompound addCompound(ReadWriteNBT comp) {
@Override
public ReadWriteNBT addCompound(ReadableNBT comp) {
if (comp instanceof NBTCompound) {
return addCompound((NBTCompound) comp);
}
@@ -21,7 +21,10 @@ public class NBTContainer extends NBTCompound {
/**
* Creates an empty, standalone NBTCompound
*
* @deprecated use {@link NBT#createNBTObject()}
*/
@Deprecated
public NBTContainer() {
super(null, null);
nbt = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
@@ -31,7 +34,9 @@ public class NBTContainer extends NBTCompound {
* Takes in any NMS Compound to wrap it
*
* @param nbt
* @deprecated Use NBT.wrapNMSTag
*/
@Deprecated
public NBTContainer(Object nbt) {
super(null, null);
if (nbt == null) {
@@ -47,7 +52,9 @@ public class NBTContainer extends NBTCompound {
* Reads in a NBT InputStream
*
* @param inputsteam
* @deprecated Use NBT.readNBT
*/
@Deprecated
public NBTContainer(InputStream inputsteam) {
super(null, null);
this.nbt = NBTReflectionUtil.readNBT(inputsteam);
@@ -58,7 +65,9 @@ public class NBTContainer extends NBTCompound {
* {@link NbtApiException} in case something goes wrong.
*
* @param nbtString
* @deprecated Use NBT.parseNBT
*/
@Deprecated
public NBTContainer(String nbtString) {
super(null, null);
if (nbtString == null) {
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
/**
@@ -12,7 +13,7 @@ import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
* @author tr7zw
*
*/
public class NBTFile extends NBTCompound {
public class NBTFile extends NBTCompound implements NBTFileHandle {
private final File file;
private Object nbt;
@@ -23,7 +24,9 @@ public class NBTFile extends NBTCompound {
*
* @param file
* @throws IOException
* @deprecated Use NBT.getFileHandle(file)
*/
@Deprecated
public NBTFile(File file) throws IOException {
super(null, null);
if (file == null) {
@@ -43,6 +46,7 @@ public class NBTFile extends NBTCompound {
*
* @throws IOException
*/
@Override
public void save() throws IOException {
try {
getWriteLock().lock();
@@ -55,6 +59,7 @@ public class NBTFile extends NBTCompound {
/**
* @return The File used to store the data
*/
@Override
public File getFile() {
return file;
}
@@ -77,7 +82,9 @@ public class NBTFile extends NBTCompound {
* @param file file to read
* @return NBTCompound holding file's nbt data
* @throws IOException exception
* @deprecated Use NBT.readFile(file)
*/
@Deprecated
public static NBTCompound readFrom(File file) throws IOException {
if (!file.exists())
return new NBTContainer();
@@ -92,7 +99,9 @@ public class NBTFile extends NBTCompound {
* @param file file
* @param nbt NBT data
* @throws IOException exception
* @deprecated Use NBT.writeFile(file, nbt)
*/
@Deprecated
public static void saveTo(File file, NBTCompound nbt) throws IOException {
if (!file.exists()) {
file.getParentFile().mkdirs();
@@ -304,8 +304,8 @@ public abstract class NBTList<T> implements List<T>, ReadWriteNBTList<T> {
try {
parent.getWriteLock().lock();
int size = size();
int id = -1;
while ((id = indexOf(o)) != -1) {
int id = indexOf(o);
if (id != -1) {
remove(id);
}
return size != size();
@@ -9,8 +9,10 @@ import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.block.BlockState;
@@ -18,11 +20,15 @@ import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DynamicOps;
import de.tr7zw.changeme.nbtapi.utils.DataFixerUtil;
import de.tr7zw.changeme.nbtapi.utils.GsonWrapper;
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.MojangToMapping;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.CodecHelper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ObjectCreator;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -40,6 +46,10 @@ public class NBTReflectionUtil {
private static Field field_handle = null;
private static Object type_custom_data = null;
private static Object registry_access = null;
public static Codec<Object> itemstack_codec = null;
public static DynamicOps<Object> nbtOps = null;
public static DynamicOps<Object> nbtRegistryOps = null;
public static Object problemReporter = null;
static {
try {
@@ -56,15 +66,22 @@ public class NBTReflectionUtil {
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
try {
Field typeField = ClassWrapper.NMS_DATACOMPONENTS.getClazz().getDeclaredField(
MojangToMapping.getMapping().get("net.minecraft.core.component.DataComponents#CUSTOM_DATA"));
Field typeField = ReflectionUtil.getMappedField(ClassWrapper.NMS_DATACOMPONENTS.getClazz(), "net.minecraft.core.component.DataComponents#CUSTOM_DATA");
type_custom_data = typeField.get(null);
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
} catch (Exception e) {
MinecraftVersion.getLogger().log(Level.WARNING,
"Unable to find DataComponents#CUSTOM_DATA, NBTApi will not be able to read/write custom data on 1.20+",
e);
}
try {
Object nmsServer = ReflectionMethod.NMSSERVER_GETSERVER.run(Bukkit.getServer());
registry_access = ReflectionMethod.NMSSERVER_GETREGISTRYACCESS.run(nmsServer);
itemstack_codec = (Codec<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_ITEMSTACK.getClazz(), "net.minecraft.world.item.ItemStack#CODEC").get(null);
nbtOps = (DynamicOps<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_NBTOPS.getClazz(), "net.minecraft.nbt.NbtOps#INSTANCE").get(null);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
nbtRegistryOps = (DynamicOps<Object>) ReflectionMethod.GET_SERIALIZATION_CONTEXT.run(registry_access, nbtOps);
problemReporter = ReflectionUtil.getMappedField(ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), "net.minecraft.util.ProblemReporter#DISCARDING").get(null);
}
} catch (Exception e) {
e.printStackTrace();
}
@@ -154,6 +171,9 @@ public class NBTReflectionUtil {
public static void writeApiNBT(NBTCompound comp, OutputStream stream) {
try {
Object workingtag = comp.getResolvedObject();
if (workingtag == null) {
workingtag = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
}
ReflectionMethod.NBTFILE_WRITE.run(null, workingtag, stream);
} catch (Exception e) {
throw new NbtApiException("Exception while writing NBT!", e);
@@ -210,21 +230,35 @@ public class NBTReflectionUtil {
* @return NMS ItemStack
*/
public static Object convertNBTCompoundtoNMSItem(NBTCompound nbtcompound) {
Object nmsComp = null;
try {
Object nmsComp = getToCompount(nbtcompound.getCompound(), nbtcompound);
nmsComp = getToCompount(nbtcompound.getCompound(), nbtcompound);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
if (nbtcompound.hasTag("tag")) {
nmsComp = DataFixerUtil.fixUpRawItemData(nmsComp, DataFixerUtil.VERSION1_20_4,
DataFixerUtil.getCurrentVersion());
if (nbtcompound.hasTag("DataVersion", NBTType.NBTTagInt)) {
int dataVersion = nbtcompound.getInteger("DataVersion");
int currentVersion = DataFixerUtil.getCurrentVersion();
if (dataVersion < currentVersion) {
nmsComp = DataFixerUtil.fixUpRawItemData(nmsComp, dataVersion, currentVersion);
}
} else if (nbtcompound.hasTag("tag") || nbtcompound.hasTag("Count")) {
nmsComp = DataFixerUtil.fixUpRawItemData(nmsComp, DataFixerUtil.VERSION1_20_4, DataFixerUtil.getCurrentVersion());
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
return CodecHelper.convertNbtToItemStack(nmsComp);
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
Optional<Object> opt = (Optional<Object>) ReflectionMethod.NMSITEM_LOAD_MODERN.run(null,
registry_access, nmsComp);
return opt.orElse(null);
} else {
return ReflectionMethod.NMSITEM_LOAD.run(null, registry_access, nmsComp);
}
return ReflectionMethod.NMSITEM_LOAD.run(null, registry_access, nmsComp);
} else if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_11_R1.getVersionId()) {
return ObjectCreator.NMS_COMPOUNDFROMITEM.getInstance(nmsComp);
} else {
return ReflectionMethod.NMSITEM_CREATESTACK.run(null, nmsComp);
}
} catch (Exception e) {
throw new NbtApiException("Exception while converting NBTCompound to NMS ItemStack!", e);
throw new NbtApiException("Exception while converting NBTCompound to NMS ItemStack! " + nmsComp, e);
}
}
@@ -236,13 +270,20 @@ public class NBTReflectionUtil {
*/
public static NBTContainer convertNMSItemtoNBTCompound(Object nmsitem) {
try {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
return new NBTContainer(ReflectionMethod.NMSITEM_SAVE_MODERN.run(nmsitem, registry_access));
NBTContainer container;
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
container = new NBTContainer(CodecHelper.convertItemStackToNbt(nmsitem));
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
container = new NBTContainer(ReflectionMethod.NMSITEM_SAVE_MODERN.run(nmsitem, registry_access));
} else {
Object answer = ReflectionMethod.NMSITEM_SAVE.run(nmsitem,
ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance());
return new NBTContainer(answer);
container = new NBTContainer(answer);
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)) {
container.setInteger("DataVersion", DataFixerUtil.getCurrentVersion());
}
return container;
} catch (Exception e) {
throw new NbtApiException("Exception while converting NMS ItemStack to NBTCompound!", e);
}
@@ -273,7 +314,16 @@ public class NBTReflectionUtil {
public static Object getEntityNBTTagCompound(Object nmsEntity) {
try {
Object nbt = ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz().newInstance();
Object answer = ReflectionMethod.NMS_ENTITY_GET_NBT.run(nmsEntity, nbt);
Object answer;
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
Object output = ReflectionMethod.NMS_GET_TAG_VALUE_OUTPUT.run(null, problemReporter, registry_access);
ReflectionMethod.NMS_ENTITY_GET_NBT_1216.run(nmsEntity, output);
answer = ReflectionMethod.NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND.run(output);
} else {
answer = ReflectionMethod.NMS_ENTITY_GET_NBT.run(nmsEntity, nbt);
}
if (answer == null)
answer = nbt;
return answer;
@@ -291,7 +341,14 @@ public class NBTReflectionUtil {
*/
public static Object setEntityNBTTag(Object nbtTag, Object nmsEntity) {
try {
ReflectionMethod.NMS_ENTITY_SET_NBT.run(nmsEntity, nbtTag);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
Object valueInputTag = ReflectionMethod.NMS_GET_TAG_VALUE_INPUT.run(null, problemReporter, registry_access, nbtTag);
ReflectionMethod.NMS_ENTITY_SET_NBT_1216.run(nmsEntity, valueInputTag);
} else {
ReflectionMethod.NMS_ENTITY_SET_NBT.run(nmsEntity, nbtTag);
}
return nmsEntity;
} catch (Exception ex) {
throw new NbtApiException("Exception while setting the NBTCompound of an Entity", ex);
@@ -323,7 +380,13 @@ public class NBTReflectionUtil {
}
Object answer = null;
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
Object output = ReflectionMethod.NMS_GET_TAG_VALUE_OUTPUT.run(null, problemReporter, registry_access);
ReflectionMethod.TILEENTITY_GET_NBT_1216.run(o, output);
answer = ReflectionMethod.NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND.run(output);
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
answer = ReflectionMethod.TILEENTITY_GET_NBT_1205.run(o, registry_access);
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_18_R1)) {
answer = ReflectionMethod.TILEENTITY_GET_NBT_1181.run(o);
@@ -358,7 +421,11 @@ public class NBTReflectionUtil {
Object pos = ObjectCreator.NMS_BLOCKPOSITION.getInstance(tile.getX(), tile.getY(), tile.getZ());
o = ReflectionMethod.NMS_WORLD_GET_TILEENTITY.run(nmsworld, pos);
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
Object valueInput = ReflectionMethod.NMS_GET_TAG_VALUE_INPUT.run(null, problemReporter, registry_access, comp);
ReflectionMethod.TILEENTITY_SET_NBT_1216.run(o, valueInput);
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
ReflectionMethod.TILEENTITY_SET_NBT_1205.run(o, comp, registry_access);
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
ReflectionMethod.TILEENTITY_SET_NBT.run(o, comp);
@@ -383,7 +450,11 @@ public class NBTReflectionUtil {
public static Object getSubNBTTagCompound(Object compound, String name) {
try {
if ((boolean) ReflectionMethod.COMPOUND_HAS_KEY.run(compound, name)) {
return ReflectionMethod.COMPOUND_GET_COMPOUND.run(compound, name);
Object comp = ReflectionMethod.COMPOUND_GET_COMPOUND.run(compound, name);
if (comp instanceof Optional) {
return ((Optional<?>) comp).orElse(null);
}
return comp;
} else {
throw new NbtApiException("Tried getting invalid compound '" + name + "' from '" + compound + "'!");
}
@@ -407,7 +478,7 @@ public class NBTReflectionUtil {
if (nbttag == null) {
nbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp)) {
if (!validCompound(comp)) {
return;
}
Object workingtag = getToCompount(nbttag, comp);
@@ -424,10 +495,13 @@ public class NBTReflectionUtil {
* Checks if the Compound is correctly linked to it's roots
*
* @param comp
* @return true if this is a valide Compound, else false
* @return true if this is a valid Compound, else false
*/
public static boolean valideCompound(NBTCompound comp) {
public static boolean validCompound(NBTCompound comp) {
Object root = comp.getCompound();
if (root instanceof Optional) {
root = ((Optional<?>) root).orElse(null);
}
if (root == null) {
root = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
@@ -442,9 +516,15 @@ public class NBTReflectionUtil {
structure.add(comp.getName());
comp = comp.getParent();
}
if (nbttag instanceof Optional) {
nbttag = ((Optional<?>) nbttag).orElse(null);
}
while (!structure.isEmpty()) {
String target = structure.pollLast();
nbttag = getSubNBTTagCompound(nbttag, target);
if (nbttag instanceof Optional) {
nbttag = ((Optional<?>) nbttag).orElse(null);
}
if (nbttag == null) {
throw new NbtApiException("Unable to find tag '" + target + "' in " + nbttag);
}
@@ -467,7 +547,7 @@ public class NBTReflectionUtil {
if (rootnbttag == null) {
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp))
if (!validCompound(comp))
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
Object workingtag = getToCompount(rootnbttag, comp);
try {
@@ -494,7 +574,7 @@ public class NBTReflectionUtil {
if (rootnbttag == null) {
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp)) {
if (!validCompound(comp)) {
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
}
Object workingtag = getToCompount(rootnbttag, comp);
@@ -522,7 +602,18 @@ public class NBTReflectionUtil {
workingtag = dummyNBT.getCompound(); // it creates a new ListTag if needed, but its unlinked
}
try {
Object nbt = ReflectionMethod.COMPOUND_GET_LIST.run(workingtag, key, type.getId());
Object nbt = null;
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
nbt = ReflectionMethod.COMPOUND_GET_LIST.run(workingtag, key);
if (nbt instanceof Optional) {
nbt = ((Optional<?>) nbt).orElse(null);
}
if (nbt == null) {
nbt = ClassWrapper.NMS_NBTTAGLIST.getClazz().newInstance();
}
} else {
nbt = ReflectionMethod.COMPOUND_GET_LIST_LEGACY.run(workingtag, key, type.getId());
}
if (clazz == String.class) {
return (NBTList<T>) new NBTStringList(comp, key, type, nbt);
} else if (clazz == NBTListCompound.class) {
@@ -554,6 +645,26 @@ public class NBTReflectionUtil {
}
try {
Object nbt = ReflectionMethod.COMPOUND_GET.run(workingtag, key);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
if (nbt instanceof Optional) {
nbt = ((Optional<?>) nbt).orElse(null);
}
if (nbt == null) {
return NBTType.NBTTagEnd;
}
if (new NBTStringList(comp, key, NBTType.NBTTagString, nbt).isEmpty()) {
return NBTType.NBTTagEnd;
}
Object compound = ReflectionMethod.LIST_GET.run(nbt, 0);
if (compound instanceof Optional) {
compound = ((Optional<?>) compound).orElse(null);
}
if (compound == null) {
return NBTType.NBTTagEnd;
}
return NBTType.fromName((String) ReflectionMethod.TAGTYPE_GET_NAME
.run(ReflectionMethod.TAGTYPE_OWN_TYPE.run(compound)));
}
String fieldname = "type";
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
fieldname = "w";
@@ -628,7 +739,7 @@ public class NBTReflectionUtil {
if (rootnbttag == null) {
return;
}
if (!valideCompound(comp))
if (!validCompound(comp))
return;
Object workingtag = getToCompount(rootnbttag, comp);
ReflectionMethod.COMPOUND_REMOVE_KEY.run(workingtag, key);
@@ -667,7 +778,7 @@ public class NBTReflectionUtil {
if (rootnbttag == null) {
rootnbttag = ObjectCreator.NMS_NBTTAGCOMPOUND.getInstance();
}
if (!valideCompound(comp))
if (!validCompound(comp))
throw new NbtApiException("The Compound wasn't able to be linked back to the root!");
Object workingtag = getToCompount(rootnbttag, comp);
type.run(workingtag, key, data);
@@ -690,7 +801,41 @@ public class NBTReflectionUtil {
if (workingtag == null) {
workingtag = dummyNBT.getCompound();
}
return type.run(workingtag, key);
if (workingtag instanceof Optional<?>) {
workingtag = ((Optional<Object>) workingtag).orElseGet(() -> dummyNBT.getCompound());
}
Object obj = type.run(workingtag, key);
if (obj instanceof Optional<?>) {
return ((Optional<Object>) obj).orElseGet(() -> getDefaultValue(type));
}
return obj;
}
private static Object getDefaultValue(ReflectionMethod type) {
if (type == ReflectionMethod.COMPOUND_GET_STRING) {
return "";
} else if (type == ReflectionMethod.COMPOUND_GET_BYTE) {
return (byte) 0;
} else if (type == ReflectionMethod.COMPOUND_GET_SHORT) {
return (short) 0;
} else if (type == ReflectionMethod.COMPOUND_GET_BOOLEAN) {
return false;
} else if (type == ReflectionMethod.COMPOUND_GET_INT) {
return 0;
} else if (type == ReflectionMethod.COMPOUND_GET_LONG) {
return 0L;
} else if (type == ReflectionMethod.COMPOUND_GET_FLOAT) {
return 0.0f;
} else if (type == ReflectionMethod.COMPOUND_GET_DOUBLE) {
return 0.0d;
} else if (type == ReflectionMethod.COMPOUND_GET_BYTEARRAY) {
return new byte[0];
} else if (type == ReflectionMethod.COMPOUND_GET_INTARRAY) {
return new int[0];
} else if (type == ReflectionMethod.COMPOUND_GET_LONGARRAY) {
return new long[0];
}
return null;
}
}
@@ -2,6 +2,7 @@ package de.tr7zw.changeme.nbtapi;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
@@ -21,7 +22,11 @@ public class NBTStringList extends NBTList<String> {
@Override
public String get(int index) {
try {
return (String) ReflectionMethod.LIST_GET_STRING.run(listObject, index);
Object ret = ReflectionMethod.LIST_GET_STRING.run(listObject, index);
if (ret instanceof Optional<?>) {
return ((Optional<String>) ret).orElse("");
}
return (String) ret;
} catch (Exception ex) {
throw new NbtApiException(ex);
}
@@ -8,14 +8,16 @@ package de.tr7zw.changeme.nbtapi;
*/
@SuppressWarnings("javadoc")
public enum NBTType {
NBTTagEnd(0), NBTTagByte(1), NBTTagShort(2), NBTTagInt(3), NBTTagLong(4), NBTTagFloat(5), NBTTagDouble(6),
NBTTagByteArray(7), NBTTagString(8), NBTTagList(9), NBTTagCompound(10), NBTTagIntArray(11), NBTTagLongArray(12);
NBTTagEnd(0, ""), NBTTagByte(1, "BYTE"), NBTTagShort(2, "SHORT"), NBTTagInt(3, "INT"), NBTTagLong(4, "LONG"), NBTTagFloat(5, "FLOAT"), NBTTagDouble(6, "DOUBLE"),
NBTTagByteArray(7, "BYTE[]"), NBTTagString(8, "STRING"), NBTTagList(9, "LIST"), NBTTagCompound(10, "COMPOUND"), NBTTagIntArray(11, "INT[]"), NBTTagLongArray(12, "LONG[]");
NBTType(int i) {
NBTType(int i, String name) {
id = i;
this.name = name;
}
private final int id;
private final String name;
/**
* @return Id used by Minecraft internally
@@ -23,6 +25,13 @@ public enum NBTType {
public int getId() {
return id;
}
/**
* @return Name of the NBTType
*/
public String getName() {
return name;
}
/**
* @param id Internal Minecraft id
@@ -35,4 +44,11 @@ public enum NBTType {
return NBTType.NBTTagEnd;
}
public static NBTType fromName(String name) {
for (NBTType t : values())
if (t.getName().equals(name))
return t;
return NBTType.NBTTagEnd;
}
}
@@ -0,0 +1,20 @@
package de.tr7zw.changeme.nbtapi.iface;
import java.io.File;
import java.io.IOException;
public interface NBTFileHandle extends ReadWriteNBT {
/**
* Saves the data to the file
*
* @throws IOException
*/
void save() throws IOException;
/**
* @return The File used to store the data
*/
File getFile();
}
@@ -10,6 +10,15 @@ public interface ReadWriteNBTCompoundList extends ReadableNBTList<ReadWriteNBT>
* @return A new instance of the class.
*/
ReadWriteNBT addCompound();
/**
* 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
*/
ReadWriteNBT addCompound(ReadableNBT comp);
/**
* Removes the element at the specified position in this list
@@ -344,6 +344,17 @@ public interface ReadableNBT {
*/
void writeCompound(OutputStream stream);
/**
* Compares this readable nbt to the other one
* and returns the difference.
* <p>Note: the result will only contain data that is present
* in this readable nbt and is missing/different in the provided one.
*
* @param other other readable nbt
* @return difference between readable nbts
*/
ReadWriteNBT extractDifference(ReadableNBT other);
/**
* @return The NBT as printable NBT-Json.
*/
@@ -5,41 +5,73 @@ import com.mojang.datafixers.DataFixer;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTReflectionUtil;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
public class DataFixerUtil {
// these values can be found in DetectedVersion inside mc
// Finding pre 1.12.2 values is left as an exercise for the reader,
// as DetectedVersion is not a thing there
// https://minecraft.wiki/w/Data_version
public static final int VERSION1_12R1 = 1343;
public static final int VERSION1_16R1 = 2586;
public static final int VERSION1_17R1 = 2730;
public static final int VERSION1_18R1 = 2975;
public static final int VERSION1_19R1 = 3120;
public static final int VERSION1_19R3 = 3337;
public static final int VERSION1_20R1 = 3465;
public static final int VERSION1_20R2 = 3578;
public static final int VERSION1_20R3 = 3700;
public static final int VERSION1_20R4 = 3837;
public static final int VERSION1_21R1 = 3953;
public static final int VERSION1_21R2 = 4080;
public static final int VERSION1_21R3 = 4189;
public static final int VERSION1_21R4 = 4323;
public static final int VERSION1_21R5 = 4435;
public static final int VERSION1_21R6 = 4554;
public static final int VERSION1_21R7 = 4671;
// There was a mixup between version numbers and revisions, kept for compatibility, use the above revision numbers
@Deprecated
public static final int VERSION1_12_2 = 1343;
@Deprecated
public static final int VERSION1_16_5 = 2586;
@Deprecated
public static final int VERSION1_17_1 = 2730;
@Deprecated
public static final int VERSION1_18_2 = 2975;
@Deprecated
public static final int VERSION1_19_2 = 3120;
@Deprecated
public static final int VERSION1_19_4 = 3337;
@Deprecated
public static final int VERSION1_20_1 = 3465;
@Deprecated
public static final int VERSION1_20_2 = 3578;
@Deprecated
public static final int VERSION1_20_4 = 3700;
@Deprecated
public static final int VERSION1_20_5 = 3837;
// the 1.21 versions use Revision instead of patch versions, unlike the other above. kept for compatibility
@Deprecated
public static final int VERSION1_21 = 3953;
@Deprecated
public static final int VERSION1_21_2 = 4080;
@Deprecated
public static final int VERSION1_21_3 = 4189;
@Deprecated
public static final int VERSION1_21_4 = 4323;
@Deprecated
public static final int VERSION1_21_5 = 4435;
@SuppressWarnings("unchecked")
public static Object fixUpRawItemData(Object nbt, int fromVersion, int toVersion)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
DataFixer dataFixer = (DataFixer) ReflectionMethod.GET_DATAFIXER.run(null);
TypeReference itemStackReference = (TypeReference) ClassWrapper.NMS_REFERENCES.getClazz()
.getField(MojangToMapping.getMapping().get("net.minecraft.util.datafix.fixes.References#ITEM_STACK"))
.get(null);
DynamicOps<Object> nbtOps = (DynamicOps<Object>) ClassWrapper.NMS_NBTOPS.getClazz()
.getField(MojangToMapping.getMapping().get("net.minecraft.nbt.NbtOps#INSTANCE")).get(null);
TypeReference itemStackReference = (TypeReference) ReflectionUtil.getMappedField(ClassWrapper.NMS_REFERENCES.getClazz(),"net.minecraft.util.datafix.fixes.References#ITEM_STACK").get(null);
DynamicOps<Object> nbtOps = (DynamicOps<Object>) ReflectionUtil.getMappedField(ClassWrapper.NMS_NBTOPS.getClazz(), "net.minecraft.nbt.NbtOps#INSTANCE").get(null);
Dynamic<Object> fixed = dataFixer.update(itemStackReference, new Dynamic<Object>(nbtOps, nbt), fromVersion,
toVersion);
return fixed.getValue();
@@ -47,7 +79,7 @@ public class DataFixerUtil {
public static ReadWriteNBT fixUpItemData(ReadWriteNBT nbt, int fromVersion, int toVersion)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
return new NBTContainer(fixUpRawItemData(
return NBT.wrapNMSTag(fixUpRawItemData(
NBTReflectionUtil.getToCompount(((NBTCompound) nbt).getCompound(), ((NBTCompound) nbt)), fromVersion,
toVersion));
}
@@ -62,26 +94,39 @@ public class DataFixerUtil {
* @return
*/
public static int getCurrentVersion() {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R1)) {
return VERSION1_21;
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R7)) {
return VERSION1_21R7;
}else
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
return VERSION1_21R6;
}else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R5)) {
return VERSION1_21R5;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
return VERSION1_21R4;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R3)) {
return VERSION1_21R3;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R2)) {
return VERSION1_21R2;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R1)) {
return VERSION1_21R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
return VERSION1_20_5;
return VERSION1_20R4;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R3)) {
return VERSION1_20_4;
return VERSION1_20R3;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R1)) {
return VERSION1_20_1;
return VERSION1_20R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_19_R3)) {
return VERSION1_19_4;
return VERSION1_19R3;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_19_R1)) {
return VERSION1_19_2;
return VERSION1_19R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_18_R1)) {
return VERSION1_18_2;
return VERSION1_18R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_17_R1)) {
return VERSION1_17_1;
return VERSION1_17R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1)) {
return VERSION1_16_5;
return VERSION1_16R1;
} else if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)) {
return VERSION1_12_2;
return VERSION1_12R1;
}
throw new NbtApiException(
"Trying to update data *to* a version before 1.12.2? Something is probably going wrong, contact the plugin author.");
@@ -1,12 +1,16 @@
package de.tr7zw.changeme.nbtapi.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
import javax.annotation.Nullable;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.PropertyMap;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
import de.tr7zw.changeme.nbtapi.iface.ReadableNBT;
@@ -14,15 +18,42 @@ import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList;
public class GameprofileUtil {
private static Method GET_NAME = null;
private static Method GET_ID = null;
private static Method GET_VALUE = null;
private static Method GET_SIGNATURE = null;
private static Method GET_PROPERTY_NAME = null;
private static Method GET_PROPERTIES = null;
static {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
GET_NAME = GameProfile.class.getDeclaredMethod("name");
GET_ID = GameProfile.class.getDeclaredMethod("id");
GET_VALUE = com.mojang.authlib.properties.Property.class.getDeclaredMethod("value");
GET_SIGNATURE = com.mojang.authlib.properties.Property.class.getDeclaredMethod("signature");
GET_PROPERTY_NAME = com.mojang.authlib.properties.Property.class.getDeclaredMethod("name");
GET_PROPERTIES = GameProfile.class.getDeclaredMethod("properties");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
@Nullable
public static GameProfile readGameProfile(ReadableNBT arg) {
String string = null;
UUID uUID = null;
if (arg.hasTag("Name") && arg.getType("Name") == NBTType.NBTTagString) {
string = arg.getString("Name");
} else if (arg.hasTag("name") && arg.getType("name") == NBTType.NBTTagString) {
string = arg.getString("name");
}
if (arg.hasTag("Id") && arg.getType("Id") == NBTType.NBTTagIntArray && arg.getIntArray("Id").length == 4) {
uUID = arg.getUUID("Id");
} else if (arg.hasTag("id") && arg.getType("id") == NBTType.NBTTagIntArray
&& arg.getIntArray("id").length == 4) {
uUID = arg.getUUID("id");
}
try {
GameProfile gameProfile = new GameProfile(uUID, string);
@@ -43,6 +74,21 @@ public class GameprofileUtil {
}
}
}
} else if (arg.getType("properties") == NBTType.NBTTagList) { // 1.20.5+
ReadableNBTList<ReadWriteNBT> listTag = arg.getCompoundList("properties");
for (int i = 0; i < listTag.size(); ++i) {
ReadableNBT compoundTag2 = listTag.get(i);
String string2 = compoundTag2.getString("name");
String string3 = compoundTag2.getString("value");
if (compoundTag2.hasTag("signature")
&& compoundTag2.getType("signature") == NBTType.NBTTagString) {
gameProfile.getProperties().put(string2, new com.mojang.authlib.properties.Property(string2,
string3, compoundTag2.getString("signature")));
} else {
gameProfile.getProperties().put(string2,
new com.mojang.authlib.properties.Property(string2, string3));
}
}
}
return gameProfile;
} catch (Throwable var11) {
@@ -51,26 +97,115 @@ public class GameprofileUtil {
}
public static ReadWriteNBT writeGameProfile(ReadWriteNBT arg, GameProfile gameProfile) {
if (!(gameProfile.getName() == null || gameProfile.getName().isEmpty())) {
arg.setString("Name", gameProfile.getName());
String name = getName(gameProfile);
if (!(name == null || name.isEmpty())) {
String nameKey = MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) ? "name" : "Name";
arg.setString(nameKey, getName(gameProfile));
}
if (gameProfile.getId() != null) {
arg.setUUID("Id", gameProfile.getId());
UUID id = getId(gameProfile);
if (id != null) {
String idKey = MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) ? "id" : "Id";
arg.setUUID(idKey, id);
}
if (!gameProfile.getProperties().isEmpty()) {
ReadWriteNBT compoundTag = arg.getOrCreateCompound("Properties");
for (String string : gameProfile.getProperties().keySet()) {
ReadWriteNBTCompoundList list = compoundTag.getCompoundList(string);
for (com.mojang.authlib.properties.Property property : gameProfile.getProperties().get(string)) {
ReadWriteNBT tag = list.addCompound();
tag.setString("Value", property.getValue());
if (property.hasSignature()) {
tag.setString("Signature", property.getSignature());
PropertyMap properties = getProperties(gameProfile);
if (!properties.isEmpty()) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
ReadWriteNBTCompoundList list = arg.getCompoundList("properties");
for (com.mojang.authlib.properties.Property property : properties.values()) {
ReadWriteNBT tag = list.addCompound();
tag.setString("name", getPropertyName(property));
tag.setString("value", getValue(property));
if (property.hasSignature()) {
tag.setString("signature", getSignature(property));
}
}
} else {
ReadWriteNBT compoundTag = arg.getOrCreateCompound("Properties");
for (String string : gameProfile.getProperties().keySet()) {
ReadWriteNBTCompoundList list = compoundTag.getCompoundList(string);
for (com.mojang.authlib.properties.Property property : properties.get(string)) {
ReadWriteNBT tag = list.addCompound();
tag.setString("Value", getValue(property));
if (property.hasSignature()) {
tag.setString("Signature", getSignature(property));
}
}
}
}
}
return arg;
}
private static String getName(GameProfile profile) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return GET_NAME.invoke(profile).toString();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get GameProfile name via reflection", e);
}
} else {
return profile.getName();
}
}
private static UUID getId(GameProfile profile) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return (UUID) GET_ID.invoke(profile);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get GameProfile id via reflection", e);
}
} else {
return profile.getId();
}
}
private static String getValue(com.mojang.authlib.properties.Property property) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return GET_VALUE.invoke(property).toString();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get Property value via reflection", e);
}
} else {
return property.getValue();
}
}
private static String getSignature(com.mojang.authlib.properties.Property property) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return GET_SIGNATURE.invoke(property).toString();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get Property signature via reflection", e);
}
} else {
return property.getSignature();
}
}
private static String getPropertyName(com.mojang.authlib.properties.Property property) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return GET_PROPERTY_NAME.invoke(property).toString();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get Property name via reflection", e);
}
} else {
return property.getName();
}
}
private static PropertyMap getProperties(GameProfile profile) {
if(MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R6)) {
try {
return (PropertyMap) GET_PROPERTIES.invoke(profile);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new NbtApiException("Failed to get GameProfile properties via reflection", e);
}
} else {
return profile.getProperties();
}
}
}
@@ -1,881 +0,0 @@
/*
* This Metrics class was auto-generated and can be copied into your project if you are
* not using a build tool like Gradle or Maven for dependency management.
*
* IMPORTANT: You are not allowed to modify this class, except changing the package.
*
* Disallowed modifications include but are not limited to:
* - Remove the option for users to opt-out
* - Change the frequency for data submission
* - Obfuscate the code (every obfuscator should allow you to make an exception for specific files)
* - Reformat the code (if you use a linter, add an exception)
*
* Violations will result in a ban of your plugin and account from bStats.
*/
package de.tr7zw.changeme.nbtapi.utils;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;
import javax.net.ssl.HttpsURLConnection;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
public class Metrics {
private final Plugin plugin;
private final MetricsBase metricsBase;
/**
* Creates a new Metrics instance.
*
* @param plugin Your plugin instance.
* @param serviceId The id of the service. It can be found at <a
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
*/
public Metrics(JavaPlugin plugin, int serviceId) {
this.plugin = plugin;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
if (!config.isSet("serverUuid")) {
config.addDefault("enabled", true);
config.addDefault("serverUuid", UUID.randomUUID().toString());
config.addDefault("logFailedRequests", false);
config.addDefault("logSentData", false);
config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config
.options()
.header(
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
+ "anonymous.")
.copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) {
}
}
// Load the data
boolean enabled = config.getBoolean("enabled", true);
String serverUUID = config.getString("serverUuid");
boolean logErrors = config.getBoolean("logFailedRequests", false);
boolean logSentData = config.getBoolean("logSentData", false);
boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false);
metricsBase =
new MetricsBase(
"bukkit",
serverUUID,
serviceId,
enabled,
this::appendPlatformData,
this::appendServiceData,
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
plugin::isEnabled,
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
(message) -> this.plugin.getLogger().log(Level.INFO, message),
logErrors,
logSentData,
logResponseStatusText);
}
/** Shuts down the underlying scheduler service. */
public void shutdown() {
metricsBase.shutdown();
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
metricsBase.addCustomChart(chart);
}
private void appendPlatformData(JsonObjectBuilder builder) {
builder.appendField("playerAmount", getPlayerAmount());
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
builder.appendField("bukkitVersion", Bukkit.getVersion());
builder.appendField("bukkitName", Bukkit.getName());
builder.appendField("javaVersion", System.getProperty("java.version"));
builder.appendField("osName", System.getProperty("os.name"));
builder.appendField("osArch", System.getProperty("os.arch"));
builder.appendField("osVersion", System.getProperty("os.version"));
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
}
private void appendServiceData(JsonObjectBuilder builder) {
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
}
private int getPlayerAmount() {
try {
// Around MC 1.8 the return type was changed from an array to a collection,
// This fixes java.lang.NoSuchMethodError:
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
return onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
// Just use the new method if the reflection failed
return Bukkit.getOnlinePlayers().size();
}
}
public static class MetricsBase {
/** The version of the Metrics class. */
public static final String METRICS_VERSION = "3.0.2";
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
private final ScheduledExecutorService scheduler;
private final String platform;
private final String serverUuid;
private final int serviceId;
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
private final Consumer<Runnable> submitTaskConsumer;
private final Supplier<Boolean> checkServiceEnabledSupplier;
private final BiConsumer<String, Throwable> errorLogger;
private final Consumer<String> infoLogger;
private final boolean logErrors;
private final boolean logSentData;
private final boolean logResponseStatusText;
private final Set<CustomChart> customCharts = new HashSet<>();
private final boolean enabled;
/**
* Creates a new MetricsBase class instance.
*
* @param platform The platform of the service.
* @param serviceId The id of the service.
* @param serverUuid The server uuid.
* @param enabled Whether or not data sending is enabled.
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all platform-specific data.
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all service-specific data.
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
* used to delegate the data collection to a another thread to prevent errors caused by
* concurrency. Can be {@code null}.
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
* @param errorLogger A consumer that accepts log message and an error.
* @param infoLogger A consumer that accepts info log messages.
* @param logErrors Whether or not errors should be logged.
* @param logSentData Whether or not the sent data should be logged.
* @param logResponseStatusText Whether or not the response status text should be logged.
*/
public MetricsBase(
String platform,
String serverUuid,
int serviceId,
boolean enabled,
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
Consumer<Runnable> submitTaskConsumer,
Supplier<Boolean> checkServiceEnabledSupplier,
BiConsumer<String, Throwable> errorLogger,
Consumer<String> infoLogger,
boolean logErrors,
boolean logSentData,
boolean logResponseStatusText) {
ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(1, task -> new Thread(task, "bStats-Metrics"));
// We want delayed tasks (non-periodic) that will execute in the future to be
// cancelled when the scheduler is shutdown.
// Otherwise, we risk preventing the server from shutting down even when
// MetricsBase#shutdown() is called
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
this.scheduler = scheduler;
this.platform = platform;
this.serverUuid = serverUuid;
this.serviceId = serviceId;
this.enabled = enabled;
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
this.appendServiceDataConsumer = appendServiceDataConsumer;
this.submitTaskConsumer = submitTaskConsumer;
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
this.errorLogger = errorLogger;
this.infoLogger = infoLogger;
this.logErrors = logErrors;
this.logSentData = logSentData;
this.logResponseStatusText = logResponseStatusText;
checkRelocation();
if (enabled) {
// WARNING: Removing the option to opt-out will get your plugin banned from
// bStats
startSubmitting();
}
}
public void addCustomChart(CustomChart chart) {
this.customCharts.add(chart);
}
public void shutdown() {
scheduler.shutdown();
}
private void startSubmitting() {
final Runnable submitTask =
() -> {
if (!enabled || !checkServiceEnabledSupplier.get()) {
// Submitting data or service is disabled
scheduler.shutdown();
return;
}
if (submitTaskConsumer != null) {
submitTaskConsumer.accept(this::submitData);
} else {
this.submitData();
}
};
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven
// distribution of requests on the
// bStats backend. To circumvent this problem, we introduce some randomness into
// the initial and second delay.
// WARNING: You must not modify and part of this Metrics class, including the
// submit delay or frequency!
// WARNING: Modifying this code will get your plugin banned on bStats. Just
// don't do it!
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
scheduler.scheduleAtFixedRate(
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
}
private void submitData() {
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
appendPlatformDataConsumer.accept(baseJsonBuilder);
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
appendServiceDataConsumer.accept(serviceJsonBuilder);
JsonObjectBuilder.JsonObject[] chartData =
customCharts.stream()
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
.filter(Objects::nonNull)
.toArray(JsonObjectBuilder.JsonObject[]::new);
serviceJsonBuilder.appendField("id", serviceId);
serviceJsonBuilder.appendField("customCharts", chartData);
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
baseJsonBuilder.appendField("serverUUID", serverUuid);
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
scheduler.execute(
() -> {
try {
// Send the data
sendData(data);
} catch (Exception e) {
// Something went wrong! :(
if (logErrors) {
errorLogger.accept("Could not submit bStats metrics data", e);
}
}
});
}
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
if (logSentData) {
infoLogger.accept("Sent bStats metrics data: " + data.toString());
}
String url = String.format(REPORT_URL, platform);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
}
StringBuilder builder = new StringBuilder();
try (BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
if (logResponseStatusText) {
infoLogger.accept("Sent data to bStats and received response: " + builder);
}
}
/** Checks that the class was properly relocated. */
private void checkRelocation() {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this
// little "trick" ... :D
final String defaultPackage =
new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
final String examplePackage =
new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure no one just copy & pastes the example and uses the wrong
// package names
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
/**
* Gzips the given string.
*
* @param str The string to gzip.
* @return The gzipped string.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
gzip.write(str.getBytes(StandardCharsets.UTF_8));
}
return outputStream.toByteArray();
}
}
public static class SimplePie extends CustomChart {
private final Callable<String> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimplePie(String chartId, Callable<String> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
public static class MultiLineChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class AdvancedPie extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class SimpleBarChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()});
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class AdvancedBarChart extends CustomChart {
private final Callable<Map<String, int[]>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> entry : map.entrySet()) {
if (entry.getValue().length == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class DrilldownPie extends CustomChart {
private final Callable<Map<String, Map<String, Integer>>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public abstract static class CustomChart {
private final String chartId;
protected CustomChart(String chartId) {
if (chartId == null) {
throw new IllegalArgumentException("chartId must not be null");
}
this.chartId = chartId;
}
public JsonObjectBuilder.JsonObject getRequestJsonObject(
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
JsonObjectBuilder builder = new JsonObjectBuilder();
builder.appendField("chartId", chartId);
try {
JsonObjectBuilder.JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
builder.appendField("data", data);
} catch (Throwable t) {
if (logErrors) {
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return builder.build();
}
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
}
public static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
/**
* An extremely simple JSON builder.
*
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
* for its use-case.
*/
public static class JsonObjectBuilder {
private StringBuilder builder = new StringBuilder();
private boolean hasAtLeastOneField = false;
public JsonObjectBuilder() {
builder.append("{");
}
/**
* Appends a null field to the JSON.
*
* @param key The key of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendNull(String key) {
appendFieldUnescaped(key, "null");
return this;
}
/**
* Appends a string field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String value) {
if (value == null) {
throw new IllegalArgumentException("JSON value must not be null");
}
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
return this;
}
/**
* Appends an integer field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int value) {
appendFieldUnescaped(key, String.valueOf(value));
return this;
}
/**
* Appends an object to the JSON.
*
* @param key The key of the field.
* @param object The object.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject object) {
if (object == null) {
throw new IllegalArgumentException("JSON object must not be null");
}
appendFieldUnescaped(key, object.toString());
return this;
}
/**
* Appends a string array to the JSON.
*
* @param key The key of the field.
* @param values The string array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values)
.map(value -> "\"" + escape(value) + "\"")
.collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an integer array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an object array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends a field to the object.
*
* @param key The key of the field.
* @param escapedValue The escaped value of the field.
*/
private void appendFieldUnescaped(String key, String escapedValue) {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
if (key == null) {
throw new IllegalArgumentException("JSON key must not be null");
}
if (hasAtLeastOneField) {
builder.append(",");
}
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
hasAtLeastOneField = true;
}
/**
* Builds the JSON string and invalidates this builder.
*
* @return The built JSON string.
*/
public JsonObject build() {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
JsonObject object = new JsonObject(builder.append("}").toString());
builder = null;
return object;
}
/**
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
*
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
*
* @param value The value to escape.
* @return The escaped value.
*/
private static String escape(String value) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (c == '"') {
builder.append("\\\"");
} else if (c == '\\') {
builder.append("\\\\");
} else if (c <= '\u000F') {
builder.append("\\u000").append(Integer.toHexString(c));
} else if (c <= '\u001F') {
builder.append("\\u00").append(Integer.toHexString(c));
} else {
builder.append(c);
}
}
return builder.toString();
}
/**
* A super simple representation of a JSON object.
*
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
* JsonObject)}.
*/
public static class JsonObject {
private final String value;
private JsonObject(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
}
}
@@ -5,10 +5,16 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.DrilldownPie;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
/**
* This class acts as the "Brain" of the NBTApi. It contains the main logger for
* other classes,registers bStats and checks rather Maven shading was done
@@ -24,11 +30,14 @@ public enum MinecraftVersion {
MC1_13_R1(1131), MC1_13_R2(1132), MC1_14_R1(1141), MC1_15_R1(1151), MC1_16_R1(1161), MC1_16_R2(1162),
MC1_16_R3(1163), MC1_17_R1(1171), MC1_18_R1(1181, true), MC1_18_R2(1182, true), MC1_19_R1(1191, true),
MC1_19_R2(1192, true), MC1_19_R3(1193, true), MC1_20_R1(1201, true), MC1_20_R2(1202, true), MC1_20_R3(1203, true),
MC1_20_R4(1204, true), MC1_21_R1(1211, true);
MC1_20_R4(1204, true), MC1_21_R1(1211, true), MC1_21_R2(1212, true), MC1_21_R3(1213, true), MC1_21_R4(1214, true),
MC1_21_R5(1215, true), MC1_21_R6(1216, true), MC1_21_R7(1217, true);
private static MinecraftVersion version;
private static Boolean hasGsonSupport;
private static Boolean isForgePresent;
private static Boolean isNeoForgePresent;
private static Boolean isFabricPresent;
private static Boolean isFoliaPresent;
private static boolean bStatsDisabled = false;
private static boolean disablePackageWarning = false;
@@ -39,7 +48,7 @@ public enum MinecraftVersion {
private static Logger logger = Logger.getLogger("NBTAPI");
// NBT-API Version
protected static final String VERSION = "2.13.2";
protected static final String VERSION = "2.15.4";
private final int versionId;
private final boolean mojangMapping;
@@ -57,6 +66,15 @@ public enum MinecraftVersion {
this.put("1.20.6", MC1_20_R4);
this.put("1.21", MC1_21_R1);
this.put("1.21.1", MC1_21_R1);
this.put("1.21.2", MC1_21_R2);
this.put("1.21.3", MC1_21_R2);
this.put("1.21.4", MC1_21_R3);
this.put("1.21.5", MC1_21_R4);
this.put("1.21.6", MC1_21_R5);
this.put("1.21.7", MC1_21_R5);
this.put("1.21.8", MC1_21_R5);
this.put("1.21.9", MC1_21_R6);
this.put("1.21.10", MC1_21_R6);
}
};
@@ -158,13 +176,70 @@ public enum MinecraftVersion {
}
private static void init() {
// 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',
'a', 'n', 'g', 'e', 'm', 'e', '.', 'n', 'b', 't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
final String reservedPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'n', 'b',
't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
try {
if (hasGsonSupport() && !bStatsDisabled) {
Plugin plugin = Bukkit.getPluginManager().getPlugin(VersionChecker.getPlugin());
if (plugin != null && plugin instanceof JavaPlugin) {
getLogger()
.info("[NBTAPI] Using the plugin '" + plugin.getName() + "' to create a bStats instance!");
new Metrics((JavaPlugin) plugin, 1058);
Metrics metrics = new Metrics((JavaPlugin) plugin, 1058);
metrics.addCustomChart(new SimplePie("nbtapi_version", () -> {
return VERSION;
}));
metrics.addCustomChart(new DrilldownPie("nms_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
Map<String, Integer> entry = new HashMap<>();
entry.put(Bukkit.getName(), 1);
map.put(getVersion().name(), entry);
return map;
}));
metrics.addCustomChart(new SimplePie("shaded", () -> {
return Boolean.toString(!"NBTAPI".equals(VersionChecker.getPlugin()));
}));
metrics.addCustomChart(new SimplePie("server_software", () -> {
return Bukkit.getName();
}));
metrics.addCustomChart(new SimplePie("parent_plugin", () -> {
return VersionChecker.getPluginforBStats();
}));
metrics.addCustomChart(new SimplePie("parent_plugin_type", () -> {
return VersionChecker.getPluginType();
}));
metrics.addCustomChart(new SimplePie("special_environment", () -> {
if (isFoliaPresent()) {
return "Folia";
} else if (isForgePresent()) {
return "Forge";
} else if (isFabricPresent()) {
return "Fabric";
} else if (isNeoForgePresent()) {
return "NeoForge";
} else {
return "None";
}
}));
metrics.addCustomChart(new SimplePie("bindings_check", () -> {
boolean failedBinding = false;
for (ClassWrapper c : ClassWrapper.values()) {
if (c.isEnabled() && c.getClazz() == null) {
failedBinding = true;
}
}
for (ReflectionMethod method : ReflectionMethod.values()) {
if (method.isCompatible() && !method.isLoaded()) {
failedBinding = true;
}
}
return failedBinding ? "Failed" : "Pass";
}));
} else if (plugin == null) {
getLogger().info("[NBTAPI] Unable to create a bStats instance!!");
}
@@ -181,12 +256,6 @@ public enum MinecraftVersion {
logger.log(Level.WARNING, "[NBTAPI] Error while checking for updates! Error: " + ex.getMessage());
}
}).start();
// 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',
'a', 'n', 'g', 'e', 'm', 'e', '.', 'n', 'b', 't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
final String reservedPackage = new String(new byte[] { 'd', 'e', '.', 't', 'r', '7', 'z', 'w', '.', 'n', 'b',
't', 'a', 'p', 'i', '.', 'u', 't', 'i', 'l', 's' });
if (!disablePackageWarning && MinecraftVersion.class.getPackage().getName().equals(defaultPackage)) {
logger.warning(
"#########################################- NBTAPI -#########################################");
@@ -246,6 +315,22 @@ public enum MinecraftVersion {
return hasGsonSupport;
}
/**
* @return True, if Fabric is present
*/
public static boolean isFabricPresent() {
if (isFabricPresent != null) {
return isFabricPresent;
}
try {
logger.info("[NBTAPI] Found Fabric: " + Class.forName("net.fabricmc.api.ModInitializer"));
isFabricPresent = true;
} catch (Exception ex) {
isFabricPresent = false;
}
return isFabricPresent;
}
/**
* @return True, if Forge is present
*/
@@ -263,6 +348,22 @@ public enum MinecraftVersion {
}
return isForgePresent;
}
/**
* @return True, if NeoForge is present
*/
public static boolean isNeoForgePresent() {
if (isNeoForgePresent != null) {
return isNeoForgePresent;
}
try {
logger.info("[NBTAPI] Found NeoForge: " + Class.forName("net.neoforged.neoforge.common.NeoForge"));
isNeoForgePresent = true;
} catch (Exception ex) {
isNeoForgePresent = false;
}
return isNeoForgePresent;
}
/**
* @return True, if Folia is present
@@ -0,0 +1,41 @@
package de.tr7zw.changeme.nbtapi.utils;
import java.util.Optional;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod;
public class NBTJsonUtil {
/**
* 1.20.3-1.21.4 only. Used to convert items into Json, used in Chat Hover Components.
*
* @param itemStack
* @return
* @throws NbtApiException
*/
@SuppressWarnings("unchecked")
public static JsonElement itemStackToJson(ItemStack itemStack) {
try {
Codec<Object> itemStackCodec = (Codec<Object>) ClassWrapper.NMS_ITEMSTACK.getClazz()
.getField(MojangToMapping.getMapping().get("net.minecraft.world.item.ItemStack#CODEC")).get(null);
Object stack = ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, itemStack);
DataResult<JsonElement> result = itemStackCodec.encode(stack, JsonOps.INSTANCE,
JsonOps.INSTANCE.emptyMap());
Optional<JsonElement> opt = (Optional<JsonElement>) result.getClass().getMethod("result").invoke(result);
return opt.orElse(null);
} catch (Exception ex) {
throw new NbtApiException("Error trying to get Json of an ItemStack.", ex);
}
}
}
@@ -1,53 +1,24 @@
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;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.MojangToMapping;
public final class ReflectionUtil {
private static Field field_modifiers;
static {
public static Field getMappedField(Class<?> clazz, String mapping) {
String mojmapName = mapping.split("#")[1];
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);
}
return clazz.getField(mojmapName);
} catch (NoSuchFieldException | SecurityException e) {
// not Mojamp, try remapped
}
if (field_modifiers == null) {
throw new NbtApiException("Unable to init the modifiers Field.");
try {
return clazz.getDeclaredField(MojangToMapping.getMapping().get(mapping));
} catch (Exception e) {
throw new NbtApiException("Unable to find field " + mapping + " in class " + clazz.getName(), e);
}
}
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);
}
}
@@ -109,7 +109,20 @@ public class VersionChecker {
protected static String getPlugin() {
ClassLoader classLoader = VersionChecker.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("plugin.yml");
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
if (inputStream != null) {
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
return pluginYml.getString("name");
} catch (IOException e) {
// ignored
} catch (IllegalArgumentException e) {
// This can happen if the paper-plugin.yml is not formatted correctly
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading paper-plugin.yml: " + e.getMessage());
}
}
inputStream = classLoader.getResourceAsStream("plugin.yml");
if (inputStream != null) {
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
@@ -117,9 +130,67 @@ public class VersionChecker {
return pluginYml.getString("name");
} catch (IOException e) {
// ignored
} catch (IllegalArgumentException e) {
// This can happen if the plugin.yml is not formatted correctly
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading plugin.yml: " + e.getMessage());
}
}
return NBTItem.class.getPackage().getName();
}
protected static String getPluginforBStats() {
ClassLoader classLoader = VersionChecker.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
if (inputStream != null) {
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
return pluginYml.getString("name");
} catch (IOException e) {
// ignored
} catch (IllegalArgumentException e) {
// This can happen if the paper-plugin.yml is not formatted correctly
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading paper-plugin.yml: " + e.getMessage());
}
}
inputStream = classLoader.getResourceAsStream("plugin.yml");
if (inputStream != null) {
try (InputStreamReader reader = new InputStreamReader(inputStream)) {
YamlConfiguration pluginYml = YamlConfiguration.loadConfiguration(reader);
return pluginYml.getString("name");
} catch (IOException e) {
// ignored
} catch (IllegalArgumentException e) {
// This can happen if the plugin.yml is not formatted correctly
MinecraftVersion.getLogger().log(Level.WARNING, "[NBTAPI] Error reading plugin.yml: " + e.getMessage());
}
}
return "UnknownPlugin";
}
protected static String getPluginType() {
ClassLoader classLoader = VersionChecker.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("paper-plugin.yml");
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// ignored
}
return "PaperPlugin";
}
inputStream = classLoader.getResourceAsStream("plugin.yml");
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// ignored
}
return "SpigotPlugin";
}
return "UnknownPlugin";
}
}
@@ -24,6 +24,7 @@ public enum ClassWrapper {
CRAFT_PERSISTENTDATACONTAINER(PackageWrapper.CRAFTBUKKIT, "persistence.CraftPersistentDataContainer",
MinecraftVersion.MC1_14_R1, null),
NMS_NBTBASE(PackageWrapper.NMS, "NBTBase", null, null, "net.minecraft.nbt", "net.minecraft.nbt.Tag"),
NMS_TAGTYPE(PackageWrapper.NMS, "NBTTagType", MinecraftVersion.MC1_21_R4, null, "net.minecraft.nbt", "net.minecraft.nbt.TagType"),
NMS_NBTTAGSTRING(PackageWrapper.NMS, "NBTTagString", null, null, "net.minecraft.nbt",
"net.minecraft.nbt.StringTag"),
NMS_NBTTAGINT(PackageWrapper.NMS, "NBTTagInt", null, null, "net.minecraft.nbt", "net.minecraft.nbt.IntTag"),
@@ -85,6 +86,18 @@ public enum ClassWrapper {
"net.minecraft.util.datafix.fixes", "net.minecraft.util.datafix.fixes.References"),
NMS_NBTOPS(PackageWrapper.NMS, "DynamicOpsNBT", MinecraftVersion.MC1_20_R4, null,
"net.minecraft.nbt", "net.minecraft.nbt.NbtOps"),
NMS_PROBLEM_REPORTER(PackageWrapper.NMS, "ProblemReporter", MinecraftVersion.MC1_21_R5, null,
"net.minecraft.util", "net.minecraft.util.ProblemReporter"),
NMS_TAG_VALUE_INPUT(PackageWrapper.NMS, "TagValueInput", MinecraftVersion.MC1_21_R5, null,
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.TagValueInput"),
NMS_VALUE_INPUT(PackageWrapper.NMS, "ValueInput", MinecraftVersion.MC1_21_R5, null,
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.ValueInput"),
NMS_TAG_VALUE_OUTPUT(PackageWrapper.NMS, "TagValueOutput", MinecraftVersion.MC1_21_R5, null,
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.TagValueOutput"),
NMS_VALUE_OUTPUT(PackageWrapper.NMS, "ValueOutput", MinecraftVersion.MC1_21_R5, null,
"net.minecraft.world.level.storage", "net.minecraft.world.level.storage.ValueOutput"),
NMS_DYNAMICOPS(PackageWrapper.NONE, "DynamicOps", MinecraftVersion.MC1_21_R5, null,
"com.mojang.serialization", "com.mojang.serialization.DynamicOps"),
GAMEPROFILE(PackageWrapper.NONE, "com.mojang.authlib.GameProfile", MinecraftVersion.MC1_8_R3, null);
private Class<?> clazz;
@@ -0,0 +1,35 @@
package de.tr7zw.changeme.nbtapi.utils.nmsmappings;
import java.util.Objects;
import java.util.Optional;
import de.tr7zw.changeme.nbtapi.NBTReflectionUtil;
import de.tr7zw.changeme.nbtapi.NbtApiException;
public class CodecHelper {
public static Object convertItemStackToNbt(Object itemStack) {
Object result = null;
try {
// FIXME caching, this has 0 exception handling
result = NBTReflectionUtil.itemstack_codec.encodeStart(NBTReflectionUtil.nbtRegistryOps, itemStack);
Objects.requireNonNull(result);
return ((Optional<Object>)result.getClass().getMethod("result").invoke(result)).get();
} catch (Exception e) {
throw new NbtApiException("Failed to convert ItemStack to NBT. " + result + " " + itemStack, e);
}
}
public static Object convertNbtToItemStack(Object nbt) {
Object result = null;
try {
// FIXME caching, this has 0 exception handling
result = NBTReflectionUtil.itemstack_codec.parse(NBTReflectionUtil.nbtRegistryOps, nbt);
Objects.requireNonNull(result);
return ((Optional<Object>)result.getClass().getMethod("result").invoke(result)).get();
} catch (Exception e) {
throw new NbtApiException("Failed to convert NBT to ItemStack. " + result + " " + nbt, e);
}
}
}
@@ -145,6 +145,7 @@ public class MojangToMapping {
put("net.minecraft.world.entity.Entity#getEncodeId()", "bw");
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId()", "p");
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "r");
put("net.minecraft.world.item.ItemStack#CODEC", "a");
}
};
@@ -169,6 +170,7 @@ public class MojangToMapping {
put("net.minecraft.util.datafix.DataFixers#getDataFixer()", "a");
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "t");
put("net.minecraft.nbt.NbtOps#INSTANCE", "a");
put("net.minecraft.world.item.ItemStack#CODEC", "b");
}
};
@@ -183,10 +185,152 @@ public class MojangToMapping {
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R2 = new HashMap<String, String>() {
{
putAll(MC1_21R1);
put("net.minecraft.server.MinecraftServer#registryAccess()", "ba");
put("net.minecraft.world.entity.Entity#getEncodeId()", "bK");
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "m");
put("net.minecraft.world.item.ItemStack#CODEC", "a");
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R3 = new HashMap<String, String>() {
{
putAll(MC1_21R2);
put("net.minecraft.world.item.component.CustomData#copyTag()", "d");
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R4 = new HashMap<String, String>() {
{
putAll(MC1_21R3);
put("net.minecraft.nbt.CompoundTag#getShort(java.lang.String)", "d");
put("net.minecraft.nbt.CompoundTag#getString(java.lang.String)", "i");
put("net.minecraft.nbt.CompoundTag#contains(java.lang.String)", "b");
put("net.minecraft.nbt.CompoundTag#getDouble(java.lang.String)", "h");
put("net.minecraft.nbt.CompoundTag#getByteArray(java.lang.String)", "j");
put("net.minecraft.nbt.CompoundTag#getFloat(java.lang.String)", "g");
put("net.minecraft.nbt.CompoundTag#get(java.lang.String)", "a");
put("net.minecraft.nbt.CompoundTag#getLong(java.lang.String)", "f");
put("net.minecraft.nbt.CompoundTag#getLongArray(java.lang.String)", "l");
put("net.minecraft.nbt.CompoundTag#getInt(java.lang.String)", "e");
put("net.minecraft.nbt.CompoundTag#getIntArray(java.lang.String)", "k");
put("net.minecraft.nbt.CompoundTag#getCompound(java.lang.String)", "m");
put("net.minecraft.nbt.CompoundTag#getByte(java.lang.String)", "c");
put("net.minecraft.nbt.ListTag#getString(int)", "m");
put("net.minecraft.world.entity.Entity#saveWithoutId(net.minecraft.nbt.CompoundTag)", "h");
put("net.minecraft.world.entity.Entity#getEncodeId()", "bI");
put("net.minecraft.world.entity.Entity#load(net.minecraft.nbt.CompoundTag)", "i");
put("net.minecraft.nbt.Tag#getType()", "c");
put("net.minecraft.nbt.TagType#getName()", "a");
put("net.minecraft.nbt.CompoundTag#getList(java.lang.String)", "o");
put("net.minecraft.world.item.ItemStack#parse(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.Tag)", "a");
put("net.minecraft.world.item.ItemStack#CODEC", "b");
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R5 = new HashMap<String, String>() {
{
putAll(MC1_21R3);
put("net.minecraft.core.HolderLookup$Provider#createSerializationContext(com.mojang.serialization.DynamicOps)", "a");
put("net.minecraft.nbt.CompoundTag#getByteArray(java.lang.String)", "j");
put("net.minecraft.nbt.CompoundTag#getDouble(java.lang.String)", "h");
put("net.minecraft.nbt.CompoundTag#keySet()", "e");
put("net.minecraft.nbt.CompoundTag#getLong(java.lang.String)", "f");
put("net.minecraft.nbt.CompoundTag#getList(java.lang.String)", "o");
put("net.minecraft.nbt.CompoundTag#getInt(java.lang.String)", "e");
put("net.minecraft.nbt.CompoundTag#getCompound(java.lang.String)", "m");
put("net.minecraft.nbt.CompoundTag#getByte(java.lang.String)", "c");
put("net.minecraft.nbt.CompoundTag#getShort(java.lang.String)", "d");
put("net.minecraft.nbt.CompoundTag#getIntArray(java.lang.String)", "k");
put("net.minecraft.nbt.CompoundTag#get(java.lang.String)", "a");
put("net.minecraft.nbt.CompoundTag#getString(java.lang.String)", "i");
put("net.minecraft.nbt.CompoundTag#getFloat(java.lang.String)", "g");
put("net.minecraft.nbt.CompoundTag#getLongArray(java.lang.String)", "l");
put("net.minecraft.nbt.CompoundTag#contains(java.lang.String)", "b");
put("net.minecraft.nbt.ListTag#getString(int)", "m");
put("net.minecraft.nbt.Tag#getType()", "c");
put("net.minecraft.nbt.TagParser#parseCompoundFully(java.lang.String)", "a");
put("net.minecraft.nbt.TagType#getName()", "a");
put("net.minecraft.world.entity.Entity#load(net.minecraft.world.level.storage.ValueInput)", "e");
put("net.minecraft.world.entity.Entity#getEncodeId()", "bN");
put("net.minecraft.world.entity.Entity#saveWithoutId(net.minecraft.world.level.storage.ValueOutput)", "d");
put("net.minecraft.world.level.block.entity.BlockEntity#saveWithId(net.minecraft.world.level.storage.ValueOutput)", "d");
put("net.minecraft.world.level.block.entity.BlockEntity#loadWithComponents(net.minecraft.world.level.storage.ValueInput)", "b");
put("net.minecraft.world.level.storage.TagValueInput#create(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)", "a");
put("net.minecraft.world.level.storage.TagValueOutput#createWithContext(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider)", "a");
put("net.minecraft.world.level.storage.TagValueOutput#buildResult()", "b");
put("net.minecraft.world.item.ItemStack#CODEC", "b");
put("net.minecraft.util.ProblemReporter#DISCARDING", "a");
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "u");
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R6 = new HashMap<String, String>() {
{
putAll(MC1_21R5);
put("net.minecraft.server.MinecraftServer#registryAccess()", "bg");
put("net.minecraft.world.entity.Entity#load(net.minecraft.world.level.storage.ValueInput)", "d");
put("net.minecraft.world.entity.Entity#getEncodeId()", "bW");
put("net.minecraft.world.item.component.CustomData#copyTag()", "b");
put("net.minecraft.world.level.block.entity.BlockEntity#getBlockState()", "o");
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "v");
}
};
@SuppressWarnings("serial")
private static Map<String, String> MC1_21R7 = new HashMap<String, String>() {
{
putAll(MC1_21R6);
put("net.minecraft.nbt.NbtAccounter#unlimitedHeap()", "c");
put("net.minecraft.server.MinecraftServer#registryAccess()", "bc");
put("net.minecraft.world.entity.Entity#getEncodeId()", "ca");
put("net.minecraft.util.datafix.fixes.References#ITEM_STACK", "x");
}
};
public static Map<String, String> getMapping() {
switch (MinecraftVersion.getVersion()) {
case MC1_21_R7:
return MC1_21R7;
case MC1_21_R6:
return MC1_21R6;
case MC1_21_R5:
return MC1_21R5;
case MC1_21_R4:
return MC1_21R4;
case MC1_21_R3:
return MC1_21R3;
case MC1_21_R2:
return MC1_21R2;
case MC1_21_R1:
return MC1_21R1;
case MC1_20_R4:
@@ -5,6 +5,8 @@ import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NbtApiException;
@@ -54,7 +56,7 @@ public enum ReflectionMethod {
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setBoolean"),
new Since(MinecraftVersion.MC1_18_R1, "putBoolean(java.lang.String,boolean)")),
COMPOUND_SET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, UUID.class },
MinecraftVersion.MC1_16_R1, new Since(MinecraftVersion.MC1_16_R1, "a"),
MinecraftVersion.MC1_16_R1, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_16_R1, "a"),
new Since(MinecraftVersion.MC1_18_R1, "putUUID(java.lang.String,java.util.UUID)")),
COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"),
@@ -65,12 +67,18 @@ public enum ReflectionMethod {
COMPOUND_GET(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "get"),
new Since(MinecraftVersion.MC1_18_R1, "get(java.lang.String)")),
COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, int.class },
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getList"),
COMPOUND_GET_LIST_LEGACY(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class, int.class },
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_7_R4, "getList"),
new Since(MinecraftVersion.MC1_18_R1, "getList(java.lang.String,int)")),
COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_21_R4,
new Since(MinecraftVersion.MC1_21_R4, "getList(java.lang.String)")),
// Only needed for 1.7.10 getType
COMPOUND_OWN_TYPE(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4,
COMPOUND_OWN_TYPE_LEGACY(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "getTypeId")),
TAGTYPE_OWN_TYPE(ClassWrapper.NMS_NBTBASE, new Class[] {}, MinecraftVersion.MC1_21_R4,
new Since(MinecraftVersion.MC1_21_R4, "getType()")),
TAGTYPE_GET_NAME(ClassWrapper.NMS_TAGTYPE, new Class[] {}, MinecraftVersion.MC1_21_R4,
new Since(MinecraftVersion.MC1_21_R4, "getName()")),
COMPOUND_GET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "getFloat"),
@@ -105,13 +113,14 @@ public enum ReflectionMethod {
COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "getBoolean"),
new Since(MinecraftVersion.MC1_18_R1, "getBoolean(java.lang.String)")),
COMPOUND_GET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_16_R1,
COMPOUND_GET_UUID(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_16_R1, MinecraftVersion.MC1_21_R3,
new Since(MinecraftVersion.MC1_16_R1, "a"),
new Since(MinecraftVersion.MC1_18_R1, "getUUID(java.lang.String)")),
COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "getCompound"),
new Since(MinecraftVersion.MC1_18_R1, "getCompound(java.lang.String)")),
NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK, new Class[] {}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_20_R3,
new Since(MinecraftVersion.MC1_7_R4, "getTag"), new Since(MinecraftVersion.MC1_18_R1, "getTag()")),
NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
@@ -126,17 +135,17 @@ public enum ReflectionMethod {
COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "hasKey"),
new Since(MinecraftVersion.MC1_18_R1, "contains(java.lang.String)")),
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_8_R3,
COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] { String.class }, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_21_R4,
new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d"),
new Since(MinecraftVersion.MC1_15_R1, "e"), new Since(MinecraftVersion.MC1_16_R1, "d"),
new Since(MinecraftVersion.MC1_18_R1, "getTagType(java.lang.String)")),
COMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()"), new Since(MinecraftVersion.MC1_21_R5, "keySet()")),
// FIXME ?!?
LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
// LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND, new Class[] {}, MinecraftVersion.MC1_7_R4,
// new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys"),
// new Since(MinecraftVersion.MC1_18_R1, "getAllKeys()")),
LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST, new Class[] { int.class }, MinecraftVersion.MC1_8_R3,
new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove"),
new Since(MinecraftVersion.MC1_18_R1, "remove(int)")),
@@ -219,11 +228,11 @@ public enum ReflectionMethod {
CRAFT_ENTITY_GET_HANDLE(ClassWrapper.CRAFT_ENTITY, new Class[] {}, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "getHandle")),
NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "f"),
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_7_R4, "f"),
new Since(MinecraftVersion.MC1_16_R1, "load"),
new Since(MinecraftVersion.MC1_18_R1, "load(net.minecraft.nbt.CompoundTag)")),
NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "e"),
MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_7_R4, "e"),
new Since(MinecraftVersion.MC1_12_R1, "save"),
new Since(MinecraftVersion.MC1_18_R1, "saveWithoutId(net.minecraft.nbt.CompoundTag)")),
NMS_ENTITY_GETSAVEID(ClassWrapper.NMS_ENTITY, new Class[] {}, MinecraftVersion.MC1_14_R1,
@@ -251,7 +260,7 @@ public enum ReflectionMethod {
PARSE_NBT(ClassWrapper.NMS_MOJANGSONPARSER, new Class[] { String.class }, MinecraftVersion.MC1_7_R4,
new Since(MinecraftVersion.MC1_7_R4, "parse"),
new Since(MinecraftVersion.MC1_18_R1, "parseTag(java.lang.String)")),
new Since(MinecraftVersion.MC1_18_R1, "parseTag(java.lang.String)"), new Since(MinecraftVersion.MC1_21_R5, "parseCompoundFully(java.lang.String)")),
REGISTRY_KEYSET(ClassWrapper.NMS_REGISTRYSIMPLE, new Class[] {}, MinecraftVersion.MC1_11_R1,
MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "keySet")),
REGISTRY_GET(ClassWrapper.NMS_REGISTRYSIMPLE, new Class[] { Object.class }, MinecraftVersion.MC1_11_R1,
@@ -292,19 +301,41 @@ public enum ReflectionMethod {
NMSITEM_SET(ClassWrapper.NMS_ITEMSTACK, new Class[] {ClassWrapper.NMS_DATACOMPONENTTYPE.getClazz(), Object.class}, MinecraftVersion.MC1_20_R4,
new Since(MinecraftVersion.MC1_20_R4, "set(net.minecraft.core.component.DataComponentType,java.lang.Object)")),
NMSITEM_SAVE_MODERN(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz() },
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "save(net.minecraft.core.HolderLookup$Provider)")),
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "save(net.minecraft.core.HolderLookup$Provider)")),
NMSITEM_LOAD(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz() },
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "parseOptional(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)")),
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R3, new Since(MinecraftVersion.MC1_20_R4, "parseOptional(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)")),
NMSITEM_LOAD_MODERN(ClassWrapper.NMS_ITEMSTACK, new Class[] { ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTBASE.getClazz() },
MinecraftVersion.MC1_21_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "parse(net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.Tag)")),
NMSSERVER_GETREGISTRYACCESS(ClassWrapper.NMS_SERVER, new Class[] {},
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "registryAccess()")),
NMSSERVER_GETSERVER(ClassWrapper.CRAFT_SERVER, new Class[] {},
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "getServer()")),
TILEENTITY_GET_NBT_1205(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_PROVIDER.getClazz()}, MinecraftVersion.MC1_20_R4,
TILEENTITY_GET_NBT_1205(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_PROVIDER.getClazz()}, MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4,
new Since(MinecraftVersion.MC1_20_R4, "saveWithId(net.minecraft.core.HolderLookup$Provider)")),
TILEENTITY_SET_NBT_1205(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz() },
MinecraftVersion.MC1_20_R4, new Since(MinecraftVersion.MC1_20_R4, "loadWithComponents(net.minecraft.nbt.CompoundTag,net.minecraft.core.HolderLookup$Provider)")),
MinecraftVersion.MC1_20_R4, MinecraftVersion.MC1_21_R4, new Since(MinecraftVersion.MC1_20_R4, "loadWithComponents(net.minecraft.nbt.CompoundTag,net.minecraft.core.HolderLookup$Provider)")),
GET_DATAFIXER(ClassWrapper.NMS_DATAFIXERS, new Class[] {}, MinecraftVersion.MC1_20_R4,
new Since(MinecraftVersion.MC1_20_R4, "getDataFixer()")),
// 1.21.6 Stuff
GET_SERIALIZATION_CONTEXT(ClassWrapper.NMS_PROVIDER, new Class[] {ClassWrapper.NMS_DYNAMICOPS.getClazz()}, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "createSerializationContext(com.mojang.serialization.DynamicOps)")),
NMS_GET_TAG_VALUE_INPUT(ClassWrapper.NMS_TAG_VALUE_INPUT, new Class[] {ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "create(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider,net.minecraft.nbt.CompoundTag)")),
NMS_GET_TAG_VALUE_OUTPUT(ClassWrapper.NMS_TAG_VALUE_OUTPUT, new Class[] {ClassWrapper.NMS_PROBLEM_REPORTER.getClazz(), ClassWrapper.NMS_PROVIDER.getClazz()}, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "createWithContext(net.minecraft.util.ProblemReporter,net.minecraft.core.HolderLookup$Provider)")),
NMS_TAG_VALUE_OUTPUT_TO_TAG_COMPOUND(ClassWrapper.NMS_TAG_VALUE_OUTPUT, new Class[] {}, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "buildResult()")),
NMS_ENTITY_SET_NBT_1216(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_VALUE_INPUT.getClazz() }, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "load(net.minecraft.world.level.storage.ValueInput)")
),
NMS_ENTITY_GET_NBT_1216(ClassWrapper.NMS_ENTITY, new Class[] { ClassWrapper.NMS_VALUE_OUTPUT.getClazz() }, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "saveWithoutId(net.minecraft.world.level.storage.ValueOutput)")),
TILEENTITY_GET_NBT_1216(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_VALUE_OUTPUT.getClazz()}, MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "saveWithId(net.minecraft.world.level.storage.ValueOutput)")),
TILEENTITY_SET_NBT_1216(ClassWrapper.NMS_TILEENTITY, new Class[] {ClassWrapper.NMS_VALUE_INPUT.getClazz() },
MinecraftVersion.MC1_21_R5,
new Since(MinecraftVersion.MC1_21_R5, "loadWithComponents(net.minecraft.world.level.storage.ValueInput)")),
;
private MinecraftVersion removedAfter;
@@ -396,7 +427,8 @@ public enum ReflectionMethod {
return method.invoke(target, args);
} catch (Exception ex) {
throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded
+ ", Enum: " + this + ", Passed Class: " + (target == null ? "null" : target.getClass()) + " Args: " + (args == null ? "null" : Arrays.toString(args)), ex);
+ ", Enum: " + this + ", Passed Class: " + (target == null ? "null" : target.getClass()) + " Args: " + (args == null ? "null" : Arrays.toString(args)) +
" Classes: " + (args == null ? "null" : Arrays.asList(args).stream().map(a -> a == null ? "NULL" : a.getClass().getName()).collect(Collectors.toList())), ex);
}
}
+10 -11
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</parent>
<artifactId>item-nbt-api-plugin</artifactId>
<packaging>jar</packaging>
@@ -12,7 +12,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -21,6 +21,13 @@
<version>4.0.26</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.1.0</version>
<!-- Overwrite to provided -->
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
@@ -33,7 +40,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<version>3.6.1</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<relocations>
@@ -41,14 +48,6 @@
<pattern>de.tr7zw.changeme.nbtapi</pattern>
<shadedPattern>de.tr7zw.nbtapi</shadedPattern>
</relocation>
<relocation>
<pattern>javassist</pattern>
<shadedPattern>de.tr7zw.nbtinjector.javassist</shadedPattern>
</relocation>
<relocation>
<pattern>de.tr7zw.annotations</pattern>
<shadedPattern>de.tr7zw.nbtapi.utils.annotations</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
@@ -7,7 +7,6 @@ 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.NbtApiException;
@@ -19,6 +18,7 @@ import de.tr7zw.nbtapi.plugin.tests.GameprofileTest;
import de.tr7zw.nbtapi.plugin.tests.NBTFileTest;
import de.tr7zw.nbtapi.plugin.tests.blocks.BlockNBTTest;
import de.tr7zw.nbtapi.plugin.tests.chunks.ChunkNBTPersistentTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.CompoundDifferenceTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.EnumTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.EqualsTest;
import de.tr7zw.nbtapi.plugin.tests.compounds.ForEachTest;
@@ -41,6 +41,7 @@ import de.tr7zw.nbtapi.plugin.tests.items.DirectApplyMetaTest;
import de.tr7zw.nbtapi.plugin.tests.items.DirectApplyTest;
import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemConversionTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemJsonTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemMergingTest;
import de.tr7zw.nbtapi.plugin.tests.items.ItemStackConversionTest;
import de.tr7zw.nbtapi.plugin.tests.items.LegacyItemTest;
@@ -99,6 +100,7 @@ public class NBTAPI extends JavaPlugin {
apiTests.add(new ForEachTest());
apiTests.add(new StreamTest());
apiTests.add(new EqualsTest());
apiTests.add(new CompoundDifferenceTest());
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_8_R3)) // 1.7.10 list support is not complete at all
apiTests.add(new IteratorTest());
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_16_R1))
@@ -112,6 +114,9 @@ public class NBTAPI extends JavaPlugin {
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4)) {
apiTests.add(new LegacyItemTest());
}
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_20_R4) && !MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
apiTests.add(new ItemJsonTest());
}
apiTests.add(new ComponentsTest());
apiTests.add(new EmptyItemTest());
apiTests.add(new SmuggleTest());
@@ -195,7 +200,7 @@ public class NBTAPI extends JavaPlugin {
} catch (Exception ex) {
results.put(test, ex);
getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex);
} catch (NoSuchFieldError th) { // NOSONAR
} 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!");
@@ -4,9 +4,9 @@ import java.util.UUID;
import com.mojang.authlib.GameProfile;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTGameProfile;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
public class GameprofileTest implements Test {
@@ -14,10 +14,9 @@ public class GameprofileTest implements Test {
public void test() throws Exception {
UUID uuid = UUID.randomUUID();
GameProfile profile = new GameProfile(uuid, "random");
NBTCompound nbt = NBTGameProfile.toNBT(profile);
profile = null;
profile = NBTGameProfile.fromNBT(nbt);
if (profile == null || !profile.getId().equals(uuid)) {
ReadWriteNBT nbt = NBT.gameProfileToNBT(profile);
GameProfile profile2 = NBT.gameProfileFromNBT(nbt);
if (profile == null || !profile.equals(profile2)) {
throw new NbtApiException("Error when converting a GameProfile from/to NBT!");
}
}
@@ -3,10 +3,10 @@ package de.tr7zw.nbtapi.plugin.tests;
import java.io.File;
import java.nio.file.Files;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTFile;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.NBTFileHandle;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.NBTAPI;
public class NBTFileTest implements Test {
@@ -16,18 +16,18 @@ public class NBTFileTest implements Test {
NBTAPI.getInstance().getDataFolder().mkdirs();
File testFile = new File(NBTAPI.getInstance().getDataFolder(), "test.nbt");
Files.deleteIfExists(testFile.toPath());
NBTFile file = new NBTFile(testFile);
file.addCompound("testcomp").setString("test1", "ok");
NBTCompound comp = file.getCompound("testcomp");
NBTFileHandle file = NBT.getFileHandle(testFile);
file.getOrCreateCompound("testcomp").setString("test1", "ok");
ReadWriteNBT comp = file.getOrCreateCompound("testcomp");
if (comp == null) {
throw new NbtApiException("Error getting compound!");
}
comp.setString("test2", "ok");
file.setLong("time", System.currentTimeMillis());
file.setString("test", "test");
NBTCompound chunks = file.addCompound("chunks");
NBTCompound chunk = chunks.addCompound("somechunk");
NBTCompound block = chunk.addCompound("someblock");
ReadWriteNBT chunks = file.getOrCreateCompound("chunks");
ReadWriteNBT chunk = chunks.getOrCreateCompound("somechunk");
ReadWriteNBT block = chunk.getOrCreateCompound("someblock");
block.setString("type", "wool");
file.save();
@@ -35,25 +35,25 @@ public class NBTFileTest implements Test {
throw new NbtApiException("SubCompounds did not work!");
}
NBTFile fileLoaded = new NBTFile(testFile);
NBTFileHandle fileLoaded = NBT.getFileHandle(testFile);
if (!fileLoaded.getString("test").equals("test")) {
throw new NbtApiException("Wasn't able to load NBT File with the correct content!");
}
Files.deleteIfExists(fileLoaded.getFile().toPath());
// String
String str = fileLoaded.toString();
NBTContainer rebuild = new NBTContainer(str);
ReadWriteNBT rebuild = NBT.parseNBT(str);
if (!str.equals(rebuild.toString())) {
throw new NbtApiException("Wasn't able to parse NBT from a String!");
}
NBTCompound dummy = new NBTContainer();
ReadWriteNBT dummy = NBT.createNBTObject();
dummy.setString("test1", "key1");
NBTFile.saveTo(testFile, dummy);
dummy = new NBTContainer();
NBT.writeFile(testFile, dummy);
dummy = NBT.createNBTObject();
dummy.setString("test2", "key2");
NBTFile.saveTo(testFile, dummy);
dummy = NBTFile.readFrom(testFile);
NBT.writeFile(testFile, dummy);
dummy = NBT.readFile(testFile);
if (dummy.hasTag("test1") || !dummy.getString("test2").equals("key2")) {
throw new NbtApiException("Wasn't able to save NBT File with the correct content!");
}
@@ -0,0 +1,69 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
import java.util.Arrays;
public class CompoundDifferenceTest implements Test {
@Override
public void test() throws Exception {
ReadWriteNBT nbt1 = NBT.createNBTObject();
nbt1.setInteger("intTag", 1);
ReadWriteNBT tmp = NBT.createNBTObject();
tmp.setInteger("foo", 1);
nbt1.getCompoundList("compoundList1").addCompound(tmp);
nbt1.setIntArray("intArray", new int[]{1, 2, 3});
tmp = NBT.createNBTObject();
tmp.setIntArray("foo", new int[]{1, 2, 3});
nbt1.getCompoundList("compoundList2").addCompound(tmp);
nbt1.getOrCreateCompound("compoundTag").setFloat("floatTag", 20F);
nbt1.getOrCreateCompound("compoundTag").setBoolean("booleanTag", true);
nbt1.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D));
nbt1.getOrCreateCompound("compoundTag").getFloatList("floatList").addAll(Arrays.asList(1F, 2F));
nbt1.getOrCreateCompound("compoundTagTwo").setString("stringTag", "string");
ReadWriteNBT nbt2 = NBT.createNBTObject();
nbt2.setInteger("intTag", 1);
tmp = NBT.createNBTObject();
tmp.setInteger("foo", 1);
nbt2.getCompoundList("compoundList1").addCompound(tmp);
nbt2.setInteger("alsoIntTag", 2);
tmp = NBT.createNBTObject();
tmp.setInteger("foo", 2);
nbt2.getCompoundList("compoundList2").addCompound(tmp);
nbt2.getOrCreateCompound("compoundTag").setFloat("floatTag", 20F);
nbt2.getOrCreateCompound("compoundTag").setBoolean("booleanTag", false);
nbt2.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D, 4D));
nbt2.getOrCreateCompound("compoundTag").getFloatList("floatList").addAll(Arrays.asList(1F, 2F));
nbt2.getOrCreateCompound("compoundTagTwo").setString("stringTag", "string");
ReadWriteNBT expectedDiff1 = NBT.createNBTObject();
tmp = NBT.createNBTObject();
tmp.setIntArray("foo", new int[]{1, 2, 3});
expectedDiff1.getCompoundList("compoundList2").addCompound(tmp);
expectedDiff1.setIntArray("intArray", new int[]{1, 2, 3});
expectedDiff1.getOrCreateCompound("compoundTag").setBoolean("booleanTag", true);
expectedDiff1.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D));
ReadWriteNBT expectedDiff2 = NBT.createNBTObject();
tmp = NBT.createNBTObject();
tmp.setInteger("foo", 2);
expectedDiff2.getCompoundList("compoundList2").addCompound(tmp);
expectedDiff2.setInteger("alsoIntTag", 2);
expectedDiff2.getOrCreateCompound("compoundTag").setBoolean("booleanTag", false);
expectedDiff2.getOrCreateCompound("compoundTag").getDoubleList("doubleList").addAll(Arrays.asList(1D, 2D, 3D, 4D));
ReadWriteNBT diff1 = nbt1.extractDifference(nbt2);
ReadWriteNBT diff2 = nbt2.extractDifference(nbt1);
if (!expectedDiff1.equals(diff1)) {
throw new NbtApiException("Diff1: Compounds did not match! " + expectedDiff1 + " " + diff1);
}
if (!expectedDiff2.equals(diff2)) {
throw new NbtApiException("Diff2: Compounds did not match! " + expectedDiff2 + " " + diff2);
}
}
}
@@ -1,16 +1,16 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class EnumTest implements Test {
@Override
public void test() throws Exception {
NBTCompound comp = new NBTContainer();
ReadWriteNBT comp = NBT.createNBTObject();
comp.setEnum("test", NBTType.NBTTagEnd);
NBTType type = comp.getEnum("test", NBTType.class);
NBTType typeNonNull = comp.getOrNull("test", NBTType.class);
@@ -5,44 +5,44 @@ import java.util.Arrays;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class EqualsTest implements Test {
@Override
public void test() throws Exception {
NBTContainer cont = new NBTContainer();
ReadWriteNBT cont = NBT.createNBTObject();
cont.setString("hello", "world");
cont.setInteger("theAnswer", 42);
cont.addCompound("sub").setString("me", "too");
cont.getOrCreateCompound("sub").setString("me", "too");
cont.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
ItemStack item = new ItemStack(Material.STONE);
NBTItem nbti = new NBTItem(item);
NBTCompound customData = nbti.addCompound("customData");
// reverse order
customData.addCompound("sub").setString("me", "too");
customData.setInteger("theAnswer", 42);
customData.setString("hello", "world");
customData.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
if (!customData.equals(cont)) {
throw new NbtApiException("Compounds did not match! " + customData + " " + cont);
}
NBT.modify(item, nbti -> {
ReadWriteNBT customData = nbti.getOrCreateCompound("customData");
// reverse order
customData.getOrCreateCompound("sub").setString("me", "too");
customData.setInteger("theAnswer", 42);
customData.setString("hello", "world");
customData.getStringList("somelist").addAll(Arrays.asList("a", "b", "c"));
if (!customData.equals(cont)) {
throw new NbtApiException("Compounds did not match! " + customData + " " + cont);
}
});
// empty test
if (!new NBTContainer().equals(new NBTContainer())) {
if (!NBT.createNBTObject().equals(NBT.createNBTObject())) {
throw new NbtApiException("Two empty tags did not match!");
}
// not equal test
NBTContainer part1 = new NBTContainer();
ReadWriteNBT part1 = NBT.createNBTObject();
part1.setString("a", "a");
part1.setString("b", "b");
NBTContainer part2 = new NBTContainer();
ReadWriteNBT part2 = NBT.createNBTObject();
part2.setString("a", "a");
part2.setString("b", "a");
if (part1.equals(part2)) {
@@ -3,24 +3,22 @@ package de.tr7zw.nbtapi.plugin.tests.compounds;
import java.util.Arrays;
import java.util.UUID;
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.NBT;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTList;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class ListTest implements Test {
@Override
public void test() throws Exception {
NBTContainer comp = new NBTContainer();
ReadWriteNBT comp = NBT.createNBTObject();
// Strings
NBTList<String> list = comp.getStringList("testlist");
ReadWriteNBTList<String> list = comp.getStringList("testlist");
list.add("test1");
list.add("test2");
list.add("test3");
@@ -32,14 +30,14 @@ public class ListTest implements Test {
}
// Compound
NBTCompoundList taglist = comp.getCompoundList("complist");
NBTListCompound lcomp = taglist.addCompound();
ReadWriteNBTCompoundList taglist = comp.getCompoundList("complist");
ReadWriteNBT lcomp = taglist.addCompound();
lcomp.setDouble("double1", 0.3333);
lcomp.setInteger("int1", 42);
lcomp.setString("test1", "test1");
lcomp.setString("test2", "test2");
lcomp.removeKey("test1");
NBTCompound subsubcomp = lcomp.addCompound("listsubkey");
ReadWriteNBT subsubcomp = lcomp.getOrCreateCompound("listsubkey");
subsubcomp.setString("deep", "String");
subsubcomp.getCompoundList("deeplist").addCompound().setString("test", "test");
subsubcomp.getCompoundList("clonelist").addCompound(comp);
@@ -73,11 +71,11 @@ public class ListTest implements Test {
}
if (comp.getListType("complist") != NBTType.NBTTagCompound) {
throw new NbtApiException("complist had the wrong type! The Item-NBT-API may not work!");
throw new NbtApiException("complist had the wrong type(" + comp.getListType("complist") + ")! The Item-NBT-API may not work!");
}
// Integer
NBTList<Integer> intlist = comp.getIntegerList("inttest");
ReadWriteNBTList<Integer> intlist = comp.getIntegerList("inttest");
intlist.add(42);
intlist.add(69);
if (intlist.size() == 2 && intlist.get(0) == 42 && intlist.get(1) == 69) {
@@ -91,7 +89,7 @@ public class ListTest implements Test {
}
// Double
NBTList<Double> doublelist = comp.getDoubleList("doubletest");
ReadWriteNBTList<Double> doublelist = comp.getDoubleList("doubletest");
doublelist.add(42.23d);
doublelist.add(69.69d);
if (doublelist.size() == 2 && doublelist.get(0) == 42.23d && doublelist.get(1) == 69.69d) {
@@ -106,7 +104,7 @@ public class ListTest implements Test {
}
// Float
NBTList<Float> floatlist = comp.getFloatList("floattest");
ReadWriteNBTList<Float> floatlist = comp.getFloatList("floattest");
floatlist.add(42.23f);
floatlist.add(69.69f);
if (floatlist.size() == 2 && floatlist.get(0) == 42.23f && floatlist.get(1) == 69.69f) {
@@ -120,7 +118,7 @@ public class ListTest implements Test {
}
// Long
NBTList<Long> longlist = comp.getLongList("longtest");
ReadWriteNBTList<Long> longlist = comp.getLongList("longtest");
longlist.add(1241234124124l);
longlist.add(1231454321312l);
if (longlist.size() == 2 && longlist.get(0) == 1241234124124l && longlist.get(1) == 1231454321312l) {
@@ -134,7 +132,7 @@ public class ListTest implements Test {
}
// int[]
NBTList<int[]> intArrayList = comp.getIntArrayList("intatest");
ReadWriteNBTList<int[]> intArrayList = comp.getIntArrayList("intatest");
intArrayList.add(new int[] { 1, 2, 3 });
intArrayList.add(new int[] { 4, 2, 0 });
if (intArrayList.size() == 2 && Arrays.equals(new int[] { 1, 2, 3 }, intArrayList.get(0))
@@ -149,7 +147,7 @@ public class ListTest implements Test {
}
// UUID
NBTList<UUID> uuidList = comp.getUUIDList("uuidtest");
ReadWriteNBTList<UUID> uuidList = comp.getUUIDList("uuidtest");
uuidList.add(UUID.fromString("fce0323d-7f50-4317-9720-5f6b14cf78ea"));
uuidList.add(UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6"));
if (uuidList.size() == 2 && UUID.fromString("fce0323d-7f50-4317-9720-5f6b14cf78ea").equals(uuidList.get(0))
@@ -3,24 +3,33 @@ package de.tr7zw.nbtapi.plugin.tests.compounds;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class StreamTest implements Test {
@Override
public void test() throws Exception {
NBTContainer base = new NBTContainer();
ReadWriteNBT base = NBT.createNBTObject();
base.getOrCreateCompound("sub").setString("hello", "world");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
base.getOrCreateCompound("sub").writeCompound(outStream);
byte[] data = outStream.toByteArray();
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
NBTContainer container = new NBTContainer(inputStream);
ReadWriteNBT container = NBT.readNBT(inputStream);
if (!container.toString().equals(base.getOrCreateCompound("sub").toString())) {
throw new NbtApiException("Component content did not match! " + base.getCompound("sub") + " " + container);
}
ItemStack item = new ItemStack(Material.STICK);
NBT.modify(item, nbt -> {
nbt.writeCompound(outStream);
});
}
}
@@ -1,8 +1,8 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class SubCompoundsTest implements Test {
@@ -19,9 +19,9 @@ public class SubCompoundsTest implements Test {
@Override
public void test() throws Exception {
NBTContainer cont = new NBTContainer();
ReadWriteNBT cont = NBT.createNBTObject();
NBTCompound comp = cont.addCompound(COMP_TEST_KEY);
ReadWriteNBT comp = cont.getOrCreateCompound(COMP_TEST_KEY);
comp.setString(STRING_TEST_KEY, STRING_TEST_VALUE + "2");
comp.setInteger(INT_TEST_KEY, INT_TEST_VALUE * 2);
comp.setDouble(DOUBLE_TEST_KEY, DOUBLE_TEST_VALUE * 2);
@@ -1,19 +1,19 @@
package de.tr7zw.nbtapi.plugin.tests.compounds;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class TypeTest implements Test {
@Override
public void test() throws Exception {
NBTCompound comp = new NBTContainer();
ReadWriteNBT comp = NBT.createNBTObject();
comp.setString("s", "test");
comp.setInteger("i", 42);
comp.addCompound("c");
comp.getOrCreateCompound("c");
if (comp.getType("s") != NBTType.NBTTagString || comp.getType("i") != NBTType.NBTTagInt
|| comp.getType("c") != NBTType.NBTTagCompound)
throw new NbtApiException("One parsed type did not match what it should have been!");
@@ -6,8 +6,7 @@ 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.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.nbtapi.plugin.tests.Test;
@@ -23,14 +22,16 @@ public class EntityCustomNbtPersistentTest implements Test {
try {
if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) {
Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next();
NBTEntity nbtEnt = new NBTEntity(ent);
NBTCompound comp = nbtEnt.getPersistentDataContainer();
comp.setString("Hello", "World");
NBTEntity nbtent = new NBTEntity(ent);
if (!nbtent.toString().contains("Hello:\"World\"")) {
throw new NbtApiException("Custom Data did not save to the Entity!");
}
comp.removeKey("Hello");
NBT.modifyPersistentData(ent, comp -> {
comp.setString("Hello", "World");
});
NBT.modifyPersistentData(ent, comp -> {
if (!comp.toString().contains("Hello:\"World\"")) {
throw new NbtApiException("Custom Data did not save to the Entity!");
}
comp.removeKey("Hello");
});
}
} catch (Exception ex) {
@@ -27,7 +27,11 @@ public class ComponentsTest implements Test {
throw new NbtApiException("ReadComponent didn't work!");
}
NBT.modifyComponents(item, nbt -> {
nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_21_R4)) {
nbt.mergeCompound(NBT.parseNBT("{\"minecraft:custom_name\":[{\"text\":\"foobar\",\"italic\":false}]}"));
} else {
nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
}
});
if(!item.getItemMeta().getDisplayName().equals("foobar")) {
throw new NbtApiException("ModifyComponent didn't work!");
@@ -1,13 +1,15 @@
package de.tr7zw.nbtapi.plugin.tests.items;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NBTType;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.google.common.collect.Lists;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.nbtapi.plugin.tests.Test;
@@ -19,14 +21,21 @@ public class ItemConversionTest implements Test {
ItemMeta meta = item.getItemMeta();
meta.setLore(Lists.newArrayList("Firest Line", "Second Line"));
item.setItemMeta(meta);
String nbt = NBTItem.convertItemtoNBT(item).toString();
if (!nbt.contains("Firest Line") || !nbt.contains("Second Line"))
throw new NbtApiException("The Item nbt '" + nbt + "' didn't contain the lore");
ItemStack rebuild = NBTItem.convertNBTtoItem(new NBTContainer(nbt));
ReadWriteNBT nbt = NBT.itemStackToNBT(item);
if (MinecraftVersion.isAtLeastVersion(MinecraftVersion.MC1_12_R1)
&& !nbt.hasTag("DataVersion", NBTType.NBTTagInt)) {
throw new NbtApiException("The item nbt '" + nbt + "' didn't contain the data version");
}
String nbtString = nbt.toString();
if (!nbtString.contains("Firest Line") || !nbtString.contains("Second Line"))
throw new NbtApiException("The Item nbt '" + nbtString + "' didn't contain the lore");
ItemStack rebuild = NBT.itemStackFromNBT(NBT.parseNBT(nbtString));
if (!item.isSimilar(rebuild))
throw new NbtApiException("Rebuilt item did not match the original!");
NBTContainer cont = new NBTContainer();
ReadWriteNBT cont = NBT.createNBTObject();
cont.setItemStack("testItem", item);
if (!item.isSimilar(cont.getItemStack("testItem")))
throw new NbtApiException("Rebuilt item did not match the original!");
@@ -0,0 +1,28 @@
package de.tr7zw.nbtapi.plugin.tests.items;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.google.gson.JsonElement;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.NBTJsonUtil;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class ItemJsonTest implements Test {
@Override
public void test() throws Exception {
ItemStack item = new ItemStack(Material.STONE);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName("test");
meta.setUnbreakable(true);
item.setItemMeta(meta);
JsonElement elem = NBTJsonUtil.itemStackToJson(item);
if (elem == null) {
throw new NbtApiException("Getting the Json didn't work correctly! " + item);
}
}
}
@@ -3,9 +3,9 @@ package de.tr7zw.nbtapi.plugin.tests.items;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.nbtapi.plugin.tests.Test;
public class ItemStackConversionTest implements Test {
@@ -14,8 +14,8 @@ public class ItemStackConversionTest implements Test {
public void test() throws Exception {
ItemStack[] src = new ItemStack[] { new ItemStack(Material.STONE), new ItemStack(Material.STICK),
new ItemStack(Material.AIR), new ItemStack(Material.STONE) };
NBTCompound comp = NBTItem.convertItemArraytoNBT(src);
ItemStack[] recreated = NBTItem.convertNBTtoItemArray(comp);
ReadWriteNBT comp = NBT.itemStackArrayToNBT(src);
ItemStack[] recreated = NBT.itemStackArrayFromNBT(comp);
if (recreated == null || src.length != recreated.length) {
throw new NbtApiException("Size did not match!");
}
@@ -29,6 +29,10 @@ public class LegacyItemTest implements Test {
|| !"test".equals(item.getItemMeta().getDisplayName())) {
throw new NbtApiException("1.12.2 item didn't load correctly! " + item);
}
ItemStack item2 = NBT.itemStackFromNBT(NBT.parseNBT("{DataVersion:" + DataFixerUtil.VERSION1_12_2 + ",id:cobblestone,Count:42,tag:{display:{Name:\"test\"},ench:[{lvl:3,id:34}]}}"));
if (!item.equals(item2))
throw new NbtApiException("Data-fixed 1.12.2 item didn't load correctly! " + item2);
}
}
@@ -5,6 +5,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.NBTTileEntity;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
@@ -24,6 +25,14 @@ public class TileTest implements Test {
world.getSpawnLocation().getBlockZ());
if (world.isChunkLoaded(block.getX() >> 4, block.getZ() >> 4) && block.getType() == Material.AIR) {
block.setType(Material.CHEST);
if (MinecraftVersion.isNewerThan(MinecraftVersion.MC1_21_R1)) {
// 1.21 changed the lock logic. So just try to get/set data, dont check for now
NBT.modify(block.getState(), nbt -> {
nbt.setString("foo", "bar");
});
block.setType(Material.AIR);
return;
}
NBTTileEntity tile = new NBTTileEntity(block.getState());
if (!MinecraftVersion.isNewerThan(MinecraftVersion.MC1_17_R1)) {
if (tile.getInteger("y") != 254) {
@@ -5,8 +5,7 @@ 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.NBT;
import de.tr7zw.changeme.nbtapi.NbtApiException;
import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion;
import de.tr7zw.nbtapi.plugin.tests.Test;
@@ -27,14 +26,16 @@ public class TilesCustomNBTPersistentTest implements Test {
world.getSpawnLocation().getBlockZ());
if (world.isChunkLoaded(block.getX() >> 4, block.getZ() >> 4) && block.getType() == Material.AIR) {
block.setType(Material.CHEST);
NBTTileEntity comp = new NBTTileEntity(block.getState());
NBTCompound persistentData = comp.getPersistentDataContainer();
persistentData.setString("Foo", "Bar");
if (!new NBTTileEntity(block.getState()).getPersistentDataContainer().getString("Foo")
.equals("Bar")) {
block.setType(Material.AIR);
throw new NbtApiException("Custom Data did not save to the Tile!");
}
NBT.modifyPersistentData(block.getState(), persistentData -> {
persistentData.setString("Foo", "Bar");
});
NBT.getPersistentData(block.getState(), persistentData -> {
if (!persistentData.getString("Foo").equals("Bar")) {
block.setType(Material.AIR);
throw new NbtApiException("Custom Data did not save to the Tile!");
}
return null;
});
block.setType(Material.AIR);
}
} catch (Exception ex) {
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</parent>
<artifactId>mappings-parser</artifactId>
<packaging>jar</packaging>
@@ -12,7 +12,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -24,7 +24,7 @@ public class MappingsParser {
public static StringBuilder builder = new StringBuilder();
public static void main(String[] args) throws IOException {
File input = new File("minecraft_server.1.21.txt");
File input = new File("minecraft_server.1.21.9.txt");
List<String> lines = Files.readAllLines(input.toPath());
Map<String, ClassWrapper> classes = new HashMap<>();
@@ -75,6 +75,33 @@ public class MappingsParser {
}
// System.out.println(currentClass + ": " + mojangName + " -> " + unmappedName);
}
for(String type : MojangToMapping.getMapping().keySet()) {
if(type.contains("(")) {
continue;
}
// Field
String clazz = type.split("#")[0];
String fieldName = type.split("#")[1];
for (String line : lines) {
if (line.startsWith("#")) {
continue;
}
if (!line.startsWith(" ")) {
currentClass = line.split(" ")[0];
continue;
}
mojangName = line.trim().split(" ")[1];
unmappedName = line.trim().split(" ")[3];
if (currentClass.equals(clazz) && mojangName.equals(fieldName)) {
if (MojangToMapping.getMapping().get(type) == null) {
System.out.println("Missing mapping for " + type);
} else if (!MojangToMapping.getMapping().get(type)
.equals(unmappedName)) {
builder.append("put(\"" + type + "\", \"" + unmappedName + "\");\n");
}
}
}
}
System.out.println(builder);
}
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</parent>
<artifactId>nbt-data-api</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</parent>
<artifactId>nbt-injector</artifactId>
<packaging>jar</packaging>
@@ -12,7 +12,7 @@
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
<scope>compile</scope>
</dependency>
<dependency>
+5 -5
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-parent</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
<packaging>pom</packaging>
<inceptionYear>2015</inceptionYear>
<organization>
@@ -88,7 +88,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.14.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
@@ -97,7 +97,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<version>3.4.0</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -110,7 +110,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.8.0</version>
<version>3.12.0</version>
<configuration>
<source>8</source>
</configuration>
@@ -139,7 +139,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.4.0</version>
<version>2.7.0</version>
<configuration>
<licenseName>mit</licenseName>
<licenseFile>LICENSE</licenseFile>
+2 -2
View File
@@ -112,7 +112,7 @@ Just use the Plugin as Maven dependency and remember to add "NBTAPI" as dependen
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api-plugin</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</dependency>
[/CODE]
[/SPOILER]
@@ -122,7 +122,7 @@ Using this method the API gets copied into your plugin. Server owners don't have
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.13.2</version>
<version>2.15.4</version>
</dependency>
...
<plugins>
+2 -2
View File
@@ -100,7 +100,7 @@ NBT.modifyPersistentData(zombie, nbt -> {
File worldDataFolder = Bukkit.getWorlds().getFirst().getWorldFolder();
// Read level data
NBTFile levelNbtFile = new NBTFile(new File(worldDataFolder, "level.dat"));
NBTFileHandle levelNbtFile = NBT.getFileHandle(new File(worldDataFolder, "level.dat"));
// Obtain world name
String worldName = levelNbtFile.resolveOrNull("Data.LevelName", String.class);
@@ -113,7 +113,7 @@ if (!playerFile.exists()) {
return;
}
NBTFile playerNbtFile = new NBTFile(playerFile);
NBTFileHandle playerNbtFile = NBT.getFileHandle(playerFile);
// Change player's health
float health = playerNbtFile.getFloat("Health");
+1 -3
View File
@@ -21,6 +21,4 @@ The experimental NBTInjector became unsupported since Minecraft 1.14 and was rem
NBTInjector is incompatible with reloads and may break things, and thus is not recommended.
If you're using Minecraft 1.14+, you should switch to the persistent storage API instead.
In versions prior to 1.14, you may use a workaround like storing data inside an item's nbt that the entity is wearing (e.g. having a button in mob's helmet, and storing data on that button).
See [this wiki section](https://github.com/tr7zw/Item-NBT-API/wiki/Using-the-NBT-API#accessing-custom-data) on how to handle custom entity nbt data without NBTInjector.
+3 -1
View File
@@ -2,9 +2,11 @@
- [IllegalStack](https://github.com/dniym/IllegalStack)
- [Prison](https://github.com/PrisonTeam/Prison)
- [CommandAPI](https://github.com/JorelAli/CommandAPI)
- [CommandAPI](https://github.com/CommandAPI/CommandAPI)
- [SkBee](https://github.com/ShaneBeee/SkBee/)
- [Monumenta](https://github.com/TeamMonumenta/monumenta-plugins-public/)
- [SummonFriendlyMobs](https://github.com/ArmyFury/SummonFriendlyMobs)
- [EvenMoreFish](https://github.com/Oheers/EvenMoreFish)
___
+27 -5
View File
@@ -2,8 +2,11 @@ To start using NB-API, you either need to depend on its plugin version, or shade
> [!IMPORTANT]
> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
>
> [!IMPORTANT]
> Alternative ways of loading the api like Libby are not supported on Discord/Github issues.
# Option 1) NBT-API as a dependency
# Option 1) NBT-API as a dependency (recommended)
Add the following entries to your Gradle build at the correct locations:
@@ -30,19 +33,38 @@ Add the API as dependency to your ``plugin.yml``:
depend: [NBTAPI]
```
# Option 2) Shading the NBT-API into your plugin
Or, if you are using ``paper-plugin.yml``:
To include NBT-API directly in your plugin, you can use the gradle shadow plugin.
```yml
dependencies:
server:
NBTAPI:
load: BEFORE
required: true
join-classpath: true
```
# Option 2) Shading the NBT-API into your plugin (Not recommended)
> [!WARNING]
> Due to the increasing amount of pitfalls in modern Paper, shading is not recommended. Please test with the normal plugin dependency before reporting issues.
To include NBT-API directly in your plugin, you can use the [Gradle Shadow Plugin](https://gradleup.com/shadow/).
Create an empty ``.mojang-mapped`` file in the META-INF folder of your plugin for 1.20+ Paper support.
> [!WARNING]
> Not adding this flag will make the shaded api not work on the latest Paper. It might also break other reflections/nms logic!
Add the plugin to the build configuration, as shown here:
```groovy
plugins {
id("com.github.johnrengelman.shadow") version "VERSION"
id("com.gradleup.shadow") version "VERSION"
}
```
The latest version of the shadow plugin can be found [here](https://github.com/johnrengelman/shadow/releases).
The latest version of the shadow plugin can be found [here](https://plugins.gradle.org/plugin/com.gradleup.shadow).
Add NBT-API to your dependencies:
+24 -2
View File
@@ -2,8 +2,11 @@ To start using NB-API, you either need to depend on its plugin version, or shade
> [!IMPORTANT]
> Plugin and shaded versions have different ``artifactId``. Make sure to correctly choose the one you need!
>
> [!IMPORTANT]
> Alternative ways of loading the api like Libby are not supported on Discord/Github issues.
# Option 1) NBT-API as a dependency
# Option 1) NBT-API as a dependency (recommended)
Add the following entries to your pom at the correct locations:
@@ -37,10 +40,29 @@ Add the API as dependency to your ``plugin.yml``:
depend: [NBTAPI]
```
# Option 2) Shading the NBT-API into your plugin
Or, if you are using ``paper-plugin.yml``:
```yml
dependencies:
server:
NBTAPI:
load: BEFORE
required: true
join-classpath: true
```
# Option 2) Shading the NBT-API into your plugin (Not recommended)
> [!WARNING]
> Due to the increasing amount of pitfalls in modern Paper, shading is not recommended. Please test with the normal plugin dependency before reporting issues.
To include NBT-API directly in your plugin, you can use the maven shade plugin.
Create an empty ``.mojang-mapped`` file in the META-INF folder of your plugin for 1.20+ Paper support.
> [!WARNING]
> Not adding this flag will make the shaded api not work on the latest Paper. It might also break other reflections/nms logic!
Add the plugin to the build configuration, as shown here:
```xml
+89 -24
View File
@@ -2,7 +2,7 @@
### Basics overview
Most of the things are exposed inside the [NBT](https://tr7zw.github.io/Item-NBT-API/v2-api/de/tr7zw/changeme/nbtapi/NBT.html) class. Make sure to explore the Javadoc, or ask your IDE for suggestions!
Most of the things are exposed inside the [NBT](https://tr7zw.github.io/Item-NBT-API/v2-api/de/tr7zw/changeme/nbtapi/NBT.html) class. Your specific use-case might not yet be covered by the wiki, so make sure to explore the [Javadoc](https://tr7zw.github.io/Item-NBT-API/v2-api/), or ask your IDE for suggestions!
#### Basic getting and setting of data
@@ -43,14 +43,34 @@ nbt.getOrCreateCompound("subtag"); // Get or create a subtag
#### Converting NBT to String and the String back to NBT
```java
// Parse Mojang-Json string to nbt
// Parse SNBT to nbt
ReadWriteNBT nbt = NBT.parseNBT("{Health:20.0f,Motion:[0.0d,10.0d,0.0d],Silent:1b}");
// Get the NBT back as a Mojang-Json string (works with any NBT object)
String json = nbt.toString();
// Get the NBT back as a SNBT (works with any NBT object)
String snbt = nbt.toString();
// Turn back into nbt again
ReadWriteNBT nbt2 = NBT.parseNBT(json);
ReadWriteNBT nbt2 = NBT.parseNBT(snbt);
```
#### Comparing NBT data
As with other objects in Java, you may compare nbt using `equals`.
To see what exactly mismatched, you can use `ReadableNBT#extractDifference`:
```java
ReadWriteNBT nbt1 = NBT.parseNBT("{intTag:1,compoundTag:{floatTag:20.0f,booleanTag:1b}},intArray:[I;1,2]");
ReadWriteNBT nbt2 = NBT.parseNBT("{intTag:1,compoundTag:{floatTag:20.0f,booleanTag:0b}},intArray:[I;1,2,3],alsoIntTag:2");
ReadWriteNBT diff1 = nbt1.extractDifference(nbt2);
ReadWriteNBT diff2 = nbt2.extractDifference(nbt1);
```
For the example above, `ReadableNBT#toString` will produce:
diff1: `{compoundTag:{booleanTag:1b},intArray:[I;1,2]}`
diff2: `{compoundTag:{booleanTag:0b},intArray:[I;1,2,3],alsoIntTag:2}`
#### Merging Compounds
You can "merge" the data from any given Compound onto some other Compound. This will overwrite the tags with the same name.
@@ -115,9 +135,13 @@ nbt.resolveOrDefault("list_key[-1]", "fallback_value"); // Get the last value in
// NBT compound lists
// Get the list (will create it if needed)
ReadWriteNBTCompoundList nbtList = nbt.getOrCreateCompound("foo").getCompoundList("other_key");
ReadWriteNBT nbtListEntry = addCompound();
// Add new compound to the list
ReadWriteNBT nbtListEntry = nbtList.addCompound();
nbtListEntry.setBoolean("bar", true);
// Add existing nbt compound to the list
ReadWriteNBT otherNbtListEntry = nbtList.addCompound(NBT.parseNBT("{foo_bar:1b}"));
// You can fetch compounds in lists
nbt.resolveCompound("foo.other_key[0]"); // Get the first compound in list, or null
@@ -162,12 +186,33 @@ int someValue = NBT.modify(itemStack, nbt -> {
> [!WARNING]
> Never mix the usage of ItemMeta and NBT.
> Setting ItemMeta will override any changes made to item's nbt.
```java
// WRONG, do not do this!
ItemMeta meta = itemStack.getItemMeta();
meta.setDisplayName("Modified!");
NBT.modify(itemStack, nbt -> nbt.setBoolean("modified", true));
itemStack.setItemMeta(meta); // Will undo all changes to nbt!
// Correct, both ItemMeta and NBT will be applied
NBT.modify(itemStack, nbt -> nbt.setBoolean("modified", true));
// Taking ItemMeta snapshot after changes to nbt
ItemMeta meta = itemStack.getItemMeta();
meta.setDisplayName("Modified!");
itemStack.setItemMeta(meta);
// If making any further changes with NBT & ItemMeta,
// re-take the item's ItemMeta after changing the nbt!
```
Alternatively, you may safely modify ItemMeta inside the NBT scope:
```java
// Updating ItemMeta using NBT
NBT.modify(itemStack, nbt -> {
nbt.setInteger("kills", nbt.getOrDefault("kills", 0) + 1);
nbt.modifyMeta((meta, readOnlyNbt) -> { // Do not modify the nbt while modifying the meta!
nbt.modifyMeta((readOnlyNbt, meta) -> { // Do not modify the nbt while modifying the meta!
meta.setDisplayName("Kills: " + readOnlyNbt.getOrDefault("kills", 0));
});
// Do more stuff
@@ -184,6 +229,15 @@ NBT.modify(itemStack, nbt -> {
```java
// NOTE: This code is only for 1.20.5+!
// Only reading vanilla data
NBT.getComponents(item, nbt -> {
if (nbt.hasTag("minecraft:custom_name")) {
String customName = nbt.getString("minecraft:custom_name");
}
});
// Modifying vanilla data
NBT.modifyComponents(item, nbt -> {
nbt.setString("minecraft:custom_name", "{\"extra\":[\"foobar\"],\"text\":\"\"}");
});
@@ -209,7 +263,12 @@ NBT.modify(entity, nbt -> {
#### Accessing custom data
For reading/storing custom data on (block-)entities, you should use methods that end with PersistentData.
> [!WARNING]
> Persistent data storage for custom (block-)entity nbt is only available in 1.14+.
>
> If you need to support versions below that, for entities you may use a workaround like storing data inside an item's nbt that the entity is wearing (e.g. having a button in mob's helmet, and storing data on that button).
For reading/storing custom data on (block-)entities, you should use methods that end with ``PersistentData``.
> [!IMPORTANT]
> When working with block entities, make sure that the block entity exists in the world.
@@ -271,26 +330,32 @@ Moreover, since the data is stored inside a Chunk, this will increase the chunk'
### NBT files
```java
// Creating nbt file
// NBTFile will automatically create the file if it does not exist
NBTFile file = new NBTFile(new File("directory"), "test.nbt"); // Will be created at ./directory/test.nbt
// Setting data
file.setString("foo", "bar");
// Saving file
file.save();
NBTFileHandle allows working with nbt files.
// Alternatively, you may use helper methods in NBTFile class
// To read the file without creating it if does not exist:
ReadWriteNBT nbt = NBTFile.readFrom(file);
// To save nbt to the file:
NBTFile.saveTo(file, nbt);
```java
// Will automatically create the file if it does not exist
NBTFileHandle nbtFile = NBT.getFileHandle(new File("directory", "test.nbt"));
// Setting data
nbtFile.setString("foo", "bar");
// Saving the file after applying changes
nbtFile.save();
```
Alternatively, you may read the nbt file without maintaining the link to it.
Unlike NBTFileHandle, the file won't be automatically created if it does not exist.
```java
File file = new File("directory", "test.nbt");
// Reading data from file (will return an empty compound if the file does not exist)
ReadWriteNBT nbt = NBT.readFile(file);
// Saving nbt to file
NBT.writeFile(file, nbt);
```
### Converting Minecraft Objects to NBT and Strings
The basic idea is that you can convert data into different representations:
Minecraft Objects <-> NBT <-> String (Mojang-Json)
Minecraft Objects <-> NBT <-> String (SNBT)
#### Items
@@ -318,8 +383,8 @@ ReadWriteNBT nbt = NBT.itemStackArrayToNBT(itemStacks);
ItemStack itemStack = NBT.itemStackFromNBT(nbt);
ItemStack[] itemStacks = NBT.itemStackArrayFromNBT(nbt);
// Reminder (NBT <-> String)
String json = nbt.toString();
ReadWriteNBT nbt = NBT.parseNBT(json);
String snbt = nbt.toString();
ReadWriteNBT nbt = NBT.parseNBT(snbt);
```
#### Entities and block entities