Compare commits

..
162 Commits
Author SHA1 Message Date
Nassim Jahnke 488a6b6919 5.2.0 Release 2024-12-06 13:12:43 +01:00
Nassim Jahnke 3cd01978df Implement block and entity picking 2024-12-06 13:02:22 +01:00
Nassim Jahnke 0c4dbbe0bb Warn when not using Java 21+ 2024-12-06 10:56:14 +01:00
Nassim Jahnke 1750131831 Update FUNDING.yml 2024-12-04 22:04:55 +01:00
FlorianMichael 5ac7aaccb7 Add snapshot support section to README 2024-12-04 20:42:40 +01:00
Nassim Jahnke ae60e2f28d Update template protocol 2024-12-04 15:38:24 +01:00
Nassim Jahnke 17a73dff82 Handle set_player_inventory 2024-12-04 15:23:56 +01:00
Nassim Jahnke 5e9d213082 Remove snapshot version 2024-12-02 10:12:41 +01:00
Nassim Jahnke 210b0a6f0e 1.21.4-rc3 2024-12-01 09:38:29 +01:00
Nassim Jahnke f0f87b26d7 Fix 1.21.2 trim material override transition 2024-11-30 13:55:45 +01:00
Nassim Jahnke 45a55a81c7 1.21.4-rc2 2024-11-30 13:55:45 +01:00
Nassim Jahnke b2ec9eab50 1.21.4-rc1 2024-11-30 13:55:45 +01:00
Nassim Jahnke 2f08f0d58c Set max capacity for remaining buf
This allows the returned buffer to be a cached empty buf if the original buffer was already fully read
2024-11-30 13:55:45 +01:00
Nassim Jahnke d3f92ce9b8 Don't swap teleport accept and move packets for 1.21.4 clients
They changed it again. Probably missing the same swap in 1.21.4<->1.21.2 now
2024-11-30 13:55:45 +01:00
Nassim Jahnke cfa20ba418 1.21.4-pre3 2024-11-30 13:55:44 +01:00
Nassim Jahnke de6ac47a2f 1.21.4-pre2 2024-11-30 13:55:44 +01:00
Nassim Jahnke b41733bdf6 1.21.4-pre1 2024-11-30 13:55:44 +01:00
Nassim Jahnke 8f8bc55bd0 24w46a 2024-11-30 13:55:44 +01:00
Nassim Jahnke 81d92a728d Add old custom model data to new float list 2024-11-30 13:55:44 +01:00
Nassim Jahnke 68666d2d44 24w45a 2024-11-30 13:55:44 +01:00
RK_01 e539375143 Only apply chunk loading fix for 1.21.2 clients (#14) 2024-11-30 13:55:43 +01:00
FlorianMichael 0acec719b1 Small cleanup 2024-11-30 13:55:43 +01:00
Nassim Jahnke 93e92ffc82 Handle item name changes in trim material registry 2024-11-30 13:55:43 +01:00
Nassim Jahnke 82c55b1d78 24w44a 2024-11-30 13:55:43 +01:00
Nassim Jahnke dd660a2de0 Add missing UUID to attribute in 1.20.5->1.20.4
Fixes #4293
2024-11-30 13:54:15 +01:00
nwayo 96c12ef483 Use global region scheduler in runSync methods on Folia (#4292) 2024-11-30 13:42:59 +01:00
EnZaXD 1653de70c8 Update block connections file (#4291) 2024-11-29 17:14:43 +01:00
EnZaXD b57265e64f Send full position update packet in 1.20.5->1.21 placement rotation fix (#4290) 2024-11-29 16:02:47 +01:00
lowercasebtw 9d4af84872 Fix footstep particle causing null kick (#4287) 2024-11-28 12:05:22 +01:00
Valaphee The Meerkat 40665782e7 Rewrite ingredient items in 1.20.5 recipe rewriter (#4285) 2024-11-26 17:20:06 +01:00
Valaphee The Meerkat 2d663db53f Fix 1.12 recipes containing stone as placeholder, improve empty handling in 1.20.5/1.21.2 (#4284) 2024-11-26 17:04:50 +01:00
Nassim Jahnke 896c6accfb Fix 1.13 recipe ingredient writing 2024-11-26 16:29:44 +01:00
Valaphee The Meerkat 1785677901 Fix BlockRewriter block event handling (#4282) 2024-11-26 15:53:44 +01:00
Nassim Jahnke e32205ddaf Fix 1.21 food using_converts_to handling
Fixes #4280
2024-11-25 10:14:12 +01:00
Pablo Herrera f93c64d6aa Improve 1.21 client enchantments on legacy servers (#4255)
Signed-off-by: Pablo Herrera <pabloherrerapalacio@gmail.com>
2024-11-24 11:19:05 +01:00
github-actions[bot]andgradle-update-robot b5eb568515 Update Gradle Wrapper from 8.11 to 8.11.1 (#4279)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-11-24 02:09:07 +01:00
EnZaXD 7897fca5be Add config option for 1.20.4->1.20.5 sword blocking fix (#4276) 2024-11-21 19:26:25 +01:00
EnZaXD 3ba86741f9 Send default entity data for items in 1.10->1.11 (#4265) 2024-11-18 15:05:25 +01:00
Nassim Jahnke 5515011644 Address Gradle deprecation warnings 2024-11-17 13:43:10 +01:00
DavyCraft648 f59e2a2de4 Fix Equippable allowed entities reading (#4267) 2024-11-17 12:21:02 +01:00
github-actions[bot]andgradle-update-robot 88c103c0a5 Update Gradle Wrapper from 8.10.2 to 8.11 (#4266)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-11-17 12:19:47 +01:00
Nassim Jahnke 5772ee4a93 Only send tags early for 1.20.5+ clients, track early send properly in 1.20->1.20.2 2024-11-17 11:47:33 +01:00
Nassim Jahnke c525575d37 Revert hard limit in 1.17 book size check 2024-11-11 14:54:38 +01:00
Nassim Jahnke b8a170873d Add more info to missing light data warning 2024-11-11 14:38:10 +01:00
Nassim Jahnke 04e936d487 Some more pre-sizing 2024-11-11 14:33:29 +01:00
EnZaXD 6553fc9ae9 Only print invalid custom payload channel warnings in debug mode (#4257)
We previously had people complaining about this being an error and not understanding what it means + servers can't do anything about these errors anyway.
2024-11-10 21:45:06 +01:00
EnZaXD ddbe8ef0fb Apply page network limit when converting book pages in 1.17->1.17.1 (#4256) 2024-11-10 21:44:10 +01:00
EnZaXD 8e4da81022 Move config option check for placement fix into packet handlers (#4248)
Fixes the config option breaking when using the reload command, also changes the message when using the /reload sub command.
2024-11-06 15:46:11 +01:00
Pro 1620fc35f5 Change "fix-1_21-placement-rotation" to true by default (#4245) 2024-11-06 15:32:15 +01:00
Nassim Jahnke e878d77959 Trim override materials are string to string 2024-11-06 10:42:18 +01:00
Nassim Jahnke deab6a0cac Don't allocate bufs in 1.18/1.20 chunk types
Unlike Mojang, we don't sneak a byte array of data outside of the actual packet reading, so there's no reason to not just use the original buffer.
Slicing doesn't allocate anything while also setting the reader index correctly, as also used in the previous types
2024-11-05 13:43:54 +01:00
Nassim Jahnke 77f0826ec8 Skip extra buf copying entirely if wrapper had no changes 2024-11-04 22:55:40 +01:00
Nassim Jahnke 76db43cab3 Don't copy full transformed buf during every transform
The resulting modified buf is the exact same as before
2024-11-04 22:12:39 +01:00
Nassim Jahnke f0eab71644 Pre-size most allocated byte buffers
Also avoids the default allocation size of 256 bytes for bufs that are much smaller than that
2024-11-04 21:27:09 +01:00
Nassim Jahnke e9985adafc Update mcstructs 2024-11-04 20:34:03 +01:00
Nassim Jahnke 157a1fe249 Small cleanup here and there 2024-11-03 17:12:29 +01:00
Nassim Jahnke d48d0a21db Prettify error messages 2024-11-02 23:13:56 +01:00
Nassim Jahnke 908078becb Bump version to 5.1.2-SNAPSHOT 2024-11-02 22:52:47 +01:00
Nassim Jahnke d0815baac7 5.1.1 Release 2024-11-01 19:00:29 +01:00
EnZaXD bc6ad16d40 Properly remove custom_data component if we created it in 1.20.5+ protocols (#4229) 2024-11-01 18:50:54 +01:00
EnZaXD 33aecef7b3 Handle custom name in block entities in 1.12->1.13 (#4232)
Fixes https://github.com/ViaVersion/ViaFabricPlus/issues/592
2024-11-01 18:18:31 +01:00
Nassim Jahnke b7d37b16ae Correctly convert lock code to json instead
The normal codec doesn't serialize components to nbt, but to json strings in a string tag...
2024-10-31 20:01:36 +01:00
FlorianMichael 2b840abfef Check if blank, not empty 2024-10-31 19:31:34 +01:00
Valaphee The MeerkatandFlorianMichael bc4ad7faa3 Remove empty lock item components in 1.21->1.21.2 (#4228)
* Fix protocol error when an empty lock is sent

* Cleanup code

---------

Co-authored-by: FlorianMichael <florian.michael07@gmail.com>
2024-10-31 19:27:49 +01:00
EnZaXD f08a412db5 Drop idle packets where only horizontal collision changed in 1.21->1.21.2 (#4220) 2024-10-31 10:22:57 +01:00
Nassim Jahnke dcf050a604 Remove unneeded optional item type from Types1_21_2
Was only used in food properties up until 1.21.2 (luckily)
2024-10-31 09:57:04 +01:00
Nassim Jahnke 1f8d1339f5 Fix painting entity data in 1.21->1.21.2
Fixes #4227
2024-10-31 09:38:24 +01:00
Nassim Jahnke 5278f8ba65 Remove enchantments with level 0 in 1.21->1.21.2 2024-10-30 21:40:15 +01:00
RK_01 8fdae33333 Add auto start option to runViaProxy task (#4225) 2024-10-30 20:48:31 +01:00
RK_01 4054e83ffe Skip ViaProxy update check in runViaProxy gradle task (#4224) 2024-10-30 19:40:05 +01:00
RK_01 10f2cad8fd Change the consume animation of swords to block (#4223) 2024-10-30 18:21:00 +01:00
Nassim Jahnke 74b9eb9f45 Fix boat entity type check
As per usual plugins sending data for untracked entities
Fixes #4222
2024-10-30 16:47:34 +01:00
EnZaXD dde599c128 Fix boat colors not visible in 1.21->1.21.2 (#4200) 2024-10-30 10:42:27 +01:00
EnZaXD af8cbaf439 Add item fixes to component rewriter in 1.21.x protocols as well (#4217)
Adds the rarity fix in 1.20.5->1.21 and the item/custom name fix in 1.21->1.21.2 to the component rewriters / chat items.
2024-10-30 10:31:45 +01:00
Nassim Jahnke ad83d01fad Creaking transient extends creaking 2024-10-30 10:18:18 +01:00
EnZaXD 7eb3632144 Fix written_book_content and potion_contents data to tag conversion (#4218) 2024-10-30 09:40:39 +01:00
EnZaXD 1ac668d9f2 Add URL of ViaProxy to runViaProxy task (#4215) 2024-10-30 09:39:15 +01:00
EnZaXD f5033342c9 Use correct tag name for 1.21->1.21.2 item name fix (#4214) 2024-10-29 14:55:28 +01:00
RK_01 a0c0b7eff2 Add gradle task to quickly test/debug code changes (#4211) 2024-10-29 14:00:55 +01:00
Nassim Jahnke 7985b39ed5 Fix trail particle reading 2024-10-29 13:32:54 +01:00
Nassim Jahnke f26e370a49 Handle 1.21.2 block_crumble particle 2024-10-29 13:15:40 +01:00
RK_01 cb0c301baf Fix 1.21.1 -> 1.21.2 chunk loading edge case (#4212)
Will usually happen on 1.8 servers or older
2024-10-29 12:51:47 +01:00
RK_01 3858a83972 Small code cleanup (#4213) 2024-10-29 12:50:36 +01:00
EnZaXD 82ff0bae49 Fix item_name<->default name priority for items in 1.21->1.21.2 (#4208) 2024-10-29 11:56:23 +01:00
Nassim Jahnke ee16d7af28 Fix two area effect cloud item particle issues 2024-10-28 12:10:36 +01:00
Nassim Jahnke f914d57678 Small cleanup 2024-10-28 11:23:27 +01:00
EnZaXDandNassim Jahnke c13b40a373 Add ParticleRewriter base (#4203)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2024-10-28 11:23:02 +01:00
Nassim Jahnke d60a37f7e6 Flatten some PacketHandlers in rewriters 2024-10-27 23:07:13 +01:00
Nassim Jahnke 3caaed00dc Write enabled features as string array 2024-10-27 16:02:37 +01:00
Nassim Jahnke f56bfbebb5 Update some deps 2024-10-27 14:59:46 +01:00
EnZaXD 3eec520ebd Send enable features packet after the play login packet in 1.19.1->1.19.3 (#4205) 2024-10-27 08:42:03 +01:00
Nassim Jahnke df69f1f344 Fix InformativeException value shuffling 2024-10-26 18:55:32 +02:00
EnZaXD 009b6c810c Fix and add missing javadocs in MappingData interface (#4202) 2024-10-26 18:55:08 +02:00
EnZaXD 65b76d53ef Fix MappingDataBase#getOldBlockId implementation (#4201) 2024-10-26 17:24:34 +02:00
Nassim Jahnke 7be7139241 Handle entity type changes in show_entity hover events
Fixes #4199
2024-10-25 20:45:42 +02:00
Nassim Jahnke 9bc943ea67 Bump version to 5.1.1-SNAPSHOT 2024-10-25 20:34:55 +02:00
Nassim Jahnke f880adced2 5.1.0 Release 2024-10-25 09:24:29 +02:00
Nassim Jahnke fc07601f24 Fix glow squid index shift 2024-10-24 16:55:24 +02:00
Nassim Jahnke ecb241c187 Exclude error prone annotations
Recently added to gson, can be safely excluded
2024-10-24 12:50:36 +02:00
Nassim Jahnke 46040b1f5d Mark fallback return value in getProtocol as unknown 2024-10-23 17:04:54 +02:00
FlorianMichael 54daa11ce4 Fix ProtocolVersion#isKnown javadoc to make difference with isRegistered more clear 2024-10-23 17:02:45 +02:00
RaphiMC c556420870 Add option to construct ChunkSectionLightImpl without block light 2024-10-23 16:42:21 +02:00
FlorianMichael 84d928ebe7 Update version ranges in gradle.properties 2024-10-23 16:25:52 +02:00
FlorianMichael fa6eab5cc3 1.21.3 2024-10-23 15:42:16 +02:00
FlorianMichael 94b26a903c Check for suppress conversion warnings option in ComponentUtil functions 2024-10-22 22:31:17 +02:00
Nassim Jahnke c242456c30 Remove snapshot version 2024-10-22 17:02:14 +02:00
Nassim Jahnke 8391e9d924 Fix consumable writing 2024-10-22 13:23:06 +02:00
RK_01 f5aac9b1ab Convert all data from food component (#13) 2024-10-22 13:21:44 +02:00
RK_01 a6850392e1 Add failsafe handling to ACCEPT_TELEPORTATION packet order fix (#12) 2024-10-22 13:03:43 +02:00
RK_01 2b37178482 Fix ACCEPT_TELEPORTATION packet order (#11) 2024-10-22 11:13:45 +02:00
Nassim Jahnke 82199d9f39 1.21.2-rc2 2024-10-21 18:36:50 +02:00
FlorianMichael c2d2c6d067 Explain SerializerVersion terminology 2024-10-19 14:50:09 +02:00
FlorianMichael 4066a7b5b6 Mark serializer versions in ComponentRewriter as nullable 2024-10-19 14:43:43 +02:00
Nassim Jahnke 4a7624fef4 Update profile actions enum type 2024-10-19 13:18:14 +02:00
EnZaXD e38b3f3824 Add new PROFILE_ACTIONS_ENUM type in Types for 1.21.2+ 2024-10-19 11:45:51 +02:00
Nassim Jahnke 4573035aab 1.21.2-rc1 2024-10-17 15:28:15 +02:00
Nassim Jahnke 393a5ee973 1.21.2-pre5 2024-10-16 16:06:39 +02:00
Nassim Jahnke 080dc18165 1.21.2-pre4 2024-10-15 15:08:36 +02:00
Nassim Jahnke 6fd421d36e Fix finish configuration state change 2024-10-15 15:08:36 +02:00
Nassim Jahnke 84bd1d0782 Use recipe inputs from old recipe packet 2024-10-15 15:08:36 +02:00
Nassim Jahnke cff2303c62 1.21.2-pre3 2024-10-15 15:08:36 +02:00
Nassim Jahnke f5733c2cb8 They fixed the typo 2024-10-15 15:08:36 +02:00
Nassim Jahnke 21fec0e263 1.21.2-pre2 2024-10-15 15:08:36 +02:00
RK_01 093acc519e Fix CONTAINER_SET_SLOT translation (#9) 2024-10-15 15:08:35 +02:00
RK_01 886be3161e Fix EXPLODE knockback check and affected blocks (#8) 2024-10-15 15:08:35 +02:00
RK_01 dc7b708556 Fix PLAYER_POSITION delta movement (#7) 2024-10-15 15:08:35 +02:00
Nassim Jahnke e82f28c1ac Rewrite particles 2024-10-15 15:08:35 +02:00
Nassim Jahnke 7c7239a70d 1.21.2-pre1 2024-10-15 15:08:35 +02:00
Nassim Jahnke 3e3dad9e33 Show notification on recipe add 2024-10-15 15:08:35 +02:00
Nassim Jahnke 4871977681 Fix recipe removal array index 2024-10-15 15:08:34 +02:00
Nassim Jahnke 0a56e57aec Send stonecutter recipes 2024-10-15 15:08:34 +02:00
Nassim Jahnke a6ff477b8a Implement clientbound ghost recipe, fix null recipe groups 2024-10-15 15:08:34 +02:00
Nassim Jahnke ddad0384f3 Make recipes mostly work again 2024-10-15 15:08:34 +02:00
Nassim Jahnke aabe47f8bc Start working on recipe rewriting 2024-10-15 15:08:34 +02:00
Nassim Jahnke 354a5f1b75 Update packet id comments 2024-10-15 15:08:34 +02:00
Nassim Jahnke f58afd434d WIP 24w40a 2024-10-15 15:08:34 +02:00
Nassim Jahnke 57d5652cd5 Remove SetWrapper, moved to addon 2024-10-15 15:08:33 +02:00
Nassim Jahnke 25b521dfcf Rewrite lock nbt 2024-10-15 15:08:33 +02:00
Nassim Jahnke ce655d0679 Use absolute day time value 2024-10-15 15:08:33 +02:00
Nassim Jahnke e4e8297a82 24w39a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 8357fd01aa Update attributes in item hover events 2024-10-15 15:08:33 +02:00
Nassim Jahnke 12b420d3e7 Send instrument registry, handle duration change from ticks to seconds 2024-10-15 15:08:33 +02:00
Nassim Jahnke db20bc0ae4 24w38a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 2a2afa3821 Register component rewriter 2024-10-15 15:08:32 +02:00
Nassim Jahnke f0b2d9aafe 24w37a 2024-10-15 15:08:32 +02:00
Nassim Jahnke cd427a2a39 Don't use -1 to indicate no vehicle 2024-10-15 15:08:32 +02:00
Nassim Jahnke 75537d3f85 Cancel player input if not in a vehicle, fix shift/sprint input 2024-10-15 15:08:32 +02:00
Nassim Jahnke a88e2f3fb5 Set impulse to 0.98 instead of 1 as per vanilla value 2024-10-15 15:08:32 +02:00
Nassim Jahnke 8a41e7add6 Remove new item data from serverbound items 2024-10-15 15:08:32 +02:00
Nassim Jahnke 9c35228287 24w36a 2024-10-15 15:08:32 +02:00
Nassim Jahnke f9ec6b9d03 Split holder implementation 2024-10-15 15:08:31 +02:00
Nassim Jahnke 22d396d909 Add item hover event handling 2024-10-15 15:08:31 +02:00
Nassim Jahnke 39b28e21ca 24w35a, including missed change from 33a 2024-10-15 15:08:31 +02:00
Nassim Jahnke 0488cb7fbe Fix item type in 1.21.2 entity data 2024-10-15 15:08:31 +02:00
Nassim Jahnke ec4aa0637e 24w34a 2024-10-15 15:08:31 +02:00
Nassim Jahnke ffc5584b1c Null check component rewriter 2024-10-15 15:08:31 +02:00
Nassim Jahnke 45c6cfedb0 Update mappings 2024-10-15 15:08:30 +02:00
Nassim Jahnke c150e50636 Store attribute mappings in full 2024-10-15 15:08:30 +02:00
Nassim Jahnke 16e32a62e5 Bump version to 5.1.0-SNAPSHOT 2024-10-15 15:08:27 +02:00
Nassim Jahnke 1d18f2e45e Fix container id conversion and itemrewriter explosion method 2024-10-15 15:08:20 +02:00
Nassim Jahnke e46b38e58a Remove outdated todos 2024-10-15 15:08:20 +02:00
Nassim Jahnke 033741d292 WIP 24w33a 2024-10-15 15:08:20 +02:00
207 changed files with 8467 additions and 2063 deletions

No files matched your search

+1
View File
@@ -1,2 +1,3 @@
github: kennytv
patreon: kennytv
custom: ['https://florianmichael.de/donate']
+4 -1
View File
@@ -109,4 +109,7 @@ nb-configuration.xml
.nb-gradle/
### MacOS ###
.DS_Store
.DS_Store
### Run Folder (ViaProxy) ###
common/run/
+7
View File
@@ -20,6 +20,13 @@ Supported Versions:
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
Snapshot support
--------
**ViaVersion will only be released a few days *after* a Minecraft update** unless the protocol changes of the update were trivial. If you want early-access, usually days or even weeks before the final release, you can subscribe to either:
- [GitHub Sponsors](https://github.com/sponsors/kennytv/sponsorships?sponsor=kennytv&tier_id=385613&preview=false) (preferred option. Use the `/verify` command on this Discord after), or alternatively
- [Patreon](https://www.patreon.com/kennytv/membership) (see the highest tier and make sure to link Patreon to your Discord account under Settings->Connections)
This also includes access to a private repository with the code, which will be pushed to the public repository after the given delay on a Minecraft update.
Releases/Dev Builds
--------
You can find official releases in the following places:
+3 -1
View File
@@ -19,7 +19,9 @@ dependencies {
api(libs.vianbt) {
exclude("it.unimi.dsi", "fastutil")
}
api(libs.gson)
api(libs.gson) {
exclude("com.google.errorprone", "error_prone_annotations")
}
implementation(rootProject.libs.text) {
exclude("com.google.code.gson", "gson")
exclude("com.viaversion", "nbt")
@@ -478,4 +478,12 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean fix1_21PlacementRotation();
/**
* If enabled, 1.20.5+ clients will have sword blocking mechanics on 1.8 servers using the consumable item component.
* Note that you won't be able to see the blocking in first person if the client is older than 1.21.4.
*
* @return true if enabled
*/
boolean swordBlockingViaConsumable();
}
@@ -53,6 +53,14 @@ public interface FullMappings extends BiMappings {
*/
@Nullable String identifier(int id);
/**
* Returns the unmapped string identifier for the given mapped identifier.
*
* @param mappedIdentifier mapped identifier
* @return unmapped string identifier, or null if not found
*/
@Nullable String identifier(String mappedIdentifier);
/**
* Returns the mapped string identifier for the given mapped id.
*
@@ -84,7 +84,18 @@ public class FullMappingsBase implements FullMappings {
}
@Override
public String mappedIdentifier(final int mappedId) {
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
}
@Override
public @Nullable String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
return null;
}
@@ -35,56 +35,82 @@ public interface MappingData {
void load();
/**
* Returns the mapped block state id, or -1 if unmapped.
* Returns the mapped block state id, or 0 if unmapped.
*
* @param id unmapped block state id
* @return mapped block state id, or -1 if unmapped
* @return mapped block state id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold block state mappings
*/
int getNewBlockStateId(int id);
/**
* Returns the mapped block id, or -1 if unmapped.
* Returns the mapped block id, or 0 if unmapped.
*
* @param id unmapped block id
* @return mapped block id, or -1 if unmapped
* @return mapped block id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold block mappings
*/
int getNewBlockId(int id);
/**
* Returns the backwards mapped block id, or 1 if unmapped.
*
* @param id mapped block id
* @return backwards mapped block id, or 1 if unmapped
*/
int getOldBlockId(int id);
/**
* Returns the mapped item id, or -1 if unmapped.
* Returns the mapped item id, or 0 if unmapped.
*
* @param id unmapped item id
* @return mapped item id, or -1 if unmapped
* @return mapped item id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold item mappings
*/
int getNewItemId(int id);
/**
* Returns the backwards mapped item id, or -1 if unmapped.
* Returns the backwards mapped item id, or 1 if unmapped.
*
* @param id mapped item id
* @return backwards mapped item id, or -1 if unmapped
* @return backwards mapped item id, or 1 if unmapped
* @throws NullPointerException if this mappingdata does not hold item mappings
*/
int getOldItemId(int id);
/**
* Returns the mapped particle id, or -1 if unmapped.
* Returns the mapped particle id, or 0 if unmapped.
*
* @param id unmapped particle id
* @return mapped particle id, or -1 if unmapped
* @return mapped particle id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold particle mappings
*/
int getNewParticleId(int id);
/**
* Returns the mapped attribute id, or 0 if unmapped.
*
* @param id unmapped attribute id
* @return mapped attribute id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold attribute mappings
*/
int getNewAttributeId(int id);
/**
* Returns the mapped sound id, or 0 if unmapped.
*
* @param id unmapped sound id
* @return mapped sound id, or 0 if unmapped
* @throws NullPointerException if this mappingdata does not hold sound mappings
*/
int getNewSoundId(int id);
/**
* Returns the backwards mapped sound id, or 1 if unmapped.
*
* @param i mapped sound id
* @return backwards mapped sound id, or 1 if unmapped
*/
int getOldSoundId(int i);
/**
@@ -126,10 +152,10 @@ public interface MappingData {
@Nullable Mappings getEnchantmentMappings();
@Nullable Mappings getAttributeMappings();
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getAttributeMappings();
@Nullable FullMappings getEntityMappings();
@Nullable FullMappings getArgumentTypeMappings();
@@ -43,10 +43,10 @@ public class MappingDataBase implements MappingData {
protected FullMappings entityMappings;
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings attributeMappings;
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected BiMappings attributeMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
@@ -76,8 +76,6 @@ public class MappingDataBase implements MappingData {
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
paintingMappings = loadMappings(data, "paintings");
attributeMappings = loadBiMappings(data, "attributes");
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
final CompoundTag mappedIdentifierData = readMappedIdentifiersFile("identifiers-" + mappedVersion + ".nbt");
@@ -87,6 +85,7 @@ public class MappingDataBase implements MappingData {
argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes");
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
@@ -180,7 +179,7 @@ public class MappingDataBase implements MappingData {
@Override
public int getOldBlockId(final int id) {
return blockMappings.getNewIdOrDefault(id, 1);
return blockMappings.inverse().getNewIdOrDefault(id, 1);
}
@Override
@@ -272,7 +271,7 @@ public class MappingDataBase implements MappingData {
}
@Override
public @Nullable Mappings getAttributeMappings() {
public @Nullable FullMappings getAttributeMappings() {
return attributeMappings;
}
@@ -36,6 +36,7 @@ public class ParticleMappings extends FullMappingsBase {
addBlockParticle("falling_dust");
addBlockParticle("block_marker");
addBlockParticle("dust_pillar");
addBlockParticle("block_crumble");
addItemParticle("item");
}
@@ -78,7 +78,7 @@ public interface DebugHandler {
/**
* Returns whether packets should be logged after being transformed.
* Set to true by default.
* Set to false by default.
*
* @return whether packets should be logged after being transformed
*/
@@ -37,6 +37,13 @@ public class BlockPosition {
return new BlockPosition(x + face.modX(), y + face.modY(), z + face.modZ());
}
public double distanceFromCenterSquared(final double x, final double y, final double z) {
final double dx = this.x + 0.5 - x;
final double dy = this.y + 0.5 - y;
final double dz = this.z + 0.5 - z;
return dx * dx + dy * dy + dz * dz;
}
public int x() {
return x;
}
@@ -66,6 +66,17 @@ public final class ChunkPosition {
return (long) chunkX & 0xffffffffL | ((long) chunkZ & 0xffffffffL) << 32;
}
/**
* Returns a long key for the given block coordinates.
*
* @param x the block X coordinate
* @param z the block Z coordinate
* @return the chunk key
*/
public static long chunkKeyForBlock(final int x, final int z) {
return chunkKey(x >> 4, z >> 4);
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
@@ -35,7 +35,7 @@ public interface Holder<T> {
* @throws IllegalArgumentException if the id is negative
*/
static <T> Holder<T> of(final int id) {
return new HolderImpl<>(id);
return new IdHolder<>(id);
}
/**
@@ -46,7 +46,7 @@ public interface Holder<T> {
* @return a new direct holder
*/
static <T> Holder<T> of(final T value) {
return new HolderImpl<>(value);
return new ValueHolder<>(value);
}
/**
@@ -36,7 +36,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final String tagKey) {
return new HolderSetImpl(tagKey);
return new HolderSetImpl.Tag(tagKey);
}
/**
@@ -46,7 +46,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final int[] ids) {
return new HolderSetImpl(ids);
return new HolderSetImpl.Ids(ids);
}
/**
@@ -22,50 +22,63 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.Arrays;
final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet {
final class HolderSetImpl {
HolderSetImpl(final String tagKey) {
super(tagKey, null);
}
record Tag(String tagKey) implements HolderSet {
@Override
public boolean hasTagKey() {
return true;
}
HolderSetImpl(final int[] ids) {
super(null, ids);
}
@Override
public int[] ids() {
throw new IllegalArgumentException("This holder set has a tag key");
}
@Override
public String tagKey() {
return left();
}
@Override
public boolean hasIds() {
return false;
}
@Override
public boolean hasTagKey() {
return isLeft();
}
@Override
public int[] ids() {
return right();
}
@Override
public boolean hasIds() {
return isRight();
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
if (hasTagKey()) {
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
return this;
}
}
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
record Ids(int[] ids) implements HolderSet {
@Override
public boolean hasTagKey() {
return false;
}
@Override
public String tagKey() {
throw new IllegalArgumentException("This holder set has direct ids");
}
@Override
public boolean hasIds() {
return true;
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new Ids(mappedIds);
}
@Override
public String toString() {
return "Ids{" +
"ids=" + Arrays.toString(ids) +
'}';
}
return new HolderSetImpl(mappedIds);
}
}
@@ -25,49 +25,29 @@ package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
final class HolderImpl<T> implements Holder<T> {
record IdHolder<T>(int id) implements Holder<T> {
private final T value;
private final int id;
HolderImpl(final int id) {
IdHolder {
Preconditions.checkArgument(id >= 0, "id cannot be negative");
this.value = null;
this.id = id;
}
HolderImpl(final T value) {
this.value = value;
this.id = -1;
}
@Override
public boolean isDirect() {
return id == -1;
return false;
}
@Override
public boolean hasId() {
return id != -1;
return true;
}
@Override
public T value() {
Preconditions.checkArgument(isDirect(), "Holder is not direct");
return value;
}
@Override
public int id() {
return id;
throw new IllegalArgumentException("Holder is not direct");
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
if (isDirect()) {
return this;
}
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
@@ -77,12 +57,4 @@ final class HolderImpl<T> implements Holder<T> {
}
return Holder.of(rewrittenId);
}
@Override
public String toString() {
return "HolderImpl{" +
"value=" + value +
", id=" + id +
'}';
}
}
@@ -22,13 +22,19 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record PaintingVariant(int width, int height, String assetId) {
public record PaintingVariant(int width, int height, String assetId, @Nullable Tag title, @Nullable Tag author) {
public static HolderType<PaintingVariant> TYPE = new HolderType<>() {
public PaintingVariant(final int width, final int height, final String assetId) {
this(width, height, assetId, null, null);
}
public static HolderType<PaintingVariant> TYPE1_21 = new HolderType<>() {
@Override
public PaintingVariant readDirect(final ByteBuf buffer) {
final int width = Types.VAR_INT.readPrimitive(buffer);
@@ -44,4 +50,24 @@ public record PaintingVariant(int width, int height, String assetId) {
Types.STRING.write(buffer, variant.assetId());
}
};
public static HolderType<PaintingVariant> TYPE1_21_2 = new HolderType<>() {
@Override
public PaintingVariant readDirect(final ByteBuf buffer) {
final int width = Types.VAR_INT.readPrimitive(buffer);
final int height = Types.VAR_INT.readPrimitive(buffer);
final String assetId = Types.STRING.read(buffer);
final Tag title = Types.OPTIONAL_TAG.read(buffer);
final Tag author = Types.OPTIONAL_TAG.read(buffer);
return new PaintingVariant(width, height, assetId, title, author);
}
@Override
public void writeDirect(final ByteBuf buffer, final PaintingVariant variant) {
Types.VAR_INT.writePrimitive(buffer, variant.width());
Types.VAR_INT.writePrimitive(buffer, variant.height());
Types.STRING.write(buffer, variant.assetId());
Types.OPTIONAL_TAG.write(buffer, variant.title());
Types.OPTIONAL_TAG.write(buffer, variant.author());
}
};
}
@@ -36,4 +36,8 @@ public record RegistryEntry(String key, @Nullable Tag tag) {
public RegistryEntry withKey(final String key) {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
public RegistryEntry copy() {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
record ValueHolder<T>(T value) implements Holder<T> {
@Override
public boolean isDirect() {
return true;
}
@Override
public boolean hasId() {
return false;
}
@Override
public int id() {
return -1;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
return this;
}
}
@@ -37,14 +37,14 @@ public class ChunkSectionImpl implements ChunkSection {
public ChunkSectionImpl(final boolean holdsLight) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
public ChunkSectionImpl(final boolean holdsLight, final int expectedPaletteLength) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE, expectedPaletteLength));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
@@ -35,7 +35,7 @@ public interface ChunkSectionLight {
/**
* Returns whether the section has sky light.
*
* @return true if skylight is present
* @return true if sky light is present
*/
boolean hasSkyLight();
@@ -43,7 +43,7 @@ public interface ChunkSectionLight {
* Returns whether the section has block light.
* This returns true unless specifically set to null.
*
* @return true if skylight is present
* @return true if block light is present
*/
boolean hasBlockLight();
@@ -30,9 +30,17 @@ public class ChunkSectionLightImpl implements ChunkSectionLight {
private NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSectionLightImpl() {
// Block light is always written
this.blockLight = new NibbleArray(ChunkSection.SIZE);
protected ChunkSectionLightImpl() {
}
public static ChunkSectionLight createWithBlockLight() {
final ChunkSectionLightImpl light = new ChunkSectionLightImpl();
light.blockLight = new NibbleArray(ChunkSection.SIZE);
return light;
}
public static ChunkSectionLight createEmpty() {
return new ChunkSectionLightImpl();
}
@Override
@@ -26,6 +26,7 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
@@ -34,13 +35,20 @@ import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
@@ -48,11 +56,15 @@ import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
import com.viaversion.viaversion.util.Unit;
public record StructuredDataKey<T>(String identifier, Type<T> type) {
@@ -64,24 +76,38 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unbreakable> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Types.TAG_ARRAY);
public static final StructuredDataKey<String> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.STRING);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TAG, 256));
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", Types.VAR_INT);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE);
public static final StructuredDataKey<AdventureModePredicate> CAN_PLACE_ON = new StructuredDataKey<>("can_place_on", AdventureModePredicate.TYPE);
public static final StructuredDataKey<AdventureModePredicate> CAN_BREAK = new StructuredDataKey<>("can_break", AdventureModePredicate.TYPE);
public static final StructuredDataKey<AttributeModifiers1_20_5> ATTRIBUTE_MODIFIERS1_20_5 = new StructuredDataKey<>("attribute_modifiers", AttributeModifiers1_20_5.TYPE);
public static final StructuredDataKey<AttributeModifiers1_21> ATTRIBUTE_MODIFIERS1_21 = new StructuredDataKey<>("attribute_modifiers", AttributeModifiers1_21.TYPE);
public static final StructuredDataKey<Integer> CUSTOM_MODEL_DATA = new StructuredDataKey<>("custom_model_data", Types.VAR_INT);
public static final StructuredDataKey<Integer> CUSTOM_MODEL_DATA1_20_5 = new StructuredDataKey<>("custom_model_data", Types.VAR_INT);
public static final StructuredDataKey<CustomModelData1_21_4> CUSTOM_MODEL_DATA1_21_4 = new StructuredDataKey<>("custom_model_data", CustomModelData1_21_4.TYPE);
public static final StructuredDataKey<Unit> HIDE_ADDITIONAL_TOOLTIP = new StructuredDataKey<>("hide_additional_tooltip", Types.EMPTY);
public static final StructuredDataKey<Unit> HIDE_TOOLTIP = new StructuredDataKey<>("hide_tooltip", Types.EMPTY);
public static final StructuredDataKey<Integer> REPAIR_COST = new StructuredDataKey<>("repair_cost", Types.VAR_INT);
public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Types.EMPTY);
public static final StructuredDataKey<Boolean> ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Types.BOOLEAN);
public static final StructuredDataKey<Tag> INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Types.TAG); // Doesn't actually hold data
public static final StructuredDataKey<FoodProperties> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_21_2> FOOD1_21_2 = new StructuredDataKey<>("food", FoodProperties1_21_2.TYPE);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE);
public static final StructuredDataKey<Item> USE_REMAINDER1_21_2 = new StructuredDataKey<>("use_remainder", Types1_21_2.ITEM);
public static final StructuredDataKey<Item> USE_REMAINDER1_21_4 = new StructuredDataKey<>("use_remainder", Types1_21_4.ITEM);
public static final StructuredDataKey<UseCooldown> USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE);
public static final StructuredDataKey<Unit> FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY);
public static final StructuredDataKey<DamageResistant> DAMAGE_RESISTANT = new StructuredDataKey<>("damage_resistant", DamageResistant.TYPE);
public static final StructuredDataKey<ToolProperties> TOOL = new StructuredDataKey<>("tool", ToolProperties.TYPE);
public static final StructuredDataKey<Integer> ENCHANTABLE = new StructuredDataKey<>("enchantable", Types.VAR_INT);
public static final StructuredDataKey<Equippable> EQUIPPABLE = new StructuredDataKey<>("equippable", Equippable.TYPE);
public static final StructuredDataKey<HolderSet> REPAIRABLE = new StructuredDataKey<>("repairable", Types.HOLDER_SET);
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<String> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.STRING);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE);
public static final StructuredDataKey<DyedColor> DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE);
public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Types.INT);
@@ -90,18 +116,26 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> MAP_POST_PROCESSING = new StructuredDataKey<>("map_post_processing", Types.VAR_INT);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_20_5 = new StructuredDataKey<>("charged_projectiles", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21 = new StructuredDataKey<>("charged_projectiles", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21_2 = new StructuredDataKey<>("charged_projectiles", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21_4 = new StructuredDataKey<>("charged_projectiles", Types1_21_4.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_20_5 = new StructuredDataKey<>("bundle_contents", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21 = new StructuredDataKey<>("bundle_contents", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS = new StructuredDataKey<>("potion_contents", PotionContents.TYPE);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21_2 = new StructuredDataKey<>("bundle_contents", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21_4 = new StructuredDataKey<>("bundle_contents", Types1_21_4.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_20_5 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_20_5);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_21_2 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_21_2);
public static final StructuredDataKey<SuspiciousStewEffect[]> SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", SuspiciousStewEffect.ARRAY_TYPE);
public static final StructuredDataKey<FilterableString[]> WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", FilterableString.ARRAY_TYPE);
public static final StructuredDataKey<WrittenBook> WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE);
public static final StructuredDataKey<ArmorTrim> TRIM = new StructuredDataKey<>("trim", ArmorTrim.TYPE);
public static final StructuredDataKey<ArmorTrim> TRIM1_20_5 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_20_5);
public static final StructuredDataKey<ArmorTrim> TRIM1_21_2 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_2);
public static final StructuredDataKey<ArmorTrim> TRIM1_21_4 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_4);
public static final StructuredDataKey<CompoundTag> DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<Holder<Instrument>> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.TYPE);
public static final StructuredDataKey<Holder<Instrument1_20_5>> INSTRUMENT1_20_5 = new StructuredDataKey<>("instrument", Instrument1_20_5.TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE);
public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Types.TAG);
@@ -115,6 +149,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<PotDecorations> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE);
public static final StructuredDataKey<Item[]> CONTAINER1_20_5 = new StructuredDataKey<>("container", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21 = new StructuredDataKey<>("container", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21_2 = new StructuredDataKey<>("container", new ArrayType<>(Types1_21_2.ITEM, 256));
public static final StructuredDataKey<Item[]> CONTAINER1_21_4 = new StructuredDataKey<>("container", Types1_21_4.ITEM_ARRAY);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<Tag> LOCK = new StructuredDataKey<>("lock", Types.TAG);
@@ -0,0 +1,314 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_2 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
PLAYER(LIVING_ENTITY),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
COW(ABSTRACT_ANIMAL),
MOOSHROOM(COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(ABSTRACT_CHESTED_HORSE),
MULE(ABSTRACT_CHESTED_HORSE),
LLAMA(ABSTRACT_CHESTED_HORSE),
TRADER_LLAMA(LLAMA),
// Monsters
ABSTRACT_MONSTER(PATHFINDER_MOB, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
BREEZE(ABSTRACT_MONSTER),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
CREAKING(ABSTRACT_MONSTER),
CREAKING_TRANSIENT(CREAKING),
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
BOGGED(ABSTRACT_SKELETON),
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
// Water mobs
AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null),
DOLPHIN(AGEABLE_WATER_CREATURE),
SQUID(AGEABLE_WATER_CREATURE),
GLOW_SQUID(SQUID),
WATER_ANIMAL(PATHFINDER_MOB, null),
ABSTRACT_FISH(WATER_ANIMAL, null),
PUFFERFISH(ABSTRACT_FISH),
TADPOLE(ABSTRACT_FISH),
ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null),
COD(ABSTRACT_SCHOOLING_FISH),
SALMON(ABSTRACT_SCHOOLING_FISH),
TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH),
// Raiders
ABSTRACT_RAIDER(ABSTRACT_MONSTER, null),
WITCH(ABSTRACT_RAIDER),
RAVAGER(ABSTRACT_RAIDER),
ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null),
SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null),
VINDICATOR(ABSTRACT_ILLAGER),
PILLAGER(ABSTRACT_ILLAGER),
EVOKER(SPELLCASTER_ILLAGER),
ILLUSIONER(SPELLCASTER_ILLAGER);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
EntityTypes1_21_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_2(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -0,0 +1,313 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_4 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
PLAYER(LIVING_ENTITY),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
COW(ABSTRACT_ANIMAL),
MOOSHROOM(COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(ABSTRACT_CHESTED_HORSE),
MULE(ABSTRACT_CHESTED_HORSE),
LLAMA(ABSTRACT_CHESTED_HORSE),
TRADER_LLAMA(LLAMA),
// Monsters
ABSTRACT_MONSTER(PATHFINDER_MOB, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
BREEZE(ABSTRACT_MONSTER),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
CREAKING(ABSTRACT_MONSTER),
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
BOGGED(ABSTRACT_SKELETON),
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
// Water mobs
AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null),
DOLPHIN(AGEABLE_WATER_CREATURE),
SQUID(AGEABLE_WATER_CREATURE),
GLOW_SQUID(SQUID),
WATER_ANIMAL(PATHFINDER_MOB, null),
ABSTRACT_FISH(WATER_ANIMAL, null),
PUFFERFISH(ABSTRACT_FISH),
TADPOLE(ABSTRACT_FISH),
ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null),
COD(ABSTRACT_SCHOOLING_FISH),
SALMON(ABSTRACT_SCHOOLING_FISH),
TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH),
// Raiders
ABSTRACT_RAIDER(ABSTRACT_MONSTER, null),
WITCH(ABSTRACT_RAIDER),
RAVAGER(ABSTRACT_RAIDER),
ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null),
SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null),
VINDICATOR(ABSTRACT_ILLAGER),
PILLAGER(ABSTRACT_ILLAGER),
EVOKER(SPELLCASTER_ILLAGER),
ILLUSIONER(SPELLCASTER_ILLAGER);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
EntityTypes1_21_4(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_4(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -26,10 +26,11 @@ import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
@@ -40,7 +41,7 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType = add(7, Types1_21.ITEM);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
@@ -59,14 +60,15 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType wolfVariantType = add(23, WolfVariant.TYPE);
public final EntityDataType frogVariantType = add(24, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(25, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE);
public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE1_21);
public final EntityDataType snifferState = add(27, Types.VAR_INT);
public final EntityDataType armadilloState = add(28, Types.VAR_INT);
public final EntityDataType vector3FType = add(29, Types.VECTOR3F);
public final EntityDataType quaternionType = add(30, Types.QUATERNION);
public EntityDataTypes1_21(final ParticleType particleType, final ArrayType<Particle> particlesType) {
public EntityDataTypes1_21(final Type<Item> itemType, final ParticleType particleType, final ArrayType<Particle> particlesType) {
super(31);
this.itemType = add(7, itemType);
this.particleType = add(17, particleType);
this.particlesType = add(18, particlesType);
}
@@ -0,0 +1,74 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entitydata.types;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
public final class EntityDataTypes1_21_2 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(21, Types.VAR_INT);
public final EntityDataType catVariantType = add(22, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(23, WolfVariant.TYPE);
public final EntityDataType frogVariantType = add(24, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(25, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(27, Types.VAR_INT);
public final EntityDataType armadilloState = add(28, Types.VAR_INT);
public final EntityDataType vector3FType = add(29, Types.VECTOR3F);
public final EntityDataType quaternionType = add(30, Types.QUATERNION);
public EntityDataTypes1_21_2(final Type<Item> itemType, final ParticleType particleType, final Type<Particle[]> particlesType) {
super(31);
this.itemType = add(7, itemType);
this.particleType = add(17, particleType);
this.particlesType = add(18, particlesType);
}
}
@@ -29,10 +29,10 @@ import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPattern> pattern, boolean showInTooltip) {
public static final Type<ArmorTrim> TYPE = new Type<>(ArmorTrim.class) {
public static final Type<ArmorTrim> TYPE1_20_5 = new Type<>(ArmorTrim.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE.read(buffer);
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_20_5.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
@@ -40,7 +40,39 @@ public record ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPatt
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE.write(buffer, value.material);
ArmorTrimMaterial.TYPE1_20_5.write(buffer, value.material);
ArmorTrimPattern.TYPE.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<ArmorTrim> TYPE1_21_2 = new Type<>(ArmorTrim.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_21_2.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_21_2.write(buffer, value.material);
ArmorTrimPattern.TYPE.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<ArmorTrim> TYPE1_21_4 = new Type<>(ArmorTrim.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_21_4.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_21_4.write(buffer, value.material);
ArmorTrimPattern.TYPE.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
@@ -27,13 +27,19 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.util.Map;
public record ArmorTrimMaterial(String assetName, int itemId, float itemModelIndex,
Int2ObjectMap<String> overrideArmorMaterials, Tag description) {
Map<String, String> overrideArmorMaterials, Tag description) {
public static final HolderType<ArmorTrimMaterial> TYPE = new HolderType<>() {
public ArmorTrimMaterial(final String assetName, final int itemId, final Map<String, String> overrideArmorMaterials, final Tag description) {
this(assetName, itemId, 0F, overrideArmorMaterials, description);
}
public static final HolderType<ArmorTrimMaterial> TYPE1_20_5 = new HolderType<>() {
// The override key is an int, but given we don't use it at all and that creating a new type is annoying,
// we'll just store it in the string map:tm:
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
@@ -41,10 +47,45 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
final float itemModelIndex = buffer.readFloat();
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
final Int2ObjectMap<String> overrideArmorMaterials = new Int2ObjectOpenHashMap<>(overrideArmorMaterialsSize);
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize);
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
final int key = Types.VAR_INT.readPrimitive(buffer);
final String value = Types.STRING.read(buffer);
overrideArmorMaterials.put(Integer.toString(key), value);
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, item, itemModelIndex, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.itemId());
buffer.writeFloat(value.itemModelIndex());
Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size());
for (final Map.Entry<String, String> entry : value.overrideArmorMaterials().entrySet()) {
Types.VAR_INT.writePrimitive(buffer, Integer.parseInt(entry.getKey()));
Types.STRING.write(buffer, entry.getValue());
}
Types.TAG.write(buffer, value.description());
}
};
public static final HolderType<ArmorTrimMaterial> TYPE1_21_2 = new HolderType<>() {
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int item = Types.VAR_INT.readPrimitive(buffer);
final float itemModelIndex = buffer.readFloat();
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize);
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
final String key = Types.STRING.read(buffer);
final String value = Types.STRING.read(buffer);
overrideArmorMaterials.put(key, value);
}
@@ -59,8 +100,41 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
buffer.writeFloat(value.itemModelIndex());
Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size());
for (final Int2ObjectMap.Entry<String> entry : value.overrideArmorMaterials().int2ObjectEntrySet()) {
Types.VAR_INT.writePrimitive(buffer, entry.getIntKey());
for (final Map.Entry<String, String> entry : value.overrideArmorMaterials().entrySet()) {
Types.STRING.write(buffer, entry.getKey());
Types.STRING.write(buffer, entry.getValue());
}
Types.TAG.write(buffer, value.description());
}
};
public static final HolderType<ArmorTrimMaterial> TYPE1_21_4 = new HolderType<>() {
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int item = Types.VAR_INT.readPrimitive(buffer);
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
final Map<String, String> overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize);
for (int i = 0; i < overrideArmorMaterialsSize; i++) {
final String key = Types.STRING.read(buffer);
final String value = Types.STRING.read(buffer);
overrideArmorMaterials.put(key, value);
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, item, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.itemId());
Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size());
for (final Map.Entry<String, String> entry : value.overrideArmorMaterials().entrySet()) {
Types.STRING.write(buffer, entry.getKey());
Types.STRING.write(buffer, entry.getValue());
}
@@ -0,0 +1,111 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<SoundEvent> sound,
boolean hasConsumeParticles, ConsumeEffect<?>[] consumeEffects) {
public static final Type<?>[] EFFECT_TYPES = {
ApplyStatusEffects.TYPE,
Types.HOLDER_SET, // remove effects
Types.EMPTY, // clear all effects
Types.FLOAT, // teleport randomly
Types.SOUND_EVENT // play sound
};
public static final Type<Consumable1_21_2> TYPE = new Type<>(Consumable1_21_2.class) {
@Override
public Consumable1_21_2 read(final ByteBuf buffer) {
final float consumeSeconds = buffer.readFloat();
final int animationType = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final boolean hasConsumeParticles = buffer.readBoolean();
final ConsumeEffect<?>[] consumeEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects);
}
@Override
public void write(final ByteBuf buffer, final Consumable1_21_2 value) {
buffer.writeFloat(value.consumeSeconds);
Types.VAR_INT.writePrimitive(buffer, value.animationType);
Types.SOUND_EVENT.write(buffer, value.sound);
buffer.writeBoolean(value.hasConsumeParticles);
ConsumeEffect.ARRAY_TYPE.write(buffer, value.consumeEffects);
}
};
public record ConsumeEffect<T>(int id, Type<T> type, T value) {
public static final Type<ConsumeEffect<?>> TYPE = new Type<>(ConsumeEffect.class) {
@Override
public ConsumeEffect<?> read(final ByteBuf buffer) {
// Oh no...
final int effectType = Types.VAR_INT.readPrimitive(buffer);
final Type<?> type = EFFECT_TYPES[effectType];
final Object value = type.read(buffer);
return ConsumeEffect.of(effectType, type, value);
}
@Override
public void write(final ByteBuf buffer, final ConsumeEffect<?> value) {
Types.VAR_INT.writePrimitive(buffer, value.id);
value.writeValue(buffer);
}
};
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE = new ArrayType<>(TYPE);
static <T> ConsumeEffect<T> of(final int id, final Type<T> type, final Object value) {
//noinspection unchecked
return new ConsumeEffect<>(id, type, (T) value);
}
void writeValue(final ByteBuf buf) {
this.type.write(buf, this.value);
}
}
public record ApplyStatusEffects(PotionEffect[] effects, float probability) {
public static final Type<ApplyStatusEffects> TYPE = new Type<>(ApplyStatusEffects.class) {
@Override
public ApplyStatusEffects read(final ByteBuf buffer) {
final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer);
final float probability = buffer.readFloat();
return new ApplyStatusEffects(effects, probability);
}
@Override
public void write(final ByteBuf buffer, final ApplyStatusEffects value) {
PotionEffect.ARRAY_TYPE.write(buffer, value.effects);
buffer.writeFloat(value.probability);
}
};
}
}
@@ -0,0 +1,49 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record CustomModelData1_21_4(float[] floats, boolean[] booleans, String[] strings, int[] colors) {
public static final Type<CustomModelData1_21_4> TYPE = new Type<>(CustomModelData1_21_4.class) {
@Override
public CustomModelData1_21_4 read(final ByteBuf buffer) {
final float[] floats = Types.FLOAT_ARRAY_PRIMITIVE.read(buffer);
final boolean[] booleans = Types.BOOLEAN_ARRAY_PRIMITIVE.read(buffer);
final String[] strings = Types.STRING_ARRAY.read(buffer);
final int[] colors = Types.INT_ARRAY_PRIMITIVE.read(buffer);
return new CustomModelData1_21_4(floats, booleans, strings, colors);
}
@Override
public void write(final ByteBuf buffer, final CustomModelData1_21_4 value) {
Types.FLOAT_ARRAY_PRIMITIVE.write(buffer, value.floats());
Types.BOOLEAN_ARRAY_PRIMITIVE.write(buffer, value.booleans());
Types.STRING_ARRAY.write(buffer, value.strings());
Types.INT_ARRAY_PRIMITIVE.write(buffer, value.colors());
}
};
}
@@ -0,0 +1,43 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record DamageResistant(String typesTagKey) {
public static final Type<DamageResistant> TYPE = new Type<>(DamageResistant.class) {
@Override
public DamageResistant read(final ByteBuf buffer) {
final String typesTagKey = Types.STRING.read(buffer);
return new DamageResistant(typesTagKey);
}
@Override
public void write(final ByteBuf buffer, final DamageResistant value) {
Types.STRING.write(buffer, value.typesTagKey());
}
};
}
@@ -22,26 +22,23 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2.ConsumeEffect;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodEffect(PotionEffect effect, float probability) {
public record DeathProtection(ConsumeEffect<?>[] deathEffects) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
public static final Type<DeathProtection> TYPE = new Type<>(DeathProtection.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
public DeathProtection read(final ByteBuf buffer) {
final ConsumeEffect<?>[] deathEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new DeathProtection(deathEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
public void write(final ByteBuf buffer, final DeathProtection value) {
ConsumeEffect.ARRAY_TYPE.write(buffer, value.deathEffects);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
@@ -0,0 +1,69 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Nullable String model,
@Nullable String cameraOverlay, @Nullable HolderSet allowedEntities, boolean dispensable,
boolean swappable, boolean damageOnHurt) {
public static final Type<Equippable> TYPE = new Type<>(Equippable.class) {
@Override
public Equippable read(final ByteBuf buffer) {
final int equipmentSlot = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final String model = Types.OPTIONAL_STRING.read(buffer);
final String cameraOverlay = Types.OPTIONAL_STRING.read(buffer);
final HolderSet allowedEntities = Types.OPTIONAL_HOLDER_SET.read(buffer);
final boolean dispensable = buffer.readBoolean();
final boolean swappable = buffer.readBoolean();
final boolean damageOnHurt = buffer.readBoolean();
return new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
@Override
public void write(final ByteBuf buffer, final Equippable value) {
Types.VAR_INT.writePrimitive(buffer, value.equipmentSlot());
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.OPTIONAL_STRING.write(buffer, value.model());
Types.OPTIONAL_STRING.write(buffer, value.cameraOverlay());
Types.OPTIONAL_HOLDER_SET.write(buffer, value.allowedEntities());
buffer.writeBoolean(value.dispensable());
buffer.writeBoolean(value.swappable());
buffer.writeBoolean(value.damageOnHurt());
}
};
public Equippable rewrite(final Int2IntFunction soundIdRewriter) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriter);
return soundEvent == this.soundEvent ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
}
@@ -25,25 +25,27 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record FoodProperties(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
Item usingConvertsTo, FoodEffect[] possibleEffects) {
public record FoodProperties1_20_5(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
@Nullable Item usingConvertsTo, FoodEffect[] possibleEffects) {
public static final Type<FoodProperties> TYPE1_20_5 = new Type<>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_20_5 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -51,20 +53,20 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public static final Type<FoodProperties> TYPE1_21 = new Type<FoodProperties>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_21 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final Item usingConvertsTo = Types1_21.OPTIONAL_ITEM.read(buffer);
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -73,4 +75,23 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public record FoodEffect(PotionEffect effect, float probability) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodProperties1_21_2(int nutrition, float saturationModifier, boolean canAlwaysEat) {
public static final Type<FoodProperties1_21_2> TYPE = new Type<>(FoodProperties1_21_2.class) {
@Override
public FoodProperties1_21_2 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
return new FoodProperties1_21_2(nutrition, saturationModifier, canAlwaysEat);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties1_21_2 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
}
};
}
@@ -29,27 +29,27 @@ import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float range) {
public record Instrument1_20_5(Holder<SoundEvent> soundEvent, int useDuration, float range) {
public static final HolderType<Instrument> TYPE = new HolderType<>() {
public static final HolderType<Instrument1_20_5> TYPE = new HolderType<>() {
@Override
public Instrument readDirect(final ByteBuf buffer) {
public Instrument1_20_5 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final int useDuration = Types.VAR_INT.readPrimitive(buffer);
final float range = buffer.readFloat();
return new Instrument(soundEvent, useDuration, range);
final float range = Types.FLOAT.readPrimitive(buffer);
return new Instrument1_20_5(soundEvent, useDuration, range);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument value) {
public void writeDirect(final ByteBuf buffer, final Instrument1_20_5 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.VAR_INT.writePrimitive(buffer, value.useDuration());
buffer.writeFloat(value.range());
Types.FLOAT.writePrimitive(buffer, value.range());
}
};
public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) {
public Instrument1_20_5 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range);
return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range);
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration, float range, Tag description) {
public static final HolderType<Instrument1_21_2> TYPE = new HolderType<>() {
@Override
public Instrument1_21_2 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final float useDuration = Types.FLOAT.readPrimitive(buffer);
final float range = Types.FLOAT.readPrimitive(buffer);
final Tag description = Types.TAG.read(buffer);
return new Instrument1_21_2(soundEvent, useDuration, range, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument1_21_2 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.FLOAT.writePrimitive(buffer, value.useDuration());
Types.FLOAT.writePrimitive(buffer, value.range());
Types.TAG.write(buffer, value.description());
}
};
public Instrument1_21_2 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description);
}
}
@@ -27,15 +27,20 @@ import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects) {
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects,
@Nullable String customName) {
public static final Type<PotionContents> TYPE = new Type<>(PotionContents.class) {
public PotionContents(final @Nullable Integer potion, final @Nullable Integer customColor, final PotionEffect[] customEffects) {
this(potion, customColor, customEffects, null);
}
public static final Type<PotionContents> TYPE1_20_5 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
return new PotionContents(potion, customColor, customEffects);
return new PotionContents(potion, customColor, customEffects, null);
}
@Override
@@ -53,4 +58,31 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
}
};
public static final Type<PotionContents> TYPE1_21_2 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
final String customName = Types.OPTIONAL_STRING.read(buffer);
return new PotionContents(potion, customColor, customEffects, customName);
}
@Override
public void write(final ByteBuf buffer, final PotionContents value) {
buffer.writeBoolean(value.potion != null);
if (value.potion != null) {
Types.VAR_INT.writePrimitive(buffer, value.potion);
}
buffer.writeBoolean(value.customColor != null);
if (value.customColor != null) {
buffer.writeInt(value.customColor);
}
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
Types.OPTIONAL_STRING.write(buffer, value.customName);
}
};
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public record UseCooldown(float seconds, @Nullable String cooldownGroup) {
public static final Type<UseCooldown> TYPE = new Type<>(UseCooldown.class) {
@Override
public UseCooldown read(final ByteBuf buffer) {
final float seconds = buffer.readFloat();
final String cooldownGroup = Types.OPTIONAL_STRING.read(buffer);
return new UseCooldown(seconds, cooldownGroup);
}
@Override
public void write(final ByteBuf buffer, final UseCooldown value) {
buffer.writeFloat(value.seconds());
Types.OPTIONAL_STRING.write(buffer, value.cooldownGroup());
}
};
public UseCooldown rewrite(final Function<String, String> idRewriter) {
if (cooldownGroup == null) {
return this;
}
final String mappedCooldownGroup = idRewriter.apply(cooldownGroup);
return new UseCooldown(seconds, mappedCooldownGroup);
}
}
@@ -198,6 +198,14 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
public void registerFinishConfiguration(final CU packetType, final PacketHandler handler) {
registerClientbound(packetType, wrapper -> {
// TODO Temporary solution to handle the finish configuration packet already having changed our tracked protocol state in a previous handler
wrapper.user().getProtocolInfo().setServerState(State.CONFIGURATION);
handler.handle(wrapper);
});
}
@Override
public final void loadMappingData() {
getMappingData().load();
@@ -36,6 +36,7 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.rewriter.ParticleRewriter;
import com.viaversion.viaversion.api.rewriter.TagRewriter;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.exception.CancelException;
@@ -374,6 +375,15 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
return null;
}
/**
* Returns the protocol's particle rewriter if present.
*
* @return particle rewriter
*/
default @Nullable ParticleRewriter getParticleRewriter() {
return null;
}
/**
* Returns the protocol's tag rewriter if present.
*
@@ -43,7 +43,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private static final List<ProtocolVersion> VERSION_LIST = new ArrayList<>();
public static final ProtocolVersion v1_7_2 = register(4, "1.7.2-1.7.5", new SubVersionRange("1.7", 2, 5));
@Deprecated(forRemoval=true) public static final ProtocolVersion v1_7_1 = v1_7_2;
@Deprecated(forRemoval = true)
public static final ProtocolVersion v1_7_1 = v1_7_2;
public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10));
public static final ProtocolVersion v1_8 = register(47, "1.8.x", new SubVersionRange("1.8", 0, 9));
public static final ProtocolVersion v1_9 = register(107, "1.9");
@@ -85,8 +86,14 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_20_3 = register(765, "1.20.3-1.20.4", new SubVersionRange("1.20", 3, 4));
public static final ProtocolVersion v1_20_5 = register(766, "1.20.5-1.20.6", new SubVersionRange("1.20", 5, 6));
public static final ProtocolVersion v1_21 = register(767, "1.21-1.21.1", new SubVersionRange("1.21", 0, 1));
public static final ProtocolVersion v1_21_2 = register(768, "1.21.2-1.21.3", new SubVersionRange("1.21", 2, 3));
public static final ProtocolVersion v1_21_4 = register(769, "1.21.4");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
unknown.known = false;
}
public static ProtocolVersion register(int version, String name) {
return register(version, -1, name);
}
@@ -150,7 +157,11 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
return protocolVersion;
}
}
return new ProtocolVersion(VersionType.SPECIAL, version, -1, "Unknown (" + version + ")", null);
// Will be made nullable instead in the future...
final ProtocolVersion unknown = new ProtocolVersion(versionType, version, -1, "Unknown (" + version + ")", null);
unknown.known = false;
return unknown;
}
public static @NonNull ProtocolVersion getProtocol(final int version) {
@@ -201,6 +212,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private final int snapshotVersion;
private final String name;
private final Set<String> includedVersions;
@Deprecated // Remove when getProtocol is made nullable
private boolean known = true;
/**
* Constructs a new ProtocolVersion instance.
@@ -285,12 +298,12 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
}
/**
* Returns whether the protocol is set. Should only be unknown for unregistered protocols returned by {@link #getProtocol(int)}.
* Returns whether the protocol version is {@link #unknown}. For checking if the protocol version is registered, use {@link #isRegistered(VersionType, int)}
*
* @return true if the protocol is set
* @return true if the protocol version is unknown
*/
public boolean isKnown() {
return version != -1;
return known;
}
/**
@@ -58,6 +58,14 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
*/
int newEntityId(int id);
/**
* Returns the mapped entity (or the same if it has not changed).
*
* @param identifier unmapped entity identifier
* @return mapped entity identifier
*/
String mappedEntityIdentifier(String identifier);
/**
* Handles and transforms entity data of an entity.
*
@@ -0,0 +1,27 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.api.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
public interface ParticleRewriter {
void rewriteParticle(UserConnection connection, Particle particle);
}
@@ -45,12 +45,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.ChunkPosition;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.BitSetType;
import com.viaversion.viaversion.api.type.types.BooleanArrayType;
import com.viaversion.viaversion.api.type.types.BooleanType;
import com.viaversion.viaversion.api.type.types.ByteArrayType;
import com.viaversion.viaversion.api.type.types.ByteType;
import com.viaversion.viaversion.api.type.types.ComponentType;
import com.viaversion.viaversion.api.type.types.DoubleType;
import com.viaversion.viaversion.api.type.types.EmptyType;
import com.viaversion.viaversion.api.type.types.FloatArrayType;
import com.viaversion.viaversion.api.type.types.FloatType;
import com.viaversion.viaversion.api.type.types.IntArrayType;
import com.viaversion.viaversion.api.type.types.IntType;
@@ -115,14 +117,17 @@ public final class Types {
public static final Type<byte[]> OPTIONAL_BYTE_ARRAY_PRIMITIVE = new ByteArrayType.OptionalByteArrayType();
public static final Type<byte[]> SHORT_BYTE_ARRAY = new ShortByteArrayType();
public static final Type<byte[]> REMAINING_BYTES = new RemainingBytesType();
public static final Type<int[]> INT_ARRAY_PRIMITIVE = new IntArrayType();
public static final ShortType SHORT = new ShortType();
public static final UnsignedShortType UNSIGNED_SHORT = new UnsignedShortType();
public static final IntType INT = new IntType();
public static final Type<int[]> INT_ARRAY_PRIMITIVE = new IntArrayType();
public static final FloatType FLOAT = new FloatType();
public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType();
public static final Type<float[]> FLOAT_ARRAY_PRIMITIVE = new FloatArrayType();
public static final DoubleType DOUBLE = new DoubleType();
public static final LongType LONG = new LongType();
@@ -130,6 +135,7 @@ public final class Types {
public static final BooleanType BOOLEAN = new BooleanType();
public static final BooleanType.OptionalBooleanType OPTIONAL_BOOLEAN = new BooleanType.OptionalBooleanType();
public static final Type<boolean[]> BOOLEAN_ARRAY_PRIMITIVE = new BooleanArrayType();
/* Other Types */
public static final Type<JsonElement> COMPONENT = new ComponentType();
@@ -149,6 +155,8 @@ public final class Types {
public static final VarLongType VAR_LONG = new VarLongType();
/* MC Types */
public static final Type<byte[]> SERVERBOUND_CUSTOM_PAYLOAD_DATA = new RemainingBytesType(Short.MAX_VALUE);
public static final Type<BlockPosition> BLOCK_POSITION1_8 = new BlockPositionType1_8();
public static final Type<BlockPosition> OPTIONAL_POSITION1_8 = new BlockPositionType1_8.OptionalBlockPositionType();
public static final Type<BlockPosition> BLOCK_POSITION1_14 = new BlockPositionType1_14();
@@ -189,7 +197,10 @@ public final class Types {
public static final Type<PlayerMessageSignature> OPTIONAL_PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType.OptionalPlayerMessageSignatureType();
public static final Type<PlayerMessageSignature[]> PLAYER_MESSAGE_SIGNATURE_ARRAY = new ArrayType<>(PLAYER_MESSAGE_SIGNATURE);
public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_19_3 = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_21_2 = new BitSetType(7);
public static final BitSetType PROFILE_ACTIONS_ENUM1_21_4 = new BitSetType(8);
public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256);
public static final BitSetType ACKNOWLEDGED_BIT_SET = new BitSetType(20);
public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256);
@@ -26,13 +26,22 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class ArrayType<T> extends Type<T[]> {
private final Type<T> elementType;
private final int maxLength;
public ArrayType(Type<T> type) {
this(type, -1);
}
public ArrayType(Type<T> type, int maxLength) {
//noinspection unchecked
super(type.getTypeName() + " Array", (Class<T[]>) getArrayClass(type.getOutputClass()));
this.elementType = type;
this.maxLength = maxLength;
}
public static Class<?> getArrayClass(Class<?> componentType) {
@@ -43,16 +52,40 @@ public class ArrayType<T> extends Type<T[]> {
@Override
public T[] read(ByteBuf buffer) {
int amount = Types.VAR_INT.readPrimitive(buffer);
T[] array = (T[]) Array.newInstance(elementType.getOutputClass(), amount);
if (maxLength != -1 && amount > maxLength) {
throw new IllegalArgumentException("Array length " + amount + " is longer than maximum " + maxLength);
}
for (int i = 0; i < amount; i++) {
return amount < Short.MAX_VALUE ? readArray(buffer, amount) : readList(buffer, amount);
}
private T[] readArray(ByteBuf buffer, int length) {
T[] array = createArray(length);
for (int i = 0; i < length; i++) {
array[i] = elementType.read(buffer);
}
return array;
}
private T[] readList(ByteBuf buffer, int length) {
List<T> list = new ArrayList<>();
for (int i = 0; i < length; i++) {
list.add(elementType.read(buffer));
}
return list.toArray(createArray(0));
}
private T[] createArray(int length) {
//noinspection unchecked
return (T[]) Array.newInstance(elementType.getOutputClass(), length);
}
@Override
public void write(ByteBuf buffer, T[] object) {
if (maxLength != -1 && object.length > maxLength) {
throw new IllegalArgumentException("Array length " + object.length + " is longer than maximum " + maxLength);
}
Types.VAR_INT.writePrimitive(buffer, object.length);
for (T o : object) {
elementType.write(buffer, o);
@@ -0,0 +1,67 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
// Ok...
public class BooleanArrayType extends Type<boolean[]> {
private final int length;
public BooleanArrayType(final int length) {
super(boolean[].class);
this.length = length;
}
public BooleanArrayType() {
super(boolean[].class);
this.length = -1;
}
@Override
public void write(final ByteBuf buffer, final boolean[] object) {
if (this.length != -1) {
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
} else {
Types.VAR_INT.writePrimitive(buffer, object.length);
}
for (final boolean b : object) {
buffer.writeBoolean(b);
}
}
@Override
public boolean[] read(final ByteBuf buffer) {
final int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length;
Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes");
final boolean[] array = new boolean[length];
for (int i = 0; i < length; i++) {
array[i] = buffer.readBoolean();
}
return array;
}
}
@@ -0,0 +1,66 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public class FloatArrayType extends Type<float[]> {
private final int length;
public FloatArrayType(final int length) {
super(float[].class);
this.length = length;
}
public FloatArrayType() {
super(float[].class);
this.length = -1;
}
@Override
public void write(final ByteBuf buffer, final float[] object) {
if (this.length != -1) {
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
} else {
Types.VAR_INT.writePrimitive(buffer, object.length);
}
for (final float f : object) {
buffer.writeFloat(f);
}
}
@Override
public float[] read(final ByteBuf buffer) {
final int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length;
Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes");
final float[] array = new float[length];
for (int i = 0; i < length; i++) {
array[i] = buffer.readFloat();
}
return array;
}
}
@@ -36,11 +36,19 @@ public class IntType extends Type<Integer> implements TypeConverter<Integer> {
return buffer.readInt();
}
public int readPrimitive(ByteBuf buffer) {
return buffer.readInt();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeInt(object);
}
public void writePrimitive(ByteBuf buffer, int object) {
buffer.writeInt(object);
}
@Override
public Integer from(Object o) {
if (o instanceof Number number) {
@@ -26,19 +26,35 @@ import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class RemainingBytesType extends Type<byte[]> {
private final int maxLength;
public RemainingBytesType() {
this(-1);
}
public RemainingBytesType(final int maxLength) {
super(byte[].class);
this.maxLength = maxLength;
}
@Override
public byte[] read(ByteBuf buffer) {
byte[] array = new byte[buffer.readableBytes()];
public byte[] read(final ByteBuf buffer) {
final int bytes = buffer.readableBytes();
if (maxLength != -1 && bytes > maxLength) {
throw new RuntimeException("Remaining bytes cannot be longer than " + maxLength + " (got " + bytes + ")");
}
final byte[] array = new byte[bytes];
buffer.readBytes(array);
return array;
}
@Override
public void write(ByteBuf buffer, byte[] object) {
public void write(final ByteBuf buffer, final byte[] object) {
if (maxLength != -1 && object.length > maxLength) {
throw new RuntimeException("Remaining bytes cannot be longer than " + maxLength + " (got " + object.length + ")");
}
buffer.writeBytes(object);
}
}
@@ -32,6 +32,15 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
private static final int VALUE_BITS = 0x7F;
private static final int MULTI_BYTE_BITS = ~VALUE_BITS;
private static final int MAX_BYTES = 5;
private static final int[] VAR_INT_LENGTHS = new int[65];
static {
// Copied from Velocity https://github.com/PaperMC/Velocity/blob/08a42b3723633ea5eb6b96c0bb42180f3c2b07eb/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L166
for (int i = 0; i <= 32; ++i) {
VAR_INT_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
}
VAR_INT_LENGTHS[32] = 1; // Special case for the number 0.
}
public VarIntType() {
super("VarInt", Integer.class);
@@ -88,4 +97,8 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
}
throw new UnsupportedOperationException();
}
}
public static int varIntLength(final int value) {
return VAR_INT_LENGTHS[Integer.numberOfLeadingZeros(value)];
}
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.type.types.chunk;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
@@ -54,4 +55,14 @@ public final class ChunkSectionType1_18 extends Type<ChunkSection> {
blockPaletteType.write(buffer, section.palette(PaletteType.BLOCKS));
biomePaletteType.write(buffer, section.palette(PaletteType.BIOMES));
}
public int serializedSize(final Chunk chunk) {
int length = 0;
for (final ChunkSection section : chunk.getSections()) {
length += Short.BYTES
+ blockPaletteType.serializedSize(section.palette(PaletteType.BLOCKS))
+ biomePaletteType.serializedSize(section.palette(PaletteType.BIOMES));
}
return length;
}
}
@@ -52,14 +52,10 @@ public final class ChunkType1_18 extends Type<Chunk> {
final CompoundTag heightMap = Types.NAMED_COMPOUND_TAG.read(buffer);
// Read sections
final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer));
final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer));
final ChunkSection[] sections = new ChunkSection[ySectionCount];
try {
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
} finally {
sectionsBuf.release();
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer);
@@ -78,16 +74,9 @@ public final class ChunkType1_18 extends Type<Chunk> {
Types.NAMED_COMPOUND_TAG.write(buffer, chunk.getHeightMap());
final ByteBuf sectionBuffer = buffer.alloc().buffer();
try {
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(sectionBuffer, section);
}
sectionBuffer.readerIndex(0);
Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes());
buffer.writeBytes(sectionBuffer);
} finally {
sectionBuffer.release(); // release buffer
Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk));
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(buffer, section);
}
Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size());
@@ -52,14 +52,10 @@ public final class ChunkType1_20_2 extends Type<Chunk> {
final CompoundTag heightMap = Types.COMPOUND_TAG.read(buffer);
// Read sections
final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer));
final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer));
final ChunkSection[] sections = new ChunkSection[ySectionCount];
try {
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
} finally {
sectionsBuf.release();
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer);
@@ -78,16 +74,9 @@ public final class ChunkType1_20_2 extends Type<Chunk> {
Types.COMPOUND_TAG.write(buffer, chunk.getHeightMap());
final ByteBuf sectionBuffer = buffer.alloc().buffer();
try {
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(sectionBuffer, section);
}
sectionBuffer.readerIndex(0);
Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes());
buffer.writeBytes(sectionBuffer);
} finally {
sectionBuffer.release(); // release buffer
Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk));
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(buffer, section);
}
Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size());
@@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.util.CompactArrayUtil;
import com.viaversion.viaversion.util.MathUtil;
import io.netty.buffer.ByteBuf;
@@ -94,13 +95,7 @@ public final class PaletteType1_18 extends Type<DataPalette> {
return;
}
// 1, 2, and 3 bit linear block palettes can't be read by the client
final int min = type == PaletteType.BLOCKS ? 4 : 1;
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size));
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
final int bitsPerValue = bitsPerValue(size);
buffer.writeByte(bitsPerValue);
if (bitsPerValue != globalPaletteBits) {
@@ -113,4 +108,39 @@ public final class PaletteType1_18 extends Type<DataPalette> {
Types.LONG_ARRAY_PRIMITIVE.write(buffer, CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt));
}
private int bitsPerValue(final int size) {
// 1, 2, and 3 bit linear block palettes can't be read by the client
final int min = type == PaletteType.BLOCKS ? 4 : 1;
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size));
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
return bitsPerValue;
}
public int serializedSize(final DataPalette palette) {
// This is a bit of extra work, but worth it to avoid otherwise having to allocate and write to an extra buffer.
// On top of saving memory, it provides small but measurable speedup compared to writing to a separate buffer and then back
final int size = palette.size();
final int bitsPerValue = bitsPerValue(size);
int serializedTypesSize = 0;
int serializedValuesSize = 1; // At least one byte for 0 length
if (size == 1) {
serializedTypesSize = VarIntType.varIntLength(palette.idByIndex(0));
} else {
if (bitsPerValue != globalPaletteBits) {
serializedTypesSize = VarIntType.varIntLength(size);
for (int i = 0; i < size; i++) {
serializedTypesSize += VarIntType.varIntLength(palette.idByIndex(i));
}
}
final int valuesPerLong = 64 / bitsPerValue;
final int values = (type.size() + valuesPerLong - 1) / valuesPerLong;
serializedValuesSize = VarIntType.varIntLength(values) + (Long.BYTES * values);
}
return Byte.BYTES + serializedTypesSize + serializedValuesSize;
}
}
@@ -63,7 +63,7 @@ public class ItemType1_20_5 extends Type<Item> {
return new Reference2ObjectOpenHashMap<>();
}
final Map<StructuredDataKey<?>, StructuredData<?>> map = new Reference2ObjectOpenHashMap<>();
final Map<StructuredDataKey<?>, StructuredData<?>> map = new Reference2ObjectOpenHashMap<>(Math.min(valuesSize + markersSize, 128));
for (int i = 0; i < valuesSize; i++) {
final StructuredData<?> value = dataType.read(buffer);
final StructuredDataKey<?> key = dataType.key(value.id());
@@ -87,5 +87,12 @@ public class StructuredDataType extends Type<StructuredData<?>> {
types[id] = key;
return this;
}
public DataFiller add(final StructuredDataKey<?>... keys) {
for (final StructuredDataKey<?> key : keys) {
add(key);
}
return this;
}
}
}
@@ -29,7 +29,6 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
@@ -77,6 +76,10 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST_TRANSITION = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Red 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green 0-1
@@ -86,6 +89,11 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue
};
public static final DataReader<Particle> DUST_TRANSITION1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // From RGB
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // To RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> VIBRATION = (buf, particle) -> {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // From block pos
@@ -136,7 +144,22 @@ public class ParticleType extends DynamicType<Particle> {
public static final DataReader<Particle> SHRIEK = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Delay
};
public static final DataReader<Particle> COLOR = (buf, particle) -> particle.add(Types.INT, buf.readInt());
public static final DataReader<Particle> COLOR = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf));
};
public static final DataReader<Particle> TRAIL1_21_2 = (buf, particle) -> {
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target X
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Y
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Z
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
};
public static final DataReader<Particle> TRAIL1_21_4 = (buf, particle) -> {
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target X
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Y
particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Z
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Duration
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -50,7 +50,7 @@ public final class Types1_21 {
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(PARTICLE, PARTICLES);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -0,0 +1,55 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5;
import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5;
import com.viaversion.viaversion.api.type.types.item.StructuredDataType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import java.util.List;
// Most of these are only safe to use after protocol loading
public final class Types1_21_2 {
public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType();
public static final Type<StructuredData<?>[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA);
public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA);
public static final Type<Item[]> ITEM_ARRAY = new ArrayType<>(ITEM);
public static final Type<Item> ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY);
public static final Type<Item> OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST);
public static final ParticleType PARTICLE = new ParticleType();
public static final Type<Particle[]> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21_2 ENTITY_DATA_TYPES = new EntityDataTypes1_21_2(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -0,0 +1,55 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5;
import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5;
import com.viaversion.viaversion.api.type.types.item.StructuredDataType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import java.util.List;
// Most of these are only safe to use after protocol loading
public final class Types1_21_4 {
public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType();
public static final Type<StructuredData<?>[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA);
public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA);
public static final Type<Item[]> ITEM_ARRAY = new ArrayType<>(ITEM);
public static final Type<Item> ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY);
public static final Type<Item> OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST);
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -22,11 +22,14 @@
*/
package com.viaversion.viaversion.exception;
import java.util.HashMap;
import java.util.Map;
import com.viaversion.viaversion.api.Via;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class InformativeException extends RuntimeException {
private final Map<String, Object> info = new HashMap<>();
private static final int MAX_MESSAGE_LENGTH = 5_000;
private final List<DataEntry> dataEntries = new ArrayList<>();
private boolean shouldBePrinted = true;
private int sources;
@@ -34,8 +37,8 @@ public class InformativeException extends RuntimeException {
super(cause);
}
public InformativeException set(String key, Object value) {
info.put(key, value);
public InformativeException set(String key, @Nullable Object value) {
dataEntries.add(new DataEntry(key, value));
return this;
}
@@ -57,14 +60,21 @@ public class InformativeException extends RuntimeException {
@Override
public String getMessage() {
StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n");
final StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n");
boolean first = true;
for (Map.Entry<String, Object> entry : info.entrySet()) {
for (final DataEntry entry : dataEntries) {
if (!first) {
builder.append(", ");
} else {
first = false;
}
builder.append(entry.getKey()).append(": ").append(entry.getValue());
first = false;
builder.append(entry.name()).append(": ");
String s = String.valueOf(entry.value());
if (!Via.getManager().isDebug() && s.length() > 10 && builder.length() + s.length() > MAX_MESSAGE_LENGTH) {
s = s.substring(0, MAX_MESSAGE_LENGTH - builder.length()) + "...";
}
builder.append(s.replaceAll("\\s", ""));
}
return builder.toString();
}
@@ -74,4 +84,7 @@ public class InformativeException extends RuntimeException {
// Don't record this stack
return this;
}
private record DataEntry(String name, @Nullable Object value) {
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.util;
public final class Limit {
public static int max(final int value, final int max) {
if (value > max) {
throw new IllegalArgumentException("Value " + value + " is higher than the maximum " + max);
}
return value;
}
}
+2 -6
View File
@@ -1,7 +1,6 @@
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.jvm.toolchain.JavaLanguageVersion
import java.io.ByteArrayOutputStream
fun Project.latestCommitHash(): String {
return runGitCommand(listOf("rev-parse", "--short", "HEAD"))
@@ -16,12 +15,9 @@ fun Project.branchName(): String {
}
fun Project.runGitCommand(args: List<String>): String {
val byteOut = ByteArrayOutputStream()
exec {
return providers.exec {
commandLine = listOf("git") + args
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
}.standardOutput.asBytes.get().toString(Charsets.UTF_8).trim()
}
fun JavaPluginExtension.javaTarget(version: Int) {
@@ -1,5 +1,6 @@
plugins {
`java-library`
`jvm-test-suite`
}
tasks {
+2 -2
View File
@@ -16,10 +16,10 @@ val main = setOf(
projects.viaversionBukkit,
projects.viaversionVelocity,
projects.viaversionFabric
).map { it.dependencyProject }
).map { it.path }
subprojects {
when (this) {
when (path) {
in main -> plugins.apply("via.shadow-conventions")
else -> plugins.apply("via.base-conventions")
}
@@ -33,6 +33,7 @@ import com.viaversion.viaversion.bukkit.platform.BukkitViaInjector;
import com.viaversion.viaversion.bukkit.platform.BukkitViaLoader;
import com.viaversion.viaversion.bukkit.platform.BukkitViaTask;
import com.viaversion.viaversion.bukkit.platform.BukkitViaTaskTask;
import com.viaversion.viaversion.bukkit.platform.FoliaViaTask;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.dump.PluginInfo;
import com.viaversion.viaversion.unsupported.UnsupportedPlugin;
@@ -171,11 +172,18 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
@Override
public PlatformTask runSync(Runnable runnable, long delay) {
if (FOLIA) {
// Set the delayed tick to at least 1, as Folia requires this.
return new FoliaViaTask(getServer().getGlobalRegionScheduler().runDelayed(this, (e) -> runnable.run(), delay <= 0L ? 1L : delay));
}
return new BukkitViaTask(getServer().getScheduler().runTaskLater(this, runnable, delay));
}
@Override
public PlatformTask runRepeatingSync(Runnable runnable, long period) {
if (FOLIA) {
return new FoliaViaTask(getServer().getGlobalRegionScheduler().runAtFixedRate(this, (e) -> runnable.run(), 1, period));
}
return new BukkitViaTask(getServer().getScheduler().runTaskTimer(this, runnable, 0, period));
}
@@ -22,6 +22,7 @@ import com.viaversion.viaversion.bukkit.util.NMSUtil;
import com.viaversion.viaversion.exception.CancelCodecException;
import com.viaversion.viaversion.exception.CancelDecoderException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.util.ByteBufUtil;
import com.viaversion.viaversion.util.PipelineUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
@@ -39,7 +40,7 @@ public final class BukkitDecodeHandler extends MessageToMessageDecoder<ByteBuf>
}
@Override
protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) throws Exception {
protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) {
if (!connection.checkServerboundPacket()) {
throw CancelDecoderException.generate(null);
}
@@ -48,7 +49,7 @@ public final class BukkitDecodeHandler extends MessageToMessageDecoder<ByteBuf>
return;
}
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
final ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf);
try {
connection.transformIncoming(transformedBuf, CancelDecoderException::generate);
out.add(transformedBuf.retain());
@@ -22,6 +22,7 @@ import com.viaversion.viaversion.bukkit.util.NMSUtil;
import com.viaversion.viaversion.exception.CancelCodecException;
import com.viaversion.viaversion.exception.CancelEncoderException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.util.ByteBufUtil;
import com.viaversion.viaversion.util.PipelineUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
@@ -52,7 +53,7 @@ public final class BukkitEncodeHandler extends MessageToMessageEncoder<ByteBuf>
return;
}
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
final ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf);
try {
final boolean needsCompression = !handledCompression && handleCompressionOrder(ctx, transformedBuf);
connection.transformClientbound(transformedBuf, CancelEncoderException::generate);
@@ -0,0 +1,72 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
public class LegacyChangeItemListener extends PlayerChangeItemListener {
public LegacyChangeItemListener(final ViaVersionPlugin plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockDamageEvent(final BlockDamageEvent event) {
final Player player = event.getPlayer();
final ItemStack item = event.getItemInHand();
sendAttributeUpdate(player, item, Slot.HAND);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(final InventoryCloseEvent event) {
if (event.getPlayer() instanceof Player player &&
(event.getInventory().getType() == InventoryType.CRAFTING ||
event.getInventory().getType() == InventoryType.PLAYER)) {
sendArmorUpdate(player);
}
}
private void sendArmorUpdate(final Player player) {
final UserConnection connection = getUserConnection(player);
final EfficiencyAttributeStorage storage = getEfficiencyStorage(connection);
if (storage == null) {
return;
}
final PlayerInventory inventory = player.getInventory();
final ItemStack helmet = inventory.getHelmet();
final ItemStack leggings = swiftSneak != null ? inventory.getLeggings() : null;
final ItemStack boots = depthStrider != null ? inventory.getBoots() : null;
storage.setEnchants(player.getEntityId(), connection, storage.activeEnchants()
.aquaAffinity(helmet != null ? helmet.getEnchantmentLevel(aquaAffinity) : 0)
.swiftSneak(leggings != null ? leggings.getEnchantmentLevel(swiftSneak) : 0)
.depthStrider(boots != null ? boots.getEnchantmentLevel(depthStrider) : 0));
}
}
@@ -18,7 +18,6 @@
package com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
@@ -38,11 +37,11 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class PlayerChangeItemListener extends ViaBukkitListener {
// Use legacy function and names here to support all versions
private final Enchantment efficiency = getByName("efficiency", "DIG_SPEED");
private final Enchantment aquaAffinity = getByName("aqua_affinity", "WATER_WORKER");
private final Enchantment depthStrider = getByName("depth_strider", "DEPTH_STRIDER");
private final Enchantment soulSpeed = getByName("soul_speed", "SOUL_SPEED");
private final Enchantment swiftSneak = getByName("swift_sneak", "SWIFT_SNEAK");
protected final Enchantment efficiency = getByName("efficiency", "DIG_SPEED");
protected final Enchantment aquaAffinity = getByName("aqua_affinity", "WATER_WORKER");
protected final Enchantment depthStrider = getByName("depth_strider", "DEPTH_STRIDER");
protected final Enchantment soulSpeed = getByName("soul_speed", "SOUL_SPEED");
protected final Enchantment swiftSneak = getByName("swift_sneak", "SWIFT_SNEAK");
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
super(plugin, Protocol1_20_5To1_21.class);
@@ -55,35 +54,26 @@ public class PlayerChangeItemListener extends ViaBukkitListener {
sendAttributeUpdate(player, item, Slot.HAND);
}
protected EfficiencyAttributeStorage getEfficiencyStorage(final UserConnection connection) {
return connection != null ? connection.get(EfficiencyAttributeStorage.class) : null;
}
void sendAttributeUpdate(final Player player, @Nullable final ItemStack item, final Slot slot) {
final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId());
if (connection == null || !isOnPipe(player)) {
return;
}
final UserConnection connection = getUserConnection(player);
final EfficiencyAttributeStorage storage = getEfficiencyStorage(connection);
if (storage == null) return;
final EfficiencyAttributeStorage storage = connection.get(EfficiencyAttributeStorage.class);
if (storage == null) {
return;
}
final EfficiencyAttributeStorage.ActiveEnchants activeEnchants = storage.activeEnchants();
int efficiencyLevel = activeEnchants.efficiency().level();
int aquaAffinityLevel = activeEnchants.aquaAffinity().level();
int soulSpeedLevel = activeEnchants.soulSpeed().level();
int swiftSneakLevel = activeEnchants.swiftSneak().level();
int depthStriderLevel = activeEnchants.depthStrider().level();
switch (slot) {
case HAND -> efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
case HELMET -> aquaAffinityLevel = item != null ? item.getEnchantmentLevel(aquaAffinity) : 0;
case LEGGINGS -> swiftSneakLevel = item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0;
case BOOTS -> {
depthStriderLevel = item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0;
// TODO This needs continuous ticking for the supporting block as a conditional effect
// and is even more prone to desync from high ping than the other attributes
//soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0;
}
}
storage.setEnchants(player.getEntityId(), connection, efficiencyLevel, soulSpeedLevel, swiftSneakLevel, aquaAffinityLevel, depthStriderLevel);
EfficiencyAttributeStorage.ActiveEnchants enchants = storage.activeEnchants();
enchants = switch (slot) {
case HAND -> enchants.efficiency(item != null ? item.getEnchantmentLevel(efficiency) : 0);
case HELMET -> enchants.aquaAffinity(item != null ? item.getEnchantmentLevel(aquaAffinity) : 0);
case LEGGINGS -> enchants.swiftSneak(item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0);
case BOOTS -> enchants.depthStrider(item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0);
// TODO This needs continuous ticking for the supporting block as a conditional effect
// and is even more prone to desync from high ping than the other attributes
//soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0;
};
storage.setEnchants(player.getEntityId(), connection, enchants);
}
enum Slot {
@@ -26,23 +26,25 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.bukkit.listeners.UpdateListener;
import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListener;
import com.viaversion.viaversion.bukkit.listeners.v1_14_4to1_15.EntityToggleGlideListener;
import com.viaversion.viaversion.bukkit.listeners.v1_19_3to1_19_4.ArmorToggleListener;
import com.viaversion.viaversion.bukkit.listeners.v1_18_2to1_19.BlockBreakListener;
import com.viaversion.viaversion.bukkit.listeners.v1_19_3to1_19_4.ArmorToggleListener;
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.LegacyChangeItemListener;
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PaperPlayerChangeItemListener;
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.ArmorListener;
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.BlockListener;
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.DeathListener;
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.HandItemCache;
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.PaperPatch;
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PaperPlayerChangeItemListener;
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PlayerChangeItemListener;
import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitPickItemProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitViaMovementTransmitter;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.provider.InventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.providers.BlockConnectionProvider;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.HandItemProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.MovementTransmitterProvider;
import java.util.HashSet;
@@ -184,7 +186,12 @@ public class BukkitViaLoader implements ViaPlatformLoader {
if (PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
new PaperPlayerChangeItemListener(plugin).register();
} else {
new PlayerChangeItemListener(plugin).register();
new LegacyChangeItemListener(plugin).register();
}
}
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21_4)) {
if (PaperViaInjector.hasMethod(Material.class, "isItem")) {
Via.getManager().getProviders().use(PickItemProvider.class, new BukkitPickItemProvider(plugin));
}
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.platform;
import com.viaversion.viaversion.api.platform.PlatformTask;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
public record FoliaViaTask(ScheduledTask task) implements PlatformTask<ScheduledTask> {
@Override
public void cancel() {
task.cancel();
}
}
@@ -65,12 +65,7 @@ public final class PaperViaInjector {
}
private static boolean hasServerProtocolMethod() {
try {
Class.forName("org.bukkit.UnsafeValues").getDeclaredMethod("getProtocolVersion");
return true;
} catch (final ClassNotFoundException | NoSuchMethodException e) {
return false;
}
return hasMethod("org.bukkit.UnsafeValues", "getProtocolVersion");
}
private static boolean hasPaperInjectionMethod() {
@@ -78,12 +73,7 @@ public final class PaperViaInjector {
}
private static boolean hasIsStoppingMethod() {
try {
Bukkit.class.getDeclaredMethod("isStopping");
return true;
} catch (final NoSuchMethodException e) {
return false;
}
return hasMethod(Bukkit.class, "isStopping");
}
private static boolean hasPacketLimiter() {
@@ -98,4 +88,22 @@ public final class PaperViaInjector {
return false;
}
}
public static boolean hasMethod(final String className, final String method) {
try {
Class.forName(className).getDeclaredMethod(method);
return true;
} catch (final ClassNotFoundException | NoSuchMethodException e) {
return false;
}
}
public static boolean hasMethod(final Class<?> clazz, final String method) {
try {
clazz.getDeclaredMethod(method);
return true;
} catch (final NoSuchMethodException e) {
return false;
}
}
}
@@ -0,0 +1,182 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.providers;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class BukkitPickItemProvider extends PickItemProvider {
private static final boolean HAS_PLACEMENT_MATERIAL_METHOD = PaperViaInjector.hasMethod("org.bukkit.block.BlockData", "getPlacementMaterial");
private static final boolean HAS_SPAWN_EGG_METHOD = PaperViaInjector.hasMethod(ItemFactory.class, "getSpawnEgg");
private static final double BLOCK_RANGE = 4.5 + 1;
private static final double BLOCK_RANGE_SQUARED = BLOCK_RANGE * BLOCK_RANGE;
private static final double ENTITY_RANGE = 3 + 3;
private final ViaVersionPlugin plugin;
public BukkitPickItemProvider(final ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@Override
public void pickItemFromBlock(final UserConnection connection, final BlockPosition blockPosition, final boolean includeData) {
final UUID uuid = connection.getProtocolInfo().getUuid();
plugin.getServer().getScheduler().runTask(plugin, () -> {
final Player player = plugin.getServer().getPlayer(uuid);
if (player == null) {
return;
}
final Location playerLocation = player.getLocation();
if (blockPosition.distanceFromCenterSquared(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ()) > BLOCK_RANGE_SQUARED) {
return;
}
final Block block = player.getWorld().getBlockAt(blockPosition.x(), blockPosition.y(), blockPosition.z());
if (block.getType() == Material.AIR) {
return;
}
final ItemStack item = blockToItem(block, includeData && player.getGameMode() == GameMode.CREATIVE);
if (item != null) {
pickItem(player, item);
}
});
}
private @Nullable ItemStack blockToItem(final Block block, final boolean includeData) {
if (HAS_PLACEMENT_MATERIAL_METHOD) {
final ItemStack item = new ItemStack(block.getBlockData().getPlacementMaterial(), 1);
if (includeData && item.getItemMeta() instanceof final BlockStateMeta blockStateMeta) {
blockStateMeta.setBlockState(block.getState());
}
return item;
} else if (block.getType().isItem()) {
return new ItemStack(block.getType(), 1);
}
return null;
}
@Override
public void pickItemFromEntity(final UserConnection connection, final int entityId, final boolean includeData) {
if (!HAS_SPAWN_EGG_METHOD) {
return;
}
final UUID uuid = connection.getProtocolInfo().getUuid();
plugin.getServer().getScheduler().runTask(plugin, () -> {
final Player player = plugin.getServer().getPlayer(uuid);
if (player == null) {
return;
}
final Entity entity = player.getWorld().getNearbyEntities(player.getLocation(), ENTITY_RANGE, ENTITY_RANGE, ENTITY_RANGE).stream()
.filter(e -> e.getEntityId() == entityId)
.findAny()
.orElse(null);
if (entity == null) {
return;
}
final Material spawnEggType = Bukkit.getItemFactory().getSpawnEgg(entity.getType());
if (spawnEggType != null) {
pickItem(player, new ItemStack(spawnEggType, 1));
}
});
}
private void pickItem(final Player player, final ItemStack item) {
// Find matching item
final PlayerInventory inventory = player.getInventory();
final ItemStack[] contents = inventory.getStorageContents();
int sourceSlot = -1;
for (int i = 0; i < contents.length; i++) {
final ItemStack content = contents[i];
if (content == null || !content.isSimilar(item)) {
continue;
}
sourceSlot = i;
break;
}
if (sourceSlot != -1) {
moveToHotbar(inventory, sourceSlot, contents);
} else if (player.getGameMode() == GameMode.CREATIVE) {
spawnItem(item, inventory, contents);
}
}
private void spawnItem(final ItemStack item, final PlayerInventory inventory, final ItemStack[] contents) {
final int targetSlot = findEmptyHotbarSlot(inventory, inventory.getHeldItemSlot());
inventory.setHeldItemSlot(targetSlot);
final ItemStack heldItem = inventory.getItem(targetSlot);
int emptySlot = targetSlot;
if (heldItem != null && heldItem.getType() != Material.AIR) {
// Swap to the first free slot in the inventory, else add it to the current hotbar slot
for (int i = 0; i < contents.length; i++) {
if (contents[i] == null || contents[i].getType() == Material.AIR) {
emptySlot = i;
break;
}
}
}
inventory.setItem(emptySlot, heldItem);
inventory.setItemInMainHand(item);
}
private void moveToHotbar(final PlayerInventory inventory, final int sourceSlot, final ItemStack[] contents) {
if (sourceSlot <= 9) {
inventory.setHeldItemSlot(sourceSlot);
return;
}
final int heldSlot = inventory.getHeldItemSlot();
final int targetSlot = findEmptyHotbarSlot(inventory, heldSlot);
inventory.setHeldItemSlot(targetSlot);
final ItemStack heldItem = inventory.getItem(targetSlot);
inventory.setItemInMainHand(contents[sourceSlot]);
inventory.setItem(sourceSlot, heldItem);
}
private int findEmptyHotbarSlot(final PlayerInventory inventory, final int heldSlot) {
for (int i = 0; i < 9; i++) {
final ItemStack item = inventory.getItem(i);
if (item == null || item.getType() == Material.AIR) {
return i;
}
}
return heldSlot;
}
}
+29
View File
@@ -18,3 +18,32 @@ java {
tasks.named<Jar>("sourcesJar") {
from(project(":viaversion-api").sourceSets.main.get().allSource)
}
// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy
// For further instructions see the ViaProxy repository README
tasks.register<JavaExec>("runViaProxy") {
dependsOn(tasks.shadowJar)
val viaProxyConfiguration = configurations.create("viaProxy")
viaProxyConfiguration.dependencies.add(dependencies.create(rootProject.libs.viaProxy.get().copy().setTransitive(false)))
mainClass.set("net.raphimc.viaproxy.ViaProxy")
classpath = viaProxyConfiguration
workingDir = file("run")
jvmArgs = listOf("-DskipUpdateCheck")
if (System.getProperty("viaproxy.gui.autoStart") != null) {
jvmArgs("-Dviaproxy.gui.autoStart")
}
doFirst {
val jarsDir = file("$workingDir/jars")
jarsDir.mkdirs()
file("$jarsDir/${project.name}.jar").writeBytes(tasks.shadowJar.get().archiveFile.get().asFile.readBytes())
}
doLast {
file("$workingDir/jars/${project.name}.jar").delete()
file("$workingDir/logs").deleteRecursively()
}
}
@@ -48,7 +48,10 @@ public abstract class ViaListener {
* @return True if on pipe
*/
protected boolean isOnPipe(UUID uuid) {
UserConnection userConnection = getUserConnection(uuid);
return isOnPipe(getUserConnection(uuid));
}
protected boolean isOnPipe(UserConnection userConnection) {
return userConnection != null &&
(requiredPipeline == null || userConnection.getProtocolInfo().getPipeline().contains(requiredPipeline));
}
@@ -244,9 +244,12 @@ public class ViaManagerImpl implements ViaManager {
}
if (version < 17) {
platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 17 (your version is " + javaVersion + ").");
platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 21 (your version is " + javaVersion + ").");
platform.getLogger().warning("ViaVersion no longer officially supports this version of Java, only offering unsupported compatibility builds.");
platform.getLogger().warning("See https://github.com/ViaVersion/ViaVersion/releases/tag/5.0.0 for more information.");
} else if (version < 21) {
platform.getLogger().warning("Please update your Java runtime to at least Java 21 (your version is " + javaVersion + ").");
platform.getLogger().warning("At some point in the future, ViaVersion will no longer be compatible with this version of Java.");
}
}
@@ -35,7 +35,7 @@ public class ReloadSubCmd implements ViaSubCommand {
@Override
public boolean execute(ViaCommandSender sender, String[] args) {
Via.getManager().getConfigurationProvider().reloadConfigs();
sendMessage(sender, "&6Configuration successfully reloaded! Some features may need a restart.");
sendMessage(sender, "&6Configuration successfully reloaded! Some config options may require a restart to take effect.");
return true;
}
}
@@ -96,6 +96,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean cancelBlockSounds;
private boolean hideScoreboardNumbers;
private boolean fix1_21PlacementRotation;
private boolean swordBlockingViaConsumable;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@@ -164,7 +165,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
handleInvalidItemCount = getBoolean("handle-invalid-item-count", false);
cancelBlockSounds = getBoolean("cancel-block-sounds", true);
hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false);
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", false);
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", true);
swordBlockingViaConsumable = getBoolean("sword-blocking-via-consumable", true);
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -556,4 +558,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean fix1_21PlacementRotation() {
return fix1_21PlacementRotation;
}
@Override
public boolean swordBlockingViaConsumable() {
return swordBlockingViaConsumable;
}
}
@@ -29,8 +29,8 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
@@ -55,6 +55,7 @@ import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public class UserConnectionImpl implements UserConnection {
private static final int PASSTHROUGH_DATA_BYTES = Long.BYTES * 2 + 2;
private static final AtomicLong IDS = new AtomicLong();
private final long id = IDS.incrementAndGet();
private final Map<Class<?>, StorableObject> storedObjects = new ConcurrentHashMap<>();
@@ -244,7 +245,8 @@ public class UserConnectionImpl implements UserConnection {
}
private void sendRawPacketToServerServerSide(final ByteBuf packet, final boolean currentThread) {
final ByteBuf buf = packet.alloc().buffer();
final int initialCapacity = active ? packet.readableBytes() + PASSTHROUGH_DATA_BYTES : packet.readableBytes();
final ByteBuf buf = packet.alloc().buffer(initialCapacity);
try {
// We'll use passing through because there are some encoder wrappers
ChannelHandlerContext context = PipelineUtil
@@ -333,7 +335,7 @@ public class UserConnectionImpl implements UserConnection {
return;
}
int id = Types.VAR_INT.readPrimitive(buf);
final int id = Types.VAR_INT.readPrimitive(buf);
if (id == PacketWrapper.PASSTHROUGH_ID) {
if (!passthroughTokens.remove(Types.UUID.read(buf))) {
throw new IllegalArgumentException("Invalid token");
@@ -341,20 +343,47 @@ public class UserConnectionImpl implements UserConnection {
return;
}
PacketWrapper wrapper = new PacketWrapperImpl(id, buf, this);
State state = protocolInfo.getState(direction);
final int valuesReaderIndex = buf.readerIndex();
final PacketWrapperImpl wrapper = new PacketWrapperImpl(id, buf, this);
try {
protocolInfo.getPipeline().transform(direction, state, wrapper);
} catch (CancelException ex) {
protocolInfo.getPipeline().transform(direction, protocolInfo.getState(direction), wrapper);
} catch (final CancelException ex) {
throw cancelSupplier.apply(ex);
}
ByteBuf transformed = buf.alloc().buffer();
writeToBuffer(wrapper, buf, id, valuesReaderIndex);
}
private void writeToBuffer(final PacketWrapperImpl wrapper, final ByteBuf buf, final int originalId, final int originalReaderIndex) {
final int remainingBytes = buf.readableBytes();
if (buf.readerIndex() == originalReaderIndex && wrapper.areStoredPacketValuesEmpty()) {
if (wrapper.getId() == originalId) {
// No changes needed; just set the reader and writer indexes and we're done
buf.setIndex(0, originalReaderIndex + remainingBytes);
return;
}
if (VarIntType.varIntLength(wrapper.getId()) == VarIntType.varIntLength(originalId)) {
// If the var int encoded length is the same, simply replace the id at the head
buf.setIndex(0, 0);
Types.VAR_INT.writePrimitive(buf, wrapper.getId());
buf.writerIndex(originalReaderIndex + remainingBytes);
return;
}
}
// Instead of allocating a possible unnecessarily large buffer to write the wrapper contents to,
// only allocate the remaining bytes and write the rest to the original buf's head directly.
final ByteBuf remainingBuf = buf.alloc().buffer(remainingBytes, remainingBytes);
try {
wrapper.writeToBuffer(transformed);
buf.clear().writeBytes(transformed);
// Copy before modifying the buffer
remainingBuf.writeBytes(buf, remainingBytes);
// Reset indexes, write wrapper contents, then the unread bytes
buf.setIndex(0, 0);
wrapper.writeProcessedValues(buf);
buf.writeBytes(remainingBuf);
} finally {
transformed.release();
remainingBuf.release();
}
}
@@ -76,6 +76,8 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3;
import com.viaversion.viaversion.protocols.v1_9_3to1_10.Protocol1_9_3To1_10;
@@ -192,6 +194,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_20_3To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_20_3);
registerProtocol(new Protocol1_20_5To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_20_5);
registerProtocol(new Protocol1_21To1_21_2(), ProtocolVersion.v1_21_2, ProtocolVersion.v1_21);
registerProtocol(new Protocol1_21_2To1_21_4(), ProtocolVersion.v1_21_4, ProtocolVersion.v1_21_2);
}
@Override
@@ -222,6 +222,18 @@ public class PacketWrapperImpl implements PacketWrapper {
@Override
public void writeToBuffer(ByteBuf buffer) throws InformativeException {
writeProcessedValues(buffer);
if (inputBuffer != null) {
buffer.writeBytes(inputBuffer);
}
}
public boolean areStoredPacketValuesEmpty() {
// Check for read/added packet values, not the input buffer
return packetValues.isEmpty() && readableObjects.isEmpty();
}
public void writeProcessedValues(ByteBuf buffer) throws InformativeException {
if (id != -1) {
Types.VAR_INT.writePrimitive(buffer, id);
}
@@ -238,16 +250,15 @@ public class PacketWrapperImpl implements PacketWrapper {
throw createInformativeException(e, packetValue.type(), i);
}
}
writeRemaining(buffer);
}
private InformativeException createInformativeException(final Exception cause, final Type<?> type, final int index) {
return new InformativeException(cause)
.set("Packet Type", this.packetType)
.set("Index", index)
.set("Type", type.getTypeName())
.set("Packet ID", this.id)
.set("Packet Type", this.packetType)
.set("Data", this.packetValues);
.set("Data", this.packetValues)
.set("Packet ID", this.id);
}
@Override
@@ -264,12 +275,6 @@ public class PacketWrapperImpl implements PacketWrapper {
packetValues.clear();
}
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
}
}
@Override
public void send(Class<? extends Protocol> protocol, boolean skipCurrentPipeline) throws InformativeException {
send0(protocol, skipCurrentPipeline, true);
@@ -320,7 +325,7 @@ public class PacketWrapperImpl implements PacketWrapper {
final ProtocolInfo protocolInfo = user().getProtocolInfo();
final List<Protocol> protocols = protocolInfo.getPipeline().pipes(protocolClass, skipCurrentPipeline, direction);
apply(direction, protocolInfo.getState(direction), protocols);
final ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
final ByteBuf output = allocateOutputBuffer();
try {
writeToBuffer(output);
return output.retain();
@@ -354,7 +359,7 @@ public class PacketWrapperImpl implements PacketWrapper {
return cancelledFuture();
}
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
ByteBuf output = allocateOutputBuffer();
try {
writeToBuffer(output);
return user().sendRawPacketFuture(output.retain());
@@ -373,7 +378,7 @@ public class PacketWrapperImpl implements PacketWrapper {
return;
}
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
ByteBuf output = allocateOutputBuffer();
try {
writeToBuffer(output);
if (currentThread) {
@@ -386,6 +391,14 @@ public class PacketWrapperImpl implements PacketWrapper {
}
}
private ByteBuf allocateOutputBuffer() {
if (inputBuffer == null) {
return user().getChannel().alloc().buffer();
}
// May have already been partially or fully read
return inputBuffer.alloc().buffer(Math.max(inputBuffer.readableBytes(), 256));
}
private ChannelFuture cancelledFuture() {
return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet"));
}
@@ -454,7 +467,7 @@ public class PacketWrapperImpl implements PacketWrapper {
return;
}
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
ByteBuf output = allocateOutputBuffer();
try {
writeToBuffer(output);
if (currentThread) {
@@ -23,11 +23,14 @@ import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
public enum ClientboundLoginPackets implements BaseClientboundPacket {
LOGIN_DISCONNECT, // 0x00
HELLO, // 0x01
GAME_PROFILE, // 0x02
LOGIN_FINISHED, // 0x02
LOGIN_COMPRESSION, // 0x03
CUSTOM_QUERY, // 0x04
COOKIE_REQUEST; // 0x05
@Deprecated(forRemoval = true)
public static final ClientboundLoginPackets GAME_PROFILE = LOGIN_FINISHED;
@Override
public final int getId() {
return ordinal();
@@ -128,7 +128,7 @@ public class ClientboundBaseProtocol1_7 extends AbstractProtocol<BaseClientbound
});
// Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
registerClientbound(ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
@@ -18,27 +18,26 @@
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
// To replace if needed:
// ChunkType1_20_2
// RecipeRewriter1_20_3
// Types1_21, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21, ServerboundPacket1_20_5, Protocol1_99To_98> {
// RecipeDisplayRewriter
// Types1_21_4, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21_2, ServerboundPacket1_21_4, Protocol1_99To_98> {
public BlockItemPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, Types1_21.ITEM, Types1_21.ITEM_ARRAY);
super(protocol, Types1_21_4.ITEM, Types1_21_4.ITEM_ARRAY);
/*super(protocol,
Types1_OLD.ITEM, Types1_OLD.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY,
Types1_OLD.ITEM_COST, Types1_OLD.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST,
Types1_OLD.PARTICLE, Types1_21.PARTICLE
Types1_OLD.ITEM, Types1_OLD.ITEM_ARRAY, Types1_21_4.ITEM, Types1_21_4.ITEM_ARRAY,
Types1_OLD.ITEM_COST, Types1_OLD.OPTIONAL_ITEM_COST, Types1_21_4.ITEM_COST, Types1_21_4.OPTIONAL_ITEM_COST
);*/
}
@@ -47,31 +46,33 @@ final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Clientbou
// Register block and block state id changes
// Other places using block state id mappings: Spawn particle, entity data, entity spawn (falling blocks)
// Tags and statistics use block (!) ids
final BlockRewriter<ClientboundPacket1_21> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA);
final BlockRewriter<ClientboundPacket1_21_2> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_2.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_2.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_2.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_2.BLOCK_ENTITY_DATA);
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenWindow(ClientboundPackets1_21.OPEN_WINDOW); - If a new container type was added
registerCooldown(ClientboundPackets1_21.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_21.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_21.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT);
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
registerExplosion(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
// registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration
protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem);
registerSetPlayerInventory(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_2.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_2.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_2.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS);
registerContainerClick1_21_2(ServerboundPackets1_21_4.CONTAINER_CLICK);
registerSetCreativeModeSlot(ServerboundPackets1_21_4.SET_CREATIVE_MODE_SLOT);
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_21.UPDATE_RECIPES);
final RecipeDisplayRewriter<ClientboundPacket1_21_2> recipeRewriter = new RecipeDisplayRewriter<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_2.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_2.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_2.PLACE_GHOST_RECIPE);
// OR do this if serialization of recipes changed and override the relevant method
// Add new serializers to RecipeRewriter, or extend the last one for changes
// new RecipeRewriter1_20_3<ClientboundPacket1_21>(this) {}.register1_20_5(ClientboundPackets1_21.DECLARE_RECIPES);
// Add new serializers to RecipeDisplayRewriter, or extend the last one for changes
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
final class ComponentRewriter1_99 extends ComponentRewriter<ClientboundPacket1_21_2> {
public ComponentRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, ReadType.NBT);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
// Remove or update data from componentsTag
}
@Override
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_21_4;
}
}
@@ -17,22 +17,20 @@
*/
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
// Replace if needed
// Types1_OLD
// Types1_21
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21, Protocol1_99To_98> {
// Types1_21_4
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21_2, Protocol1_99To_98> {
public EntityPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol);
@@ -41,36 +39,32 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
@Override
public void registerPackets() {
// Tracks entities, applies entity data rewrites registered below, untracks entities
registerTrackerWithData1_19(ClientboundPackets1_21.ADD_ENTITY, EntityTypes1_20_5.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_21.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES);
registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_21_4.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING));
final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY);
handleRegistryData1_20_5(wrapper.user(), registryKey, entries); // Caches dimensions to access data like height later and tracks the amount of biomes sent for chunk data
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> {
final int entityId = wrapper.passthrough(Types.INT); // Entity id
wrapper.passthrough(Types.BOOLEAN); // Hardcore
wrapper.passthrough(Types.STRING_ARRAY); // World List
wrapper.passthrough(Types.VAR_INT); // Max players
wrapper.passthrough(Types.VAR_INT); // View distance
wrapper.passthrough(Types.VAR_INT); // Simulation distance
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
wrapper.passthrough(Types.BOOLEAN); // Show death screen
wrapper.passthrough(Types.BOOLEAN); // Limited crafting
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
final String world = wrapper.passthrough(Types.STRING);
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
trackPlayer(wrapper.user(), entityId);
});
protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
map(Types.BOOLEAN); // Hardcore
map(Types.STRING_ARRAY); // World List
map(Types.VAR_INT); // Max players
map(Types.VAR_INT); // View distance
map(Types.VAR_INT); // Simulation distance
map(Types.BOOLEAN); // Reduced debug info
map(Types.BOOLEAN); // Show death screen
map(Types.BOOLEAN); // Limited crafting
map(Types.VAR_INT); // Dimension id
map(Types.STRING); // World
handler(worldDataTrackerHandlerByKey1_20_5(3)); // Tracks world height and name for chunk data and entity (un)tracking
handler(playerTrackerHandler());
}
});
protocol.registerClientbound(ClientboundPackets1_21.RESPAWN, wrapper -> {
protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> {
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
final String world = wrapper.passthrough(Types.STRING);
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
@@ -85,20 +79,20 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
if (id >= SomeAddedIndex) {
id++;
}
return Types1_21.ENTITY_DATA_TYPES.byId(id);
return Types1_21_4.ENTITY_DATA_TYPES.byId(id);
});*/
// Registers registry type id changes
registerEntityDataTypeHandler(
Types1_21.ENTITY_DATA_TYPES.itemType,
Types1_21.ENTITY_DATA_TYPES.blockStateType,
Types1_21.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_21.ENTITY_DATA_TYPES.particleType,
Types1_21.ENTITY_DATA_TYPES.particlesType,
Types1_21.ENTITY_DATA_TYPES.componentType,
Types1_21.ENTITY_DATA_TYPES.optionalComponentType
Types1_21_4.ENTITY_DATA_TYPES.itemType,
Types1_21_4.ENTITY_DATA_TYPES.blockStateType,
Types1_21_4.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_21_4.ENTITY_DATA_TYPES.particleType,
Types1_21_4.ENTITY_DATA_TYPES.particlesType,
Types1_21_4.ENTITY_DATA_TYPES.componentType,
Types1_21_4.ENTITY_DATA_TYPES.optionalComponentType
);
registerBlockStateHandler(EntityTypes1_20_5.ABSTRACT_MINECART, 11);
registerBlockStateHandler(EntityTypes1_21_4.ABSTRACT_MINECART, 11);
}
@Override
@@ -109,6 +103,6 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_20_5.getTypeFromId(type);
return EntityTypes1_21_4.getTypeFromId(type);
}
}
@@ -20,18 +20,21 @@ package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.type.types.version.Types1_21_4;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
@@ -40,35 +43,56 @@ import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_99To_98, EntityPacketRewriter1_99, BlockItemPacketRewriter1_99 - move the latter two to a rewriter package
// ClientboundPacket1_21
// ServerboundPacket1_20_5
// EntityTypes1_20_5 (MAPPED type)
// ClientboundPacket1_21_2
// ServerboundPacket1_21_4
// EntityTypes1_21_4 (MAPPED type)
// Types1_21_4.PARTICLE
// 1.99, 1.98
final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> {
final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21_2, ClientboundPacket1_21_2, ServerboundPacket1_21_4, ServerboundPacket1_21_4> {
public static final MappingData MAPPINGS = new MappingDataBase("1.98", "1.99");
private final EntityPacketRewriter1_99 entityRewriter = new EntityPacketRewriter1_99(this);
private final BlockItemPacketRewriter1_99 itemRewriter = new BlockItemPacketRewriter1_99(this);
private final TagRewriter<ClientboundPacket1_21> tagRewriter = new TagRewriter<>(this);
private final ParticleRewriter<ClientboundPacket1_21_2> particleRewriter = new ParticleRewriter<>(this, /*Types1_OLD.PARTICLE,*/ Types1_21_4.PARTICLE);
private final TagRewriter<ClientboundPacket1_21_2> tagRewriter = new TagRewriter<>(this);
private final ComponentRewriter<ClientboundPacket1_21_2> componentRewriter = new ComponentRewriter1_99(this);
public Protocol1_99To_98() {
// Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted
super(ClientboundPacket1_21.class, ClientboundPacket1_21.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class);
super(ClientboundPacket1_21_2.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_4.class, ServerboundPacket1_21_4.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundPackets1_21_2.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_21> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY);
// If needed for item or component changes
componentRewriter.registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISGUISED_CHAT);
componentRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_2.PLAYER_INFO_UPDATE);
componentRewriter.registerPing();
new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES);
// If needed for any particle, item, or block changes. Extend ParticleRewriter for particle serializer changes
particleRewriter.registerLevelParticles1_20_5(ClientboundPackets1_21_2.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE); // Rewrites the included sound and particles
final SoundRewriter<ClientboundPacket1_21_2> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_2.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_2.UPDATE_ATTRIBUTES);
// Uncomment if an existing type changed serialization format. Mappings for argument type keys can also be defined in mapping files
/*new CommandRewriter1_19_4<>(this) {
@@ -81,25 +105,29 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
super.handleArgument(wrapper, argumentType);
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_21.COMMANDS);*/
}.registerDeclareCommands1_19(ClientboundPackets1_21_2.COMMANDS);*/
}
@Override
protected void onMappingDataLoaded() {
// Uncomment this if the entity types enum has been newly added specifically for this Protocol
// EntityTypes1_20_5.initialize(this);
// EntityTypes1_21_4.initialize(this);
// Uncomment if a new particle was added = ids shifted; requires a new Types_ class copied from the last
/*Types1_21.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION)
.reader("item", ParticleType.Readers.ITEM1_20_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK);*/
/*Types1_21_4.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("block_crumble", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST1_21_2)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION1_21_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK)
.reader("entity_effect", ParticleType.Readers.COLOR)
.reader("trail", ParticleType.Readers.TRAIL1_21_4)
.reader("item", ParticleType.Readers.item(itemRewriter.mappedItemType()));*/
super.onMappingDataLoaded(); // Calls load methods on rewriters. Last in case the rewriters access the above filled data
}
@@ -107,7 +135,7 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
@Override
public void init(final UserConnection connection) {
// Register the entity tracker - used for entity id/entity data rewriting AND for tracking world data sent to the client (then used for chunk data rewriting)
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_5.PLAYER));
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
}
// Overriding these four methods is important as they are relied on various rewriter classes
@@ -128,17 +156,27 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
}
@Override
public TagRewriter<ClientboundPacket1_21> getTagRewriter() {
public ParticleRewriter<ClientboundPacket1_21_2> getParticleRewriter() {
return particleRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_2> getTagRewriter() {
return tagRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
public ComponentRewriter<ClientboundPacket1_21_2> getComponentRewriter() {
return componentRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_2, ClientboundPacket1_21_2, ServerboundPacket1_21_4, ServerboundPacket1_21_4> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class)
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class)
);
}
}
@@ -132,13 +132,13 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
if (effectID == 2002) {
int data = packetWrapper.get(Types.INT, 1);
boolean isInstant = false;
Pair<Integer, Boolean> newData = PotionColorMappings1_11.getNewData(data);
PotionColorMappings1_11.PotionData newData = PotionColorMappings1_11.getNewData(data);
if (newData == null) {
getLogger().warning("Received unknown potion data: " + data);
data = 0;
} else {
data = newData.key();
isInstant = newData.value();
data = newData.data();
isInstant = newData.instant();
}
if (isInstant) {
packetWrapper.set(Types.INT, 0, 2007);
@@ -17,14 +17,13 @@
*/
package com.viaversion.viaversion.protocols.v1_10to1_11.data;
import com.viaversion.viaversion.util.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class PotionColorMappings1_11 {
//<oldData> to <newData, isInstant> mapping
private static final Int2ObjectMap<Pair<Integer, Boolean>> POTIONS = new Int2ObjectOpenHashMap<>(37);
private static final Int2ObjectMap<PotionData> POTIONS = new Int2ObjectOpenHashMap<>(37);
static {
addRewrite(0, 3694022, false);
@@ -66,12 +65,14 @@ public class PotionColorMappings1_11 {
addRewrite(36, 3381504, false);
}
public static Pair<Integer, Boolean> getNewData(int oldData) {
public static @Nullable PotionData getNewData(int oldData) {
return POTIONS.get(oldData);
}
private static void addRewrite(int oldData, int newData, boolean isInstant) {
POTIONS.put(oldData, new Pair<>(newData, isInstant));
POTIONS.put(oldData, new PotionData(newData, isInstant));
}
public record PotionData(int data, boolean instant) {
}
}
@@ -24,9 +24,9 @@ import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11.EntityType;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@@ -37,6 +37,7 @@ import com.viaversion.viaversion.protocols.v1_10to1_11.data.EntityMappings1_11;
import com.viaversion.viaversion.protocols.v1_10to1_11.storage.EntityTracker1_11;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
@@ -91,13 +92,27 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
map(Types.INT); // 8 - Data
// Track Entity
handler(objectTrackerHandler());
handler(wrapper -> {
byte type = wrapper.get(Types.BYTE, 0);
if (type == EntityTypes1_10.ObjectType.FISHIHNG_HOOK.getId()) {
tryFixFishingHookVelocity(wrapper);
} else if (type == EntityTypes1_10.ObjectType.ITEM.getId()) {
// Older clients used stone as fallback as long as the entity data was not set
wrapper.send(Protocol1_10To1_11.class);
wrapper.cancel();
final int entityId = wrapper.get(Types.VAR_INT, 0);
final List<EntityData> entityDataList = new ArrayList<>();
entityDataList.add(new EntityData(6, EntityDataTypes1_9.ITEM, new DataItem(1, (byte) 1, null)));
final PacketWrapper setItem = PacketWrapper.create(ClientboundPackets1_9_3.SET_ENTITY_DATA, wrapper.user());
setItem.write(Types.VAR_INT, entityId);
setItem.write(Types1_9.ENTITY_DATA_LIST, entityDataList);
setItem.send(Protocol1_10To1_11.class);
}
});
handler(objectTrackerHandler());
}
});
@@ -166,8 +166,8 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, tag.getValue().clone());
}
});
if (w.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_2)) {
// Make sure it's included in the configuration packets
if (w.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_5)) {
// Make sure it's included in the configuration packets as it may already be required for registry data
tagsPacket.send(Protocol1_12_2To1_13.class);
} else {
tagsPacket.scheduleSend(Protocol1_12_2To1_13.class);
@@ -353,7 +353,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
registerClientbound(ClientboundPackets1_12_1.PLACE_GHOST_RECIPE, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE);
map(Types.UNSIGNED_BYTE);
handler(wrapper -> wrapper.write(Types.STRING, "viaversion:legacy/" + wrapper.read(Types.VAR_INT)));
}
});
@@ -594,7 +594,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
registerServerbound(ServerboundPackets1_13.PLACE_RECIPE, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // Window id
map(Types.UNSIGNED_BYTE); // Window id
handler(wrapper -> {
String s = wrapper.read(Types.STRING);
@@ -775,7 +775,10 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
for (Item[] ingredient : recipe.ingredients()) {
Item[] clone = new Item[ingredient.length];
for (int i = 0; i < ingredient.length; i++) {
if (clone[i] == null) continue;
if (ingredient[i] == null) {
continue;
}
clone[i] = ingredient[i].copy();
}
recipesPacket.write(Types.ITEM1_13_ARRAY, clone);
@@ -789,7 +792,10 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
for (Item[] ingredient : recipe.ingredients()) {
Item[] clone = new Item[ingredient.length];
for (int i = 0; i < ingredient.length; i++) {
if (clone[i] == null) continue;
if (ingredient[i] == null) {
continue;
}
clone[i] = ingredient[i].copy();
}
recipesPacket.write(Types.ITEM1_13_ARRAY, clone);
@@ -800,7 +806,10 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
recipesPacket.write(Types.STRING, recipe.group());
Item[] ingredient = new Item[recipe.ingredient().length];
for (int i = 0; i < ingredient.length; i++) {
if (recipe.ingredient()[i] == null) continue;
if (recipe.ingredient()[i] == null) {
continue;
}
ingredient[i] = recipe.ingredient()[i].copy();
}
recipesPacket.write(Types.ITEM1_13_ARRAY, ingredient);
@@ -33,6 +33,7 @@ import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities.
import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities.FlowerPotHandler;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities.SkullHandler;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities.SpawnerHandler;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.HashMap;
import java.util.Map;
@@ -46,6 +47,21 @@ public class BlockEntityProvider implements Provider {
handlers.put("minecraft:skull", new SkullHandler());
handlers.put("minecraft:mob_spawner", new SpawnerHandler());
handlers.put("minecraft:command_block", new CommandBlockHandler());
final BlockEntityHandler customNameHandler = (user, tag) -> {
final StringTag name = tag.getStringTag("CustomName");
if (name != null) {
name.setValue(ComponentUtil.legacyToJsonString(name.getValue()));
}
return -1;
};
handlers.put("minecraft:chest", customNameHandler);
handlers.put("minecraft:dispenser", customNameHandler);
handlers.put("minecraft:dropper", customNameHandler);
handlers.put("minecraft:enchanting_table", customNameHandler);
handlers.put("minecraft:furnace", customNameHandler);
handlers.put("minecraft:hopper", customNameHandler);
handlers.put("minecraft:shulker_box", customNameHandler);
}
/**
@@ -18,16 +18,19 @@
package com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.BlockEntityProvider;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Pair;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class FlowerPotHandler implements BlockEntityProvider.BlockEntityHandler {
// Object -> string (id without namespace) or byte (numeric id)
private static final Map<Pair<?, Byte>, Integer> flowers = new ConcurrentHashMap<>();
private static final int EMPTY_POT = 5265;
private static final Map<String, Byte> STRING_TO_BYTE_ID = new HashMap<>();
private static final Map<IntIdPair, Integer> FLOWERS = new HashMap<>();
static {
register("air", (byte) 0, (byte) 0, 5265);
@@ -55,37 +58,40 @@ public class FlowerPotHandler implements BlockEntityProvider.BlockEntityHandler
}
public static void register(String identifier, byte numbericBlockId, byte blockData, int newId) {
flowers.put(new Pair<>(identifier, blockData), newId);
flowers.put(new Pair<>(numbericBlockId, blockData), newId);
private static void register(String identifier, byte blockId, byte blockData, int newId) {
STRING_TO_BYTE_ID.put(identifier, blockId);
FLOWERS.put(new IntIdPair(blockId, blockData), newId);
}
@Override
public int transform(UserConnection user, CompoundTag tag) {
Object item = tag.contains("Item") ? tag.get("Item").getValue() : null;
Object data = tag.contains("Data") ? tag.get("Data").getValue() : null;
// Convert item to String without namespace or to Byte
if (item instanceof String) {
item = Key.stripMinecraftNamespace((String) item);
} else if (item instanceof Number) {
item = ((Number) item).byteValue();
} else {
item = (byte) 0;
Tag itemTag = tag.get("Item");
byte item = 0;
if (itemTag instanceof StringTag stringTag) {
item = STRING_TO_BYTE_ID.getOrDefault(Key.stripMinecraftNamespace(stringTag.getValue()), (byte) 0);
} else if (itemTag instanceof NumberTag numberTag) {
item = numberTag.asByte();
}
// Convert data to Byte
if (data instanceof Number) {
data = ((Number) data).byteValue();
} else {
data = (byte) 0;
byte data = 0;
if (tag.get("Data") instanceof NumberTag dataTag) {
data = dataTag.asByte();
}
Integer flower = flowers.get(new Pair<>(item, (byte) data));
if (flower != null) return flower;
flower = flowers.get(new Pair<>(item, (byte) 0));
if (flower != null) return flower;
Integer flower = FLOWERS.get(new IntIdPair(item, data));
if (flower != null) {
return flower;
}
return 5265; // Fallback to empty pot
flower = FLOWERS.get(new IntIdPair(item, (byte) 0));
if (flower != null) {
return flower;
}
return EMPTY_POT; // Fallback to empty pot
}
private record IntIdPair(int id, byte data) {
}
}
@@ -205,23 +205,23 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
String old = channel;
channel = getOldPluginChannelId(channel);
if (channel == null) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getManager().isDebug()) {
protocol.getLogger().warning("Ignoring serverbound plugin message with channel: " + old);
}
wrapper.cancel();
return;
} else if (channel.equals("REGISTER") || channel.equals("UNREGISTER")) {
String[] channels = new String(wrapper.read(Types.REMAINING_BYTES), StandardCharsets.UTF_8).split("\0");
String[] channels = new String(wrapper.read(Types.SERVERBOUND_CUSTOM_PAYLOAD_DATA), StandardCharsets.UTF_8).split("\0");
List<String> rewrittenChannels = new ArrayList<>();
for (String s : channels) {
String rewritten = getOldPluginChannelId(s);
if (rewritten != null) {
rewrittenChannels.add(rewritten);
} else if (!Via.getConfig().isSuppressConversionWarnings()) {
} else if (Via.getManager().isDebug()) {
protocol.getLogger().warning("Ignoring plugin channel in serverbound " + channel + ": " + s);
}
}
wrapper.write(Types.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8));
wrapper.write(Types.SERVERBOUND_CUSTOM_PAYLOAD_DATA, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8));
}
wrapper.set(Types.STRING, 0, channel);
});
@@ -17,7 +17,10 @@
*/
package com.viaversion.viaversion.protocols.v1_13_1to1_13_2.rewriter;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@@ -30,8 +33,16 @@ public class EntityPacketRewriter1_13_2 {
public static void register(Protocol1_13_1To1_13_2 protocol) {
final PacketHandler dataTypeHandler = wrapper -> {
for (EntityData data : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) {
data.setDataType(Types1_13_2.ENTITY_DATA_TYPES.byId(data.dataType().typeId()));
for (final EntityData data : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) {
final EntityDataType dataType = Types1_13_2.ENTITY_DATA_TYPES.byId(data.dataType().typeId());
if (dataType == Types1_13_2.ENTITY_DATA_TYPES.particleType) {
final Particle particle = data.value();
if (particle.id() == 27) {
final Item item = particle.<Item>getArgument(0).getValue();
particle.set(0, Types.ITEM1_13_2, item);
}
}
data.setDataType(dataType);
}
};
@@ -23,15 +23,16 @@ import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_13_2;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ComponentRewriter1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.data.MappingData1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ComponentRewriter1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.EntityPacketRewriter1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ItemPacketRewriter1_14;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.PlayerPacketRewriter1_14;
@@ -39,6 +40,7 @@ import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.WorldPacketRew
import com.viaversion.viaversion.protocols.v1_13_2to1_14.storage.EntityTracker1_14;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
@@ -49,6 +51,7 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
public static final MappingData1_14 MAPPINGS = new MappingData1_14();
private final EntityPacketRewriter1_14 entityRewriter = new EntityPacketRewriter1_14(this);
private final ItemPacketRewriter1_14 itemRewriter = new ItemPacketRewriter1_14(this);
private final ParticleRewriter<ClientboundPackets1_13> particleRewriter = new ParticleRewriter<>(this);
private final TagRewriter<ClientboundPackets1_13> tagRewriter = new TagRewriter<>(this);
public Protocol1_13_2To1_14() {
@@ -65,6 +68,8 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
new SoundRewriter<>(this).registerSound(ClientboundPackets1_13.SOUND);
new StatisticsRewriter<>(this).register(ClientboundPackets1_13.AWARD_STATS);
particleRewriter.registerLevelParticles1_13(ClientboundPackets1_13.LEVEL_PARTICLES, Types.FLOAT);
ComponentRewriter<ClientboundPackets1_13> componentRewriter = new ComponentRewriter1_14<>(this);
componentRewriter.registerComponentPacket(ClientboundPackets1_13.CHAT);
@@ -139,6 +144,11 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
return itemRewriter;
}
@Override
public ParticleRewriter<ClientboundPackets1_13> getParticleRewriter() {
return particleRewriter;
}
@Override
public TagRewriter<ClientboundPackets1_13> getTagRewriter() {
return tagRewriter;
Loaded 100 of 207 files, more files were not shown because too many files have changed in this diff. Show more