Compare commits

..
152 Commits
Author SHA1 Message Date
Nassim Jahnke f880adced2 5.1.0 Release 2024-10-25 09:24:29 +02:00
Nassim Jahnke fc07601f24 Fix glow squid index shift 2024-10-24 16:55:24 +02:00
Nassim Jahnke ecb241c187 Exclude error prone annotations
Recently added to gson, can be safely excluded
2024-10-24 12:50:36 +02:00
Nassim Jahnke 46040b1f5d Mark fallback return value in getProtocol as unknown 2024-10-23 17:04:54 +02:00
FlorianMichael 54daa11ce4 Fix ProtocolVersion#isKnown javadoc to make difference with isRegistered more clear 2024-10-23 17:02:45 +02:00
RaphiMC c556420870 Add option to construct ChunkSectionLightImpl without block light 2024-10-23 16:42:21 +02:00
FlorianMichael 84d928ebe7 Update version ranges in gradle.properties 2024-10-23 16:25:52 +02:00
FlorianMichael fa6eab5cc3 1.21.3 2024-10-23 15:42:16 +02:00
FlorianMichael 94b26a903c Check for suppress conversion warnings option in ComponentUtil functions 2024-10-22 22:31:17 +02:00
Nassim Jahnke c242456c30 Remove snapshot version 2024-10-22 17:02:14 +02:00
Nassim Jahnke 8391e9d924 Fix consumable writing 2024-10-22 13:23:06 +02:00
RK_01 f5aac9b1ab Convert all data from food component (#13) 2024-10-22 13:21:44 +02:00
RK_01 a6850392e1 Add failsafe handling to ACCEPT_TELEPORTATION packet order fix (#12) 2024-10-22 13:03:43 +02:00
RK_01 2b37178482 Fix ACCEPT_TELEPORTATION packet order (#11) 2024-10-22 11:13:45 +02:00
Nassim Jahnke 82199d9f39 1.21.2-rc2 2024-10-21 18:36:50 +02:00
FlorianMichael c2d2c6d067 Explain SerializerVersion terminology 2024-10-19 14:50:09 +02:00
FlorianMichael 4066a7b5b6 Mark serializer versions in ComponentRewriter as nullable 2024-10-19 14:43:43 +02:00
Nassim Jahnke 4a7624fef4 Update profile actions enum type 2024-10-19 13:18:14 +02:00
EnZaXD e38b3f3824 Add new PROFILE_ACTIONS_ENUM type in Types for 1.21.2+ 2024-10-19 11:45:51 +02:00
Nassim Jahnke 4573035aab 1.21.2-rc1 2024-10-17 15:28:15 +02:00
Nassim Jahnke 393a5ee973 1.21.2-pre5 2024-10-16 16:06:39 +02:00
Nassim Jahnke 080dc18165 1.21.2-pre4 2024-10-15 15:08:36 +02:00
Nassim Jahnke 6fd421d36e Fix finish configuration state change 2024-10-15 15:08:36 +02:00
Nassim Jahnke 84bd1d0782 Use recipe inputs from old recipe packet 2024-10-15 15:08:36 +02:00
Nassim Jahnke cff2303c62 1.21.2-pre3 2024-10-15 15:08:36 +02:00
Nassim Jahnke f5733c2cb8 They fixed the typo 2024-10-15 15:08:36 +02:00
Nassim Jahnke 21fec0e263 1.21.2-pre2 2024-10-15 15:08:36 +02:00
RK_01 093acc519e Fix CONTAINER_SET_SLOT translation (#9) 2024-10-15 15:08:35 +02:00
RK_01 886be3161e Fix EXPLODE knockback check and affected blocks (#8) 2024-10-15 15:08:35 +02:00
RK_01 dc7b708556 Fix PLAYER_POSITION delta movement (#7) 2024-10-15 15:08:35 +02:00
Nassim Jahnke e82f28c1ac Rewrite particles 2024-10-15 15:08:35 +02:00
Nassim Jahnke 7c7239a70d 1.21.2-pre1 2024-10-15 15:08:35 +02:00
Nassim Jahnke 3e3dad9e33 Show notification on recipe add 2024-10-15 15:08:35 +02:00
Nassim Jahnke 4871977681 Fix recipe removal array index 2024-10-15 15:08:34 +02:00
Nassim Jahnke 0a56e57aec Send stonecutter recipes 2024-10-15 15:08:34 +02:00
Nassim Jahnke a6ff477b8a Implement clientbound ghost recipe, fix null recipe groups 2024-10-15 15:08:34 +02:00
Nassim Jahnke ddad0384f3 Make recipes mostly work again 2024-10-15 15:08:34 +02:00
Nassim Jahnke aabe47f8bc Start working on recipe rewriting 2024-10-15 15:08:34 +02:00
Nassim Jahnke 354a5f1b75 Update packet id comments 2024-10-15 15:08:34 +02:00
Nassim Jahnke f58afd434d WIP 24w40a 2024-10-15 15:08:34 +02:00
Nassim Jahnke 57d5652cd5 Remove SetWrapper, moved to addon 2024-10-15 15:08:33 +02:00
Nassim Jahnke 25b521dfcf Rewrite lock nbt 2024-10-15 15:08:33 +02:00
Nassim Jahnke ce655d0679 Use absolute day time value 2024-10-15 15:08:33 +02:00
Nassim Jahnke e4e8297a82 24w39a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 8357fd01aa Update attributes in item hover events 2024-10-15 15:08:33 +02:00
Nassim Jahnke 12b420d3e7 Send instrument registry, handle duration change from ticks to seconds 2024-10-15 15:08:33 +02:00
Nassim Jahnke db20bc0ae4 24w38a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 2a2afa3821 Register component rewriter 2024-10-15 15:08:32 +02:00
Nassim Jahnke f0b2d9aafe 24w37a 2024-10-15 15:08:32 +02:00
Nassim Jahnke cd427a2a39 Don't use -1 to indicate no vehicle 2024-10-15 15:08:32 +02:00
Nassim Jahnke 75537d3f85 Cancel player input if not in a vehicle, fix shift/sprint input 2024-10-15 15:08:32 +02:00
Nassim Jahnke a88e2f3fb5 Set impulse to 0.98 instead of 1 as per vanilla value 2024-10-15 15:08:32 +02:00
Nassim Jahnke 8a41e7add6 Remove new item data from serverbound items 2024-10-15 15:08:32 +02:00
Nassim Jahnke 9c35228287 24w36a 2024-10-15 15:08:32 +02:00
Nassim Jahnke f9ec6b9d03 Split holder implementation 2024-10-15 15:08:31 +02:00
Nassim Jahnke 22d396d909 Add item hover event handling 2024-10-15 15:08:31 +02:00
Nassim Jahnke 39b28e21ca 24w35a, including missed change from 33a 2024-10-15 15:08:31 +02:00
Nassim Jahnke 0488cb7fbe Fix item type in 1.21.2 entity data 2024-10-15 15:08:31 +02:00
Nassim Jahnke ec4aa0637e 24w34a 2024-10-15 15:08:31 +02:00
Nassim Jahnke ffc5584b1c Null check component rewriter 2024-10-15 15:08:31 +02:00
Nassim Jahnke 45c6cfedb0 Update mappings 2024-10-15 15:08:30 +02:00
Nassim Jahnke c150e50636 Store attribute mappings in full 2024-10-15 15:08:30 +02:00
Nassim Jahnke 16e32a62e5 Bump version to 5.1.0-SNAPSHOT 2024-10-15 15:08:27 +02:00
Nassim Jahnke 1d18f2e45e Fix container id conversion and itemrewriter explosion method 2024-10-15 15:08:20 +02:00
Nassim Jahnke e46b38e58a Remove outdated todos 2024-10-15 15:08:20 +02:00
Nassim Jahnke 033741d292 WIP 24w33a 2024-10-15 15:08:20 +02:00
Nassim Jahnke 7a3ef1e0b7 5.0.5 Release 2024-10-15 10:44:03 +02:00
Nassim Jahnke 5be41ed3e9 Use stripped key in tag getting
Fixes #4182
2024-10-14 21:35:10 +02:00
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
218 changed files with 5888 additions and 1745 deletions

No files matched your search

+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
+5 -5
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,9 +9,9 @@ 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:
@@ -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.
+4 -2
View File
@@ -19,13 +19,15 @@ dependencies {
api(libs.vianbt) {
exclude("it.unimi.dsi", "fastutil")
}
api(libs.gson)
api(libs.gson) {
exclude("com.google.errorprone", "error_prone_annotations")
}
implementation(rootProject.libs.text) {
exclude("com.google.code.gson", "gson")
exclude("com.viaversion", "nbt")
}
api(libs.snakeYaml)
compileOnlyApi(libs.snakeYaml)
compileOnlyApi(libs.netty)
compileOnlyApi(libs.guava)
compileOnlyApi(libs.checkerQual)
@@ -464,4 +464,18 @@ public interface ViaVersionConfig extends Config {
* @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
@@ -53,6 +53,14 @@ public interface FullMappings extends BiMappings {
*/
@Nullable String identifier(int id);
/**
* Returns the unmapped string identifier for the given mapped identifier.
*
* @param mappedIdentifier mapped identifier
* @return unmapped string identifier, or null if not found
*/
@Nullable String identifier(String mappedIdentifier);
/**
* Returns the mapped string identifier for the given mapped id.
*
@@ -83,6 +83,17 @@ public class FullMappingsBase implements FullMappings {
return Key.namespaced(identifier);
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
}
@Override
public String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
@@ -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.
*
@@ -122,10 +126,10 @@ public interface MappingData {
@Nullable Mappings getEnchantmentMappings();
@Nullable Mappings getAttributeMappings();
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getAttributeMappings();
@Nullable FullMappings getEntityMappings();
@Nullable FullMappings getArgumentTypeMappings();
@@ -43,10 +43,10 @@ public class MappingDataBase implements MappingData {
protected FullMappings entityMappings;
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings attributeMappings;
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected BiMappings attributeMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
@@ -76,8 +76,6 @@ public class MappingDataBase implements MappingData {
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
paintingMappings = loadMappings(data, "paintings");
attributeMappings = loadBiMappings(data, "attributes");
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
final CompoundTag mappedIdentifierData = readMappedIdentifiersFile("identifiers-" + mappedVersion + ".nbt");
@@ -87,6 +85,7 @@ public class MappingDataBase implements MappingData {
argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes");
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
@@ -203,6 +202,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;
@@ -262,7 +271,7 @@ public class MappingDataBase implements MappingData {
}
@Override
public @Nullable Mappings getAttributeMappings() {
public @Nullable FullMappings getAttributeMappings() {
return attributeMappings;
}
@@ -315,4 +324,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();
}
@@ -78,7 +78,7 @@ public interface DebugHandler {
/**
* Returns whether packets should be logged after being transformed.
* Set to true by default.
* Set to false by default.
*
* @return whether packets should be logged after being transformed
*/
@@ -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> {
/**
@@ -33,7 +35,7 @@ public interface Holder<T> {
* @throws IllegalArgumentException if the id is negative
*/
static <T> Holder<T> of(final int id) {
return new HolderImpl<>(id);
return new IdHolder<>(id);
}
/**
@@ -44,7 +46,7 @@ public interface Holder<T> {
* @return a new direct holder
*/
static <T> Holder<T> of(final T value) {
return new HolderImpl<>(value);
return new ValueHolder<>(value);
}
/**
@@ -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);
}
@@ -36,7 +36,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final String tagKey) {
return new HolderSetImpl(tagKey);
return new HolderSetImpl.Tag(tagKey);
}
/**
@@ -46,7 +46,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final int[] ids) {
return new HolderSetImpl(ids);
return new HolderSetImpl.Ids(ids);
}
/**
@@ -22,50 +22,63 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.Arrays;
final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet {
final class HolderSetImpl {
HolderSetImpl(final String tagKey) {
super(tagKey, null);
}
record Tag(String tagKey) implements HolderSet {
@Override
public boolean hasTagKey() {
return true;
}
HolderSetImpl(final int[] ids) {
super(null, ids);
}
@Override
public int[] ids() {
throw new IllegalArgumentException("This holder set has a tag key");
}
@Override
public String tagKey() {
return left();
}
@Override
public boolean hasIds() {
return false;
}
@Override
public boolean hasTagKey() {
return isLeft();
}
@Override
public int[] ids() {
return right();
}
@Override
public boolean hasIds() {
return isRight();
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
if (hasTagKey()) {
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
return this;
}
}
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.apply(ids[i]);
record Ids(int[] ids) implements HolderSet {
@Override
public boolean hasTagKey() {
return false;
}
@Override
public String tagKey() {
throw new IllegalArgumentException("This holder set has direct ids");
}
@Override
public boolean hasIds() {
return true;
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new Ids(mappedIds);
}
@Override
public String toString() {
return "Ids{" +
"ids=" + Arrays.toString(ids) +
'}';
}
return new HolderSetImpl(mappedIds);
}
}
@@ -23,49 +23,38 @@
package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
final class HolderImpl<T> implements Holder<T> {
record IdHolder<T>(int id) implements Holder<T> {
private final T value;
private final int id;
HolderImpl(final int id) {
IdHolder {
Preconditions.checkArgument(id >= 0, "id cannot be negative");
this.value = null;
this.id = id;
}
HolderImpl(final T value) {
this.value = value;
this.id = -1;
}
@Override
public boolean isDirect() {
return id == -1;
return false;
}
@Override
public boolean hasId() {
return id != -1;
return true;
}
@Override
public T value() {
Preconditions.checkArgument(isDirect(), "Holder is not direct");
return value;
throw new IllegalArgumentException("Holder is not direct");
}
@Override
public int id() {
return id;
}
@Override
public String toString() {
return "HolderImpl{" +
"value=" + value +
", id=" + id +
'}';
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
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);
}
}
@@ -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{" +
@@ -36,4 +36,8 @@ public record RegistryEntry(String key, @Nullable Tag tag) {
public RegistryEntry withKey(final String key) {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
public RegistryEntry copy() {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
record ValueHolder<T>(T value) implements Holder<T> {
@Override
public boolean isDirect() {
return true;
}
@Override
public boolean hasId() {
return false;
}
@Override
public int id() {
return -1;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
return this;
}
}
@@ -37,14 +37,14 @@ public class ChunkSectionImpl implements ChunkSection {
public ChunkSectionImpl(final boolean holdsLight) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
public ChunkSectionImpl(final boolean holdsLight, final int expectedPaletteLength) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE, expectedPaletteLength));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
@@ -35,7 +35,7 @@ public interface ChunkSectionLight {
/**
* Returns whether the section has sky light.
*
* @return true if skylight is present
* @return true if sky light is present
*/
boolean hasSkyLight();
@@ -43,7 +43,7 @@ public interface ChunkSectionLight {
* Returns whether the section has block light.
* This returns true unless specifically set to null.
*
* @return true if skylight is present
* @return true if block light is present
*/
boolean hasBlockLight();
@@ -30,9 +30,17 @@ public class ChunkSectionLightImpl implements ChunkSectionLight {
private NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSectionLightImpl() {
// Block light is always written
this.blockLight = new NibbleArray(ChunkSection.SIZE);
protected ChunkSectionLightImpl() {
}
public static ChunkSectionLight createWithBlockLight() {
final ChunkSectionLightImpl light = new ChunkSectionLightImpl();
light.blockLight = new NibbleArray(ChunkSection.SIZE);
return light;
}
public static ChunkSectionLight createEmpty() {
return new ChunkSectionLightImpl();
}
@Override
@@ -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 +
'}';
}
}
@@ -26,6 +26,7 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
@@ -34,13 +35,19 @@ import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
@@ -48,11 +55,13 @@ import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.util.Unit;
public record StructuredDataKey<T>(String identifier, Type<T> type) {
@@ -64,6 +73,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unbreakable> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG);
public static final StructuredDataKey<String> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.STRING);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Types.TAG_ARRAY);
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", Types.VAR_INT);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE);
@@ -78,10 +88,21 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Types.EMPTY);
public static final StructuredDataKey<Boolean> ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Types.BOOLEAN);
public static final StructuredDataKey<Tag> INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Types.TAG); // Doesn't actually hold data
public static final StructuredDataKey<FoodProperties> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_21_2> FOOD1_21_2 = new StructuredDataKey<>("food", FoodProperties1_21_2.TYPE);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE);
public static final StructuredDataKey<Item> USE_REMAINDER = new StructuredDataKey<>("use_remainder", Types1_21_2.ITEM);
public static final StructuredDataKey<UseCooldown> USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE);
public static final StructuredDataKey<Unit> FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY);
public static final StructuredDataKey<DamageResistant> DAMAGE_RESISTANT = new StructuredDataKey<>("damage_resistant", DamageResistant.TYPE);
public static final StructuredDataKey<ToolProperties> TOOL = new StructuredDataKey<>("tool", ToolProperties.TYPE);
public static final StructuredDataKey<Integer> ENCHANTABLE = new StructuredDataKey<>("enchantable", Types.VAR_INT);
public static final StructuredDataKey<Equippable> EQUIPPABLE = new StructuredDataKey<>("equippable", Equippable.TYPE);
public static final StructuredDataKey<HolderSet> REPAIRABLE = new StructuredDataKey<>("repairable", Types.HOLDER_SET);
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<String> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.STRING);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE);
public static final StructuredDataKey<DyedColor> DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE);
public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Types.INT);
@@ -90,9 +111,12 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> MAP_POST_PROCESSING = new StructuredDataKey<>("map_post_processing", Types.VAR_INT);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_20_5 = new StructuredDataKey<>("charged_projectiles", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21 = new StructuredDataKey<>("charged_projectiles", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21_2 = new StructuredDataKey<>("charged_projectiles", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_20_5 = new StructuredDataKey<>("bundle_contents", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21 = new StructuredDataKey<>("bundle_contents", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS = new StructuredDataKey<>("potion_contents", PotionContents.TYPE);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21_2 = new StructuredDataKey<>("bundle_contents", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_20_5 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_20_5);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_21_2 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_21_2);
public static final StructuredDataKey<SuspiciousStewEffect[]> SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", SuspiciousStewEffect.ARRAY_TYPE);
public static final StructuredDataKey<FilterableString[]> WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", FilterableString.ARRAY_TYPE);
public static final StructuredDataKey<WrittenBook> WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE);
@@ -101,7 +125,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<Holder<Instrument>> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.TYPE);
public static final StructuredDataKey<Holder<Instrument1_20_5>> INSTRUMENT1_20_5 = new StructuredDataKey<>("instrument", Instrument1_20_5.TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE);
public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Types.TAG);
@@ -115,6 +140,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<PotDecorations> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE);
public static final StructuredDataKey<Item[]> CONTAINER1_20_5 = new StructuredDataKey<>("container", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21 = new StructuredDataKey<>("container", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21_2 = new StructuredDataKey<>("container", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<Tag> LOCK = new StructuredDataKey<>("lock", Types.TAG);
@@ -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),
@@ -0,0 +1,314 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_2 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
PLAYER(LIVING_ENTITY),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
COW(ABSTRACT_ANIMAL),
MOOSHROOM(COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(ABSTRACT_CHESTED_HORSE),
MULE(ABSTRACT_CHESTED_HORSE),
LLAMA(ABSTRACT_CHESTED_HORSE),
TRADER_LLAMA(LLAMA),
// Monsters
ABSTRACT_MONSTER(PATHFINDER_MOB, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
BREEZE(ABSTRACT_MONSTER),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
CREAKING(ABSTRACT_MONSTER),
CREAKING_TRANSIENT(ABSTRACT_MONSTER),
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
BOGGED(ABSTRACT_SKELETON),
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
// Water mobs
AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null),
DOLPHIN(AGEABLE_WATER_CREATURE),
SQUID(AGEABLE_WATER_CREATURE),
GLOW_SQUID(SQUID),
WATER_ANIMAL(PATHFINDER_MOB, null),
ABSTRACT_FISH(WATER_ANIMAL, null),
PUFFERFISH(ABSTRACT_FISH),
TADPOLE(ABSTRACT_FISH),
ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null),
COD(ABSTRACT_SCHOOLING_FISH),
SALMON(ABSTRACT_SCHOOLING_FISH),
TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH),
// Raiders
ABSTRACT_RAIDER(ABSTRACT_MONSTER, null),
WITCH(ABSTRACT_RAIDER),
RAVAGER(ABSTRACT_RAIDER),
ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null),
SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null),
VINDICATOR(ABSTRACT_ILLAGER),
PILLAGER(ABSTRACT_ILLAGER),
EVOKER(SPELLCASTER_ILLAGER),
ILLUSIONER(SPELLCASTER_ILLAGER);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
EntityTypes1_21_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_2(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -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),
@@ -67,7 +67,7 @@ public interface EntityDataType {
@Override
public String toString() {
return "EntityDataType{" +
return "EntityDataTypeImpl{" +
"typeId=" + typeId +
", type=" + type +
'}';
@@ -26,10 +26,11 @@ import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
@@ -40,7 +41,7 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType = add(7, Types1_21.ITEM);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
@@ -65,8 +66,9 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType vector3FType = add(29, Types.VECTOR3F);
public final EntityDataType quaternionType = add(30, Types.QUATERNION);
public EntityDataTypes1_21(final ParticleType particleType, final ArrayType<Particle> particlesType) {
public EntityDataTypes1_21(final Type<Item> itemType, final ParticleType particleType, final ArrayType<Particle> particlesType) {
super(31);
this.itemType = add(7, itemType);
this.particleType = add(17, particleType);
this.particlesType = add(18, particlesType);
}
@@ -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) {
@@ -0,0 +1,111 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<SoundEvent> sound,
boolean hasConsumeParticles, ConsumeEffect<?>[] consumeEffects) {
public static final Type<?>[] EFFECT_TYPES = {
ApplyStatusEffects.TYPE,
Types.HOLDER_SET, // remove effects
Types.EMPTY, // clear all effects
Types.FLOAT, // teleport randomly
Types.SOUND_EVENT // play sound
};
public static final Type<Consumable1_21_2> TYPE = new Type<>(Consumable1_21_2.class) {
@Override
public Consumable1_21_2 read(final ByteBuf buffer) {
final float consumeSeconds = buffer.readFloat();
final int animationType = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final boolean hasConsumeParticles = buffer.readBoolean();
final ConsumeEffect<?>[] consumeEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects);
}
@Override
public void write(final ByteBuf buffer, final Consumable1_21_2 value) {
buffer.writeFloat(value.consumeSeconds);
Types.VAR_INT.writePrimitive(buffer, value.animationType);
Types.SOUND_EVENT.write(buffer, value.sound);
buffer.writeBoolean(value.hasConsumeParticles);
ConsumeEffect.ARRAY_TYPE.write(buffer, value.consumeEffects);
}
};
public record ConsumeEffect<T>(int id, Type<T> type, T value) {
public static final Type<ConsumeEffect<?>> TYPE = new Type<>(ConsumeEffect.class) {
@Override
public ConsumeEffect<?> read(final ByteBuf buffer) {
// Oh no...
final int effectType = Types.VAR_INT.readPrimitive(buffer);
final Type<?> type = EFFECT_TYPES[effectType];
final Object value = type.read(buffer);
return ConsumeEffect.of(effectType, type, value);
}
@Override
public void write(final ByteBuf buffer, final ConsumeEffect<?> value) {
Types.VAR_INT.writePrimitive(buffer, value.id);
value.writeValue(buffer);
}
};
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE = new ArrayType<>(TYPE);
static <T> ConsumeEffect<T> of(final int id, final Type<T> type, final Object value) {
//noinspection unchecked
return new ConsumeEffect<>(id, type, (T) value);
}
void writeValue(final ByteBuf buf) {
this.type.write(buf, this.value);
}
}
public record ApplyStatusEffects(PotionEffect[] effects, float probability) {
public static final Type<ApplyStatusEffects> TYPE = new Type<>(ApplyStatusEffects.class) {
@Override
public ApplyStatusEffects read(final ByteBuf buffer) {
final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer);
final float probability = buffer.readFloat();
return new ApplyStatusEffects(effects, probability);
}
@Override
public void write(final ByteBuf buffer, final ApplyStatusEffects value) {
PotionEffect.ARRAY_TYPE.write(buffer, value.effects);
buffer.writeFloat(value.probability);
}
};
}
}
@@ -25,32 +25,19 @@ 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 record DamageResistant(String typesTagKey) {
public static final Type<MapDecorations> TYPE = new Type<>(MapDecorations.class) {
public static final Type<DamageResistant> TYPE = new Type<>(DamageResistant.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);
public DamageResistant read(final ByteBuf buffer) {
final String typesTagKey = Types.STRING.read(buffer);
return new DamageResistant(typesTagKey);
}
@Override
public void write(final ByteBuf buffer, final 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());
}
public void write(final ByteBuf buffer, final DamageResistant value) {
Types.STRING.write(buffer, value.typesTagKey());
}
};
}
@@ -22,26 +22,23 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2.ConsumeEffect;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodEffect(PotionEffect effect, float probability) {
public record DeathProtection(ConsumeEffect<?>[] deathEffects) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
public static final Type<DeathProtection> TYPE = new Type<>(DeathProtection.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
public DeathProtection read(final ByteBuf buffer) {
final ConsumeEffect<?>[] deathEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new DeathProtection(deathEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
public void write(final ByteBuf buffer, final DeathProtection value) {
ConsumeEffect.ARRAY_TYPE.write(buffer, value.deathEffects);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
@@ -0,0 +1,69 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Nullable String model,
@Nullable String cameraOverlay, @Nullable HolderSet allowedEntities, boolean dispensable,
boolean swappable, boolean damageOnHurt) {
public static final Type<Equippable> TYPE = new Type<>(Equippable.class) {
@Override
public Equippable read(final ByteBuf buffer) {
final int equipmentSlot = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final String model = Types.OPTIONAL_STRING.read(buffer);
final String cameraOverlay = Types.OPTIONAL_STRING.read(buffer);
final HolderSet allowedEntities = Types.HOLDER_SET.read(buffer);
final boolean dispensable = buffer.readBoolean();
final boolean swappable = buffer.readBoolean();
final boolean damageOnHurt = buffer.readBoolean();
return new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
@Override
public void write(final ByteBuf buffer, final Equippable value) {
Types.VAR_INT.writePrimitive(buffer, value.equipmentSlot());
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.OPTIONAL_STRING.write(buffer, value.model());
Types.OPTIONAL_STRING.write(buffer, value.cameraOverlay());
Types.HOLDER_SET.write(buffer, value.allowedEntities());
buffer.writeBoolean(value.dispensable());
buffer.writeBoolean(value.swappable());
buffer.writeBoolean(value.damageOnHurt());
}
};
public Equippable rewrite(final Int2IntFunction soundIdRewriter) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriter);
return soundEvent == this.soundEvent ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
}
@@ -25,25 +25,26 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import io.netty.buffer.ByteBuf;
public record FoodProperties(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
Item usingConvertsTo, FoodEffect[] possibleEffects) {
public record FoodProperties1_20_5(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
Item usingConvertsTo, FoodEffect[] possibleEffects) {
public static final Type<FoodProperties> TYPE1_20_5 = new Type<>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_20_5 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -51,20 +52,20 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public static final Type<FoodProperties> TYPE1_21 = new Type<FoodProperties>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_21 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final Item usingConvertsTo = Types1_21.OPTIONAL_ITEM.read(buffer);
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -73,4 +74,23 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public record FoodEffect(PotionEffect effect, float probability) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodProperties1_21_2(int nutrition, float saturationModifier, boolean canAlwaysEat) {
public static final Type<FoodProperties1_21_2> TYPE = new Type<>(FoodProperties1_21_2.class) {
@Override
public FoodProperties1_21_2 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
return new FoodProperties1_21_2(nutrition, saturationModifier, canAlwaysEat);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties1_21_2 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
}
};
}
@@ -27,24 +27,29 @@ 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) {
public record Instrument1_20_5(Holder<SoundEvent> soundEvent, int useDuration, float range) {
public static final HolderType<Instrument> TYPE = new HolderType<>() {
public static final HolderType<Instrument1_20_5> TYPE = new HolderType<>() {
@Override
public Instrument readDirect(final ByteBuf buffer) {
public Instrument1_20_5 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final int useDuration = Types.VAR_INT.readPrimitive(buffer);
final float range = buffer.readFloat();
return new Instrument(soundEvent, useDuration, range);
final float range = Types.FLOAT.readPrimitive(buffer);
return new Instrument1_20_5(soundEvent, useDuration, range);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument value) {
public void writeDirect(final ByteBuf buffer, final Instrument1_20_5 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.VAR_INT.writePrimitive(buffer, value.useDuration());
buffer.writeFloat(value.range());
Types.FLOAT.writePrimitive(buffer, value.range());
}
};
public Instrument1_20_5 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range);
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration, float range, Tag description) {
public static final HolderType<Instrument1_21_2> TYPE = new HolderType<>() {
@Override
public Instrument1_21_2 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final float useDuration = Types.FLOAT.readPrimitive(buffer);
final float range = Types.FLOAT.readPrimitive(buffer);
final Tag description = Types.TAG.read(buffer);
return new Instrument1_21_2(soundEvent, useDuration, range, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument1_21_2 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.FLOAT.writePrimitive(buffer, value.useDuration());
Types.FLOAT.writePrimitive(buffer, value.range());
Types.TAG.write(buffer, value.description());
}
};
public Instrument1_21_2 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description);
}
}
@@ -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);
}
}
}
@@ -27,15 +27,20 @@ import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects) {
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects,
@Nullable String customName) {
public static final Type<PotionContents> TYPE = new Type<>(PotionContents.class) {
public PotionContents(final @Nullable Integer potion, final @Nullable Integer customColor, final PotionEffect[] customEffects) {
this(potion, customColor, customEffects, null);
}
public static final Type<PotionContents> TYPE1_20_5 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
return new PotionContents(potion, customColor, customEffects);
return new PotionContents(potion, customColor, customEffects, null);
}
@Override
@@ -53,4 +58,31 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
}
};
public static final Type<PotionContents> TYPE1_21_2 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
final String customName = Types.OPTIONAL_STRING.read(buffer);
return new PotionContents(potion, customColor, customEffects, customName);
}
@Override
public void write(final ByteBuf buffer, final PotionContents value) {
buffer.writeBoolean(value.potion != null);
if (value.potion != null) {
Types.VAR_INT.writePrimitive(buffer, value.potion);
}
buffer.writeBoolean(value.customColor != null);
if (value.customColor != null) {
buffer.writeInt(value.customColor);
}
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
Types.OPTIONAL_STRING.write(buffer, value.customName);
}
};
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public record UseCooldown(float seconds, @Nullable String cooldownGroup) {
public static final Type<UseCooldown> TYPE = new Type<>(UseCooldown.class) {
@Override
public UseCooldown read(final ByteBuf buffer) {
final float seconds = buffer.readFloat();
final String cooldownGroup = Types.OPTIONAL_STRING.read(buffer);
return new UseCooldown(seconds, cooldownGroup);
}
@Override
public void write(final ByteBuf buffer, final UseCooldown value) {
buffer.writeFloat(value.seconds());
Types.OPTIONAL_STRING.write(buffer, value.cooldownGroup());
}
};
public UseCooldown rewrite(final Function<String, String> idRewriter) {
if (cooldownGroup == null) {
return this;
}
final String mappedCooldownGroup = idRewriter.apply(cooldownGroup);
return new UseCooldown(seconds, mappedCooldownGroup);
}
}
@@ -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;
}
}
@@ -198,6 +198,14 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
public void registerFinishConfiguration(final CU packetType, final PacketHandler handler) {
registerClientbound(packetType, wrapper -> {
// TODO Temporary solution to handle the finish configuration packet already having changed our tracked protocol state in a previous handler
wrapper.user().getProtocolInfo().setServerState(State.CONFIGURATION);
handler.handle(wrapper);
});
}
@Override
public final void loadMappingData() {
getMappingData().load();
@@ -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));
}
/**
@@ -43,7 +43,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private static final List<ProtocolVersion> VERSION_LIST = new ArrayList<>();
public static final ProtocolVersion v1_7_2 = register(4, "1.7.2-1.7.5", new SubVersionRange("1.7", 2, 5));
@Deprecated(forRemoval=true) public static final ProtocolVersion v1_7_1 = v1_7_2;
@Deprecated(forRemoval = true)
public static final ProtocolVersion v1_7_1 = v1_7_2;
public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10));
public static final ProtocolVersion v1_8 = register(47, "1.8.x", new SubVersionRange("1.8", 0, 9));
public static final ProtocolVersion v1_9 = register(107, "1.9");
@@ -84,9 +85,14 @@ 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 v1_21_2 = register(768, "1.21.2-1.21.3", new SubVersionRange("1.21", 2, 3));
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
unknown.known = false;
}
public static ProtocolVersion register(int version, String name) {
return register(version, -1, name);
}
@@ -150,7 +156,11 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
return protocolVersion;
}
}
return new ProtocolVersion(VersionType.SPECIAL, version, -1, "Unknown (" + version + ")", null);
// Will be made nullable instead in the future...
final ProtocolVersion unknown = new ProtocolVersion(versionType, version, -1, "Unknown (" + version + ")", null);
unknown.known = false;
return unknown;
}
public static @NonNull ProtocolVersion getProtocol(final int version) {
@@ -201,6 +211,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private final int snapshotVersion;
private final String name;
private final Set<String> includedVersions;
@Deprecated // Remove when getProtocol is made nullable
private boolean known = true;
/**
* Constructs a new ProtocolVersion instance.
@@ -285,12 +297,12 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
}
/**
* Returns whether the protocol is set. Should only be unknown for unregistered protocols returned by {@link #getProtocol(int)}.
* Returns whether the protocol version is {@link #unknown}. For checking if the protocol version is registered, use {@link #isRegistered(VersionType, int)}
*
* @return true if the protocol is set
* @return true if the protocol version is unknown
*/
public boolean isKnown() {
return version != -1;
return known;
}
/**
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
@@ -50,6 +51,8 @@ public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T
@Nullable
Item handleItemToServer(UserConnection connection, @Nullable Item item);
void rewriteParticle(UserConnection connection, Particle particle);
/**
* Returns the item type of the current protocol.
*
@@ -189,7 +189,9 @@ public final class Types {
public static final Type<PlayerMessageSignature> OPTIONAL_PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType.OptionalPlayerMessageSignatureType();
public static final Type<PlayerMessageSignature[]> PLAYER_MESSAGE_SIGNATURE_ARRAY = new ArrayType<>(PLAYER_MESSAGE_SIGNATURE);
public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_19_3 = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_21_2 = new BitSetType(7);
public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256);
public static final BitSetType ACKNOWLEDGED_BIT_SET = new BitSetType(20);
public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256);
@@ -36,11 +36,19 @@ public class IntType extends Type<Integer> implements TypeConverter<Integer> {
return buffer.readInt();
}
public int readPrimitive(ByteBuf buffer) {
return buffer.readInt();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeInt(object);
}
public void writePrimitive(ByteBuf buffer, int object) {
buffer.writeInt(object);
}
@Override
public Integer from(Object o) {
if (o instanceof Number number) {
@@ -87,5 +87,12 @@ public class StructuredDataType extends Type<StructuredData<?>> {
types[id] = key;
return this;
}
public DataFiller add(final StructuredDataKey<?>... keys) {
for (final StructuredDataKey<?> key : keys) {
add(key);
}
return this;
}
}
}
@@ -77,6 +77,10 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST_TRANSITION = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Red 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green 0-1
@@ -86,6 +90,11 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue
};
public static final DataReader<Particle> DUST_TRANSITION1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // From RGB
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // To RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> VIBRATION = (buf, particle) -> {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // From block pos
@@ -136,7 +145,15 @@ public class ParticleType extends DynamicType<Particle> {
public static final DataReader<Particle> SHRIEK = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Delay
};
public static final DataReader<Particle> COLOR = (buf, particle) -> particle.add(Types.INT, buf.readInt());
public static final DataReader<Particle> COLOR = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf));
};
public static final DataReader<Particle> TRAIL = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target X
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target Y
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target Z
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -50,7 +50,7 @@ public final class Types1_21 {
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(PARTICLE, PARTICLES);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5;
import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5;
import com.viaversion.viaversion.api.type.types.item.StructuredDataType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import java.util.List;
// Most of these are only safe to use after protocol loading
public final class Types1_21_2 {
public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType();
public static final Type<StructuredData<?>[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA);
public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA);
public static final Type<Item> OPTIONAL_ITEM = ITEM.new OptionalItemType(); // Optional as in boolean prefixed, not via the amount
public static final Type<Item[]> ITEM_ARRAY = new ArrayType<>(ITEM);
public static final Type<Item> ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY);
public static final Type<Item> OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST);
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
+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) {
@@ -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;
}
}
@@ -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;
@@ -179,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)
}
@@ -210,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) {
@@ -220,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
@@ -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,14 +25,14 @@ 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 {
@@ -94,6 +94,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
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);
@@ -161,6 +163,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
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() {
@@ -542,4 +546,14 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
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;
@@ -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,7 +74,9 @@ 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_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3;
import com.viaversion.viaversion.protocols.v1_9_3to1_10.Protocol1_9_3To1_10;
@@ -109,14 +111,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 +140,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);
@@ -190,6 +193,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_20_3To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_20_3);
registerProtocol(new Protocol1_20_5To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_20_5);
registerProtocol(new Protocol1_21To1_21_2(), ProtocolVersion.v1_21_2, ProtocolVersion.v1_21);
}
@Override
@@ -234,7 +238,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 +247,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 +281,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 +375,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 +538,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 {
@@ -55,4 +57,11 @@ 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());
@@ -23,11 +23,14 @@ import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
public enum ClientboundLoginPackets implements BaseClientboundPacket {
LOGIN_DISCONNECT, // 0x00
HELLO, // 0x01
GAME_PROFILE, // 0x02
LOGIN_FINISHED, // 0x02
LOGIN_COMPRESSION, // 0x03
CUSTOM_QUERY, // 0x04
COOKIE_REQUEST; // 0x05
@Deprecated(forRemoval = true)
public static final ClientboundLoginPackets GAME_PROFILE = LOGIN_FINISHED;
@Override
public final int getId() {
return ordinal();
@@ -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,19 +43,24 @@ 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
@@ -89,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
@@ -118,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) {
@@ -162,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
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 -> {
// Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.LOGIN_FINISHED, 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;
}
}
@@ -0,0 +1,80 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.protocols.v1_20_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.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
// To replace if needed:
// ChunkType1_20_2
// RecipeRewriter1_20_3
// Types1_21, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21, ServerboundPacket1_20_5, Protocol1_99To_98> {
public BlockItemPacketRewriter1_99(final Protocol1_99To_98 protocol) {
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
public void registerPackets() {
// Register block and block state id changes
// Other places using block state id mappings: Spawn particle, entity data, entity spawn (falling blocks)
// Tags and statistics use block (!) ids
final BlockRewriter<ClientboundPacket1_21> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA);
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration
//protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem);
registerCooldown1_21_2(ClientboundPackets1_21.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT);
registerContainerClick1_21_2(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
registerExplosion1_21_2(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
final RecipeDisplayRewriter<ClientboundPacket1_21> recipeRewriter = new RecipeDisplayRewriter<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21.UPDATE_RECIPES);
//recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21.PLACE_GHOST_RECIPE);
// OR do this if serialization of recipes changed and override the relevant method
// Add new serializers to RecipeDisplayRewriter, or extend the last one for changes
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
public final class ComponentRewriter1_99 extends ComponentRewriter<ClientboundPacket1_21> {
public ComponentRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, ReadType.NBT);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
// Remove or update data from componentsTag
}
@Override
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_20_5;
}
}
@@ -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;
@@ -24,66 +24,80 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
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);
private final ComponentRewriter1_99 componentRewriter = new ComponentRewriter1_99(this);
public Protocol1_99To_98() {
// Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted
super(ClientboundPacket1_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);
// If needed for item or component changes
componentRewriter.registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21.PLAYER_COMBAT_KILL);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SYSTEM_CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISGUISED_CHAT);
componentRewriter.registerPlayerInfoUpdate1_21_2(ClientboundPackets1_21.PLAYER_INFO_UPDATE);
componentRewriter.registerPing();
new StatisticsRewriter<>(this).register(ClientboundPackets1_20_5.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_20_5.UPDATE_ATTRIBUTES);
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_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);*/
}.registerDeclareCommands1_19(ClientboundPackets1_21.COMMANDS);*/
}
@Override
@@ -92,16 +106,19 @@ 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)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION)
.reader("item", ParticleType.Readers.ITEM1_20_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK);*/
/*Types1_21_2.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST1_21_2)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION1_21_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK)
.reader("entity_effect", ParticleType.Readers.COLOR)
.reader("trail", ParticleType.Readers.TRAIL)
.reader("item", ParticleType.Readers.item(itemRewriter.mappedItemType()));*/
super.onMappingDataLoaded(); // Calls load methods on rewriters. Last in case the rewriters access the above filled data
}
@@ -130,17 +147,22 @@ 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() {
public ComponentRewriter getComponentRewriter() {
return componentRewriter;
}
@Override
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)
);
}
}
}
@@ -99,7 +99,7 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
});
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
Chunk chunk = wrapper.passthrough(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()));
@@ -120,31 +120,6 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
}
});
registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
}
});
registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
this.registerClientbound(ClientboundPackets1_9_3.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
@@ -238,11 +213,8 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_11(userConnection));
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld());
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff. Show more