Compare commits

..
133 Commits
Author SHA1 Message Date
Nassim Jahnke 83e44641d0 5.0.4 Release 2024-10-14 17:24:05 +02:00
Nassim Jahnke 50084c112d Fix tag related issues to prepare for 1.21.2
- Inline tag values in 1.21 enchantments
- Fix TagRewriter addTags if the server doesn't send values for a registry
- Send the tags packet in 1.12->1.13 before the play login packet to fix tracking in 1.20->1.20.2
2024-10-14 17:16:01 +02:00
EnZaXD 81682f4921 Change description of dump sub command to be more generic (#4180) 2024-10-13 10:33:58 +02:00
Nassim Jahnke 1c339e8b54 Null check input serializer version
Fixes ViaVersion/ViaBackwards#896
2024-10-11 19:37:35 +02:00
EnZaXD 1a9cda0579 Handle WRITTEN_BOOK_CONTENT component in rewriters as well (#4175)
Closes https://github.com/ViaVersion/ViaVersion/issues/4144
2024-10-10 22:42:21 +02:00
EnZaXD 6ad9a71907 Print book conversion errors to default logger in 1.20.2->1.20.3 (#4158) 2024-10-10 22:37:21 +02:00
Nassim Jahnke 9f24576ba7 Update some dependencies 2024-10-10 21:21:54 +02:00
EnZaXD 8661bbc1fc Update required ViaFabric version, don't require fabric-loader (#4174) 2024-10-10 12:26:32 +02:00
EnZaXD 0b5fa37f96 Put title directly into component in 1.8->1.9 bossbar emulation (#4173)
The JsonParser#parseString detection in CommonBoss will detect " " as valid json (JsonNull) and won't wrap it around ComponentUtil#plainToJson like it should, at some point in the future I would like CommonBoss to only accept a JsonElement instance and not raw strings anymore.

Closes https://github.com/ViaVersion/ViaFabricPlus/issues/494
2024-10-10 12:25:27 +02:00
EnZaXD dab32bafa1 Write correct on ground state in 1.20.5->1.21 placement rotation fix (#4170) 2024-10-09 16:37:30 +02:00
Nassim Jahnke 9e5c541f79 Disable placement rotation fix for now
Closes #4168
2024-10-07 21:43:20 +02:00
EnZaXD 9674c617ca Add option to fix wrong block placement rotation in 1.20.5->1.21 (#4166) 2024-10-06 15:19:05 +02:00
EnZaXD 9df1704357 Fix holder set direct id conversion in 1.20.3->1.20.5 component rewriter (#4164) 2024-10-05 21:34:34 +02:00
EnZaXD c0821de2e2 Define as Sponge plugin for ViaSponge (#4163) 2024-10-02 10:41:59 +02:00
Nassim Jahnke c358c39027 Make clearer distinction between filled and empty data component patch, simplify direct value getting 2024-09-29 13:34:32 +02:00
github-actions[bot]andgradle-update-robot 451b3a2637 Update Gradle Wrapper from 8.10.1 to 8.10.2 (#4161)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-09-29 04:19:11 +02:00
Nassim Jahnke 619eecacf8 Don't add block entity tag if the id is missing 2024-09-26 12:16:06 +02:00
RK_01 6bae039d52 Update mcstructs (#4159) 2024-09-24 19:09:32 +02:00
dependabot[bot] b321029886 Bump gradle-update/update-gradle-wrapper-action from 1 to 2 (#4157)
Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1 to 2.
- [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases)
- [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: gradle-update/update-gradle-wrapper-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 19:44:27 +02:00
EnZaXD 5287d4fb4f Fix enchantment glint behaviour in 1.10->1.11 (#4156) 2024-09-23 19:24:46 +02:00
EnZaXD a0a2794291 Change player parent to living entity base in 1.9/1.12 entity enums (#4154) 2024-09-20 13:35:58 +02:00
EnZaXD 9e354e956e Update MCStructs (#4153) 2024-09-20 13:35:48 +02:00
EnZaXD 27033e9096 Remove transaction tracking (and cancelling) in 1.16.4->1.17 (#4140) 2024-09-15 21:52:32 +02:00
EnZaXD e436bbe375 Refactor dimension switch handling across all protocols (#4146) 2024-09-15 21:51:29 +02:00
EnZaXD 050a1dbacb Fix set equipment body slot in 1.20.3->.5 if value is not the last (#4149) 2024-09-15 19:14:42 +02:00
github-actions[bot]andgradle-update-robot ae1838d78a Update Gradle Wrapper from 8.10 to 8.10.1. (#4148)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-09-15 09:51:02 +02:00
EnZaXD 7235485802 Cleanup enchantment conversion in 1.12->1.13 to match vanilla (#4147)
Closes https://github.com/ViaVersion/ViaFabricPlus/issues/560
2024-09-14 21:33:18 +02:00
EnZaXD fcb472347e Add EntityTrackerBase#hasClientEntityId and don't use -1 as not set indicator (#4143) 2024-09-14 10:45:19 +02:00
EnZaXD e0ce8cc715 Make EntityTrackerBase#clearEntities call removeEntity for all entries (#4142) 2024-09-12 22:09:52 +02:00
EnZaXD ebc0e61be8 Fix invalid book view not visible in 1.20.3->.5 (#4139) 2024-09-07 10:45:10 +02:00
Nassim Jahnke 95581a6fa5 Fix mapping reading of changed_id type 2024-09-05 10:02:55 +02:00
EnZaXD d0b49009e5 Rewrite display name component in player info packet in 1.20.3->.5 (#4136) 2024-09-04 20:27:38 +02:00
Nassim Jahnke 369b076cad Null check channel in player join listener
Fixes #3390
2024-09-03 16:43:55 +02:00
Nassim Jahnke 6555bcda74 Small cleanup to mapping file loading 2024-09-02 23:21:29 +02:00
Nassim Jahnke e537dbb024 Clean up StructuredItemRewriter, also handle sound events 2024-08-30 19:10:43 +02:00
Nassim Jahnke f92dbb655d Also cache missing protocol paths, don't reverse base protocols 2024-08-30 11:19:32 +02:00
RK_01 0b2dac9056 Copy item in Particle#copy (#4130) 2024-08-29 23:28:39 +02:00
EnZaXD 7cd5514b90 Add PacketWrapper#sendFutureRaw, cleanup login disconnect handling. (#4129)
Removes the special handling in Protocol1_8To1_9 and always send the correct/expected data by the client in ServerboundBaseProtocol1_7 itself. Also prevent sending the packet through the protocol pipeline since packet/format changes should also be handled inside the base protocol.
2024-08-29 21:46:43 +02:00
RK_01 5017d4bbb3 Add Particle#copy (#4126) 2024-08-29 15:32:28 +02:00
EnZaXD 32e51b52aa Cleanup LOGIN/STATUS packet handlers (#4113) 2024-08-28 15:52:28 +02:00
Nassim Jahnke 4f66fd793b Go back to fast entity data list iteration and mutation
This is a fairly hot method and the array list cannot be modified outside of the already managed event cancellation and provided extra list
2024-08-25 18:59:48 +02:00
Nassim Jahnke 2a71612aea Small cleanup of a few rewriters 2024-08-25 18:42:21 +02:00
Nassim Jahnke a993a08b8d Only map between different primitive types when explicitly requested
This would otherwise only happen with unsafe type usage
2024-08-24 18:00:06 +02:00
Nassim Jahnke a9c947517c Don't unnecessarily re-wrap objects in passthrough 2024-08-24 17:10:20 +02:00
Pablo Herrera 2841bf3040 Add option to hide scoreboard numbers (#4122) 2024-08-24 15:49:09 +02:00
RK_01 7edddda36e Split base protocols list (#4118) 2024-08-23 14:09:14 +02:00
RK_01 33de12ceb1 Reset reader before passing packet through protocols (#4117) 2024-08-23 09:42:50 +02:00
RK_01 f8eb57cdbb Fix 1.8->1.9 click sound mappings (#4116) 2024-08-22 19:39:09 +02:00
EnZaXD b2d523f5c0 Add more API for base protocols and skip manually added ones. (#4115) 2024-08-22 17:15:29 +02:00
EnZaXD b586b0d361 Allow client intention packet to be cancelled (#4114) 2024-08-22 10:59:35 +02:00
EnZaXD c6381e7f4d Allow protocols to handle client intention packet (#4112) 2024-08-21 19:58:32 +02:00
EnZaXD 10ee7e1930 Deprecate StoredObject#getUser (#4104) 2024-08-21 19:14:40 +02:00
EnZaXD 78abf8be00 Use RedirectProtocolVersion#getOrigin in InitialBaseProtocol if possible (#4110)
This way, we should be able to get rid of manually adding the base protocol in projects like ViaAprilFools:
https://github.com/ViaVersion/ViaAprilFools/blob/main/common/src/main/java/net/raphimc/viaaprilfools/protocol/s3d_sharewaretov1_14/Protocol3D_SharewareTo1_14.java#L87
2024-08-21 16:56:20 +02:00
EnZaXD 1dde24bb68 [ci skip] Remove outdated comments (#4111) 2024-08-21 16:56:09 +02:00
EnZaXD bc57512ca2 Allow for multiple base protocols per version (#4106) 2024-08-21 14:35:19 +02:00
github-actions[bot]andgradle-update-robot 6ad3beca76 Update Gradle Wrapper from 8.9 to 8.10. (#4105)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-08-18 11:04:12 +02:00
EnZaXD 9d75125e41 Make EntityTrackerBase#entities protected (#4103) 2024-08-18 11:03:57 +02:00
RK_01 8ce4112e86 Improve/Fix 1.8->1.9 sound mappings (#4099) 2024-08-14 18:04:37 +02:00
EnZaXD 7d542d5667 Fix ComponentRewriter1_20_5#convertFood behaviour (#4095)
Closes https://github.com/ViaVersion/ViaFabricPlus/issues/517
2024-08-14 15:26:22 +02:00
EnZaXD 7d6599b90e [ci skip] Setup dependabot for GH Actions and add workflow for updating the Gradle Wrapper (#4097) 2024-08-14 15:01:57 +02:00
EnZaXD 1b03e24160 Move VV specific item handling out of component<->nbt conversion in 1.20.3->1.20.5 (#4094)
The current code backups the tag in CUSTOM_DATA inside the toStructuredItem function which in VB is used for to server packets which causes bad data, this PR moves the backup logic out to the VV specific handler and also prevents toOldItem logic for using the backup to ever get executed in VB. The counterpart PR will add proper handling for CUSTOM_DATA.

Fixes https://github.com/ViaVersion/ViaVersion/issues/4092
2024-08-14 09:31:27 +02:00
Nassim Jahnke fcd91bb855 Add item cost and particle types to item rewriter 2024-08-13 12:45:36 +02:00
Nassim Jahnke bda4ea9fd0 [ci skip] Move template protocol into common module
Had to move the rewriter classes into the flattened package to make them package private, but this is nicer than having a separate module just for those
2024-08-13 10:24:20 +02:00
FlorianMichael cbd26ce9d9 [ci skip] Link to our new website instead 2024-08-13 10:14:22 +02:00
Nassim Jahnke 8d53f4aa5a Update mcstructs 2024-08-13 09:59:59 +02:00
EnZaXD 1438f1f68d [ci skip] Update README.md (#4088) 2024-08-11 11:33:12 +02:00
RK_01 61fcf6f895 Update 1.21 version range (#4082) 2024-08-08 17:27:38 +02:00
Nassim Jahnke 736834441d [ci skip] Update shadow 2024-08-08 10:55:56 +02:00
Nassim Jahnke 3f5417be97 5.0.3 Release 2024-08-07 17:56:01 +02:00
Nassim Jahnke cc1c88001f Hotfix item id changes in item hover events 2024-08-07 17:36:42 +02:00
Nassim Jahnke 274f98c24e Fix double remapping of area effect cloud particle in 1.20.2->.3
Fixes #4042
2024-08-07 15:37:14 +02:00
Kichura f39b466ac0 Update Ubuntu, Change wrapper-validation in publish. (#4081) 2024-08-07 15:27:03 +02:00
EnZaXD aa22ca1d56 Handle pitch/yaw->data item frame rotation change in 1.16.4->1.17 (#4064)
See https://github.com/ViaVersion/ViaBackwards/pull/848
2024-08-07 13:02:51 +02:00
Nassim Jahnke 802e868b2e Track sent armor trim registries in 1.20.3->1.20.5 2024-08-07 12:36:51 +02:00
Nassim Jahnke 02442a9775 Only resend attribute modifiers when necessary
Fixes #3973
2024-08-07 11:59:13 +02:00
EnZaXD 5349de91c5 Rename CI workflow and update gradle wrapper validation (#4079) 2024-08-07 11:32:16 +02:00
Nassim Jahnke a8ef3c890a Only add dummy enchantment once 2024-08-06 15:21:18 +02:00
EnZaXD b556e6528a Rename remaining packages in bukkit modules to new format (#4074) 2024-08-05 09:48:01 +02:00
EnZaXD 434b32cad8 Fix typo in ViaManagerImpl#destroy log message (#4073) 2024-08-05 09:30:48 +02:00
EnZaXD 60b3ba6bb7 Include snakeyaml into final jar, delete compat layers (#4070)
Snakeyaml is an untypical library which most Via platforms don't have and also broke in the past with V2, having it directly in the jar like Gson cleans up the build scripts massively, reduces the build time and also doesn't break in the future if they release V3 or any other breaking changes.
2024-08-05 09:30:34 +02:00
EnZaXD 864beef341 Regenerate toString() functions and remove them from protocol internals (#4072) 2024-08-05 09:09:34 +02:00
EnZaXD 7b21df2c12 Use GH repository description in platforms (#4071) 2024-08-05 09:09:09 +02:00
Nassim Jahnke 462a10363c Only print reload info when needed, add additional log message after shutdown
Thanks to its name and dependency order, ViaVersion will generally be the last plugin to be disabled and has occasionally been blamed for other plugins stalling server shutdown
2024-08-03 20:35:22 +02:00
EnZaXD 040f85659d Fix enchantment emulation in 1.20.5->1.21 on non Paper servers (#4060) 2024-08-02 11:05:17 +02:00
Nassim Jahnke 48d5aaf8fa 5.0.2 Release 2024-07-28 14:37:59 +02:00
EnZaXD 41b0d95d70 Fix horse/llama's armor/carpet not visible in 1.20.3->1.20.5 (#4052) 2024-07-27 20:26:53 +02:00
EnZaXD b599399c48 Cleanup 1.20->1.20.2 item and recipe rewriter (#4050) 2024-07-27 19:53:59 +02:00
EnZaXD 721e27eb39 Rewrite show_item in translation components in 1.11.1->1.12 (#4053)
Fixes https://github.com/ViaVersion/ViaVersion/issues/4051
2024-07-27 19:53:44 +02:00
EnZaXD c9d6fbfcd0 Add VersionProvider#getServerProtocol (#4049)
Most platforms won't ever throw an error and usually ViaVersion shouldn't even load when the server version can't be found. Therefore, I added this bouncer function, so I don't need to try catch my code in ViaLoader/VFP where an exception is never thrown
2024-07-27 19:53:33 +02:00
RK_01 b1f64fd081 Use enhanced switches in more places (#4043) 2024-07-24 14:32:36 +02:00
EnZaXD 2b508567db Move damage types 1.20.3 into nbt file (#4026) 2024-07-24 13:13:36 +02:00
EnZaXD 24d0ae7607 Add ViaManager#addPostEnableListener (#4038) 2024-07-22 18:24:06 +02:00
EnZaXD 40a44d5dc5 Remove version type from dump (#4036) 2024-07-22 17:45:21 +02:00
EnZaXD b5a06181d4 Fix item projectile hierarchy in 1.14+ (#4034) 2024-07-22 17:44:07 +02:00
EnZaXD 35fa7e78a0 Handle attribute_modifiers inside container components in 1.21->1.20.5 (#4035)
Closes https://github.com/ViaVersion/ViaVersion/issues/3968
2024-07-22 17:42:25 +02:00
EnZaXD 7f4faab4ab Add 1.21 to the version table (#4037) 2024-07-22 17:40:37 +02:00
EnZaXD 3906b47654 Apply required changes for ViaAprilFools (#4033)
1. Allow the version provider to get the client version sent through the handshake packet
2. Allow platform to override provider instead
2024-07-21 17:45:13 +02:00
Nassim Jahnke 1476adb281 Slightly improve logging on config loading errors 2024-07-21 12:12:06 +02:00
EnZaXD 6fb072120b Removes VFP as well and recommends ViaBackwards/ViaRewind on both platforms (#4032) 2024-07-21 09:43:40 +02:00
EnZaXD f2f0be0581 Allow base protocols to set client version (#4029) 2024-07-20 09:15:15 +02:00
EnZaXD 5ec30ef18a Expose origin version in RedirectProtocolVersion (#4030) 2024-07-20 09:12:44 +02:00
Nassim Jahnke 0915afe43b Handle 1.21 attribute id changes
Fixes #4005
2024-07-19 11:26:28 +02:00
EnZaXD 87b041bf3a Fix block predicate conversion in 1.20.3->1.20.5 (#4025) 2024-07-19 11:00:00 +02:00
EnZaXD 275b09bdbb Use SerializerVersion#toTag when converting 1.20.5->1.20.3 block predicates (#4024) 2024-07-19 10:54:40 +02:00
Nassim Jahnke cc87c02020 Add shulker box block entity id if missing 2024-07-17 18:48:07 +02:00
EnZaXD a45985ed58 Validate index when reading structured data type (#4020) 2024-07-16 09:59:33 +02:00
Nassim Jahnke 92dedfb950 Update Gradle wrapper 2024-07-14 21:31:38 +02:00
RK_01 6bbcf7d784 Fix respawn "keep data" translation (#4015) 2024-07-13 11:00:12 +02:00
EnZaXD 465a2354c0 Call component rewriter in pre 1.20.3 advancement handler (#4014)
Required for ViaBackwards where we need to rewrite the translation key (and it also doesn't hurt to have this in forward protocols).

Closes https://github.com/ViaVersion/ViaBackwards/issues/819
2024-07-13 11:00:00 +02:00
EnZaXD c59c15d6f3 [ci skip] Fix player combat packet value comments (#4013) 2024-07-13 10:59:47 +02:00
EnZaXD 20f7738f08 Add cancel-block-sounds option for 1.8->1.9 place/break fix (#4011) 2024-07-12 00:11:11 +02:00
EnZaXD 323f0fa087 Remove minimize-cooldown config option (#4009) 2024-07-07 18:03:35 +02:00
RK_01 3138d667a6 Fix crossbow max damage and 1.8 sword blocking using item data components (#4010) 2024-07-07 18:02:51 +02:00
EnZaXD 365040f59d Handle rarity changes in trident/banner pattern item in 1.20.5->1.21 (#4001) 2024-07-07 17:39:30 +02:00
lowercasebtwandEnZaXD 303d9ecf51 Hide cooldown indicator completely in 1.8->1.9 (#4006)
* Change 1.8 to 1.9 Attack Speed

* Fix The Attack Speed Value Type

* Change Attack Speed to 20

Requested/Suggested change from FlorianMichael

Co-authored-by: EnZaXD <florian.michael07@gmail.com>

---------

Co-authored-by: EnZaXD <florian.michael07@gmail.com>
2024-07-06 23:12:01 +02:00
EnZaXD 463381b84e Rename missing metadata references to entity data (#4007) 2024-07-06 21:05:40 +02:00
Nassim Jahnke 7fef96d77e Remove unneeded 1.13 enchantment translatable mappings 2024-07-03 11:32:25 +02:00
Gegy 17358120cd Fix: delay chat acknowledgements instead of spoofing (#3997)
An easy reproduction case is to mute a player using the Social Interactions screen, let them chat, and then send a message. As ViaVersion produces its own acknowledgements, this now does not match with what the client produced and signed its messages with - so the signature will fail verification.

As an alternative, we *always* pass through the same acknowledgement bit set - and for 'spoofed' messages, we reuse the last one that we received. In the case of the chat ack packet with just an offset, we need to hold back the window by at least 20 messages to ensure we don't start making claims about whether the client saw a message that ViaVersion cannot yet make a judgement on.
2024-07-03 10:52:01 +02:00
EnZaXD e6da77cf47 Handle Slot tag inside CONTAINER tag in 1.20.3->1.20.5 (#3995)
Fixes shulker box tooltips not showing all items for 1.20.3 clients on 1.20.5+ servers
2024-07-02 11:53:34 +02:00
EnZaXD dc503cd613 Update legacy Minecraft version warning (#3989) 2024-06-30 11:30:54 +02:00
Nassim Jahnke 8aa2f4be46 Handle show item hovers in more component packets
Because servers do weird things
2024-06-30 11:10:44 +02:00
Nassim Jahnke c5dc5b2bf8 Actually restrict velocity change to fishing hooks 2024-06-28 15:29:06 +02:00
EnZaXD f4d6659760 Only print broken json in component type when debug mode is enabled (#3990) 2024-06-28 13:44:31 +02:00
EnZaXD bfbb80f708 Update unsupported java version warning (#3988)
Now links to the release which contains a guide on how to update
2024-06-27 14:56:15 +02:00
EnZaXD 248da118a9 Move bukkit-only settings into BukkitViaConfig (#3985) 2024-06-27 09:56:50 +02:00
EnZaXD a987882132 Rework unsupported config options in AbstractViaConfig (#3986) 2024-06-27 09:54:44 +02:00
EnZaXD bca25d4744 Rewrite filtered_pages in 1.20.2->1.20.3 (#3983) 2024-06-26 10:58:50 +02:00
EnZaXD 2417ffe483 Fixup horse inventory translation in 1.20.5->1.21 (#3980)
Fixes #3978
2024-06-25 15:27:02 +02:00
EnZaXD 8606e5d663 Handle both json and plain text in CommonBoss (#3981) 2024-06-25 15:21:34 +02:00
EnZaXD 5a0ca55b97 Add test command handler to DummyInitializer test (#3970) 2024-06-25 15:21:26 +02:00
Nassim Jahnke ceb1cffb00 Cancel "message not delivered" messages
Fixes #3438
2024-06-25 15:19:03 +02:00
Nassim Jahnke 1ff3035bc0 Make 1.10->1.11 fishing hook position desync slightly less bad 2024-06-25 15:17:29 +02:00
Nassim Jahnke 1f221ea828 Bump version to 5.0.2-SNAPSHOT 2024-06-25 15:16:36 +02:00
221 changed files with 3227 additions and 2611 deletions

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = false
insert_final_newline = true
tab_width = 4
[*.java]
@@ -13,4 +13,4 @@ ij_java_generate_final_locals = true
ij_java_generate_final_parameters = true
[{*.json,*.yml}]
indent_size = 2
indent_size = 2
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
@@ -7,13 +7,13 @@ jobs:
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v3
uses: gradle/actions/wrapper-validation@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
+2 -2
View File
@@ -8,12 +8,12 @@ on:
jobs:
publish:
if: github.repository_owner == 'ViaVersion'
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v3
uses: gradle/actions/wrapper-validation@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
@@ -0,0 +1,14 @@
name: Update Gradle Wrapper
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * 0"
jobs:
update-gradle-wrapper:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v2
+6 -6
View File
@@ -1,7 +1,7 @@
# ViaVersion
[![Latest Release](https://img.shields.io/github/v/release/ViaVersion/ViaVersion)](https://viaversion.com)
[![Build Status](https://github.com/ViaVersion/ViaVersion/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaVersion/actions)
[![Build Status](https://github.com/ViaVersion/ViaVersion/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaVersion/actions)
[![Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord)
**Allows the connection of higher client versions to lower server versions -
@@ -9,14 +9,14 @@ it works on any platform you can think of.**
The base ViaVersion jar runs on Paper and Velocity. We also have projects integrating ViaVersion to run
on Fabric, Forge, Bungee, Sponge, or as a standalone proxy to join from basically any client version on
any server version from the past decade. **See [HERE](https://github.com/ViaVersion) for an overview of the different Via\* projects.**
any server version from the past decade. **See [HERE](https://viaversion.com) for an overview of the different Via\* projects.**
Note that ViaVersion will be able to **run best on either Paper servers or Fabric clients** due to having
Note that ViaVersion will be able to **run best on either Paper servers or through [ViaFabricPlus](https://github.com/ViaVersion/ViaFabricPlus?tab=readme-ov-file#viafabricplus)** due to having
direct access to client/server state and more extensive API.
Supported Versions:
![Table (https://i.imgur.com/sTrVnC2.png)](https://i.imgur.com/sTrVnC2.png)
![Table (https://i.imgur.com/zrQTcf0.png)](https://i.imgur.com/zrQTcf0.png)
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
@@ -83,7 +83,7 @@ You need JDK 17 or newer to build ViaVersion.
Mapping Files
--------------
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings).
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings). The generated mapping output is stored [here](./common/src/main/resources/assets/viaversion).
Resources
@@ -96,7 +96,7 @@ Resources
License
--------
The entirety of the [API directory](api) (including the legacy API directory) is licensed under the MIT License;
The entirety of the [API directory](api) is licensed under the MIT License;
see [licenses/MIT.md](licenses/MIT.md) for
details.
+1 -1
View File
@@ -24,8 +24,8 @@ dependencies {
exclude("com.google.code.gson", "gson")
exclude("com.viaversion", "nbt")
}
api(libs.snakeYaml)
compileOnlyApi(libs.snakeYaml)
compileOnlyApi(libs.netty)
compileOnlyApi(libs.guava)
compileOnlyApi(libs.checkerQual)
@@ -140,6 +140,13 @@ public interface ViaManager {
*/
void addEnableListener(Runnable runnable);
/**
* Adds a runnable to be executed when ViaVersion has finished its init after the full server load.
*
* @param runnable runnable to be executed
*/
void addPostEnableListener(Runnable runnable);
/**
* Returns whether the manager has been initialized (and protocols have been loaded).
*
@@ -67,9 +67,9 @@ public interface ViaVersionConfig extends Config {
boolean isShowNewDeathMessages();
/**
* Get if metadata errors will be suppressed
* Get if entity data errors will be suppressed
*
* @return true if metadata errors suppression is enabled
* @return true if entity data errors suppression is enabled
*/
boolean isSuppressMetadataErrors();
@@ -292,13 +292,6 @@ public interface ViaVersionConfig extends Config {
*/
boolean isDisable1_13AutoComplete();
/**
* Tries to minimize cooldown animation.
*
* @return true if enabled
*/
boolean isMinimizeCooldown();
/**
* Enable the serverside blockconnections for 1.13+ clients
*
@@ -464,4 +457,25 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean handleInvalidItemCount();
/**
* Tries to cancel block break/place sounds sent by 1.8 servers to 1.9+ clients to prevent them from playing twice
*
* @return true if enabled
*/
boolean cancelBlockSounds();
/**
* Hides scoreboard numbers for 1.20.3+ clients on older server versions.
*
* @return true if enabled
*/
boolean hideScoreboardNumbers();
/**
* Fixes 1.21+ clients on 1.20.5 servers placing water/lava buckets at the wrong location when moving fast.
*
* @return true if enabled
*/
boolean fix1_21PlacementRotation();
}
@@ -29,6 +29,11 @@ public abstract class StoredObject implements StorableObject {
this.user = user;
}
public UserConnection user() {
return this.user;
}
@Deprecated
public UserConnection getUser() {
return user;
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.connection;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -99,14 +100,33 @@ public interface UserConnection {
void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker);
/**
* Clear stored objects and entity trackers.
* Returns the client world by the given protocol class if present.
*
* @param protocolClass protocol class
* @param <T> client world type
* @return client world if present
*/
@Nullable
<T extends ClientWorld> T getClientWorld(Class<? extends Protocol> protocolClass);
/**
* Adds a client world to the user connection.
* Does not override existing client worlds.
*
* @param protocolClass protocol class
* @param clientWorld client world
*/
void addClientWorld(Class<? extends Protocol> protocolClass, ClientWorld clientWorld);
/**
* Clear stored objects, entity trackers and client worlds.
*/
default void clearStoredObjects() {
clearStoredObjects(false);
}
/**
* Clear stored objects and entity trackers.
* Clear stored objects, entity trackers and client worlds.
* If cleared for a proxy server switch, some stored objects and tracker data will be retained.
*
* @param isServerSwitch whether the clear is due to a server switch
@@ -83,6 +83,10 @@ public interface MappingData {
int getNewAttributeId(int id);
int getNewSoundId(int id);
int getOldSoundId(int i);
/**
* Returns a list of tags to send if present.
*
@@ -46,6 +46,7 @@ public class MappingDataBase implements MappingData {
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected BiMappings attributeMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
@@ -53,7 +54,6 @@ public class MappingDataBase implements MappingData {
protected Mappings enchantmentMappings;
protected Mappings paintingMappings;
protected Mappings menuMappings;
protected Mappings attributeMappings;
protected Map<RegistryType, List<TagData>> tags;
public MappingDataBase(final String unmappedVersion, final String mappedVersion) {
@@ -76,7 +76,7 @@ public class MappingDataBase implements MappingData {
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
paintingMappings = loadMappings(data, "paintings");
attributeMappings = loadMappings(data, "attributes");
attributeMappings = loadBiMappings(data, "attributes");
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
@@ -203,6 +203,16 @@ public class MappingDataBase implements MappingData {
return checkValidity(id, attributeMappings.getNewId(id), "attributes");
}
@Override
public int getNewSoundId(final int id) {
return checkValidity(id, soundMappings.getNewId(id), "sound");
}
@Override
public int getOldSoundId(final int i) {
return soundMappings.getNewIdOrDefault(i, 0);
}
@Override
public @Nullable List<TagData> getTags(final RegistryType type) {
return tags != null ? tags.get(type) : null;
@@ -315,4 +325,4 @@ public class MappingDataBase implements MappingData {
protected void loadExtras(final CompoundTag data) {
}
}
}
@@ -30,7 +30,6 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.viaversion.nbt.io.NBTIO;
import com.viaversion.nbt.io.TagReader;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
@@ -211,68 +210,64 @@ public class MappingDataLoader {
return null;
}
final ByteTag serializationStragetyTag = tag.getUnchecked("id");
final IntTag mappedSizeTag = tag.getUnchecked("mappedSize");
final byte strategy = serializationStragetyTag.asByte();
final int mappedSize = tag.getIntTag("mappedSize").asInt();
final byte strategy = tag.getByteTag("id").asByte();
final V mappings;
if (strategy == DIRECT_ID) {
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
return IntArrayMappings.of(valuesTag.getValue(), mappedSizeTag.asInt());
return IntArrayMappings.of(valuesTag.getValue(), mappedSize);
} else if (strategy == SHIFTS_ID) {
final IntArrayTag shiftsAtTag = tag.getIntArrayTag("at");
final IntArrayTag shiftsTag = tag.getIntArrayTag("to");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] shiftsAt = shiftsAtTag.getValue();
final int[] shiftsTo = shiftsTag.getValue();
final int size = sizeTag.asInt();
final int[] shiftsAt = tag.getIntArrayTag("at").getValue();
final int[] shiftsTo = tag.getIntArrayTag("to").getValue();
final int size = tag.getIntTag("size").asInt();
mappings = holderSupplier.get(size);
// Handle values until first shift
if (shiftsAt[0] != 0) {
// Add identity values before the first shift
final int to = shiftsAt[0];
for (int id = 0; id < to; id++) {
addConsumer.addTo(mappings, id, id);
}
}
// Handle shifts
// Read shifts
for (int i = 0; i < shiftsAt.length; i++) {
final boolean isLast = i == shiftsAt.length - 1;
final int from = shiftsAt[i];
final int to = i == shiftsAt.length - 1 ? size : shiftsAt[i + 1];
final int to = isLast ? size : shiftsAt[i + 1];
int mappedId = shiftsTo[i];
for (int id = from; id < to; id++) {
addConsumer.addTo(mappings, id, mappedId++);
}
}
} else if (strategy == CHANGES_ID) {
final IntArrayTag changesAtTag = tag.getIntArrayTag("at");
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] changesAt = tag.getIntArrayTag("at").getValue();
final int[] values = tag.getIntArrayTag("val").getValue();
final int size = tag.getIntTag("size").asInt();
final boolean fillBetween = tag.get("nofill") == null;
final int[] changesAt = changesAtTag.getValue();
final int[] values = valuesTag.getValue();
mappings = holderSupplier.get(sizeTag.asInt());
mappings = holderSupplier.get(size);
int nextUnhandledId = 0;
for (int i = 0; i < changesAt.length; i++) {
final int id = changesAt[i];
final int changedId = changesAt[i];
if (fillBetween) {
// Fill from after the last change to before this change with unchanged ids
final int previousId = i != 0 ? changesAt[i - 1] + 1 : 0;
for (int identity = previousId; identity < id; identity++) {
addConsumer.addTo(mappings, identity, identity);
for (int id = nextUnhandledId; id < changedId; id++) {
addConsumer.addTo(mappings, id, id);
}
nextUnhandledId = changedId + 1;
}
// Assign the changed value
addConsumer.addTo(mappings, id, values[i]);
addConsumer.addTo(mappings, changedId, values[i]);
}
} else if (strategy == IDENTITY_ID) {
final IntTag sizeTag = tag.getUnchecked("size");
return new IdentityMappings(sizeTag.asInt(), mappedSizeTag.asInt());
final IntTag sizeTag = tag.getIntTag("size");
return new IdentityMappings(sizeTag.asInt(), mappedSize);
} else {
throw new IllegalArgumentException("Unknown serialization strategy: " + strategy);
}
return mappingsSupplier.create(mappings, mappedSizeTag.asInt());
return mappingsSupplier.create(mappings, mappedSize);
}
public @Nullable List<String> identifiersFromGlobalIds(final CompoundTag mappingsTag, final String key) {
@@ -295,7 +290,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> indexedObjectToMap(final JsonObject object) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size());
map.defaultReturnValue(-1);
for (final Map.Entry<String, JsonElement> entry : object.entrySet()) {
map.put(entry.getValue().getAsString(), Integer.parseInt(entry.getKey()));
@@ -310,7 +305,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> arrayToMap(final JsonArray array) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size());
map.defaultReturnValue(-1);
for (int i = 0; i < array.size(); i++) {
map.put(array.get(i).getAsString(), i);
@@ -78,7 +78,7 @@ public interface EntityTracker {
void removeEntity(int id);
/**
* Clears stored entity types and data.
* Clears stored entity types and data, only leaving behind the client entity.
*/
void clearEntities();
@@ -102,11 +102,19 @@ public interface EntityTracker {
@Nullable StoredEntityData entityDataIfPresent(int id);
/**
* Returns the client entity id or -1 if unset.
* Returns whether the client entity id has been set.
*
* @return client entity id or -1 if unset
* @return whether the client entity id has been set
*/
int clientEntityId();
boolean hasClientEntityId();
/**
* Returns the client entity id. Should be wrapped around {@link #hasClientEntityId()}.
*
* @return client entity id
* @throws IllegalStateException if the client entity id has not been set
*/
int clientEntityId() throws IllegalStateException;
/**
* Sets the client entity id.
@@ -169,12 +177,4 @@ public interface EntityTracker {
@Nullable DimensionData dimensionData(int dimensionId);
void setDimensions(Map<String, DimensionData> dimensions);
/**
* Adds the client player entity to the tracker.
* If the client entity has not been set yet, this will return false.
*
* @return whether the client has been tracked
*/
boolean trackClientEntity();
}
@@ -23,13 +23,12 @@
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.connection.StorableObject;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Stored up until 1.14 to be used in chunk sending.
*/
public class ClientWorld implements StorableObject {
private Environment environment;
private Environment environment = Environment.NORMAL;
public ClientWorld() {
}
@@ -38,11 +37,20 @@ public class ClientWorld implements StorableObject {
this.environment = environment;
}
public @Nullable Environment getEnvironment() {
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(final int environmentId) {
/**
* Sets the environment of the world and returns whether the environment was changed.
*
* @param environmentId the id of the environment to set
* @return whether the environment was changed
*/
public boolean setEnvironment(final int environmentId) {
final int previousEnvironmentId = environment.id();
this.environment = Environment.getEnvironmentById(environmentId);
return previousEnvironmentId != environmentId;
}
}
@@ -22,6 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public interface Holder<T> {
/**
@@ -79,4 +81,12 @@ public interface Holder<T> {
* @see #hasId()
*/
int id();
/**
* Returns a new holder with the id rewritten using the given function, or self if this is a direct holder or the id did not change.
*
* @param rewriteFunction the function to rewrite the id
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(final Int2IntFunction rewriteFunction);
}
@@ -23,6 +23,7 @@
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> {
@@ -61,6 +62,22 @@ final class HolderImpl<T> implements Holder<T> {
return id;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
if (isDirect()) {
return this;
}
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
}
if (rewrittenId == -1) {
throw new IllegalArgumentException("Received invalid id in updateId");
}
return Holder.of(rewrittenId);
}
@Override
public String toString() {
return "HolderImpl{" +
@@ -64,7 +64,7 @@ final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.apply(ids[i]);
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new HolderSetImpl(mappedIds);
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.IdHolder;
@@ -72,6 +73,14 @@ public final class Particle implements IdHolder {
arguments.set(index, new ParticleData<>(type, value));
}
public Particle copy() {
final Particle particle = new Particle(id);
for (ParticleData<?> argument : arguments) {
particle.arguments.add(argument.copy());
}
return particle;
}
@Override
public String toString() {
return "Particle{" +
@@ -109,6 +118,14 @@ public final class Particle implements IdHolder {
wrapper.write(type, value);
}
public ParticleData<T> copy() {
if (value instanceof Item item) {
return new ParticleData<>(type, (T) item.copy());
} else {
return new ParticleData<>(type, value);
}
}
@Override
public String toString() {
return "ParticleData{" +
@@ -52,16 +52,14 @@ public interface StructuredData<T> extends IdHolder {
return new EmptyStructuredData<>(key, id);
}
void setValue(final T value);
@Nullable T value();
void write(final ByteBuf buffer);
void setValue(final T value);
void setId(final int id);
StructuredDataKey<T> key();
@Nullable T value();
/**
* Returns whether the structured data is present. Even if true, the value may be null.
*
@@ -77,4 +75,6 @@ public interface StructuredData<T> extends IdHolder {
* @return true if the structured data is empty
*/
boolean isEmpty();
void write(final ByteBuf buffer);
}
@@ -33,6 +33,26 @@ import java.util.Map;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Loosely represents Minecraft's data component patch, but may also be used for an item's full data components.
* <p>
* The most commonly used methods will ignore empty data (aka empty overrides that remove item defaults) since those will rarely be needed.
* These are:
* <ul>
* <li>{@link #get(StructuredDataKey)}</li>
* <li>{@link #set(StructuredDataKey, Object)}</li>
* <li>{@link #set(StructuredDataKey)}</li>
* <li>{@link #getNonEmptyData(StructuredDataKey)}</li>
* <li>{@link #hasValue(StructuredDataKey)}</li>
* </ul>
*
* To interact with empty patches specifically, use:
* <ul>
* <li>{@link #setEmpty(StructuredDataKey)}</li>
* <li>{@link #hasEmpty(StructuredDataKey)}</li>
* </ul>
* Other methods (e.g. {@link #getData(StructuredDataKey)} and {@link #has(StructuredDataKey)}) will handle both empty and non-empty data.
*/
public final class StructuredDataContainer {
private final Map<StructuredDataKey<?>, StructuredData<?>> data;
@@ -55,66 +75,45 @@ public final class StructuredDataContainer {
}
/**
* Returns structured data by id if present.
* Returns the non-empty value by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data
* @see #hasEmpty(StructuredDataKey)
*/
public @Nullable <T> T get(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
if (data == null || data.isEmpty()) {
return null;
}
//noinspection unchecked
return ((StructuredData<T>) data).value();
}
/**
* Returns structured data by id if present, either empty or non-empty.
*
* @param key serializer id
* @param <T> data type
* @return structured data
*/
public @Nullable <T> StructuredData<T> get(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getData(final StructuredDataKey<T> key) {
//noinspection unchecked
return (StructuredData<T>) this.data.get(key);
}
/**
* Returns structured data by id if not empty.
* Returns non-empty structured data by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data if not empty
* @return non-empty structured data
*/
public @Nullable <T> StructuredData<T> getNonEmpty(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getNonEmptyData(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
//noinspection unchecked
final StructuredData<T> data = (StructuredData<T>) this.data.get(key);
return data != null && data.isPresent() ? data : null;
}
/**
* Returns structured data by id if not empty, or creates it.
*
* @param key serializer id
* @param mappingFunction function to create structured data if not present
* @param <T> data type
* @return structured data if not empty
*/
public <T> StructuredData<T> computeIfAbsent(final StructuredDataKey<T> key, final Function<StructuredDataKey<T>, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data != null) {
return data;
}
final int id = serializerId(key);
final StructuredData<T> empty = StructuredData.of(key, mappingFunction.apply(key), id);
this.data.put(key, empty);
return empty;
}
/**
* Updates and returns the structured data by id if not empty.
*
* @param key serializer id
* @param mappingFunction function to update existing data
* @param <T> data type
* @return updated structured data if not empty
*/
public <T> @Nullable StructuredData<T> updateIfPresent(final StructuredDataKey<T> key, final Function<T, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data == null) {
return null;
}
data.setValue(mappingFunction.apply(data.value()));
return data;
return data != null && data.isPresent() ? (StructuredData<T>) data : null;
}
public <T> void set(final StructuredDataKey<T> key, final T value) {
@@ -124,49 +123,105 @@ public final class StructuredDataContainer {
}
}
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, V> valueMapper) {
final StructuredData<T> data = remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
set(toKey, valueMapper.apply(data.value()));
} else {
addEmpty(toKey);
}
}
public void set(final StructuredDataKey<Unit> key) {
this.set(key, Unit.INSTANCE);
}
public void addEmpty(final StructuredDataKey<?> key) {
public void setEmpty(final StructuredDataKey<?> key) {
// Empty optional to override the Minecraft default
this.data.put(key, StructuredData.empty(key, serializerId(key)));
}
/**
* Removes and returns structured data by the given key.
* Updates the structured data by id if not empty.
*
* @param key serializer key
* @param <T> data type
* @return removed structured data
* @param key serializer id
* @param valueMapper function to update existing data
* @param <T> data type
*/
public @Nullable <T> StructuredData<T> remove(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.remove(key);
//noinspection unchecked
return data != null ? (StructuredData<T>) data : null;
public <T> void replace(final StructuredDataKey<T> key, final Function<T, @Nullable T> valueMapper) {
final StructuredData<T> data = this.getNonEmptyData(key);
if (data == null) {
return;
}
final T replacement = valueMapper.apply(data.value());
if (replacement != null) {
data.setValue(replacement);
} else {
this.data.remove(key);
}
}
public boolean contains(final StructuredDataKey<?> key) {
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, @Nullable V> valueMapper) {
final StructuredData<?> data = this.data.remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
//noinspection unchecked
final T value = (T) data.value();
final V replacement = valueMapper.apply(value);
if (replacement != null) {
set(toKey, replacement);
}
} else {
// Also replace the key for empty data
setEmpty(toKey);
}
}
/**
* Removes data by the given key.
*
* @param key data key
* @see #replace(StructuredDataKey, Function)
* @see #replace(StructuredDataKey, StructuredDataKey, Function)
* @see #replaceKey(StructuredDataKey, StructuredDataKey)
*/
public void remove(final StructuredDataKey<?> key) {
this.data.remove(key);
}
/**
* Returns whether there is data for the given key, either empty or non-empty.
*
* @param key data key
* @return whether there data for the given key
* @see #hasEmpty(StructuredDataKey)
* @see #hasValue(StructuredDataKey)
*/
public boolean has(final StructuredDataKey<?> key) {
return this.data.containsKey(key);
}
/**
* Returns whether there is non-empty data for the given key.
*
* @param key data key
* @return whether there is non-empty data for the given key
*/
public boolean hasValue(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isPresent();
}
/**
* Returns whether the structured data has an empty patch/override.
*
* @param key serializer id
* @return whether the structured data has an empty patch/override
*/
public boolean hasEmpty(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isEmpty();
}
/**
* Sets the lookup for serializer ids. Required to call most of the other methods.
*
@@ -212,6 +267,8 @@ public final class StructuredDataContainer {
public String toString() {
return "StructuredDataContainer{" +
"data=" + data +
", lookup=" + lookup +
", mappedNames=" + mappedNames +
'}';
}
}
@@ -101,7 +101,7 @@ public class EntityTypes1_12 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(LIVING_ENTITY_BASE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_14 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_15 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
@@ -51,11 +51,12 @@ public enum EntityTypes1_16 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -51,11 +51,12 @@ public enum EntityTypes1_16_2 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -53,11 +53,12 @@ public enum EntityTypes1_17 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -53,11 +53,12 @@ public enum EntityTypes1_19 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -53,11 +53,12 @@ public enum EntityTypes1_19_3 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -59,11 +59,12 @@ public enum EntityTypes1_19_4 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -59,11 +59,12 @@ public enum EntityTypes1_20_3 implements EntityType {
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -59,12 +59,13 @@ public enum EntityTypes1_20_5 implements EntityType {
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
SNOWBALL(PROJECTILE),
ENDER_PEARL(PROJECTILE),
EGG(PROJECTILE),
POTION(PROJECTILE),
EXPERIENCE_BOTTLE(PROJECTILE),
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),
@@ -93,7 +93,7 @@ public class EntityTypes1_8 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and metadata indexing
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and entity data indexing
// Living entities as a larger subclass
LIVING_ENTITY(48, LIVING_ENTITY_BASE),
@@ -99,7 +99,7 @@ public class EntityTypes1_9 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(48, LIVING_ENTITY_BASE),
@@ -28,21 +28,21 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityData {
private int id;
private EntityDataType metaType;
private EntityDataType dataType;
private Object value;
/**
* Creates a new metadata instance.
* Creates a new entity data instance.
*
* @param id metadata index
* @param metaType metadata type
* @param id data index
* @param dataType data type
* @param value value if present
* @throws IllegalArgumentException if the value and metaType are incompatible
* @throws IllegalArgumentException if the value and dataType are incompatible
*/
public EntityData(int id, EntityDataType metaType, @Nullable Object value) {
public EntityData(int id, EntityDataType dataType, @Nullable Object value) {
this.id = id;
this.metaType = metaType;
this.value = checkValue(metaType, value);
this.dataType = dataType;
this.value = checkValue(dataType, value);
}
public int id() {
@@ -54,19 +54,19 @@ public final class EntityData {
}
public EntityDataType dataType() {
return metaType;
return dataType;
}
/**
* Sets the metadata type if compatible with the current value.
* Sets the entity data type if compatible with the current value.
*
* @param metaType metadata type
* @throws IllegalArgumentException if the metadata type and current value are incompatible
* @param dataType entity data type
* @throws IllegalArgumentException if the entity data type and current value are incompatible
* @see #setTypeAndValue(EntityDataType, Object)
*/
public void setDataType(EntityDataType metaType) {
checkValue(metaType, this.value);
this.metaType = metaType;
public void setDataType(EntityDataType dataType) {
checkValue(dataType, this.value);
this.dataType = dataType;
}
public @Nullable <T> T value() {
@@ -78,32 +78,32 @@ public final class EntityData {
}
/**
* Sets the metadata value if compatible with the current meta type.
* Sets the entity data value if compatible with the current data type.
*
* @param value value
* @throws IllegalArgumentException if the value and current metaType are incompatible
* @throws IllegalArgumentException if the value and current dataType are incompatible
* @see #setTypeAndValue(EntityDataType, Object)
*/
public void setValue(@Nullable Object value) {
this.value = checkValue(this.metaType, value);
this.value = checkValue(this.dataType, value);
}
/**
* Sets metadata type and value.
* Sets entity data type and value.
*
* @param metaType metadata type
* @param dataType entity data type
* @param value value
* @throws IllegalArgumentException if the value and metaType are incompatible
* @throws IllegalArgumentException if the value and dataType are incompatible
*/
public void setTypeAndValue(EntityDataType metaType, @Nullable Object value) {
this.value = checkValue(metaType, value);
this.metaType = metaType;
public void setTypeAndValue(EntityDataType dataType, @Nullable Object value) {
this.value = checkValue(dataType, value);
this.dataType = dataType;
}
private Object checkValue(EntityDataType metaType, @Nullable Object value) {
Preconditions.checkNotNull(metaType);
if (value != null && !metaType.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Metadata value and metaType are incompatible. Type=" + metaType
private Object checkValue(EntityDataType dataType, @Nullable Object value) {
Preconditions.checkNotNull(dataType);
if (value != null && !dataType.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Entity data value and dataType are incompatible. Type=" + dataType
+ ", value=" + value + " (" + value.getClass().getSimpleName() + ")");
}
return value;
@@ -111,32 +111,32 @@ public final class EntityData {
@Deprecated
public void setDataTypeUnsafe(EntityDataType type) {
this.metaType = type;
this.dataType = type;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EntityData metadata = (EntityData) o;
if (id != metadata.id) return false;
if (metaType != metadata.metaType) return false;
return Objects.equals(value, metadata.value);
EntityData entityData = (EntityData) o;
if (id != entityData.id) return false;
if (dataType != entityData.dataType) return false;
return Objects.equals(value, entityData.value);
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + metaType.hashCode();
result = 31 * result + dataType.hashCode();
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Metadata{" +
return "EntityData{" +
"id=" + id +
", metaType=" + metaType +
", dataType=" + dataType +
", value=" + value +
'}';
}
@@ -35,7 +35,7 @@ public interface EntityDataType {
Type type();
/**
* Get type id from the specific MetaDataType
* Get type id from the specific EntityDataType
*
* @return Type id as an integer
*/
@@ -67,7 +67,7 @@ public interface EntityDataType {
@Override
public String toString() {
return "EntityDataType{" +
return "EntityDataTypeImpl{" +
"typeId=" + typeId +
", type=" + type +
'}';
@@ -77,9 +77,9 @@ public interface EntityDataType {
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final EntityDataTypeImpl metaType = (EntityDataTypeImpl) o;
if (typeId != metaType.typeId) return false;
return type.equals(metaType.type);
final EntityDataTypeImpl dataType = (EntityDataTypeImpl) o;
if (typeId != dataType.typeId) return false;
return type.equals(dataType.type);
}
@Override
@@ -44,8 +44,8 @@ public abstract class AbstractEntityDataTypes implements EntityDataTypes {
}
protected EntityDataType add(final int typeId, final Type<?> type) {
final EntityDataType metaType = EntityDataType.create(typeId, type);
values[typeId] = metaType;
return metaType;
final EntityDataType dataType = EntityDataType.create(typeId, type);
values[typeId] = dataType;
return dataType;
}
}
@@ -27,18 +27,18 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
public interface EntityDataTypes {
/**
* Returns the meta type by the given id.
* Returns the data type by the given id.
*
* @param id type id
* @return meta type by id
* @return data type by id
* @throws IndexOutOfBoundsException if id is out of bounds
*/
EntityDataType byId(int id);
/**
* Returns an array of meta types.
* Returns an array of data types.
*
* @return array of meta types
* @return array of data types
*/
EntityDataType[] values();
}
@@ -124,11 +124,11 @@ public class DataItem implements Item {
@Override
public String toString() {
return "Item{" +
return "DataItem{" +
"identifier=" + identifier +
", amount=" + amount +
", data=" + data +
", tag=" + tag +
'}';
}
}
}
@@ -26,6 +26,7 @@ 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;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) {
@@ -44,6 +45,15 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
}
};
public AttributeModifiers1_21 rewrite(final Int2IntFunction rewriteFunction) {
final AttributeModifier[] modifiers = new AttributeModifier[this.modifiers.length];
for (int i = 0; i < this.modifiers.length; i++) {
final AttributeModifier modifier = this.modifiers[i];
modifiers[i] = new AttributeModifier(rewriteFunction.applyAsInt(modifier.attribute()), modifier.modifier(), modifier.slotType());
}
return new AttributeModifiers1_21(modifiers, showInTooltip);
}
public record AttributeModifier(int attribute, ModifierData modifier, int slotType) {
public static final Type<AttributeModifier> TYPE = new Type<>(AttributeModifier.class) {
@@ -27,6 +27,7 @@ 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 Instrument(Holder<SoundEvent> soundEvent, int useDuration, float range) {
@@ -47,4 +48,8 @@ public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float r
}
};
public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range);
}
}
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Either;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean showInTooltip) {
@@ -56,6 +57,20 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
}
};
public JukeboxPlayable rewrite(final Int2IntFunction soundIdRewriteFunction) {
if (song.isRight()) {
return this;
}
final Holder<JukeboxSong> songHolder = this.song.left();
if (songHolder.hasId()) {
return this;
}
final JukeboxSong rewrittenSong = songHolder.value().rewrite(soundIdRewriteFunction);
return rewrittenSong == songHolder.value() ? this : new JukeboxPlayable(Holder.of(rewrittenSong), showInTooltip);
}
public record JukeboxSong(Holder<SoundEvent> soundEvent, Tag description,
float lengthInSeconds, int comparatorOutput) {
@@ -77,5 +92,10 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
Types.VAR_INT.writePrimitive(buffer, value.comparatorOutput);
}
};
public JukeboxSong rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}
}
}
@@ -1,56 +0,0 @@
/*
* 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 it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Map;
public record MapDecorations(Map<String, MapDecoration> decorations) {
public static final Type<MapDecorations> TYPE = new Type<>(MapDecorations.class) {
@Override
public MapDecorations read(final ByteBuf buffer) {
final Object2ObjectMap<String, MapDecoration> decorations = new Object2ObjectOpenHashMap<>();
final int size = Types.VAR_INT.readPrimitive(buffer);
for (int i = 0; i < size; i++) {
final String id = Types.STRING.read(buffer);
final MapDecoration decoration = MapDecoration.TYPE.read(buffer);
decorations.put(id, decoration);
}
return new MapDecorations(decorations);
}
@Override
public void write(final ByteBuf buffer, final MapDecorations value) {
Types.VAR_INT.writePrimitive(buffer, value.decorations.size());
for (final Map.Entry<String, MapDecoration> entry : value.decorations.entrySet()) {
Types.STRING.write(buffer, entry.getKey());
MapDecoration.TYPE.write(buffer, entry.getValue());
}
}
};
}
@@ -215,4 +215,13 @@ public interface ViaPlatform<T> {
* @return whether the platform has a plugin/mod with the given name
*/
boolean hasPlugin(String name);
/**
* Returns whether the platform might be reloading.
*
* @return whether the platform might be reloading
*/
default boolean couldBeReloading() {
return true;
}
}
@@ -30,4 +30,9 @@ public interface ViaServerProxyPlatform<T> extends ViaPlatform<T> {
* @return protocol detector service
*/
ProtocolDetectorService protocolDetectorService();
@Override
default boolean couldBeReloading() {
return false;
}
}
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.protocol;
import com.google.common.collect.Range;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
@@ -73,13 +74,14 @@ public interface ProtocolManager {
Protocol getBaseProtocol();
/**
* Returns the base protocol for a specific server protocol version.
* Returns the base protocols for a specific server and client protocol version.
* The standard base protocols deal with status and login packets for userconnection initialization.
*
* @param clientVersion client protocol version
* @param serverVersion server protocol version
* @return base protocol for the given server protocol version if present, else null
* @return base protocols for the given server and client protocol version
*/
@Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion);
List<Protocol> getBaseProtocols(@Nullable ProtocolVersion clientVersion, @Nullable ProtocolVersion serverVersion);
/**
* Returns an immutable collection of registered protocols.
@@ -120,11 +122,12 @@ public interface ProtocolManager {
* Registers and initializes a base protocol. Base Protocols registered later have higher priority.
* Only base protocol will always be added to pipeline.
*
* @param direction direction of the base protocol
* @param baseProtocol base protocol to register
* @param supportedProtocols protocol versions supported by the base protocol
* @throws IllegalArgumentException if the protocol is not a base protocol as given by {@link Protocol#isBaseProtocol()}
*/
void registerBaseProtocol(Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols);
void registerBaseProtocol(Direction direction, Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols);
/**
* Calculates and returns the protocol path from a client protocol version to server protocol version.
@@ -145,6 +145,18 @@ public interface PacketWrapper {
*/
<T> T passthrough(Type<T> type) throws InformativeException;
/**
* Take a value from the input and write to the output, mapping the output type.
* This only works for types implementing {@link com.viaversion.viaversion.api.type.TypeConverter}, which is generally only the primitive wrapper types.
*
* @param type The type to read.
* @param mappedType The type to write.
* @param <T> The return type of the type you wish to pass through.
* @return The type which was read/written.
* @throws InformativeException If it failed to read or write
*/
<T> T passthroughAndMap(Type<?> type, Type<T> mappedType) throws InformativeException;
/**
* Take all the inputs and write them to the output.
*
@@ -224,6 +236,14 @@ public interface PacketWrapper {
*/
void sendRaw() throws InformativeException;
/**
* Sends this packet to the associated user, submitted to netty's event loop.
* <b>Unlike {@link #sendFuture(Class)}, this method does not handle the pipeline with packet id and data changes.</b>
*
* @throws InformativeException if it fails to write
*/
ChannelFuture sendFutureRaw() throws InformativeException;
/**
* Sends this packet to the associated user, submitted to netty's event loop.
* <b>Unlike {@link #send(Class)}, this method does not handle the pipeline with packet id and data changes.</b>
@@ -54,7 +54,7 @@ public abstract class PacketHandlers implements PacketHandler {
* @param type type to map
*/
public <T> void map(Type<T> type) {
handler(wrapper -> wrapper.write(type, wrapper.read(type)));
handler(wrapper -> wrapper.passthrough(type));
}
/**
@@ -63,8 +63,8 @@ public abstract class PacketHandlers implements PacketHandler {
* @param oldType old type
* @param newType new type
*/
public void map(Type oldType, Type newType) {
handler(wrapper -> wrapper.write(newType, wrapper.read(oldType)));
public void map(Type<?> oldType, Type<?> newType) {
handler(wrapper -> wrapper.passthroughAndMap(oldType, newType));
}
/**
@@ -84,7 +84,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_20_2 = register(764, "1.20.2");
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");
public static final ProtocolVersion v1_21 = register(767, "1.21-1.21.1", new SubVersionRange("1.21", 0, 1));
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
public static ProtocolVersion register(int version, String name) {
@@ -28,6 +28,31 @@ import com.viaversion.viaversion.api.platform.providers.Provider;
@FunctionalInterface
public interface VersionProvider extends Provider {
/**
* Optionally allows platforms to specify the client version of a user. This is needed when the platform supports
* connecting other version types then {@link VersionType#RELEASE} to the server.
*
* @param connection connection
* @return client protocol version, or null if handshake packet should be used
*/
default ProtocolVersion getClientProtocol(UserConnection connection) {
return null;
}
/**
* Calls {@link #getClosestServerProtocol(UserConnection)} and catches any exceptions by returning null.
*
* @param connection connection
* @return closest server protocol version to the user's protocol version
*/
default ProtocolVersion getServerProtocol(UserConnection connection) {
try {
return getClosestServerProtocol(connection);
} catch (Exception e) {
return null;
}
}
/**
* Returns the closest server protocol version to the user's protocol version.
* On non-proxy servers, this returns the actual server version.
@@ -59,13 +59,13 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
int newEntityId(int id);
/**
* Handles and transforms metadata of an entity.
* Handles and transforms entity data of an entity.
*
* @param entityId entity id
* @param metadataList full, mutable list of metadata
* @param dataList full, mutable list of entity data
* @param connection user connection
*/
void handleEntityData(int entityId, List<EntityData> metadataList, UserConnection connection);
void handleEntityData(int entityId, List<EntityData> dataList, UserConnection connection);
/**
* Returns the entity tracker for the current protocol.
@@ -44,7 +44,9 @@ public class ComponentType extends Type<JsonElement> {
try {
return JsonParser.parseString(s);
} catch (JsonSyntaxException e) {
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
}
throw e;
}
}
@@ -40,20 +40,20 @@ public final class EntityDataListType extends EntityDataListTypeTemplate {
@Override
public List<EntityData> read(final ByteBuf buffer) {
final List<EntityData> list = new ArrayList<>();
EntityData meta;
EntityData data;
do {
meta = this.type.read(buffer);
if (meta != null) {
list.add(meta);
data = this.type.read(buffer);
if (data != null) {
list.add(data);
}
} while (meta != null);
} while (data != null);
return list;
}
@Override
public void write(final ByteBuf buffer, final List<EntityData> object) {
for (final EntityData metadata : object) {
this.type.write(buffer, metadata);
for (final EntityData data : object) {
this.type.write(buffer, data);
}
this.type.write(buffer, null);
}
@@ -26,14 +26,14 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes;
public final class EntityDataType extends ModernEntityDataType {
private final EntityDataTypes metaTypes;
private final EntityDataTypes dataTypes;
public EntityDataType(final EntityDataTypes metaTypes) {
this.metaTypes = metaTypes;
public EntityDataType(final EntityDataTypes dataTypes) {
this.dataTypes = dataTypes;
}
@Override
protected com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType getType(final int index) {
return metaTypes.byId(index);
return dataTypes.byId(index);
}
}
@@ -33,7 +33,7 @@ public abstract class ModernEntityDataType extends EntityDataTypeTemplate {
@Override
public EntityData read(final ByteBuf buffer) {
final short index = buffer.readUnsignedByte();
if (index == END) return null; // End of metadata
if (index == END) return null; // End of data
final EntityDataType type = this.getType(Types.VAR_INT.readPrimitive(buffer));
return new EntityData(index, type, type.type().read(buffer));
}
@@ -32,7 +32,7 @@ public abstract class OldEntityDataType extends EntityDataTypeTemplate {
@Override
public EntityData read(final ByteBuf buffer) {
final byte index = buffer.readByte();
if (index == END) return null; // End of metadata
if (index == END) return null; // End of data
final EntityDataType type = this.getType((index & 224) >> 5);
return new EntityData(index & 31, type, type.type().read(buffer));
}
@@ -50,7 +50,7 @@ public class StructuredDataType extends Type<StructuredData<?>> {
public StructuredData<?> read(final ByteBuf buffer) {
Preconditions.checkNotNull(types, "StructuredDataType has not been initialized");
final int id = Types.VAR_INT.readPrimitive(buffer);
final StructuredDataKey<?> key = this.types[id];
final StructuredDataKey<?> key = key(id);
if (key == null) {
throw new IllegalArgumentException("No data component serializer found for id " + id);
}
@@ -31,11 +31,11 @@ import java.util.List;
public final class Types1_12 {
/**
* Metadata type for 1.12
* Entity data type for 1.12
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_12();
/**
* Metadata list type for 1.12
* Entity data list type for 1.12
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -33,11 +33,11 @@ import java.util.List;
public final class Types1_8 {
/**
* Metadata type for 1.8
* Entity data type for 1.8
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_8();
/**
* Metadata list type for 1.8
* Entity data list type for 1.8
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
@@ -32,11 +32,11 @@ import java.util.List;
public final class Types1_9 {
/**
* Metadata type for 1.9
* Entity data type for 1.9
*/
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_9();
/**
* Metadata list type for 1.9
* Entity data list type for 1.9
*/
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
+1 -1
View File
@@ -8,5 +8,5 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.0")
}
@@ -5,7 +5,7 @@ plugins {
tasks {
// Variable replacements
processResources {
filesMatching(listOf("plugin.yml", "fabric.mod.json")) {
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand("version" to project.version, "description" to project.description, "url" to "https://viaversion.com")
}
}
@@ -4,7 +4,7 @@ import org.gradle.jvm.tasks.Jar
plugins {
id("via.base-conventions")
id("maven-publish")
id("com.github.johnrengelman.shadow")
id("com.gradleup.shadow")
}
tasks {
@@ -45,6 +45,7 @@ fun ShadowJar.configureRelocations() {
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs")
relocate("org.yaml.snakeyaml", "com.viaversion.viaversion.libs.snakeyaml")
}
fun ShadowJar.configureExcludes() {
+1 -1
View File
@@ -6,7 +6,7 @@ plugins {
allprojects {
group = "com.viaversion"
version = property("projectVersion") as String // from gradle.properties
description = "Allow newer clients to join older server versions."
description = "Allows the connection of newer clients to older server versions for Minecraft servers."
}
val main = setOf(
@@ -15,7 +15,7 @@
* 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.protocol1_9to1_8;
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -117,4 +117,4 @@ public class ArmorListener extends ViaBukkitListener {
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
Via.getPlatform().runSync(() -> sendArmorUpdate(player));
}
}
}
@@ -15,7 +15,7 @@
* 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.protocol1_9to1_8;
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
@@ -15,7 +15,7 @@
* 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.protocol1_9to1_8;
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -15,7 +15,7 @@
* 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.protocol1_9to1_8;
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
@@ -15,7 +15,7 @@
* 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.protocol1_9to1_8;
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import com.viaversion.viaversion.bukkit.util.CollisionChecker;
@@ -268,6 +268,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
return getServer().getPluginManager().getPlugin(name) != null;
}
@Override
public boolean couldBeReloading() {
return !(PaperViaInjector.PAPER_IS_STOPPING_METHOD && Bukkit.isStopping());
}
public boolean isLateBind() {
return lateBind;
}
@@ -112,7 +112,10 @@ public class JoinListener implements Listener {
return;
}
// The connection has already closed, that was a quick leave
if (!channel.isOpen()) return;
// Channel may be null if a plugin is manually calling the event for a non-player...
if (channel == null || !channel.isOpen()) {
return;
}
UserConnection user = getUserConnection(channel);
if (user == null) {
@@ -51,13 +51,13 @@ public class EntityToggleGlideListener extends ViaBukkitListener {
if (!isOnPipe(player)) return;
// Cancelling can only be done by updating the player's metadata
// Cancelling can only be done by updating the player's entity data
if (event.isGliding() && event.isCancelled()) {
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_15.SET_ENTITY_DATA, null, getUserConnection(player));
packet.write(Types.VAR_INT, player.getEntityId());
byte bitmask = 0;
// Collect other metadata for the mitmask
// Collect other entity data for the mitmask
if (player.getFireTicks() > 0) {
bitmask |= 0x01;
}
@@ -0,0 +1,51 @@
/*
* 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 io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
public final class PaperPlayerChangeItemListener extends PlayerChangeItemListener {
public PaperPlayerChangeItemListener(final ViaVersionPlugin plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
final Player player = event.getPlayer();
final ItemStack item = event.getNewItemStack();
final PlayerInventory inventory = player.getInventory();
final int slot = event.getSlot();
if (slot == inventory.getHeldItemSlot()) {
sendAttributeUpdate(player, item, Slot.HAND);
} else if (slot == 36) {
sendAttributeUpdate(player, item, Slot.BOOTS);
} else if (slot == 37) {
sendAttributeUpdate(player, item, Slot.LEGGINGS);
} else if (slot == 39) {
sendAttributeUpdate(player, item, Slot.HELMET);
}
}
}
@@ -23,50 +23,31 @@ 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;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage;
import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* For some reason, mining efficiency is not calculated by the client anymore, but by the server,
* then sending the current value to the client every time the item changes. This roughly emulates that behavior.
*/
public final class PlayerChangeItemListener extends ViaBukkitListener {
public class PlayerChangeItemListener extends ViaBukkitListener {
private final Enchantment efficiency = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
private final Enchantment aquaAffinity = Enchantment.getByKey(NamespacedKey.minecraft("aqua_affinity"));
private final Enchantment depthStrider = Enchantment.getByKey(NamespacedKey.minecraft("depth_strider"));
private final Enchantment soulSpeed = Enchantment.getByKey(NamespacedKey.minecraft("soul_speed"));
private final Enchantment swiftSneak = Enchantment.getByKey(NamespacedKey.minecraft("swift_sneak"));
// 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");
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
super(plugin, Protocol1_20_5To1_21.class);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
final Player player = event.getPlayer();
final ItemStack item = event.getNewItemStack();
final PlayerInventory inventory = player.getInventory();
final int slot = event.getSlot();
if (slot == inventory.getHeldItemSlot()) {
sendAttributeUpdate(player, item, Slot.HAND);
} else if (slot == 36) {
sendAttributeUpdate(player, item, Slot.BOOTS);
} else if (slot == 37) {
sendAttributeUpdate(player, item, Slot.LEGGINGS);
} else if (slot == 39) {
sendAttributeUpdate(player, item, Slot.HELMET);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerItemHeld(final PlayerItemHeldEvent event) {
final Player player = event.getPlayer();
@@ -74,7 +55,7 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
sendAttributeUpdate(player, item, Slot.HAND);
}
private void sendAttributeUpdate(final Player player, @Nullable final ItemStack item, final Slot slot) {
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;
@@ -105,7 +86,15 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
storage.setEnchants(player.getEntityId(), connection, efficiencyLevel, soulSpeedLevel, swiftSneakLevel, aquaAffinityLevel, depthStriderLevel);
}
private enum Slot {
enum Slot {
HAND, BOOTS, LEGGINGS, HELMET
}
private Enchantment getByName(final String newName, final String oldName) {
final Enchantment enchantment = Enchantment.getByName(newName);
if (enchantment == null) {
return Enchantment.getByName(oldName);
}
return enchantment;
}
}
@@ -19,19 +19,20 @@ package com.viaversion.viaversion.bukkit.platform;
import com.viaversion.viaversion.configuration.AbstractViaConfig;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class BukkitViaConfig extends AbstractViaConfig {
private static final List<String> UNSUPPORTED = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
private boolean quickMoveActionFix;
private boolean hitboxFix1_9;
private boolean hitboxFix1_14;
private String blockConnectionMethod;
private boolean armorToggleFix;
private boolean registerUserConnectionOnJoin;
private boolean useNewDeathMessages;
private boolean itemCache;
private boolean nmsPlayerTicking;
public BukkitViaConfig(final File folder, final Logger logger) {
super(new File(folder, "config.yml"), logger);
@@ -46,6 +47,9 @@ public class BukkitViaConfig extends AbstractViaConfig {
hitboxFix1_14 = getBoolean("change-1_14-hitbox", false);
blockConnectionMethod = getString("blockconnection-method", "packet");
armorToggleFix = getBoolean("armor-toggle-fix", true);
useNewDeathMessages = getBoolean("use-new-deathmessages", true);
itemCache = getBoolean("item-cache", true);
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
}
@Override
@@ -82,8 +86,23 @@ public class BukkitViaConfig extends AbstractViaConfig {
return armorToggleFix;
}
@Override
public boolean isShowNewDeathMessages() {
return useNewDeathMessages;
}
@Override
public boolean isItemCache() {
return itemCache;
}
@Override
public boolean isNMSPlayerTicking() {
return nmsPlayerTicking;
}
@Override
public List<String> getUnsupportedOptions() {
return UNSUPPORTED;
return VELOCITY_ONLY_OPTIONS;
}
}
@@ -28,11 +28,12 @@ import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListen
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.protocol1_9to1_8.ArmorListener;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.BlockListener;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.DeathListener;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.HandItemCache;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.PaperPatch;
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;
@@ -87,7 +88,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_9)) {
new ArmorListener(plugin).register();
new DeathListener(plugin).register();
new BlockListener(plugin).register();
if (plugin.getConf().cancelBlockSounds()) {
new BlockListener(plugin).register();
}
if (plugin.getConf().isItemCache()) {
handItemCache = new HandItemCache();
@@ -177,8 +180,12 @@ public class BukkitViaLoader implements ViaPlatformLoader {
Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin));
new BlockBreakListener(plugin).register();
}
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21) && PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
new PlayerChangeItemListener(plugin).register();
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21)) {
if (PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
new PaperPlayerChangeItemListener(plugin).register();
} else {
new PlayerChangeItemListener(plugin).register();
}
}
}
@@ -28,6 +28,7 @@ public final class PaperViaInjector {
public static final boolean PAPER_INJECTION_METHOD = hasPaperInjectionMethod();
public static final boolean PAPER_PROTOCOL_METHOD = hasServerProtocolMethod();
public static final boolean PAPER_PACKET_LIMITER = hasPacketLimiter();
public static final boolean PAPER_IS_STOPPING_METHOD = hasIsStoppingMethod();
private PaperViaInjector() {
}
@@ -76,6 +77,15 @@ public final class PaperViaInjector {
return hasClass("io.papermc.paper.network.ChannelInitializeListener");
}
private static boolean hasIsStoppingMethod() {
try {
Bukkit.class.getDeclaredMethod("isStopping");
return true;
} catch (final NoSuchMethodException e) {
return false;
}
}
private static boolean hasPacketLimiter() {
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.configuration.GlobalConfiguration$PacketLimiter");
}
@@ -20,7 +20,7 @@ package com.viaversion.viaversion.bukkit.providers;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.bukkit.tasks.protocol1_19to1_18_2.AckSequenceTask;
import com.viaversion.viaversion.bukkit.tasks.v1_18_2to1_19.AckSequenceTask;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.storage.SequenceStorage;
@@ -45,4 +45,4 @@ public final class BukkitAckSequenceProvider extends AckSequenceProvider {
}
}
}
}
}
@@ -21,7 +21,7 @@ import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.bukkit.tasks.protocol1_12to1_11_1.BukkitInventoryUpdateTask;
import com.viaversion.viaversion.bukkit.tasks.v1_11_1to1_12.BukkitInventoryUpdateTask;
import com.viaversion.viaversion.bukkit.util.NMSUtil;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.provider.InventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.storage.ItemTransactionStorage;
@@ -201,4 +201,4 @@ public class BukkitInventoryQuickMoveProvider extends InventoryQuickMoveProvider
final ProtocolVersion protocol = Via.getAPI().getServerVersion().lowestSupportedProtocolVersion();
return protocol.newerThanOrEqualTo(ProtocolVersion.v1_8) && protocol.olderThanOrEqualTo(ProtocolVersion.v1_11_1);
}
}
}
@@ -15,7 +15,7 @@
* 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.tasks.protocol1_12to1_11_1;
package com.viaversion.viaversion.bukkit.tasks.v1_11_1to1_12;
import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.storage.ItemTransactionStorage;
@@ -65,4 +65,4 @@ public class BukkitInventoryUpdateTask implements Runnable {
provider.onTaskExecuted(uuid);
}
}
}
}
@@ -15,7 +15,7 @@
* 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.tasks.protocol1_19to1_18_2;
package com.viaversion.viaversion.bukkit.tasks.v1_18_2to1_19;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
+1 -3
View File
@@ -3,13 +3,11 @@ dependencies {
api(rootProject.libs.text) {
exclude("com.google.code.gson", "gson")
}
implementation(projects.compat.snakeyaml2Compat)
implementation(projects.compat.snakeyaml1Compat)
// Note: If manually starting tests doesn't work for you in IJ, change 'Gradle -> Run Tests Using' to 'IntelliJ IDEA'
testImplementation(rootProject.libs.netty)
testImplementation(rootProject.libs.guava)
testImplementation(rootProject.libs.snakeYaml2)
testImplementation(rootProject.libs.snakeYaml)
testImplementation(rootProject.libs.bundles.junit)
}
@@ -67,6 +67,7 @@ public class ViaManagerImpl implements ViaManager {
private final ViaPlatformLoader loader;
private final Set<String> subPlatforms = new HashSet<>();
private List<Runnable> enableListeners = new ArrayList<>();
private List<Runnable> postEnableListeners = new ArrayList<>();
private PlatformTask<?> mappingLoadingTask;
private boolean initialized;
@@ -150,7 +151,7 @@ public class ViaManagerImpl implements ViaManager {
platform.getLogger().warning("and if you're still unsure, feel free to join our Discord-Server for further assistance.");
} else if (protocolVersion.highestSupportedProtocolVersion().olderThan(ProtocolVersion.v1_13)) {
platform.getLogger().warning("This version of Minecraft is extremely outdated and support for it has reached its end of life. "
+ "You will still be able to run Via on this Minecraft version, but we are unlikely to provide any further fixes or help with problems specific to legacy Minecraft versions. "
+ "You will still be able to run Via on this Minecraft version, but we will prioritize issues with legacy Minecraft versions less. "
+ "Please consider updating to give your players a better experience and to avoid issues that have long been fixed.");
}
}
@@ -184,6 +185,11 @@ public class ViaManagerImpl implements ViaManager {
// Refresh Versions
protocolManager.refreshVersions();
for (final Runnable listener : postEnableListeners) {
listener.run();
}
postEnableListeners = null;
}
private void loadServerProtocol() {
@@ -204,8 +210,10 @@ public class ViaManagerImpl implements ViaManager {
}
public void destroy() {
// Uninject
platform.getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
if (platform.couldBeReloading()) {
platform.getLogger().info("ViaVersion is disabling. If this is a reload and you experience issues, please reboot instead.");
}
try {
injector.uninject();
} catch (Exception e) {
@@ -214,6 +222,8 @@ public class ViaManagerImpl implements ViaManager {
loader.unload();
scheduler.shutdown();
platform.getLogger().info("ViaVersion has been disabled; uninjected the platform and shut down the scheduler.");
}
private void checkJavaVersion() { // Stolen from Paper
@@ -235,7 +245,8 @@ 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("Starting with Minecraft 1.21, ViaVersion will no longer officially be compatible with this version of Java, only offering unsupported compatibility builds.");
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.");
}
}
@@ -316,25 +327,21 @@ public class ViaManagerImpl implements ViaManager {
return configurationProvider;
}
/**
* Returns a mutable set of self-added subplatform version strings.
* This set is expanded by the subplatform itself (e.g. ViaBackwards), and may not contain all running ones.
*
* @return mutable set of subplatform versions
*/
@Override
public Set<String> getSubPlatforms() {
return subPlatforms;
}
/**
* Adds a runnable to be executed when ViaVersion has finished its init before the full server load.
*
* @param runnable runnable to be executed
*/
@Override
public void addEnableListener(Runnable runnable) {
enableListeners.add(runnable);
}
@Override
public void addPostEnableListener(final Runnable runnable) {
postEnableListeners.add(runnable);
}
@Override
public boolean isInitialized() {
return initialized;
@@ -30,7 +30,7 @@ public class DumpSubCmd implements ViaSubCommand {
@Override
public String description() {
return "Dump information about your server, this is helpful if you report bugs.";
return "Dump information about your platform implementation, this is helpful if you report bugs.";
}
@Override
@@ -25,21 +25,26 @@ import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.BlockedProtocolVersionsImpl;
import com.viaversion.viaversion.util.Config;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class AbstractViaConfig extends Config implements ViaVersionConfig {
public static final List<String> BUKKIT_ONLY_OPTIONS = Arrays.asList("register-userconnections-on-join", "quick-move-action-fix",
"change-1_9-hitbox", "change-1_14-hitbox", "blockconnection-method", "armor-toggle-fix", "use-new-deathmessages",
"item-cache", "nms-player-ticking");
public static final List<String> VELOCITY_ONLY_OPTIONS = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
private boolean checkForUpdates;
private boolean preventCollision;
private boolean useNewEffectIndicator;
private boolean useNewDeathmessages;
private boolean suppressMetadataErrors;
private boolean shieldBlocking;
private boolean noDelayShieldBlocking;
@@ -57,8 +62,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private String maxPPSWarningsKickMessage;
private boolean sendSupportedVersions;
private boolean simulatePlayerTick;
private boolean itemCache;
private boolean nmsPlayerTicking;
private boolean replacePistons;
private int pistonReplacementId;
private boolean chunkBorderFix;
@@ -69,7 +72,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private String reloadDisconnectMessage;
private boolean suppressConversionWarnings;
private boolean disable1_13TabComplete;
private boolean minimizeCooldown;
private boolean teamColourFix;
private boolean serversideBlockConnections;
private boolean reduceBlockStorageMemory;
@@ -91,6 +93,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean translateOcelotToCat;
private boolean enforceSecureChat;
private boolean handleInvalidItemCount;
private boolean cancelBlockSounds;
private boolean hideScoreboardNumbers;
private boolean fix1_21PlacementRotation;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@@ -106,7 +111,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
checkForUpdates = getBoolean("check-for-updates", true);
preventCollision = getBoolean("prevent-collision", true);
useNewEffectIndicator = getBoolean("use-new-effect-indicator", true);
useNewDeathmessages = getBoolean("use-new-deathmessages", true);
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
shieldBlocking = getBoolean("shield-blocking", true);
noDelayShieldBlocking = getBoolean("no-delay-shield-blocking", false);
@@ -124,8 +128,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
maxPPSWarningsKickMessage = getString("tracking-max-kick-msg", "You are sending too many packets, :(");
sendSupportedVersions = getBoolean("send-supported-versions", false);
simulatePlayerTick = getBoolean("simulate-pt", true);
itemCache = getBoolean("item-cache", true);
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
replacePistons = getBoolean("replace-pistons", false);
pistonReplacementId = getInt("replacement-piston-id", 0);
chunkBorderFix = getBoolean("chunk-border-fix", false);
@@ -134,7 +136,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
blockedProtocolVersions = loadBlockedProtocolVersions();
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
minimizeCooldown = getBoolean("minimize-cooldown", true);
teamColourFix = getBoolean("team-colour-fix", true);
suppressConversionWarnings = getBoolean("suppress-conversion-warnings", false);
disable1_13TabComplete = getBoolean("disable-1_13-auto-complete", false);
@@ -161,6 +162,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
translateOcelotToCat = getBoolean("translate-ocelot-to-cat", true);
enforceSecureChat = getBoolean("enforce-secure-chat", false);
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);
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -254,7 +258,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public boolean isShowNewDeathMessages() {
return useNewDeathmessages;
return false;
}
@Override
@@ -344,12 +348,12 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public boolean isItemCache() {
return itemCache;
return false;
}
@Override
public boolean isNMSPlayerTicking() {
return nmsPlayerTicking;
return false;
}
@Override
@@ -403,11 +407,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return reloadDisconnectMessage;
}
@Override
public boolean isMinimizeCooldown() {
return minimizeCooldown;
}
@Override
public boolean is1_13TeamColourFix() {
return teamColourFix;
@@ -542,4 +541,19 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean handleInvalidItemCount() {
return handleInvalidItemCount;
}
@Override
public boolean cancelBlockSounds() {
return cancelBlockSounds;
}
@Override
public boolean hideScoreboardNumbers() {
return hideScoreboardNumbers;
}
@Override
public boolean fix1_21PlacementRotation() {
return fix1_21PlacementRotation;
}
}
@@ -23,6 +23,7 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.platform.ViaInjector;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.Direction;
@@ -58,6 +59,7 @@ public class UserConnectionImpl implements UserConnection {
private final long id = IDS.incrementAndGet();
private final Map<Class<?>, StorableObject> storedObjects = new ConcurrentHashMap<>();
private final Map<Class<? extends Protocol>, EntityTracker> entityTrackers = new HashMap<>();
private final Map<Class<? extends Protocol>, ClientWorld> clientWorlds = new HashMap<>();
private final PacketTracker packetTracker = new PacketTracker(this);
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
@@ -125,9 +127,17 @@ public class UserConnectionImpl implements UserConnection {
@Override
public void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker) {
if (!entityTrackers.containsKey(protocolClass)) {
entityTrackers.put(protocolClass, tracker);
}
entityTrackers.putIfAbsent(protocolClass, tracker);
}
@Override
public @Nullable <T extends ClientWorld> T getClientWorld(final Class<? extends Protocol> protocolClass) {
return (T) clientWorlds.get(protocolClass);
}
@Override
public void addClientWorld(final Class<? extends Protocol> protocolClass, final ClientWorld clientWorld) {
clientWorlds.putIfAbsent(protocolClass, clientWorld);
}
@Override
@@ -142,7 +152,6 @@ public class UserConnectionImpl implements UserConnection {
});
for (EntityTracker tracker : entityTrackers.values()) {
tracker.clearEntities();
tracker.trackClientEntity();
}
} else {
for (StorableObject object : storedObjects.values()) {
@@ -150,6 +159,7 @@ public class UserConnectionImpl implements UserConnection {
}
storedObjects.clear();
entityTrackers.clear();
clientWorlds.clear();
}
}
@@ -73,8 +73,9 @@ public final class DimensionDataImpl implements DimensionData {
@Override
public String toString() {
return "DimensionData{" +
"minY=" + minY +
return "DimensionDataImpl{" +
"id=" + id +
", minY=" + minY +
", height=" + height +
'}';
}
@@ -34,10 +34,10 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeListener {
private final Int2ObjectMap<TrackedEntity> entities = new Int2ObjectOpenHashMap<>();
protected final Int2ObjectMap<TrackedEntity> entities = new Int2ObjectOpenHashMap<>();
private final UserConnection connection;
private final EntityType playerType;
private int clientEntityId = -1;
private Integer clientEntityId;
private int currentWorldSectionHeight = -1;
private int currentMinY;
private String currentWorld;
@@ -87,7 +87,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
return entity != null && entity.hasData() ? entity.data() : null;
}
//TODO Soft memory leak: Remove entities on respawn in protocols prior to 1.18 (1.16+ only when the worldname is different)
@Override
public void removeEntity(int id) {
entities.remove(id);
@@ -95,11 +94,27 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
@Override
public void clearEntities() {
entities.clear();
// Call wrapper function in case protocols need to do additional removals
for (final int id : entities.keySet().toIntArray()) {
removeEntity(id);
}
// Re-add the client entity. Keep the call above to untrack attached data if necessary
if (clientEntityId != null) {
entities.put(clientEntityId.intValue(), new TrackedEntityImpl(playerType));
}
}
@Override
public int clientEntityId() {
public boolean hasClientEntityId() {
return clientEntityId != null;
}
@Override
public int clientEntityId() throws IllegalStateException {
if (clientEntityId == null) {
throw new IllegalStateException("Client entity id not set");
}
return clientEntityId;
}
@@ -107,7 +122,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
public void setClientEntityId(int clientEntityId) {
Preconditions.checkNotNull(playerType);
final TrackedEntity oldEntity;
if (this.clientEntityId != -1 && (oldEntity = entities.remove(this.clientEntityId)) != null) {
if (this.clientEntityId != null && (oldEntity = entities.remove(this.clientEntityId.intValue())) != null) {
entities.put(clientEntityId, oldEntity);
} else {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
@@ -116,15 +131,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
this.clientEntityId = clientEntityId;
}
@Override
public boolean trackClientEntity() {
if (clientEntityId != -1) {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
return true;
}
return false;
}
@Override
public int currentWorldSectionHeight() {
return currentWorldSectionHeight;
@@ -17,10 +17,9 @@
*/
package com.viaversion.viaversion.dump;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import java.util.Set;
public record VersionInfo(String javaVersion, String operatingSystem, VersionType versionType,
public record VersionInfo(String javaVersion, String operatingSystem,
int serverProtocol, String serverVersion,
Set<String> enabledProtocols, String platformName,
String platformVersion, String pluginVersion,
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.legacy.bossbar;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
import com.google.gson.JsonParser;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.legacy.bossbar.BossBar;
@@ -26,7 +27,6 @@ import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
import com.viaversion.viaversion.api.legacy.bossbar.BossFlag;
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
@@ -246,28 +246,32 @@ public class CommonBoss implements BossBar {
wrapper.write(Types.UUID, uuid);
wrapper.write(Types.VAR_INT, action.getId());
switch (action) {
case ADD:
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
case ADD -> {
try {
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
} catch (Exception e) {
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
}
wrapper.write(Types.FLOAT, health);
wrapper.write(Types.VAR_INT, color.getId());
wrapper.write(Types.VAR_INT, style.getId());
wrapper.write(Types.BYTE, (byte) flagToBytes());
break;
case REMOVE:
break;
case UPDATE_HEALTH:
wrapper.write(Types.FLOAT, health);
break;
case UPDATE_TITLE:
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
break;
case UPDATE_STYLE:
}
case REMOVE -> {
}
case UPDATE_HEALTH -> wrapper.write(Types.FLOAT, health);
case UPDATE_TITLE -> {
try {
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
} catch (Exception e) {
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
}
}
case UPDATE_STYLE -> {
wrapper.write(Types.VAR_INT, color.getId());
wrapper.write(Types.VAR_INT, style.getId());
break;
case UPDATE_FLAGS:
wrapper.write(Types.BYTE, (byte) flagToBytes());
break;
}
case UPDATE_FLAGS -> wrapper.write(Types.BYTE, (byte) flagToBytes());
}
return wrapper;
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.protocol.ProtocolManager;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.ProtocolPathKey;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
@@ -38,10 +39,9 @@ import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl;
import com.viaversion.viaversion.protocols.base.BaseProtocol;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_16;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_7;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.base.InitialBaseProtocol;
import com.viaversion.viaversion.protocols.base.v1_7.ClientboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.base.v1_7.ServerboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.v1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viaversion.protocols.v1_11to1_11_1.Protocol1_11To1_11_1;
@@ -74,6 +74,7 @@ import com.viaversion.viaversion.protocols.v1_19_4to1_20.Protocol1_19_4To1_20;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.Protocol1_19To1_19_1;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3;
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_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3;
@@ -109,14 +110,15 @@ import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolManagerImpl implements ProtocolManager {
private static final Protocol BASE_PROTOCOL = new BaseProtocol();
private static final Protocol BASE_PROTOCOL = new InitialBaseProtocol();
// Input Version -> Output Version & Protocol (Allows fast lookup)
private final Object2ObjectMap<ProtocolVersion, Object2ObjectMap<ProtocolVersion, Protocol>> registryMap = new Object2ObjectOpenHashMap<>(32);
private final Map<Class<? extends Protocol>, Protocol<?, ?, ?, ?>> protocols = new HashMap<>(64);
private final Map<ProtocolPathKey, List<ProtocolPathEntry>> pathCache = new ConcurrentHashMap<>();
private final Set<ProtocolVersion> supportedVersions = new HashSet<>();
private final List<Pair<Range<ProtocolVersion>, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList();
private final List<Pair<Range<ProtocolVersion>, Protocol>> serverboundBaseProtocols = Lists.newCopyOnWriteArrayList();
private final List<Pair<Range<ProtocolVersion>, Protocol>> clientboundBaseProtocols = Lists.newCopyOnWriteArrayList();
private final ReadWriteLock mappingLoaderLock = new ReentrantReadWriteLock();
private Map<Class<? extends Protocol>, CompletableFuture<Void>> mappingLoaderFutures = new HashMap<>();
@@ -137,8 +139,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
// Base Protocol
BASE_PROTOCOL.initialize();
BASE_PROTOCOL.register(Via.getManager().getProviders());
registerBaseProtocol(new BaseProtocol1_7(), Range.closedOpen(ProtocolVersion.v1_7_2, ProtocolVersion.v1_16));
registerBaseProtocol(new BaseProtocol1_16(), Range.atLeast(ProtocolVersion.v1_16));
registerBaseProtocol(Direction.CLIENTBOUND, new ClientboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerBaseProtocol(Direction.SERVERBOUND, new ServerboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerProtocol(new Protocol1_8To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_8);
registerProtocol(new Protocol1_9To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9);
@@ -234,7 +236,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public void registerBaseProtocol(Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols) {
public void registerBaseProtocol(Direction direction, Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols) {
Preconditions.checkArgument(baseProtocol.isBaseProtocol(), "Protocol is not a base protocol");
final ProtocolVersion lower = supportedProtocols.hasLowerBound() ? supportedProtocols.lowerEndpoint() : null;
final ProtocolVersion upper = supportedProtocols.hasUpperBound() ? supportedProtocols.upperEndpoint() : null;
@@ -243,7 +245,11 @@ public class ProtocolManagerImpl implements ProtocolManager {
baseProtocol.initialize();
baseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
if (direction == Direction.SERVERBOUND) {
serverboundBaseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
} else {
clientboundBaseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
}
baseProtocol.register(Via.getManager().getProviders());
if (Via.getManager().isInitialized()) {
refreshVersions();
@@ -273,12 +279,14 @@ public class ProtocolManagerImpl implements ProtocolManager {
ProtocolPathKey protocolKey = new ProtocolPathKeyImpl(clientVersion, serverVersion);
List<ProtocolPathEntry> protocolList = pathCache.get(protocolKey);
if (protocolList != null) {
return protocolList;
return protocolList.isEmpty() ? null : protocolList;
}
// Calculate path
Object2ObjectSortedMap<ProtocolVersion, Protocol> outputPath = getProtocolPath(new Object2ObjectLinkedOpenHashMap<>(), clientVersion, serverVersion);
if (outputPath == null) {
// Also cache that there is no path
pathCache.put(protocolKey, List.of());
return null;
}
@@ -365,13 +373,23 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public @Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) {
if (rangeProtocol.key().contains(serverVersion)) {
return rangeProtocol.value();
public List<Protocol> getBaseProtocols(@Nullable ProtocolVersion clientVersion, @Nullable ProtocolVersion serverVersion) {
final List<Protocol> list = new ArrayList<>();
if (clientVersion != null) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : serverboundBaseProtocols) {
if (rangeProtocol.key().contains(clientVersion)) {
list.add(rangeProtocol.value());
}
}
}
return null;
if (serverVersion != null) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : clientboundBaseProtocols) {
if (rangeProtocol.key().contains(serverVersion)) {
list.add(rangeProtocol.value());
}
}
}
return list;
}
@Override
@@ -518,7 +536,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
Preconditions.checkArgument(!mappingsLoaded);
// If this log message is missing, something is wrong
Via.getPlatform().getLogger().info("Finished mapping loading, shutting down loader executor!");
Via.getPlatform().getLogger().info("Finished mapping loading, shutting down loader executor.");
mappingsLoaded = true;
mappingLoaderExecutor.shutdown();
mappingLoaderExecutor = null;
@@ -24,8 +24,10 @@ import java.util.Comparator;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Special protocol version that compares to another version. This can be used for e.g. April Fool versions which are depending
* on vanilla game versions.
* Intended API class for protocol versions with the version type {@link VersionType#SPECIAL}.
* <p>
* Compares equal to the given origin version and allows base protocol determination via {@link #getBaseProtocolVersion()}
* which can be null for special cases where there is no base protocol.
*/
public class RedirectProtocolVersion extends ProtocolVersion {
@@ -52,4 +54,14 @@ public class RedirectProtocolVersion extends ProtocolVersion {
};
}
public ProtocolVersion getOrigin() {
return origin;
}
/**
* @return the protocol version used to determine the base protocol, null in case there is no base protocol.
*/
public @Nullable ProtocolVersion getBaseProtocolVersion() {
return origin;
}
}
@@ -123,7 +123,7 @@ public class PacketWrapperImpl implements PacketWrapper {
continue;
}
if (currentIndex == index) {
packetValue.setValue(attemptTransform(type, value));
packetValue.setValue(value);
return;
}
currentIndex++;
@@ -133,23 +133,26 @@ public class PacketWrapperImpl implements PacketWrapper {
@Override
public <T> T read(Type<T> type) {
if (readableObjects.isEmpty()) {
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
try {
return type.read(inputBuffer);
} catch (Exception e) {
throw createInformativeException(e, type, packetValues.size() + 1);
}
}
return readableObjects.isEmpty() ? readFromBuffer(type) : pollReadableObject(type).value;
}
PacketValue readValue = readableObjects.poll();
private <T> T readFromBuffer(Type<T> type) {
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
try {
return type.read(inputBuffer);
} catch (Exception e) {
throw createInformativeException(e, type, packetValues.size() + 1);
}
}
private <T> PacketValue<T> pollReadableObject(Type<T> type) {
PacketValue<?> readValue = readableObjects.poll();
Type<?> readType = readValue.type();
if (readType == type
|| (type.getBaseClass() == readType.getBaseClass()
&& type.getOutputClass() == readType.getOutputClass())) {
//noinspection unchecked
return (T) readValue.value();
return (PacketValue<T>) readValue;
} else {
throw createInformativeException(new IOException("Unable to read type " + type.getTypeName() + ", found " + readValue.type().getTypeName()), type, readableObjects.size());
}
@@ -157,7 +160,7 @@ public class PacketWrapperImpl implements PacketWrapper {
@Override
public <T> void write(Type<T> type, T value) {
packetValues.add(new PacketValue<>(type, attemptTransform(type, value)));
packetValues.add(new PacketValue<>(type, value));
}
/**
@@ -167,7 +170,7 @@ public class PacketWrapperImpl implements PacketWrapper {
* @param value value
* @return value if already matching, else the converted value or possibly unmatched value
*/
private <T> @Nullable T attemptTransform(Type<T> expectedType, @Nullable T value) {
private <T> @Nullable T attemptTransform(Type<T> expectedType, @Nullable Object value) {
if (value != null && !expectedType.getOutputClass().isAssignableFrom(value.getClass())) {
// Attempt conversion
if (expectedType instanceof TypeConverter<?>) {
@@ -177,14 +180,33 @@ public class PacketWrapperImpl implements PacketWrapper {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + expectedType.getOutputClass());
}
return value;
//noinspection unchecked
return (T) value;
}
@Override
public <T> T passthrough(Type<T> type) throws InformativeException {
T value = read(type);
write(type, value);
return value;
if (readableObjects.isEmpty()) {
T value = readFromBuffer(type);
packetValues.add(new PacketValue<>(type, value));
return value;
} else {
PacketValue<T> value = pollReadableObject(type);
packetValues.add(value);
return value.value;
}
}
@Override
public <T> T passthroughAndMap(Type<?> type, Type<T> mappedType) throws InformativeException {
if (type == mappedType) {
return passthrough(mappedType);
}
final Object value = read(type);
final T mappedValue = attemptTransform(mappedType, value);
write(mappedType, mappedValue);
return mappedValue;
}
@Override
@@ -318,7 +340,7 @@ public class PacketWrapperImpl implements PacketWrapper {
}
return user().sendRawPacketFuture(output);
}
return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet"));
return cancelledFuture();
}
@Override
@@ -326,6 +348,21 @@ public class PacketWrapperImpl implements PacketWrapper {
sendRaw(true);
}
@Override
public ChannelFuture sendFutureRaw() throws InformativeException {
if (isCancelled()) {
return cancelledFuture();
}
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
try {
writeToBuffer(output);
return user().sendRawPacketFuture(output.retain());
} finally {
output.release();
}
}
@Override
public void scheduleSendRaw() throws InformativeException {
sendRaw(false);
@@ -349,6 +386,10 @@ public class PacketWrapperImpl implements PacketWrapper {
}
}
private ChannelFuture cancelledFuture() {
return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet"));
}
@Override
public PacketWrapperImpl create(int packetId) {
return new PacketWrapperImpl(packetId, null, user());
@@ -35,6 +35,7 @@ import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.protocol.RedirectProtocolVersion;
import com.viaversion.viaversion.protocol.version.BaseVersionProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
@@ -42,34 +43,45 @@ import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import java.util.ArrayList;
import java.util.List;
public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
/**
* Initial base protocol which is kept always in the pipeline.
* <p>
* State tracking for configuration state is done via {@link AbstractProtocol#registerConfigurationChangeHandlers()}
*/
public class InitialBaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
private static final int STATUS_INTENT = 1;
private static final int LOGIN_INTENT = 2;
private static final int TRANSFER_INTENT = 3;
public BaseProtocol() {
public InitialBaseProtocol() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// Handshake Packet
// Setup protocol pipeline + track initial state
registerServerbound(ServerboundHandshakePackets.CLIENT_INTENTION, wrapper -> {
int protocolVersion = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Server Address
wrapper.passthrough(Types.UNSIGNED_SHORT); // Server Port
int state = wrapper.passthrough(Types.VAR_INT);
ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
// Ensure the server has a version provider
VersionProvider versionProvider = Via.getManager().getProviders().get(VersionProvider.class);
// Ensure the server has a version provider
if (versionProvider == null) {
wrapper.user().setActive(false);
return;
}
ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
ProtocolVersion clientVersion = versionProvider.getClientProtocol(wrapper.user());
if (clientVersion != null) {
info.setProtocolVersion(clientVersion);
}
// Choose the pipe
ProtocolVersion serverProtocol;
try {
@@ -83,16 +95,22 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
ProtocolManager protocolManager = Via.getManager().getProtocolManager();
List<ProtocolPathEntry> protocolPath = protocolManager.getProtocolPath(info.protocolVersion(), serverProtocol);
// Add Base Protocol
ProtocolPipeline pipeline = info.getPipeline();
// Special versions might compare equal to normal versions and would break this getter
// Save manually added protocols for later
List<Protocol> alreadyAdded = new ArrayList<>(pipeline.pipes());
// Special versions might compare equal to normal versions and would the normal lookup,
// platforms can use the RedirectProtocolVersion API or need to manually handle their base protocols.
ProtocolVersion clientboundBaseProtocolVersion = null;
if (serverProtocol.getVersionType() != VersionType.SPECIAL) {
final Protocol baseProtocol = protocolManager.getBaseProtocol(serverProtocol);
// Platforms might add their base protocol manually (e.g. SPECIAL versions)
if (baseProtocol != null) {
pipeline.add(baseProtocol);
}
clientboundBaseProtocolVersion = serverProtocol;
} else if (serverProtocol instanceof RedirectProtocolVersion version) {
clientboundBaseProtocolVersion = version.getBaseProtocolVersion();
}
// Add base protocols
for (final Protocol protocol : protocolManager.getBaseProtocols(info.protocolVersion(), clientboundBaseProtocolVersion)) {
pipeline.add(protocol);
}
// Add other protocols
@@ -112,11 +130,22 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
wrapper.set(Types.VAR_INT, 0, serverProtocol.getOriginalVersion());
}
// Send client intention into the pipeline in case protocols down the line need to transform it
try {
final List<Protocol> protocols = new ArrayList<>(pipeline.pipes());
protocols.removeAll(alreadyAdded); // Skip all manually added protocols to prevent double handling
wrapper.resetReader();
wrapper.apply(Direction.SERVERBOUND, State.HANDSHAKE, protocols);
} catch (CancelException e) {
wrapper.cancel();
}
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().info("User connected with protocol: " + info.protocolVersion() + " and serverProtocol: " + info.serverProtocolVersion());
Via.getPlatform().getLogger().info("Protocol pipeline: " + pipeline.pipes());
}
// Set initial state
if (state == STATUS_INTENT) {
info.setState(State.STATUS);
} else if (state == LOGIN_INTENT) {
@@ -156,4 +185,4 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
return BasePacketTypesProvider.INSTANCE;
}
}
}
@@ -15,7 +15,7 @@
* 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.base;
package com.viaversion.viaversion.protocols.base.v1_7;
import com.google.common.base.Joiner;
import com.google.gson.JsonElement;
@@ -26,7 +26,6 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@@ -35,25 +34,25 @@ import com.viaversion.viaversion.api.protocol.version.VersionProvider;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ClientboundStatusPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.GsonUtil;
import io.netty.channel.ChannelFuture;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public class ClientboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public BaseProtocol1_7() {
public ClientboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// Handle server pinging sent by the client
registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() {
@Override
public void register() {
@@ -128,60 +127,27 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
}
});
// Login Success Packet
// Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
ProtocolInfo info = wrapper.user().getProtocolInfo();
if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
info.setState(State.PLAY);
}
UUID uuid = passthroughLoginUUID(wrapper);
info.setUuid(uuid);
String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(wrapper.user());
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
wrapper.user().setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
username,
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
}
});
// Login Start Packet
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
disconnectPacket.write(Types.COMPONENT, ComponentUtil.plainToJson(disconnectMessage));
// Send and close
final ChannelFuture future = disconnectPacket.sendFuture(null);
future.addListener(f -> user.getChannel().close());
}
});
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
String uuidString = wrapper.passthrough(Types.STRING);
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters
// Trimmed
uuidString = addDashes(uuidString);
}
info.setUuid(UUID.fromString(uuidString));
} else {
final UUID uuid = wrapper.passthrough(Types.UUID);
info.setUuid(uuid);
}
final String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Setup connection
onLoginSuccess(wrapper.user());
});
}
@@ -199,13 +165,28 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
return idBuff.toString();
}
protected UUID passthroughLoginUUID(PacketWrapper wrapper) {
String uuidString = wrapper.passthrough(Types.STRING);
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters
// Trimmed
uuidString = addDashes(uuidString);
public static void onLoginSuccess(final UserConnection connection) {
final ProtocolInfo info = connection.getProtocolInfo();
if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
info.setState(State.PLAY);
}
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(connection);
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
connection.setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
info.getUsername(),
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
}
return UUID.fromString(uuidString);
}
@Override
@@ -0,0 +1,91 @@
/*
* 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.base.v1_7;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import io.netty.channel.ChannelFuture;
public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public ServerboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// State tracking
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
});
// Handle blocked version disconnect
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
final JsonObject object = ComponentUtil.plainToJson(disconnectMessage);
if (protocol.olderThanOrEqualTo(ProtocolVersion.v1_8)) {
disconnectPacket.write(Types.STRING, object.toString());
} else {
disconnectPacket.write(Types.COMPONENT, object);
}
// Send and close
final ChannelFuture future = disconnectPacket.sendFutureRaw();
future.addListener(f -> user.getChannel().close());
}
});
}
@Override
public boolean isBaseProtocol() {
return true;
}
@Override
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
return BasePacketTypesProvider.INSTANCE;
}
}
@@ -15,26 +15,31 @@
* 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.template.protocols.rewriter;
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_20_5;
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.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_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.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import com.viaversion.viaversion.template.protocols.Protocol1_99To_98;
// To replace if needed:
// ChunkType1_20_2
// RecipeRewriter1_20_3
public final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_20_5, ServerboundPacket1_20_5, Protocol1_99To_98> {
// Types1_21, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21, ServerboundPacket1_20_5, Protocol1_99To_98> {
public BlockItemPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, /*TypesOLD.ITEM, TypesOLD.ITEM_ARRAY, */Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY);
super(protocol, Types1_21.ITEM, Types1_21.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
);*/
}
@Override
@@ -42,32 +47,31 @@ public final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Cl
// 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_20_5> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_20_5.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_20_5.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_20_5.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_20_5.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_20_5.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_20_5.BLOCK_ENTITY_DATA);
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);
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenWindow(ClientboundPackets1_20_5.OPEN_WINDOW); - If a new container type was added
registerCooldown(ClientboundPackets1_20_5.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_20_5.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_20_5.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_20_5.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_20_5.SET_EQUIPMENT);
// 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_20_5.MERCHANT_OFFERS, Types1_20_5.ITEM_COST, Types1_20_5.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerContainerSetData(ClientboundPackets1_20_5.CONTAINER_SET_DATA);
registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES, Types1_20_5.PARTICLE, Types1_20_5.PARTICLE);
registerExplosion(ClientboundPackets1_20_5.EXPLODE, Types1_20_5.PARTICLE, Types1_20_5.PARTICLE); // Rewrites the included sound and particles
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
registerExplosion(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_20_5.UPDATE_RECIPES);
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_21.UPDATE_RECIPES);
// 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<ClientboundPackets1_20_5>(this) {}.register1_20_5(ClientboundPackets1_20_5.DECLARE_RECIPES);
// new RecipeRewriter1_20_3<ClientboundPacket1_21>(this) {}.register1_20_5(ClientboundPackets1_21.DECLARE_RECIPES);
}
}
}
@@ -15,25 +15,24 @@
* 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.template.protocols.rewriter;
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.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
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.rewriter.EntityRewriter;
import com.viaversion.viaversion.template.protocols.Protocol1_99To_98;
import com.viaversion.viaversion.util.Key;
// Replace if needed
// Types1_OLD
// Types1_20_5
public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_20_5, Protocol1_99To_98> {
// Types1_21
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21, Protocol1_99To_98> {
public EntityPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol);
@@ -42,17 +41,17 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
@Override
public void registerPackets() {
// Tracks entities, applies entity data rewrites registered below, untracks entities
registerTrackerWithData1_19(ClientboundPackets1_20_5.ADD_ENTITY, EntityTypes1_20_5.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_20_5.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_20_5.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
registerRemoveEntities(ClientboundPackets1_20_5.REMOVE_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);
protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA, wrapper -> {
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
});
protocol.registerClientbound(ClientboundPackets1_20_5.LOGIN, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
@@ -71,7 +70,7 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
}
});
protocol.registerClientbound(ClientboundPackets1_20_5.RESPAWN, wrapper -> {
protocol.registerClientbound(ClientboundPackets1_21.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
@@ -82,24 +81,23 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
protected void registerRewrites() {
/* Uncomment if entity data classes changed
filter().mapDataType(typeId -> {
final int id = typeId;
int id = typeId;
if (id >= SomeAddedIndex) {
id++;
}
return Types1_20_5.ENTITY_DATA_TYPES.byId(id);
return Types1_21.ENTITY_DATA_TYPES.byId(id);
});*/
// Registers registry type id changes
registerEntityDataTypeHandler(
Types1_20_5.ENTITY_DATA_TYPES.itemType,
Types1_20_5.ENTITY_DATA_TYPES.blockStateType,
Types1_20_5.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_20_5.ENTITY_DATA_TYPES.particleType,
Types1_20_5.ENTITY_DATA_TYPES.particlesType,
Types1_20_5.ENTITY_DATA_TYPES.componentType,
Types1_20_5.ENTITY_DATA_TYPES.optionalComponentType
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
);
// Minecarts are special
registerBlockStateHandler(EntityTypes1_20_5.ABSTRACT_MINECART, 11);
}
@@ -113,4 +111,4 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
public EntityType typeFromId(final int type) {
return EntityTypes1_20_5.getTypeFromId(type);
}
}
}
@@ -15,7 +15,7 @@
* 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.template.protocols;
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
@@ -25,68 +25,63 @@ 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.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
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.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.template.protocols.rewriter.BlockItemPacketRewriter1_99;
import com.viaversion.viaversion.template.protocols.rewriter.EntityPacketRewriter1_99;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_99To_98, EntityPacketRewriter1_99, BlockItemPacketRewriter1_99
// ClientboundPacket1_20_5
// 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)
// 1.99, 1.98
public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_20_5, ClientboundPacket1_20_5, ServerboundPacket1_20_5, ServerboundPacket1_20_5> {
final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> {
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_20_5> tagRewriter = new TagRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21> tagRewriter = new TagRewriter<>(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_20_5.class, ClientboundPacket1_20_5.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class);
super(ClientboundPacket1_21.class, ClientboundPacket1_21.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_20_5.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_20_5.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_20_5> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_20_5.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_20_5.SOUND_ENTITY);
final SoundRewriter<ClientboundPacket1_21> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_20_5.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_20_5.UPDATE_ATTRIBUTES);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES);
// Uncomment if an existing type changed serialization format. Mappings for argument type keys can also be defined in mapping files
/*final CommandRewriter1_19_4<ClientboundPackets1_20_5> commandRewriter = new CommandRewriter1_19_4<ClientboundPackets1_20_5>(this) {
/*new CommandRewriter1_19_4<>(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception {
public void handleArgument(final PacketWrapper wrapper, final String argumentType) {
if (argumentType.equals("minecraft:abc")) {
// New argument
wrapper.write(Type.INT, 0);
wrapper.write(Types.INT, 0);
} else {
super.handleArgument(wrapper, argumentType);
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_20_5.DECLARE_COMMANDS);*/
// TODO Rewrite structured data ids and items within them
}.registerDeclareCommands1_19(ClientboundPackets1_21.COMMANDS);*/
}
@Override
@@ -95,7 +90,7 @@ public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1
// EntityTypes1_20_5.initialize(this);
// Uncomment if a new particle was added = ids shifted; requires a new Types_ class copied from the last
/*Types1_20_5.PARTICLE.filler(this)
/*Types1_21.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
@@ -133,17 +128,17 @@ public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1
}
@Override
public TagRewriter<ClientboundPacket1_20_5> getTagRewriter() {
public TagRewriter<ClientboundPacket1_21> getTagRewriter() {
return tagRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_20_5, ClientboundPacket1_20_5, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
protected PacketTypesProvider<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class),
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)
);
}
}
}
Loaded 100 of 221 files, more files were not shown because too many files have changed in this diff. Show more