Compare commits

...
358 Commits
Author SHA1 Message Date
Nassim Jahnke b67d7c076f Fix dust/dust_color_transition particles in biome data
Fixes #926
2024-12-05 17:16:57 +01:00
Nassim Jahnke 9d5cd04d4b Always update storage data 2024-11-27 21:50:46 +01:00
Nassim Jahnke 30499c8b30 Fix entity teleport for non-self in 1.21.2->1.21.1
Fixes #922
2024-11-27 21:47:40 +01:00
Nassim Jahnke fb328d4753 Fix recipe removal 2024-11-26 18:16:42 +01:00
Nassim Jahnke 5347820c28 Fix typo 2024-11-25 10:18:16 +01:00
Nassim Jahnke c4af653e42 Fix 1.21 client-sent food using_converts_to handling 2024-11-25 10:17:10 +01:00
github-actions[bot]andgradle-update-robot 5240487a35 Update Gradle Wrapper from 8.11 to 8.11.1 (#920)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-11-24 02:09:33 +01:00
EnZaXDandNassim Jahnke 276953f6cb Backup inconvertible item component data for creative clients in 1.21+ (#907)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2024-11-22 10:36:42 +01:00
EnZaXD 1dfef5b97e Emulate block and item display entities in 1.19.4->1.19.3 (#871) 2024-11-18 14:38:20 +01:00
Nassim Jahnke 4a9c98aa1b Address Gradle deprecation warnings 2024-11-17 13:45:25 +01:00
github-actions[bot]andgradle-update-robot 07e2848e5b Update Gradle Wrapper from 8.10.2 to 8.11 (#917)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-11-17 12:23:33 +01:00
Gero 1db6824391 Fix remapping of 1.21.3 PLAYER_INFO_UPDATE list order (#915) 2024-11-11 17:01:35 +01:00
Nassim Jahnke 82a7c9bc3d Update VV usage 2024-11-11 15:00:34 +01:00
Nassim Jahnke 3a67be7fe5 Don't forget to rewrite item in set cursor and set player inventory 2024-11-08 17:25:40 +01:00
EnZaXD 8cb285db69 Change darkness->blindness in 1.19->1.18.2 (#908) 2024-11-07 09:18:33 +01:00
EnZaXD 04a692022a Move config option check for player face fix into packet handlers (#913) 2024-11-07 09:11:38 +01:00
Nassim Jahnke 498bec9065 Remove 'has recipe error' container data from smithing table
Fixes #909
2024-11-05 20:20:27 +01:00
Nassim Jahnke ab2a407742 Bump version to 5.1.2-SNAPSHOT 2024-11-05 20:18:30 +01:00
Nassim Jahnke cfad15a9b2 5.1.1 Release 2024-11-01 19:00:56 +01:00
EnZaXDandNassim Jahnke 2c3c62d246 Update VV API usage (#906)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2024-11-01 18:58:44 +01:00
Nassim Jahnke d6c27add17 Add viaproxy jvm flags 2024-10-30 21:07:30 +01:00
RK_01 7b5ee01929 Fix SET_CURSOR_ITEM container id type (#905) 2024-10-30 17:05:57 +01:00
Nassim Jahnke c7a5de1176 Write inventory id as unsigned byte... 2024-10-30 16:52:52 +01:00
Nassim Jahnke 16aa6a51a2 Fix issues with creaking entity data
Fixes #904
2024-10-30 10:21:04 +01:00
EnZaXD 562651cd9d [ci skip] Add component rewriter to template (#903) 2024-10-30 10:20:24 +01:00
EnZaXD 3e8086e136 Add gradle task to quickly test/debug code changes (#902) 2024-10-29 15:00:34 +01:00
Nassim Jahnke 368f450e11 Remove lock item data in component rewriter 2024-10-29 13:38:01 +01:00
Nassim Jahnke 80b530a368 Fix trail particle handling 2024-10-29 13:33:16 +01:00
Nassim Jahnke d2d1d0014f Remove instrument registry
Some older clients don't like unknown registries
2024-10-29 12:45:56 +01:00
Nassim Jahnke 5a576d66b4 Update item type in area effect cloud particles in 1.13.2->1.13.1 2024-10-28 12:21:57 +01:00
EnZaXD a94d06716c Use new ParticleRewriter (#901) 2024-10-28 11:28:12 +01:00
Nassim Jahnke 8af8319839 Small cleanup 2024-10-27 23:25:00 +01:00
EnZaXD 927ffaf20a Correctly update action bits in PLAYER_INFO_UPDATE in 1.21.2->1.21 (#899) 2024-10-26 14:07:13 +02:00
Nassim Jahnke 31d5a98f26 5.1.0 Release 2024-10-25 18:15:16 +02:00
Nassim Jahnke b3c1266da7 Update ChunkSectionLightImpl call 2024-10-25 18:09:02 +02:00
Nassim Jahnke 0a6d143d92 Remove baby index via parent type 2024-10-24 16:56:54 +02:00
Nassim Jahnke b1f4a88050 Fix 1.20.5->1.20.3 darkness effect transition 2024-10-23 21:26:12 +02:00
FlorianMichael 4f119d26d7 Update version ranges in gradle.properties 2024-10-23 16:27:14 +02:00
Nassim Jahnke afb8384319 Enable bundle feature 2024-10-22 18:42:43 +02:00
Nassim Jahnke f27c977be2 Back to onenable tasks 2024-10-22 18:10:18 +02:00
RK_01 90878517db Fix CLIENT_INFORMATION skin flags data type (#4) 2024-10-22 10:26:05 +02:00
RK_01 a0f2a8595e Fix PLAYER_INFO_UPDATE display name data type (#5) 2024-10-22 10:25:43 +02:00
Nassim Jahnke 2ce11704ba Register tasks in the right place 2024-10-20 19:48:26 +02:00
Nassim Jahnke 0827b6f6bb Handle player info components in 1.20.5->1.20.3 2024-10-19 13:17:13 +02:00
Nassim Jahnke 1c7017a056 Pass position/rotation values directly, fix relative position and rotation handling 2024-10-19 13:10:54 +02:00
FlorianMichael 4d4f66a1a2 Emulate PLAYER_INPUT packet as well 2024-10-19 02:28:26 +02:00
FlorianMichael f274d643a5 Emulate CLIENT_TICK_END packet 2024-10-19 01:47:38 +02:00
FlorianMichael c7324b1b35 Use SET_ENTITY_MOTION and EXPLODE for delta movement translation 2024-10-19 01:19:22 +02:00
FlorianMichael c8ec145880 Always use correct PROFILE_ACTIONS_ENUM from VV types 2024-10-18 23:20:36 +02:00
FlorianMichael 30d3b0d02e Handle new relative arguments in PLAYER_POSITION and TELEPORT_ENTITY 2024-10-18 23:05:41 +02:00
FlorianMichael 545365786f Handle PLAYER_ROTATION packet using PLAYER_LOOK_AT 2024-10-18 21:57:06 +02:00
Nassim Jahnke 1b9d53af2a Create tag if needed 2024-10-17 19:44:37 +02:00
Nassim Jahnke fd85b67a92 Sort recipes 2024-10-17 17:06:56 +02:00
Nassim Jahnke 16eca5f6aa 1.21.2-pre3 2024-10-14 17:55:19 +02:00
Nassim Jahnke c57b238b86 Recipes mostly work now 2024-10-14 17:55:19 +02:00
Nassim Jahnke 5646d04ba9 1.21.2-pre1 2024-10-14 17:55:19 +02:00
Nassim Jahnke 4937ec4800 Start working on recipes 2024-10-14 17:55:19 +02:00
Nassim Jahnke d3be34adc9 Very WIP 24w40a 2024-10-14 17:55:19 +02:00
Nassim Jahnke 49febd1e63 Fix vehicle exiting 2024-10-14 17:55:18 +02:00
Nassim Jahnke 8737b2b51a 24w39a 2024-10-14 17:55:18 +02:00
Nassim Jahnke 1876b9bb95 Convert attributes in item hover event 2024-10-14 17:55:18 +02:00
Nassim Jahnke f2fcc9d02f 24w38a 2024-10-14 17:55:18 +02:00
Nassim Jahnke d0eeae92d3 24w37a 2024-10-14 17:55:18 +02:00
Nassim Jahnke be28d0c3e8 24w36a, mostly 2024-10-14 17:55:18 +02:00
Nassim Jahnke b0276eaa7d Handle item hover events 2024-10-14 17:55:17 +02:00
Nassim Jahnke 6b690a0218 Remove baby entity data from changed water animals 2024-10-14 17:55:17 +02:00
Nassim Jahnke 4bcc213f1b Handle item tags in recipe ingredients 2024-10-14 17:55:17 +02:00
Nassim Jahnke ff94019b08 Actually track inventory state id 2024-10-14 17:55:17 +02:00
Nassim Jahnke 681e8a2f07 Working 24w34a 2024-10-14 17:55:17 +02:00
Nassim Jahnke 5269a610d1 More work 2024-10-14 17:55:17 +02:00
Nassim Jahnke 5cd34e6fa8 WIP 24w33a 2024-10-14 17:55:16 +02:00
Nassim Jahnke 752c5fc48b Bump version to 5.1.0-SNAPSHOT 2024-10-14 17:55:14 +02:00
Nassim Jahnke a08de7ccc3 5.0.4 Release 2024-10-14 17:25:39 +02:00
EnZaXD cb9179c873 Update required ViaFabric version, don't require fabric-loader (#895) 2024-10-10 12:45:14 +02:00
EnZaXD 904c83f341 Define as Sponge plugin for ViaSponge (#892) 2024-10-02 10:43:15 +02:00
Nassim Jahnke f4253641e1 Update VV usage 2024-09-29 13:42:26 +02:00
github-actions[bot]andgradle-update-robot 1d1e9bc040 Update Gradle Wrapper from 8.10.1 to 8.10.2 (#891)
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:27 +02:00
dependabot[bot] f57f22502e Bump gradle-update/update-gradle-wrapper-action from 1 to 2 (#889)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-25 17:11:36 +02:00
EnZaXD b376b52ce8 Refactor dimension switch handling across all protocols (#884) 2024-09-15 22:09:03 +02:00
EnZaXD 36baf6ed24 Fix body set equipment in 1.20.5->.3 if value is not the last (#886) 2024-09-15 19:17:45 +02:00
github-actions[bot]andgradle-update-robot 733bd9aa9b Update Gradle Wrapper from 8.10 to 8.10.1 (#885)
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:23 +02:00
EnZaXD 66a1748573 Remove transaction tracking (and cancelling) in 1.17->1.16.4 (#883) 2024-09-12 14:45:44 +02:00
Nassim Jahnke 0bac9201ac Don't remove configuration packet storage on login
Needed with proxies if a server is doing nonstandard optimizations
Fixes #881
2024-09-08 11:12:34 +02:00
EnZaXD ffb98523e6 Don't process component twice in 1.19.4->1.19.3 text display handler (#878) 2024-08-30 21:05:03 +02:00
Nassim Jahnke 830ccce303 Update VV usage 2024-08-30 19:45:02 +02:00
Nassim Jahnke a5d0e4baff Strip new attributes in 1.21->1.20.5 item hover events 2024-08-30 11:05:07 +02:00
Nassim Jahnke 4066b9b52b More cleanup to structured enchantment rewriter 2024-08-29 19:53:47 +02:00
Nassim Jahnke 678775ab9d Move the iterator remove down 2024-08-29 19:45:43 +02:00
Nassim Jahnke db47040543 Fix 1.21->1.20.5 enchantment lore format and add show_in_tooltip check
Fixes #877
2024-08-29 19:18:43 +02:00
EnZaXD 47b1508f66 Clean up LOGIN/STATUS/CONFIGURATION handlers (#876) 2024-08-28 15:55:40 +02:00
Nassim Jahnke 6cc4990b6e Update VV usage 2024-08-25 19:03:59 +02:00
Nassim Jahnke d6279757bb Also explicitly map entity data list type in 1.12 2024-08-24 17:20:42 +02:00
EnZaXD 24f67ffe80 Fix compressed id overlap in legacy block item rewriter (#874) 2024-08-20 16:12:19 +02:00
Nassim Jahnke 0b3a792a51 Properly read unused light data in 1.17->1.16
Some servers for some reason do this
2024-08-18 15:13:51 +02:00
github-actions[bot]andgradle-update-robot ef2621c917 Update Gradle Wrapper from 8.9 to 8.10 (#872)
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:33:23 +02:00
Nassim Jahnke eb4d30ae73 Always map command to signed command in 1.20.5->1.20.3
Sending any message, any non-message command, and again any message would kick the client with a chat validation error. Let's see if this is better
2024-08-15 13:35:37 +02:00
Nassim Jahnke 9ca523620d Map wind charges to shulker bullets instead of llama spit
Spit has gravity by default and a short lifespan
Fixes #868
2024-08-15 13:10:48 +02:00
EnZaXD 4f7acf211b [ci skip] Setup dependabot for GH Actions and add workflow for updati… (#867) 2024-08-14 15:14:11 +02:00
EnZaXD 585ab030b5 [ci skip] Link to our new website instead (#866) 2024-08-14 09:53:38 +02:00
Nassim Jahnke 5ce7857d49 Actually remove template submodule 2024-08-14 09:52:24 +02:00
Nassim Jahnke 5539ff99cb Update supported version range 2024-08-14 09:48:54 +02:00
Nassim Jahnke c2b5a5f545 Update template protocol classes 2024-08-14 09:42:32 +02:00
EnZaXD 9c3255d5a4 Only play totem animation for dying player in 1.11->1.10 (#860) 2024-08-14 09:38:27 +02:00
EnZaXD b03be8ecfe Properly handle custom item data in 1.20.5->1.20.3 (#865) 2024-08-14 09:36:44 +02:00
Nassim Jahnke 609205f9fd [ci skip] Update shadow 2024-08-08 10:45:56 +02:00
Nassim Jahnke 4c56605ca0 5.0.3 Release 2024-08-07 17:56:17 +02:00
Nassim Jahnke 55ea81f9c7 Hotfix item ids in 1.21 item hover events 2024-08-07 17:37:24 +02:00
Kichura 9c2021b947 Update Ubuntu, Change wrapper-validation in publish (#857) 2024-08-07 15:25:13 +02:00
EnZaXD ad1b8b71a5 Rename CI workflow and update gradle wrapper validation (#855) 2024-08-07 13:03:15 +02:00
Nassim Jahnke 6a766f2467 Handle custom armor trims in 1.20.5->1.20.3
Fixes #847, closes #850
2024-08-07 12:47:26 +02:00
Nassim Jahnke 87d05ae487 Only change container data for enchantment tables
Fixes #853
2024-08-06 15:37:28 +02:00
EnZaXD 29a7b01937 Use GH repository description in platforms and README.md file (#851) 2024-08-05 09:09:43 +02:00
EnZaXD bc06d9ecc1 Handle experience orb spawn via add entity packet in 1.14->1.13.2 (#849) 2024-08-03 10:41:03 +02:00
EnZaXD a0d063d93e Handle data->pitch/yaw item frame rotation change in 1.17->1.16.4 (#848) 2024-08-02 10:29:54 +02:00
EnZaXD 24f994ff2a Convert components in sign block entities in 1.12->1.11 (#845) 2024-07-31 18:21:42 +02:00
Nassim Jahnke f4bc485408 Only create custom data tag in enchantment rewriter if necessary 2024-07-31 17:07:45 +02:00
Nassim Jahnke b4a4b540cc Always remap body armor slot 2024-07-30 22:39:56 +02:00
Nassim Jahnke 8add9677a8 Bump version to 5.0.3-SNAPSHOT 2024-07-30 22:35:57 +02:00
Nassim Jahnke 9fed88c1a3 5.0.2 Release 2024-07-28 14:38:59 +02:00
EnZaXD 2df954de90 Cleanup 1.20.5->1.20.3 SET_EQUIPMENT translation (#841) 2024-07-27 21:47:30 +02:00
EnZaXD d3721307b1 Cleanup 1.20.2->1.20 item and recipe rewriter (#840) 2024-07-27 19:58:29 +02:00
RK_01 0ed3efc643 Fix typo (#837) 2024-07-27 19:54:16 +02:00
EnZaXD 4536ca41e2 Fix enchantment rewriter description conversion in 1.21->1.20.5 (#833) 2024-07-24 20:39:15 +02:00
Nassim Jahnke 09e862383a Fix editorconfig new lines 2024-07-24 14:34:35 +02:00
EnZaXD 1413bd63ef Handle attribute_modifiers inside container components in 1.21->1.20.5 (#829) 2024-07-24 14:33:56 +02:00
EnZaXD 136678b0b7 Use enhanced switch in more places, fix typo (#831) 2024-07-24 14:33:16 +02:00
Nassim Jahnke 99618af747 Fix enchantment table hints 2024-07-22 18:00:28 +02:00
EnZaXD ede8b877b5 Remove ViaFabricPlus as required dependency (#827) 2024-07-21 09:43:32 +02:00
EnZaXD b5319dbb32 Check if item is null in 1.17.1->1.17 book conversion (#826) 2024-07-20 17:09:34 +02:00
EnZaXD 94c755166c Change modrinth/hangar publishing dependencies (#825) 2024-07-20 09:15:57 +02:00
EnZaXD b6caa30c16 Add alternative sculk shrieker mapping in 1.19->1.18.2 (#820) 2024-07-17 19:06:44 +02:00
EnZaXD bb2f26a5eb Handle keep all player attributes boolean in LOGIN in 1.16->1.15.2 (#822) 2024-07-17 19:02:34 +02:00
Nassim Jahnke b10b161fe7 Update Gradle wrapper 2024-07-14 21:33:19 +02:00
EnZaXD c9d57aab8d Fix possible NPE in 1.17->1.16.4 bedrock at 0 emulation (#821) 2024-07-14 10:10:03 +02:00
EnZaXD 7e08534f4f [ci skip] Fix player combat packet value comments (#818) 2024-07-13 10:59:39 +02:00
EnZaXD d7e7992ca4 Include new bedrock-at-0 config option in world height warning (#815) 2024-07-09 18:26:49 +02:00
EnZaXD e56920c7b1 Fix possible BannerHandler NPE in 1.13->1.12.2 (#814) 2024-07-09 17:59:06 +02:00
EnZaXD e0ec308fa0 Handle rarity changes in trident/banner pattern item in 1.21->1.20.5 (#813) 2024-07-08 12:34:37 +02:00
EnZaXD 1c8438d2a6 Change BlockEntityHandler#handleOrNewCompoundTag to a void function (#812) 2024-07-07 17:31:15 +02:00
EnZaXD 33d8485852 Rename missing metadata references to entity data (#811) 2024-07-06 21:13:55 +02:00
EnZaXD 16f1bdff02 Put enchantment level into translatables in enchantment rewriters (#807) 2024-07-05 16:10:00 +02:00
EnZaXD dd6bc4f1db Handle translatables in lore tag conversion in 1.14->1.13.2 (#810) 2024-07-05 16:09:43 +02:00
Nassim Jahnke 22508f6ab7 Add setting to send bedrock at y 0
Closes #670
2024-07-04 08:58:42 +02:00
Nassim Jahnke 520552fe69 Properly swift sneak in lore 2024-07-03 11:31:02 +02:00
EnZaXD 355ca898d7 Rewrite falling block state ids in 1.20.3->1.20.2 (#806) 2024-07-02 11:50:23 +02:00
EnZaXD 2159dea31d Remove ViaRewind recommendation in fabric.mod.json (#804) 2024-06-30 11:31:34 +02:00
EnZaXD 793bedf4e2 [ci skip] Update supported versions section in README (#805) 2024-06-30 11:31:28 +02:00
Nassim Jahnke 2cb3fd186b Move bee entity mapping to onMappingDataLoaded method 2024-06-26 10:55:59 +02:00
EnZaXD 7ccb5634ff Rewrite title/player_combat components in 1.17->1.16.4 (#801) 2024-06-24 22:17:24 +02:00
Nassim Jahnke f461a0b14c 5.0.1 Release 2024-06-22 15:54:10 +02:00
Nassim Jahnke 2daa1aa39e Handle infinite effect duration in 1.19.4->1.19.3
Fixes #796
2024-06-20 13:53:33 +02:00
Nassim Jahnke 38af6f883b Fix 1.21 enchantment remapping
Fixes #795
2024-06-20 13:21:54 +02:00
Nassim Jahnke 418357d8eb Add empty axolotl_tempt_items tag 2024-06-19 23:01:11 +02:00
Nassim Jahnke 13a74f43ef Remove old particles type handling code 2024-06-18 18:42:39 +02:00
Nassim Jahnke a921337178 Add music_discs item tag for 1.20.5 clients
Needed back in 1.17
Fixes #794
2024-06-18 10:03:13 +02:00
Nassim Jahnke da5837d794 Move particles type handling into generic handler
This allows for handling of data for untracked entities
2024-06-18 10:00:20 +02:00
EnZaXD 4dded860ce Rewrite window title in 1.20->1.19.4 (#792) 2024-06-17 16:52:05 +02:00
EnZaXD 8e99dddb91 Write player rotation on USE_ITEM in 1.21->1.20.5 (#791) 2024-06-17 16:27:55 +02:00
Nassim Jahnke e662640377 Handle item_name item data for component rewriting 2024-06-17 12:58:39 +02:00
Nassim Jahnke bba0a3a3a6 Handle new trial chamber map decoration type
Fixes #789
2024-06-17 12:26:27 +02:00
Nassim Jahnke 4061e91e53 Update translations 2024-06-17 12:12:36 +02:00
Nassim Jahnke 14e208e9d7 Enable experimental 1.21 features for 1.20 clients
Fixes #790
2024-06-17 11:59:38 +02:00
Nassim Jahnke c5dacad81e Bump version to 5.0.1-SNAPSHOT 2024-06-16 21:48:18 +02:00
Nassim Jahnke 132cf1d6e1 5.0.0 Release 2024-06-16 14:02:32 +02:00
Nassim Jahnke 5f57041413 Fix item data handling order 2024-06-16 11:05:50 +02:00
Nassim Jahnke f91a25cba7 Make sure we have block mappings before trying to apply them 2024-06-16 10:22:37 +02:00
Nassim Jahnke 547041cb62 Merge branch 'refs/heads/dev' into preview 2024-06-15 16:11:26 +02:00
Pantera (Mad_Daniel) b7af3b7d8e Fix player head in 1.20.2->1.20 (#786) 2024-06-15 15:10:20 +02:00
Nassim Jahnke bb927b31f7 Some fixups
Informative commit message I know
2024-06-14 00:58:32 +02:00
EnZaXD eceda8ac58 Add remaining item array type in BlockItemPacketRewriter1_13 (#784) 2024-06-13 18:42:17 +02:00
Nassim Jahnke 65d829065a Read proper sound event type in 1.20.5->1.20.3 2024-06-13 18:33:43 +02:00
Nassim Jahnke 0b38dc18a5 Remove snapshot from version 2024-06-12 18:10:36 +02:00
Nassim Jahnke 4b58f6d154 1.21-rc1 2024-06-12 18:08:23 +02:00
Nassim Jahnke 6d8fee053d 1.21-pre3 2024-06-12 18:08:23 +02:00
Nassim Jahnke 335415efd7 1.21-pre2 2024-06-12 18:08:23 +02:00
Nassim Jahnke 59f7ce339e Remove jukebox_playable 2024-06-12 18:08:22 +02:00
Nassim Jahnke a9b9c48b26 Handle item changes in show item text components 2024-06-12 18:08:22 +02:00
Nassim Jahnke 8fb814ef11 Handle chat and horse container changes 2024-06-12 18:08:22 +02:00
Nassim Jahnke 9873f279a4 Bump version 2024-06-12 18:08:22 +02:00
Nassim Jahnke ab1467dba5 Handle jukebox song level event 2024-06-12 18:08:21 +02:00
Nassim Jahnke 3749a5d5da Update data component ids 2024-06-12 18:08:21 +02:00
Nassim Jahnke 6f8da18f65 24w21b, mostly 2024-06-12 18:08:21 +02:00
Nassim Jahnke 1a24ce6d87 24w20a 2024-06-12 18:08:21 +02:00
Nassim Jahnke e9d142e2ec Rebase onto 5.0.0 2024-06-12 18:08:20 +02:00
Nassim Jahnke 218b2abe45 24w19a 2024-06-12 18:08:20 +02:00
Nassim Jahnke 263790e9f6 24w18a 2024-06-12 18:08:20 +02:00
EnZaXD 094bfe34c6 Use trade list rewriter functions (#782) 2024-06-11 15:10:22 +02:00
Nassim Jahnke bfbc086f44 Revert "Send registry data before finish configuration in 1.20.5->1.20.3 (#778)"
This reverts commit e93e30c235.
2024-06-08 20:09:10 +02:00
EnZaXD 7bd43e0234 Use TagRewriter#registerGeneric in 1.20.3->1.20.2 (#779) 2024-06-07 18:38:29 +02:00
EnZaXD e93e30c235 Send registry data before finish configuration in 1.20.5->1.20.3 (#778) 2024-06-07 18:19:49 +02:00
Nassim Jahnke 2f5fbd93ea Make items in 1.20.5+ non null 2024-06-07 13:52:45 +02:00
EnZaXD f86fdd1eb4 Update VV API usage (#776) 2024-06-06 11:09:39 +02:00
Nassim Jahnke 993608b4b4 Also apply MC-68487 workaround to items 2024-06-06 10:56:43 +02:00
EnZaXD a786152dfc Handle UPDATE_LISTED state in 1.19.3->1.19.1 (#775) 2024-06-05 09:24:47 +02:00
EnZaXD 89caecef4f Ignore errors in 1.14->1.13.2 lore tag conversion (#773) 2024-06-04 12:42:43 +02:00
EnZaXD 6058763489 Don't publish extra modules (#772) 2024-06-03 20:31:54 +02:00
EnZaXD 8a675923d1 Emulate recovery compass using lodestone compass in 1.19->1.18.2 (#770) 2024-06-03 09:49:39 +02:00
EnZaXD 3370383481 Add firework flight length fix from VV (#769) 2024-06-02 09:04:17 +02:00
Nassim Jahnke 449ddd1de7 Update Gradle wrapper 2024-06-01 17:10:40 +02:00
Nassim Jahnke 9efc2e630f Update publication metadata 2024-05-30 22:37:44 +02:00
Nassim Jahnke 5849bf06e6 Move Bungee and Sponge modules to separate plugins 2024-05-30 22:21:49 +02:00
EnZaXD 1c45e41934 Fix horse/llama's armor/carpet not visible in 1.20.5->.3 (#765) 2024-05-30 15:47:06 +02:00
Nassim Jahnke bc3d6b952f Resend damageable item on cancelled block break in 1.11->1.10
The client assumes durability changes, so we have to resend the item
2024-05-30 15:42:07 +02:00
EnZaXD b53c0aeb9b Handle block state particles when identifier is used in 1.20.5->.3 (#764) 2024-05-30 10:45:02 +02:00
EnZaXD 3511ba3c67 [ci skip] Replace GitHub link to hangar/viaversion.com sub link (#766) 2024-05-30 10:43:20 +02:00
EnZaXD 1bf5f7408b Add missing translation mappings and component rewriter (#761) 2024-05-28 10:52:08 +02:00
EnZaXD 9e63243003 Make TranslatableRewriter usable in other projects as well (#762) 2024-05-27 19:37:57 +02:00
RK_01 98fad11060 Update Via API usage (#760) 2024-05-27 13:35:14 +02:00
Nassim Jahnke fe4986b042 Fix sniffer entity data removal
Fixes #757
2024-05-22 10:11:09 +02:00
Nassim Jahnke 0618037a0e Rename Position 2024-05-21 13:12:18 +02:00
Nassim Jahnke d7f550fc4f Remove empty item tags
Fixes #752
2024-05-21 11:20:55 +02:00
Nassim Jahnke a9ed655d95 Add extra slot to horse inventories
Fixes #754
2024-05-21 10:36:02 +02:00
EnZaXD 6e75026681 Add config option to suppress emulation warnings (#751) 2024-05-19 09:27:22 +02:00
EnZaXD f9890db702 Use legacy chunk rewriter functions (#750) 2024-05-15 17:27:43 +02:00
EnZaXD dd4ab8082e Update data class names to indicate target version (#749) 2024-05-15 11:16:50 +02:00
EnZaXD f949fd658a [ci skip] Add J17 note to README as well (#748) 2024-05-14 22:20:07 +02:00
EnZaXD 8f92d55747 Update Via API usage (#747) 2024-05-14 20:48:49 +02:00
EnZaXD 4d6c6a2da1 Fix wrong Protocol1_8To1_9#STRING_TO_JSON usages in 1.12->1.11.1 (#746) 2024-05-14 20:48:19 +02:00
Nassim Jahnke 903a49b96a Apply IJ code reformat 2024-05-14 20:48:17 +02:00
FlorianMichael b85046f11d Rework logging inside protocols and rewriters 2024-05-14 20:48:07 +02:00
FlorianMichael 264cce865b Rename data, protocol and mapping classes
Syncs names with https://github.com/ViaVersion/ViaVersion/commit/a2b7fc82e2bc3a30823812da3c4d478f467a5411
2024-05-14 20:47:58 +02:00
FlorianMichael c27f720316 Update Via API usage
Question to EntityPacketRewriter1_16_2: is it intended that the LOGIN handler doesn't copy the written dimensions tag or was that just forgotten?
2024-05-14 20:47:43 +02:00
Nassim Jahnke a946632e8b Lots of renames 2024-05-14 20:47:40 +02:00
Nassim Jahnke 5e7371d39b Start working on 5.0.0 2024-05-11 15:01:36 +02:00
EnZaXD abb1803aaf Cache dimensions without namespace in 1.19->1.18.2 (#744) 2024-05-10 21:47:45 +02:00
Nassim Jahnke e45a95c6ec Bump version to 4.10.3-SNAPSHOT 2024-05-10 21:47:35 +02:00
Nassim Jahnke 17bda0fc29 4.10.2 Release 2024-05-10 13:24:40 +02:00
EnZaXD 1a22b371cd Handle bad heightmaps in 1.17->1.16.4 (#743) 2024-05-09 21:56:14 +02:00
EnZaXD 6292c5a5a5 Use backup tag remove method when rewriting trade list (#742) 2024-05-09 20:55:31 +02:00
Nassim Jahnke 6b616d8b07 Fixup banner handling 2024-05-09 19:44:03 +02:00
Nassim Jahnke fd43ca56d7 Properly write properties 2024-05-09 18:04:13 +02:00
Nassim Jahnke 91193cf602 Handle player head block entities
Fixes #741
2024-05-09 17:22:31 +02:00
EnZaXD 1680f9985d [ci skip] Use login/status packet enums in older protocols (#740) 2024-05-09 09:25:17 +02:00
EnZaXD e8602adf5b Fix red nether brick name in 1.11->1.10 (#739) 2024-05-07 19:35:18 +02:00
EnZaXD 7f0982e59c Fix item mappings with explicit data (0) (#738) 2024-05-07 18:54:38 +02:00
Nassim Jahnke 072b59060c Don't write null criteria for unknown advancements 2024-05-07 17:07:13 +02:00
EnZaXD 633b4b393b Remove alpha channel from particle colors in 1.20.5->.3 (#737) 2024-05-06 09:50:33 +02:00
Nassim Jahnke 34101ea8b8 4.10.1 Release
Definitely the first time I made this commit
2024-05-05 16:53:56 +02:00
Nassim Jahnke 093328db11 Handle missing mappings 2024-05-05 16:53:36 +02:00
Nassim Jahnke 5bd8786737 Update entity mapping usage 2024-05-05 12:22:17 +02:00
EnZaXD fedda03062 Use TagUtil#removeNamespaced in 1.19.4->.3 (#735) 2024-05-02 16:07:22 +02:00
EnZaXD 99f6356230 Make chat_types handling in 1.19 protocols optional (#733) 2024-05-02 15:59:51 +02:00
EnZaXD 9b8e65c59d Implement handleTranslate() for tags in TranslatableRewriter (#734) 2024-05-02 15:28:40 +02:00
Nassim JahnkeandKrakenied bd2eb42374 Add advancement criteria if possible in 1.20.2->1.20
Fixes #616

Co-authored-by: Krakenied <Krakenied1@gmail.com>
2024-05-01 11:31:03 +02:00
Nassim Jahnke e9db3f040f Check both namespaced and implicit key when replacing registries 2024-05-01 10:35:48 +02:00
Nassim Jahnke ce0e01abec Auto: Update copyright headers 2024-04-30 22:29:02 +02:00
Nassim Jahnke 025603027e Remove default components from trade list 2024-04-30 22:29:02 +02:00
EnZaXD 67ae00faeb Add support for different mapping types with same id (#731) 2024-04-30 18:29:45 +02:00
Nassim Jahnke 325e3f92ed Remove 1.19.4 registries without namespace as well 2024-04-29 23:12:37 +02:00
Nassim Jahnke 42897030f7 Fix entity effect reading below 1.20.2
Fixes #3811
2024-04-28 11:39:43 +02:00
Nassim Jahnke ddeaf921be Register listeners a tick later
Because 1.8 has task registration order reverse???
Fixes #730
2024-04-28 11:35:51 +02:00
Nassim Jahnke 06c30c2838 Add paperweight-mappings-namespace attribute 2024-04-28 03:52:25 +02:00
Gero bf7ed14506 Fix remapping of 1.20.5 CLICK_WINDOW_BUTTON 2024-04-27 21:31:49 +02:00
Gero c4d0c7ab8f Bump to 4.10.1-SNAPSHOT 2024-04-27 21:31:41 +02:00
Nassim Jahnke f1f337af27 Bump VV dependency 2024-04-26 15:25:19 +02:00
Nassim Jahnke e37fea42d4 4.10.0 Release 2024-04-26 15:15:57 +02:00
FlorianMichael 78a667c5b9 Add constructors to LegacyBlockItemRewriter to define item types 2024-04-26 15:15:24 +02:00
Nassim Jahnke 27dd2e39bd Merge branch 'refs/heads/dev' into preview
# Conflicts:
#	common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappings.java
2024-04-26 14:32:00 +02:00
Nassim Jahnke b3115ea71d Fix some namespace parsing issues 2024-04-26 13:31:14 +02:00
Nassim Jahnke be742fc493 Fix 1.20.3->1.20.2 cloud particle handling 2024-04-26 13:19:09 +02:00
EnZaXD 100febf575 Rework legacy item/block mappings format (#728) 2024-04-26 09:18:42 +02:00
Nassim Jahnke cddf30b60f Read normal byte array type for cookie packet 2024-04-25 19:11:19 +02:00
EnZaXD c4c15fb047 Add EntityRewriterBase#getDisplayVisibilityMetaValue (#725) 2024-04-23 22:18:58 +02:00
EnZaXD ab11527c86 Reuse existing logger getter in BackwardsMappings (#726) 2024-04-23 22:18:45 +02:00
Nassim Jahnke 1d3a444fe0 Update version 2024-04-23 17:02:21 +02:00
Nassim Jahnke 82bb374edc Update version references 2024-04-23 11:26:31 +02:00
Nassim Jahnke a4147a24f1 Merge branch 'refs/heads/dev' into preview 2024-04-23 11:00:24 +02:00
EnZaXD 87f2a6ba7b Add mob spawn rewriter function for pre 1.11 (#724) 2024-04-23 10:45:12 +02:00
EnZaXD 948c615622 Replace LegacyEntityRewriter#getObjectTypeFromId with existing method (#723) 2024-04-22 23:30:15 +02:00
Nassim Jahnke 0996fc9270 Merge branch 'refs/heads/dev' into preview
# Conflicts:
#	common/src/main/java/com/viaversion/viabackwards/api/rewriters/EntityRewriterBase.java
#	common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java
2024-04-21 23:43:33 +02:00
Nassim Jahnke 0cd46fdac9 Also to component rewriter methods 2024-04-21 23:37:00 +02:00
Nassim Jahnke 2a4bfb936f Add UserConnection param to item rewriter methods 2024-04-21 22:48:56 +02:00
Nassim Jahnke 3b9b3ab257 Use getFullItemMappings 2024-04-21 20:50:04 +02:00
FlorianMichael e52210a674 Update mappings 2024-04-21 10:11:17 +02:00
Nassim Jahnke 11286b2162 Fall back to keys without namespace in registry data 2024-04-20 12:13:06 +02:00
Gero 471d4acf20 Add missing dust_color_transition data remapping (changed in 24w03a) 2024-04-19 16:54:52 +02:00
Gero e5fff8fabc 1.20.5-rc2 2024-04-19 16:54:10 +02:00
Nassim Jahnke 23955e5385 Update particle format in biome registry data 2024-04-18 19:16:42 +02:00
Nassim Jahnke bf635cc6c5 1.20.5-rc1 2024-04-18 16:30:58 +02:00
Nassim Jahnke 5a49413dbc Merge branch 'refs/heads/dev' into preview 2024-04-18 16:26:20 +02:00
Nassim Jahnke c64e9acf35 Override getTagRewriter methods 2024-04-18 16:26:03 +02:00
Nassim Jahnke 00f773d150 Merge branch 'refs/heads/master' into dev 2024-04-18 16:19:39 +02:00
EnZaXD 1ac504afb9 Use correct constructor in MappedLegacyBlockItem (#721) 2024-04-17 08:46:48 +02:00
EnZaXD 09eda34051 Use VVs IdAndData class for block id conversions (#719) 2024-04-16 21:05:45 +02:00
EnZaXD 9cf5f98ed1 Replace incoming/outgoing usages with client/server bound (#720) 2024-04-16 21:00:20 +02:00
Nassim Jahnke 1e8cf198e7 Update missed call 2024-04-15 17:29:22 +02:00
Nassim Jahnke caa28df36d 1.20.5-pre2 2024-04-15 17:17:19 +02:00
Nassim Jahnke d2edf3fbfe 1.20.5-pre1 2024-04-10 17:41:19 +02:00
Nassim Jahnke 68807be880 Track banner patterns 2024-04-09 13:18:40 +02:00
Nassim Jahnke 7d6c330fa3 Handle entity effect particle color 2024-04-08 15:05:01 +02:00
Nassim Jahnke 3ea95a0d78 Update authors 2024-04-07 20:44:24 +02:00
FlorianMichael fe708ba0eb Fix chat command handling 2024-04-07 19:58:44 +02:00
Nassim Jahnke fccd5b3f3b Fix trade list handling 2024-04-07 13:41:51 +02:00
Nassim Jahnke 9f652ad24a Update VV usage 2024-04-06 21:33:41 +02:00
Nassim Jahnke f7dad9b5d7 Add StructuredEnchantmentRewriter, update translation mappings 2024-04-06 21:30:19 +02:00
Nassim Jahnke 1507f788ec 24w14a 2024-04-06 21:28:59 +02:00
Nassim Jahnke 41b04f9902 24w13a 2024-04-06 21:28:59 +02:00
Nassim Jahnke 9beaf71196 Handle new argument types 2024-04-06 21:28:59 +02:00
Nassim Jahnke 0c7aa1d037 Update mappings 2024-04-06 21:28:59 +02:00
Nassim Jahnke 7a7d2f1fa1 Handle lore and name in StructuredItemRewriter 2024-04-06 21:28:56 +02:00
Nassim Jahnke 37711d0079 Set rewritten item in metadata rewriter 2024-04-06 21:28:21 +02:00
Nassim Jahnke e1f2f151c9 24w11a 2024-04-06 21:28:21 +02:00
Nassim Jahnke a453163822 Some 24w10a changes 2024-04-06 21:28:21 +02:00
EnZaXD 1647b18233 Override nbtTagName() correctly (#717) 2024-04-05 20:36:03 +02:00
vadage c7dc80b71b Support config loading from input stream (#718) 2024-04-05 20:32:47 +02:00
EnZaXD 39d3265463 Update VV ItemRewriter API Usage (#716) 2024-04-04 09:48:19 +02:00
Nassim Jahnke 2b953556ec Update VV API usage 2024-04-01 14:20:15 +02:00
EnZaXD 4e5b6fe876 Fix minor inconsistencies in older protocols (#714) 2024-04-01 13:01:07 +02:00
EnZaXD 0e74527342 Update Via API usage (#713) 2024-03-31 15:14:33 +02:00
EnZaXD 75fddd0fb9 Allow platforms to disable dummy enchantment in LegacyEnchantmentRewriter (#710) 2024-03-28 14:32:13 +01:00
EnZaXD 0aacfe3bcb Add item handler methods to LegacyEnchantmentRewriter (#709) 2024-03-28 11:22:34 +01:00
EnZaXD 4547d5c702 Move methods in LegacyBlockItemRewriter and expose handleChunk method (#707) 2024-03-27 20:15:57 +01:00
EnZaXD b438484dc7 Keep original item data in LegacyBlockItemRewriter (#706) 2024-03-27 17:04:50 +01:00
EnZaXD ed52ef21ee Add calculation methods for block id and data (#704) 2024-03-27 16:49:14 +01:00
EnZaXD 9d1a5a05f5 Expose EntityRewriterBase#alwaysShowOriginalMobName (#705) 2024-03-27 16:48:35 +01:00
EnZaXD 4e856ef396 Various API changes to LegacyBlockItemRewriter (#703) 2024-03-27 13:27:19 +01:00
EnZaXD 082cc010b2 Update Via API usage (#702) 2024-03-24 22:10:06 +01:00
EnZaXD 59a621315b Allow platforms to use BackwardsMappingDataLoader (#701) 2024-03-24 12:14:51 +01:00
EnZaXD d8b7e7d9ff Update mapping data loader (#700) 2024-03-24 11:46:08 +01:00
Nassim Jahnke 51561d143c Merge branch 'master' into dev
# Conflicts:
#	.github/workflows/publish.yml
2024-03-22 20:55:44 +01:00
Nassim Jahnke 2ffa852c92 Update build dependencies 2024-03-22 20:48:31 +01:00
Nassim Jahnke ac86d891fe Check if id is present in EnchantmentRewriter
Closes #699
2024-03-17 19:58:05 +01:00
Nassim Jahnke 9d8aa9a232 Update mappings 2024-03-17 16:29:32 +01:00
Nassim Jahnke f3b26c5aa5 Fix 1.20.2->1.20 entity sound reading
Fixes ViaVersion/ViaVersion#3744
2024-03-14 14:41:49 +01:00
Nassim Jahnke d96cef7134 Merge branch 'master' into dev 2024-03-09 13:09:17 +01:00
Nassim Jahnke ced1a65230 Replace some generic CompoundTag get usages 2024-03-09 13:08:36 +01:00
Nassim Jahnke 6ad1dc4195 Merge branch 'master' into dev
# Conflicts:
#	gradle.properties
#	gradle/libs.versions.toml
2024-03-07 13:51:41 +01:00
Nassim Jahnke c6ea04fd33 Update ViaNBT 2024-03-07 13:37:42 +01:00
Nassim Jahnke 39e9d6dd04 Use new SoundEvent type 2024-03-01 14:23:13 +01:00
Nassim Jahnke 445d798a17 Partially implement mapped item handling 2024-02-29 20:30:46 +01:00
Nassim Jahnke 66896d2027 Update version 2024-02-29 14:28:48 +01:00
Nassim Jahnke 05b1a6bacd Start working on 24w09a 2024-02-29 12:41:39 +01:00
Nassim Jahnke 8f417b6caa Rename methods once again 2024-02-14 19:27:40 +01:00
Nassim Jahnke 96d6c0697e Fix compilation 2024-02-14 18:15:41 +01:00
Nassim Jahnke c112044b5a 24w07a 2024-02-14 17:39:31 +01:00
Nassim Jahnke 45c44c8f7e Update VV usage 2024-02-14 11:13:58 +01:00
Nassim Jahnke 5a3a82a83d Update VV usage 2024-02-13 19:03:56 +01:00
Nassim Jahnke bc03235f42 Merge branch 'master' into dev
# Conflicts:
#	common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_16_4to1_17/packets/EntityPackets1_17.java
2024-02-12 11:08:17 +01:00
Nassim Jahnke 073488abcf Update template 2024-02-12 11:03:39 +01:00
Nassim Jahnke f90861dbce Remap breeze wind charge 2024-02-08 16:19:17 +01:00
Nassim Jahnke 06f07d2b2c 24w06a 2024-02-07 19:07:34 +01:00
Nassim Jahnke fa1c3e1520 24w05b 2024-02-01 17:53:18 +01:00
Nassim Jahnke 680d0642c9 Merge branch 'master' into dev
# Conflicts:
#	common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java
2024-01-31 22:58:51 +01:00
Nassim Jahnke f6def0c97c 24w05a (mostly) 2024-01-31 18:06:46 +01:00
Nassim Jahnke b3b4d0f618 Merge branch 'master' into dev
# Conflicts:
#	common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java
2024-01-29 17:33:42 +01:00
Nassim Jahnke 9abfdfb8f9 Include config packets in Protocol generic types 2024-01-26 16:23:17 +01:00
Nassim Jahnke 8c2f80a632 Fix missed type removal from last commit 2024-01-26 14:38:55 +01:00
Nassim Jahnke 3e89641448 24w04a 2024-01-24 20:23:29 +01:00
Nassim Jahnke a2ddcae076 Merge branch 'master' into dev
# Conflicts:
#	.github/workflows/gradle.yml
2024-01-24 17:51:31 +01:00
Nassim Jahnke 8ffbc7047f Add cookie handling, TransferProvider for other platforms 2024-01-20 10:26:56 +01:00
Nassim Jahnke e6814a13a9 24w03b (probably) 2024-01-18 16:34:00 +01:00
EnZaXD 6b1f913b91 Fix VV API usage (#664) 2024-01-13 09:54:39 +01:00
Nassim Jahnke de42850dd1 Merge branch 'master' into dev
# Conflicts:
#	template/src/main/java/com/viaversion/viabackwards/template/protocol/rewriter/EntityPacketRewriter1_99.java
2024-01-12 10:33:40 +01:00
Nassim Jahnke 62765d03ce Merge remote-tracking branch 'origin/master' into dev 2024-01-04 17:51:18 +01:00
Nassim Jahnke 59660a5bdc Merge branch 'master' into dev 2023-12-27 19:48:40 +01:00
Kichura fa18a572c0 Update setup-java to v4, Fix friendly names in CI steps (#660) 2023-12-27 19:47:31 +01:00
Nassim Jahnke 19ec92c261 Merge remote-tracking branch 'origin/master' into dev 2023-12-26 21:51:03 +01:00
Nassim Jahnke ba725df33e 23w51b 2023-12-18 19:50:25 +01:00
325 changed files with 20210 additions and 14072 deletions

No files matched your search

+6 -3
View File
@@ -2,12 +2,15 @@
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = false
insert_final_newline = true
tab_width = 4
[*.java]
ij_java_class_count_to_use_import_on_demand = 999999
ij_java_names_count_to_use_import_on_demand = 999999
ij_java_imports_layout = *,|,$*
ij_java_imports_layout = *, |, $*
ij_java_generate_final_locals = true
ij_java_generate_final_parameters = true
ij_java_generate_final_parameters = true
[{*.json,*.yml}]
indent_size = 2
+3 -3
View File
@@ -69,9 +69,9 @@ body:
attributes:
label: Additional Server Info
description: |
Do you use a proxy (eg. BungeeCord)? What software do you use and what plugins?
Do you use a proxy (eg. Velocity)? What software do you use and what plugins?
placeholder: |
Example: "I also use BungeeCord with the following plugins: x, y, z"
Example: "I also use Velocity with the following plugins: x, y, z"
validations:
required: false
@@ -80,7 +80,7 @@ body:
label: Checklist
description: Make sure you have followed each of the steps outlined here.
options:
- label: Via plugins are only running on **EITHER** the backend servers (e.g. Paper) **OR** the proxy (e.g. BungeeCord), **not on both**.
- label: Via plugins are only running on **EITHER** the backend servers (e.g. Paper) **OR** the proxy (e.g. Velocity), **not on both**.
required: true
- label: I have included a ViaVersion dump.
required: true
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
@@ -6,13 +6,13 @@ jobs:
build:
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/wrapper-validation-action@v1
uses: gradle/actions/wrapper-validation@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
+5 -3
View File
@@ -8,10 +8,12 @@ on:
jobs:
publish:
if: github.repository_owner == 'ViaVersion'
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v1
- name: Checkout Repository
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
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
+3
View File
@@ -107,3 +107,6 @@ nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
### Run Folder (ViaProxy) ###
common/run/
+7 -4
View File
@@ -4,16 +4,17 @@
[![Build Status](https://github.com/ViaVersion/ViaBackwards/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/ViaVersion/ViaBackwards/actions)
[![Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord)
**Allows older Minecraft client versions to connect to newer server versions.**
**Allows the connection of older clients to newer server versions for Minecraft servers.**
Requires [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) to be installed..
Supported Versions
-
As a plugin, ViaBackwards runs on servers on releases 1.10-latest. Versions from the dev branch will also support the
latest snapshot. You can also use ViaBackwards in ViaFabric or ViaFabricPlus.
As a plugin, ViaBackwards runs on servers on releases 1.10-latest. You can also use ViaBackwards in ViaFabric or ViaFabricPlus.
- in **ViaFabric**, put ViaBackwards into the `mods` folder
- in **ViaFabricPlus**, put ViaBackwards into the `ViaFabricPlus/jars` folder
See [HERE](https://github.com/ViaVersion) for an overview of the different Via* projects.
See [HERE](https://viaversion.com) for an overview of the different Via* projects.
Releases/Dev Builds
-
@@ -48,6 +49,8 @@ Building
After cloning this repository, build the project with Gradle by running `./gradlew build` and take the created jar out
of the `build/libs` directory.
You need JDK 17 or newer to build ViaBackwards.
License
-
This project is licensed under the [GNU General Public License Version 3](LICENSE).
+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")
}
+11 -48
View File
@@ -1,59 +1,23 @@
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import java.io.ByteArrayOutputStream
fun Project.publishShadowJar() {
configurePublication {
artifact(tasks["shadowJar"])
artifact(tasks["sourcesJar"])
}
}
fun Project.publishJavaComponents() {
configurePublication {
from(components["java"])
}
}
private fun Project.configurePublication(configurer: MavenPublication.() -> Unit) {
extensions.configure<PublishingExtension> {
publications.named<MavenPublication>("mavenJava") {
apply(configurer)
}
}
}
import org.gradle.jvm.toolchain.JavaLanguageVersion
fun Project.latestCommitHash(): String {
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
return runGitCommand(listOf("rev-parse", "--short", "HEAD"))
}
fun Project.latestCommitMessage(): String {
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "log", "-1", "--pretty=%B")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
return runGitCommand(listOf("log", "-1", "--pretty=%B"))
}
fun Project.branchName(): String {
val byteOut = ByteArrayOutputStream()
exec {
commandLine = listOf("git", "rev-parse", "--abbrev-ref", "HEAD")
standardOutput = byteOut
}
return byteOut.toString(Charsets.UTF_8.name()).trim()
return runGitCommand(listOf("rev-parse", "--abbrev-ref", "HEAD"))
}
fun Project.runGitCommand(args: List<String>): String {
return providers.exec {
commandLine = listOf("git") + args
}.standardOutput.asBytes.get().toString(Charsets.UTF_8).trim()
}
fun Project.parseMinecraftSnapshotVersion(version: String): String? {
@@ -66,6 +30,5 @@ fun Project.parseMinecraftSnapshotVersion(version: String): String? {
}
fun JavaPluginExtension.javaTarget(version: Int) {
sourceCompatibility = JavaVersion.toVersion(version)
targetCompatibility = JavaVersion.toVersion(version)
toolchain.languageVersion.set(JavaLanguageVersion.of(version))
}
@@ -1,13 +1,12 @@
plugins {
`java-library`
`maven-publish`
}
tasks {
// Variable replacements
processResources {
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json", "bungee.yml")) {
expand("version" to project.version, "description" to project.description, "url" to "https://github.com/ViaVersion/ViaBackwards")
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/backwards")
}
}
javadoc {
@@ -21,22 +20,6 @@ tasks {
}
java {
javaTarget(8)
javaTarget(17)
withSourcesJar()
}
publishing {
publications.create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
artifactId = project.name
version = rootProject.version as String
}
repositories.maven {
name = "Via"
url = uri("https://repo.viaversion.com/")
credentials(PasswordCredentials::class)
authentication {
create<BasicAuthentication>("basic")
}
}
}
@@ -4,7 +4,8 @@ import org.gradle.kotlin.dsl.named
plugins {
id("vb.base-conventions")
id("com.github.johnrengelman.shadow")
id("maven-publish")
id("com.gradleup.shadow")
}
tasks {
@@ -21,7 +22,24 @@ tasks {
}
}
publishShadowJar()
publishing {
publications.create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
artifactId = project.name
version = rootProject.version as String
artifact(tasks["shadowJar"])
artifact(tasks["sourcesJar"])
}
repositories.maven {
name = "Via"
url = uri("https://repo.viaversion.com/")
credentials(PasswordCredentials::class)
authentication {
create<BasicAuthentication>("basic")
}
}
}
fun ShadowJar.configureRelocations() {
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
@@ -1,5 +0,0 @@
plugins {
id("vb.base-conventions")
}
publishJavaComponents()
+10 -11
View File
@@ -6,22 +6,21 @@ plugins {
allprojects {
group = "com.viaversion"
version = property("projectVersion") as String // from gradle.properties
description = "Allows older Minecraft client versions to connect to newer server versions."
description = "Allows the connection of older clients to newer server versions for Minecraft servers."
}
val main = setOf(
projects.viabackwards,
projects.viabackwardsCommon,
projects.viabackwardsBukkit,
projects.viabackwardsBungee,
projects.viabackwardsFabric,
projects.viabackwardsSponge,
projects.viabackwardsVelocity
).map { it.dependencyProject }
projects.viabackwards,
projects.viabackwardsCommon,
projects.viabackwardsBukkit,
projects.viabackwardsVelocity,
projects.viabackwardsSponge,
projects.viabackwardsFabric
).map { it.path }
subprojects {
when (this) {
when (path) {
in main -> plugins.apply("vb.shadow-conventions")
else -> plugins.apply("vb.standard-conventions")
else -> plugins.apply("vb.base-conventions")
}
}
@@ -19,15 +19,18 @@
package com.viaversion.viabackwards;
import com.viaversion.viabackwards.api.ViaBackwardsPlatform;
import com.viaversion.viabackwards.listener.BlockBreakListener;
import com.viaversion.viabackwards.listener.FireDamageListener;
import com.viaversion.viabackwards.listener.FireExtinguishListener;
import com.viaversion.viabackwards.listener.LecternInteractListener;
import com.viaversion.viabackwards.listener.PlayerItemDropListener;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.provider.AdvancementCriteriaProvider;
import com.viaversion.viabackwards.provider.BukkitAdvancementCriteriaProvider;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import org.bukkit.plugin.java.JavaPlugin;
public class BukkitPlugin extends JavaPlugin implements ViaBackwardsPlatform {
@@ -39,26 +42,37 @@ public class BukkitPlugin extends JavaPlugin implements ViaBackwardsPlatform {
public void onEnable() {
if (Via.getManager().getInjector().lateProtocolVersionSetting()) {
// Enable in the next tick
Via.getPlatform().runSync(this::enable);
Via.getPlatform().runSync(this::enable, 1);
} else {
enable();
}
}
private void enable() {
int protocolVersion = Via.getAPI().getServerVersion().highestSupportedVersion();
if (protocolVersion >= ProtocolVersion.v1_17.getVersion()) {
@Override
public void enable() {
ViaBackwardsPlatform.super.enable();
final ProtocolVersion protocolVersion = Via.getAPI().getServerVersion().highestSupportedProtocolVersion();
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_17)) {
new PlayerItemDropListener(this).register();
}
if (protocolVersion >= ProtocolVersion.v1_16.getVersion()) {
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_16)) {
new FireExtinguishListener(this).register();
}
if (protocolVersion >= ProtocolVersion.v1_14.getVersion()) {
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_14)) {
new LecternInteractListener(this).register();
}
if (protocolVersion >= ProtocolVersion.v1_12.getVersion()) {
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_12)) {
new FireDamageListener(this).register();
}
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_11)) {
new BlockBreakListener(this).register();
}
final ViaProviders providers = Via.getManager().getProviders();
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_2)) {
providers.use(AdvancementCriteriaProvider.class, new BukkitAdvancementCriteriaProvider());
}
}
@Override
@@ -0,0 +1,54 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
public class BlockBreakListener extends ViaBukkitListener {
public BlockBreakListener(final BukkitPlugin plugin) {
super(plugin, Protocol1_11To1_10.class);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onBlockBreak(final BlockBreakEvent event) {
if (!event.isCancelled()) {
return;
}
final Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || !isOnPipe(player)) {
return;
}
// Resend the item in the hand to sync durability
final int slot = player.getInventory().getHeldItemSlot();
final ItemStack item = player.getInventory().getItem(slot);
if (item != null && item.getType().getMaxDurability() > 0) {
player.getInventory().setItem(slot, item);
}
}
}
@@ -18,7 +18,7 @@
package com.viaversion.viabackwards.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
@@ -31,7 +31,7 @@ import org.bukkit.event.entity.EntityDamageEvent;
public class FireDamageListener extends ViaBukkitListener {
public FireDamageListener(BukkitPlugin plugin) {
super(plugin, Protocol1_11_1To1_12.class);
super(plugin, Protocol1_12To1_11_1.class);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@@ -40,9 +40,9 @@ public class FireDamageListener extends ViaBukkitListener {
EntityDamageEvent.DamageCause cause = event.getCause();
if (cause != EntityDamageEvent.DamageCause.FIRE
&& cause != EntityDamageEvent.DamageCause.FIRE_TICK
&& cause != EntityDamageEvent.DamageCause.LAVA
&& cause != EntityDamageEvent.DamageCause.DROWNING) {
&& cause != EntityDamageEvent.DamageCause.FIRE_TICK
&& cause != EntityDamageEvent.DamageCause.LAVA
&& cause != EntityDamageEvent.DamageCause.DROWNING) {
return;
}
@@ -18,7 +18,7 @@
package com.viaversion.viabackwards.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -31,7 +31,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
public class FireExtinguishListener extends ViaBukkitListener {
public FireExtinguishListener(BukkitPlugin plugin) {
super(plugin, Protocol1_15_2To1_16.class);
super(plugin, Protocol1_16To1_15_2.class);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@@ -18,7 +18,7 @@
package com.viaversion.viabackwards.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.Protocol1_13_2To1_14;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -33,7 +33,7 @@ import org.bukkit.inventory.meta.BookMeta;
public class LecternInteractListener extends ViaBukkitListener {
public LecternInteractListener(BukkitPlugin plugin) {
super(plugin, Protocol1_13_2To1_14.class);
super(plugin, Protocol1_14To1_13_2.class);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@@ -19,7 +19,7 @@
package com.viaversion.viabackwards.listener;
import com.viaversion.viabackwards.BukkitPlugin;
import com.viaversion.viabackwards.protocol.protocol1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -30,7 +30,7 @@ import org.bukkit.inventory.ItemStack;
public class PlayerItemDropListener extends ViaBukkitListener {
public PlayerItemDropListener(final BukkitPlugin plugin) {
super(plugin, Protocol1_13To1_13_1.class); // Starts with 1.13 clients on 1.17 servers
super(plugin, Protocol1_13_1To1_13.class); // Starts with 1.13 clients on 1.17 servers
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -40,7 +40,7 @@ public class PlayerItemDropListener extends ViaBukkitListener {
return;
}
// Resent the item in the hand
// Resend the item in the hand
final int slot = player.getInventory().getHeldItemSlot();
final ItemStack item = player.getInventory().getItem(slot);
player.getInventory().setItem(slot, item);
@@ -15,24 +15,20 @@
* 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.viabackwards.provider;
package com.viaversion.viabackwards;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.provider.AdvancementCriteriaProvider;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.advancement.Advancement;
import com.viaversion.viabackwards.api.ViaBackwardsPlatform;
import com.viaversion.viaversion.api.Via;
import net.md_5.bungee.api.plugin.Plugin;
public final class BukkitAdvancementCriteriaProvider extends AdvancementCriteriaProvider {
import java.io.File;
public class BungeePlugin extends Plugin implements ViaBackwardsPlatform {
private static final String[] EMPTY_CRITERIA = new String[0];
@Override
public void onLoad() {
Via.getManager().addEnableListener(() -> this.init(new File(getDataFolder(), "config.yml")));
}
@Override
public void disable() {
public String[] getCriteria(final String advancementKey) {
final Advancement advancement = Bukkit.getAdvancement(NamespacedKey.fromString(advancementKey));
return advancement == null ? EMPTY_CRITERIA : advancement.getCriteria().toArray(EMPTY_CRITERIA);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ main: com.viaversion.viabackwards.BukkitPlugin
api-version: 1.13
folia-supported: true
authors: [Matsv, kennytv, Gerrygames, creeper123123321, ForceUpdate1]
authors: [Matsv, kennytv, Gerrygames, creeper123123321, ForceUpdate1, EnZaXD]
website: ${url}
depend: [ViaVersion]
-4
View File
@@ -1,4 +0,0 @@
dependencies {
compileOnlyApi(projects.viabackwardsCommon)
compileOnly(libs.bungee)
}
-5
View File
@@ -1,5 +0,0 @@
name: ViaBackwards
main: com.viaversion.viabackwards.BungeePlugin
author: "Matsv, kennytv, Gerrygames, creeper123123321, ForceUpdate1"
version: ${version}
depends: [ViaVersion]
+29
View File
@@ -24,3 +24,32 @@ dependencies {
java {
withJavadocJar()
}
// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy
// For further instructions see the ViaProxy repository README
tasks.register<JavaExec>("runViaProxy") {
dependsOn(tasks.shadowJar)
val viaProxyConfiguration = configurations.create("viaProxy")
viaProxyConfiguration.dependencies.add(dependencies.create(rootProject.libs.viaProxy.get().copy().setTransitive(false)))
mainClass.set("net.raphimc.viaproxy.ViaProxy")
classpath = viaProxyConfiguration
workingDir = file("run")
jvmArgs = listOf("-DskipUpdateCheck")
if (System.getProperty("viaproxy.gui.autoStart") != null) {
jvmArgs("-Dviaproxy.gui.autoStart")
}
doFirst {
val jarsDir = file("$workingDir/jars")
jarsDir.mkdirs()
file("$jarsDir/${project.name}.jar").writeBytes(tasks.shadowJar.get().archiveFile.get().asFile.readBytes())
}
doLast {
file("$workingDir/jars/${project.name}.jar").delete()
file("$workingDir/logs").deleteRecursively()
}
}
@@ -19,10 +19,12 @@ package com.viaversion.viabackwards;
import com.viaversion.viaversion.util.Config;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class ViaBackwardsConfig extends Config implements com.viaversion.viabackwards.api.ViaBackwardsConfig {
@@ -32,9 +34,13 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
private boolean alwaysShowOriginalMobName;
private boolean fix1_13FormattedInventoryTitles;
private boolean handlePingsAsInvAcknowledgements;
private boolean bedrockAtY0;
private boolean sculkShriekersToCryingObsidian;
private boolean mapDarknessEffect;
private boolean suppressEmulationWarnings;
public ViaBackwardsConfig(File configFile) {
super(configFile);
public ViaBackwardsConfig(File configFile, Logger logger) {
super(configFile, logger);
}
@Override
@@ -50,6 +56,10 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
fix1_13FormattedInventoryTitles = getBoolean("fix-formatted-inventory-titles", true);
alwaysShowOriginalMobName = getBoolean("always-show-original-mob-name", true);
handlePingsAsInvAcknowledgements = getBoolean("handle-pings-as-inv-acknowledgements", false);
bedrockAtY0 = getBoolean("bedrock-at-y-0", false);
sculkShriekersToCryingObsidian = getBoolean("sculk-shriekers-to-crying-obsidian", false);
mapDarknessEffect = getBoolean("map-darkness-effect", true);
suppressEmulationWarnings = getBoolean("suppress-emulation-warnings", false);
}
@Override
@@ -82,11 +92,36 @@ public class ViaBackwardsConfig extends Config implements com.viaversion.viaback
return handlePingsAsInvAcknowledgements || Boolean.getBoolean("com.viaversion.handlePingsAsInvAcknowledgements");
}
@Override
public boolean bedrockAtY0() {
return bedrockAtY0;
}
@Override
public boolean sculkShriekerToCryingObsidian() {
return sculkShriekersToCryingObsidian;
}
@Override
public boolean mapDarknessEffect() {
return mapDarknessEffect;
}
@Override
public boolean suppressEmulationWarnings() {
return suppressEmulationWarnings;
}
@Override
public URL getDefaultConfigURL() {
return getClass().getClassLoader().getResource("assets/viabackwards/config.yml");
}
@Override
public InputStream getDefaultConfigInputStream() {
return getClass().getClassLoader().getResourceAsStream("assets/viabackwards/config.yml");
}
@Override
protected void handleConfig(Map<String, Object> map) {
}
@@ -17,7 +17,7 @@
*/
package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
@@ -48,7 +48,7 @@ public abstract class BackwardsProtocol<CU extends ClientboundPacketType, CM ext
protected void registerPackets() {
super.registerPackets();
final BackwardsMappings mappingData = getMappingData();
final BackwardsMappingData mappingData = getMappingData();
if (mappingData != null && mappingData.getViaVersionProtocolClass() != null) {
executeAsyncAfterLoaded(mappingData.getViaVersionProtocolClass(), this::loadMappingData);
}
@@ -61,11 +61,12 @@ public abstract class BackwardsProtocol<CU extends ClientboundPacketType, CM ext
}
@Override
public @Nullable BackwardsMappings getMappingData() { // Change return type to BackwardsMappings
public @Nullable BackwardsMappingData getMappingData() { // Change return type to BackwardsMappings
return null;
}
public @Nullable TranslatableRewriter<CU> getTranslatableRewriter() {
@Override
public @Nullable TranslatableRewriter<CU> getComponentRewriter() {
return null;
}
}
@@ -63,4 +63,32 @@ public interface ViaBackwardsConfig extends Config {
* @return true if enabled
*/
boolean handlePingsAsInvAcknowledgements();
/**
* Adds bedrock at y=0 for sub 1.17 clients.
*
* @return true if enabled
*/
boolean bedrockAtY0();
/**
* Shows sculk shriekers as crying obsidian for 1.18.2 clients on 1.19+ servers. This fixes collision and block breaking issues.
*
* @return true if enabled
*/
boolean sculkShriekerToCryingObsidian();
/**
* Maps the darkness effect to blindness for 1.18.2 clients on 1.19+ servers.
*
* @return true if enabled
*/
boolean mapDarknessEffect();
/**
* Suppresses warnings of missing emulations for certain features that are not supported (e.g. world height in 1.17+).
*
* @return true if enabled
*/
boolean suppressEmulationWarnings();
}
@@ -21,41 +21,45 @@ package com.viaversion.viabackwards.api;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.ViaBackwardsConfig;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.protocol1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viabackwards.protocol.protocol1_11to1_11_1.Protocol1_11To1_11_1;
import com.viaversion.viabackwards.protocol.protocol1_12_1to1_12_2.Protocol1_12_1To1_12_2;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viabackwards.protocol.protocol1_12to1_12_1.Protocol1_12To1_12_1;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.Protocol1_13_1To1_13_2;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.Protocol1_13_2To1_14;
import com.viaversion.viabackwards.protocol.protocol1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viabackwards.protocol.protocol1_14_1to1_14_2.Protocol1_14_1To1_14_2;
import com.viaversion.viabackwards.protocol.protocol1_14_2to1_14_3.Protocol1_14_2To1_14_3;
import com.viaversion.viabackwards.protocol.protocol1_14_3to1_14_4.Protocol1_14_3To1_14_4;
import com.viaversion.viabackwards.protocol.protocol1_14_4to1_15.Protocol1_14_4To1_15;
import com.viaversion.viabackwards.protocol.protocol1_14to1_14_1.Protocol1_14To1_14_1;
import com.viaversion.viabackwards.protocol.protocol1_15_1to1_15_2.Protocol1_15_1To1_15_2;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viabackwards.protocol.protocol1_15to1_15_1.Protocol1_15To1_15_1;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.Protocol1_16_1To1_16_2;
import com.viaversion.viabackwards.protocol.protocol1_16_2to1_16_3.Protocol1_16_2To1_16_3;
import com.viaversion.viabackwards.protocol.protocol1_16_3to1_16_4.Protocol1_16_3To1_16_4;
import com.viaversion.viabackwards.protocol.protocol1_16_4to1_17.Protocol1_16_4To1_17;
import com.viaversion.viabackwards.protocol.protocol1_16to1_16_1.Protocol1_16To1_16_1;
import com.viaversion.viabackwards.protocol.protocol1_17_1to1_18.Protocol1_17_1To1_18;
import com.viaversion.viabackwards.protocol.protocol1_17to1_17_1.Protocol1_17To1_17_1;
import com.viaversion.viabackwards.protocol.protocol1_18_2to1_19.Protocol1_18_2To1_19;
import com.viaversion.viabackwards.protocol.protocol1_18to1_18_2.Protocol1_18To1_18_2;
import com.viaversion.viabackwards.protocol.protocol1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.Protocol1_19_3To1_19_4;
import com.viaversion.viabackwards.protocol.protocol1_19_4to1_20.Protocol1_19_4To1_20;
import com.viaversion.viabackwards.protocol.protocol1_19to1_19_1.Protocol1_19To1_19_1;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viabackwards.protocol.protocol1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viabackwards.protocol.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2To1_9_3_4;
import com.viaversion.viabackwards.protocol.protocol1_9_4to1_10.Protocol1_9_4To1_10;
import com.viaversion.viabackwards.protocol.protocol1_9to1_9_1.Protocol1_9To1_9_1;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.Protocol1_12_2To1_12_1;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viabackwards.protocol.v1_12_1to1_12.Protocol1_12_1To1_12;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viabackwards.protocol.v1_14to1_13_2.Protocol1_14To1_13_2;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viabackwards.protocol.v1_14_2to1_14_1.Protocol1_14_2To1_14_1;
import com.viaversion.viabackwards.protocol.v1_14_3to1_14_2.Protocol1_14_3To1_14_2;
import com.viaversion.viabackwards.protocol.v1_14_4to1_14_3.Protocol1_14_4To1_14_3;
import com.viaversion.viabackwards.protocol.v1_15to1_14_4.Protocol1_15To1_14_4;
import com.viaversion.viabackwards.protocol.v1_14_1to1_14.Protocol1_14_1To1_14;
import com.viaversion.viabackwards.protocol.v1_15_2to1_15_1.Protocol1_15_2To1_15_1;
import com.viaversion.viabackwards.protocol.v1_16to1_15_2.Protocol1_16To1_15_2;
import com.viaversion.viabackwards.protocol.v1_15_1to1_15.Protocol1_15_1To1_15;
import com.viaversion.viabackwards.protocol.v1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viabackwards.protocol.v1_16_3to1_16_2.Protocol1_16_3To1_16_2;
import com.viaversion.viabackwards.protocol.v1_16_4to1_16_3.Protocol1_16_4To1_16_3;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_16_1to1_16.Protocol1_16_1To1_16;
import com.viaversion.viabackwards.protocol.v1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.Protocol1_17_1To1_17;
import com.viaversion.viabackwards.protocol.v1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viabackwards.protocol.v1_18_2to1_18.Protocol1_18_2To1_18;
import com.viaversion.viabackwards.protocol.v1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viabackwards.protocol.v1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viabackwards.protocol.v1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viabackwards.protocol.v1_20_3to1_20_2.Protocol1_20_3To1_20_2;
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viabackwards.protocol.v1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.task.PlayerPacketsTickTask;
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.Protocol1_21To1_20_5;
import com.viaversion.viabackwards.protocol.v1_9_3to1_9_1.Protocol1_9_3To1_9_1;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viabackwards.protocol.v1_9_1to1_9.Protocol1_9_1To1_9;
import com.viaversion.viabackwards.utils.VersionInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
@@ -67,13 +71,13 @@ import java.util.logging.Logger;
public interface ViaBackwardsPlatform {
String MINIMUM_VV_VERSION = "4.9.3";
String MINIMUM_VV_VERSION = "5.1.2";
/**
* Initialize ViaBackwards.
*/
default void init(final File configFile) {
ViaBackwardsConfig config = new ViaBackwardsConfig(configFile);
ViaBackwardsConfig config = new ViaBackwardsConfig(configFile, getLogger());
config.reload();
Via.getManager().getConfigurationProvider().register(config);
@@ -91,51 +95,62 @@ public interface ViaBackwardsPlatform {
getLogger().info("Registering protocols...");
final ProtocolManager protocolManager = Via.getManager().getProtocolManager();
protocolManager.registerProtocol(new Protocol1_9To1_9_1(), ProtocolVersion.v1_9, ProtocolVersion.v1_9_1);
protocolManager.registerProtocol(new Protocol1_9_1_2To1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getVersion(), ProtocolVersion.v1_9_2.getVersion()), ProtocolVersion.v1_9_3.getVersion());
protocolManager.registerProtocol(new Protocol1_9_4To1_10(), ProtocolVersion.v1_9_3, ProtocolVersion.v1_10);
protocolManager.registerProtocol(new Protocol1_9_1To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_9_1);
protocolManager.registerProtocol(new Protocol1_9_3To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9_3);
protocolManager.registerProtocol(new Protocol1_10To1_9_3(), ProtocolVersion.v1_9_3, ProtocolVersion.v1_10);
protocolManager.registerProtocol(new Protocol1_10To1_11(), ProtocolVersion.v1_10, ProtocolVersion.v1_11);
protocolManager.registerProtocol(new Protocol1_11To1_11_1(), ProtocolVersion.v1_11, ProtocolVersion.v1_11_1);
protocolManager.registerProtocol(new Protocol1_11To1_10(), ProtocolVersion.v1_10, ProtocolVersion.v1_11);
protocolManager.registerProtocol(new Protocol1_11_1To1_11(), ProtocolVersion.v1_11, ProtocolVersion.v1_11_1);
protocolManager.registerProtocol(new Protocol1_11_1To1_12(), ProtocolVersion.v1_11_1, ProtocolVersion.v1_12);
protocolManager.registerProtocol(new Protocol1_12To1_12_1(), ProtocolVersion.v1_12, ProtocolVersion.v1_12_1);
protocolManager.registerProtocol(new Protocol1_12_1To1_12_2(), ProtocolVersion.v1_12_1, ProtocolVersion.v1_12_2);
protocolManager.registerProtocol(new Protocol1_12To1_11_1(), ProtocolVersion.v1_11_1, ProtocolVersion.v1_12);
protocolManager.registerProtocol(new Protocol1_12_1To1_12(), ProtocolVersion.v1_12, ProtocolVersion.v1_12_1);
protocolManager.registerProtocol(new Protocol1_12_2To1_12_1(), ProtocolVersion.v1_12_1, ProtocolVersion.v1_12_2);
protocolManager.registerProtocol(new Protocol1_12_2To1_13(), ProtocolVersion.v1_12_2, ProtocolVersion.v1_13);
protocolManager.registerProtocol(new Protocol1_13To1_13_1(), ProtocolVersion.v1_13, ProtocolVersion.v1_13_1);
protocolManager.registerProtocol(new Protocol1_13_1To1_13_2(), ProtocolVersion.v1_13_1, ProtocolVersion.v1_13_2);
protocolManager.registerProtocol(new Protocol1_13To1_12_2(), ProtocolVersion.v1_12_2, ProtocolVersion.v1_13);
protocolManager.registerProtocol(new Protocol1_13_1To1_13(), ProtocolVersion.v1_13, ProtocolVersion.v1_13_1);
protocolManager.registerProtocol(new Protocol1_13_2To1_13_1(), ProtocolVersion.v1_13_1, ProtocolVersion.v1_13_2);
protocolManager.registerProtocol(new Protocol1_13_2To1_14(), ProtocolVersion.v1_13_2, ProtocolVersion.v1_14);
protocolManager.registerProtocol(new Protocol1_14To1_14_1(), ProtocolVersion.v1_14, ProtocolVersion.v1_14_1);
protocolManager.registerProtocol(new Protocol1_14_1To1_14_2(), ProtocolVersion.v1_14_1, ProtocolVersion.v1_14_2);
protocolManager.registerProtocol(new Protocol1_14_2To1_14_3(), ProtocolVersion.v1_14_2, ProtocolVersion.v1_14_3);
protocolManager.registerProtocol(new Protocol1_14_3To1_14_4(), ProtocolVersion.v1_14_3, ProtocolVersion.v1_14_4);
protocolManager.registerProtocol(new Protocol1_14To1_13_2(), ProtocolVersion.v1_13_2, ProtocolVersion.v1_14);
protocolManager.registerProtocol(new Protocol1_14_1To1_14(), ProtocolVersion.v1_14, ProtocolVersion.v1_14_1);
protocolManager.registerProtocol(new Protocol1_14_2To1_14_1(), ProtocolVersion.v1_14_1, ProtocolVersion.v1_14_2);
protocolManager.registerProtocol(new Protocol1_14_3To1_14_2(), ProtocolVersion.v1_14_2, ProtocolVersion.v1_14_3);
protocolManager.registerProtocol(new Protocol1_14_4To1_14_3(), ProtocolVersion.v1_14_3, ProtocolVersion.v1_14_4);
protocolManager.registerProtocol(new Protocol1_14_4To1_15(), ProtocolVersion.v1_14_4, ProtocolVersion.v1_15);
protocolManager.registerProtocol(new Protocol1_15To1_15_1(), ProtocolVersion.v1_15, ProtocolVersion.v1_15_1);
protocolManager.registerProtocol(new Protocol1_15_1To1_15_2(), ProtocolVersion.v1_15_1, ProtocolVersion.v1_15_2);
protocolManager.registerProtocol(new Protocol1_15To1_14_4(), ProtocolVersion.v1_14_4, ProtocolVersion.v1_15);
protocolManager.registerProtocol(new Protocol1_15_1To1_15(), ProtocolVersion.v1_15, ProtocolVersion.v1_15_1);
protocolManager.registerProtocol(new Protocol1_15_2To1_15_1(), ProtocolVersion.v1_15_1, ProtocolVersion.v1_15_2);
protocolManager.registerProtocol(new Protocol1_15_2To1_16(), ProtocolVersion.v1_15_2, ProtocolVersion.v1_16);
protocolManager.registerProtocol(new Protocol1_16To1_16_1(), ProtocolVersion.v1_16, ProtocolVersion.v1_16_1);
protocolManager.registerProtocol(new Protocol1_16_1To1_16_2(), ProtocolVersion.v1_16_1, ProtocolVersion.v1_16_2);
protocolManager.registerProtocol(new Protocol1_16_2To1_16_3(), ProtocolVersion.v1_16_2, ProtocolVersion.v1_16_3);
protocolManager.registerProtocol(new Protocol1_16_3To1_16_4(), ProtocolVersion.v1_16_3, ProtocolVersion.v1_16_4);
protocolManager.registerProtocol(new Protocol1_16To1_15_2(), ProtocolVersion.v1_15_2, ProtocolVersion.v1_16);
protocolManager.registerProtocol(new Protocol1_16_1To1_16(), ProtocolVersion.v1_16, ProtocolVersion.v1_16_1);
protocolManager.registerProtocol(new Protocol1_16_2To1_16_1(), ProtocolVersion.v1_16_1, ProtocolVersion.v1_16_2);
protocolManager.registerProtocol(new Protocol1_16_3To1_16_2(), ProtocolVersion.v1_16_2, ProtocolVersion.v1_16_3);
protocolManager.registerProtocol(new Protocol1_16_4To1_16_3(), ProtocolVersion.v1_16_3, ProtocolVersion.v1_16_4);
protocolManager.registerProtocol(new Protocol1_16_4To1_17(), ProtocolVersion.v1_16_4, ProtocolVersion.v1_17);
protocolManager.registerProtocol(new Protocol1_17To1_17_1(), ProtocolVersion.v1_17, ProtocolVersion.v1_17_1);
protocolManager.registerProtocol(new Protocol1_17To1_16_4(), ProtocolVersion.v1_16_4, ProtocolVersion.v1_17);
protocolManager.registerProtocol(new Protocol1_17_1To1_17(), ProtocolVersion.v1_17, ProtocolVersion.v1_17_1);
protocolManager.registerProtocol(new Protocol1_17_1To1_18(), ProtocolVersion.v1_17_1, ProtocolVersion.v1_18);
protocolManager.registerProtocol(new Protocol1_18To1_18_2(), ProtocolVersion.v1_18, ProtocolVersion.v1_18_2);
protocolManager.registerProtocol(new Protocol1_18To1_17_1(), ProtocolVersion.v1_17_1, ProtocolVersion.v1_18);
protocolManager.registerProtocol(new Protocol1_18_2To1_18(), ProtocolVersion.v1_18, ProtocolVersion.v1_18_2);
protocolManager.registerProtocol(new Protocol1_18_2To1_19(), ProtocolVersion.v1_18_2, ProtocolVersion.v1_19);
protocolManager.registerProtocol(new Protocol1_19To1_19_1(), ProtocolVersion.v1_19, ProtocolVersion.v1_19_1);
protocolManager.registerProtocol(new Protocol1_19_1To1_19_3(), ProtocolVersion.v1_19_1, ProtocolVersion.v1_19_3);
protocolManager.registerProtocol(new Protocol1_19_3To1_19_4(), ProtocolVersion.v1_19_3, ProtocolVersion.v1_19_4);
protocolManager.registerProtocol(new Protocol1_19To1_18_2(), ProtocolVersion.v1_18_2, ProtocolVersion.v1_19);
protocolManager.registerProtocol(new Protocol1_19_1To1_19(), ProtocolVersion.v1_19, ProtocolVersion.v1_19_1);
protocolManager.registerProtocol(new Protocol1_19_3To1_19_1(), ProtocolVersion.v1_19_1, ProtocolVersion.v1_19_3);
protocolManager.registerProtocol(new Protocol1_19_4To1_19_3(), ProtocolVersion.v1_19_3, ProtocolVersion.v1_19_4);
protocolManager.registerProtocol(new Protocol1_19_4To1_20(), ProtocolVersion.v1_19_4, ProtocolVersion.v1_20);
protocolManager.registerProtocol(new Protocol1_20To1_20_2(), ProtocolVersion.v1_20, ProtocolVersion.v1_20_2);
protocolManager.registerProtocol(new Protocol1_20_2To1_20_3(), ProtocolVersion.v1_20_2, ProtocolVersion.v1_20_3);
protocolManager.registerProtocol(new Protocol1_20To1_19_4(), ProtocolVersion.v1_19_4, ProtocolVersion.v1_20);
protocolManager.registerProtocol(new Protocol1_20_2To1_20(), ProtocolVersion.v1_20, ProtocolVersion.v1_20_2);
protocolManager.registerProtocol(new Protocol1_20_3To1_20_2(), ProtocolVersion.v1_20_2, ProtocolVersion.v1_20_3);
protocolManager.registerProtocol(new Protocol1_20_5To1_20_3(), ProtocolVersion.v1_20_3, ProtocolVersion.v1_20_5);
protocolManager.registerProtocol(new Protocol1_21To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_21);
protocolManager.registerProtocol(new Protocol1_21_2To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_21_2);
}
default void enable() {
final ProtocolVersion protocolVersion = Via.getAPI().getServerVersion().highestSupportedProtocolVersion();
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_21_2)) {
Via.getPlatform().runRepeatingSync(new PlayerPacketsTickTask(), 1L);
}
}
/**
@@ -149,7 +164,7 @@ public interface ViaBackwardsPlatform {
String vvVersion = Via.getPlatform().getPluginVersion();
if (vvVersion != null && new Version(vvVersion).compareTo(new Version(MINIMUM_VV_VERSION + "--")) < 0) {
getLogger().severe("================================");
getLogger().severe("YOUR VIAVERSION IS OUTDATED");
getLogger().severe("YOUR VIAVERSION IS OUTDATED (you are running " + vvVersion + ")");
getLogger().severe("PLEASE USE VIAVERSION " + MINIMUM_VV_VERSION + " OR NEWER");
getLogger().severe("LINK: https://ci.viaversion.com/");
getLogger().severe("VIABACKWARDS WILL NOW DISABLE");
@@ -22,54 +22,58 @@ import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.BiMappings;
import com.viaversion.viaversion.api.data.IdentityMappings;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectArrayMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsMappings extends MappingDataBase {
public class BackwardsMappingData extends MappingDataBase {
private final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass;
protected Int2ObjectMap<MappedItem> backwardsItemMappings;
private Map<String, String> backwardsSoundMappings;
private Map<String, String> entityNames;
private Int2ObjectMap<String> enchantmentNames;
public BackwardsMappings(final String unmappedVersion, final String mappedVersion) {
public BackwardsMappingData(final String unmappedVersion, final String mappedVersion) {
this(unmappedVersion, mappedVersion, null);
}
public BackwardsMappings(final String unmappedVersion, final String mappedVersion, @Nullable final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass) {
public BackwardsMappingData(final String unmappedVersion, final String mappedVersion, @Nullable final Class<? extends Protocol<?, ?, ?, ?>> vvProtocolClass) {
super(unmappedVersion, mappedVersion);
Preconditions.checkArgument(vvProtocolClass == null || !vvProtocolClass.isAssignableFrom(BackwardsProtocol.class));
Preconditions.checkArgument(vvProtocolClass == null || !BackwardsProtocol.class.isAssignableFrom(vvProtocolClass));
this.vvProtocolClass = vvProtocolClass;
}
@Override
protected void loadExtras(final CompoundTag data) {
final CompoundTag itemNames = data.get("itemnames");
final CompoundTag itemNames = data.getCompoundTag("itemnames");
if (itemNames != null) {
Preconditions.checkNotNull(itemMappings);
backwardsItemMappings = new Int2ObjectOpenHashMap<>(itemNames.size());
final CompoundTag extraItemData = data.get("itemdata");
final CompoundTag extraItemData = data.getCompoundTag("itemdata");
for (final Map.Entry<String, Tag> entry : itemNames.entrySet()) {
final StringTag name = (StringTag) entry.getValue();
final int id = Integer.parseInt(entry.getKey());
Integer customModelData = null;
if (extraItemData != null && extraItemData.contains(entry.getKey())) {
final CompoundTag entryTag = extraItemData.get(entry.getKey());
final NumberTag customModelDataTag = entryTag.get("custom_model_data");
final CompoundTag entryTag = extraItemData.getCompoundTag(entry.getKey());
final NumberTag customModelDataTag = entryTag.getNumberTag("custom_model_data");
customModelData = customModelDataTag != null ? customModelDataTag.asInt() : null;
}
@@ -77,32 +81,50 @@ public class BackwardsMappings extends MappingDataBase {
}
}
final CompoundTag entityNames = data.get("entitynames");
if (entityNames != null) {
this.entityNames = new HashMap<>(entityNames.size());
for (final Map.Entry<String, Tag> entry : entityNames.entrySet()) {
final StringTag mappedTag = (StringTag) entry.getValue();
this.entityNames.put(entry.getKey(), mappedTag.getValue());
}
this.entityNames = loadNameByStringMappings(data, "entitynames");
this.enchantmentNames = loadNameByIdMappings(data, "enchantmentnames");
this.backwardsSoundMappings = loadNameByStringMappings(data, "soundnames");
}
private @Nullable Map<String, String> loadNameByStringMappings(final CompoundTag data, final String key) {
final CompoundTag nameMappings = data.getCompoundTag(key);
if (nameMappings == null) {
return null;
}
final CompoundTag soundNames = data.get("soundnames");
if (soundNames != null) {
backwardsSoundMappings = new HashMap<>(soundNames.size());
for (final Map.Entry<String, Tag> entry : soundNames.entrySet()) {
final StringTag mappedTag = (StringTag) entry.getValue();
backwardsSoundMappings.put(entry.getKey(), mappedTag.getValue());
}
final Map<String, String> map = new HashMap<>(nameMappings.size());
for (final Map.Entry<String, Tag> entry : nameMappings.entrySet()) {
final StringTag mappedTag = (StringTag) entry.getValue();
map.put(entry.getKey(), mappedTag.getValue());
}
return map;
}
private @Nullable Int2ObjectMap<String> loadNameByIdMappings(final CompoundTag data, final String key) {
final CompoundTag nameMappings = data.getCompoundTag(key);
if (nameMappings == null) {
return null;
}
final Int2ObjectMap<String> map = new Int2ObjectArrayMap<>(nameMappings.size());
for (final Map.Entry<String, Tag> entry : nameMappings.entrySet()) {
final StringTag mappedTag = (StringTag) entry.getValue();
map.put(Integer.parseInt(entry.getKey()), mappedTag.getValue());
}
return map;
}
@Override
protected @Nullable BiMappings loadBiMappings(final CompoundTag data, final String key) {
if (key.equals("items") && vvProtocolClass != null) {
final Mappings mappings = super.loadMappings(data, key);
Mappings mappings = super.loadMappings(data, key);
final MappingData mappingData = Via.getManager().getProtocolManager().getProtocol(vvProtocolClass).getMappingData();
if (mappingData != null && mappingData.getItemMappings() != null) {
return ItemMappings.of(mappings, mappingData.getItemMappings());
final BiMappings vvItemMappings = mappingData.getItemMappings();
if (mappings == null) {
mappings = new IdentityMappings(vvItemMappings.mappedSize(), vvItemMappings.size());
}
return ItemMappings.of(mappings, vvItemMappings);
}
}
return super.loadBiMappings(data, key);
@@ -129,6 +151,11 @@ public class BackwardsMappings extends MappingDataBase {
return checkValidity(id, this.itemMappings.inverse().getNewId(id), "item");
}
@Override
public int getNewAttributeId(final int id) {
return this.attributeMappings.getNewId(id);
}
public @Nullable MappedItem getMappedItem(final int id) {
return backwardsItemMappings != null ? backwardsItemMappings.get(id) : null;
}
@@ -142,13 +169,20 @@ public class BackwardsMappings extends MappingDataBase {
public @Nullable String mappedEntityName(final String entityName) {
if (entityNames == null) {
ViaBackwards.getPlatform().getLogger().severe("No entity mappings found when requesting them for " + entityName);
new Exception().printStackTrace();
getLogger().log(Level.SEVERE, "No entity mappings found when requesting them for " + entityName, new RuntimeException());
return null;
}
return entityNames.get(entityName);
}
public @Nullable String mappedEnchantmentName(final int enchantmentId) {
if (enchantmentNames == null) {
ViaBackwards.getPlatform().getLogger().log(Level.SEVERE, "No enchantment name mappings found when requesting " + enchantmentId, new RuntimeException());
return null;
}
return enchantmentNames.get(enchantmentId);
}
public @Nullable Int2ObjectMap<MappedItem> getBackwardsItemMappings() {
return backwardsItemMappings;
}
@@ -167,7 +201,7 @@ public class BackwardsMappings extends MappingDataBase {
}
@Override
protected @Nullable CompoundTag readNBTFile(final String name) {
return VBMappingDataLoader.loadNBTFromDir(name);
protected @Nullable CompoundTag readMappingsFile(final String name) {
return BackwardsMappingDataLoader.INSTANCE.loadNBTFromDir(name);
}
}
@@ -0,0 +1,87 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsMappingDataLoader extends MappingDataLoader {
public static final BackwardsMappingDataLoader INSTANCE = new BackwardsMappingDataLoader(BackwardsMappingDataLoader.class, "assets/viabackwards/data/");
public BackwardsMappingDataLoader(final Class<?> dataLoaderClass, final String dataPath) {
super(dataLoaderClass, dataPath);
}
/**
* Returns nbt data from the plugin folder or packed assets.
* If a file with the same name exists in the plugin folder, the data of the original packed tag will be merged with the file's tag.
*
* @param name name of the file
* @return nbt data from the plugin folder or packed assets
*/
public @Nullable CompoundTag loadNBTFromDir(final String name) {
final CompoundTag packedData = loadNBT(name);
final File file = new File(getDataFolder(), name);
if (!file.exists()) {
return packedData;
}
getLogger().info("Loading " + name + " from plugin folder");
try {
final CompoundTag fileData = MAPPINGS_READER.read(file.toPath(), false);
return mergeTags(packedData, fileData);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private CompoundTag mergeTags(final CompoundTag original, final CompoundTag extra) {
for (final Map.Entry<String, Tag> entry : extra.entrySet()) {
if (entry.getValue() instanceof CompoundTag) {
// For compound tags, don't replace the entire tag
final CompoundTag originalEntry = original.getCompoundTag(entry.getKey());
if (originalEntry != null) {
mergeTags(originalEntry, (CompoundTag) entry.getValue());
continue;
}
}
original.put(entry.getKey(), entry.getValue());
}
return original;
}
@Override
public Logger getLogger() {
return ViaBackwards.getPlatform().getLogger();
}
@Override
public File getDataFolder() {
return ViaBackwards.getPlatform().getDataFolder();
}
}
@@ -17,6 +17,7 @@
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.ComponentUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,6 +25,7 @@ public class MappedItem {
private final int id;
private final String jsonName;
private final Tag tagName;
private final Integer customModelData;
public MappedItem(final int id, final String name) {
@@ -33,17 +35,22 @@ public class MappedItem {
public MappedItem(final int id, final String name, @Nullable final Integer customModelData) {
this.id = id;
this.jsonName = ComponentUtil.legacyToJsonString("§f" + name, true);
this.tagName = ComponentUtil.jsonStringToTag(jsonName);
this.customModelData = customModelData;
}
public int getId() {
public int id() {
return id;
}
public String getJsonName() {
public String jsonName() {
return jsonName;
}
public Tag tagName() {
return tagName;
}
public @Nullable Integer customModelData() {
return customModelData;
}
@@ -17,8 +17,8 @@
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.viabackwards.utils.Block;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.util.IdAndData;
import org.checkerframework.checker.nullness.qual.Nullable;
public class MappedLegacyBlockItem {
@@ -26,14 +26,18 @@ public class MappedLegacyBlockItem {
private final int id;
private final short data;
private final String name;
private final Block block;
private final IdAndData block;
private BlockEntityHandler blockEntityHandler;
public MappedLegacyBlockItem(int id, short data, @Nullable String name, boolean block) {
public MappedLegacyBlockItem(int id) {
this(id, (short) -1, null, Type.ITEM);
}
public MappedLegacyBlockItem(int id, short data, @Nullable String name, Type type) {
this.id = id;
this.data = data;
this.name = name != null ? "§f" + name : null;
this.block = block ? new Block(id, data) : null;
this.block = type != Type.ITEM ? data != -1 ? new IdAndData(id, data) : new IdAndData(id) : null;
}
public int getId() {
@@ -48,11 +52,7 @@ public class MappedLegacyBlockItem {
return name;
}
public boolean isBlock() {
return block != null;
}
public Block getBlock() {
public IdAndData getBlock() {
return block;
}
@@ -71,6 +71,23 @@ public class MappedLegacyBlockItem {
@FunctionalInterface
public interface BlockEntityHandler {
CompoundTag handleOrNewCompoundTag(int block, CompoundTag tag);
void handleCompoundTag(int block, CompoundTag tag);
}
public enum Type {
ITEM("items"),
BLOCK_ITEM("block-items"),
BLOCK("blocks");
final String name;
Type(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
@@ -1,126 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.libs.gson.JsonIOException;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.libs.opennbt.tag.io.NBTIO;
import com.viaversion.viaversion.libs.opennbt.tag.io.TagReader;
import com.viaversion.viaversion.util.GsonUtil;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class VBMappingDataLoader {
private static final TagReader<CompoundTag> TAG_READER = NBTIO.reader(CompoundTag.class).named();
public static @Nullable CompoundTag loadNBT(final String name) {
final InputStream resource = getResource(name);
if (resource == null) {
return null;
}
try (final InputStream stream = resource) {
return TAG_READER.read(stream);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
/**
* Returns nbt data from the plugin folder or packed assets.
* If a file with the same name exists in the plugin folder, the data of the original packed tag will be merged with the file's tag.
*
* @param name name of the file
* @return nbt data from the plugin folder or packed assets
*/
public static @Nullable CompoundTag loadNBTFromDir(final String name) {
final CompoundTag packedData = loadNBT(name);
final File file = new File(ViaBackwards.getPlatform().getDataFolder(), name);
if (!file.exists()) {
return packedData;
}
ViaBackwards.getPlatform().getLogger().info("Loading " + name + " from plugin folder");
try {
final CompoundTag fileData = TAG_READER.read(file.toPath(), false);
return mergeTags(packedData, fileData);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private static CompoundTag mergeTags(final CompoundTag original, final CompoundTag extra) {
for (final Map.Entry<String, Tag> entry : extra.entrySet()) {
if (entry.getValue() instanceof CompoundTag) {
// For compound tags, don't replace the entire tag
final CompoundTag originalEntry = original.get(entry.getKey());
if (originalEntry != null) {
mergeTags(originalEntry, (CompoundTag) entry.getValue());
continue;
}
}
original.put(entry.getKey(), entry.getValue());
}
return original;
}
public static JsonObject loadData(final String name) {
try (final InputStream stream = getResource(name)) {
if (stream == null) return null;
return GsonUtil.getGson().fromJson(new InputStreamReader(stream), JsonObject.class);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public static JsonObject loadFromDataDir(final String name) {
final File file = new File(ViaBackwards.getPlatform().getDataFolder(), name);
if (!file.exists()) {
return loadData(name);
}
// Load the file from the platform's directory if present
try (final FileReader reader = new FileReader(file)) {
return GsonUtil.getGson().fromJson(reader, JsonObject.class);
} catch (final JsonSyntaxException e) {
ViaBackwards.getPlatform().getLogger().warning(name + " is badly formatted!");
e.printStackTrace();
ViaBackwards.getPlatform().getLogger().warning("Falling back to resource's file!");
return loadData(name);
} catch (final IOException | JsonIOException e) {
e.printStackTrace();
}
return null;
}
public static @Nullable InputStream getResource(final String name) {
return VBMappingDataLoader.class.getClassLoader().getResourceAsStream("assets/viabackwards/data/" + name);
}
}
@@ -19,7 +19,7 @@ package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viabackwards.api.BackwardsProtocol;
public class EntityObjectData extends EntityData {
public class EntityObjectData extends EntityReplacement {
private final int objectData;
public EntityObjectData(BackwardsProtocol<?, ?, ?, ?> protocol, String key, int id, int replacementId, int objectData) {
@@ -17,13 +17,13 @@
*/
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.EntityRewriterBase;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.ProtocolLogger;
import java.util.function.Supplier;
public class EntityPositionHandler {
@@ -41,22 +41,23 @@ public class EntityPositionHandler {
this.storageSupplier = storageSupplier;
}
public void cacheEntityPosition(PacketWrapper wrapper, boolean create, boolean relative) throws Exception {
public void cacheEntityPosition(PacketWrapper wrapper, boolean create, boolean relative) {
cacheEntityPosition(wrapper,
wrapper.get(Type.DOUBLE, 0), wrapper.get(Type.DOUBLE, 1), wrapper.get(Type.DOUBLE, 2), create, relative);
wrapper.get(Types.DOUBLE, 0), wrapper.get(Types.DOUBLE, 1), wrapper.get(Types.DOUBLE, 2), create, relative);
}
public void cacheEntityPosition(PacketWrapper wrapper, double x, double y, double z, boolean create, boolean relative) throws Exception {
int entityId = wrapper.get(Type.VAR_INT, 0);
public void cacheEntityPosition(PacketWrapper wrapper, double x, double y, double z, boolean create, boolean relative) {
int entityId = wrapper.get(Types.VAR_INT, 0);
StoredEntityData storedEntity = entityRewriter.tracker(wrapper.user()).entityData(entityId);
if (storedEntity == null) {
if (Via.getManager().isDebug()) { // There is too many plugins violating this out there, and reading seems to be hard! :>
ViaBackwards.getPlatform().getLogger().warning("Stored entity with id " + entityId + " missing at position: " + x + " - " + y + " - " + z + " in " + storageClass.getSimpleName());
ProtocolLogger logger = entityRewriter.protocol().getLogger();
logger.warning("Stored entity with id " + entityId + " missing at position: " + x + " - " + y + " - " + z + " in " + storageClass.getSimpleName());
if (entityId == -1 && x == 0 && y == 0 && z == 0) {
ViaBackwards.getPlatform().getLogger().warning("DO NOT REPORT THIS TO VIA, THIS IS A PLUGIN ISSUE");
logger.warning("DO NOT REPORT THIS TO VIA, THIS IS A PLUGIN ISSUE");
} else if (!warnedForMissingEntity) {
warnedForMissingEntity = true;
ViaBackwards.getPlatform().getLogger().warning("This is very likely caused by a plugin sending a teleport packet for an entity outside of the player's range.");
logger.warning("This is very likely caused by a plugin sending a teleport packet for an entity outside of the player's range.");
}
}
return;
@@ -69,19 +70,23 @@ public class EntityPositionHandler {
} else {
positionStorage = storedEntity.get(storageClass);
if (positionStorage == null) {
ViaBackwards.getPlatform().getLogger().warning("Stored entity with id " + entityId + " missing " + storageClass.getSimpleName());
entityRewriter.protocol().getLogger().warning("Stored entity with id " + entityId + " missing " + storageClass.getSimpleName());
return;
}
}
positionStorage.setCoordinates(x, y, z, relative);
if (relative) {
positionStorage.addRelativePosition(x, y, z);
} else {
positionStorage.setPosition(x, y, z);
}
}
public EntityPositionStorage getStorage(UserConnection user, int entityId) {
StoredEntityData storedEntity = entityRewriter.tracker(user).entityData(entityId);
EntityPositionStorage entityStorage;
if (storedEntity == null || (entityStorage = storedEntity.get(EntityPositionStorage.class)) == null) {
ViaBackwards.getPlatform().getLogger().warning("Untracked entity with id " + entityId + " in " + storageClass.getSimpleName());
entityRewriter.protocol().getLogger().warning("Untracked entity with id " + entityId + " in " + storageClass.getSimpleName());
return null;
}
return entityStorage;
@@ -98,8 +103,8 @@ public class EntityPositionHandler {
}
double pitch = -Math.asin(dY / r) / Math.PI * 180;
wrapper.write(Type.BYTE, (byte) (yaw * 256f / 360f));
wrapper.write(Type.BYTE, (byte) (pitch * 256f / 360f));
wrapper.write(Types.BYTE, (byte) (yaw * 256f / 360f));
wrapper.write(Types.BYTE, (byte) (pitch * 256f / 360f));
}
public static void writeFacingDegrees(PacketWrapper wrapper, double x, double y, double z, double targetX, double targetY, double targetZ) {
@@ -113,7 +118,7 @@ public class EntityPositionHandler {
}
double pitch = -Math.asin(dY / r) / Math.PI * 180;
wrapper.write(Type.FLOAT, (float) yaw);
wrapper.write(Type.FLOAT, (float) pitch);
wrapper.write(Types.FLOAT, (float) yaw);
wrapper.write(Types.FLOAT, (float) pitch);
}
}
@@ -22,27 +22,27 @@ public abstract class EntityPositionStorage {
private double y;
private double z;
public double getX() {
public double x() {
return x;
}
public double getY() {
public double y() {
return y;
}
public double getZ() {
public double z() {
return z;
}
public void setCoordinates(double x, double y, double z, boolean relative) {
if (relative) {
this.x += x;
this.y += y;
this.z += z;
} else {
this.x = x;
this.y = y;
this.z = z;
}
public void setPosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void addRelativePosition(double relX, double relY, double relZ) {
this.x += relX;
this.y += relY;
this.z += relZ;
}
}
@@ -20,52 +20,52 @@ package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public class EntityData {
public class EntityReplacement {
private final BackwardsProtocol<?, ?, ?, ?> protocol;
private final int id;
private final int replacementId;
private final String key;
private ComponentType componentType = ComponentType.NONE;
private MetaCreator defaultMeta;
private EntityDataCreator defaultData;
public EntityData(BackwardsProtocol<?, ?, ?, ?> protocol, EntityType type, int replacementId) {
public EntityReplacement(BackwardsProtocol<?, ?, ?, ?> protocol, EntityType type, int replacementId) {
this(protocol, type.name(), type.getId(), replacementId);
}
public EntityData(BackwardsProtocol<?, ?, ?, ?> protocol, String key, int id, int replacementId) {
public EntityReplacement(BackwardsProtocol<?, ?, ?, ?> protocol, String key, int id, int replacementId) {
this.protocol = protocol;
this.id = id;
this.replacementId = replacementId;
this.key = key.toLowerCase(Locale.ROOT);
}
public EntityData jsonName() {
public EntityReplacement jsonName() {
this.componentType = ComponentType.JSON;
return this;
}
public EntityData tagName() {
public EntityReplacement tagName() {
this.componentType = ComponentType.TAG;
return this;
}
public EntityData plainName() {
public EntityReplacement plainName() {
this.componentType = ComponentType.PLAIN;
return this;
}
public EntityData spawnMetadata(MetaCreator handler) {
this.defaultMeta = handler;
public EntityReplacement spawnEntityData(EntityDataCreator handler) {
this.defaultData = handler;
return this;
}
public boolean hasBaseMeta() {
return this.defaultMeta != null;
public boolean hasBaseData() {
return this.defaultData != null;
}
public int typeId() {
@@ -97,8 +97,8 @@ public class EntityData {
return replacementId;
}
public @Nullable MetaCreator defaultMeta() {
return defaultMeta;
public @Nullable EntityDataCreator defaultData() {
return defaultData;
}
public boolean isObjectType() {
@@ -111,18 +111,20 @@ public class EntityData {
@Override
public String toString() {
return "EntityData{" +
"id=" + id +
", mobName='" + key + '\'' +
return "EntityReplacement{" +
"protocol=" + protocol +
", id=" + id +
", replacementId=" + replacementId +
", defaultMeta=" + defaultMeta +
", key='" + key + '\'' +
", componentType=" + componentType +
", defaultData=" + defaultData +
'}';
}
@FunctionalInterface
public interface MetaCreator {
public interface EntityDataCreator {
void createMeta(WrappedMetadata storage);
void createData(WrappedEntityData storage);
}
private enum ComponentType {
@@ -18,8 +18,6 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
public abstract class PlayerPositionStorage implements StorableObject {
private double x;
@@ -29,15 +27,15 @@ public abstract class PlayerPositionStorage implements StorableObject {
protected PlayerPositionStorage() {
}
public double getX() {
public double x() {
return x;
}
public double getY() {
public double y() {
return y;
}
public double getZ() {
public double z() {
return z;
}
@@ -53,19 +51,15 @@ public abstract class PlayerPositionStorage implements StorableObject {
this.z = z;
}
public void setCoordinates(PacketWrapper wrapper, boolean relative) throws Exception {
setCoordinates(wrapper.get(Type.DOUBLE, 0), wrapper.get(Type.DOUBLE, 1), wrapper.get(Type.DOUBLE, 2), relative);
public void setPosition(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void setCoordinates(double x, double y, double z, boolean relative) {
if (relative) {
this.x += x;
this.y += y;
this.z += z;
} else {
this.x = x;
this.y = y;
this.z = z;
}
public void addRelativePosition(double relX, double relY, double relZ) {
this.x += relX;
this.y += relY;
this.z += relZ;
}
}
@@ -18,48 +18,34 @@
package com.viaversion.viabackwards.api.entities.storage;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class WrappedMetadata {
private final List<Metadata> metadataList;
public record WrappedEntityData(List<EntityData> entityDataList) {
public WrappedMetadata(List<Metadata> metadataList) {
this.metadataList = metadataList;
public boolean has(EntityData data) {
return this.entityDataList.contains(data);
}
public boolean has(Metadata data) {
return this.metadataList.contains(data);
}
public void remove(Metadata data) {
this.metadataList.remove(data);
public void remove(EntityData data) {
this.entityDataList.remove(data);
}
public void remove(int index) {
metadataList.removeIf(meta -> meta.id() == index);
entityDataList.removeIf(data -> data.id() == index);
}
public void add(Metadata data) {
this.metadataList.add(data);
public void add(EntityData data) {
this.entityDataList.add(data);
}
public @Nullable Metadata get(int index) {
for (Metadata meta : this.metadataList) {
if (index == meta.id()) {
return meta;
public @Nullable EntityData get(int index) {
for (EntityData data : this.entityDataList) {
if (index == data.id()) {
return data;
}
}
return null;
}
public List<Metadata> metadataList() {
return metadataList;
}
@Override
public String toString() {
return "MetaStorage{" + "metaDataList=" + metadataList + '}';
}
}
@@ -0,0 +1,125 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends BackwardsItemRewriterBase<C, S, T> {
public BackwardsItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType, true);
}
public BackwardsItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType, Type<Item> mappedItemType, Type<Item[]> mappedItemArrayType) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, true);
}
@Override
public @Nullable Item handleItemToClient(UserConnection connection, @Nullable Item item) {
if (item == null) {
return null;
}
CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
if (protocol.getComponentRewriter() != null && display != null) {
// Handle name and lore components
StringTag name = display.getStringTag("Name");
if (name != null) {
String newValue = protocol.getComponentRewriter().processText(connection, name.getValue()).toString();
if (!newValue.equals(name.getValue())) {
saveStringTag(display, name, "Name");
}
name.setValue(newValue);
}
ListTag<StringTag> lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
boolean changed = false;
for (StringTag loreEntry : lore) {
String newValue = protocol.getComponentRewriter().processText(connection, loreEntry.getValue()).toString();
if (!changed && !newValue.equals(loreEntry.getValue())) {
// Backup original lore before doing any modifications
changed = true;
saveListTag(display, lore, "Lore");
}
loreEntry.setValue(newValue);
}
}
}
MappedItem data = protocol.getMappingData() != null ? protocol.getMappingData().getMappedItem(item.identifier()) : null;
if (data == null) {
// Just rewrite the id
return super.handleItemToClient(connection, item);
}
if (item.tag() == null) {
item.setTag(new CompoundTag());
}
// Save original id, set remapped id
item.tag().putInt(nbtTagName("id"), item.identifier());
item.setIdentifier(data.id());
// Add custom model data
if (data.customModelData() != null && !item.tag().contains("CustomModelData")) {
item.tag().putInt("CustomModelData", data.customModelData());
}
// Set custom name - only done if there is no original one
if (display == null) {
item.tag().put("display", display = new CompoundTag());
}
if (!display.contains("Name")) {
display.put("Name", new StringTag(data.jsonName()));
display.put(nbtTagName("customName"), new ByteTag(false));
}
return item;
}
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
item.setIdentifier(((NumberTag) originalId).asInt());
}
}
return item;
}
}
@@ -18,61 +18,60 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class ItemRewriterBase<C extends ClientboundPacketType, S extends ServerboundPacketType,
public abstract class BackwardsItemRewriterBase<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends ItemRewriter<C, S, T> {
protected final String nbtTagName;
protected final boolean jsonNameFormat;
protected ItemRewriterBase(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType, boolean jsonNameFormat) {
super(protocol, itemType, itemArrayType);
this.jsonNameFormat = jsonNameFormat;
nbtTagName = "VB|" + protocol.getClass().getSimpleName();
protected BackwardsItemRewriterBase(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType, Type<Item> mappedItemType, Type<Item[]> mappedItemArrayType, boolean jsonFormat) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType);
this.jsonNameFormat = jsonFormat;
}
protected BackwardsItemRewriterBase(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType, boolean jsonNameFormat) {
this(protocol, itemType, itemArrayType, itemType, itemArrayType, jsonNameFormat);
}
@Override
public @Nullable Item handleItemToServer(@Nullable Item item) {
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(item);
super.handleItemToServer(connection, item);
restoreDisplayTag(item);
return item;
}
protected boolean hasBackupTag(CompoundTag displayTag, String tagName) {
return displayTag.contains(nbtTagName + "|o" + tagName);
protected boolean hasBackupTag(CompoundTag tag, String tagName) {
return tag.contains(nbtTagName(tagName));
}
protected void saveStringTag(CompoundTag displayTag, StringTag original, String name) {
protected void saveStringTag(CompoundTag tag, StringTag original, String name) {
// Multiple places might try to backup data
String backupName = nbtTagName + "|o" + name;
if (!displayTag.contains(backupName)) {
displayTag.putString(backupName, original.getValue());
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
tag.putString(backupName, original.getValue());
}
}
protected void saveListTag(CompoundTag displayTag, ListTag original, String name) {
protected void saveListTag(CompoundTag tag, ListTag<?> original, String name) {
// Multiple places might try to backup data
String backupName = nbtTagName + "|o" + name;
if (!displayTag.contains(backupName)) {
// Clone all tag entries
ListTag listTag = new ListTag();
for (Tag tag : original.getValue()) {
listTag.add(tag.copy());
}
displayTag.put(backupName, listTag);
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
tag.put(backupName, original.copy());
}
}
@@ -82,7 +81,7 @@ public abstract class ItemRewriterBase<C extends ClientboundPacketType, S extend
CompoundTag display = item.tag().getCompoundTag("display");
if (display != null) {
// Remove custom name / restore original name
if (display.remove(nbtTagName + "|customName") != null) {
if (display.remove(nbtTagName("customName")) != null) {
display.remove("Name");
} else {
restoreStringTag(display, "Name");
@@ -94,20 +93,21 @@ public abstract class ItemRewriterBase<C extends ClientboundPacketType, S extend
}
protected void restoreStringTag(CompoundTag tag, String tagName) {
Tag original = tag.remove(nbtTagName + "|o" + tagName);
Tag original = tag.remove(nbtTagName(tagName));
if (original instanceof StringTag) {
tag.putString(tagName, ((StringTag) original).getValue());
}
}
protected void restoreListTag(CompoundTag tag, String tagName) {
Tag original = tag.remove(nbtTagName + "|o" + tagName);
Tag original = tag.remove(nbtTagName(tagName));
if (original instanceof ListTag) {
tag.put(tagName, new ListTag(((ListTag) original).getValue()));
tag.put(tagName, ((ListTag<?>) original).copy());
}
}
public String getNbtTagName() {
return nbtTagName;
@Override
public String nbtTagName() {
return "VB|" + protocol.getClass().getSimpleName();
}
}
@@ -0,0 +1,226 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends StructuredItemRewriter<C, S, T> {
public BackwardsStructuredItemRewriter(
T protocol,
Type<Item> itemType, Type<Item[]> itemArrayType, Type<Item> mappedItemType, Type<Item[]> mappedItemArrayType,
Type<Item> itemCostType, Type<Item> optionalItemCostType, Type<Item> mappedItemCostType, Type<Item> mappedOptionalItemCostType
) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, itemCostType, optionalItemCostType, mappedItemCostType, mappedOptionalItemCostType);
}
public BackwardsStructuredItemRewriter(final T protocol, final Type<Item> itemType, final Type<Item[]> itemArrayType, final Type<Item> mappedItemType, final Type<Item[]> mappedItemArrayType) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType);
}
public BackwardsStructuredItemRewriter(final T protocol, final Type<Item> itemType, final Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType);
}
@Override
public Item handleItemToClient(final UserConnection connection, final Item item) {
if (item.isEmpty()) {
return item;
}
final StructuredDataContainer dataContainer = item.dataContainer();
updateItemDataComponentTypeIds(dataContainer, true);
final BackwardsMappingData mappingData = protocol.getMappingData();
final MappedItem mappedItem = mappingData != null ? mappingData.getMappedItem(item.identifier()) : null;
if (mappedItem == null) {
// Just rewrite the id
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getNewItemId(item.identifier()));
}
updateItemDataComponents(connection, item, true);
return item;
}
// Save original id, set remapped id
final CompoundTag tag = createCustomTag(item);
tag.putInt(nbtTagName("id"), item.identifier());
item.setIdentifier(mappedItem.id());
// Add custom model data
if (mappedItem.customModelData() != null && !dataContainer.has(StructuredDataKey.CUSTOM_MODEL_DATA)) {
dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA, mappedItem.customModelData());
}
// Set custom name - only done if there is no original one
if (!dataContainer.has(StructuredDataKey.CUSTOM_NAME)) {
dataContainer.set(StructuredDataKey.CUSTOM_NAME, mappedItem.tagName());
tag.putBoolean(nbtTagName("added_custom_name"), true);
}
updateItemDataComponents(connection, item, true);
return item;
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
if (item.isEmpty()) {
return item;
}
final StructuredDataContainer dataContainer = item.dataContainer();
updateItemDataComponentTypeIds(dataContainer, false);
final BackwardsMappingData mappingData = protocol.getMappingData();
if (mappingData != null && mappingData.getItemMappings() != null) {
item.setIdentifier(mappingData.getOldItemId(item.identifier()));
}
final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA);
if (customData != null) {
if (customData.remove(nbtTagName("id")) instanceof final IntTag originalTag) {
item.setIdentifier(originalTag.asInt());
removeCustomTag(dataContainer, customData);
}
}
restoreTextComponents(item);
updateItemDataComponents(connection, item, false);
return item;
}
protected void saveListTag(CompoundTag tag, ListTag<?> original, String name) {
// Multiple places might try to backup data
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
tag.put(backupName, original.copy());
}
}
public <T extends Tag> @Nullable ListTag<T> removeListTag(CompoundTag tag, String tagName, Class<T> tagType) {
String backupName = nbtTagName(tagName);
ListTag<T> data = tag.getListTag(backupName, tagType);
if (data == null) {
return null;
}
tag.remove(backupName);
return data;
}
protected void saveGenericTagList(CompoundTag tag, List<Tag> original, String name) {
// List tags cannot contain tags of different types, so we have to store them a bit more awkwardly as an indexed compound tag
String backupName = nbtTagName(name);
if (!tag.contains(backupName)) {
CompoundTag output = new CompoundTag();
for (int i = 0; i < original.size(); i++) {
output.put(Integer.toString(i), original.get(i));
}
tag.put(backupName, output);
}
}
protected List<Tag> removeGenericTagList(CompoundTag tag, String name) {
String backupName = nbtTagName(name);
CompoundTag data = tag.getCompoundTag(backupName);
if (data == null) {
return null;
}
tag.remove(backupName);
return new ArrayList<>(data.values());
}
protected Tag holderSetToTag(final HolderSet set) {
if (set.hasIds()) {
return new IntArrayTag(set.ids());
} else {
return new StringTag(set.tagKey());
}
}
protected HolderSet restoreHolderSet(final CompoundTag tag, final String key) {
final Tag savedTag = tag.get(key);
if (savedTag == null) {
return HolderSet.of(new int[0]);
}
if (savedTag instanceof StringTag tagKey) {
return HolderSet.of(tagKey.getValue());
} else if (savedTag instanceof IntArrayTag idsTag) {
return HolderSet.of(idsTag.getValue());
} else {
return HolderSet.of(new int[0]);
}
}
protected <V> Tag holderToTag(final Holder<V> holder, final BiConsumer<V, CompoundTag> valueSaveFunction) {
if (holder.hasId()) {
return new IntTag(holder.id());
} else {
final CompoundTag savedTag = new CompoundTag();
valueSaveFunction.accept(holder.value(), savedTag);
return savedTag;
}
}
protected <V> Holder<V> restoreHolder(final CompoundTag tag, final String key, final Function<CompoundTag, V> valueRestoreFunction) {
final Tag savedTag = tag.get(key);
if (savedTag == null) {
return Holder.of(0);
}
if (savedTag instanceof IntTag idTag) {
return Holder.of(idTag.asInt());
} else if (savedTag instanceof CompoundTag compoundTag) {
return Holder.of(valueRestoreFunction.apply(compoundTag));
} else {
return Holder.of(0);
}
}
@Override
public String nbtTagName() {
return "VB|" + protocol.getClass().getSimpleName();
}
}
@@ -17,13 +17,13 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.util.Key;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -35,21 +35,23 @@ import java.util.Map;
*/
public class EnchantmentRewriter {
private final Map<String, String> enchantmentMappings = new HashMap<>();
private final ItemRewriter<?, ?, ?> itemRewriter;
public static final String ENCHANTMENT_LEVEL_TRANSLATION = "enchantment.level.%s";
protected final Map<String, String> enchantmentMappings = new HashMap<>();
protected final BackwardsItemRewriter<?, ?, ?> itemRewriter;
private final boolean jsonFormat;
public EnchantmentRewriter(ItemRewriter<?, ?, ?> itemRewriter, boolean jsonFormat) {
public EnchantmentRewriter(BackwardsItemRewriter<?, ?, ?> itemRewriter, boolean jsonFormat) {
this.itemRewriter = itemRewriter;
this.jsonFormat = jsonFormat;
}
public EnchantmentRewriter(ItemRewriter<?, ?, ?> itemRewriter) {
public EnchantmentRewriter(BackwardsItemRewriter<?, ?, ?> itemRewriter) {
this(itemRewriter, true);
}
public void registerEnchantment(String key, String replacementLore) {
enchantmentMappings.put(key, replacementLore);
enchantmentMappings.put(Key.stripMinecraftNamespace(key), replacementLore);
}
public void handleToClient(Item item) {
@@ -68,26 +70,29 @@ public class EnchantmentRewriter {
CompoundTag tag = item.tag();
if (tag == null) return;
if (tag.contains(itemRewriter.getNbtTagName() + "|Enchantments")) {
if (tag.contains(itemRewriter.nbtTagName("Enchantments"))) {
rewriteEnchantmentsToServer(tag, false);
}
if (tag.contains(itemRewriter.getNbtTagName() + "|StoredEnchantments")) {
if (tag.contains(itemRewriter.nbtTagName("StoredEnchantments"))) {
rewriteEnchantmentsToServer(tag, true);
}
}
public void rewriteEnchantmentsToClient(CompoundTag tag, boolean storedEnchant) {
String key = storedEnchant ? "StoredEnchantments" : "Enchantments";
ListTag enchantments = tag.getListTag(key);
List<Tag> loreToAdd = new ArrayList<>();
ListTag<CompoundTag> enchantments = tag.getListTag(key, CompoundTag.class);
List<StringTag> loreToAdd = new ArrayList<>();
boolean changed = false;
Iterator<Tag> iterator = enchantments.iterator();
Iterator<CompoundTag> iterator = enchantments.iterator();
while (iterator.hasNext()) {
CompoundTag enchantmentEntry = (CompoundTag) iterator.next();
CompoundTag enchantmentEntry = iterator.next();
StringTag idTag = enchantmentEntry.getStringTag("id");
if (idTag == null) {
continue;
}
String enchantmentId = idTag.getValue();
String enchantmentId = Key.stripMinecraftNamespace(idTag.getValue());
String remappedName = enchantmentMappings.get(enchantmentId);
if (remappedName != null) {
if (!changed) {
@@ -100,9 +105,11 @@ public class EnchantmentRewriter {
NumberTag levelTag = enchantmentEntry.getNumberTag("lvl");
int level = levelTag != null ? levelTag.asInt() : 1;
String loreValue = remappedName + " " + getRomanNumber(level);
String loreValue;
if (jsonFormat) {
loreValue = ComponentUtil.legacyToJsonString(loreValue);
loreValue = ChatUtil.legacyToJsonString(remappedName, ENCHANTMENT_LEVEL_TRANSLATION.formatted(level), true);
} else {
loreValue = remappedName + " " + getRomanNumber(level);
}
loreToAdd.add(new StringTag(loreValue));
@@ -123,9 +130,9 @@ public class EnchantmentRewriter {
tag.put("display", display = new CompoundTag());
}
ListTag loreTag = display.getListTag("Lore");
ListTag<StringTag> loreTag = display.getListTag("Lore", StringTag.class);
if (loreTag == null) {
display.put("Lore", loreTag = new ListTag(StringTag.class));
display.put("Lore", loreTag = new ListTag<>(StringTag.class));
} else {
// Save original lore
itemRewriter.saveListTag(display, loreTag, "Lore");
@@ -143,29 +150,18 @@ public class EnchantmentRewriter {
}
public static String getRomanNumber(int number) {
switch (number) {
case 1:
return "I";
case 2:
return "II";
case 3:
return "III";
case 4:
return "IV";
case 5:
return "V";
case 6:
return "VI";
case 7:
return "VII";
case 8:
return "VIII";
case 9:
return "IX";
case 10:
return "X";
default:
return Integer.toString(number);
}
return switch (number) {
case 1 -> "I";
case 2 -> "II";
case 3 -> "III";
case 4 -> "IV";
case 5 -> "V";
case 6 -> "VI";
case 7 -> "VII";
case 8 -> "VIII";
case 9 -> "IX";
case 10 -> "X";
default -> ENCHANTMENT_LEVEL_TRANSLATION.formatted(number); // Fallback to translation to match vanilla style
};
}
}
@@ -20,21 +20,21 @@ package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
public abstract class EntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends EntityRewriterBase<C, T> {
protected EntityRewriter(T protocol) {
this(protocol, Types1_14.META_TYPES.optionalComponentType, Types1_14.META_TYPES.booleanType);
this(protocol, Types1_14.ENTITY_DATA_TYPES.optionalComponentType, Types1_14.ENTITY_DATA_TYPES.booleanType);
}
protected EntityRewriter(T protocol, MetaType displayType, MetaType displayVisibilityType) {
protected EntityRewriter(T protocol, EntityDataType displayType, EntityDataType displayVisibilityType) {
super(protocol, displayType, 2, displayVisibilityType, 3);
}
@@ -43,15 +43,15 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - Data
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - Entity UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - Data
handler(getSpawnTrackerWithDataHandler(fallingBlockType));
}
});
@@ -62,16 +62,16 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.UUID); // Entity UUID
map(Type.VAR_INT); // Entity type
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Y
map(Type.DOUBLE); // Z
map(Type.BYTE); // Pitch
map(Type.BYTE); // Yaw
map(Type.BYTE); // Head yaw
map(Type.VAR_INT); // Data
map(Types.VAR_INT); // Entity id
map(Types.UUID); // Entity UUID
map(Types.VAR_INT); // Entity type
map(Types.DOUBLE); // X
map(Types.DOUBLE); // Y
map(Types.DOUBLE); // Z
map(Types.BYTE); // Pitch
map(Types.BYTE); // Yaw
map(Types.BYTE); // Head yaw
map(Types.VAR_INT); // Data
handler(getSpawnTrackerWithDataHandler1_19(fallingBlockType));
}
});
@@ -82,8 +82,8 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == fallingBlockType) {
int blockState = wrapper.get(Type.INT, 0);
wrapper.set(Type.INT, 0, protocol.getMappingData().getNewBlockStateId(blockState));
int blockState = wrapper.get(Types.INT, 0);
wrapper.set(Types.INT, 0, protocol.getMappingData().getNewBlockStateId(blockState));
}
};
}
@@ -97,21 +97,18 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
// Check against the UNMAPPED entity type
EntityType entityType = trackAndMapEntity(wrapper);
if (entityType == fallingBlockType) {
int blockState = wrapper.get(Type.VAR_INT, 2);
wrapper.set(Type.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(blockState));
int blockState = wrapper.get(Types.VAR_INT, 2);
wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(blockState));
}
};
}
public void registerSpawnTracker(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
handler(wrapper -> trackAndMapEntity(wrapper));
}
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.passthrough(Types.UUID); // Entity UUID
wrapper.passthrough(Types.VAR_INT); // Entity Type
trackAndMapEntity(wrapper);
});
}
@@ -123,10 +120,9 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
public PacketHandler worldTrackerHandlerByKey() {
return wrapper -> {
EntityTracker tracker = tracker(wrapper.user());
String world = wrapper.get(Type.STRING, 1);
String world = wrapper.get(Types.STRING, 1);
if (tracker.currentWorld() != null && !tracker.currentWorld().equals(world)) {
tracker.clearEntities();
tracker.trackClientEntity();
}
tracker.setCurrentWorld(world);
};
@@ -138,14 +134,14 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
* @param wrapper packet wrapper
* @return unmapped (!) entity type
*/
protected EntityType trackAndMapEntity(PacketWrapper wrapper) throws Exception {
int typeId = wrapper.get(Type.VAR_INT, 1);
protected EntityType trackAndMapEntity(PacketWrapper wrapper) {
int typeId = wrapper.get(Types.VAR_INT, 1);
EntityType entityType = typeFromId(typeId);
tracker(wrapper.user()).addEntity(wrapper.get(Type.VAR_INT, 0), entityType);
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
int mappedTypeId = newEntityId(entityType.getId());
if (typeId != mappedTypeId) {
wrapper.set(Type.VAR_INT, 1, mappedTypeId);
wrapper.set(Types.VAR_INT, 1, mappedTypeId);
}
return entityType;
@@ -20,24 +20,26 @@ package com.viaversion.viabackwards.api.rewriters;
import com.google.common.base.Preconditions;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.entities.storage.EntityData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.Int2IntMapMappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -48,89 +50,97 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @see LegacyEntityRewriter
*/
public abstract class EntityRewriterBase<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends EntityRewriter<C, T> {
private final Int2ObjectMap<EntityData> entityDataMappings = new Int2ObjectOpenHashMap<>();
private final MetaType displayNameMetaType;
private final MetaType displayVisibilityMetaType;
private final Int2ObjectMap<EntityReplacement> entityDataMappings = new Int2ObjectOpenHashMap<>();
private final EntityDataType displayNameDataType;
private final EntityDataType displayVisibilityDataType;
private final int displayNameIndex;
private final int displayVisibilityIndex;
EntityRewriterBase(T protocol, MetaType displayNameMetaType, int displayNameIndex,
MetaType displayVisibilityMetaType, int displayVisibilityIndex) {
EntityRewriterBase(T protocol, EntityDataType displayNameDataType, int displayNameIndex,
EntityDataType displayVisibilityDataType, int displayVisibilityIndex) {
super(protocol, false);
this.displayNameMetaType = displayNameMetaType;
this.displayNameDataType = displayNameDataType;
this.displayNameIndex = displayNameIndex;
this.displayVisibilityMetaType = displayVisibilityMetaType;
this.displayVisibilityDataType = displayVisibilityDataType;
this.displayVisibilityIndex = displayVisibilityIndex;
}
@Override
public void handleMetadata(int entityId, List<Metadata> metadataList, UserConnection connection) {
public void handleEntityData(int entityId, List<EntityData> entityDataList, UserConnection connection) {
final TrackedEntity entity = tracker(connection).entity(entityId);
final boolean initialMetadata = !(entity != null && entity.hasSentMetadata());
final boolean initialEntityData = !(entity != null && entity.hasSentEntityData());
super.handleMetadata(entityId, metadataList, connection);
super.handleEntityData(entityId, entityDataList, connection);
if (entity == null) {
return; // Don't handle untracked entities - basically always the fault of a plugin sending virtual entities through concurrency-unsafe handling
}
// Set the mapped entity name if there is no custom name set already
final EntityData entityData = entityDataForType(entity.entityType());
final EntityReplacement entityMapping = entityDataForType(entity.entityType());
final Object displayNameObject;
if (entityData != null && (displayNameObject = entityData.entityName()) != null) {
final Metadata displayName = getMeta(displayNameIndex, metadataList);
if (initialMetadata) {
if (entityMapping != null && (displayNameObject = entityMapping.entityName()) != null) {
final EntityData displayName = getData(displayNameIndex, entityDataList);
if (initialEntityData) {
if (displayName == null) {
// Add it as new metadata
metadataList.add(new Metadata(displayNameIndex, displayNameMetaType, displayNameObject));
addDisplayVisibilityMeta(metadataList);
// Add it as new entity data
entityDataList.add(new EntityData(displayNameIndex, displayNameDataType, displayNameObject));
addDisplayVisibilityData(entityDataList);
} else if (displayName.getValue() == null || displayName.getValue().toString().isEmpty()) {
// Overwrite the existing null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityMeta(metadataList);
addDisplayVisibilityData(entityDataList);
}
} else if (displayName != null && (displayName.getValue() == null || displayName.getValue().toString().isEmpty())) {
// Overwrite null/empty display name
displayName.setValue(displayNameObject);
addDisplayVisibilityMeta(metadataList);
addDisplayVisibilityData(entityDataList);
}
}
// Add any other extra meta for mapped entities
if (entityData != null && entityData.hasBaseMeta() && initialMetadata) {
entityData.defaultMeta().createMeta(new WrappedMetadata(metadataList));
// Add any other extra data for mapped entities
if (entityMapping != null && entityMapping.hasBaseData() && initialEntityData) {
entityMapping.defaultData().createData(new WrappedEntityData(entityDataList));
}
}
private void addDisplayVisibilityMeta(List<Metadata> metadataList) {
if (ViaBackwards.getConfig().alwaysShowOriginalMobName()) {
removeMeta(displayVisibilityIndex, metadataList);
metadataList.add(new Metadata(displayVisibilityIndex, displayVisibilityMetaType, true));
private void addDisplayVisibilityData(List<EntityData> entityDataList) {
if (alwaysShowOriginalMobName()) {
removeData(displayVisibilityIndex, entityDataList);
entityDataList.add(new EntityData(displayVisibilityIndex, displayVisibilityDataType, getDisplayVisibilityDataValue()));
}
}
protected @Nullable Metadata getMeta(int metaIndex, List<Metadata> metadataList) {
for (Metadata metadata : metadataList) {
if (metadata.id() == metaIndex) {
return metadata;
protected Object getDisplayVisibilityDataValue() {
return true;
}
protected boolean alwaysShowOriginalMobName() {
return ViaBackwards.getConfig().alwaysShowOriginalMobName();
}
protected @Nullable EntityData getData(int dataIndex, List<EntityData> entityDataList) {
for (EntityData entityData : entityDataList) {
if (entityData.id() == dataIndex) {
return entityData;
}
}
return null;
}
protected void removeMeta(int metaIndex, List<Metadata> metadataList) {
metadataList.removeIf(meta -> meta.id() == metaIndex);
protected void removeData(int dataIndex, List<EntityData> entityDataList) {
entityDataList.removeIf(data -> data.id() == dataIndex);
}
protected boolean hasData(EntityType type) {
return entityDataMappings.containsKey(type.getId());
}
protected @Nullable EntityData entityDataForType(EntityType type) {
protected @Nullable EntityReplacement entityDataForType(EntityType type) {
return entityDataMappings.get(type.getId());
}
protected @Nullable StoredEntityData storedEntityData(MetaHandlerEvent event) {
protected @Nullable StoredEntityData storedEntityData(EntityDataHandlerEvent event) {
return tracker(event.user()).entityData(event.entityId());
}
@@ -143,67 +153,76 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
* @return created entity data
* @see #mapEntityType(EntityType, EntityType) for id only rewriting
*/
protected EntityData mapEntityTypeWithData(EntityType type, EntityType mappedType) {
protected EntityReplacement mapEntityTypeWithData(EntityType type, EntityType mappedType) {
Preconditions.checkArgument(type.getClass() == mappedType.getClass(), "Both entity types need to be of the same class");
// Already rewrite the id here
int mappedReplacementId = newEntityId(mappedType.getId());
EntityData data = new EntityData(protocol, type, mappedReplacementId);
EntityReplacement data = new EntityReplacement(protocol, type, mappedReplacementId);
mapEntityType(type.getId(), mappedReplacementId);
entityDataMappings.put(type.getId(), data);
return data;
}
/**
* Maps entity ids based on the enum constant's names.
*
* @param oldTypes entity types of the higher version
* @param newTypeClass entity types enum class of the lower version
* @param <E> new enum type
*/
@Override
public <E extends Enum<E> & EntityType> void mapTypes(EntityType[] oldTypes, Class<E> newTypeClass) {
if (typeMappings == null) {
typeMappings = Int2IntMapMappings.of();
}
for (EntityType oldType : oldTypes) {
try {
E newType = Enum.valueOf(newTypeClass, oldType.name());
typeMappings.setNewId(oldType.getId(), newType.getId());
} catch (IllegalArgumentException ignored) {
// Don't warn
}
}
}
public void registerMetaTypeHandler(
@Nullable MetaType itemType,
@Nullable MetaType blockStateType,
@Nullable MetaType optionalBlockStateType,
@Nullable MetaType particleType,
@Nullable MetaType componentType,
@Nullable MetaType optionalComponentType
public void registerEntityDataTypeHandler(
@Nullable EntityDataType itemType,
@Nullable EntityDataType blockStateType,
@Nullable EntityDataType optionalBlockStateType,
@Nullable EntityDataType particleType,
@Nullable EntityDataType componentType,
@Nullable EntityDataType optionalComponentType
) {
filter().handler((event, meta) -> {
MetaType type = meta.metaType();
filter().handler((event, data) -> {
EntityDataType type = data.dataType();
if (type == itemType) {
protocol.getItemRewriter().handleItemToClient(meta.value());
protocol.getItemRewriter().handleItemToClient(event.user(), data.value());
} else if (type == blockStateType) {
int data = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
int value = data.value();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
} else if (type == optionalBlockStateType) {
int data = meta.value();
if (data != 0) {
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
int value = data.value();
if (value != 0) {
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
}
} else if (type == particleType) {
rewriteParticle(meta.value());
protocol.getParticleRewriter().rewriteParticle(event.user(), data.value());
} else if (type == optionalComponentType || type == componentType) {
JsonElement text = data.value();
protocol.getComponentRewriter().processText(event.user(), text);
}
});
}
JsonElement text = meta.value();
if (text != null) {
protocol.getTranslatableRewriter().processText(text);
public void registerEntityDataTypeHandler1_20_3(
@Nullable EntityDataType itemType,
@Nullable EntityDataType blockStateType,
@Nullable EntityDataType optionalBlockStateType,
@Nullable EntityDataType particleType,
@Nullable EntityDataType particlesType,
@Nullable EntityDataType componentType,
@Nullable EntityDataType optionalComponentType
) {
filter().handler((event, data) -> {
EntityDataType type = data.dataType();
if (type == itemType) {
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), data.value()));
} else if (type == blockStateType) {
int value = data.value();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
} else if (type == optionalBlockStateType) {
int value = data.value();
if (value != 0) {
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
}
} else if (type == particleType) {
protocol.getParticleRewriter().rewriteParticle(event.user(), data.value());
} else if (type == particlesType) {
Particle[] particles = data.value();
for (final Particle particle : particles) {
protocol.getParticleRewriter().rewriteParticle(event.user(), particle);
}
} else if (type == optionalComponentType || type == componentType) {
protocol.getComponentRewriter().processTag(event.user(), data.value());
}
});
}
@@ -212,23 +231,35 @@ public abstract class EntityRewriterBase<C extends ClientboundPacketType, T exte
protected PacketHandler getTrackerHandler(Type<? extends Number> intType, int typeIndex) {
return wrapper -> {
Number id = wrapper.get(intType, typeIndex);
tracker(wrapper.user()).addEntity(wrapper.get(Type.VAR_INT, 0), typeFromId(id.intValue()));
tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), typeFromId(id.intValue()));
};
}
protected PacketHandler getTrackerHandler() {
return getTrackerHandler(Type.VAR_INT, 1);
return getTrackerHandler(Types.VAR_INT, 1);
}
protected PacketHandler getTrackerHandler(EntityType entityType, Type<? extends Number> intType) {
return wrapper -> tracker(wrapper.user()).addEntity((int) wrapper.get(intType, 0), entityType);
protected PacketHandler getTrackerHandler(EntityType entityType) {
return wrapper -> tracker(wrapper.user()).addEntity(wrapper.get(Types.VAR_INT, 0), entityType);
}
protected PacketHandler getPlayerTrackerHandler() {
return wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
final EntityTracker tracker = tracker(wrapper.user());
tracker(wrapper.user()).setClientEntityId(entityId);
tracker.addEntity(entityId, tracker.playerType());
};
}
protected PacketHandler getDimensionHandler(int index) {
return wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, index);
clientWorld.setEnvironment(dimensionId);
ClientWorld clientWorld = wrapper.user().getClientWorld(this.protocol.getClass());
int dimensionId = wrapper.get(Types.INT, index);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
};
}
}
@@ -1,219 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ByteTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.IntTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends ItemRewriterBase<C, S, T> {
public ItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
super(protocol, itemType, itemArrayType, true);
}
@Override
public @Nullable Item handleItemToClient(@Nullable Item item) {
if (item == null) {
return null;
}
CompoundTag display = item.tag() != null ? item.tag().getCompoundTag("display") : null;
if (protocol.getTranslatableRewriter() != null && display != null) {
// Handle name and lore components
StringTag name = display.getStringTag("Name");
if (name != null) {
String newValue = protocol.getTranslatableRewriter().processText(name.getValue()).toString();
if (!newValue.equals(name.getValue())) {
saveStringTag(display, name, "Name");
}
name.setValue(newValue);
}
ListTag lore = display.getListTag("Lore");
if (lore != null) {
boolean changed = false;
for (Tag loreEntryTag : lore) {
if (!(loreEntryTag instanceof StringTag)) {
continue;
}
StringTag loreEntry = (StringTag) loreEntryTag;
String newValue = protocol.getTranslatableRewriter().processText(loreEntry.getValue()).toString();
if (!changed && !newValue.equals(loreEntry.getValue())) {
// Backup original lore before doing any modifications
changed = true;
saveListTag(display, lore, "Lore");
}
loreEntry.setValue(newValue);
}
}
}
MappedItem data = protocol.getMappingData() != null ? protocol.getMappingData().getMappedItem(item.identifier()) : null;
if (data == null) {
// Just rewrite the id
return super.handleItemToClient(item);
}
if (item.tag() == null) {
item.setTag(new CompoundTag());
}
// Save original id, set remapped id
item.tag().putInt(nbtTagName + "|id", item.identifier());
item.setIdentifier(data.getId());
// Add custom model data
if (data.customModelData() != null && !item.tag().contains("CustomModelData")) {
item.tag().putInt("CustomModelData", data.customModelData());
}
// Set custom name - only done if there is no original one
if (display == null) {
item.tag().put("display", display = new CompoundTag());
}
if (!display.contains("Name")) {
display.put("Name", new StringTag(data.getJsonName()));
display.put(nbtTagName + "|customName", new ByteTag());
}
return item;
}
@Override
public @Nullable Item handleItemToServer(@Nullable Item item) {
if (item == null) return null;
super.handleItemToServer(item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName + "|id");
if (originalId instanceof IntTag) {
item.setIdentifier(((NumberTag) originalId).asInt());
}
}
return item;
}
@Override
public void registerAdvancements(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.STRING);
}
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
final JsonElement title = wrapper.passthrough(Type.COMPONENT);
final JsonElement description = wrapper.passthrough(Type.COMPONENT);
final TranslatableRewriter<C> translatableRewriter = protocol.getTranslatableRewriter();
if (translatableRewriter != null) {
translatableRewriter.processText(title);
translatableRewriter.processText(description);
}
handleItemToClient(wrapper.passthrough(getItemType())); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
wrapper.passthrough(Type.STRING_ARRAY); // Criteria
final int arrayLength = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Type.STRING_ARRAY); // String array
}
}
});
}
});
}
@Override
public void registerAdvancements1_20_3(final C packetType) {
// Insert translatable rewriter
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.STRING);
}
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
final Tag title = wrapper.passthrough(Type.TAG);
final Tag description = wrapper.passthrough(Type.TAG);
final TranslatableRewriter<C> translatableRewriter = protocol.getTranslatableRewriter();
if (translatableRewriter != null) {
translatableRewriter.processTag(title);
translatableRewriter.processTag(description);
}
handleItemToClient(wrapper.passthrough(Type.ITEM1_20_2)); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Type.INT);
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
final int requirements = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < requirements; array++) {
wrapper.passthrough(Type.STRING_ARRAY);
}
wrapper.passthrough(Type.BOOLEAN); // Send telemetry
}
});
}
}
@@ -20,55 +20,81 @@ package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.MappedLegacyBlockItem;
import com.viaversion.viabackwards.api.data.VBMappingDataLoader;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.BlockColors;
import com.viaversion.viabackwards.utils.Block;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.data.BlockColors1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ByteTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.ShortTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.HashMap;
import java.util.Map;
import com.viaversion.viaversion.util.IdAndData;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends BackwardsProtocol<C, ?, ?, S>> extends ItemRewriterBase<C, S, T> {
T extends BackwardsProtocol<C, ?, ?, S>> extends BackwardsItemRewriterBase<C, S, T> {
private static final Map<String, Int2ObjectMap<MappedLegacyBlockItem>> LEGACY_MAPPINGS = new HashMap<>();
protected final Int2ObjectMap<MappedLegacyBlockItem> replacementData; // Raw id -> mapped data
protected final Int2ObjectMap<MappedLegacyBlockItem> itemReplacements = new Int2ObjectOpenHashMap<>(8); // Raw id -> mapped data
protected final Int2ObjectMap<MappedLegacyBlockItem> blockReplacements = new Int2ObjectOpenHashMap<>(8); // Raw id -> mapped data
static {
JsonObject jsonObject = VBMappingDataLoader.loadFromDataDir("legacy-mappings.json");
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
Int2ObjectMap<MappedLegacyBlockItem> mappings = new Int2ObjectOpenHashMap<>(8);
LEGACY_MAPPINGS.put(entry.getKey(), mappings);
for (Map.Entry<String, JsonElement> dataEntry : entry.getValue().getAsJsonObject().entrySet()) {
addMapping(dataEntry.getKey(), dataEntry.getValue().getAsJsonObject(), mappings);
protected LegacyBlockItemRewriter(T protocol, String name, Type<Item> itemType, Type<Item[]> itemArrayType, Type<Item> mappedItemType, Type<Item[]> mappedItemArrayType) {
super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, false);
Int2ObjectMap<MappedLegacyBlockItem> blockItemReplacements = new Int2ObjectOpenHashMap<>(8);
final JsonObject jsonObject = readMappingsFile("item-mappings-" + name + ".json");
addMappings(MappedLegacyBlockItem.Type.ITEM, jsonObject, itemReplacements);
addMappings(MappedLegacyBlockItem.Type.BLOCK_ITEM, jsonObject, blockItemReplacements);
addMappings(MappedLegacyBlockItem.Type.BLOCK, jsonObject, blockReplacements);
blockReplacements.putAll(blockItemReplacements);
itemReplacements.putAll(blockItemReplacements);
}
protected LegacyBlockItemRewriter(T protocol, String name, Type<Item> itemType, Type<Item[]> itemArrayType) {
this(protocol, name, itemType, itemArrayType, itemType, itemArrayType);
}
protected LegacyBlockItemRewriter(T protocol, String name) {
this(protocol, name, Types.ITEM1_8, Types.ITEM1_8_SHORT_ARRAY);
}
private void addMappings(MappedLegacyBlockItem.Type type, JsonObject object, Int2ObjectMap<MappedLegacyBlockItem> mappings) {
if (object.has(type.getName())) {
final JsonObject mappingsObject = object.getAsJsonObject(type.getName());
for (Map.Entry<String, JsonElement> dataEntry : mappingsObject.entrySet()) {
addMapping(dataEntry.getKey(), dataEntry.getValue().getAsJsonObject(), type, mappings);
}
}
}
private static void addMapping(String key, JsonObject object, Int2ObjectMap<MappedLegacyBlockItem> mappings) {
private void addMapping(String key, JsonObject object, MappedLegacyBlockItem.Type type, Int2ObjectMap<MappedLegacyBlockItem> mappings) {
int id = object.getAsJsonPrimitive("id").getAsInt();
JsonPrimitive jsonData = object.getAsJsonPrimitive("data");
short data = jsonData != null ? jsonData.getAsShort() : 0;
String name = object.getAsJsonPrimitive("name").getAsString();
JsonPrimitive blockField = object.getAsJsonPrimitive("block");
boolean block = blockField != null && blockField.getAsBoolean();
String name = type != MappedLegacyBlockItem.Type.BLOCK ? object.getAsJsonPrimitive("name").getAsString() : null;
if (key.indexOf('-') == -1) {
int unmappedId;
@@ -77,12 +103,12 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
// Include data
short unmappedData = Short.parseShort(key.substring(dataSeparatorIndex + 1));
unmappedId = Integer.parseInt(key.substring(0, dataSeparatorIndex));
unmappedId = (unmappedId << 4) | (unmappedData & 15);
unmappedId = compress(unmappedId, unmappedData);
} else {
unmappedId = Integer.parseInt(key) << 4;
unmappedId = compress(Integer.parseInt(key), -1);
}
mappings.put(unmappedId, new MappedLegacyBlockItem(id, data, name, block));
mappings.put(unmappedId, new MappedLegacyBlockItem(id, data, name, type));
return;
}
@@ -92,46 +118,74 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
int to = Integer.parseInt(split[1]);
// Special block color handling
if (name.contains("%color%")) {
if (name != null && name.contains("%color%")) {
for (int i = from; i <= to; i++) {
mappings.put(i << 4, new MappedLegacyBlockItem(id, data, name.replace("%color%", BlockColors.get(i - from)), block));
mappings.put(compress(i, -1), new MappedLegacyBlockItem(id, data, name.replace("%color%", BlockColors1_11_1.get(i - from)), type));
}
} else {
MappedLegacyBlockItem mappedBlockItem = new MappedLegacyBlockItem(id, data, name, block);
MappedLegacyBlockItem mappedBlockItem = new MappedLegacyBlockItem(id, data, name, type);
for (int i = from; i <= to; i++) {
mappings.put(i << 4, mappedBlockItem);
mappings.put(compress(i, -1), mappedBlockItem);
}
}
}
protected LegacyBlockItemRewriter(T protocol) {
super(protocol, Type.ITEM1_8, Type.ITEM1_8_SHORT_ARRAY, false);
replacementData = LEGACY_MAPPINGS.get(protocol.getClass().getSimpleName().split("To")[1].replace("_", "."));
public void registerBlockChange(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // 0 - Block Position
map(Types.VAR_INT); // 1 - Block
handler(wrapper -> {
int idx = wrapper.get(Types.VAR_INT, 0);
wrapper.set(Types.VAR_INT, 0, handleBlockId(idx));
});
}
});
}
public void registerMultiBlockChange(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Chunk X
map(Types.INT); // 1 - Chunk Z
map(Types.BLOCK_CHANGE_ARRAY);
handler(wrapper -> {
for (BlockChangeRecord record : wrapper.get(Types.BLOCK_CHANGE_ARRAY, 0)) {
record.setBlockId(handleBlockId(record.getBlockId()));
}
});
}
});
}
@Override
public @Nullable Item handleItemToClient(@Nullable Item item) {
public @Nullable Item handleItemToClient(UserConnection connection, @Nullable Item item) {
if (item == null) return null;
MappedLegacyBlockItem data = getMappedBlockItem(item.identifier(), item.data());
MappedLegacyBlockItem data = getMappedItem(item.identifier(), item.data());
if (data == null) {
// Just rewrite the id
return super.handleItemToClient(item);
return super.handleItemToClient(connection, item);
}
if (item.tag() == null) {
item.setTag(new CompoundTag());
}
short originalData = item.data();
item.tag().putInt(nbtTagName("id"), item.identifier());
item.setIdentifier(data.getId());
// Keep original data if mapped data is set to -1
if (data.getData() != -1) {
item.setData(data.getData());
item.tag().putShort(nbtTagName("data"), originalData);
}
// Set display name
if (data.getName() != null) {
if (item.tag() == null) {
item.setTag(new CompoundTag());
}
CompoundTag display = item.tag().getCompoundTag("display");
if (display == null) {
item.tag().put("display", display = new CompoundTag());
@@ -141,33 +195,56 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
if (nameTag == null) {
nameTag = new StringTag(data.getName());
display.put("Name", nameTag);
display.put(nbtTagName + "|customName", new ByteTag());
display.put(nbtTagName("customName"), new ByteTag(false));
}
// Handle colors
String value = nameTag.getValue();
if (value.contains("%vb_color%")) {
display.putString("Name", value.replace("%vb_color%", BlockColors.get(originalData)));
display.putString("Name", value.replace("%vb_color%", BlockColors1_11_1.get(originalData)));
}
}
return item;
}
public int handleBlockID(int idx) {
int type = idx >> 4;
int meta = idx & 15;
Block b = handleBlock(type, meta);
if (b == null) return idx;
return (b.getId() << 4 | (b.getData() & 15));
@Override
public @Nullable Item handleItemToServer(UserConnection connection, @Nullable final Item item) {
if (item == null) return null;
super.handleItemToServer(connection, item);
if (item.tag() != null) {
Tag originalId = item.tag().remove(nbtTagName("id"));
if (originalId instanceof IntTag) {
item.setIdentifier(((NumberTag) originalId).asInt());
}
Tag originalData = item.tag().remove(nbtTagName("data"));
if (originalData instanceof ShortTag) {
item.setData(((NumberTag) originalData).asShort());
}
}
return item;
}
public @Nullable Block handleBlock(int blockId, int data) {
MappedLegacyBlockItem settings = getMappedBlockItem(blockId, data);
if (settings == null || !settings.isBlock()) return null;
public PacketHandler getFallingBlockHandler() {
return wrapper -> {
final EntityTypes1_12.ObjectType type = EntityTypes1_12.ObjectType.findById(wrapper.get(Types.BYTE, 0));
if (type == EntityTypes1_12.ObjectType.FALLING_BLOCK) {
final int objectData = wrapper.get(Types.INT, 0);
Block block = settings.getBlock();
final IdAndData block = handleBlock(objectData & 4095, objectData >> 12 & 15);
if (block == null) return;
wrapper.set(Types.INT, 0, block.getId() | block.getData() << 12);
}
};
}
public @Nullable IdAndData handleBlock(int blockId, int data) {
MappedLegacyBlockItem settings = getMappedBlock(blockId, data);
if (settings == null) {
return null;
}
IdAndData block = settings.getBlock();
// For some blocks, the data can still be useful (:
if (block.getData() == -1) {
return block.withData(data);
@@ -175,17 +252,17 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
return block;
}
private @Nullable MappedLegacyBlockItem getMappedBlockItem(int id, int data) {
MappedLegacyBlockItem mapping = replacementData.get((id << 4) | (data & 15));
return mapping != null || data == 0 ? mapping : replacementData.get(id << 4);
public int handleBlockId(final int rawId) {
final int id = IdAndData.getId(rawId);
final int data = IdAndData.getData(rawId);
final IdAndData mappedBlock = handleBlock(id, data);
if (mappedBlock == null) return rawId;
return IdAndData.toRawData(mappedBlock.getId(), mappedBlock.getData());
}
private @Nullable MappedLegacyBlockItem getMappedBlockItem(int rawId) {
MappedLegacyBlockItem mapping = replacementData.get(rawId);
return mapping != null ? mapping : replacementData.get(rawId & ~15);
}
protected void handleChunk(Chunk chunk) {
public void handleChunk(Chunk chunk) {
// Map Block Entities
Map<Pos, CompoundTag> tags = new HashMap<>();
for (CompoundTag tag : chunk.getBlockEntities()) {
@@ -202,16 +279,16 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
tags.put(pos, tag);
// Handle given Block Entities
if (pos.getY() < 0 || pos.getY() > 255) continue; // 1.17
if (pos.y() < 0 || pos.y() > 255) continue; // 1.17
ChunkSection section = chunk.getSections()[pos.getY() >> 4];
ChunkSection section = chunk.getSections()[pos.y() >> 4];
if (section == null) continue;
int block = section.palette(PaletteType.BLOCKS).idAt(pos.getX(), pos.getY() & 0xF, pos.getZ());
int block = section.palette(PaletteType.BLOCKS).idAt(pos.x(), pos.y() & 0xF, pos.z());
MappedLegacyBlockItem settings = getMappedBlockItem(block);
MappedLegacyBlockItem settings = getMappedBlock(block);
if (settings != null && settings.hasBlockEntityHandler()) {
settings.getBlockEntityHandler().handleOrNewCompoundTag(block, tag);
settings.getBlockEntityHandler().handleCompoundTag(block, tag);
}
}
@@ -230,15 +307,15 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
int btype = block >> 4;
int meta = block & 0xF;
Block b = handleBlock(btype, meta);
IdAndData b = handleBlock(btype, meta);
if (b != null) {
palette.setIdByIndex(j, (b.getId() << 4) | (b.getData() & 0xF));
palette.setIdByIndex(j, IdAndData.toRawData(b.getId(), b.getData()));
}
// We already know that is has a handler
if (hasBlockEntityHandler) continue;
MappedLegacyBlockItem settings = getMappedBlockItem(block);
MappedLegacyBlockItem settings = getMappedBlock(block);
if (settings != null && settings.hasBlockEntityHandler()) {
hasBlockEntityHandler = true;
}
@@ -252,7 +329,7 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
for (int z = 0; z < 16; z++) {
int block = palette.idAt(x, y, z);
MappedLegacyBlockItem settings = getMappedBlockItem(block);
MappedLegacyBlockItem settings = getMappedBlock(block);
if (settings == null || !settings.hasBlockEntityHandler()) continue;
Pos pos = new Pos(x, (y + (i << 4)), z);
@@ -265,7 +342,7 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
tag.putInt("y", y + (i << 4));
tag.putInt("z", z + (chunk.getZ() << 4));
settings.getBlockEntityHandler().handleOrNewCompoundTag(block, tag);
settings.getBlockEntityHandler().handleCompoundTag(block, tag);
chunk.getBlockEntities().add(tag);
}
}
@@ -282,51 +359,35 @@ public abstract class LegacyBlockItemRewriter<C extends ClientboundPacketType, S
return tag;
}
private static final class Pos {
private @Nullable MappedLegacyBlockItem getMappedBlock(int id, int data) {
MappedLegacyBlockItem mapping = blockReplacements.get(compress(id, data));
return mapping != null ? mapping : blockReplacements.get(compress(id, -1));
}
private final int x;
private final short y;
private final int z;
private @Nullable MappedLegacyBlockItem getMappedItem(int id, int data) {
MappedLegacyBlockItem mapping = itemReplacements.get(compress(id, data));
return mapping != null ? mapping : itemReplacements.get(compress(id, -1));
}
private Pos(int x, int y, int z) {
this.x = x;
this.y = (short) y;
this.z = z;
}
private @Nullable MappedLegacyBlockItem getMappedBlock(int rawId) {
int id = IdAndData.getId(rawId);
int data = IdAndData.getData(rawId);
return getMappedBlock(id, data);
}
public int getX() {
return x;
}
protected JsonObject readMappingsFile(final String name) {
return BackwardsMappingDataLoader.INSTANCE.loadFromDataDir(name);
}
public int getY() {
return y;
}
protected int compress(final int id, final int data) {
// Using IdAndData for the internal storage can cause id overlaps in edge cases and would lead to wrong data
return (id << 16) | (data & 0xFFFF);
}
public int getZ() {
return z;
}
private record Pos(int x, short y, int z) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pos pos = (Pos) o;
if (x != pos.x) return false;
if (y != pos.y) return false;
return z == pos.z;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
result = 31 * result + z;
return result;
}
@Override
public String toString() {
return "Pos{" + "x=" + x + ", y=" + y + ", z=" + z + '}';
public Pos(int x, int y, int z) {
this(x, (short) y, z);
}
}
}
@@ -17,13 +17,14 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ByteTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.IntTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -35,35 +36,61 @@ public class LegacyEnchantmentRewriter {
private final Map<Short, String> enchantmentMappings = new HashMap<>();
private final String nbtTagName;
private final boolean dummyEnchantment;
private Set<Short> hideLevelForEnchants;
public LegacyEnchantmentRewriter(String nbtTagName) {
this(nbtTagName, true);
}
public LegacyEnchantmentRewriter(String nbtTagName, boolean dummyEnchantment) {
this.nbtTagName = nbtTagName;
this.dummyEnchantment = dummyEnchantment;
}
public void registerEnchantment(int id, String replacementLore) {
enchantmentMappings.put((short) id, replacementLore);
}
public void handleToClient(Item item) {
CompoundTag tag = item.tag();
if (tag == null) return;
if (tag.getListTag("ench") != null) {
rewriteEnchantmentsToClient(tag, false);
}
if (tag.getListTag("StoredEnchantments") != null) {
rewriteEnchantmentsToClient(tag, true);
}
}
public void handleToServer(Item item) {
CompoundTag tag = item.tag();
if (tag == null) return;
if (tag.getListTag(nbtTagName + "|ench", CompoundTag.class) != null) {
rewriteEnchantmentsToServer(tag, false);
}
if (tag.getListTag(nbtTagName + "|StoredEnchantments", CompoundTag.class) != null) {
rewriteEnchantmentsToServer(tag, true);
}
}
public void rewriteEnchantmentsToClient(CompoundTag tag, boolean storedEnchant) {
String key = storedEnchant ? "StoredEnchantments" : "ench";
ListTag enchantments = tag.getListTag(key);
ListTag remappedEnchantments = new ListTag(CompoundTag.class);
List<Tag> lore = new ArrayList<>();
for (Tag enchantmentEntry : enchantments.copy()) {
if (!(enchantmentEntry instanceof CompoundTag)) {
continue;
}
CompoundTag entryTag = (CompoundTag) enchantmentEntry;
NumberTag idTag = entryTag.getNumberTag("id");
ListTag<CompoundTag> enchantments = tag.getListTag(key, CompoundTag.class);
ListTag<CompoundTag> remappedEnchantments = new ListTag<>(CompoundTag.class);
List<StringTag> lore = new ArrayList<>();
for (CompoundTag enchantmentEntry : enchantments.copy()) {
NumberTag idTag = enchantmentEntry.getNumberTag("id");
if (idTag == null) continue;
short newId = idTag.asShort();
String enchantmentName = enchantmentMappings.get(newId);
if (enchantmentName != null) {
enchantments.remove(enchantmentEntry);
NumberTag levelTag = entryTag.getNumberTag("lvl");
NumberTag levelTag = enchantmentEntry.getNumberTag("lvl");
short level = levelTag != null ? levelTag.asShort() : 1;
if (hideLevelForEnchants != null && hideLevelForEnchants.contains(newId)) {
lore.add(new StringTag(enchantmentName));
@@ -74,13 +101,13 @@ public class LegacyEnchantmentRewriter {
}
}
if (!lore.isEmpty()) {
if (!storedEnchant && enchantments.isEmpty()) {
if (this.dummyEnchantment && !storedEnchant && enchantments.isEmpty()) {
CompoundTag dummyEnchantment = new CompoundTag();
dummyEnchantment.putShort("id", (short) 0);
dummyEnchantment.putShort("lvl", (short) 0);
enchantments.add(dummyEnchantment);
tag.put(nbtTagName + "|dummyEnchant", new ByteTag());
enchantments.add(dummyEnchantment);
tag.put(nbtTagName + "|dummyEnchant", new ByteTag(false));
NumberTag hideFlags = tag.getNumberTag("HideFlags");
if (hideFlags == null) {
@@ -99,9 +126,9 @@ public class LegacyEnchantmentRewriter {
if (display == null) {
tag.put("display", display = new CompoundTag());
}
ListTag loreTag = display.getListTag("Lore");
ListTag<StringTag> loreTag = display.getListTag("Lore", StringTag.class);
if (loreTag == null) {
display.put("Lore", loreTag = new ListTag(StringTag.class));
display.put("Lore", loreTag = new ListTag<>(StringTag.class));
}
lore.addAll(loreTag.getValue());
@@ -111,21 +138,15 @@ public class LegacyEnchantmentRewriter {
public void rewriteEnchantmentsToServer(CompoundTag tag, boolean storedEnchant) {
String key = storedEnchant ? "StoredEnchantments" : "ench";
ListTag remappedEnchantments = tag.remove(nbtTagName + "|" + key);
ListTag enchantments = tag.getListTag(key);
ListTag<CompoundTag> enchantments = tag.getListTag(key, CompoundTag.class);
if (enchantments == null) {
enchantments = new ListTag(CompoundTag.class);
enchantments = new ListTag<>(CompoundTag.class);
}
if (!storedEnchant && tag.remove(nbtTagName + "|dummyEnchant") != null) {
for (Tag enchantment : enchantments.copy()) {
if (!(enchantment instanceof CompoundTag)) {
continue;
}
CompoundTag entryTag = (CompoundTag) enchantment;
NumberTag idTag = entryTag.getNumberTag("id");
NumberTag levelTag = entryTag.getNumberTag("lvl");
for (CompoundTag enchantment : enchantments.copy()) {
NumberTag idTag = enchantment.getNumberTag("id");
NumberTag levelTag = enchantment.getNumberTag("lvl");
short id = idTag != null ? idTag.asShort() : 0;
short level = levelTag != null ? levelTag.asShort() : 0;
if (id == 0 && level == 0) {
@@ -134,8 +155,8 @@ public class LegacyEnchantmentRewriter {
}
Tag hideFlags = tag.remove(nbtTagName + "|oldHideFlags");
if (hideFlags instanceof IntTag) {
tag.putInt("HideFlags", ((IntTag) hideFlags).asByte());
if (hideFlags instanceof IntTag intTag) {
tag.putInt("HideFlags", intTag.asByte());
} else {
tag.remove("HideFlags");
}
@@ -143,8 +164,9 @@ public class LegacyEnchantmentRewriter {
CompoundTag display = tag.getCompoundTag("display");
// A few null checks just to be safe, though they shouldn't actually be
ListTag lore = display != null ? display.getListTag("Lore") : null;
for (Tag enchantment : remappedEnchantments.copy()) {
ListTag<StringTag> lore = display != null ? display.getListTag("Lore", StringTag.class) : null;
ListTag<CompoundTag> remappedEnchantments = (ListTag<CompoundTag>) tag.remove(nbtTagName + "|" + key);
for (CompoundTag enchantment : remappedEnchantments.copy()) {
enchantments.add(enchantment);
if (lore != null && !lore.isEmpty()) {
lore.remove(lore.get(0));
@@ -17,22 +17,22 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.entities.storage.EntityData;
import com.viaversion.viabackwards.api.entities.storage.EntityObjectData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.ObjectType;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_9;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -40,13 +40,13 @@ import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T extends BackwardsProtocol<C, ?, ?, ?>> extends EntityRewriterBase<C, T> {
private final Map<ObjectType, EntityData> objectTypes = new HashMap<>();
private final Map<ObjectType, EntityReplacement> objectTypes = new HashMap<>();
protected LegacyEntityRewriter(T protocol) {
this(protocol, MetaType1_9.String, MetaType1_9.Boolean);
this(protocol, EntityDataTypes1_9.STRING, EntityDataTypes1_9.BOOLEAN);
}
protected LegacyEntityRewriter(T protocol, MetaType displayType, MetaType displayVisibilityType) {
protected LegacyEntityRewriter(T protocol, EntityDataType displayType, EntityDataType displayVisibilityType) {
super(protocol, displayType, 2, displayVisibilityType, 3);
}
@@ -56,7 +56,7 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
return entData;
}
protected @Nullable EntityData getObjectData(ObjectType type) {
protected @Nullable EntityReplacement getObjectData(ObjectType type) {
return objectTypes.get(type);
}
@@ -64,10 +64,12 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.INT);
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
clientWorld.setEnvironment(wrapper.get(Type.INT, 0));
ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
if (clientWorld.setEnvironment(wrapper.get(Types.INT, 0))) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
@@ -77,96 +79,85 @@ public abstract class LegacyEntityRewriter<C extends ClientboundPacketType, T ex
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
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);
clientChunks.setEnvironment(wrapper.get(Type.INT, 1));
addTrackedEntity(wrapper, wrapper.get(Type.INT, 0), playerType);
ClientWorld clientWorld = wrapper.user().getClientWorld(protocol.getClass());
clientWorld.setEnvironment(wrapper.get(Types.INT, 1));
final int entityId = wrapper.get(Types.INT, 0);
addTrackedEntity(wrapper, entityId, playerType);
tracker(wrapper.user()).setClientEntityId(entityId);
});
}
});
}
@Override
public void registerMetadataRewriter(C packetType, Type<List<Metadata>> oldMetaType, Type<List<Metadata>> newMetaType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
if (oldMetaType != null) {
map(oldMetaType, newMetaType);
} else {
map(newMetaType);
}
handler(wrapper -> {
List<Metadata> metadata = wrapper.get(newMetaType, 0);
handleMetadata(wrapper.get(Type.VAR_INT, 0), metadata, wrapper.user());
});
}
});
}
@Override
public void registerMetadataRewriter(C packetType, Type<List<Metadata>> metaType) {
registerMetadataRewriter(packetType, null, metaType);
}
protected PacketHandler getMobSpawnRewriter(Type<List<Metadata>> metaType) {
protected PacketHandler getMobSpawnRewriter(Type<List<EntityData>> dataType, IdSetter idSetter) {
return wrapper -> {
int entityId = wrapper.get(Type.VAR_INT, 0);
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityType type = tracker(wrapper.user()).entityType(entityId);
List<Metadata> metadata = wrapper.get(metaType, 0);
handleMetadata(entityId, metadata, wrapper.user());
List<EntityData> entityDataList = wrapper.get(dataType, 0);
handleEntityData(entityId, entityDataList, wrapper.user());
EntityData entityData = entityDataForType(type);
if (entityData != null) {
wrapper.set(Type.VAR_INT, 1, entityData.replacementId());
if (entityData.hasBaseMeta()) {
entityData.defaultMeta().createMeta(new WrappedMetadata(metadata));
EntityReplacement entityReplacement = entityDataForType(type);
if (entityReplacement != null) {
idSetter.setId(wrapper, entityReplacement.replacementId());
if (entityReplacement.hasBaseData()) {
entityReplacement.defaultData().createData(new WrappedEntityData(entityDataList));
}
}
};
}
protected PacketHandler getObjectTrackerHandler() {
return wrapper -> addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), getObjectTypeFromId(wrapper.get(Type.BYTE, 0)));
public PacketHandler getMobSpawnRewriter(Type<List<EntityData>> dataType) {
return getMobSpawnRewriter(dataType, (wrapper, id) -> wrapper.set(Types.UNSIGNED_BYTE, 0, (short) id));
}
protected PacketHandler getTrackerAndMetaHandler(Type<List<Metadata>> metaType, EntityType entityType) {
public PacketHandler getMobSpawnRewriter1_11(Type<List<EntityData>> dataType) {
return getMobSpawnRewriter(dataType, (wrapper, id) -> wrapper.set(Types.VAR_INT, 1, id));
}
protected PacketHandler getObjectTrackerHandler() {
return wrapper -> addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), objectTypeFromId(wrapper.get(Types.BYTE, 0)));
}
protected PacketHandler getTrackerAndDataHandler(Type<List<EntityData>> dataType, EntityType entityType) {
return wrapper -> {
addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), entityType);
List<Metadata> metadata = wrapper.get(metaType, 0);
handleMetadata(wrapper.get(Type.VAR_INT, 0), metadata, wrapper.user());
addTrackedEntity(wrapper, wrapper.get(Types.VAR_INT, 0), entityType);
List<EntityData> entityDataList = wrapper.get(dataType, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), entityDataList, wrapper.user());
};
}
protected PacketHandler getObjectRewriter(Function<Byte, ObjectType> objectGetter) {
return wrapper -> {
ObjectType type = objectGetter.apply(wrapper.get(Type.BYTE, 0));
ObjectType type = objectGetter.apply(wrapper.get(Types.BYTE, 0));
if (type == null) {
ViaBackwards.getPlatform().getLogger().warning("Could not find Entity Type" + wrapper.get(Type.BYTE, 0));
protocol.getLogger().warning("Could not find entity type " + wrapper.get(Types.BYTE, 0));
return;
}
EntityData data = getObjectData(type);
EntityReplacement data = getObjectData(type);
if (data != null) {
wrapper.set(Type.BYTE, 0, (byte) data.replacementId());
wrapper.set(Types.BYTE, 0, (byte) data.replacementId());
if (data.objectData() != -1) {
wrapper.set(Type.INT, 0, data.objectData());
wrapper.set(Types.INT, 0, data.objectData());
}
}
};
}
protected EntityType getObjectTypeFromId(int typeId) {
return typeFromId(typeId);
}
@Deprecated
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) throws Exception {
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) {
tracker(wrapper.user()).addEntity(entityId, type);
}
@FunctionalInterface
protected interface IdSetter {
void setId(PacketWrapper wrapper, int id);
}
}
@@ -50,11 +50,11 @@ public abstract class LegacySoundRewriter<T extends BackwardsProtocol<?, ?, ?, ?
public int handleSounds(int soundId) {
int newSoundId = soundId;
SoundData data = soundRewrites.get(soundId);
if (data != null) return data.getReplacementSound();
if (data != null) return data.replacementSound();
for (Int2ObjectMap.Entry<SoundData> entry : soundRewrites.int2ObjectEntrySet()) {
if (soundId > entry.getIntKey()) {
if (entry.getValue().isAdded()) {
if (entry.getValue().added()) {
newSoundId--;
} else {
newSoundId++;
@@ -66,41 +66,14 @@ public abstract class LegacySoundRewriter<T extends BackwardsProtocol<?, ?, ?, ?
public boolean hasPitch(int soundId) {
SoundData data = soundRewrites.get(soundId);
return data != null && data.isChangePitch();
return data != null && data.changePitch();
}
public float handlePitch(int soundId) {
SoundData data = soundRewrites.get(soundId);
return data != null ? data.getNewPitch() : 1F;
return data != null ? data.newPitch() : 1F;
}
public static final class SoundData {
private final int replacementSound;
private final boolean changePitch;
private final float newPitch;
private final boolean added;
public SoundData(int replacementSound, boolean changePitch, float newPitch, boolean added) {
this.replacementSound = replacementSound;
this.changePitch = changePitch;
this.newPitch = newPitch;
this.added = added;
}
public int getReplacementSound() {
return replacementSound;
}
public boolean isChangePitch() {
return changePitch;
}
public float getNewPitch() {
return newPitch;
}
public boolean isAdded() {
return added;
}
public record SoundData(int replacementSound, boolean changePitch, float newPitch, boolean added) {
}
}
@@ -19,6 +19,7 @@ package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
public final class MapColorRewriter {
@@ -31,22 +32,22 @@ public final class MapColorRewriter {
*/
public static PacketHandler getRewriteHandler(IdRewriteFunction rewriter) {
return wrapper -> {
int iconCount = wrapper.passthrough(Type.VAR_INT);
int iconCount = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < iconCount; i++) {
wrapper.passthrough(Type.VAR_INT); // Type
wrapper.passthrough(Type.BYTE); // X
wrapper.passthrough(Type.BYTE); // Z
wrapper.passthrough(Type.BYTE); // Direction
wrapper.passthrough(Type.OPTIONAL_COMPONENT); // Display Name
wrapper.passthrough(Types.VAR_INT); // Type
wrapper.passthrough(Types.BYTE); // X
wrapper.passthrough(Types.BYTE); // Z
wrapper.passthrough(Types.BYTE); // Direction
wrapper.passthrough(Types.OPTIONAL_COMPONENT); // Display Name
}
short columns = wrapper.passthrough(Type.UNSIGNED_BYTE);
short columns = wrapper.passthrough(Types.UNSIGNED_BYTE);
if (columns < 1) return;
wrapper.passthrough(Type.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Type.UNSIGNED_BYTE); // X
wrapper.passthrough(Type.UNSIGNED_BYTE); // Z
byte[] data = wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE);
wrapper.passthrough(Types.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Types.UNSIGNED_BYTE); // X
wrapper.passthrough(Types.UNSIGNED_BYTE); // Z
byte[] data = wrapper.passthrough(Types.BYTE_ARRAY_PRIMITIVE);
for (int i = 0; i < data.length; i++) {
int color = data[i] & 0xFF;
int mappedColor = rewriter.rewrite(color);
@@ -18,49 +18,43 @@
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversion.viaversion.rewriter.SoundRewriter<C> {
private final BackwardsProtocol<C, ?, ?, ?> protocol;
public SoundRewriter(BackwardsProtocol<C, ?, ?, ?> protocol) {
public SoundRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol) {
super(protocol);
this.protocol = protocol;
}
public void registerNamedSound(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Sound identifier
handler(getNamedSoundHandler());
}
public void registerNamedSound(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.STRING); // Sound identifier
getNamedSoundHandler().handle(wrapper);
});
}
public void registerStopSound(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
handler(getStopSoundHandler());
}
});
public void registerStopSound(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> getStopSoundHandler().handle(wrapper));
}
public PacketHandler getNamedSoundHandler() {
return wrapper -> {
String soundId = wrapper.get(Type.STRING, 0);
String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
final String soundId = wrapper.get(Types.STRING, 0);
final String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
if (mappedId == null) {
return;
}
if (!mappedId.isEmpty()) {
wrapper.set(Type.STRING, 0, mappedId);
wrapper.set(Types.STRING, 0, mappedId);
} else {
wrapper.cancel();
}
@@ -69,23 +63,23 @@ public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversi
public PacketHandler getStopSoundHandler() {
return wrapper -> {
byte flags = wrapper.passthrough(Type.BYTE);
final byte flags = wrapper.passthrough(Types.BYTE);
if ((flags & 0x02) == 0) return; // No sound specified
if ((flags & 0x01) != 0) {
wrapper.passthrough(Type.VAR_INT); // Source
wrapper.passthrough(Types.VAR_INT); // Source
}
String soundId = wrapper.read(Type.STRING);
String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
final String soundId = wrapper.read(Types.STRING);
final String mappedId = protocol.getMappingData().getMappedNamedSound(soundId);
if (mappedId == null) {
// No mapping found
wrapper.write(Type.STRING, soundId);
wrapper.write(Types.STRING, soundId);
return;
}
if (!mappedId.isEmpty()) {
wrapper.write(Type.STRING, mappedId);
wrapper.write(Types.STRING, mappedId);
} else {
// Cancel if set to empty
wrapper.cancel();
@@ -94,38 +88,41 @@ public class SoundRewriter<C extends ClientboundPacketType> extends com.viaversi
}
@Override
public void register1_19_3Sound(C packetType) {
protocol.registerClientbound(packetType, get1_19_3SoundHandler());
public void registerSound1_19_3(final C packetType) {
protocol.registerClientbound(packetType, getSoundHandler1_19_3());
}
public PacketHandler get1_19_3SoundHandler() {
public PacketHandler getSoundHandler1_19_3() {
return wrapper -> {
final int soundId = wrapper.read(Type.VAR_INT);
if (soundId != 0) {
final int mappedId = idRewriter.rewrite(soundId - 1); // Normalize the id
if (mappedId == -1) {
wrapper.cancel();
return;
}
wrapper.write(Type.VAR_INT, mappedId + 1);
Holder<SoundEvent> soundEventHolder = wrapper.read(Types.SOUND_EVENT);
if (soundEventHolder.isDirect()) {
wrapper.write(Types.SOUND_EVENT, rewriteSoundEvent(wrapper, soundEventHolder));
return;
}
// Is followed by the resource loation
wrapper.write(Type.VAR_INT, 0);
String soundIdentifier = wrapper.read(Type.STRING);
final String mappedIdentifier = protocol.getMappingData().getMappedNamedSound(soundIdentifier);
if (mappedIdentifier != null) {
if (mappedIdentifier.isEmpty()) {
wrapper.cancel();
return;
}
soundIdentifier = mappedIdentifier;
final int mappedId = idRewriter.rewrite(soundEventHolder.id());
if (mappedId == -1) {
wrapper.cancel();
return;
}
wrapper.write(Type.STRING, soundIdentifier);
if (mappedId != soundEventHolder.id()) {
soundEventHolder = Holder.of(mappedId);
}
wrapper.write(Types.SOUND_EVENT, soundEventHolder);
};
}
public Holder<SoundEvent> rewriteSoundEvent(final PacketWrapper wrapper, final Holder<SoundEvent> soundEventHolder) {
final SoundEvent soundEvent = soundEventHolder.value();
final String mappedIdentifier = protocol.getMappingData().getMappedNamedSound(soundEvent.identifier());
if (mappedIdentifier != null) {
if (!mappedIdentifier.isEmpty()) {
return Holder.of(soundEvent.withIdentifier(mappedIdentifier));
}
wrapper.cancel();
}
return soundEventHolder;
}
}
@@ -0,0 +1,216 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.objects.ObjectIterator;
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter.ENCHANTMENT_LEVEL_TRANSLATION;
public class StructuredEnchantmentRewriter {
protected final BackwardsStructuredItemRewriter<?, ?, ?> itemRewriter;
private boolean rewriteIds = true;
public StructuredEnchantmentRewriter(final BackwardsStructuredItemRewriter<?, ?, ?> itemRewriter) {
this.itemRewriter = itemRewriter;
}
public void handleToClient(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final BackwardsMappingData mappingData = itemRewriter.protocol().getMappingData();
final IdRewriteFunction idRewriteFunction = id -> {
final Mappings mappings = mappingData.getEnchantmentMappings();
return mappings.getNewId(id);
};
final DescriptionSupplier descriptionSupplier = (id, level) -> {
final String remappedName = mappingData.mappedEnchantmentName(id);
return ComponentUtil.jsonStringToTag(ChatUtil.legacyToJsonString("§7" + remappedName, ENCHANTMENT_LEVEL_TRANSLATION.formatted(level), true));
};
rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS, idRewriteFunction, descriptionSupplier, false);
rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS, idRewriteFunction, descriptionSupplier, true);
}
public void handleToServer(final Item item) {
final StructuredDataContainer data = item.dataContainer();
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
if (customData != null) {
rewriteEnchantmentsToServer(data, customData, StructuredDataKey.ENCHANTMENTS);
rewriteEnchantmentsToServer(data, customData, StructuredDataKey.STORED_ENCHANTMENTS);
}
}
public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey<Enchantments> key, final IdRewriteFunction rewriteFunction, final DescriptionSupplier descriptionSupplier, final boolean storedEnchant) {
final Enchantments enchantments = data.get(key);
if (enchantments == null || enchantments.size() == 0) {
return;
}
final List<Tag> loreToAdd = new ArrayList<>();
boolean removedEnchantments = false;
boolean updatedLore = false;
final ObjectIterator<Int2IntMap.Entry> iterator = enchantments.enchantments().int2IntEntrySet().iterator();
final List<PendingIdChange> updatedIds = new ArrayList<>();
while (iterator.hasNext()) {
final Int2IntMap.Entry entry = iterator.next();
final int id = entry.getIntKey();
final int mappedId = rewriteFunction.rewrite(id);
final int level = entry.getIntValue();
if (mappedId != -1) {
if (rewriteIds) {
// Update the map after to iteration to preserve the current ids before possibly saving the original, avoid CME
updatedIds.add(new PendingIdChange(id, mappedId, level));
}
continue;
}
if (!removedEnchantments) {
// Backup original before doing modifications
final CompoundTag customData = customData(data);
itemRewriter.saveListTag(customData, asTag(enchantments), key.identifier());
removedEnchantments = true;
}
final Tag description = descriptionSupplier.get(id, level);
if (description != null && enchantments.showInTooltip()) {
loreToAdd.add(description);
updatedLore = true;
}
iterator.remove();
}
// Remove all first, then add the new ones
for (final PendingIdChange change : updatedIds) {
enchantments.remove(change.id());
}
for (final PendingIdChange change : updatedIds) {
enchantments.add(change.mappedId(), change.level());
}
if (removedEnchantments) {
final CompoundTag tag = customData(data);
if (!storedEnchant && enchantments.size() == 0) {
// Add glint override if there are no enchantments left
final Boolean glintOverride = data.get(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE);
if (glintOverride != null) {
tag.putBoolean(itemRewriter.nbtTagName("glint"), glintOverride);
} else {
tag.putBoolean(itemRewriter.nbtTagName("noglint"), true);
}
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true);
}
if (enchantments.showInTooltip()) {
tag.putBoolean(itemRewriter.nbtTagName("show_" + key.identifier()), true);
}
}
if (updatedLore) {
// Save original lore
final CompoundTag tag = customData(data);
final Tag[] lore = data.get(StructuredDataKey.LORE);
if (lore != null) {
final List<Tag> loreList = Arrays.asList(lore);
itemRewriter.saveGenericTagList(tag, loreList, "lore");
loreToAdd.addAll(loreList);
} else {
tag.putBoolean(itemRewriter.nbtTagName("nolore"), true);
}
data.set(StructuredDataKey.LORE, loreToAdd.toArray(new Tag[0]));
}
}
private CompoundTag customData(final StructuredDataContainer data) {
CompoundTag tag = data.get(StructuredDataKey.CUSTOM_DATA);
if (tag == null) {
tag = new CompoundTag();
data.set(StructuredDataKey.CUSTOM_DATA, tag);
}
return tag;
}
private ListTag<CompoundTag> asTag(final Enchantments enchantments) {
final ListTag<CompoundTag> listTag = new ListTag<>(CompoundTag.class);
for (final Int2IntMap.Entry entry : enchantments.enchantments().int2IntEntrySet()) {
final CompoundTag enchantment = new CompoundTag();
enchantment.putInt("id", entry.getIntKey());
enchantment.putInt("lvl", entry.getIntValue());
listTag.add(enchantment);
}
return listTag;
}
public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey<Enchantments> key) {
final ListTag<CompoundTag> enchantmentsTag = itemRewriter.removeListTag(tag, key.identifier(), CompoundTag.class);
if (enchantmentsTag == null) {
return;
}
final Tag glintTag = tag.remove(itemRewriter.nbtTagName("glint"));
if (glintTag instanceof ByteTag) {
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, ((NumberTag) glintTag).asBoolean());
} else if (tag.remove(itemRewriter.nbtTagName("noglint")) != null) {
data.remove(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE);
}
final List<Tag> lore = itemRewriter.removeGenericTagList(tag, "lore");
if (lore != null) {
data.set(StructuredDataKey.LORE, lore.toArray(new Tag[0]));
} else if (tag.remove(itemRewriter.nbtTagName("nolore")) != null) {
data.remove(StructuredDataKey.LORE);
}
final Enchantments enchantments = new Enchantments(tag.remove(itemRewriter.nbtTagName("show_" + key.identifier())) != null);
for (final CompoundTag enchantment : enchantmentsTag) {
enchantments.add(enchantment.getInt("id"), enchantment.getInt("lvl"));
}
data.set(key, enchantments);
}
public void setRewriteIds(final boolean rewriteIds) {
this.rewriteIds = rewriteIds;
}
@FunctionalInterface
public interface DescriptionSupplier {
Tag get(int id, int level);
}
private record PendingIdChange(int id, int mappedId, int level) {
}
}
@@ -17,9 +17,12 @@
*/
package com.viaversion.viabackwards.api.rewriters;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.VBMappingDataLoader;
import com.viaversion.viabackwards.api.data.BackwardsMappingDataLoader;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
@@ -34,10 +37,16 @@ public class TranslatableRewriter<C extends ClientboundPacketType> extends Compo
private final Map<String, String> translatables;
public static void loadTranslatables() {
final JsonObject jsonObject = VBMappingDataLoader.loadFromDataDir("translation-mappings.json");
if (!TRANSLATABLES.isEmpty()) {
throw new IllegalStateException("Translatables already loaded!");
}
fillTranslatables(BackwardsMappingDataLoader.INSTANCE.loadFromDataDir("translation-mappings.json"), TRANSLATABLES);
}
public static void fillTranslatables(final JsonObject jsonObject, final Map<String, Map<String, String>> translatables) {
for (final Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
final Map<String, String> versionMappings = new HashMap<>();
TRANSLATABLES.put(entry.getKey(), versionMappings);
translatables.put(entry.getKey(), versionMappings);
for (final Map.Entry<String, JsonElement> translationEntry : entry.getValue().getAsJsonObject().entrySet()) {
versionMappings.put(translationEntry.getKey(), translationEntry.getValue().getAsString());
}
@@ -45,14 +54,14 @@ public class TranslatableRewriter<C extends ClientboundPacketType> extends Compo
}
public TranslatableRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type) {
this(protocol, type, protocol.getClass().getSimpleName().split("To")[1].replace("_", "."));
this(protocol, type, protocol.getClass().getSimpleName().replace("Protocol", "").split("To")[0].replace("_", "."));
}
public TranslatableRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type, final String sectionIdentifier) {
public TranslatableRewriter(final BackwardsProtocol<C, ?, ?, ?> protocol, final ReadType type, final String version) {
super(protocol, type);
final Map<String, String> translatableMappings = TRANSLATABLES.get(sectionIdentifier);
final Map<String, String> translatableMappings = getTranslatableMappings(version);
if (translatableMappings == null) {
ViaBackwards.getPlatform().getLogger().warning("Missing " + sectionIdentifier + " translatables!");
ViaBackwards.getPlatform().getLogger().warning("Missing " + version + " translatables!");
this.translatables = new HashMap<>();
} else {
this.translatables = translatableMappings;
@@ -67,7 +76,19 @@ public class TranslatableRewriter<C extends ClientboundPacketType> extends Compo
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
final String newTranslate = mappedTranslationKey(translateTag.getValue());
if (newTranslate != null) {
parentTag.put("translate", new StringTag(newTranslate));
}
}
public @Nullable String mappedTranslationKey(final String translationKey) {
return translatables.get(translationKey);
}
public static Map<String, String> getTranslatableMappings(final String sectionIdentifier) {
return TRANSLATABLES.get(sectionIdentifier);
}
}
@@ -1,403 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_10to1_11.packets;
import com.viaversion.viabackwards.api.entities.storage.EntityData;
import com.viaversion.viabackwards.api.entities.storage.WrappedMetadata;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_10to1_11.PotionSplashHandler;
import com.viaversion.viabackwards.protocol.protocol1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viabackwards.protocol.protocol1_10to1_11.storage.ChestedHorseStorage;
import com.viaversion.viabackwards.utils.Block;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_9;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
import java.util.List;
import java.util.Optional;
public class EntityPackets1_11 extends LegacyEntityRewriter<ClientboundPackets1_9_3, Protocol1_10To1_11> {
public EntityPackets1_11(Protocol1_10To1_11 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.INT);
map(Type.POSITION1_8);
map(Type.INT);
handler(wrapper -> {
int type = wrapper.get(Type.INT, 0);
if (type == 2002 || type == 2007) {
// 2007 potion id doesn't exist in 1.10
if (type == 2007) {
wrapper.set(Type.INT, 0, 2002);
}
int mappedData = PotionSplashHandler.getOldData(wrapper.get(Type.INT, 1));
if (mappedData != -1) {
wrapper.set(Type.INT, 1, mappedData);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.BYTE); // 2 - Type
map(Type.DOUBLE); // 3 - x
map(Type.DOUBLE); // 4 - y
map(Type.DOUBLE); // 5 - z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(id -> EntityTypes1_11.ObjectType.findById(id).orElse(null)));
// Handle FallingBlock blocks
handler(wrapper -> {
Optional<EntityTypes1_12.ObjectType> type = EntityTypes1_12.ObjectType.findById(wrapper.get(Type.BYTE, 0));
if (type.isPresent() && type.get() == EntityTypes1_12.ObjectType.FALLING_BLOCK) {
int objectData = wrapper.get(Type.INT, 0);
int objType = objectData & 4095;
int data = objectData >> 12 & 15;
Block block = protocol.getItemRewriter().handleBlock(objType, data);
if (block == null)
return;
wrapper.set(Type.INT, 0, block.getId() | block.getData() << 12);
}
});
}
});
registerTracker(ClientboundPackets1_9_3.SPAWN_EXPERIENCE_ORB, EntityTypes1_11.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_9_3.SPAWN_GLOBAL_ENTITY, EntityTypes1_11.EntityType.WEATHER);
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.VAR_INT, Type.UNSIGNED_BYTE); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_9.METADATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler(Type.UNSIGNED_BYTE, 0));
// Rewrite entity type / metadata
handler(wrapper -> {
int entityId = wrapper.get(Type.VAR_INT, 0);
EntityType type = tracker(wrapper.user()).entityType(entityId);
List<Metadata> list = wrapper.get(Types1_9.METADATA_LIST, 0);
handleMetadata(wrapper.get(Type.VAR_INT, 0), list, wrapper.user());
EntityData entityData = entityDataForType(type);
if (entityData != null) {
wrapper.set(Type.UNSIGNED_BYTE, 0, (short) entityData.replacementId());
if (entityData.hasBaseMeta()) {
entityData.defaultMeta().createMeta(new WrappedMetadata(list));
}
}
// Sub 1.11 clients will error if the list is empty
if (list.isEmpty()) {
list.add(new Metadata(0, MetaType1_9.Byte, (byte) 0));
}
});
}
});
registerTracker(ClientboundPackets1_9_3.SPAWN_PAINTING, EntityTypes1_11.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_9_3.JOIN_GAME, EntityTypes1_11.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_9_3.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_9.METADATA_LIST); // 7 - Metadata list
handler(getTrackerAndMetaHandler(Types1_9.METADATA_LIST, EntityTypes1_11.EntityType.PLAYER));
handler(wrapper -> {
// Sub 1.11 clients will cry if the list is empty
List<Metadata> metadata = wrapper.get(Types1_9.METADATA_LIST, 0);
if (metadata.isEmpty()) {
metadata.add(new Metadata(0, MetaType1_9.Byte, (byte) 0));
}
});
}
});
registerRemoveEntities(ClientboundPackets1_9_3.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_9_3.ENTITY_METADATA, Types1_9.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_9_3.ENTITY_STATUS, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Entity ID
map(Type.BYTE); // 1 - Entity Status
handler(wrapper -> {
byte b = wrapper.get(Type.BYTE, 0);
if (b == 35) {
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_9_3.GAME_EVENT);
wrapper.write(Type.UNSIGNED_BYTE, (short) 10); // Play Elder Guardian animation
wrapper.write(Type.FLOAT, 0F);
}
});
}
});
}
@Override
protected void registerRewrites() {
// Guardian
mapEntityTypeWithData(EntityTypes1_11.EntityType.ELDER_GUARDIAN, EntityTypes1_11.EntityType.GUARDIAN);
// Skeletons
mapEntityTypeWithData(EntityTypes1_11.EntityType.WITHER_SKELETON, EntityTypes1_11.EntityType.SKELETON).spawnMetadata(storage -> storage.add(getSkeletonTypeMeta(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.STRAY, EntityTypes1_11.EntityType.SKELETON).plainName().spawnMetadata(storage -> storage.add(getSkeletonTypeMeta(2)));
// Zombies
mapEntityTypeWithData(EntityTypes1_11.EntityType.HUSK, EntityTypes1_11.EntityType.ZOMBIE).plainName().spawnMetadata(storage -> handleZombieType(storage, 6));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_VILLAGER, EntityTypes1_11.EntityType.ZOMBIE).spawnMetadata(storage -> handleZombieType(storage, 1));
// Horses
mapEntityTypeWithData(EntityTypes1_11.EntityType.HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(0))); // Nob able to ride the horse without having the MetaType sent.
mapEntityTypeWithData(EntityTypes1_11.EntityType.DONKEY, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.MULE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(2)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.SKELETON_HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(4)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_HORSE, EntityTypes1_11.EntityType.HORSE).spawnMetadata(storage -> storage.add(getHorseMetaType(3)));
// New mobs
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOCATION_FANGS, EntityTypes1_11.EntityType.SHULKER);
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOCATION_ILLAGER, EntityTypes1_11.EntityType.VILLAGER).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VEX, EntityTypes1_11.EntityType.BAT).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VINDICATION_ILLAGER, EntityTypes1_11.EntityType.VILLAGER).plainName().spawnMetadata(storage -> storage.add(new Metadata(13, MetaType1_9.VarInt, 4))); // Base Profession
mapEntityTypeWithData(EntityTypes1_11.EntityType.LIAMA, EntityTypes1_11.EntityType.HORSE).plainName().spawnMetadata(storage -> storage.add(getHorseMetaType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.LIAMA_SPIT, EntityTypes1_11.EntityType.SNOWBALL);
mapObjectType(EntityTypes1_11.ObjectType.LIAMA_SPIT, EntityTypes1_11.ObjectType.SNOWBALL, -1);
// Replace with endertorchthingies
mapObjectType(EntityTypes1_11.ObjectType.EVOCATION_FANGS, EntityTypes1_11.ObjectType.FALLING_BLOCK, 198 | 1 << 12);
// Handle ElderGuardian & target metadata
filter().type(EntityTypes1_11.EntityType.GUARDIAN).index(12).handler((event, meta) -> {
boolean b = (boolean) meta.getValue();
int bitmask = b ? 0x02 : 0;
if (event.entityType() == EntityTypes1_11.EntityType.ELDER_GUARDIAN) {
bitmask |= 0x04;
}
meta.setTypeAndValue(MetaType1_9.Byte, (byte) bitmask);
});
// Handle skeleton swing
filter().type(EntityTypes1_11.EntityType.ABSTRACT_SKELETON).index(12).toIndex(13);
/*
ZOMBIE CHANGES
*/
filter().type(EntityTypes1_11.EntityType.ZOMBIE).handler((event, meta) -> {
switch (meta.id()) {
case 13:
event.cancel();
return;
case 14:
event.setIndex(15);
break;
case 15:
event.setIndex(14);
break;
// Profession
case 16:
event.setIndex(13);
meta.setValue(1 + (int) meta.getValue());
break;
}
});
// Handle Evocation Illager
filter().type(EntityTypes1_11.EntityType.EVOCATION_ILLAGER).index(12).handler((event, meta) -> {
event.setIndex(13);
meta.setTypeAndValue(MetaType1_9.VarInt, ((Byte) meta.getValue()).intValue()); // Change the profession for the states
});
// Handle Vex (Remove this field completely since the position is not updated correctly when idling for bats. Sad ):
filter().type(EntityTypes1_11.EntityType.VEX).index(12).handler((event, meta) -> {
meta.setValue((byte) 0x00);
});
// Handle VindicationIllager
filter().type(EntityTypes1_11.EntityType.VINDICATION_ILLAGER).index(12).handler((event, meta) -> {
event.setIndex(13);
meta.setTypeAndValue(MetaType1_9.VarInt, ((Number) meta.getValue()).intValue() == 1 ? 2 : 4);
});
/*
HORSES
*/
// Handle horse flags
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(13).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
byte b = (byte) meta.getValue();
if (data.has(ChestedHorseStorage.class) && data.get(ChestedHorseStorage.class).isChested()) {
b |= 0x08; // Chested
meta.setValue(b);
}
});
// Create chested horse storage
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
if (!data.has(ChestedHorseStorage.class)) {
data.put(new ChestedHorseStorage());
}
});
// Handle horse armor
filter().type(EntityTypes1_11.EntityType.HORSE).index(16).toIndex(17);
// Handle chested horse
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).index(15).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ChestedHorseStorage storage = data.get(ChestedHorseStorage.class);
boolean b = (boolean) meta.getValue();
storage.setChested(b);
event.cancel();
});
// Get rid of Liama metadata
filter().type(EntityTypes1_11.EntityType.LIAMA).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ChestedHorseStorage storage = data.get(ChestedHorseStorage.class);
int index = event.index();
// Store them for later (:
switch (index) {
case 16:
storage.setLiamaStrength((int) meta.getValue());
event.cancel();
break;
case 17:
storage.setLiamaCarpetColor((int) meta.getValue());
event.cancel();
break;
case 18:
storage.setLiamaVariant((int) meta.getValue());
event.cancel();
break;
}
});
// Handle Horse (Correct owner)
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(14).toIndex(16);
// Handle villager - Change non-existing profession
filter().type(EntityTypes1_11.EntityType.VILLAGER).index(13).handler((event, meta) -> {
if ((int) meta.getValue() == 5) {
meta.setValue(0);
}
});
// handle new Shulker color meta
filter().type(EntityTypes1_11.EntityType.SHULKER).cancel(15);
}
/*
0 - Skeleton
1 - Wither Skeleton
2 - Stray
*/
private Metadata getSkeletonTypeMeta(int type) {
return new Metadata(12, MetaType1_9.VarInt, type);
}
/*
0 - Zombie
1-5 - Villager with profession
6 - Husk
*/
private Metadata getZombieTypeMeta(int type) {
return new Metadata(13, MetaType1_9.VarInt, type);
}
private void handleZombieType(WrappedMetadata storage, int type) {
Metadata meta = storage.get(13);
if (meta == null) {
storage.add(getZombieTypeMeta(type));
}
}
/*
Horse 0
Donkey 1
Mule 2
Zombie horse 3
Skeleton horse 4
*/
private Metadata getHorseMetaType(int type) {
return new Metadata(14, MetaType1_9.VarInt, type);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, false);
}
@Override
protected EntityType getObjectTypeFromId(int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, true);
}
}
@@ -1,101 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11_1to1_12;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.ShoulderTracker;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.packets.BlockItemPackets1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.packets.ChatPackets1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.packets.EntityPackets1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.packets.SoundPackets1_12;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
public class Protocol1_11_1To1_12 extends BackwardsProtocol<ClientboundPackets1_12, ClientboundPackets1_9_3, ServerboundPackets1_12, ServerboundPackets1_9_3> {
private static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.12", "1.11");
private final EntityPackets1_12 entityPackets = new EntityPackets1_12(this);
private final BlockItemPackets1_12 blockItemPackets = new BlockItemPackets1_12(this);
public Protocol1_11_1To1_12() {
super(ClientboundPackets1_12.class, ClientboundPackets1_9_3.class, ServerboundPackets1_12.class, ServerboundPackets1_9_3.class);
}
@Override
protected void registerPackets() {
blockItemPackets.register();
entityPackets.register();
new SoundPackets1_12(this).register();
new ChatPackets1_12(this).register();
registerClientbound(ClientboundPackets1_12.TITLE, wrapper -> {
int action = wrapper.passthrough(Type.VAR_INT);
if (action >= 0 && action <= 2) {
JsonElement component = wrapper.read(Type.COMPONENT);
wrapper.write(Type.COMPONENT, Protocol1_9To1_8.fixJson(component.toString()));
}
});
cancelClientbound(ClientboundPackets1_12.ADVANCEMENTS);
cancelClientbound(ClientboundPackets1_12.UNLOCK_RECIPES);
cancelClientbound(ClientboundPackets1_12.SELECT_ADVANCEMENTS_TAB);
}
@Override
public void init(UserConnection user) {
// Register ClientWorld
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_12.EntityType.PLAYER));
user.put(new ShoulderTracker(user));
}
@Override
public BackwardsMappings getMappingData() {
return MAPPINGS;
}
@Override
public EntityPackets1_12 getEntityRewriter() {
return entityPackets;
}
@Override
public BlockItemPackets1_12 getItemRewriter() {
return blockItemPackets;
}
@Override
public boolean hasMappingDataToLoad() {
return true;
}
}
@@ -1,154 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11_1to1_12.data;
import java.util.HashMap;
import java.util.Map;
public class AdvancementTranslations {
private static final Map<String, String> advancements = new HashMap<>();
static {
add("advancements.nether.get_wither_skull.title", "Spooky Scary Skeleton");
add("advancements.husbandry.break_diamond_hoe.description", "Completely use up a diamond hoe, and then reevaluate your life choices");
add("advancements.nether.fast_travel.description", "Use the Nether to travel 7km in the Overworld");
add("advancements.story.enter_the_end.description", "Enter the End Portal");
add("advancements.story.follow_ender_eye.title", "Eye Spy");
add("advancements.toast.task", "Advancement Made!");
add("advancements.nether.find_fortress.description", "Break your way into a Nether Fortress");
add("advancements.story.form_obsidian.description", "Form and mine a block of Obsidian");
add("advancements.adventure.sniper_duel.description", "Kill a skeleton with an arrow from more than 50 meters");
add("advancements.end.root.description", "Or the beginning?");
add("advancements.adventure.kill_a_mob.title", "Monster Hunter");
add("advancements.end.elytra.description", "Find an Elytra");
add("advancements.end.dragon_breath.description", "Collect dragon's breath in a glass bottle");
add("advancements.story.enter_the_nether.title", "We Need to Go Deeper");
add("advancements.story.upgrade_tools.title", "Getting an Upgrade");
add("advancements.story.lava_bucket.title", "Hot Stuff");
add("advancements.story.shiny_gear.title", "Cover Me With Diamonds");
add("advancements.story.smelt_iron.description", "Smelt an iron ingot");
add("chat.type.advancement.goal", "%s has reached the goal %s");
add("advancements.husbandry.break_diamond_hoe.title", "Serious Dedication");
add("advancements.story.iron_tools.description", "Upgrade your pickaxe");
add("advancements.end.respawn_dragon.title", "The End... Again...");
add("advancements.husbandry.tame_an_animal.description", "Tame an animal");
add("advancements.end.levitate.description", "Levitate up 50 blocks from the attacks of a Shulker");
add("advancements.adventure.shoot_arrow.description", "Shoot something with a bow and arrow");
add("advancements.nether.root.description", "Bring summer clothes");
add("advancements.story.enchant_item.description", "Enchant an item at an Enchanting Table");
add("advancements.adventure.root.title", "Adventure");
add("advancements.adventure.trade.title", "What a Deal!");
add("advancements.husbandry.breed_all_animals.title", "Two by Two");
add("advancements.nether.find_fortress.title", "A Terrible Fortress");
add("advancements.nether.create_full_beacon.title", "Beaconator");
add("advancements.story.cure_zombie_villager.description", "Weaken and then cure a zombie villager");
add("advancements.toast.challenge", "Challenge Complete!");
add("advancements.nether.create_full_beacon.description", "Bring a beacon to full power");
add("advancements.story.follow_ender_eye.description", "Follow an Ender Eye");
add("advancements.end.find_end_city.title", "The City at the End of the Game");
add("chat.type.advancement.challenge", "%s has completed the challenge %s");
add("advancements.story.deflect_arrow.title", "Not Today, Thank You");
add("advancements.adventure.kill_all_mobs.description", "Kill one of every hostile monster");
add("advancements.story.smelt_iron.title", "Acquire Hardware");
add("advancements.end.levitate.title", "Great View From Up Here");
add("advancements.end.kill_dragon.title", "Free the End");
add("advancements.end.kill_dragon.description", "Good luck");
add("advancements.nether.brew_potion.title", "Local Brewery");
add("advancements.story.enchant_item.title", "Enchanter");
add("advancements.end.respawn_dragon.description", "Respawn the ender dragon");
add("advancements.nether.uneasy_alliance.title", "Uneasy Alliance");
add("advancements.nether.root.title", "Nether");
add("advancements.nether.brew_potion.description", "Brew a potion");
add("advancements.nether.obtain_blaze_rod.title", "Into Fire");
add("advancements.nether.summon_wither.title", "Withering Heights");
add("advancements.story.root.title", "Minecraft");
add("advancements.husbandry.balanced_diet.description", "Eat everything that is edible, even if it's not good for you");
add("advancements.nether.uneasy_alliance.description", "Rescue a Ghast from the Nether, bring it safely home to the Overworld... and then kill it.");
add("advancements.husbandry.breed_all_animals.description", "Breed all the animals!");
add("advancements.adventure.kill_all_mobs.title", "Monsters Hunted");
add("advancements.story.cure_zombie_villager.title", "Zombie Doctor");
add("advancements.husbandry.plant_seed.title", "A Seedy Place");
add("advancements.end.dragon_breath.title", "You Need a Mint");
add("advancements.story.mine_stone.title", "Stone Age");
add("advancements.end.find_end_city.description", "Go on in, what could happen?");
add("advancements.nether.create_beacon.description", "Construct and place a Beacon");
add("advancements.adventure.summon_iron_golem.title", "Hired Help");
add("advancements.end.elytra.title", "Sky's the Limit");
add("chat.type.advancement.task", "%s has made the advancement %s");
add("advancements.story.deflect_arrow.description", "Deflect an arrow with a shield");
add("advancements.nether.all_effects.description", "Have every effect applied at the same time");
add("advancements.story.enter_the_nether.description", "Build, light and enter a Nether Portal");
add("advancements.story.mine_diamond.title", "Diamonds!");
add("advancements.husbandry.balanced_diet.title", "A Balanced Diet");
add("advancements.husbandry.root.title", "Husbandry");
add("advancements.story.root.description", "The heart and story of the game");
add("advancements.story.upgrade_tools.description", "Construct a better pickaxe");
add("advancements.nether.all_effects.title", "How Did We Get Here?");
add("advancements.end.enter_end_gateway.title", "Remote Getaway");
add("advancements.story.mine_stone.description", "Mine stone with your new pickaxe");
add("advancements.husbandry.root.description", "The world is full of friends and food");
add("advancements.end.dragon_egg.title", "The Next Generation");
add("advancements.toast.goal", "Goal Reached!");
add("advancements.empty", "There doesn't seem to be anything here...");
add("advancements.husbandry.tame_an_animal.title", "Best Friends Forever");
add("advancements.end.root.title", "The End");
add("advancements.husbandry.breed_an_animal.title", "The Parrots and the Bats");
add("advancements.story.mine_diamond.description", "Acquire diamonds");
add("advancements.adventure.sleep_in_bed.title", "Sweet dreams");
add("advancements.nether.return_to_sender.title", "Return to Sender");
add("advancements.story.obtain_armor.title", "Suit Up");
add("advancements.adventure.kill_a_mob.description", "Kill any hostile monster");
add("advancements.nether.all_potions.description", "Have every potion effect applied at the same time");
add("advancements.story.iron_tools.title", "Isn't It Iron Pick");
add("advancements.adventure.sleep_in_bed.description", "Change your respawn point");
add("advancements.husbandry.plant_seed.description", "Plant a seed and watch it grow");
add("advancements.husbandry.breed_an_animal.description", "Breed two animals together");
add("advancements.adventure.shoot_arrow.title", "Take Aim");
add("advancements.adventure.adventuring_time.description", "Discover every biome");
add("advancements.adventure.adventuring_time.title", "Adventuring Time");
add("advancements.nether.get_wither_skull.description", "Obtain a wither skeleton's skull");
add("advancements.adventure.summon_iron_golem.description", "Summon an Iron Golem to help defend a village");
add("advancements.nether.return_to_sender.description", "Destroy a Ghast with a fireball");
add("advancements.adventure.trade.description", "Successfully trade with a Villager");
add("advancements.story.obtain_armor.description", "Protect yourself with a piece of iron armor");
add("advancements.adventure.root.description", "Adventure, exploration and combat");
add("advancements.nether.create_beacon.title", "Bring Home the Beacon");
add("advancements.end.dragon_egg.description", "Hold the Dragon Egg");
add("advancements.nether.obtain_blaze_rod.description", "Relieve a Blaze of its rod");
add("advancements.story.lava_bucket.description", "Fill a bucket with lava");
add("advancements.story.form_obsidian.title", "Ice Bucket Challenge");
add("advancements.story.enter_the_end.title", "The End?");
add("advancements.nether.fast_travel.title", "Subspace Bubble");
add("advancements.end.enter_end_gateway.description", "Escape the island");
add("advancements.adventure.totem_of_undying.title", "Postmortal");
add("advancements.nether.all_potions.title", "A Furious Cocktail");
add("advancements.adventure.sniper_duel.title", "Sniper duel");
add("advancements.nether.summon_wither.description", "Summon the Wither");
add("advancements.adventure.totem_of_undying.description", "Use a Totem of Undying to cheat death");
add("advancements.story.shiny_gear.description", "Diamond armor saves lives");
}
private static void add(String key, String value) {
advancements.put(key, value);
}
public static String get(String key) {
return advancements.get(key);
}
}
@@ -1,306 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11_1to1_12.packets;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.MapColorMapping;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.IntArrayTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.LongArrayTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
import java.util.Iterator;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BlockItemPackets1_12 extends LegacyBlockItemRewriter<ClientboundPackets1_12, ServerboundPackets1_9_3, Protocol1_11_1To1_12> {
public BlockItemPackets1_12(Protocol1_11_1To1_12 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_12.MAP_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.BYTE);
map(Type.BOOLEAN);
handler(wrapper -> {
int count = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < count * 3; i++) {
wrapper.passthrough(Type.BYTE);
}
});
handler(wrapper -> {
short columns = wrapper.passthrough(Type.UNSIGNED_BYTE);
if (columns <= 0) return;
wrapper.passthrough(Type.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Type.UNSIGNED_BYTE); // X
wrapper.passthrough(Type.UNSIGNED_BYTE); // Z
byte[] data = wrapper.read(Type.BYTE_ARRAY_PRIMITIVE);
for (int i = 0; i < data.length; i++) {
short color = (short) (data[i] & 0xFF);
if (color > 143) {
color = (short) MapColorMapping.getNearestOldColor(color);
data[i] = (byte) color;
}
}
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, data);
});
}
});
registerSetSlot(ClientboundPackets1_12.SET_SLOT);
registerWindowItems(ClientboundPackets1_12.WINDOW_ITEMS);
registerEntityEquipment(ClientboundPackets1_12.ENTITY_EQUIPMENT);
// Plugin message Packet -> Trading
protocol.registerClientbound(ClientboundPackets1_12.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Type.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Type.INT); // Passthrough Window ID
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Input Item
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Type.BOOLEAN); // Has second item
if (secondItem)
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Second Item
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
}
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_9_3.CLICK_WINDOW, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.SHORT); // 1 - Slot
map(Type.BYTE); // 2 - Button
map(Type.SHORT); // 3 - Action number
map(Type.VAR_INT); // 4 - Mode
map(Type.ITEM1_8); // 5 - Clicked Item
handler(wrapper -> {
if (wrapper.get(Type.VAR_INT, 0) == 1) { // Shift click
// https://github.com/ViaVersion/ViaVersion/pull/754
// Previously clients grab the item from the clicked slot *before* it has
// been moved however now they grab the slot item *after* it has been moved
// and send that in the packet.
wrapper.set(Type.ITEM1_8, 0, null); // Set null item (probably will work)
// Apologize (may happen in some cases, maybe if inventory is full?)
PacketWrapper confirm = wrapper.create(ServerboundPackets1_12.WINDOW_CONFIRMATION);
confirm.write(Type.UNSIGNED_BYTE, wrapper.get(Type.UNSIGNED_BYTE, 0));
confirm.write(Type.SHORT, wrapper.get(Type.SHORT, 1));
confirm.write(Type.BOOLEAN, false); // Success - not used
wrapper.sendToServer(Protocol1_11_1To1_12.class);
wrapper.cancel();
confirm.sendToServer(Protocol1_11_1To1_12.class);
return;
}
Item item = wrapper.get(Type.ITEM1_8, 0);
handleItemToServer(item);
});
}
});
registerCreativeInvAction(ServerboundPackets1_9_3.CREATIVE_INVENTORY_ACTION);
protocol.registerClientbound(ClientboundPackets1_12.CHUNK_DATA, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()); // Use the 1.9.4 Chunk type since nothing changed.
Chunk chunk = wrapper.passthrough(type);
handleChunk(chunk);
});
protocol.registerClientbound(ClientboundPackets1_12.BLOCK_CHANGE, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8); // 0 - Block Position
map(Type.VAR_INT); // 1 - Block
handler(wrapper -> {
int idx = wrapper.get(Type.VAR_INT, 0);
wrapper.set(Type.VAR_INT, 0, handleBlockID(idx));
});
}
});
protocol.registerClientbound(ClientboundPackets1_12.MULTI_BLOCK_CHANGE, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Chunk X
map(Type.INT); // 1 - Chunk Z
map(Type.BLOCK_CHANGE_RECORD_ARRAY);
handler(wrapper -> {
for (BlockChangeRecord record : wrapper.get(Type.BLOCK_CHANGE_RECORD_ARRAY, 0)) {
record.setBlockId(handleBlockID(record.getBlockId()));
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_12.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8); // 0 - Position
map(Type.UNSIGNED_BYTE); // 1 - Action
map(Type.NAMED_COMPOUND_TAG); // 2 - NBT
handler(wrapper -> {
// Remove bed color
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 11)
wrapper.cancel();
});
}
});
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.metaType().type().equals(Type.ITEM1_8)) // Is Item
meta.setValue(handleItemToClient((Item) meta.getValue()));
});
protocol.registerServerbound(ServerboundPackets1_9_3.CLIENT_STATUS, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Action ID
handler(wrapper -> {
// Open Inventory
if (wrapper.get(Type.VAR_INT, 0) == 2) {
wrapper.cancel();
}
});
}
});
}
@Override
public @Nullable Item handleItemToClient(Item item) {
if (item == null) return null;
super.handleItemToClient(item);
if (item.tag() != null) {
CompoundTag backupTag = new CompoundTag();
if (handleNbtToClient(item.tag(), backupTag)) {
item.tag().put("Via|LongArrayTags", backupTag);
}
}
return item;
}
private boolean handleNbtToClient(CompoundTag compoundTag, CompoundTag backupTag) {
// Long array tags were introduced in 1.12 - just remove them
// Only save the removed tags instead of blindly copying the entire nbt again
Iterator<Map.Entry<String, Tag>> iterator = compoundTag.iterator();
boolean hasLongArrayTag = false;
while (iterator.hasNext()) {
Map.Entry<String, Tag> entry = iterator.next();
if (entry.getValue() instanceof CompoundTag) {
CompoundTag nestedBackupTag = new CompoundTag();
backupTag.put(entry.getKey(), nestedBackupTag);
hasLongArrayTag |= handleNbtToClient((CompoundTag) entry.getValue(), nestedBackupTag);
} else if (entry.getValue() instanceof LongArrayTag) {
backupTag.put(entry.getKey(), fromLongArrayTag((LongArrayTag) entry.getValue()));
iterator.remove();
hasLongArrayTag = true;
}
}
return hasLongArrayTag;
}
@Override
public @Nullable Item handleItemToServer(Item item) {
if (item == null) return null;
super.handleItemToServer(item);
if (item.tag() != null) {
Tag tag = item.tag().remove("Via|LongArrayTags");
if (tag instanceof CompoundTag) {
handleNbtToServer(item.tag(), (CompoundTag) tag);
}
}
return item;
}
private void handleNbtToServer(CompoundTag compoundTag, CompoundTag backupTag) {
// Restore the removed long array tags
for (Map.Entry<String, Tag> entry : backupTag) {
if (entry.getValue() instanceof CompoundTag) {
CompoundTag nestedTag = compoundTag.getCompoundTag(entry.getKey());
handleNbtToServer(nestedTag, (CompoundTag) entry.getValue());
} else {
compoundTag.put(entry.getKey(), fromIntArrayTag((IntArrayTag) entry.getValue()));
}
}
}
private IntArrayTag fromLongArrayTag(LongArrayTag tag) {
int[] intArray = new int[tag.length() * 2];
long[] longArray = tag.getValue();
int i = 0;
for (long l : longArray) {
intArray[i++] = (int) (l >> 32);
intArray[i++] = (int) l;
}
return new IntArrayTag(intArray);
}
private LongArrayTag fromIntArrayTag(IntArrayTag tag) {
long[] longArray = new long[tag.length() / 2];
int[] intArray = tag.getValue();
for (int i = 0, j = 0; i < intArray.length; i += 2, j++) {
longArray[j] = (long) intArray[i] << 32 | ((long) intArray[i + 1] & 0xFFFFFFFFL);
}
return new LongArrayTag(longArray);
}
}
@@ -1,70 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11_1to1_12.packets;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.AdvancementTranslations;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ClientboundPackets1_12;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
public class ChatPackets1_12 extends RewriterBase<Protocol1_11_1To1_12> {
public static final ComponentRewriter<ClientboundPackets1_12> COMPONENT_REWRITER = new ComponentRewriter<ClientboundPackets1_12>(null, ComponentRewriter.ReadType.JSON) {
@Override
public void processText(JsonElement element) {
super.processText(element);
if (element == null || !element.isJsonObject()) {
return;
}
JsonObject object = element.getAsJsonObject();
JsonElement keybind = object.remove("keybind");
if (keybind == null) {
return;
}
//TODO Add nicer text for the key, also use this component rewriter in more packets
object.addProperty("text", keybind.getAsString());
}
@Override
protected void handleTranslate(JsonObject object, String translate) {
String text = AdvancementTranslations.get(translate);
if (text != null) {
object.addProperty("translate", text);
}
}
};
public ChatPackets1_12(Protocol1_11_1To1_12 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_12.CHAT_MESSAGE, wrapper -> {
JsonElement element = wrapper.passthrough(Type.COMPONENT);
COMPONENT_REWRITER.processText(element);
});
}
}
@@ -1,313 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11_1to1_12.packets;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.ParrotStorage;
import com.viaversion.viabackwards.protocol.protocol1_11_1to1_12.data.ShoulderTracker;
import com.viaversion.viabackwards.utils.Block;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_12;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
import java.util.Optional;
public class EntityPackets1_12 extends LegacyEntityRewriter<ClientboundPackets1_12, Protocol1_11_1To1_12> {
public EntityPackets1_12(Protocol1_11_1To1_12 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_12.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.BYTE); // 2 - Type
map(Type.DOUBLE); // 3 - x
map(Type.DOUBLE); // 4 - y
map(Type.DOUBLE); // 5 - z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(id -> EntityTypes1_12.ObjectType.findById(id).orElse(null)));
// Handle FallingBlock blocks
handler(wrapper -> {
Optional<EntityTypes1_12.ObjectType> type = EntityTypes1_12.ObjectType.findById(wrapper.get(Type.BYTE, 0));
if (type.isPresent() && type.get() == EntityTypes1_12.ObjectType.FALLING_BLOCK) {
int objectData = wrapper.get(Type.INT, 0);
int objType = objectData & 4095;
int data = objectData >> 12 & 15;
Block block = protocol.getItemRewriter().handleBlock(objType, data);
if (block == null) {
return;
}
wrapper.set(Type.INT, 0, block.getId() | block.getData() << 12);
}
});
}
});
registerTracker(ClientboundPackets1_12.SPAWN_EXPERIENCE_ORB, EntityTypes1_12.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_12.SPAWN_GLOBAL_ENTITY, EntityTypes1_12.EntityType.WEATHER);
protocol.registerClientbound(ClientboundPackets1_12.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_12.METADATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / metadata
handler(getMobSpawnRewriter(Types1_12.METADATA_LIST));
}
});
registerTracker(ClientboundPackets1_12.SPAWN_PAINTING, EntityTypes1_12.EntityType.PAINTING);
protocol.registerClientbound(ClientboundPackets1_12.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_12.METADATA_LIST); // 7 - Metadata list
handler(getTrackerAndMetaHandler(Types1_12.METADATA_LIST, EntityTypes1_12.EntityType.PLAYER));
}
});
protocol.registerClientbound(ClientboundPackets1_12.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
handler(getTrackerHandler(EntityTypes1_12.EntityType.PLAYER, Type.INT));
handler(getDimensionHandler(1));
handler(wrapper -> {
ShoulderTracker tracker = wrapper.user().get(ShoulderTracker.class);
tracker.setEntityId(wrapper.get(Type.INT, 0));
});
// Send fake inventory achievement
handler(packetWrapper -> {
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_9_3.STATISTICS, packetWrapper.user());
wrapper.write(Type.VAR_INT, 1);
wrapper.write(Type.STRING, "achievement.openInventory");
wrapper.write(Type.VAR_INT, 1);
wrapper.scheduleSend(Protocol1_11_1To1_12.class);
});
}
});
registerRespawn(ClientboundPackets1_12.RESPAWN);
registerRemoveEntities(ClientboundPackets1_12.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_12.ENTITY_METADATA, Types1_12.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_12.ENTITY_PROPERTIES, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.INT);
handler(wrapper -> {
int size = wrapper.get(Type.INT, 0);
int newSize = size;
for (int i = 0; i < size; i++) {
String key = wrapper.read(Type.STRING);
// Remove new attribute
if (key.equals("generic.flyingSpeed")) {
newSize--;
wrapper.read(Type.DOUBLE);
int modSize = wrapper.read(Type.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.read(Type.UUID);
wrapper.read(Type.DOUBLE);
wrapper.read(Type.BYTE);
}
} else {
wrapper.write(Type.STRING, key);
wrapper.passthrough(Type.DOUBLE);
int modSize = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.passthrough(Type.UUID);
wrapper.passthrough(Type.DOUBLE);
wrapper.passthrough(Type.BYTE);
}
}
}
if (newSize != size) {
wrapper.set(Type.INT, 0, newSize);
}
});
}
});
}
@Override
protected void registerRewrites() {
mapEntityTypeWithData(EntityTypes1_12.EntityType.PARROT, EntityTypes1_12.EntityType.BAT).plainName().spawnMetadata(storage -> storage.add(new Metadata(12, MetaType1_12.Byte, (byte) 0x00)));
mapEntityTypeWithData(EntityTypes1_12.EntityType.ILLUSION_ILLAGER, EntityTypes1_12.EntityType.EVOCATION_ILLAGER).plainName();
filter().handler((event, meta) -> {
if (meta.metaType() == MetaType1_12.Chat) {
ChatPackets1_12.COMPONENT_REWRITER.processText((JsonElement) meta.getValue());
}
});
// Handle Illager
filter().type(EntityTypes1_12.EntityType.EVOCATION_ILLAGER).cancel(12);
filter().type(EntityTypes1_12.EntityType.EVOCATION_ILLAGER).index(13).toIndex(12);
filter().type(EntityTypes1_12.EntityType.ILLUSION_ILLAGER).index(0).handler((event, meta) -> {
byte mask = (byte) meta.getValue();
if ((mask & 0x20) == 0x20) {
mask &= ~0x20;
}
meta.setValue(mask);
});
// Create Parrot storage
filter().type(EntityTypes1_12.EntityType.PARROT).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
if (!data.has(ParrotStorage.class)) {
data.put(new ParrotStorage());
}
});
// Parrot remove animal metadata
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(12); // Is baby
filter().type(EntityTypes1_12.EntityType.PARROT).index(13).handler((event, meta) -> {
StoredEntityData data = storedEntityData(event);
ParrotStorage storage = data.get(ParrotStorage.class);
boolean isSitting = (((byte) meta.getValue()) & 0x01) == 0x01;
boolean isTamed = (((byte) meta.getValue()) & 0x04) == 0x04;
if (!storage.isTamed() && isTamed) {
// TODO do something to let the user know it's done
}
storage.setTamed(isTamed);
if (isSitting) {
event.setIndex(12);
meta.setValue((byte) 0x01);
storage.setSitting(true);
} else if (storage.isSitting()) {
event.setIndex(12);
meta.setValue((byte) 0x00);
storage.setSitting(false);
} else {
event.cancel();
}
}); // Flags (Is sitting etc, might be useful in the future
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(14); // Owner
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(15); // Variant
// Left shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(15).handler((event, meta) -> {
CompoundTag tag = (CompoundTag) meta.getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
if (tag.isEmpty() && tracker.getLeftShoulder() != null) {
tracker.setLeftShoulder(null);
tracker.update();
} else if (tag.getStringTag("id") != null && event.entityId() == tracker.getEntityId()) {
String id = tag.getStringTag("id").getValue();
if (tracker.getLeftShoulder() == null || !tracker.getLeftShoulder().equals(id)) {
tracker.setLeftShoulder(id);
tracker.update();
}
}
event.cancel();
});
// Right shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(16).handler((event, meta) -> {
CompoundTag tag = (CompoundTag) event.meta().getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
if (tag.isEmpty() && tracker.getRightShoulder() != null) {
tracker.setRightShoulder(null);
tracker.update();
} else if (tag.getStringTag("id") != null && event.entityId() == tracker.getEntityId()) {
String id = tag.getStringTag("id").getValue();
if (tracker.getRightShoulder() == null || !tracker.getRightShoulder().equals(id)) {
tracker.setRightShoulder(id);
tracker.update();
}
}
event.cancel();
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_12.getTypeFromId(typeId, false);
}
@Override
protected EntityType getObjectTypeFromId(final int typeId) {
return EntityTypes1_12.getTypeFromId(typeId, true);
}
}
@@ -1,127 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11to1_11_1.packets;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_11to1_11_1.Protocol1_11To1_11_1;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
public class EntityPackets1_11_1 extends LegacyEntityRewriter<ClientboundPackets1_9_3, Protocol1_11To1_11_1> {
public EntityPackets1_11_1(Protocol1_11To1_11_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.BYTE); // 2 - Type
map(Type.DOUBLE); // 3 - x
map(Type.DOUBLE); // 4 - y
map(Type.DOUBLE); // 5 - z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(id -> EntityTypes1_11.ObjectType.findById(id).orElse(null)));
}
});
registerTracker(ClientboundPackets1_9_3.SPAWN_EXPERIENCE_ORB, EntityTypes1_11.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_9_3.SPAWN_GLOBAL_ENTITY, EntityTypes1_11.EntityType.WEATHER);
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_9.METADATA_LIST); // 12 - Metadata
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / metadata
handler(getMobSpawnRewriter(Types1_9.METADATA_LIST));
}
});
registerTracker(ClientboundPackets1_9_3.SPAWN_PAINTING, EntityTypes1_11.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_9_3.JOIN_GAME, EntityTypes1_11.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_9_3.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_9_3.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_9.METADATA_LIST); // 7 - Metadata list
handler(getTrackerAndMetaHandler(Types1_9.METADATA_LIST, EntityTypes1_11.EntityType.PLAYER));
}
});
registerRemoveEntities(ClientboundPackets1_9_3.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_9_3.ENTITY_METADATA, Types1_9.METADATA_LIST);
}
@Override
protected void registerRewrites() {
// Handle non-existing firework metadata (index 7 entity id for boosting)
filter().type(EntityTypes1_11.EntityType.FIREWORK).cancel(7);
// Handle non-existing pig metadata (index 14 - boost time)
filter().type(EntityTypes1_11.EntityType.PIG).cancel(14);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, false);
}
@Override
protected EntityType getObjectTypeFromId(final int typeId) {
return EntityTypes1_11.getTypeFromId(typeId, true);
}
}
@@ -1,124 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_11to1_11_1.packets;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viabackwards.protocol.protocol1_11to1_11_1.Protocol1_11To1_11_1;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
public class ItemPackets1_11_1 extends LegacyBlockItemRewriter<ClientboundPackets1_9_3, ServerboundPackets1_9_3, Protocol1_11To1_11_1> {
private LegacyEnchantmentRewriter enchantmentRewriter;
public ItemPackets1_11_1(Protocol1_11To1_11_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerSetSlot(ClientboundPackets1_9_3.SET_SLOT);
registerWindowItems(ClientboundPackets1_9_3.WINDOW_ITEMS);
registerEntityEquipment(ClientboundPackets1_9_3.ENTITY_EQUIPMENT);
// Plugin message Packet -> Trading
protocol.registerClientbound(ClientboundPackets1_9_3.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // 0 - Channel
handler(wrapper -> {
if (wrapper.get(Type.STRING, 0).equals("MC|TrList")) {
wrapper.passthrough(Type.INT); // Passthrough Window ID
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Input Item
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Output Item
boolean secondItem = wrapper.passthrough(Type.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Type.ITEM1_8, handleItemToClient(wrapper.read(Type.ITEM1_8))); // Second Item
}
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
}
}
});
}
});
registerClickWindow(ServerboundPackets1_9_3.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_9_3.CREATIVE_INVENTORY_ACTION);
// Handle item metadata
protocol.getEntityRewriter().filter().handler((event, meta) -> {
if (meta.metaType().type().equals(Type.ITEM1_8)) { // Is Item
meta.setValue(handleItemToClient((Item) meta.getValue()));
}
});
}
@Override
protected void registerRewrites() {
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName);
enchantmentRewriter.registerEnchantment(22, "§7Sweeping Edge");
}
@Override
public Item handleItemToClient(Item item) {
if (item == null) return null;
super.handleItemToClient(item);
CompoundTag tag = item.tag();
if (tag == null) return item;
if (tag.getListTag("ench") != null) {
enchantmentRewriter.rewriteEnchantmentsToClient(tag, false);
}
if (tag.getListTag("StoredEnchantments") != null) {
enchantmentRewriter.rewriteEnchantmentsToClient(tag, true);
}
return item;
}
@Override
public Item handleItemToServer(Item item) {
if (item == null) return null;
super.handleItemToServer(item);
CompoundTag tag = item.tag();
if (tag == null) return item;
if (tag.getListTag(nbtTagName + "|ench") != null) {
enchantmentRewriter.rewriteEnchantmentsToServer(tag, false);
}
if (tag.getListTag(nbtTagName + "|StoredEnchantments") != null) {
enchantmentRewriter.rewriteEnchantmentsToServer(tag, true);
}
return item;
}
}
@@ -1,378 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_12_2to1_13.packets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.entities.storage.EntityPositionHandler;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.data.EntityTypeMapping;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.data.PaintingMapping;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.data.ParticleMapping;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.storage.PlayerPositionStorage1_13;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaType1_12;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_12_1to1_12.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.protocol1_12_1to1_12.ServerboundPackets1_12_1;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import java.util.Optional;
public class EntityPackets1_13 extends LegacyEntityRewriter<ClientboundPackets1_13, Protocol1_12_2To1_13> {
public EntityPackets1_13(Protocol1_12_2To1_13 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.BYTE);
handler(wrapper -> {
if (!ViaBackwards.getConfig().isFix1_13FacePlayer()) return;
PlayerPositionStorage1_13 playerStorage = wrapper.user().get(PlayerPositionStorage1_13.class);
byte bitField = wrapper.get(Type.BYTE, 0);
playerStorage.setX(toSet(bitField, 0, playerStorage.getX(), wrapper.get(Type.DOUBLE, 0)));
playerStorage.setY(toSet(bitField, 1, playerStorage.getY(), wrapper.get(Type.DOUBLE, 1)));
playerStorage.setZ(toSet(bitField, 2, playerStorage.getZ(), wrapper.get(Type.DOUBLE, 2)));
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.UUID);
map(Type.BYTE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.BYTE);
map(Type.BYTE);
map(Type.INT);
handler(getObjectTrackerHandler());
handler(wrapper -> {
Optional<EntityTypes1_13.ObjectType> optionalType = EntityTypes1_13.ObjectType.findById(wrapper.get(Type.BYTE, 0));
if (!optionalType.isPresent()) return;
EntityTypes1_13.ObjectType type = optionalType.get();
if (type == EntityTypes1_13.ObjectType.FALLING_BLOCK) {
int blockState = wrapper.get(Type.INT, 0);
int combined = Protocol1_12_2To1_13.MAPPINGS.getNewBlockStateId(blockState);
combined = ((combined >> 4) & 0xFFF) | ((combined & 0xF) << 12);
wrapper.set(Type.INT, 0, combined);
} else if (type == EntityTypes1_13.ObjectType.ITEM_FRAME) {
int data = wrapper.get(Type.INT, 0);
switch (data) {
case 3:
data = 0;
break;
case 4:
data = 1;
break;
case 5:
data = 3;
break;
}
wrapper.set(Type.INT, 0, data);
} else if (type == EntityTypes1_13.ObjectType.TRIDENT) {
wrapper.set(Type.BYTE, 0, (byte) EntityTypes1_13.ObjectType.TIPPED_ARROW.getId());
}
});
}
});
registerTracker(ClientboundPackets1_13.SPAWN_EXPERIENCE_ORB, EntityTypes1_13.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_13.SPAWN_GLOBAL_ENTITY, EntityTypes1_13.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.UUID);
map(Type.VAR_INT);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.BYTE);
map(Type.BYTE);
map(Type.BYTE);
map(Type.SHORT);
map(Type.SHORT);
map(Type.SHORT);
map(Types1_13.METADATA_LIST, Types1_12.METADATA_LIST);
handler(wrapper -> {
int type = wrapper.get(Type.VAR_INT, 1);
EntityType entityType = EntityTypes1_13.getTypeFromId(type, false);
tracker(wrapper.user()).addEntity(wrapper.get(Type.VAR_INT, 0), entityType);
int oldId = EntityTypeMapping.getOldId(type);
if (oldId == -1) {
if (!hasData(entityType)) {
ViaBackwards.getPlatform().getLogger().warning("Could not find 1.12 entity type for 1.13 entity type " + type + "/" + entityType);
}
} else {
wrapper.set(Type.VAR_INT, 1, oldId);
}
});
// Rewrite entity type / metadata
handler(getMobSpawnRewriter(Types1_12.METADATA_LIST));
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.UUID);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.BYTE);
map(Type.BYTE);
map(Types1_13.METADATA_LIST, Types1_12.METADATA_LIST);
handler(getTrackerAndMetaHandler(Types1_12.METADATA_LIST, EntityTypes1_13.EntityType.PLAYER));
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.UUID);
handler(getTrackerHandler(EntityTypes1_13.EntityType.PAINTING, Type.VAR_INT));
handler(wrapper -> {
int motive = wrapper.read(Type.VAR_INT);
String title = PaintingMapping.getStringId(motive);
wrapper.write(Type.STRING, title);
});
}
});
registerJoinGame(ClientboundPackets1_13.JOIN_GAME, EntityTypes1_13.EntityType.PLAYER);
protocol.registerClientbound(ClientboundPackets1_13.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Dimension ID
handler(getDimensionHandler(0));
handler(wrapper -> {
wrapper.user().get(BackwardsBlockStorage.class).clear();
wrapper.user().get(NoteBlockStorage.class).clear();
});
}
});
registerRemoveEntities(ClientboundPackets1_13.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_13.ENTITY_METADATA, Types1_13.METADATA_LIST, Types1_12.METADATA_LIST);
// Face Player (new packet)
protocol.registerClientbound(ClientboundPackets1_13.FACE_PLAYER, null, wrapper -> {
wrapper.cancel();
if (!ViaBackwards.getConfig().isFix1_13FacePlayer()) return;
// We will just accept a possible, very minor mismatch between server and client position,
// and will take the server's one in both cases, else we would have to cache all entities' positions.
final int anchor = wrapper.read(Type.VAR_INT); // feet/eyes enum
final double x = wrapper.read(Type.DOUBLE);
final double y = wrapper.read(Type.DOUBLE);
final double z = wrapper.read(Type.DOUBLE);
PlayerPositionStorage1_13 positionStorage = wrapper.user().get(PlayerPositionStorage1_13.class);
// Send teleport packet to client
PacketWrapper positionAndLook = wrapper.create(ClientboundPackets1_12_1.PLAYER_POSITION);
positionAndLook.write(Type.DOUBLE, 0D);
positionAndLook.write(Type.DOUBLE, 0D);
positionAndLook.write(Type.DOUBLE, 0D);
//TODO properly cache and calculate head position?
EntityPositionHandler.writeFacingDegrees(positionAndLook, positionStorage.getX(),
anchor == 1 ? positionStorage.getY() + 1.62 : positionStorage.getY(),
positionStorage.getZ(), x, y, z);
positionAndLook.write(Type.BYTE, (byte) 7); // bitfield, 0=absolute, 1=relative - x,y,z relative, yaw,pitch absolute
positionAndLook.write(Type.VAR_INT, -1);
positionAndLook.send(Protocol1_12_2To1_13.class);
});
if (ViaBackwards.getConfig().isFix1_13FacePlayer()) {
PacketHandlers movementRemapper = new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
handler(wrapper -> wrapper.user().get(PlayerPositionStorage1_13.class).setCoordinates(wrapper, false));
}
};
protocol.registerServerbound(ServerboundPackets1_12_1.PLAYER_POSITION, movementRemapper); // Player Position
protocol.registerServerbound(ServerboundPackets1_12_1.PLAYER_POSITION_AND_ROTATION, movementRemapper); // Player Position And Look (serverbound)
protocol.registerServerbound(ServerboundPackets1_12_1.VEHICLE_MOVE, movementRemapper); // Vehicle Move (serverbound)
}
}
@Override
protected void registerRewrites() {
// Rewrite new Entity 'drowned'
mapEntityTypeWithData(EntityTypes1_13.EntityType.DROWNED, EntityTypes1_13.EntityType.ZOMBIE_VILLAGER).plainName();
// Fishy
mapEntityTypeWithData(EntityTypes1_13.EntityType.COD, EntityTypes1_13.EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityTypes1_13.EntityType.SALMON, EntityTypes1_13.EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityTypes1_13.EntityType.PUFFERFISH, EntityTypes1_13.EntityType.SQUID).plainName();
mapEntityTypeWithData(EntityTypes1_13.EntityType.TROPICAL_FISH, EntityTypes1_13.EntityType.SQUID).plainName();
// Phantom
mapEntityTypeWithData(EntityTypes1_13.EntityType.PHANTOM, EntityTypes1_13.EntityType.PARROT).plainName().spawnMetadata(storage -> {
// The phantom is grey/blue so let's do yellow/blue
storage.add(new Metadata(15, MetaType1_12.VarInt, 3));
});
// Dolphin
mapEntityTypeWithData(EntityTypes1_13.EntityType.DOLPHIN, EntityTypes1_13.EntityType.SQUID).plainName();
// Turtle
mapEntityTypeWithData(EntityTypes1_13.EntityType.TURTLE, EntityTypes1_13.EntityType.OCELOT).plainName();
// Rewrite Meta types
filter().handler((event, meta) -> {
int typeId = meta.metaType().typeId();
if (typeId == 4) {
JsonElement element = meta.value();
protocol.translatableRewriter().processText(element);
meta.setMetaType(MetaType1_12.Chat);
} else if (typeId == 5) {
// Rewrite optional chat to string
JsonElement element = meta.value();
meta.setTypeAndValue(MetaType1_12.String, protocol.jsonToLegacy(element));
} else if (typeId == 6) {
Item item = (Item) meta.getValue();
meta.setTypeAndValue(MetaType1_12.Slot, protocol.getItemRewriter().handleItemToClient(item));
} else if (typeId == 15) {
// Discontinue particles
event.cancel();
} else {
meta.setMetaType(MetaType1_12.byId(typeId > 5 ? typeId - 1 : typeId));
}
});
// Handle zombie metadata
filter().type(EntityTypes1_13.EntityType.ZOMBIE).removeIndex(15);
// Handle turtle metadata (Remove them all for now)
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(13); // Home pos
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(14); // Has egg
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(15); // Laying egg
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(16); // Travel pos
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(17); // Going home
filter().type(EntityTypes1_13.EntityType.TURTLE).cancel(18); // Traveling
// Remove additional fish meta
filter().type(EntityTypes1_13.EntityType.ABSTRACT_FISHES).cancel(12);
filter().type(EntityTypes1_13.EntityType.ABSTRACT_FISHES).cancel(13);
// Remove phantom size
filter().type(EntityTypes1_13.EntityType.PHANTOM).cancel(12);
// Remove boat splash timer
filter().type(EntityTypes1_13.EntityType.BOAT).cancel(12);
// Remove Trident special loyalty level
filter().type(EntityTypes1_13.EntityType.TRIDENT).cancel(7);
// Handle new wolf colors
filter().type(EntityTypes1_13.EntityType.WOLF).index(17).handler((event, meta) -> {
meta.setValue(15 - (int) meta.getValue());
});
// Rewrite AreaEffectCloud
filter().type(EntityTypes1_13.EntityType.AREA_EFFECT_CLOUD).index(9).handler((event, meta) -> {
Particle particle = (Particle) meta.getValue();
ParticleMapping.ParticleData data = ParticleMapping.getMapping(particle.getId());
int firstArg = 0;
int secondArg = 0;
int[] particleArgs = data.rewriteMeta(protocol, particle.getArguments());
if (particleArgs != null && particleArgs.length != 0) {
if (data.getHandler().isBlockHandler() && particleArgs[0] == 0) {
// Air doesn't have a break particle for sub 1.13 clients -> glass pane
particleArgs[0] = 102;
}
firstArg = particleArgs[0];
secondArg = particleArgs.length == 2 ? particleArgs[1] : 0;
}
event.createExtraMeta(new Metadata(9, MetaType1_12.VarInt, data.getHistoryId()));
event.createExtraMeta(new Metadata(10, MetaType1_12.VarInt, firstArg));
event.createExtraMeta(new Metadata(11, MetaType1_12.VarInt, secondArg));
event.cancel();
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_13.getTypeFromId(typeId, false);
}
@Override
protected EntityType getObjectTypeFromId(final int typeId) {
return EntityTypes1_13.getTypeFromId(typeId, true);
}
@Override
public int newEntityId(final int newId) {
return EntityTypeMapping.getOldId(newId);
}
private static double toSet(int field, int bitIndex, double origin, double packetValue) {
// If bit is set, coordinate is relative
return (field & (1 << bitIndex)) != 0 ? origin + packetValue : packetValue;
}
}
@@ -1,574 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_12_2to1_13.packets;
import com.google.common.base.Joiner;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.data.ParticleMapping;
import com.viaversion.viabackwards.protocol.protocol1_12_2to1_13.storage.TabCompleteStorage;
import com.viaversion.viabackwards.utils.ChatUtil;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_12_1to1_12.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.protocol1_12_1to1_12.ServerboundPackets1_12_1;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets.InventoryPackets;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public class PlayerPacket1_13 extends RewriterBase<Protocol1_12_2To1_13> {
private final CommandRewriter<ClientboundPackets1_13> commandRewriter = new CommandRewriter<>(protocol);
public PlayerPacket1_13(Protocol1_12_2To1_13 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
// Login Plugin Request
protocol.registerClientbound(State.LOGIN, 0x04, -1, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
packetWrapper.cancel();
// Plugin response
packetWrapper.create(0x02, wrapper -> {
wrapper.write(Type.VAR_INT, packetWrapper.read(Type.VAR_INT)); // Packet id
wrapper.write(Type.BOOLEAN, false); // Success
}).sendToServer(Protocol1_12_2To1_13.class);
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.PLUGIN_MESSAGE, wrapper -> {
String channel = wrapper.read(Type.STRING);
if (channel.equals("minecraft:trader_list")) {
wrapper.write(Type.STRING, "MC|TrList");
wrapper.passthrough(Type.INT); //Passthrough Window ID
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
//Input Item
Item input = wrapper.read(Type.ITEM1_13);
wrapper.write(Type.ITEM1_8, protocol.getItemRewriter().handleItemToClient(input));
//Output Item
Item output = wrapper.read(Type.ITEM1_13);
wrapper.write(Type.ITEM1_8, protocol.getItemRewriter().handleItemToClient(output));
boolean secondItem = wrapper.passthrough(Type.BOOLEAN); //Has second item
if (secondItem) {
//Second Item
Item second = wrapper.read(Type.ITEM1_13);
wrapper.write(Type.ITEM1_8, protocol.getItemRewriter().handleItemToClient(second));
}
wrapper.passthrough(Type.BOOLEAN); //Trade disabled
wrapper.passthrough(Type.INT); //Number of tools uses
wrapper.passthrough(Type.INT); //Maximum number of trade uses
}
} else {
String oldChannel = InventoryPackets.getOldPluginChannelId(channel);
if (oldChannel == null) {
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
ViaBackwards.getPlatform().getLogger().warning("Ignoring outgoing plugin message with channel: " + channel);
}
wrapper.cancel();
return;
}
wrapper.write(Type.STRING, oldChannel);
if (oldChannel.equals("REGISTER") || oldChannel.equals("UNREGISTER")) {
String[] channels = new String(wrapper.read(Type.REMAINING_BYTES), StandardCharsets.UTF_8).split("\0");
List<String> rewrittenChannels = new ArrayList<>();
for (String s : channels) {
String rewritten = InventoryPackets.getOldPluginChannelId(s);
if (rewritten != null) {
rewrittenChannels.add(rewritten);
} else if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
ViaBackwards.getPlatform().getLogger().warning("Ignoring plugin channel in outgoing REGISTER: " + s);
}
}
wrapper.write(Type.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8));
}
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(Type.FLOAT); // 2 - X
map(Type.FLOAT); // 3 - Y
map(Type.FLOAT); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
handler(wrapper -> {
ParticleMapping.ParticleData old = ParticleMapping.getMapping(wrapper.get(Type.INT, 0));
wrapper.set(Type.INT, 0, old.getHistoryId());
int[] data = old.rewriteData(protocol, wrapper);
if (data != null) {
if (old.getHandler().isBlockHandler() && data[0] == 0) {
// Cancel air block particles
wrapper.cancel();
return;
}
for (int i : data) {
wrapper.write(Type.VAR_INT, i);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.PLAYER_INFO, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
TabCompleteStorage storage = packetWrapper.user().get(TabCompleteStorage.class);
int action = packetWrapper.passthrough(Type.VAR_INT);
int nPlayers = packetWrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < nPlayers; i++) {
UUID uuid = packetWrapper.passthrough(Type.UUID);
if (action == 0) { // Add
String name = packetWrapper.passthrough(Type.STRING);
storage.usernames().put(uuid, name);
int nProperties = packetWrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < nProperties; j++) {
packetWrapper.passthrough(Type.STRING);
packetWrapper.passthrough(Type.STRING);
packetWrapper.passthrough(Type.OPTIONAL_STRING);
}
packetWrapper.passthrough(Type.VAR_INT);
packetWrapper.passthrough(Type.VAR_INT);
packetWrapper.passthrough(Type.OPTIONAL_COMPONENT);
} else if (action == 1) { // Update Game Mode
packetWrapper.passthrough(Type.VAR_INT);
} else if (action == 2) { // Update Ping
packetWrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update Display Name
packetWrapper.passthrough(Type.OPTIONAL_COMPONENT);
} else if (action == 4) { // Remove Player
storage.usernames().remove(uuid);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.SCOREBOARD_OBJECTIVE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING);
map(Type.BYTE);
handler(wrapper -> {
byte mode = wrapper.get(Type.BYTE, 0);
if (mode == 0 || mode == 2) {
JsonElement value = wrapper.read(Type.COMPONENT);
String legacyValue = protocol.jsonToLegacy(value);
wrapper.write(Type.STRING, ChatUtil.fromLegacy(legacyValue, 'f', 32));
int type = wrapper.read(Type.VAR_INT);
wrapper.write(Type.STRING, type == 1 ? "hearts" : "integer");
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.TEAMS, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Name
map(Type.BYTE); // Action
handler(wrapper -> {
byte action = wrapper.get(Type.BYTE, 0);
if (action == 0 || action == 2) {
JsonElement displayName = wrapper.read(Type.COMPONENT);
String legacyTextDisplayName = protocol.jsonToLegacy(displayName);
wrapper.write(Type.STRING, ChatUtil.fromLegacy(legacyTextDisplayName, 'f', 32));
byte flags = wrapper.read(Type.BYTE);
String nameTagVisibility = wrapper.read(Type.STRING);
String collisionRule = wrapper.read(Type.STRING);
int colour = wrapper.read(Type.VAR_INT);
if (colour == 21) {
colour = -1;
}
JsonElement prefixComponent = wrapper.read(Type.COMPONENT);
JsonElement suffixComponent = wrapper.read(Type.COMPONENT);
String prefix = protocol.jsonToLegacy(prefixComponent);
if (ViaBackwards.getConfig().addTeamColorTo1_13Prefix()) {
prefix += "§" + (colour > -1 && colour <= 15 ? Integer.toHexString(colour) : "r");
}
String suffix = protocol.jsonToLegacy(suffixComponent);
wrapper.write(Type.STRING, ChatUtil.fromLegacyPrefix(prefix, 'f', 16));
wrapper.write(Type.STRING, ChatUtil.fromLegacy(suffix, '\0', 16));
wrapper.write(Type.BYTE, flags);
wrapper.write(Type.STRING, nameTagVisibility);
wrapper.write(Type.STRING, collisionRule);
wrapper.write(Type.BYTE, (byte) colour);
}
if (action == 0 || action == 3 || action == 4) {
wrapper.passthrough(Type.STRING_ARRAY); //Entities
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.DECLARE_COMMANDS, null, wrapper -> {
wrapper.cancel();
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
if (!storage.commands().isEmpty()) {
storage.commands().clear();
}
int size = wrapper.read(Type.VAR_INT);
boolean initialNodes = true;
for (int i = 0; i < size; i++) {
byte flags = wrapper.read(Type.BYTE);
wrapper.read(Type.VAR_INT_ARRAY_PRIMITIVE); // Children indices
if ((flags & 0x08) != 0) {
wrapper.read(Type.VAR_INT); // Redirect node index
}
byte nodeType = (byte) (flags & 0x03);
if (initialNodes && nodeType == 2) {
initialNodes = false;
}
if (nodeType == 1 || nodeType == 2) { // Literal/argument node
String name = wrapper.read(Type.STRING);
if (nodeType == 1 && initialNodes) {
storage.commands().add('/' + name);
}
}
if (nodeType == 2) { // Argument node
commandRewriter.handleArgument(wrapper, wrapper.read(Type.STRING));
}
if ((flags & 0x10) != 0) {
wrapper.read(Type.STRING); // Suggestion type
}
}
});
protocol.registerClientbound(ClientboundPackets1_13.TAB_COMPLETE, wrapper -> {
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
if (storage.lastRequest() == null) {
wrapper.cancel();
return;
}
if (storage.lastId() != wrapper.read(Type.VAR_INT)) wrapper.cancel();
int start = wrapper.read(Type.VAR_INT);
int length = wrapper.read(Type.VAR_INT);
int lastRequestPartIndex = storage.lastRequest().lastIndexOf(' ') + 1;
if (lastRequestPartIndex != start) wrapper.cancel(); // Client only replaces after space
if (length != storage.lastRequest().length() - lastRequestPartIndex) {
wrapper.cancel(); // We can't set the length in previous versions
}
int count = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < count; i++) {
String match = wrapper.read(Type.STRING);
wrapper.write(Type.STRING, (start == 0 && !storage.isLastAssumeCommand() ? "/" : "") + match);
wrapper.read(Type.OPTIONAL_COMPONENT); // Remove tooltip
}
});
protocol.registerServerbound(ServerboundPackets1_12_1.TAB_COMPLETE, wrapper -> {
TabCompleteStorage storage = wrapper.user().get(TabCompleteStorage.class);
List<String> suggestions = new ArrayList<>();
String command = wrapper.read(Type.STRING);
boolean assumeCommand = wrapper.read(Type.BOOLEAN);
wrapper.read(Type.OPTIONAL_POSITION1_8);
if (!assumeCommand && !command.startsWith("/")) {
// Complete usernames for non-commands
String buffer = command.substring(command.lastIndexOf(' ') + 1);
for (String value : storage.usernames().values()) {
if (startsWithIgnoreCase(value, buffer)) {
suggestions.add(value);
}
}
} else if (!storage.commands().isEmpty() && !command.contains(" ")) {
// Complete commands names with values from 'Declare Commands' packet
for (String value : storage.commands()) {
if (startsWithIgnoreCase(value, command)) {
suggestions.add(value);
}
}
}
if (!suggestions.isEmpty()) {
wrapper.cancel();
PacketWrapper response = wrapper.create(ClientboundPackets1_12_1.TAB_COMPLETE);
response.write(Type.VAR_INT, suggestions.size());
for (String value : suggestions) {
response.write(Type.STRING, value);
}
response.scheduleSend(Protocol1_12_2To1_13.class);
storage.setLastRequest(null);
return;
}
if (!assumeCommand && command.startsWith("/")) {
command = command.substring(1);
}
int id = ThreadLocalRandom.current().nextInt();
wrapper.write(Type.VAR_INT, id);
wrapper.write(Type.STRING, command);
storage.setLastId(id);
storage.setLastAssumeCommand(assumeCommand);
storage.setLastRequest(command);
});
protocol.registerServerbound(ServerboundPackets1_12_1.PLUGIN_MESSAGE, wrapper -> {
String channel = wrapper.read(Type.STRING);
switch (channel) {
case "MC|BSign":
case "MC|BEdit":
wrapper.setPacketType(ServerboundPackets1_13.EDIT_BOOK);
Item book = wrapper.read(Type.ITEM1_8);
wrapper.write(Type.ITEM1_13, protocol.getItemRewriter().handleItemToServer(book));
boolean signing = channel.equals("MC|BSign");
wrapper.write(Type.BOOLEAN, signing);
break;
case "MC|ItemName":
wrapper.setPacketType(ServerboundPackets1_13.RENAME_ITEM);
break;
case "MC|AdvCmd":
byte type = wrapper.read(Type.BYTE);
if (type == 0) {
//Information from https://wiki.vg/index.php?title=Plugin_channels&oldid=14089
//The Notchain client only uses this for command block minecarts and uses MC|AutoCmd for blocks, but the Notchian server still accepts it for either.
//Maybe older versions used this and we need to implement this? The issue is that we would have to save the command block types
wrapper.setPacketType(ServerboundPackets1_13.UPDATE_COMMAND_BLOCK);
wrapper.cancel();
ViaBackwards.getPlatform().getLogger().warning("Client send MC|AdvCmd custom payload to update command block, weird!");
} else if (type == 1) {
wrapper.setPacketType(ServerboundPackets1_13.UPDATE_COMMAND_BLOCK_MINECART);
wrapper.write(Type.VAR_INT, wrapper.read(Type.INT)); //Entity Id
wrapper.passthrough(Type.STRING); //Command
wrapper.passthrough(Type.BOOLEAN); //Track Output
} else {
wrapper.cancel();
}
break;
case "MC|AutoCmd": {
wrapper.setPacketType(ServerboundPackets1_13.UPDATE_COMMAND_BLOCK);
int x = wrapper.read(Type.INT);
int y = wrapper.read(Type.INT);
int z = wrapper.read(Type.INT);
wrapper.write(Type.POSITION1_8, new Position(x, (short) y, z));
wrapper.passthrough(Type.STRING); //Command
byte flags = 0;
if (wrapper.read(Type.BOOLEAN)) flags |= 0x01; //Track Output
String mode = wrapper.read(Type.STRING);
int modeId = mode.equals("SEQUENCE") ? 0 : mode.equals("AUTO") ? 1 : 2;
wrapper.write(Type.VAR_INT, modeId);
if (wrapper.read(Type.BOOLEAN)) flags |= 0x02; //Is conditional
if (wrapper.read(Type.BOOLEAN)) flags |= 0x04; //Automatic
wrapper.write(Type.BYTE, flags);
break;
}
case "MC|Struct": {
wrapper.setPacketType(ServerboundPackets1_13.UPDATE_STRUCTURE_BLOCK);
int x = wrapper.read(Type.INT);
int y = wrapper.read(Type.INT);
int z = wrapper.read(Type.INT);
wrapper.write(Type.POSITION1_8, new Position(x, (short) y, z));
wrapper.write(Type.VAR_INT, wrapper.read(Type.BYTE) - 1);
String mode = wrapper.read(Type.STRING);
int modeId = mode.equals("SAVE") ? 0 : mode.equals("LOAD") ? 1 : mode.equals("CORNER") ? 2 : 3;
wrapper.write(Type.VAR_INT, modeId);
wrapper.passthrough(Type.STRING); //Name
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Offset X
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Offset Y
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Offset Z
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Size X
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Size Y
wrapper.write(Type.BYTE, wrapper.read(Type.INT).byteValue()); //Size Z
String mirror = wrapper.read(Type.STRING);
int mirrorId = mode.equals("NONE") ? 0 : mode.equals("LEFT_RIGHT") ? 1 : 2;
String rotation = wrapper.read(Type.STRING);
int rotationId = mode.equals("NONE") ? 0 : mode.equals("CLOCKWISE_90") ? 1 : mode.equals("CLOCKWISE_180") ? 2 : 3;
wrapper.passthrough(Type.STRING); //Metadata
byte flags = 0;
if (wrapper.read(Type.BOOLEAN)) flags |= 0x01; //Ignore entities
if (wrapper.read(Type.BOOLEAN)) flags |= 0x02; //Show air
if (wrapper.read(Type.BOOLEAN)) flags |= 0x04; //Show bounding box
wrapper.passthrough(Type.FLOAT); //Integrity
wrapper.passthrough(Type.VAR_LONG); //Seed
wrapper.write(Type.BYTE, flags);
break;
}
case "MC|Beacon":
wrapper.setPacketType(ServerboundPackets1_13.SET_BEACON_EFFECT);
wrapper.write(Type.VAR_INT, wrapper.read(Type.INT)); //Primary Effect
wrapper.write(Type.VAR_INT, wrapper.read(Type.INT)); //Secondary Effect
break;
case "MC|TrSel":
wrapper.setPacketType(ServerboundPackets1_13.SELECT_TRADE);
wrapper.write(Type.VAR_INT, wrapper.read(Type.INT)); //Slot
break;
case "MC|PickItem":
wrapper.setPacketType(ServerboundPackets1_13.PICK_ITEM);
break;
default:
String newChannel = InventoryPackets.getNewPluginChannelId(channel);
if (newChannel == null) {
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
ViaBackwards.getPlatform().getLogger().warning("Ignoring incoming plugin message with channel: " + channel);
}
wrapper.cancel();
return;
}
wrapper.write(Type.STRING, newChannel);
if (newChannel.equals("minecraft:register") || newChannel.equals("minecraft:unregister")) {
String[] channels = new String(wrapper.read(Type.REMAINING_BYTES), StandardCharsets.UTF_8).split("\0");
List<String> rewrittenChannels = new ArrayList<>();
for (String s : channels) {
String rewritten = InventoryPackets.getNewPluginChannelId(s);
if (rewritten != null) {
rewrittenChannels.add(rewritten);
} else if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
ViaBackwards.getPlatform().getLogger().warning("Ignoring plugin channel in incoming REGISTER: " + s);
}
}
if (!rewrittenChannels.isEmpty()) {
wrapper.write(Type.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8));
} else {
wrapper.cancel();
return;
}
}
break;
}
});
protocol.registerClientbound(ClientboundPackets1_13.STATISTICS, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
handler(wrapper -> {
int size = wrapper.get(Type.VAR_INT, 0);
int newSize = size;
for (int i = 0; i < size; i++) {
int categoryId = wrapper.read(Type.VAR_INT);
int statisticId = wrapper.read(Type.VAR_INT);
String name = "";
// categories 0-7 (items, blocks, entities) - probably not feasible
switch (categoryId) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
wrapper.read(Type.VAR_INT); // remove value
newSize--;
continue;
case 8:
name = protocol.getMappingData().getStatisticMappings().get(statisticId);
if (name == null) {
wrapper.read(Type.VAR_INT);
newSize--;
continue;
}
break;
}
wrapper.write(Type.STRING, name); // string id
wrapper.passthrough(Type.VAR_INT); // value
}
if (newSize != size) {
wrapper.set(Type.VAR_INT, 0, newSize);
}
});
}
});
}
private static boolean startsWithIgnoreCase(String string, String prefix) {
if (string.length() < prefix.length()) {
return false;
}
return string.regionMatches(true, 0, prefix, 0, prefix.length());
}
}
@@ -1,83 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13_1to1_13_2;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.packets.EntityPackets1_13_2;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.packets.InventoryPackets1_13_2;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.packets.WorldPackets1_13_2;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
public class Protocol1_13_1To1_13_2 extends BackwardsProtocol<ClientboundPackets1_13, ClientboundPackets1_13, ServerboundPackets1_13, ServerboundPackets1_13> {
public Protocol1_13_1To1_13_2() {
super(ClientboundPackets1_13.class, ClientboundPackets1_13.class, ServerboundPackets1_13.class, ServerboundPackets1_13.class);
}
@Override
protected void registerPackets() {
InventoryPackets1_13_2.register(this);
WorldPackets1_13_2.register(this);
EntityPackets1_13_2.register(this);
registerServerbound(ServerboundPackets1_13.EDIT_BOOK, new PacketHandlers() {
@Override
public void register() {
map(Type.ITEM1_13, Type.ITEM1_13_2);
}
});
registerClientbound(ClientboundPackets1_13.ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN))
wrapper.passthrough(Type.STRING);
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT); // Title
wrapper.passthrough(Type.COMPONENT); // Description
Item icon = wrapper.read(Type.ITEM1_13_2);
wrapper.write(Type.ITEM1_13, icon);
wrapper.passthrough(Type.VAR_INT); // Frame type
int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0)
wrapper.passthrough(Type.STRING); // Background texture
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
wrapper.passthrough(Type.STRING_ARRAY); // Criteria
int arrayLength = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Type.STRING_ARRAY); // String array
}
}
});
}
}
@@ -1,92 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13_1to1_13_2.packets;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.Protocol1_13_1To1_13_2;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.api.type.types.version.Types1_13_2;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
public class EntityPackets1_13_2 {
public static void register(Protocol1_13_1To1_13_2 protocol) {
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_13_2.METADATA_LIST, Types1_13.METADATA_LIST); // 12 - Metadata
handler(wrapper -> {
for (Metadata metadata : wrapper.get(Types1_13.METADATA_LIST, 0)) {
metadata.setMetaType(Types1_13.META_TYPES.byId(metadata.metaType().typeId()));
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_13_2.METADATA_LIST, Types1_13.METADATA_LIST); // 7 - Metadata
handler(wrapper -> {
for (Metadata metadata : wrapper.get(Types1_13.METADATA_LIST, 0)) {
metadata.setMetaType(Types1_13.META_TYPES.byId(metadata.metaType().typeId()));
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.ENTITY_METADATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Types1_13_2.METADATA_LIST, Types1_13.METADATA_LIST); // 1 - Metadata list
handler(wrapper -> {
for (Metadata metadata : wrapper.get(Types1_13.METADATA_LIST, 0)) {
metadata.setMetaType(Types1_13.META_TYPES.byId(metadata.metaType().typeId()));
}
});
}
});
}
}
@@ -1,136 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13_1to1_13_2.packets;
import com.viaversion.viabackwards.protocol.protocol1_13_1to1_13_2.Protocol1_13_1To1_13_2;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
public class InventoryPackets1_13_2 {
public static void register(Protocol1_13_1To1_13_2 protocol) {
protocol.registerClientbound(ClientboundPackets1_13.SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.SHORT); // 1 - Slot ID
map(Type.ITEM1_13_2, Type.ITEM1_13); // 2 - Slot Value
}
});
protocol.registerClientbound(ClientboundPackets1_13.WINDOW_ITEMS, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.ITEM1_13_2_SHORT_ARRAY, Type.ITEM1_13_SHORT_ARRAY); // 1 - Window Values
}
});
protocol.registerClientbound(ClientboundPackets1_13.PLUGIN_MESSAGE, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Channel
handler(wrapper -> {
String channel = wrapper.get(Type.STRING, 0);
if (channel.equals("minecraft:trader_list") || channel.equals("trader_list")) {
wrapper.passthrough(Type.INT); // Passthrough Window ID
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
// Input Item
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
// Output Item
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
boolean secondItem = wrapper.passthrough(Type.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
}
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.ENTITY_EQUIPMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.VAR_INT); // 1 - Slot ID
map(Type.ITEM1_13_2, Type.ITEM1_13); // 2 - Item
}
});
protocol.registerClientbound(ClientboundPackets1_13.DECLARE_RECIPES, wrapper -> {
int recipesNo = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < recipesNo; i++) {
wrapper.passthrough(Type.STRING); // Id
String type = wrapper.passthrough(Type.STRING);
if (type.equals("crafting_shapeless")) {
wrapper.passthrough(Type.STRING); // Group
int ingredientsNo = wrapper.passthrough(Type.VAR_INT);
for (int i1 = 0; i1 < ingredientsNo; i1++) {
wrapper.write(Type.ITEM1_13_ARRAY, wrapper.read(Type.ITEM1_13_2_ARRAY));
}
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
} else if (type.equals("crafting_shaped")) {
int ingredientsNo = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
for (int i1 = 0; i1 < ingredientsNo; i1++) {
wrapper.write(Type.ITEM1_13_ARRAY, wrapper.read(Type.ITEM1_13_2_ARRAY));
}
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
} else if (type.equals("smelting")) {
wrapper.passthrough(Type.STRING); // Group
// Ingredient start
wrapper.write(Type.ITEM1_13_ARRAY, wrapper.read(Type.ITEM1_13_2_ARRAY));
// Ingredient end
wrapper.write(Type.ITEM1_13, wrapper.read(Type.ITEM1_13_2));
wrapper.passthrough(Type.FLOAT); // EXP
wrapper.passthrough(Type.VAR_INT); // Cooking time
}
}
});
protocol.registerServerbound(ServerboundPackets1_13.CLICK_WINDOW, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.SHORT); // 1 - Slot
map(Type.BYTE); // 2 - Button
map(Type.SHORT); // 3 - Action number
map(Type.VAR_INT); // 4 - Mode
map(Type.ITEM1_13, Type.ITEM1_13_2); // 5 - Clicked Item
}
});
protocol.registerServerbound(ServerboundPackets1_13.CREATIVE_INVENTORY_ACTION, new PacketHandlers() {
@Override
public void register() {
map(Type.SHORT); // 0 - Slot
map(Type.ITEM1_13, Type.ITEM1_13_2); // 1 - Clicked Item
}
});
}
}
@@ -1,506 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13_2to1_14.packets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.entities.storage.EntityData;
import com.viaversion.viabackwards.api.entities.storage.EntityPositionHandler;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.Protocol1_13_2To1_14;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.storage.ChunkLightStorage;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.storage.DifficultyStorage;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.storage.EntityPositionStorage1_14;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.VillagerData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_13_2;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14;
import com.viaversion.viaversion.rewriter.meta.MetaHandler;
public class EntityPackets1_14 extends LegacyEntityRewriter<ClientboundPackets1_14, Protocol1_13_2To1_14> {
private EntityPositionHandler positionHandler;
public EntityPackets1_14(Protocol1_13_2To1_14 protocol) {
super(protocol, Types1_13_2.META_TYPES.optionalComponentType, Types1_13_2.META_TYPES.booleanType);
}
//TODO work the method into this class alone
@Override
protected void addTrackedEntity(PacketWrapper wrapper, int entityId, EntityType type) throws Exception {
super.addTrackedEntity(wrapper, entityId, type);
// Cache the position for every newly tracked entity
if (type == EntityTypes1_14.PAINTING) {
final Position position = wrapper.get(Type.POSITION1_8, 0);
positionHandler.cacheEntityPosition(wrapper, position.x(), position.y(), position.z(), true, false);
} else if (wrapper.getId() != ClientboundPackets1_14.JOIN_GAME.getId()) { // ignore join game
positionHandler.cacheEntityPosition(wrapper, true, false);
}
}
@Override
protected void registerPackets() {
positionHandler = new EntityPositionHandler(this, EntityPositionStorage1_14.class, EntityPositionStorage1_14::new);
protocol.registerClientbound(ClientboundPackets1_14.ENTITY_STATUS, wrapper -> {
int entityId = wrapper.passthrough(Type.INT);
byte status = wrapper.passthrough(Type.BYTE);
// Check for death status
if (status != 3) return;
EntityTracker tracker = tracker(wrapper.user());
EntityType entityType = tracker.entityType(entityId);
if (entityType != EntityTypes1_14.PLAYER) return;
// Remove equipment, else the client will see ghost items
for (int i = 0; i <= 5; i++) {
PacketWrapper equipmentPacket = wrapper.create(ClientboundPackets1_13.ENTITY_EQUIPMENT);
equipmentPacket.write(Type.VAR_INT, entityId);
equipmentPacket.write(Type.VAR_INT, i);
equipmentPacket.write(Type.ITEM1_13_2, null);
equipmentPacket.send(Protocol1_13_2To1_14.class);
}
});
protocol.registerClientbound(ClientboundPackets1_14.ENTITY_TELEPORT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
handler(wrapper -> positionHandler.cacheEntityPosition(wrapper, false, false));
}
});
PacketHandlers relativeMoveHandler = new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.SHORT);
map(Type.SHORT);
map(Type.SHORT);
handler(wrapper -> {
double x = wrapper.get(Type.SHORT, 0) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
double y = wrapper.get(Type.SHORT, 1) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
double z = wrapper.get(Type.SHORT, 2) / EntityPositionHandler.RELATIVE_MOVE_FACTOR;
positionHandler.cacheEntityPosition(wrapper, x, y, z, false, true);
});
}
};
protocol.registerClientbound(ClientboundPackets1_14.ENTITY_POSITION, relativeMoveHandler);
protocol.registerClientbound(ClientboundPackets1_14.ENTITY_POSITION_AND_ROTATION, relativeMoveHandler);
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.VAR_INT, Type.BYTE); // 2 - Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - Data
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
handler(getObjectTrackerHandler());
handler(wrapper -> {
int id = wrapper.get(Type.BYTE, 0);
int mappedId = newEntityId(id);
EntityTypes1_13.EntityType entityType = EntityTypes1_13.getTypeFromId(mappedId, false);
EntityTypes1_13.ObjectType objectType;
if (entityType.isOrHasParent(EntityTypes1_13.EntityType.MINECART_ABSTRACT)) {
objectType = EntityTypes1_13.ObjectType.MINECART;
int data = 0;
switch (entityType) {
case CHEST_MINECART:
data = 1;
break;
case FURNACE_MINECART:
data = 2;
break;
case TNT_MINECART:
data = 3;
break;
case SPAWNER_MINECART:
data = 4;
break;
case HOPPER_MINECART:
data = 5;
break;
case COMMAND_BLOCK_MINECART:
data = 6;
break;
}
if (data != 0)
wrapper.set(Type.INT, 0, data);
} else {
objectType = EntityTypes1_13.ObjectType.fromEntityType(entityType).orElse(null);
}
if (objectType == null) return;
wrapper.set(Type.BYTE, 0, (byte) objectType.getId());
int data = wrapper.get(Type.INT, 0);
if (objectType == EntityTypes1_13.ObjectType.FALLING_BLOCK) {
int blockState = wrapper.get(Type.INT, 0);
int combined = protocol.getMappingData().getNewBlockStateId(blockState);
wrapper.set(Type.INT, 0, combined);
} else if (entityType.isOrHasParent(EntityTypes1_13.EntityType.ABSTRACT_ARROW)) {
wrapper.set(Type.INT, 0, data + 1);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_14.METADATA_LIST, Types1_13_2.METADATA_LIST); // 12 - Metadata
handler(wrapper -> {
int type = wrapper.get(Type.VAR_INT, 1);
EntityType entityType = EntityTypes1_14.getTypeFromId(type);
addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), entityType);
int oldId = newEntityId(type);
if (oldId == -1) {
EntityData entityData = entityDataForType(entityType);
if (entityData == null) {
ViaBackwards.getPlatform().getLogger().warning("Could not find 1.13.2 entity type for 1.14 entity type " + type + "/" + entityType);
wrapper.cancel();
} else {
wrapper.set(Type.VAR_INT, 1, entityData.replacementId());
}
} else {
wrapper.set(Type.VAR_INT, 1, oldId);
}
});
// Handle entity type & metadata
handler(getMobSpawnRewriter(Types1_13_2.METADATA_LIST));
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_EXPERIENCE_ORB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.DOUBLE); // Needs to be mapped for the position cache
map(Type.DOUBLE);
map(Type.DOUBLE);
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), EntityTypes1_14.EXPERIENCE_ORB));
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_GLOBAL_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.BYTE);
map(Type.DOUBLE); // Needs to be mapped for the position cache
map(Type.DOUBLE);
map(Type.DOUBLE);
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), EntityTypes1_14.LIGHTNING_BOLT));
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_PAINTING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.UUID);
map(Type.VAR_INT);
map(Type.POSITION1_14, Type.POSITION1_8);
map(Type.BYTE);
// Track entity
handler(wrapper -> addTrackedEntity(wrapper, wrapper.get(Type.VAR_INT, 0), EntityTypes1_14.PAINTING));
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_14.METADATA_LIST, Types1_13_2.METADATA_LIST); // 7 - Metadata
handler(getTrackerAndMetaHandler(Types1_13_2.METADATA_LIST, EntityTypes1_14.PLAYER));
handler(wrapper -> positionHandler.cacheEntityPosition(wrapper, true, false));
}
});
registerRemoveEntities(ClientboundPackets1_14.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_14.ENTITY_METADATA, Types1_14.METADATA_LIST, Types1_13_2.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_14.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
handler(getTrackerHandler(EntityTypes1_14.PLAYER, Type.INT));
handler(getDimensionHandler(1));
handler(wrapper -> {
short difficulty = wrapper.user().get(DifficultyStorage.class).getDifficulty();
wrapper.write(Type.UNSIGNED_BYTE, difficulty);
wrapper.passthrough(Type.UNSIGNED_BYTE); // Max Players
wrapper.passthrough(Type.STRING); // Level Type
wrapper.read(Type.VAR_INT); // Read View Distance
//TODO Track client position
// Manually add position storage
/*int entitiyId = wrapper.get(Type.INT, 0);
StoredEntityData storedEntity = protocol.getEntityRewriter().tracker(wrapper.user()).entityData(entitiyId);
storedEntity.put(new EntityPositionStorage1_14());*/
});
}
});
protocol.registerClientbound(ClientboundPackets1_14.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 0);
clientWorld.setEnvironment(dimensionId);
short difficulty = wrapper.user().get(DifficultyStorage.class).getDifficulty();
wrapper.write(Type.UNSIGNED_BYTE, difficulty);
wrapper.user().get(ChunkLightStorage.class).clear();
});
}
});
}
@Override
protected void registerRewrites() {
mapTypes(EntityTypes1_14.values(), EntityTypes1_13.EntityType.class);
mapEntityTypeWithData(EntityTypes1_14.CAT, EntityTypes1_14.OCELOT).jsonName();
mapEntityTypeWithData(EntityTypes1_14.TRADER_LLAMA, EntityTypes1_14.LLAMA).jsonName();
mapEntityTypeWithData(EntityTypes1_14.FOX, EntityTypes1_14.WOLF).jsonName();
mapEntityTypeWithData(EntityTypes1_14.PANDA, EntityTypes1_14.POLAR_BEAR).jsonName();
mapEntityTypeWithData(EntityTypes1_14.PILLAGER, EntityTypes1_14.VILLAGER).jsonName();
mapEntityTypeWithData(EntityTypes1_14.WANDERING_TRADER, EntityTypes1_14.VILLAGER).jsonName();
mapEntityTypeWithData(EntityTypes1_14.RAVAGER, EntityTypes1_14.COW).jsonName();
filter().handler((event, meta) -> {
int typeId = meta.metaType().typeId();
if (typeId <= 15) {
meta.setMetaType(Types1_13_2.META_TYPES.byId(typeId));
}
});
registerMetaTypeHandler(Types1_13_2.META_TYPES.itemType, Types1_13_2.META_TYPES.blockStateType, null, null,
Types1_13_2.META_TYPES.componentType, Types1_13_2.META_TYPES.optionalComponentType);
filter().type(EntityTypes1_14.PILLAGER).cancel(15);
filter().type(EntityTypes1_14.FOX).cancel(15);
filter().type(EntityTypes1_14.FOX).cancel(16);
filter().type(EntityTypes1_14.FOX).cancel(17);
filter().type(EntityTypes1_14.FOX).cancel(18);
filter().type(EntityTypes1_14.PANDA).cancel(15);
filter().type(EntityTypes1_14.PANDA).cancel(16);
filter().type(EntityTypes1_14.PANDA).cancel(17);
filter().type(EntityTypes1_14.PANDA).cancel(18);
filter().type(EntityTypes1_14.PANDA).cancel(19);
filter().type(EntityTypes1_14.PANDA).cancel(20);
filter().type(EntityTypes1_14.CAT).cancel(18);
filter().type(EntityTypes1_14.CAT).cancel(19);
filter().type(EntityTypes1_14.CAT).cancel(20);
filter().handler((event, meta) -> {
EntityType type = event.entityType();
if (type == null) return;
if (type.isOrHasParent(EntityTypes1_14.ABSTRACT_ILLAGER_BASE) || type == EntityTypes1_14.RAVAGER || type == EntityTypes1_14.WITCH) {
int index = event.index();
if (index == 14) {
event.cancel();
} else if (index > 14) {
event.setIndex(index - 1);
}
}
});
filter().type(EntityTypes1_14.AREA_EFFECT_CLOUD).index(10).handler((event, meta) -> {
rewriteParticle((Particle) meta.getValue());
});
filter().type(EntityTypes1_14.FIREWORK_ROCKET).index(8).handler((event, meta) -> {
meta.setMetaType(Types1_13_2.META_TYPES.varIntType);
Integer value = (Integer) meta.getValue();
if (value == null) {
meta.setValue(0);
}
});
filter().type(EntityTypes1_14.ABSTRACT_ARROW).removeIndex(9);
filter().type(EntityTypes1_14.VILLAGER).cancel(15); // Head shake timer
MetaHandler villagerDataHandler = (event, meta) -> {
VillagerData villagerData = (VillagerData) meta.getValue();
meta.setTypeAndValue(Types1_13_2.META_TYPES.varIntType, villagerDataToProfession(villagerData));
if (meta.id() == 16) {
event.setIndex(15); // decreased by 2 again in one of the following handlers
}
};
filter().type(EntityTypes1_14.ZOMBIE_VILLAGER).index(18).handler(villagerDataHandler);
filter().type(EntityTypes1_14.VILLAGER).index(16).handler(villagerDataHandler);
// Holding arms up - from bitfield into own boolean
filter().type(EntityTypes1_14.ABSTRACT_SKELETON).index(13).handler((event, meta) -> {
byte value = (byte) meta.getValue();
if ((value & 4) != 0) {
event.createExtraMeta(new Metadata(14, Types1_13_2.META_TYPES.booleanType, true));
}
});
filter().type(EntityTypes1_14.ZOMBIE).index(13).handler((event, meta) -> {
byte value = (byte) meta.getValue();
if ((value & 4) != 0) {
event.createExtraMeta(new Metadata(16, Types1_13_2.META_TYPES.booleanType, true));
}
});
filter().type(EntityTypes1_14.ZOMBIE).addIndex(16);
// Remove bed location
filter().type(EntityTypes1_14.LIVINGENTITY).handler((event, meta) -> {
int index = event.index();
if (index == 12) {
Position position = (Position) meta.getValue();
if (position != null) {
// Use bed
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_13.USE_BED, null, event.user());
wrapper.write(Type.VAR_INT, event.entityId());
wrapper.write(Type.POSITION1_8, position);
try {
wrapper.scheduleSend(Protocol1_13_2To1_14.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
event.cancel();
} else if (index > 12) {
event.setIndex(index - 1);
}
});
// Pose
filter().removeIndex(6);
filter().type(EntityTypes1_14.OCELOT).index(13).handler((event, meta) -> {
event.setIndex(15);
meta.setTypeAndValue(Types1_13_2.META_TYPES.varIntType, 0);
});
filter().type(EntityTypes1_14.CAT).handler((event, meta) -> {
if (event.index() == 15) {
meta.setValue(1);
} else if (event.index() == 13) {
meta.setValue((byte) ((byte) meta.getValue() & 0x4));
}
});
filter().handler((event, meta) -> {
if (meta.metaType().typeId() > 15) {
throw new IllegalArgumentException("Unhandled metadata: " + meta);
}
});
}
public int villagerDataToProfession(VillagerData data) {
switch (data.profession()) {
case 1: // Armorer
case 10: // Mason
case 13: // Toolsmith
case 14: // Weaponsmith
return 3; // Blacksmith
case 2: // Butcher
case 8: // Leatherworker
return 4; // Butcher
case 3: // Cartographer
case 9: // Librarian
return 1; // Librarian
case 4: // Cleric
return 2; // Priest
case 5: // Farmer
case 6: // Fisherman
case 7: // Fletcher
case 12: // Shepherd
return 0; // Farmer
case 0: // None
case 11: // Nitwit
default:
return 5; // Nitwit
}
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_14.getTypeFromId(typeId);
}
}
@@ -1,130 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13_2to1_14.packets;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.Protocol1_13_2To1_14;
import com.viaversion.viabackwards.protocol.protocol1_13_2to1_14.storage.DifficultyStorage;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14;
public class PlayerPackets1_14 extends RewriterBase<Protocol1_13_2To1_14> {
public PlayerPackets1_14(Protocol1_13_2To1_14 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_14.SERVER_DIFFICULTY, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE);
read(Type.BOOLEAN); // Locked
handler(wrapper -> {
byte difficulty = wrapper.get(Type.UNSIGNED_BYTE, 0).byteValue();
wrapper.user().get(DifficultyStorage.class).setDifficulty(difficulty);
});
}
});
protocol.registerClientbound(ClientboundPackets1_14.OPEN_SIGN_EDITOR, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_14, Type.POSITION1_8);
}
});
protocol.registerServerbound(ServerboundPackets1_13.QUERY_BLOCK_NBT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.POSITION1_8, Type.POSITION1_14);
}
});
protocol.registerServerbound(ServerboundPackets1_13.PLAYER_DIGGING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Action
map(Type.POSITION1_8, Type.POSITION1_14); // Position
}
});
protocol.registerServerbound(ServerboundPackets1_13.RECIPE_BOOK_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
handler(wrapper -> {
int type = wrapper.get(Type.VAR_INT, 0);
if (type == 0) {
wrapper.passthrough(Type.STRING);
} else if (type == 1) {
wrapper.passthrough(Type.BOOLEAN); // Crafting Recipe Book Open
wrapper.passthrough(Type.BOOLEAN); // Crafting Recipe Filter Active
wrapper.passthrough(Type.BOOLEAN); // Smelting Recipe Book Open
wrapper.passthrough(Type.BOOLEAN); // Smelting Recipe Filter Active
// Blast furnace/smoker data
wrapper.write(Type.BOOLEAN, false);
wrapper.write(Type.BOOLEAN, false);
wrapper.write(Type.BOOLEAN, false);
wrapper.write(Type.BOOLEAN, false);
}
});
}
});
protocol.registerServerbound(ServerboundPackets1_13.UPDATE_COMMAND_BLOCK, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Type.POSITION1_14);
}
});
protocol.registerServerbound(ServerboundPackets1_13.UPDATE_STRUCTURE_BLOCK, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Type.POSITION1_14);
}
});
protocol.registerServerbound(ServerboundPackets1_13.UPDATE_SIGN, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_8, Type.POSITION1_14);
}
});
protocol.registerServerbound(ServerboundPackets1_13.PLAYER_BLOCK_PLACEMENT, wrapper -> {
Position position = wrapper.read(Type.POSITION1_8);
int face = wrapper.read(Type.VAR_INT);
int hand = wrapper.read(Type.VAR_INT);
float x = wrapper.read(Type.FLOAT);
float y = wrapper.read(Type.FLOAT);
float z = wrapper.read(Type.FLOAT);
wrapper.write(Type.VAR_INT, hand);
wrapper.write(Type.POSITION1_14, position);
wrapper.write(Type.VAR_INT, face);
wrapper.write(Type.FLOAT, x);
wrapper.write(Type.FLOAT, y);
wrapper.write(Type.FLOAT, z);
wrapper.write(Type.BOOLEAN, false); // Inside block
});
}
}
@@ -1,174 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13to1_13_1.packets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import java.util.List;
public class EntityPackets1_13_1 extends LegacyEntityRewriter<ClientboundPackets1_13, Protocol1_13To1_13_1> {
public EntityPackets1_13_1(Protocol1_13To1_13_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.BYTE); // 2 - Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - Data
handler(wrapper -> {
int entityId = wrapper.get(Type.VAR_INT, 0);
byte type = wrapper.get(Type.BYTE, 0);
EntityTypes1_13.EntityType entType = EntityTypes1_13.getTypeFromId(type, true);
if (entType == null) {
ViaBackwards.getPlatform().getLogger().warning("Could not find 1.13 entity type " + type);
return;
}
// Rewrite falling block
if (entType.is(EntityTypes1_13.EntityType.FALLING_BLOCK)) {
int data = wrapper.get(Type.INT, 0);
wrapper.set(Type.INT, 0, protocol.getMappingData().getNewBlockStateId(data));
}
// Track Entity
tracker(wrapper.user()).addEntity(entityId, entType);
});
}
});
registerTracker(ClientboundPackets1_13.SPAWN_EXPERIENCE_ORB, EntityTypes1_13.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_13.SPAWN_GLOBAL_ENTITY, EntityTypes1_13.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_13.METADATA_LIST); // 12 - Metadata
// Track Entity
handler(getTrackerHandler());
// Rewrite Metadata
handler(wrapper -> {
List<Metadata> metadata = wrapper.get(Types1_13.METADATA_LIST, 0);
handleMetadata(wrapper.get(Type.VAR_INT, 0), metadata, wrapper.user());
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Types1_13.METADATA_LIST); // 7 - Metadata
handler(getTrackerAndMetaHandler(Types1_13.METADATA_LIST, EntityTypes1_13.EntityType.PLAYER));
}
});
registerTracker(ClientboundPackets1_13.SPAWN_PAINTING, EntityTypes1_13.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_13.JOIN_GAME, EntityTypes1_13.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_13.RESPAWN);
registerRemoveEntities(ClientboundPackets1_13.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_13.ENTITY_METADATA, Types1_13.METADATA_LIST);
}
@Override
protected void registerRewrites() {
// Rewrite items & blocks
filter().handler((event, meta) -> {
if (meta.metaType() == Types1_13.META_TYPES.itemType) {
protocol.getItemRewriter().handleItemToClient((Item) meta.getValue());
} else if (meta.metaType() == Types1_13.META_TYPES.blockStateType) {
// Convert to new block id
int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
} else if (meta.metaType() == Types1_13.META_TYPES.particleType) {
rewriteParticle((Particle) meta.getValue());
} else if (meta.metaType() == Types1_13.META_TYPES.optionalComponentType || meta.metaType() == Types1_13.META_TYPES.componentType) {
JsonElement element = meta.value();
protocol.translatableRewriter().processText(element);
}
});
// Remove shooter UUID
filter().type(EntityTypes1_13.EntityType.ABSTRACT_ARROW).cancel(7);
// Move colors to old position
filter().type(EntityTypes1_13.EntityType.SPECTRAL_ARROW).index(8).toIndex(7);
// Move loyalty level to old position
filter().type(EntityTypes1_13.EntityType.TRIDENT).index(8).toIndex(7);
// Rewrite Minecart blocks
filter().type(EntityTypes1_13.EntityType.MINECART_ABSTRACT).index(9).handler((event, meta) -> {
int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_13.getTypeFromId(typeId, false);
}
@Override
protected EntityType getObjectTypeFromId(final int typeId) {
return EntityTypes1_13.getTypeFromId(typeId, true);
}
}
@@ -1,73 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13to1_13_1.packets;
import com.viaversion.viabackwards.protocol.protocol1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13;
import com.viaversion.viaversion.rewriter.ItemRewriter;
public class InventoryPackets1_13_1 extends ItemRewriter<ClientboundPackets1_13, ServerboundPackets1_13, Protocol1_13To1_13_1> {
public InventoryPackets1_13_1(Protocol1_13To1_13_1 protocol) {
super(protocol, Type.ITEM1_13, Type.ITEM1_13_SHORT_ARRAY);
}
@Override
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_13.COOLDOWN);
registerWindowItems(ClientboundPackets1_13.WINDOW_ITEMS);
registerSetSlot(ClientboundPackets1_13.SET_SLOT);
protocol.registerClientbound(ClientboundPackets1_13.PLUGIN_MESSAGE, wrapper -> {
String channel = wrapper.passthrough(Type.STRING);
if (channel.equals("minecraft:trader_list")) {
wrapper.passthrough(Type.INT); //Passthrough Window ID
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
//Input Item
Item input = wrapper.passthrough(Type.ITEM1_13);
handleItemToClient(input);
//Output Item
Item output = wrapper.passthrough(Type.ITEM1_13);
handleItemToClient(output);
boolean secondItem = wrapper.passthrough(Type.BOOLEAN); //Has second item
if (secondItem) {
//Second Item
Item second = wrapper.passthrough(Type.ITEM1_13);
handleItemToClient(second);
}
wrapper.passthrough(Type.BOOLEAN); //Trade disabled
wrapper.passthrough(Type.INT); //Number of tools uses
wrapper.passthrough(Type.INT); //Maximum number of trade uses
}
}
});
registerEntityEquipment(ClientboundPackets1_13.ENTITY_EQUIPMENT);
registerClickWindow(ServerboundPackets1_13.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_13.CREATIVE_INVENTORY_ACTION);
registerSpawnParticle(ClientboundPackets1_13.SPAWN_PARTICLE, Type.FLOAT);
}
}
@@ -1,100 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_13to1_13_1.packets;
import com.viaversion.viabackwards.protocol.protocol1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.api.minecraft.BlockFace;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.rewriter.BlockRewriter;
public class WorldPackets1_13_1 {
public static void register(Protocol1_13To1_13_1 protocol) {
BlockRewriter<ClientboundPackets1_13> blockRewriter = BlockRewriter.legacy(protocol);
protocol.registerClientbound(ClientboundPackets1_13.CHUNK_DATA, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
Chunk chunk = wrapper.passthrough(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
for (ChunkSection section : chunk.getSections()) {
if (section == null) {
continue;
}
DataPalette palette = section.palette(PaletteType.BLOCKS);
for (int i = 0; i < palette.size(); i++) {
int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(palette.idByIndex(i));
palette.setIdByIndex(i, mappedBlockStateId);
}
}
});
blockRewriter.registerBlockAction(ClientboundPackets1_13.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_13.BLOCK_CHANGE);
blockRewriter.registerMultiBlockChange(ClientboundPackets1_13.MULTI_BLOCK_CHANGE);
protocol.registerClientbound(ClientboundPackets1_13.EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Effect Id
map(Type.POSITION1_8); // Location
map(Type.INT); // Data
handler(wrapper -> {
int id = wrapper.get(Type.INT, 0);
int data = wrapper.get(Type.INT, 1);
if (id == 1010) { // Play record
wrapper.set(Type.INT, 1, protocol.getMappingData().getNewItemId(data));
} else if (id == 2001) { // Block break + block break sound
wrapper.set(Type.INT, 1, protocol.getMappingData().getNewBlockStateId(data));
} else if (id == 2000) { // Smoke
switch (data) {
case 0: // Down
case 1: // Up
Position pos = wrapper.get(Type.POSITION1_8, 0);
BlockFace relative = data == 0 ? BlockFace.BOTTOM : BlockFace.TOP;
wrapper.set(Type.POSITION1_8, 0, pos.getRelative(relative)); // Y Offset
wrapper.set(Type.INT, 1, 4); // Self
break;
case 2: // North
wrapper.set(Type.INT, 1, 1); // North
break;
case 3: // South
wrapper.set(Type.INT, 1, 7); // South
break;
case 4: // West
wrapper.set(Type.INT, 1, 3); // West
break;
case 5: // East
wrapper.set(Type.INT, 1, 5); // East
break;
}
}
});
}
});
}
}
@@ -1,137 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_14_4to1_15.packets;
import com.viaversion.viabackwards.protocol.protocol1_14_4to1_15.Protocol1_14_4To1_15;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_14;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_15;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
public class BlockItemPackets1_15 extends com.viaversion.viabackwards.api.rewriters.ItemRewriter<ClientboundPackets1_15, ServerboundPackets1_14, Protocol1_14_4To1_15> {
public BlockItemPackets1_15(Protocol1_14_4To1_15 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_SHORT_ARRAY);
}
@Override
protected void registerPackets() {
BlockRewriter<ClientboundPackets1_15> blockRewriter = BlockRewriter.for1_14(protocol);
new RecipeRewriter<>(protocol).register(ClientboundPackets1_15.DECLARE_RECIPES);
protocol.registerServerbound(ServerboundPackets1_14.EDIT_BOOK, wrapper -> handleItemToServer(wrapper.passthrough(Type.ITEM1_13_2)));
registerSetCooldown(ClientboundPackets1_15.COOLDOWN);
registerWindowItems(ClientboundPackets1_15.WINDOW_ITEMS);
registerSetSlot(ClientboundPackets1_15.SET_SLOT);
registerTradeList(ClientboundPackets1_15.TRADE_LIST);
registerEntityEquipment(ClientboundPackets1_15.ENTITY_EQUIPMENT);
registerAdvancements(ClientboundPackets1_15.ADVANCEMENTS);
registerClickWindow(ServerboundPackets1_14.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_14.CREATIVE_INVENTORY_ACTION);
blockRewriter.registerAcknowledgePlayerDigging(ClientboundPackets1_15.ACKNOWLEDGE_PLAYER_DIGGING);
blockRewriter.registerBlockAction(ClientboundPackets1_15.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_15.BLOCK_CHANGE);
blockRewriter.registerMultiBlockChange(ClientboundPackets1_15.MULTI_BLOCK_CHANGE);
protocol.registerClientbound(ClientboundPackets1_15.CHUNK_DATA, wrapper -> {
Chunk chunk = wrapper.read(ChunkType1_15.TYPE);
wrapper.write(ChunkType1_14.TYPE, chunk);
if (chunk.isFullChunk()) {
int[] biomeData = chunk.getBiomeData();
int[] newBiomeData = new int[256];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
int x = j << 2;
int z = i << 2;
int newIndex = z << 4 | x;
int oldIndex = i << 2 | j;
int biome = biomeData[oldIndex];
for (int k = 0; k < 4; k++) {
int offX = newIndex + (k << 4);
for (int l = 0; l < 4; l++) {
newBiomeData[offX + l] = biome;
}
}
}
}
chunk.setBiomeData(newBiomeData);
}
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) {
continue;
}
DataPalette palette = section.palette(PaletteType.BLOCKS);
for (int j = 0; j < palette.size(); j++) {
int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(palette.idByIndex(j));
palette.setIdByIndex(j, mappedBlockStateId);
}
}
});
blockRewriter.registerEffect(ClientboundPackets1_15.EFFECT, 1010, 2001);
protocol.registerClientbound(ClientboundPackets1_15.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(Type.DOUBLE, Type.FLOAT); // 2 - X
map(Type.DOUBLE, Type.FLOAT); // 3 - Y
map(Type.DOUBLE, Type.FLOAT); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
handler(wrapper -> {
int id = wrapper.get(Type.INT, 0);
if (id == 3 || id == 23) {
int data = wrapper.passthrough(Type.VAR_INT);
wrapper.set(Type.VAR_INT, 0, protocol.getMappingData().getNewBlockStateId(data));
} else if (id == 32) {
Item item = handleItemToClient(wrapper.read(Type.ITEM1_13_2));
wrapper.write(Type.ITEM1_13_2, item);
}
int mappedId = protocol.getMappingData().getNewParticleId(id);
if (id != mappedId) {
wrapper.set(Type.INT, 0, mappedId);
}
});
}
});
}
}
@@ -1,227 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_14_4to1_15.packets;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_14_4to1_15.Protocol1_14_4To1_15;
import com.viaversion.viabackwards.protocol.protocol1_14_4to1_15.data.EntityTypeMapping;
import com.viaversion.viabackwards.protocol.protocol1_14_4to1_15.data.ImmediateRespawn;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_15;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
import java.util.ArrayList;
public class EntityPackets1_15 extends EntityRewriter<ClientboundPackets1_15, Protocol1_14_4To1_15> {
public EntityPackets1_15(Protocol1_14_4To1_15 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_15.UPDATE_HEALTH, wrapper -> {
float health = wrapper.passthrough(Type.FLOAT);
if (health > 0) return;
if (!wrapper.user().get(ImmediateRespawn.class).isImmediateRespawn()) return;
// Instantly request respawn when 1.15 gamerule is set
PacketWrapper statusPacket = wrapper.create(ServerboundPackets1_14.CLIENT_STATUS);
statusPacket.write(Type.VAR_INT, 0);
statusPacket.sendToServer(Protocol1_14_4To1_15.class);
});
protocol.registerClientbound(ClientboundPackets1_15.GAME_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE);
map(Type.FLOAT);
handler(wrapper -> {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 11) {
wrapper.user().get(ImmediateRespawn.class).setImmediateRespawn(wrapper.get(Type.FLOAT, 0) == 1);
}
});
}
});
registerTrackerWithData(ClientboundPackets1_15.SPAWN_ENTITY, EntityTypes1_15.FALLING_BLOCK);
protocol.registerClientbound(ClientboundPackets1_15.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
handler(wrapper -> wrapper.write(Types1_14.METADATA_LIST, new ArrayList<>())); // Metadata is no longer sent in 1.15, so we have to send an empty one
handler(wrapper -> {
int type = wrapper.get(Type.VAR_INT, 1);
EntityType entityType = EntityTypes1_15.getTypeFromId(type);
tracker(wrapper.user()).addEntity(wrapper.get(Type.VAR_INT, 0), entityType);
wrapper.set(Type.VAR_INT, 1, EntityTypeMapping.getOldEntityId(type));
});
}
});
protocol.registerClientbound(ClientboundPackets1_15.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.INT);
read(Type.LONG); // Seed
}
});
protocol.registerClientbound(ClientboundPackets1_15.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
read(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // 3 - Max Players
map(Type.STRING); // 4 - Level Type
map(Type.VAR_INT); // 5 - View Distance
map(Type.BOOLEAN); // 6 - Reduce Debug Info
handler(getTrackerHandler(EntityTypes1_15.PLAYER, Type.INT));
handler(wrapper -> {
boolean immediateRespawn = !wrapper.read(Type.BOOLEAN); // Inverted
wrapper.user().get(ImmediateRespawn.class).setImmediateRespawn(immediateRespawn);
});
}
});
registerTracker(ClientboundPackets1_15.SPAWN_EXPERIENCE_ORB, EntityTypes1_15.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_15.SPAWN_GLOBAL_ENTITY, EntityTypes1_15.LIGHTNING_BOLT);
registerTracker(ClientboundPackets1_15.SPAWN_PAINTING, EntityTypes1_15.PAINTING);
protocol.registerClientbound(ClientboundPackets1_15.SPAWN_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
handler(wrapper -> wrapper.write(Types1_14.METADATA_LIST, new ArrayList<>())); // Metadata is no longer sent in 1.15, so we have to send an empty one
handler(getTrackerHandler(EntityTypes1_15.PLAYER, Type.VAR_INT));
}
});
registerRemoveEntities(ClientboundPackets1_15.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_15.ENTITY_METADATA, Types1_14.METADATA_LIST);
// Attributes (get rid of generic.flyingSpeed for the Bee remap)
protocol.registerClientbound(ClientboundPackets1_15.ENTITY_PROPERTIES, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT);
map(Type.INT);
handler(wrapper -> {
int entityId = wrapper.get(Type.VAR_INT, 0);
EntityType entityType = tracker(wrapper.user()).entityType(entityId);
if (entityType != EntityTypes1_15.BEE) return;
int size = wrapper.get(Type.INT, 0);
int newSize = size;
for (int i = 0; i < size; i++) {
String key = wrapper.read(Type.STRING);
if (key.equals("generic.flyingSpeed")) {
newSize--;
wrapper.read(Type.DOUBLE);
int modSize = wrapper.read(Type.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.read(Type.UUID);
wrapper.read(Type.DOUBLE);
wrapper.read(Type.BYTE);
}
} else {
wrapper.write(Type.STRING, key);
wrapper.passthrough(Type.DOUBLE);
int modSize = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.passthrough(Type.UUID);
wrapper.passthrough(Type.DOUBLE);
wrapper.passthrough(Type.BYTE);
}
}
}
if (newSize != size) {
wrapper.set(Type.INT, 0, newSize);
}
});
}
});
}
@Override
protected void registerRewrites() {
registerMetaTypeHandler(Types1_14.META_TYPES.itemType, Types1_14.META_TYPES.blockStateType, null, Types1_14.META_TYPES.particleType,
Types1_14.META_TYPES.componentType, Types1_14.META_TYPES.optionalComponentType);
filter().type(EntityTypes1_15.LIVINGENTITY).removeIndex(12);
filter().type(EntityTypes1_15.BEE).cancel(15);
filter().type(EntityTypes1_15.BEE).cancel(16);
mapEntityTypeWithData(EntityTypes1_15.BEE, EntityTypes1_15.PUFFERFISH).jsonName().spawnMetadata(storage -> {
storage.add(new Metadata(14, Types1_14.META_TYPES.booleanType, false));
storage.add(new Metadata(15, Types1_14.META_TYPES.varIntType, 2));
});
filter().type(EntityTypes1_15.ENDERMAN).cancel(16);
filter().type(EntityTypes1_15.TRIDENT).cancel(10);
// Redundant health removed in 1.15
filter().type(EntityTypes1_15.WOLF).addIndex(17);
filter().type(EntityTypes1_15.WOLF).index(8).handler((event, meta) -> {
event.createExtraMeta(new Metadata(17/*WOLF_HEALTH*/, Types1_14.META_TYPES.floatType, event.meta().value()));
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_15.getTypeFromId(typeId);
}
@Override
public int newEntityId(final int newId) {
return EntityTypeMapping.getOldEntityId(newId);
}
}
@@ -1,102 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_14to1_14_1.packets;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_14to1_14_1.Protocol1_14To1_14_1;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14;
import java.util.List;
public class EntityPackets1_14_1 extends LegacyEntityRewriter<ClientboundPackets1_14, Protocol1_14To1_14_1> {
public EntityPackets1_14_1(Protocol1_14To1_14_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerTracker(ClientboundPackets1_14.SPAWN_EXPERIENCE_ORB, EntityTypes1_14.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_14.SPAWN_GLOBAL_ENTITY, EntityTypes1_14.LIGHTNING_BOLT);
registerTracker(ClientboundPackets1_14.SPAWN_PAINTING, EntityTypes1_14.PAINTING);
registerTracker(ClientboundPackets1_14.SPAWN_PLAYER, EntityTypes1_14.PLAYER);
registerTracker(ClientboundPackets1_14.JOIN_GAME, EntityTypes1_14.PLAYER, Type.INT);
registerRemoveEntities(ClientboundPackets1_14.DESTROY_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.VAR_INT); // 2 - Type
handler(getTrackerHandler());
}
});
protocol.registerClientbound(ClientboundPackets1_14.SPAWN_MOB, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Types1_14.METADATA_LIST); // 12 - Metadata
handler(wrapper -> {
int entityId = wrapper.get(Type.VAR_INT, 0);
int type = wrapper.get(Type.VAR_INT, 1);
// Register Type ID
tracker(wrapper.user()).addEntity(entityId, EntityTypes1_14.getTypeFromId(type));
List<Metadata> metadata = wrapper.get(Types1_14.METADATA_LIST, 0);
handleMetadata(entityId, metadata, wrapper.user());
});
}
});
// Entity Metadata
registerMetadataRewriter(ClientboundPackets1_14.ENTITY_METADATA, Types1_14.METADATA_LIST);
}
@Override
protected void registerRewrites() {
filter().type(EntityTypes1_14.VILLAGER).cancel(15);
filter().type(EntityTypes1_14.VILLAGER).index(16).toIndex(15);
filter().type(EntityTypes1_14.WANDERING_TRADER).cancel(15);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_14.getTypeFromId(typeId);
}
}
@@ -1,195 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_15_2to1_16;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.chat.TranslatableRewriter1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.BackwardsMappings;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.CommandRewriter1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.WorldNameTracker;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.packets.BlockItemPackets1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.packets.EntityPackets1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.storage.PlayerSneakStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ServerboundPackets1_16;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.GsonUtil;
import java.util.UUID;
public class Protocol1_15_2To1_16 extends BackwardsProtocol<ClientboundPackets1_16, ClientboundPackets1_15, ServerboundPackets1_16, ServerboundPackets1_14> {
public static final BackwardsMappings MAPPINGS = new BackwardsMappings();
private final EntityPackets1_16 entityRewriter = new EntityPackets1_16(this);
private final BlockItemPackets1_16 blockItemPackets = new BlockItemPackets1_16(this);
private final TranslatableRewriter1_16 translatableRewriter = new TranslatableRewriter1_16(this);
public Protocol1_15_2To1_16() {
super(ClientboundPackets1_16.class, ClientboundPackets1_15.class, ServerboundPackets1_16.class, ServerboundPackets1_14.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
translatableRewriter.registerBossBar(ClientboundPackets1_16.BOSSBAR);
translatableRewriter.registerCombatEvent(ClientboundPackets1_16.COMBAT_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_16.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_16.TAB_LIST);
translatableRewriter.registerTitle(ClientboundPackets1_16.TITLE);
translatableRewriter.registerPing();
new CommandRewriter1_16(this).registerDeclareCommands(ClientboundPackets1_16.DECLARE_COMMANDS);
registerClientbound(State.STATUS, 0x00, 0x00, wrapper -> {
String original = wrapper.passthrough(Type.STRING);
JsonObject object = GsonUtil.getGson().fromJson(original, JsonObject.class);
JsonElement description = object.get("description");
if (description == null) return;
translatableRewriter.processText(description);
wrapper.set(Type.STRING, 0, object.toString());
});
registerClientbound(ClientboundPackets1_16.CHAT_MESSAGE, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> translatableRewriter.processText(wrapper.passthrough(Type.COMPONENT)));
map(Type.BYTE);
read(Type.UUID); // Sender
}
});
registerClientbound(ClientboundPackets1_16.OPEN_WINDOW, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Window Id
map(Type.VAR_INT); // Window Type
handler(wrapper -> translatableRewriter.processText(wrapper.passthrough(Type.COMPONENT)));
handler(wrapper -> {
int windowType = wrapper.get(Type.VAR_INT, 1);
if (windowType == 20) { // Smithing table
wrapper.set(Type.VAR_INT, 1, 7); // Open anvil inventory
} else if (windowType > 20) {
wrapper.set(Type.VAR_INT, 1, --windowType);
}
});
}
});
SoundRewriter<ClientboundPackets1_16> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound(ClientboundPackets1_16.SOUND);
soundRewriter.registerSound(ClientboundPackets1_16.ENTITY_SOUND);
soundRewriter.registerNamedSound(ClientboundPackets1_16.NAMED_SOUND);
soundRewriter.registerStopSound(ClientboundPackets1_16.STOP_SOUND);
// Login success
registerClientbound(State.LOGIN, 0x02, 0x02, wrapper -> {
// Transform uuid to plain string
UUID uuid = wrapper.read(Type.UUID);
wrapper.write(Type.STRING, uuid.toString());
});
new TagRewriter<>(this).register(ClientboundPackets1_16.TAGS, RegistryType.ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_16.STATISTICS);
registerServerbound(ServerboundPackets1_14.ENTITY_ACTION, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // player id
int action = wrapper.passthrough(Type.VAR_INT);
if (action == 0) {
wrapper.user().get(PlayerSneakStorage.class).setSneaking(true);
} else if (action == 1) {
wrapper.user().get(PlayerSneakStorage.class).setSneaking(false);
}
});
registerServerbound(ServerboundPackets1_14.INTERACT_ENTITY, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Entity Id
int action = wrapper.passthrough(Type.VAR_INT);
if (action == 0 || action == 2) {
if (action == 2) {
// Location
wrapper.passthrough(Type.FLOAT);
wrapper.passthrough(Type.FLOAT);
wrapper.passthrough(Type.FLOAT);
}
wrapper.passthrough(Type.VAR_INT); // Hand
}
// New boolean: Whether the client is sneaking
wrapper.write(Type.BOOLEAN, wrapper.user().get(PlayerSneakStorage.class).isSneaking());
});
registerServerbound(ServerboundPackets1_14.PLAYER_ABILITIES, wrapper -> {
byte flags = wrapper.read(Type.BYTE);
flags &= 2; // Only take the isFlying value (everything else has been removed and wasn't used anyways)
wrapper.write(Type.BYTE, flags);
wrapper.read(Type.FLOAT);
wrapper.read(Type.FLOAT);
});
cancelServerbound(ServerboundPackets1_14.UPDATE_JIGSAW_BLOCK);
}
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.put(new PlayerSneakStorage());
user.put(new WorldNameTracker());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_16.PLAYER));
}
@Override
public TranslatableRewriter1_16 getTranslatableRewriter() {
return translatableRewriter;
}
@Override
public BackwardsMappings getMappingData() {
return MAPPINGS;
}
@Override
public EntityPackets1_16 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPackets1_16 getItemRewriter() {
return blockItemPackets;
}
}
@@ -1,364 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_15_2to1_16.packets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter;
import com.viaversion.viabackwards.api.rewriters.MapColorRewriter;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.MapColorRewrites;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_15;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_16;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.IntArrayTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.LongArrayTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ServerboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.packets.InventoryPackets;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
import com.viaversion.viaversion.util.CompactArrayUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.UUIDUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class BlockItemPackets1_16 extends com.viaversion.viabackwards.api.rewriters.ItemRewriter<ClientboundPackets1_16, ServerboundPackets1_14, Protocol1_15_2To1_16> {
private EnchantmentRewriter enchantmentRewriter;
public BlockItemPackets1_16(Protocol1_15_2To1_16 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_SHORT_ARRAY);
}
@Override
protected void registerPackets() {
BlockRewriter<ClientboundPackets1_16> blockRewriter = BlockRewriter.for1_14(protocol);
RecipeRewriter<ClientboundPackets1_16> recipeRewriter = new RecipeRewriter<>(protocol);
// Remove new smithing type, only in this handler
protocol.registerClientbound(ClientboundPackets1_16.DECLARE_RECIPES, wrapper -> {
int size = wrapper.passthrough(Type.VAR_INT);
int newSize = size;
for (int i = 0; i < size; i++) {
String originalType = wrapper.read(Type.STRING);
String type = Key.stripMinecraftNamespace(originalType);
if (type.equals("smithing")) {
newSize--;
wrapper.read(Type.STRING);
wrapper.read(Type.ITEM1_13_2_ARRAY);
wrapper.read(Type.ITEM1_13_2_ARRAY);
wrapper.read(Type.ITEM1_13_2);
continue;
}
wrapper.write(Type.STRING, originalType);
wrapper.passthrough(Type.STRING); // Recipe Identifier
recipeRewriter.handleRecipeType(wrapper, type);
}
wrapper.set(Type.VAR_INT, 0, newSize);
});
registerSetCooldown(ClientboundPackets1_16.COOLDOWN);
registerWindowItems(ClientboundPackets1_16.WINDOW_ITEMS);
registerSetSlot(ClientboundPackets1_16.SET_SLOT);
registerTradeList(ClientboundPackets1_16.TRADE_LIST);
registerAdvancements(ClientboundPackets1_16.ADVANCEMENTS);
blockRewriter.registerAcknowledgePlayerDigging(ClientboundPackets1_16.ACKNOWLEDGE_PLAYER_DIGGING);
blockRewriter.registerBlockAction(ClientboundPackets1_16.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_16.BLOCK_CHANGE);
blockRewriter.registerMultiBlockChange(ClientboundPackets1_16.MULTI_BLOCK_CHANGE);
protocol.registerClientbound(ClientboundPackets1_16.ENTITY_EQUIPMENT, wrapper -> {
int entityId = wrapper.passthrough(Type.VAR_INT);
List<EquipmentData> equipmentData = new ArrayList<>();
byte slot;
do {
slot = wrapper.read(Type.BYTE);
Item item = handleItemToClient(wrapper.read(Type.ITEM1_13_2));
int rawSlot = slot & 0x7F;
equipmentData.add(new EquipmentData(rawSlot, item));
} while ((slot & 0xFFFFFF80) != 0);
// Send first data in the current packet
EquipmentData firstData = equipmentData.get(0);
wrapper.write(Type.VAR_INT, firstData.slot);
wrapper.write(Type.ITEM1_13_2, firstData.item);
// If there are more items, send new packets for them
for (int i = 1; i < equipmentData.size(); i++) {
PacketWrapper equipmentPacket = wrapper.create(ClientboundPackets1_15.ENTITY_EQUIPMENT);
EquipmentData data = equipmentData.get(i);
equipmentPacket.write(Type.VAR_INT, entityId);
equipmentPacket.write(Type.VAR_INT, data.slot);
equipmentPacket.write(Type.ITEM1_13_2, data.item);
equipmentPacket.send(Protocol1_15_2To1_16.class);
}
});
protocol.registerClientbound(ClientboundPackets1_16.UPDATE_LIGHT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // x
map(Type.VAR_INT); // y
read(Type.BOOLEAN);
}
});
protocol.registerClientbound(ClientboundPackets1_16.CHUNK_DATA, wrapper -> {
Chunk chunk = wrapper.read(ChunkType1_16.TYPE);
wrapper.write(ChunkType1_15.TYPE, chunk);
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) {
continue;
}
DataPalette palette = section.palette(PaletteType.BLOCKS);
for (int j = 0; j < palette.size(); j++) {
int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(palette.idByIndex(j));
palette.setIdByIndex(j, mappedBlockStateId);
}
}
CompoundTag heightMaps = chunk.getHeightMap();
for (Tag heightMapTag : heightMaps.values()) {
if (!(heightMapTag instanceof LongArrayTag)) {
continue;
}
LongArrayTag heightMap = (LongArrayTag) heightMapTag;
int[] heightMapData = new int[256];
CompactArrayUtil.iterateCompactArrayWithPadding(9, heightMapData.length, heightMap.getValue(), (i, v) -> heightMapData[i] = v);
heightMap.setValue(CompactArrayUtil.createCompactArray(9, heightMapData.length, i -> heightMapData[i]));
}
if (chunk.isBiomeData()) {
if (wrapper.user().getProtocolInfo().getServerProtocolVersion() >= ProtocolVersion.v1_16_2.getVersion()) {
BiomeStorage biomeStorage = wrapper.user().get(BiomeStorage.class);
for (int i = 0; i < 1024; i++) {
int biome = chunk.getBiomeData()[i];
int legacyBiome = biomeStorage.legacyBiome(biome);
if (legacyBiome == -1) {
ViaBackwards.getPlatform().getLogger().warning("Biome sent that does not exist in the biome registry: " + biome);
legacyBiome = 1;
}
chunk.getBiomeData()[i] = legacyBiome;
}
} else {
for (int i = 0; i < 1024; i++) {
int biome = chunk.getBiomeData()[i];
switch (biome) {
case 170: // new nether biomes
case 171:
case 172:
case 173:
chunk.getBiomeData()[i] = 8;
break;
}
}
}
}
if (chunk.getBlockEntities() == null) return;
for (CompoundTag blockEntity : chunk.getBlockEntities()) {
handleBlockEntity(blockEntity);
}
});
blockRewriter.registerEffect(ClientboundPackets1_16.EFFECT, 1010, 2001);
registerSpawnParticle(ClientboundPackets1_16.SPAWN_PARTICLE, Type.DOUBLE);
protocol.registerClientbound(ClientboundPackets1_16.WINDOW_PROPERTY, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.SHORT); // Property
map(Type.SHORT); // Value
handler(wrapper -> {
short property = wrapper.get(Type.SHORT, 0);
if (property >= 4 && property <= 6) { // Enchantment id
short enchantmentId = wrapper.get(Type.SHORT, 1);
if (enchantmentId > 11) { // soul_speed
wrapper.set(Type.SHORT, 1, --enchantmentId);
} else if (enchantmentId == 11) {
wrapper.set(Type.SHORT, 1, (short) 9);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_16.MAP_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Map ID
map(Type.BYTE); // Scale
map(Type.BOOLEAN); // Tracking Position
map(Type.BOOLEAN); // Locked
handler(MapColorRewriter.getRewriteHandler(MapColorRewrites::getMappedColor));
}
});
protocol.registerClientbound(ClientboundPackets1_16.BLOCK_ENTITY_DATA, wrapper -> {
wrapper.passthrough(Type.POSITION1_14); // Position
wrapper.passthrough(Type.UNSIGNED_BYTE); // Action
CompoundTag tag = wrapper.passthrough(Type.NAMED_COMPOUND_TAG);
handleBlockEntity(tag);
});
registerClickWindow(ServerboundPackets1_14.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_14.CREATIVE_INVENTORY_ACTION);
protocol.registerServerbound(ServerboundPackets1_14.EDIT_BOOK, wrapper -> handleItemToServer(wrapper.passthrough(Type.ITEM1_13_2)));
}
private void handleBlockEntity(CompoundTag tag) {
StringTag idTag = tag.getStringTag("id");
if (idTag == null) return;
String id = idTag.getValue();
if (id.equals("minecraft:conduit")) {
Tag targetUuidTag = tag.remove("Target");
if (!(targetUuidTag instanceof IntArrayTag)) return;
// Target -> target_uuid
UUID targetUuid = UUIDUtil.fromIntArray((int[]) targetUuidTag.getValue());
tag.putString("target_uuid", targetUuid.toString());
} else if (id.equals("minecraft:skull")) {
Tag skullOwnerTag = tag.remove("SkullOwner");
if (!(skullOwnerTag instanceof CompoundTag)) return;
CompoundTag skullOwnerCompoundTag = (CompoundTag) skullOwnerTag;
Tag ownerUuidTag = skullOwnerCompoundTag.remove("Id");
if (ownerUuidTag instanceof IntArrayTag) {
UUID ownerUuid = UUIDUtil.fromIntArray((int[]) ownerUuidTag.getValue());
skullOwnerCompoundTag.putString("Id", ownerUuid.toString());
}
// SkullOwner -> Owner
CompoundTag ownerTag = new CompoundTag();
for (Map.Entry<String, Tag> entry : skullOwnerCompoundTag) {
ownerTag.put(entry.getKey(), entry.getValue());
}
tag.put("Owner", ownerTag);
}
}
@Override
protected void registerRewrites() {
enchantmentRewriter = new EnchantmentRewriter(this);
enchantmentRewriter.registerEnchantment("minecraft:soul_speed", "§7Soul Speed");
}
@Override
public Item handleItemToClient(Item item) {
if (item == null) return null;
super.handleItemToClient(item);
CompoundTag tag = item.tag();
if (item.identifier() == 771 && tag != null) {
CompoundTag ownerTag = tag.getCompoundTag("SkullOwner");
if (ownerTag != null) {
IntArrayTag idTag = ownerTag.getIntArrayTag("Id");
if (idTag != null) {
UUID ownerUuid = UUIDUtil.fromIntArray(idTag.getValue());
ownerTag.putString("Id", ownerUuid.toString());
}
}
}
// Handle hover event changes in written book pages
if (item.identifier() == 759 && tag != null) {
ListTag pagesTag = tag.getListTag("pages");
if (pagesTag != null) {
for (Tag page : pagesTag) {
if (!(page instanceof StringTag)) {
continue;
}
StringTag pageTag = (StringTag) page;
JsonElement jsonElement = protocol.getTranslatableRewriter().processText(pageTag.getValue());
pageTag.setValue(jsonElement.toString());
}
}
}
InventoryPackets.newToOldAttributes(item);
enchantmentRewriter.handleToClient(item);
return item;
}
@Override
public Item handleItemToServer(Item item) {
if (item == null) return null;
int identifier = item.identifier();
super.handleItemToServer(item);
CompoundTag tag = item.tag();
if (identifier == 771 && tag != null) {
CompoundTag ownerTag = tag.getCompoundTag("SkullOwner");
if (ownerTag != null) {
StringTag idTag = ownerTag.getStringTag("Id");
if (idTag != null) {
UUID ownerUuid = UUID.fromString(idTag.getValue());
ownerTag.put("Id", new IntArrayTag(UUIDUtil.toIntArray(ownerUuid)));
}
}
}
InventoryPackets.oldToNewAttributes(item);
enchantmentRewriter.handleToServer(item);
return item;
}
private static final class EquipmentData {
private final int slot;
private final Item item;
private EquipmentData(final int slot, final Item item) {
this.slot = slot;
this.item = item;
}
}
}
@@ -1,319 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_15_2to1_16.packets;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.Protocol1_15_2To1_16;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.data.WorldNameTracker;
import com.viaversion.viabackwards.protocol.protocol1_15_2to1_16.storage.WolfDataMaskStorage;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_15;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_14;
import com.viaversion.viaversion.api.type.types.version.Types1_16;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
import com.viaversion.viaversion.util.Key;
public class EntityPackets1_16 extends EntityRewriter<ClientboundPackets1_16, Protocol1_15_2To1_16> {
private final ValueTransformer<String, Integer> dimensionTransformer = new ValueTransformer<String, Integer>(Type.STRING, Type.INT) {
@Override
public Integer transform(PacketWrapper wrapper, String input) {
switch (input) {
case "minecraft:the_nether":
return -1;
default:
case "minecraft:overworld":
return 0;
case "minecraft:the_end":
return 1;
}
}
};
public EntityPackets1_16(Protocol1_15_2To1_16 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_16.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - Entity UUID
map(Type.VAR_INT); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - Data
handler(wrapper -> {
EntityType entityType = typeFromId(wrapper.get(Type.VAR_INT, 1));
if (entityType == EntityTypes1_16.LIGHTNING_BOLT) {
// Map to old weather entity packet
wrapper.cancel();
PacketWrapper spawnLightningPacket = wrapper.create(ClientboundPackets1_15.SPAWN_GLOBAL_ENTITY);
spawnLightningPacket.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0)); // Entity id
spawnLightningPacket.write(Type.BYTE, (byte) 1); // Lightning type
spawnLightningPacket.write(Type.DOUBLE, wrapper.get(Type.DOUBLE, 0)); // X
spawnLightningPacket.write(Type.DOUBLE, wrapper.get(Type.DOUBLE, 1)); // Y
spawnLightningPacket.write(Type.DOUBLE, wrapper.get(Type.DOUBLE, 2)); // Z
spawnLightningPacket.send(Protocol1_15_2To1_16.class);
}
});
handler(getSpawnTrackerWithDataHandler(EntityTypes1_16.FALLING_BLOCK));
}
});
registerSpawnTracker(ClientboundPackets1_16.SPAWN_MOB);
protocol.registerClientbound(ClientboundPackets1_16.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(dimensionTransformer); // Dimension Type
handler(wrapper -> {
// Grab the tracker for world names
WorldNameTracker worldNameTracker = wrapper.user().get(WorldNameTracker.class);
String nextWorldName = wrapper.read(Type.STRING); // World Name
wrapper.passthrough(Type.LONG); // Seed
wrapper.passthrough(Type.UNSIGNED_BYTE); // Gamemode
wrapper.read(Type.BYTE); // Previous gamemode
// Grab client world
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimension = wrapper.get(Type.INT, 0);
// Send a dummy respawn with a different dimension if the world name was different and the same dimension was used
if (clientWorld.getEnvironment() != null && dimension == clientWorld.getEnvironment().id()
&& (wrapper.user().isClientSide() || Via.getPlatform().isProxy()
|| wrapper.user().getProtocolInfo().getProtocolVersion() <= ProtocolVersion.v1_12_2.getVersion() // Hotfix for https://github.com/ViaVersion/ViaBackwards/issues/381
|| !nextWorldName.equals(worldNameTracker.getWorldName()))) {
PacketWrapper packet = wrapper.create(ClientboundPackets1_15.RESPAWN);
packet.write(Type.INT, dimension == 0 ? -1 : 0);
packet.write(Type.LONG, 0L);
packet.write(Type.UNSIGNED_BYTE, (short) 0);
packet.write(Type.STRING, "default");
packet.send(Protocol1_15_2To1_16.class);
}
clientWorld.setEnvironment(dimension);
wrapper.write(Type.STRING, "default"); // Level type
wrapper.read(Type.BOOLEAN); // Debug
if (wrapper.read(Type.BOOLEAN)) {
wrapper.set(Type.STRING, 0, "flat");
}
wrapper.read(Type.BOOLEAN); // Keep all playerdata
// Finally update the world name
worldNameTracker.setWorldName(nextWorldName);
});
}
});
protocol.registerClientbound(ClientboundPackets1_16.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity ID
map(Type.UNSIGNED_BYTE); // Gamemode
read(Type.BYTE); // Previous gamemode
read(Type.STRING_ARRAY); // World list
read(Type.NAMED_COMPOUND_TAG); // whatever this is
map(dimensionTransformer); // Dimension Type
handler(wrapper -> {
WorldNameTracker worldNameTracker = wrapper.user().get(WorldNameTracker.class);
worldNameTracker.setWorldName(wrapper.read(Type.STRING)); // Save the world name
});
map(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // Max players
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
clientChunks.setEnvironment(wrapper.get(Type.INT, 1));
tracker(wrapper.user()).addEntity(wrapper.get(Type.INT, 0), EntityTypes1_16.PLAYER);
wrapper.write(Type.STRING, "default"); // Level type
wrapper.passthrough(Type.VAR_INT); // View distance
wrapper.passthrough(Type.BOOLEAN); // Reduced debug info
wrapper.passthrough(Type.BOOLEAN); // Show death screen
wrapper.read(Type.BOOLEAN); // Debug
if (wrapper.read(Type.BOOLEAN)) {
wrapper.set(Type.STRING, 0, "flat");
}
});
}
});
registerTracker(ClientboundPackets1_16.SPAWN_EXPERIENCE_ORB, EntityTypes1_16.EXPERIENCE_ORB);
// F Spawn Global Object, it is no longer with us :(
registerTracker(ClientboundPackets1_16.SPAWN_PAINTING, EntityTypes1_16.PAINTING);
registerTracker(ClientboundPackets1_16.SPAWN_PLAYER, EntityTypes1_16.PLAYER);
registerRemoveEntities(ClientboundPackets1_16.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_16.ENTITY_METADATA, Types1_16.METADATA_LIST, Types1_14.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_16.ENTITY_PROPERTIES, wrapper -> {
wrapper.passthrough(Type.VAR_INT);
int size = wrapper.passthrough(Type.INT);
for (int i = 0; i < size; i++) {
String attributeIdentifier = wrapper.read(Type.STRING);
String oldKey = protocol.getMappingData().getAttributeMappings().get(attributeIdentifier);
wrapper.write(Type.STRING, oldKey != null ? oldKey : Key.stripMinecraftNamespace(attributeIdentifier));
wrapper.passthrough(Type.DOUBLE);
int modifierSize = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < modifierSize; j++) {
wrapper.passthrough(Type.UUID);
wrapper.passthrough(Type.DOUBLE);
wrapper.passthrough(Type.BYTE);
}
}
});
protocol.registerClientbound(ClientboundPackets1_16.PLAYER_INFO, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
int action = packetWrapper.passthrough(Type.VAR_INT);
int playerCount = packetWrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < playerCount; i++) {
packetWrapper.passthrough(Type.UUID);
if (action == 0) { // Add
packetWrapper.passthrough(Type.STRING);
int properties = packetWrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < properties; j++) {
packetWrapper.passthrough(Type.STRING);
packetWrapper.passthrough(Type.STRING);
packetWrapper.passthrough(Type.OPTIONAL_STRING);
}
packetWrapper.passthrough(Type.VAR_INT);
packetWrapper.passthrough(Type.VAR_INT);
// Display Name
protocol.getTranslatableRewriter().processText(packetWrapper.passthrough(Type.OPTIONAL_COMPONENT));
} else if (action == 1) { // Update Game Mode
packetWrapper.passthrough(Type.VAR_INT);
} else if (action == 2) { // Update Ping
packetWrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update Display Name
// Display name
protocol.getTranslatableRewriter().processText(packetWrapper.passthrough(Type.OPTIONAL_COMPONENT));
} // 4 = Remove Player
}
});
}
});
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
meta.setMetaType(Types1_14.META_TYPES.byId(meta.metaType().typeId()));
MetaType type = meta.metaType();
if (type == Types1_14.META_TYPES.itemType) {
meta.setValue(protocol.getItemRewriter().handleItemToClient((Item) meta.getValue()));
} else if (type == Types1_14.META_TYPES.blockStateType) {
meta.setValue(protocol.getMappingData().getNewBlockStateId((int) meta.getValue()));
} else if (type == Types1_14.META_TYPES.particleType) {
rewriteParticle((Particle) meta.getValue());
} else if (type == Types1_14.META_TYPES.optionalComponentType) {
JsonElement text = meta.value();
if (text != null) {
protocol.getTranslatableRewriter().processText(text);
}
}
});
mapEntityType(EntityTypes1_16.ZOMBIFIED_PIGLIN, EntityTypes1_15.ZOMBIE_PIGMAN);
mapTypes(EntityTypes1_16.values(), EntityTypes1_15.class);
mapEntityTypeWithData(EntityTypes1_16.HOGLIN, EntityTypes1_16.COW).jsonName();
mapEntityTypeWithData(EntityTypes1_16.ZOGLIN, EntityTypes1_16.COW).jsonName();
mapEntityTypeWithData(EntityTypes1_16.PIGLIN, EntityTypes1_16.ZOMBIFIED_PIGLIN).jsonName();
mapEntityTypeWithData(EntityTypes1_16.STRIDER, EntityTypes1_16.MAGMA_CUBE).jsonName();
filter().type(EntityTypes1_16.ZOGLIN).cancel(16);
filter().type(EntityTypes1_16.HOGLIN).cancel(15);
filter().type(EntityTypes1_16.PIGLIN).cancel(16);
filter().type(EntityTypes1_16.PIGLIN).cancel(17);
filter().type(EntityTypes1_16.PIGLIN).cancel(18);
filter().type(EntityTypes1_16.STRIDER).index(15).handler((event, meta) -> {
boolean baby = meta.value();
meta.setTypeAndValue(Types1_14.META_TYPES.varIntType, baby ? 1 : 3);
});
filter().type(EntityTypes1_16.STRIDER).cancel(16);
filter().type(EntityTypes1_16.STRIDER).cancel(17);
filter().type(EntityTypes1_16.STRIDER).cancel(18);
filter().type(EntityTypes1_16.FISHING_BOBBER).cancel(8);
filter().type(EntityTypes1_16.ABSTRACT_ARROW).cancel(8);
filter().type(EntityTypes1_16.ABSTRACT_ARROW).handler((event, meta) -> {
if (event.index() >= 8) {
event.setIndex(event.index() + 1);
}
});
filter().type(EntityTypes1_16.WOLF).index(16).handler((event, meta) -> {
byte mask = meta.value();
StoredEntityData data = tracker(event.user()).entityData(event.entityId());
data.put(new WolfDataMaskStorage(mask));
});
filter().type(EntityTypes1_16.WOLF).index(20).handler((event, meta) -> {
StoredEntityData data = tracker(event.user()).entityDataIfPresent(event.entityId());
byte previousMask = 0;
if (data != null) {
WolfDataMaskStorage wolfData = data.get(WolfDataMaskStorage.class);
if (wolfData != null) {
previousMask = wolfData.tameableMask();
}
}
int angerTime = meta.value();
byte tameableMask = (byte) (angerTime > 0 ? previousMask | 2 : previousMask & -3);
event.createExtraMeta(new Metadata(16, Types1_14.META_TYPES.byteType, tameableMask));
event.cancel();
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_16.getTypeFromId(typeId);
}
}
@@ -1,145 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_16_1to1_16_2;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.data.CommandRewriter1_16_2;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.packets.BlockItemPackets1_16_2;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.packets.EntityPackets1_16_2;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16_2;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.Protocol1_16_2To1_16_1;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ServerboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ServerboundPackets1_16;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
public class Protocol1_16_1To1_16_2 extends BackwardsProtocol<ClientboundPackets1_16_2, ClientboundPackets1_16, ServerboundPackets1_16_2, ServerboundPackets1_16> {
public static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.16.2", "1.16", Protocol1_16_2To1_16_1.class);
private final EntityPackets1_16_2 entityRewriter = new EntityPackets1_16_2(this);
private final BlockItemPackets1_16_2 blockItemPackets = new BlockItemPackets1_16_2(this);
private final TranslatableRewriter<ClientboundPackets1_16_2> translatableRewriter = new TranslatableRewriter<>(this, ComponentRewriter.ReadType.JSON);
public Protocol1_16_1To1_16_2() {
super(ClientboundPackets1_16_2.class, ClientboundPackets1_16.class, ServerboundPackets1_16_2.class, ServerboundPackets1_16.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
translatableRewriter.registerBossBar(ClientboundPackets1_16_2.BOSSBAR);
translatableRewriter.registerCombatEvent(ClientboundPackets1_16_2.COMBAT_EVENT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_16_2.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_16_2.TAB_LIST);
translatableRewriter.registerTitle(ClientboundPackets1_16_2.TITLE);
translatableRewriter.registerOpenWindow(ClientboundPackets1_16_2.OPEN_WINDOW);
translatableRewriter.registerPing();
new CommandRewriter1_16_2(this).registerDeclareCommands(ClientboundPackets1_16_2.DECLARE_COMMANDS);
SoundRewriter<ClientboundPackets1_16_2> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound(ClientboundPackets1_16_2.SOUND);
soundRewriter.registerSound(ClientboundPackets1_16_2.ENTITY_SOUND);
soundRewriter.registerNamedSound(ClientboundPackets1_16_2.NAMED_SOUND);
soundRewriter.registerStopSound(ClientboundPackets1_16_2.STOP_SOUND);
registerClientbound(ClientboundPackets1_16_2.CHAT_MESSAGE, wrapper -> {
JsonElement message = wrapper.passthrough(Type.COMPONENT);
translatableRewriter.processText(message);
byte position = wrapper.passthrough(Type.BYTE);
if (position == 2) { // https://bugs.mojang.com/browse/MC-119145
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_16.TITLE);
wrapper.write(Type.VAR_INT, 2);
wrapper.write(Type.COMPONENT, message);
}
});
// Recipe book data has been split into 2 separate packets
registerServerbound(ServerboundPackets1_16.RECIPE_BOOK_DATA, wrapper -> {
int type = wrapper.read(Type.VAR_INT);
if (type == 0) {
// Shown, change to its own packet
wrapper.passthrough(Type.STRING); // Recipe
wrapper.setPacketType(ServerboundPackets1_16_2.SEEN_RECIPE);
} else {
wrapper.cancel();
// Settings
for (int i = 0; i < 3; i++) {
sendSeenRecipePacket(i, wrapper);
}
}
});
new TagRewriter<>(this).register(ClientboundPackets1_16_2.TAGS, RegistryType.ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_16_2.STATISTICS);
}
private static void sendSeenRecipePacket(int recipeType, PacketWrapper wrapper) throws Exception {
boolean open = wrapper.read(Type.BOOLEAN);
boolean filter = wrapper.read(Type.BOOLEAN);
PacketWrapper newPacket = wrapper.create(ServerboundPackets1_16_2.RECIPE_BOOK_DATA);
newPacket.write(Type.VAR_INT, recipeType);
newPacket.write(Type.BOOLEAN, open);
newPacket.write(Type.BOOLEAN, filter);
newPacket.sendToServer(Protocol1_16_1To1_16_2.class);
}
@Override
public void init(UserConnection user) {
user.put(new BiomeStorage());
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_16_2.PLAYER));
}
@Override
public TranslatableRewriter<ClientboundPackets1_16_2> getTranslatableRewriter() {
return translatableRewriter;
}
@Override
public BackwardsMappings getMappingData() {
return MAPPINGS;
}
@Override
public EntityPackets1_16_2 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPackets1_16_2 getItemRewriter() {
return blockItemPackets;
}
}
@@ -1,164 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_16_1to1_16_2.packets;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.Protocol1_16_1To1_16_2;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord1_8;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_16;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_16_2;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.IntArrayTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ServerboundPackets1_16;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
public class BlockItemPackets1_16_2 extends com.viaversion.viabackwards.api.rewriters.ItemRewriter<ClientboundPackets1_16_2, ServerboundPackets1_16, Protocol1_16_1To1_16_2> {
public BlockItemPackets1_16_2(Protocol1_16_1To1_16_2 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_SHORT_ARRAY);
}
@Override
protected void registerPackets() {
BlockRewriter<ClientboundPackets1_16_2> blockRewriter = BlockRewriter.for1_14(protocol);
new RecipeRewriter<>(protocol).register(ClientboundPackets1_16_2.DECLARE_RECIPES);
registerSetCooldown(ClientboundPackets1_16_2.COOLDOWN);
registerWindowItems(ClientboundPackets1_16_2.WINDOW_ITEMS);
registerSetSlot(ClientboundPackets1_16_2.SET_SLOT);
registerEntityEquipmentArray(ClientboundPackets1_16_2.ENTITY_EQUIPMENT);
registerTradeList(ClientboundPackets1_16_2.TRADE_LIST);
registerAdvancements(ClientboundPackets1_16_2.ADVANCEMENTS);
protocol.registerClientbound(ClientboundPackets1_16_2.UNLOCK_RECIPES, wrapper -> {
wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.BOOLEAN); // Open
wrapper.passthrough(Type.BOOLEAN); // Filter
wrapper.passthrough(Type.BOOLEAN); // Furnace Open
wrapper.passthrough(Type.BOOLEAN); // Filter furnace
// Blast furnace / smoker
wrapper.read(Type.BOOLEAN);
wrapper.read(Type.BOOLEAN);
wrapper.read(Type.BOOLEAN);
wrapper.read(Type.BOOLEAN);
});
blockRewriter.registerAcknowledgePlayerDigging(ClientboundPackets1_16_2.ACKNOWLEDGE_PLAYER_DIGGING);
blockRewriter.registerBlockAction(ClientboundPackets1_16_2.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_16_2.BLOCK_CHANGE);
protocol.registerClientbound(ClientboundPackets1_16_2.CHUNK_DATA, wrapper -> {
Chunk chunk = wrapper.read(ChunkType1_16_2.TYPE);
wrapper.write(ChunkType1_16.TYPE, chunk);
chunk.setIgnoreOldLightData(true);
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null) {
continue;
}
DataPalette palette = section.palette(PaletteType.BLOCKS);
for (int j = 0; j < palette.size(); j++) {
int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(palette.idByIndex(j));
palette.setIdByIndex(j, mappedBlockStateId);
}
}
for (CompoundTag blockEntity : chunk.getBlockEntities()) {
if (blockEntity != null) {
handleBlockEntity(blockEntity);
}
}
});
protocol.registerClientbound(ClientboundPackets1_16_2.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Type.POSITION1_14);
map(Type.UNSIGNED_BYTE);
handler(wrapper -> handleBlockEntity(wrapper.passthrough(Type.NAMED_COMPOUND_TAG)));
}
});
protocol.registerClientbound(ClientboundPackets1_16_2.MULTI_BLOCK_CHANGE, wrapper -> {
long chunkPosition = wrapper.read(Type.LONG);
wrapper.read(Type.BOOLEAN); // Ignore old light data
int chunkX = (int) (chunkPosition >> 42);
int chunkY = (int) (chunkPosition << 44 >> 44);
int chunkZ = (int) (chunkPosition << 22 >> 42);
wrapper.write(Type.INT, chunkX);
wrapper.write(Type.INT, chunkZ);
BlockChangeRecord[] blockChangeRecord = wrapper.read(Type.VAR_LONG_BLOCK_CHANGE_RECORD_ARRAY);
wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, blockChangeRecord);
for (int i = 0; i < blockChangeRecord.length; i++) {
BlockChangeRecord record = blockChangeRecord[i];
int blockId = protocol.getMappingData().getNewBlockStateId(record.getBlockId());
// Relative y -> absolute y
blockChangeRecord[i] = new BlockChangeRecord1_8(record.getSectionX(), record.getY(chunkY), record.getSectionZ(), blockId);
}
});
blockRewriter.registerEffect(ClientboundPackets1_16_2.EFFECT, 1010, 2001);
registerSpawnParticle(ClientboundPackets1_16_2.SPAWN_PARTICLE, Type.DOUBLE);
registerClickWindow(ServerboundPackets1_16.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_16.CREATIVE_INVENTORY_ACTION);
protocol.registerServerbound(ServerboundPackets1_16.EDIT_BOOK, wrapper -> handleItemToServer(wrapper.passthrough(Type.ITEM1_13_2)));
}
private void handleBlockEntity(CompoundTag tag) {
StringTag idTag = tag.getStringTag("id");
if (idTag == null) return;
if (idTag.getValue().equals("minecraft:skull")) {
// Workaround an old client bug: MC-68487
CompoundTag skullOwnerTag = tag.getCompoundTag("SkullOwner");
if (skullOwnerTag == null) return;
if (!skullOwnerTag.contains("Id")) return;
CompoundTag properties = skullOwnerTag.getCompoundTag("Properties");
if (properties == null) return;
ListTag textures = properties.getListTag("textures");
if (textures == null) return;
CompoundTag first = !textures.isEmpty() ? textures.get(0) : null;
if (first == null) return;
// Make the client cache the skinprofile over this uuid
int hashCode = first.get("Value").getValue().hashCode();
int[] uuidIntArray = {hashCode, 0, 0, 0}; //TODO split texture in 4 for a lower collision chance
skullOwnerTag.put("Id", new IntArrayTag(uuidIntArray));
}
}
}
@@ -1,139 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_16_1to1_16_2.packets;
import com.google.common.collect.Sets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.Protocol1_16_1To1_16_2;
import com.viaversion.viabackwards.protocol.protocol1_16_1to1_16_2.storage.BiomeStorage;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16_2;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_16;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.packets.EntityPackets;
import java.util.Set;
public class EntityPackets1_16_2 extends EntityRewriter<ClientboundPackets1_16_2, Protocol1_16_1To1_16_2> {
private final Set<String> oldDimensions = Sets.newHashSet("minecraft:overworld", "minecraft:the_nether", "minecraft:the_end");
private boolean warned;
public EntityPackets1_16_2(Protocol1_16_1To1_16_2 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerTrackerWithData(ClientboundPackets1_16_2.SPAWN_ENTITY, EntityTypes1_16_2.FALLING_BLOCK);
registerSpawnTracker(ClientboundPackets1_16_2.SPAWN_MOB);
registerTracker(ClientboundPackets1_16_2.SPAWN_EXPERIENCE_ORB, EntityTypes1_16_2.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_16_2.SPAWN_PAINTING, EntityTypes1_16_2.PAINTING);
registerTracker(ClientboundPackets1_16_2.SPAWN_PLAYER, EntityTypes1_16_2.PLAYER);
registerRemoveEntities(ClientboundPackets1_16_2.DESTROY_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_16_2.ENTITY_METADATA, Types1_16.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_16_2.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity ID
handler(wrapper -> {
boolean hardcore = wrapper.read(Type.BOOLEAN);
short gamemode = wrapper.read(Type.BYTE);
if (hardcore) {
gamemode |= 0x08;
}
wrapper.write(Type.UNSIGNED_BYTE, gamemode);
});
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
handler(wrapper -> {
CompoundTag registry = wrapper.read(Type.NAMED_COMPOUND_TAG);
if (wrapper.user().getProtocolInfo().getProtocolVersion() <= ProtocolVersion.v1_15_2.getVersion()) {
// Store biomes for <1.16 client handling
CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
ListTag biomes = biomeRegistry.get("value");
BiomeStorage biomeStorage = wrapper.user().get(BiomeStorage.class);
biomeStorage.clear();
for (Tag biome : biomes) {
CompoundTag biomeCompound = (CompoundTag) biome;
StringTag name = biomeCompound.get("name");
NumberTag id = biomeCompound.get("id");
biomeStorage.addBiome(name.getValue(), id.asInt());
}
} else if (!warned) {
warned = true;
ViaBackwards.getPlatform().getLogger().warning("1.16 and 1.16.1 clients are only partially supported and may have wrong biomes displayed.");
}
// Just screw the registry and write the defaults for 1.16 and 1.16.1 clients
wrapper.write(Type.NAMED_COMPOUND_TAG, EntityPackets.DIMENSIONS_TAG);
CompoundTag dimensionData = wrapper.read(Type.NAMED_COMPOUND_TAG);
wrapper.write(Type.STRING, getDimensionFromData(dimensionData));
});
map(Type.STRING); // Dimension
map(Type.LONG); // Seed
handler(wrapper -> {
int maxPlayers = wrapper.read(Type.VAR_INT);
wrapper.write(Type.UNSIGNED_BYTE, (short) Math.min(maxPlayers, 255));
});
// ...
handler(getTrackerHandler(EntityTypes1_16_2.PLAYER, Type.INT));
}
});
protocol.registerClientbound(ClientboundPackets1_16_2.RESPAWN, wrapper -> {
CompoundTag dimensionData = wrapper.read(Type.NAMED_COMPOUND_TAG);
wrapper.write(Type.STRING, getDimensionFromData(dimensionData));
});
}
private String getDimensionFromData(CompoundTag dimensionData) {
// This may technically break other custom dimension settings for 1.16/1.16.1 clients, so those cases are considered semi "unsupported" here
StringTag effectsLocation = dimensionData.get("effects");
return effectsLocation != null && oldDimensions.contains(effectsLocation.getValue()) ?
effectsLocation.getValue() : "minecraft:overworld";
}
@Override
protected void registerRewrites() {
registerMetaTypeHandler(Types1_16.META_TYPES.itemType, Types1_16.META_TYPES.blockStateType, null,
Types1_16.META_TYPES.particleType, Types1_16.META_TYPES.componentType, Types1_16.META_TYPES.optionalComponentType);
mapTypes(EntityTypes1_16_2.values(), EntityTypes1_16.class);
mapEntityTypeWithData(EntityTypes1_16_2.PIGLIN_BRUTE, EntityTypes1_16_2.PIGLIN).jsonName();
filter().type(EntityTypes1_16_2.ABSTRACT_PIGLIN).index(15).toIndex(16);
filter().type(EntityTypes1_16_2.ABSTRACT_PIGLIN).index(16).toIndex(15);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_16_2.getTypeFromId(typeId);
}
}
@@ -1,226 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_16_4to1_17.packets;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_16_4to1_17.Protocol1_16_4To1_17;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_16_2;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_17;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_16;
import com.viaversion.viaversion.api.type.types.version.Types1_17;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ClientboundPackets1_17;
public final class EntityPackets1_17 extends EntityRewriter<ClientboundPackets1_17, Protocol1_16_4To1_17> {
private boolean warned;
public EntityPackets1_17(Protocol1_16_4To1_17 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerTrackerWithData(ClientboundPackets1_17.SPAWN_ENTITY, EntityTypes1_17.FALLING_BLOCK);
registerSpawnTracker(ClientboundPackets1_17.SPAWN_MOB);
registerTracker(ClientboundPackets1_17.SPAWN_EXPERIENCE_ORB, EntityTypes1_17.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_17.SPAWN_PAINTING, EntityTypes1_17.PAINTING);
registerTracker(ClientboundPackets1_17.SPAWN_PLAYER, EntityTypes1_17.PLAYER);
registerMetadataRewriter(ClientboundPackets1_17.ENTITY_METADATA, Types1_17.METADATA_LIST, Types1_16.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_17.REMOVE_ENTITY, ClientboundPackets1_16_2.DESTROY_ENTITIES, wrapper -> {
int entityId = wrapper.read(Type.VAR_INT);
tracker(wrapper.user()).removeEntity(entityId);
// Write into single value array
int[] array = {entityId};
wrapper.write(Type.VAR_INT_ARRAY_PRIMITIVE, array);
});
protocol.registerClientbound(ClientboundPackets1_17.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity ID
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // Worlds
map(Type.NAMED_COMPOUND_TAG); // Dimension registry
map(Type.NAMED_COMPOUND_TAG); // Current dimension data
map(Type.STRING); // World
handler(wrapper -> {
byte previousGamemode = wrapper.get(Type.BYTE, 1);
if (previousGamemode == -1) { // "Unset" gamemode removed
wrapper.set(Type.BYTE, 1, (byte) 0);
}
});
handler(getTrackerHandler(EntityTypes1_17.PLAYER, Type.INT));
handler(worldDataTrackerHandler(1));
handler(wrapper -> {
CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
ListTag biomes = biomeRegistry.get("value");
for (Tag biome : biomes) {
CompoundTag biomeCompound = ((CompoundTag) biome).get("element");
StringTag category = biomeCompound.get("category");
if (category.getValue().equalsIgnoreCase("underground")) {
category.setValue("none");
}
}
CompoundTag dimensionRegistry = registry.get("minecraft:dimension_type");
ListTag dimensions = dimensionRegistry.get("value");
for (Tag dimension : dimensions) {
CompoundTag dimensionCompound = ((CompoundTag) dimension).get("element");
reduceExtendedHeight(dimensionCompound, false);
}
reduceExtendedHeight(wrapper.get(Type.NAMED_COMPOUND_TAG, 1), true);
});
}
});
protocol.registerClientbound(ClientboundPackets1_17.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.NAMED_COMPOUND_TAG); // Dimension data
map(Type.STRING); // World
handler(worldDataTrackerHandler(0));
handler(wrapper -> reduceExtendedHeight(wrapper.get(Type.NAMED_COMPOUND_TAG, 0), true));
}
});
protocol.registerClientbound(ClientboundPackets1_17.PLAYER_POSITION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.DOUBLE);
map(Type.FLOAT);
map(Type.FLOAT);
map(Type.BYTE);
map(Type.VAR_INT);
handler(wrapper -> {
// Dismount vehicle ¯\_(ツ)_/¯
wrapper.read(Type.BOOLEAN);
});
}
});
protocol.registerClientbound(ClientboundPackets1_17.ENTITY_PROPERTIES, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
handler(wrapper -> {
wrapper.write(Type.INT, wrapper.read(Type.VAR_INT)); // Collection length
});
}
});
// TODO translatables
protocol.mergePacket(ClientboundPackets1_17.COMBAT_ENTER, ClientboundPackets1_16_2.COMBAT_EVENT, 0);
protocol.mergePacket(ClientboundPackets1_17.COMBAT_END, ClientboundPackets1_16_2.COMBAT_EVENT, 1);
protocol.mergePacket(ClientboundPackets1_17.COMBAT_KILL, ClientboundPackets1_16_2.COMBAT_EVENT, 2);
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
meta.setMetaType(Types1_16.META_TYPES.byId(meta.metaType().typeId()));
MetaType type = meta.metaType();
if (type == Types1_16.META_TYPES.particleType) {
Particle particle = (Particle) meta.getValue();
if (particle.getId() == 16) { // Dust / Dust Transition
// Remove transition target color values 4-6
particle.getArguments().subList(4, 7).clear();
} else if (particle.getId() == 37) { // Vibration Signal
// No nice mapping possible without tracking entity positions and doing particle tasks
particle.setId(0);
particle.getArguments().clear();
return;
}
rewriteParticle(particle);
} else if (type == Types1_16.META_TYPES.poseType) {
// Goat LONG_JUMP added at 6
int pose = meta.value();
if (pose == 6) {
meta.setValue(1); // FALL_FLYING
} else if (pose > 6) {
meta.setValue(pose - 1);
}
}
});
// Particles have already been handled
registerMetaTypeHandler(Types1_16.META_TYPES.itemType, Types1_16.META_TYPES.blockStateType, null, null,
Types1_16.META_TYPES.componentType, Types1_16.META_TYPES.optionalComponentType);
mapTypes(EntityTypes1_17.values(), EntityTypes1_16_2.class);
filter().type(EntityTypes1_17.AXOLOTL).cancel(17);
filter().type(EntityTypes1_17.AXOLOTL).cancel(18);
filter().type(EntityTypes1_17.AXOLOTL).cancel(19);
filter().type(EntityTypes1_17.GLOW_SQUID).cancel(16);
filter().type(EntityTypes1_17.GOAT).cancel(17);
mapEntityTypeWithData(EntityTypes1_17.AXOLOTL, EntityTypes1_17.TROPICAL_FISH).jsonName();
mapEntityTypeWithData(EntityTypes1_17.GOAT, EntityTypes1_17.SHEEP).jsonName();
mapEntityTypeWithData(EntityTypes1_17.GLOW_SQUID, EntityTypes1_17.SQUID).jsonName();
mapEntityTypeWithData(EntityTypes1_17.GLOW_ITEM_FRAME, EntityTypes1_17.ITEM_FRAME);
filter().type(EntityTypes1_17.SHULKER).addIndex(17); // TODO Handle attachment pos?
filter().removeIndex(7); // Ticks frozen
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_17.getTypeFromId(typeId);
}
private void reduceExtendedHeight(CompoundTag tag, boolean warn) {
NumberTag minY = tag.getNumberTag("min_y");
NumberTag height = tag.getNumberTag("height");
NumberTag logicalHeight = tag.getNumberTag("logical_height");
if (minY.asInt() != 0 || height.asInt() > 256 || logicalHeight.asInt() > 256) {
if (warn && !warned) {
ViaBackwards.getPlatform().getLogger().warning("Custom worlds heights are NOT SUPPORTED for 1.16 players and older and may lead to errors!");
ViaBackwards.getPlatform().getLogger().warning("You have min/max set to " + minY.asInt() + "/" + height.asInt());
warned = true;
}
tag.putInt("height", Math.min(256, height.asInt()));
tag.putInt("logical_height", Math.min(256, logicalHeight.asInt()));
}
}
}
@@ -1,34 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_16_4to1_17.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.libs.fastutil.ints.IntOpenHashSet;
import com.viaversion.viaversion.libs.fastutil.ints.IntSet;
public final class PingRequests implements StorableObject {
private final IntSet ids = new IntOpenHashSet();
public void addId(short id) {
ids.add(id);
}
public boolean removeId(short id) {
return ids.remove(id);
}
}
@@ -1,53 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_18_2to1_19.data;
import com.viaversion.viabackwards.api.data.VBMappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class BackwardsMappings extends com.viaversion.viabackwards.api.data.BackwardsMappings {
private final Int2ObjectMap<CompoundTag> defaultChatTypes = new Int2ObjectOpenHashMap<>();
public BackwardsMappings() {
super("1.19", "1.18", Protocol1_19To1_18_2.class);
}
@Override
protected void loadExtras(final CompoundTag data) {
super.loadExtras(data);
final ListTag chatTypes = VBMappingDataLoader.loadNBT("chat-types-1.19.1.nbt").get("values");
for (final Tag chatType : chatTypes) {
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
final NumberTag idTag = chatTypeCompound.get("id");
defaultChatTypes.put(idTag.asInt(), chatTypeCompound);
}
}
public @Nullable CompoundTag chatType(final int id) {
return defaultChatTypes.get(id);
}
}
@@ -1,206 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_18_2to1_19.packets;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_18_2to1_19.Protocol1_18_2To1_19;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
import com.viaversion.viaversion.util.MathUtil;
public final class BlockItemPackets1_19 extends ItemRewriter<ClientboundPackets1_19, ServerboundPackets1_17, Protocol1_18_2To1_19> {
public BlockItemPackets1_19(final Protocol1_18_2To1_19 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_ARRAY);
}
@Override
protected void registerPackets() {
final BlockRewriter<ClientboundPackets1_19> blockRewriter = BlockRewriter.for1_14(protocol);
new RecipeRewriter<>(protocol).register(ClientboundPackets1_19.DECLARE_RECIPES);
registerSetCooldown(ClientboundPackets1_19.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19.SET_SLOT);
registerEntityEquipmentArray(ClientboundPackets1_19.ENTITY_EQUIPMENT);
registerAdvancements(ClientboundPackets1_19.ADVANCEMENTS);
registerClickWindow1_17_1(ServerboundPackets1_17.CLICK_WINDOW);
blockRewriter.registerBlockAction(ClientboundPackets1_19.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange(ClientboundPackets1_19.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19.EFFECT, 1010, 2001);
registerCreativeInvAction(ServerboundPackets1_17.CREATIVE_INVENTORY_ACTION);
protocol.registerClientbound(ClientboundPackets1_19.TRADE_LIST, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Container id
handler(wrapper -> {
final int size = wrapper.read(Type.VAR_INT);
wrapper.write(Type.UNSIGNED_BYTE, (short) size);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // First item
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // Result
final Item secondItem = wrapper.read(Type.ITEM1_13_2);
if (secondItem != null) {
handleItemToClient(secondItem);
wrapper.write(Type.BOOLEAN, true);
wrapper.write(Type.ITEM1_13_2, secondItem);
} else {
wrapper.write(Type.BOOLEAN, false);
}
wrapper.passthrough(Type.BOOLEAN); // Out of stock
wrapper.passthrough(Type.INT); // Uses
wrapper.passthrough(Type.INT); // Max uses
wrapper.passthrough(Type.INT); // Xp
wrapper.passthrough(Type.INT); // Special price diff
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); //Demand
}
});
}
});
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19.WINDOW_PROPERTY);
protocol.registerClientbound(ClientboundPackets1_19.BLOCK_CHANGED_ACK, null, new PacketHandlers() {
@Override
public void register() {
read(Type.VAR_INT); // Sequence
handler(PacketWrapper::cancel); // This is fine:tm:
}
});
protocol.registerClientbound(ClientboundPackets1_19.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // Particle id
map(Type.BOOLEAN); // Override limiter
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Y
map(Type.DOUBLE); // Z
map(Type.FLOAT); // Offset X
map(Type.FLOAT); // Offset Y
map(Type.FLOAT); // Offset Z
map(Type.FLOAT); // Max speed
map(Type.INT); // Particle Count
handler(wrapper -> {
final int id = wrapper.get(Type.INT, 0);
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (id == particleMappings.id("sculk_charge")) {
//TODO
wrapper.set(Type.INT, 0, -1);
wrapper.cancel();
} else if (id == particleMappings.id("shriek")) {
//TODO
wrapper.set(Type.INT, 0, -1);
wrapper.cancel();
} else if (id == particleMappings.id("vibration")) {
// Can't do without the position
wrapper.set(Type.INT, 0, -1);
wrapper.cancel();
}
});
handler(getSpawnParticleHandler());
}
});
protocol.registerClientbound(ClientboundPackets1_19.CHUNK_DATA, wrapper -> {
final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user());
final ChunkType1_18 chunkType = new ChunkType1_18(tracker.currentWorldSectionHeight(),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().mappedSize()),
MathUtil.ceilLog2(tracker.biomesSent()));
final Chunk chunk = wrapper.passthrough(chunkType);
for (final ChunkSection section : chunk.getSections()) {
final DataPalette blockPalette = section.palette(PaletteType.BLOCKS);
for (int i = 0; i < blockPalette.size(); i++) {
final int id = blockPalette.idByIndex(i);
blockPalette.setIdByIndex(i, protocol.getMappingData().getNewBlockStateId(id));
}
}
});
// The server does nothing but track the sequence, so we can just set it as 0
protocol.registerServerbound(ServerboundPackets1_17.PLAYER_DIGGING, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Action
map(Type.POSITION1_14); // Block position
map(Type.UNSIGNED_BYTE); // Direction
create(Type.VAR_INT, 0); // Sequence
}
});
protocol.registerServerbound(ServerboundPackets1_17.PLAYER_BLOCK_PLACEMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Hand
map(Type.POSITION1_14); // Block position
map(Type.VAR_INT); // Direction
map(Type.FLOAT); // X
map(Type.FLOAT); // Y
map(Type.FLOAT); // Z
map(Type.BOOLEAN); // Inside
create(Type.VAR_INT, 0); // Sequence
}
});
protocol.registerServerbound(ServerboundPackets1_17.USE_ITEM, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Hand
create(Type.VAR_INT, 0); // Sequence
}
});
protocol.registerServerbound(ServerboundPackets1_17.SET_BEACON_EFFECT, wrapper -> {
final int primaryEffect = wrapper.read(Type.VAR_INT);
if (primaryEffect != -1) {
wrapper.write(Type.BOOLEAN, true);
wrapper.write(Type.VAR_INT, primaryEffect);
} else {
wrapper.write(Type.BOOLEAN, false);
}
final int secondaryEffect = wrapper.read(Type.VAR_INT);
if (secondaryEffect != -1) {
wrapper.write(Type.BOOLEAN, true);
wrapper.write(Type.VAR_INT, secondaryEffect);
} else {
wrapper.write(Type.BOOLEAN, false);
}
});
}
}
@@ -1,327 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_18_2to1_19.packets;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_18_2to1_19.Protocol1_18_2To1_19;
import com.viaversion.viabackwards.protocol.protocol1_18_2to1_19.storage.DimensionRegistryStorage;
import com.viaversion.viabackwards.protocol.protocol1_18_2to1_19.storage.StoredPainting;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_18;
import com.viaversion.viaversion.api.type.types.version.Types1_19;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
public final class EntityPackets1_19 extends EntityRewriter<ClientboundPackets1_19, Protocol1_18_2To1_19> {
public EntityPackets1_19(final Protocol1_18_2To1_19 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
registerTracker(ClientboundPackets1_19.SPAWN_EXPERIENCE_ORB, EntityTypes1_19.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_19.SPAWN_PLAYER, EntityTypes1_19.PLAYER);
registerMetadataRewriter(ClientboundPackets1_19.ENTITY_METADATA, Types1_19.METADATA_LIST, Types1_18.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_19.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_19.SPAWN_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.UUID); // Entity UUID
map(Type.VAR_INT); // Entity Type
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Y
map(Type.DOUBLE); // Z
map(Type.BYTE); // Pitch
map(Type.BYTE); // Yaw
handler(wrapper -> {
final byte headYaw = wrapper.read(Type.BYTE);
int data = wrapper.read(Type.VAR_INT);
final EntityType entityType = trackAndMapEntity(wrapper);
if (entityType.isOrHasParent(EntityTypes1_19.LIVINGENTITY)) {
wrapper.write(Type.BYTE, headYaw);
// Switch pitch and yaw position
final byte pitch = wrapper.get(Type.BYTE, 0);
final byte yaw = wrapper.get(Type.BYTE, 1);
wrapper.set(Type.BYTE, 0, yaw);
wrapper.set(Type.BYTE, 1, pitch);
wrapper.setPacketType(ClientboundPackets1_18.SPAWN_MOB);
return;
} else if (entityType == EntityTypes1_19.PAINTING) {
wrapper.cancel();
// The entity has been tracked, now we wait for the metadata packet
final int entityId = wrapper.get(Type.VAR_INT, 0);
final StoredEntityData entityData = tracker(wrapper.user()).entityData(entityId);
final Position position = new Position(wrapper.get(Type.DOUBLE, 0).intValue(), wrapper.get(Type.DOUBLE, 1).intValue(), wrapper.get(Type.DOUBLE, 2).intValue());
entityData.put(new StoredPainting(entityId, wrapper.get(Type.UUID, 0), position, data));
return;
}
if (entityType == EntityTypes1_19.FALLING_BLOCK) {
data = protocol.getMappingData().getNewBlockStateId(data);
}
wrapper.write(Type.INT, data);
});
}
});
protocol.registerClientbound(ClientboundPackets1_19.ENTITY_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
map(Type.VAR_INT); // Effect id
map(Type.BYTE); // Amplifier
map(Type.VAR_INT); // Duration
map(Type.BYTE); // Flags
handler(wrapper -> {
// Remove factor data
if (wrapper.read(Type.BOOLEAN)) {
wrapper.read(Type.NAMED_COMPOUND_TAG);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity ID
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // Worlds
map(Type.NAMED_COMPOUND_TAG); // Dimension registry
handler(wrapper -> {
final DimensionRegistryStorage dimensionRegistryStorage = wrapper.user().get(DimensionRegistryStorage.class);
dimensionRegistryStorage.clear();
// Cache dimensions and find current dimension
final String dimensionKey = wrapper.read(Type.STRING);
final CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
final ListTag dimensions = ((CompoundTag) registry.get("minecraft:dimension_type")).get("value");
boolean found = false;
for (final Tag dimension : dimensions) {
final CompoundTag dimensionCompound = (CompoundTag) dimension;
final StringTag nameTag = dimensionCompound.get("name");
final CompoundTag dimensionData = dimensionCompound.get("element");
dimensionRegistryStorage.addDimension(nameTag.getValue(), dimensionData.copy());
if (!found && nameTag.getValue().equals(dimensionKey)) {
wrapper.write(Type.NAMED_COMPOUND_TAG, dimensionData);
found = true;
}
}
if (!found) {
throw new IllegalStateException("Could not find dimension " + dimensionKey + " in dimension registry");
}
// Add biome category and track biomes
final CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
final ListTag biomes = biomeRegistry.get("value");
for (final Tag biome : biomes.getValue()) {
final CompoundTag biomeCompound = ((CompoundTag) biome).get("element");
biomeCompound.putString("category", "none");
}
tracker(wrapper.user()).setBiomesSent(biomes.size());
// Cache and remove chat types
final ListTag chatTypes = ((CompoundTag) registry.remove("minecraft:chat_type")).get("value");
for (final Tag chatType : chatTypes) {
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
final NumberTag idTag = chatTypeCompound.get("id");
dimensionRegistryStorage.addChatType(idTag.asInt(), chatTypeCompound);
}
});
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.VAR_INT); // Max players
map(Type.VAR_INT); // Chunk radius
map(Type.VAR_INT); // Simulation distance
map(Type.BOOLEAN); // Reduced debug info
map(Type.BOOLEAN); // Show death screen
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
read(Type.OPTIONAL_GLOBAL_POSITION); // Read last death location
handler(worldDataTrackerHandler(1));
handler(playerTrackerHandler());
}
});
protocol.registerClientbound(ClientboundPackets1_19.RESPAWN, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final String dimensionKey = wrapper.read(Type.STRING);
final CompoundTag dimension = wrapper.user().get(DimensionRegistryStorage.class).dimension(dimensionKey);
if (dimension == null) {
throw new IllegalArgumentException("Could not find dimension " + dimensionKey + " in dimension registry");
}
wrapper.write(Type.NAMED_COMPOUND_TAG, dimension);
});
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous gamemode
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
map(Type.BOOLEAN); // Keep player data
read(Type.OPTIONAL_GLOBAL_POSITION); // Read last death location
handler(worldDataTrackerHandler(0));
}
});
protocol.registerClientbound(ClientboundPackets1_19.PLAYER_INFO, wrapper -> {
final int action = wrapper.passthrough(Type.VAR_INT);
final int entries = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Type.UUID); // UUID
if (action == 0) { // Add player
wrapper.passthrough(Type.STRING); // Player Name
final int properties = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Type.STRING); // Name
wrapper.passthrough(Type.STRING); // Value
wrapper.passthrough(Type.OPTIONAL_STRING); // Signature
}
wrapper.passthrough(Type.VAR_INT); // Gamemode
wrapper.passthrough(Type.VAR_INT); // Ping
wrapper.passthrough(Type.OPTIONAL_COMPONENT); // Display name
// Remove public profile signature
wrapper.read(Type.OPTIONAL_PROFILE_KEY);
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update display name
wrapper.passthrough(Type.OPTIONAL_COMPONENT);
}
}
});
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
if (meta.metaType().typeId() <= Types1_18.META_TYPES.poseType.typeId()) {
meta.setMetaType(Types1_18.META_TYPES.byId(meta.metaType().typeId()));
}
final MetaType type = meta.metaType();
if (type == Types1_18.META_TYPES.particleType) {
final Particle particle = (Particle) meta.getValue();
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (particle.getId() == particleMappings.id("sculk_charge")) {
//TODO
event.cancel();
return;
} else if (particle.getId() == particleMappings.id("shriek")) {
//TODO
event.cancel();
return;
} else if (particle.getId() == particleMappings.id("vibration")) {
// Can't do without the position
event.cancel();
return;
}
rewriteParticle(particle);
} else if (type == Types1_18.META_TYPES.poseType) {
final int pose = meta.value();
if (pose >= 8) {
// Croaking, using_tongue, roaring, sniffing, emerging, digging -> standing -> standing
meta.setValue(0);
}
}
});
registerMetaTypeHandler(Types1_18.META_TYPES.itemType, Types1_18.META_TYPES.blockStateType, null, null,
Types1_18.META_TYPES.componentType, Types1_18.META_TYPES.optionalComponentType);
filter().type(EntityTypes1_19.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
});
filter().type(EntityTypes1_19.PAINTING).index(8).handler((event, meta) -> {
event.cancel();
final StoredEntityData entityData = tracker(event.user()).entityDataIfPresent(event.entityId());
final StoredPainting storedPainting = entityData.remove(StoredPainting.class);
if (storedPainting != null) {
final PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_18.SPAWN_PAINTING, event.user());
packet.write(Type.VAR_INT, storedPainting.entityId());
packet.write(Type.UUID, storedPainting.uuid());
packet.write(Type.VAR_INT, meta.value());
packet.write(Type.POSITION1_14, storedPainting.position());
packet.write(Type.BYTE, storedPainting.direction());
try {
// TODO Race condition
packet.send(Protocol1_18_2To1_19.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
filter().type(EntityTypes1_19.CAT).index(19).handler((event, meta) -> meta.setMetaType(Types1_18.META_TYPES.varIntType));
filter().type(EntityTypes1_19.FROG).cancel(16); // Age
filter().type(EntityTypes1_19.FROG).cancel(17); // Variant
filter().type(EntityTypes1_19.FROG).cancel(18); // Tongue target
filter().type(EntityTypes1_19.WARDEN).cancel(16); // Anger
filter().type(EntityTypes1_19.GOAT).cancel(18);
filter().type(EntityTypes1_19.GOAT).cancel(19);
}
@Override
public void onMappingDataLoaded() {
mapTypes();
mapEntityTypeWithData(EntityTypes1_19.FROG, EntityTypes1_19.RABBIT).jsonName();
mapEntityTypeWithData(EntityTypes1_19.TADPOLE, EntityTypes1_19.PUFFERFISH).jsonName();
mapEntityTypeWithData(EntityTypes1_19.CHEST_BOAT, EntityTypes1_19.BOAT);
mapEntityTypeWithData(EntityTypes1_19.WARDEN, EntityTypes1_19.IRON_GOLEM).jsonName();
mapEntityTypeWithData(EntityTypes1_19.ALLAY, EntityTypes1_19.VEX).jsonName();
}
@Override
public EntityType typeFromId(final int typeId) {
return EntityTypes1_19.getTypeFromId(typeId);
}
}
@@ -1,105 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_18to1_18_2;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.protocol1_18to1_18_2.data.CommandRewriter1_18_2;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.ClientboundPackets1_18;
public final class Protocol1_18To1_18_2 extends BackwardsProtocol<ClientboundPackets1_18, ClientboundPackets1_18, ServerboundPackets1_17, ServerboundPackets1_17> {
public Protocol1_18To1_18_2() {
super(ClientboundPackets1_18.class, ClientboundPackets1_18.class, ServerboundPackets1_17.class, ServerboundPackets1_17.class);
}
@Override
protected void registerPackets() {
new CommandRewriter1_18_2(this).registerDeclareCommands(ClientboundPackets1_18.DECLARE_COMMANDS);
final PacketHandler entityEffectIdHandler = wrapper -> {
final int id = wrapper.read(Type.VAR_INT);
if ((byte) id != id) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
ViaBackwards.getPlatform().getLogger().warning("Cannot send entity effect id " + id + " to old client");
}
wrapper.cancel();
return;
}
wrapper.write(Type.BYTE, (byte) id);
};
registerClientbound(ClientboundPackets1_18.ENTITY_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
handler(entityEffectIdHandler);
}
});
registerClientbound(ClientboundPackets1_18.REMOVE_ENTITY_EFFECT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
handler(entityEffectIdHandler);
}
});
registerClientbound(ClientboundPackets1_18.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity ID
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
map(Type.NAMED_COMPOUND_TAG); // Registry
map(Type.NAMED_COMPOUND_TAG); // Current dimension data
handler(wrapper -> {
final CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
final CompoundTag dimensionsHolder = registry.get("minecraft:dimension_type");
final ListTag dimensions = dimensionsHolder.get("value");
for (final Tag dimension : dimensions) {
removeTagPrefix(((CompoundTag) dimension).get("element"));
}
removeTagPrefix(wrapper.get(Type.NAMED_COMPOUND_TAG, 1));
});
}
});
registerClientbound(ClientboundPackets1_18.RESPAWN, wrapper -> removeTagPrefix(wrapper.passthrough(Type.NAMED_COMPOUND_TAG)));
}
private void removeTagPrefix(CompoundTag tag) {
final Tag infiniburnTag = tag.get("infiniburn");
if (infiniburnTag instanceof StringTag) {
final StringTag infiniburn = (StringTag) infiniburnTag;
infiniburn.setValue(infiniburn.getValue().substring(1));
}
}
}
@@ -1,137 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_1to1_19_3.packets;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ServerboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
import com.viaversion.viaversion.util.Key;
public final class BlockItemPackets1_19_3 extends ItemRewriter<ClientboundPackets1_19_3, ServerboundPackets1_19_1, Protocol1_19_1To1_19_3> {
public BlockItemPackets1_19_3(final Protocol1_19_1To1_19_3 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_ARRAY);
}
@Override
protected void registerPackets() {
final BlockRewriter<ClientboundPackets1_19_3> blockRewriter = BlockRewriter.for1_14(protocol);
blockRewriter.registerBlockAction(ClientboundPackets1_19_3.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19_3.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange(ClientboundPackets1_19_3.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19_3.EFFECT, 1010, 2001);
blockRewriter.registerChunkData1_19(ClientboundPackets1_19_3.CHUNK_DATA, ChunkType1_18::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_19_3.BLOCK_ENTITY_DATA);
registerSetCooldown(ClientboundPackets1_19_3.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19_3.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19_3.SET_SLOT);
registerEntityEquipmentArray(ClientboundPackets1_19_3.ENTITY_EQUIPMENT);
registerAdvancements(ClientboundPackets1_19_3.ADVANCEMENTS);
registerClickWindow1_17_1(ServerboundPackets1_19_1.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_19_3.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_19_1.CREATIVE_INVENTORY_ACTION);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19_3.WINDOW_PROPERTY);
registerSpawnParticle1_19(ClientboundPackets1_19_3.SPAWN_PARTICLE);
protocol.registerClientbound(ClientboundPackets1_19_3.EXPLOSION, new PacketHandlers() {
@Override
public void register() {
map(Type.DOUBLE, Type.FLOAT); // X
map(Type.DOUBLE, Type.FLOAT); // Y
map(Type.DOUBLE, Type.FLOAT); // Z
}
});
final RecipeRewriter<ClientboundPackets1_19_3> recipeRewriter = new RecipeRewriter<>(protocol);
protocol.registerClientbound(ClientboundPackets1_19_3.DECLARE_RECIPES, wrapper -> {
final int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
final String type = Key.stripMinecraftNamespace(wrapper.passthrough(Type.STRING));
wrapper.passthrough(Type.STRING); // Recipe Identifier
switch (type) {
case "crafting_shapeless": {
wrapper.passthrough(Type.STRING); // Group
wrapper.read(Type.VAR_INT); // Crafting book category
final int ingredients = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
}
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // Result
break;
}
case "crafting_shaped": {
final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
wrapper.read(Type.VAR_INT); // Crafting book category
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
}
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // Result
break;
}
case "smelting":
case "campfire_cooking":
case "blasting":
case "smoking":
wrapper.passthrough(Type.STRING); // Group
wrapper.read(Type.VAR_INT); // Crafting book category
final Item[] items = wrapper.passthrough(Type.ITEM1_13_2_ARRAY); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // Result
wrapper.passthrough(Type.FLOAT); // EXP
wrapper.passthrough(Type.VAR_INT); // Cooking time
break;
case "crafting_special_armordye":
case "crafting_special_bookcloning":
case "crafting_special_mapcloning":
case "crafting_special_mapextending":
case "crafting_special_firework_rocket":
case "crafting_special_firework_star":
case "crafting_special_firework_star_fade":
case "crafting_special_tippedarrow":
case "crafting_special_bannerduplicate":
case "crafting_special_shielddecoration":
case "crafting_special_shulkerboxcoloring":
case "crafting_special_suspiciousstew":
case "crafting_special_repairitem":
wrapper.read(Type.VAR_INT); // Crafting book category
break;
default:
recipeRewriter.handleRecipeType(wrapper, type);
break;
}
}
});
}
}
@@ -1,306 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_1to1_19_3.packets;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_1to1_19_3.Protocol1_19_1To1_19_3;
import com.viaversion.viabackwards.protocol.protocol1_19_1to1_19_3.storage.ChatTypeStorage1_19_3;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3;
import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19_3;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.BitSetType;
import com.viaversion.viaversion.api.type.types.version.Types1_19;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3;
import java.util.BitSet;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class EntityPackets1_19_3 extends EntityRewriter<ClientboundPackets1_19_3, Protocol1_19_1To1_19_3> {
private static final BitSetType PROFILE_ACTIONS_ENUM_TYPE = new BitSetType(6);
private static final int[] PROFILE_ACTIONS = {2, 4, 5}; // Ignore initialize chat and listed status; add player already handled before
private static final int ADD_PLAYER = 0;
private static final int INITIALIZE_CHAT = 1;
private static final int UPDATE_GAMEMODE = 2;
private static final int UPDATE_LISTED = 3;
private static final int UPDATE_LATENCY = 4;
private static final int UPDATE_DISPLAYNAME = 5;
public EntityPackets1_19_3(final Protocol1_19_1To1_19_3 protocol) {
super(protocol, Types1_19.META_TYPES.optionalComponentType, Types1_19.META_TYPES.booleanType);
}
@Override
protected void registerPackets() {
registerMetadataRewriter(ClientboundPackets1_19_3.ENTITY_METADATA, Types1_19_3.METADATA_LIST, Types1_19.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_19_3.REMOVE_ENTITIES);
registerTrackerWithData1_19(ClientboundPackets1_19_3.SPAWN_ENTITY, EntityTypes1_19_3.FALLING_BLOCK);
protocol.registerClientbound(ClientboundPackets1_19_3.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
map(Type.NAMED_COMPOUND_TAG); // Dimension registry
map(Type.STRING); // Dimension key
map(Type.STRING); // World
handler(dimensionDataHandler());
handler(biomeSizeTracker());
handler(worldDataTrackerHandlerByKey());
handler(wrapper -> {
final ChatTypeStorage1_19_3 chatTypeStorage = wrapper.user().get(ChatTypeStorage1_19_3.class);
chatTypeStorage.clear();
final CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
final ListTag chatTypes = registry.getCompoundTag("minecraft:chat_type").get("value");
for (final Tag chatType : chatTypes) {
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
final NumberTag idTag = chatTypeCompound.get("id");
chatTypeStorage.addChatType(idTag.asInt(), chatTypeCompound);
}
});
handler(wrapper -> {
final ChatSession1_19_3 chatSession = wrapper.user().get(ChatSession1_19_3.class);
if (chatSession != null) {
final PacketWrapper chatSessionUpdate = wrapper.create(ServerboundPackets1_19_3.CHAT_SESSION_UPDATE);
chatSessionUpdate.write(Type.UUID, chatSession.getSessionId());
chatSessionUpdate.write(Type.PROFILE_KEY, chatSession.getProfileKey());
chatSessionUpdate.sendToServer(Protocol1_19_1To1_19_3.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Dimension
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous gamemode
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
handler(worldDataTrackerHandlerByKey());
handler(wrapper -> {
// Old clients will always keep entity data (packed here as 0x02), nothing we can do there
final byte keepDataMask = wrapper.read(Type.BYTE);
wrapper.write(Type.BOOLEAN, (keepDataMask & 1) != 0); // Keep attributes
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_3.PLAYER_INFO_UPDATE, ClientboundPackets1_19_1.PLAYER_INFO, wrapper -> {
wrapper.cancel();
final BitSet actions = wrapper.read(PROFILE_ACTIONS_ENUM_TYPE);
final int entries = wrapper.read(Type.VAR_INT);
if (actions.get(ADD_PLAYER)) {
// Special case, as we need to write everything into one action
final PacketWrapper playerInfoPacket = wrapper.create(ClientboundPackets1_19_1.PLAYER_INFO);
playerInfoPacket.write(Type.VAR_INT, 0);
playerInfoPacket.write(Type.VAR_INT, entries);
for (int i = 0; i < entries; i++) {
playerInfoPacket.write(Type.UUID, wrapper.read(Type.UUID));
playerInfoPacket.write(Type.STRING, wrapper.read(Type.STRING)); // Player Name
final int properties = wrapper.read(Type.VAR_INT);
playerInfoPacket.write(Type.VAR_INT, properties);
for (int j = 0; j < properties; j++) {
playerInfoPacket.write(Type.STRING, wrapper.read(Type.STRING)); // Name
playerInfoPacket.write(Type.STRING, wrapper.read(Type.STRING)); // Value
playerInfoPacket.write(Type.OPTIONAL_STRING, wrapper.read(Type.OPTIONAL_STRING)); // Signature
}
// Now check for the other parts individually and add dummy values if not present
final ProfileKey profileKey;
if (actions.get(INITIALIZE_CHAT) && wrapper.read(Type.BOOLEAN)) {
wrapper.read(Type.UUID); // Session UUID
profileKey = wrapper.read(Type.PROFILE_KEY);
} else {
profileKey = null;
}
final int gamemode = actions.get(UPDATE_GAMEMODE) ? wrapper.read(Type.VAR_INT) : 0;
if (actions.get(UPDATE_LISTED)) {
wrapper.read(Type.BOOLEAN); // Listed - throw away
}
final int latency = actions.get(UPDATE_LATENCY) ? wrapper.read(Type.VAR_INT) : 0;
final JsonElement displayName = actions.get(UPDATE_DISPLAYNAME) ? wrapper.read(Type.OPTIONAL_COMPONENT) : null;
playerInfoPacket.write(Type.VAR_INT, gamemode);
playerInfoPacket.write(Type.VAR_INT, latency);
playerInfoPacket.write(Type.OPTIONAL_COMPONENT, displayName);
playerInfoPacket.write(Type.OPTIONAL_PROFILE_KEY, profileKey);
}
playerInfoPacket.send(Protocol1_19_1To1_19_3.class);
return;
}
final PlayerProfileUpdate[] updates = new PlayerProfileUpdate[entries];
for (int i = 0; i < entries; i++) {
final UUID uuid = wrapper.read(Type.UUID);
int gamemode = 0;
int latency = 0;
JsonElement displayName = null;
for (final int action : PROFILE_ACTIONS) {
if (!actions.get(action)) {
continue;
}
switch (action) {
case UPDATE_GAMEMODE:
gamemode = wrapper.read(Type.VAR_INT);
break;
case UPDATE_LATENCY:
latency = wrapper.read(Type.VAR_INT);
break;
case UPDATE_DISPLAYNAME:
displayName = wrapper.read(Type.OPTIONAL_COMPONENT);
break;
}
}
updates[i] = new PlayerProfileUpdate(uuid, gamemode, latency, displayName);
}
if (actions.get(UPDATE_GAMEMODE)) {
sendPlayerProfileUpdate(wrapper.user(), 1, updates);
} else if (actions.get(UPDATE_LATENCY)) {
sendPlayerProfileUpdate(wrapper.user(), 2, updates);
} else if (actions.get(UPDATE_DISPLAYNAME)) {
sendPlayerProfileUpdate(wrapper.user(), 3, updates);
}
});
protocol.registerClientbound(ClientboundPackets1_19_3.PLAYER_INFO_REMOVE, ClientboundPackets1_19_1.PLAYER_INFO, wrapper -> {
final UUID[] uuids = wrapper.read(Type.UUID_ARRAY);
wrapper.write(Type.VAR_INT, 4); // Remove player
wrapper.write(Type.VAR_INT, uuids.length);
for (final UUID uuid : uuids) {
wrapper.write(Type.UUID, uuid);
}
});
}
private void sendPlayerProfileUpdate(final UserConnection connection, final int action, final PlayerProfileUpdate[] updates) throws Exception {
final PacketWrapper playerInfoPacket = PacketWrapper.create(ClientboundPackets1_19_1.PLAYER_INFO, connection);
playerInfoPacket.write(Type.VAR_INT, action);
playerInfoPacket.write(Type.VAR_INT, updates.length);
for (final PlayerProfileUpdate update : updates) {
playerInfoPacket.write(Type.UUID, update.uuid());
if (action == 1) {
playerInfoPacket.write(Type.VAR_INT, update.gamemode());
} else if (action == 2) {
playerInfoPacket.write(Type.VAR_INT, update.latency());
} else if (action == 3) {
playerInfoPacket.write(Type.OPTIONAL_COMPONENT, update.displayName());
} else {
throw new IllegalArgumentException("Invalid action: " + action);
}
}
playerInfoPacket.send(Protocol1_19_1To1_19_3.class);
}
@Override
public void registerRewrites() {
filter().handler((event, meta) -> {
final int id = meta.metaType().typeId();
if (id > 2) {
meta.setMetaType(Types1_19.META_TYPES.byId(id - 1)); // long added
} else if (id != 2) {
meta.setMetaType(Types1_19.META_TYPES.byId(id));
}
});
registerMetaTypeHandler(Types1_19.META_TYPES.itemType, Types1_19.META_TYPES.blockStateType, null, Types1_19.META_TYPES.particleType,
Types1_19.META_TYPES.componentType, Types1_19.META_TYPES.optionalComponentType);
filter().index(6).handler((event, meta) -> {
// Sitting pose added
final int pose = meta.value();
if (pose == 10) {
meta.setValue(0); // Standing
} else if (pose > 10) {
meta.setValue(pose - 1);
}
});
filter().type(EntityTypes1_19_3.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
});
filter().type(EntityTypes1_19_3.CAMEL).cancel(19); // Dashing
filter().type(EntityTypes1_19_3.CAMEL).cancel(20); // Last pose change time
}
@Override
public void onMappingDataLoaded() {
mapTypes();
mapEntityTypeWithData(EntityTypes1_19_3.CAMEL, EntityTypes1_19_3.DONKEY).jsonName();
}
@Override
public EntityType typeFromId(final int typeId) {
return EntityTypes1_19_3.getTypeFromId(typeId);
}
private static final class PlayerProfileUpdate {
private final UUID uuid;
private final int gamemode;
private final int latency;
private final JsonElement displayName;
private PlayerProfileUpdate(final UUID uuid, final int gamemode, final int latency, @Nullable final JsonElement displayName) {
this.uuid = uuid;
this.gamemode = gamemode;
this.latency = latency;
this.displayName = displayName;
}
public UUID uuid() {
return uuid;
}
public int gamemode() {
return gamemode;
}
public int latency() {
return latency;
}
public @Nullable JsonElement displayName() {
return displayName;
}
}
}
@@ -1,142 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_3to1_19_4;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.packets.BlockItemPackets1_19_4;
import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.packets.EntityPackets1_19_4;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.Protocol1_19_4To1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public final class Protocol1_19_3To1_19_4 extends BackwardsProtocol<ClientboundPackets1_19_4, ClientboundPackets1_19_3, ServerboundPackets1_19_4, ServerboundPackets1_19_3> {
public static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.19.4", "1.19.3", Protocol1_19_4To1_19_3.class);
private final EntityPackets1_19_4 entityRewriter = new EntityPackets1_19_4(this);
private final BlockItemPackets1_19_4 itemRewriter = new BlockItemPackets1_19_4(this);
private final TranslatableRewriter<ClientboundPackets1_19_4> translatableRewriter = new TranslatableRewriter<>(this, ComponentRewriter.ReadType.JSON);
public Protocol1_19_3To1_19_4() {
super(ClientboundPackets1_19_4.class, ClientboundPackets1_19_3.class, ServerboundPackets1_19_4.class, ServerboundPackets1_19_3.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
final SoundRewriter<ClientboundPackets1_19_4> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerStopSound(ClientboundPackets1_19_4.STOP_SOUND);
soundRewriter.register1_19_3Sound(ClientboundPackets1_19_4.SOUND);
soundRewriter.registerSound(ClientboundPackets1_19_4.ENTITY_SOUND);
// TODO fallback field in components
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.ACTIONBAR);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.TITLE_TEXT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.TITLE_SUBTITLE);
translatableRewriter.registerBossBar(ClientboundPackets1_19_4.BOSSBAR);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISCONNECT);
translatableRewriter.registerTabList(ClientboundPackets1_19_4.TAB_LIST);
translatableRewriter.registerCombatKill(ClientboundPackets1_19_4.COMBAT_KILL);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.SYSTEM_CHAT);
translatableRewriter.registerComponentPacket(ClientboundPackets1_19_4.DISGUISED_CHAT);
translatableRewriter.registerPing();
new CommandRewriter<ClientboundPackets1_19_4>(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception {
switch (argumentType) {
case "minecraft:heightmap":
wrapper.write(Type.VAR_INT, 0);
break;
case "minecraft:time":
wrapper.read(Type.INT); // Minimum
break;
case "minecraft:resource":
case "minecraft:resource_or_tag":
final String resource = wrapper.read(Type.STRING);
// Replace damage types with... something
wrapper.write(Type.STRING, resource.equals("minecraft:damage_type") ? "minecraft:mob_effect" : resource);
break;
default:
super.handleArgument(wrapper, argumentType);
break;
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_19_4.DECLARE_COMMANDS);
final TagRewriter<ClientboundPackets1_19_4> tagRewriter = new TagRewriter<>(this);
tagRewriter.removeTags("minecraft:damage_type");
tagRewriter.registerGeneric(ClientboundPackets1_19_4.TAGS);
new StatisticsRewriter<>(this).register(ClientboundPackets1_19_4.STATISTICS);
registerClientbound(ClientboundPackets1_19_4.SERVER_DATA, wrapper -> {
final JsonElement element = wrapper.read(Type.COMPONENT);
wrapper.write(Type.OPTIONAL_COMPONENT, element);
final byte[] iconBytes = wrapper.read(Type.OPTIONAL_BYTE_ARRAY_PRIMITIVE);
final String iconBase64 = iconBytes != null ? "data:image/png;base64," + new String(Base64.getEncoder().encode(iconBytes), StandardCharsets.UTF_8) : null;
wrapper.write(Type.OPTIONAL_STRING, iconBase64);
});
cancelClientbound(ClientboundPackets1_19_4.BUNDLE);
cancelClientbound(ClientboundPackets1_19_4.CHUNK_BIOMES); // We definitely do not want to cache every single chunk just to resent them with new biomes
}
@Override
public void init(final UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_19_4.PLAYER));
}
@Override
public BackwardsMappings getMappingData() {
return MAPPINGS;
}
@Override
public BlockItemPackets1_19_4 getItemRewriter() {
return itemRewriter;
}
@Override
public EntityPackets1_19_4 getEntityRewriter() {
return entityRewriter;
}
@Override
public TranslatableRewriter<ClientboundPackets1_19_4> getTranslatableRewriter() {
return translatableRewriter;
}
}
@@ -1,124 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_3to1_19_4.packets;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.Protocol1_19_3To1_19_4;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.rewriter.RecipeRewriter1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.util.Key;
public final class BlockItemPackets1_19_4 extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_19_3, Protocol1_19_3To1_19_4> {
public BlockItemPackets1_19_4(final Protocol1_19_3To1_19_4 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_ARRAY);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPackets1_19_4> blockRewriter = BlockRewriter.for1_14(protocol);
blockRewriter.registerBlockAction(ClientboundPackets1_19_4.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19_4.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange(ClientboundPackets1_19_4.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19_4.EFFECT, 1010, 2001);
blockRewriter.registerChunkData1_19(ClientboundPackets1_19_4.CHUNK_DATA, ChunkType1_18::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_19_4.BLOCK_ENTITY_DATA);
protocol.registerClientbound(ClientboundPackets1_19_4.OPEN_WINDOW, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Container id
map(Type.VAR_INT); // Container type
map(Type.COMPONENT); // Title
handler(wrapper -> {
final int windowType = wrapper.get(Type.VAR_INT, 1);
if (windowType == 21) { // New smithing menu
wrapper.cancel();
} else if (windowType > 21) {
wrapper.set(Type.VAR_INT, 1, windowType - 1);
}
protocol.getTranslatableRewriter().processText(wrapper.get(Type.COMPONENT, 0));
});
}
});
registerSetCooldown(ClientboundPackets1_19_4.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19_4.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19_4.SET_SLOT);
registerAdvancements(ClientboundPackets1_19_4.ADVANCEMENTS);
registerEntityEquipmentArray(ClientboundPackets1_19_4.ENTITY_EQUIPMENT);
registerClickWindow1_17_1(ServerboundPackets1_19_3.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_19_4.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_19_3.CREATIVE_INVENTORY_ACTION);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19_4.WINDOW_PROPERTY);
registerSpawnParticle1_19(ClientboundPackets1_19_4.SPAWN_PARTICLE);
final RecipeRewriter1_19_3<ClientboundPackets1_19_4> recipeRewriter = new RecipeRewriter1_19_3<ClientboundPackets1_19_4>(protocol) {
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) throws Exception {
final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
for (int i = 0; i < ingredients; i++) {
handleIngredient(wrapper);
}
rewrite(wrapper.passthrough(Type.ITEM1_13_2)); // Result
// Remove notification boolean
wrapper.read(Type.BOOLEAN);
}
};
protocol.registerClientbound(ClientboundPackets1_19_4.DECLARE_RECIPES, wrapper -> {
final int size = wrapper.passthrough(Type.VAR_INT);
int newSize = size;
for (int i = 0; i < size; i++) {
final String type = wrapper.read(Type.STRING);
final String cutType = Key.stripMinecraftNamespace(type);
if (cutType.equals("smithing_transform") || cutType.equals("smithing_trim")) {
newSize--;
wrapper.read(Type.STRING); // Recipe identifier
wrapper.read(Type.ITEM1_13_2_ARRAY); // Template
wrapper.read(Type.ITEM1_13_2_ARRAY); // Base
wrapper.read(Type.ITEM1_13_2_ARRAY); // Additions
if (cutType.equals("smithing_transform")) {
wrapper.read(Type.ITEM1_13_2); // Result
}
continue;
} else if (cutType.equals("crafting_decorated_pot")) {
newSize--;
wrapper.read(Type.STRING); // Recipe identifier
wrapper.read(Type.VAR_INT); // Crafting book category
continue;
}
wrapper.write(Type.STRING, type);
wrapper.passthrough(Type.STRING); // Recipe Identifier
recipeRewriter.handleRecipeType(wrapper, cutType);
}
wrapper.set(Type.VAR_INT, 0, newSize);
});
}
}
@@ -1,209 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_3to1_19_4.packets;
import com.viaversion.viabackwards.api.entities.storage.EntityData;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_3to1_19_4.Protocol1_19_3To1_19_4;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.api.type.types.version.Types1_19_4;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
public final class EntityPackets1_19_4 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_19_3To1_19_4> {
public EntityPackets1_19_4(final Protocol1_19_3To1_19_4 protocol) {
super(protocol, Types1_19_3.META_TYPES.optionalComponentType, Types1_19_3.META_TYPES.booleanType);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_19_4.SPAWN_ENTITY, EntityTypes1_19_4.FALLING_BLOCK);
registerRemoveEntities(ClientboundPackets1_19_4.REMOVE_ENTITIES);
registerMetadataRewriter(ClientboundPackets1_19_4.ENTITY_METADATA, Types1_19_4.METADATA_LIST, Types1_19_3.METADATA_LIST);
protocol.registerClientbound(ClientboundPackets1_19_4.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
map(Type.NAMED_COMPOUND_TAG); // Dimension registry
map(Type.STRING); // Dimension key
map(Type.STRING); // World
handler(dimensionDataHandler());
handler(biomeSizeTracker());
handler(worldDataTrackerHandlerByKey());
handler(wrapper -> {
final CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
registry.remove("minecraft:trim_pattern");
registry.remove("minecraft:trim_material");
registry.remove("minecraft:damage_type");
final CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
final ListTag biomes = biomeRegistry.get("value");
for (final Tag biomeTag : biomes) {
final CompoundTag biomeData = ((CompoundTag) biomeTag).get("element");
final NumberTag hasPrecipitation = biomeData.get("has_precipitation");
biomeData.putString("precipitation", hasPrecipitation.asByte() == 1 ? "rain" : "none");
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.PLAYER_POSITION, new PacketHandlers() {
@Override
protected void register() {
map(Type.DOUBLE); // X
map(Type.DOUBLE); // Y
map(Type.DOUBLE); // Z
map(Type.FLOAT); // Yaw
map(Type.FLOAT); // Pitch
map(Type.BYTE); // Relative arguments
map(Type.VAR_INT); // Id
create(Type.BOOLEAN, false); // Dismount vehicle
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.DAMAGE_EVENT, ClientboundPackets1_19_3.ENTITY_STATUS, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT, Type.INT); // Entity id
read(Type.VAR_INT); // Damage type
read(Type.VAR_INT); // Cause entity
read(Type.VAR_INT); // Direct cause entity
handler(wrapper -> {
// Source position
if (wrapper.read(Type.BOOLEAN)) {
wrapper.read(Type.DOUBLE);
wrapper.read(Type.DOUBLE);
wrapper.read(Type.DOUBLE);
}
});
create(Type.BYTE, (byte) 2); // Generic hurt
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.HIT_ANIMATION, ClientboundPackets1_19_3.ENTITY_ANIMATION, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Entity id
read(Type.FLOAT); // Yaw
create(Type.UNSIGNED_BYTE, (short) 1); // Hit
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Dimension
map(Type.STRING); // World
handler(worldDataTrackerHandlerByKey());
}
});
}
@Override
public void registerRewrites() {
filter().handler((event, meta) -> {
int id = meta.metaType().typeId();
if (id >= 25) { // Sniffer state, Vector3f, Quaternion types
return;
} else if (id >= 15) { // Optional block state - just map down to block state
id--;
}
meta.setMetaType(Types1_19_3.META_TYPES.byId(id));
});
registerMetaTypeHandler(Types1_19_3.META_TYPES.itemType, Types1_19_3.META_TYPES.blockStateType, null, Types1_19_3.META_TYPES.particleType,
Types1_19_3.META_TYPES.componentType, Types1_19_3.META_TYPES.optionalComponentType);
filter().type(EntityTypes1_19_4.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int blockState = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
});
filter().type(EntityTypes1_19_4.BOAT).index(11).handler((event, meta) -> {
final int boatType = meta.value();
if (boatType > 4) { // Cherry
meta.setValue(boatType - 1);
}
});
filter().type(EntityTypes1_19_4.TEXT_DISPLAY).index(22).handler(((event, meta) -> {
// Send as custom display name
event.setIndex(2);
meta.setMetaType(Types1_19_3.META_TYPES.optionalComponentType);
event.createExtraMeta(new Metadata(3, Types1_19_3.META_TYPES.booleanType, true)); // Show custom name
final JsonElement element = meta.value();
protocol.getTranslatableRewriter().processText(element);
}));
filter().type(EntityTypes1_19_4.DISPLAY).handler((event, meta) -> {
// TODO Maybe spawn an extra entity to ride the armor stand for blocks and items
// Remove a large heap of display metadata
if (event.index() > 7) {
event.cancel();
}
});
filter().type(EntityTypes1_19_4.INTERACTION).removeIndex(8); // Width
filter().type(EntityTypes1_19_4.INTERACTION).removeIndex(9); // Height
filter().type(EntityTypes1_19_4.INTERACTION).removeIndex(10); // Response
filter().type(EntityTypes1_19_4.SNIFFER).removeIndex(17); // State
filter().type(EntityTypes1_19_4.SNIFFER).removeIndex(18); // Drop seed at tick
filter().type(EntityTypes1_19_4.ABSTRACT_HORSE).addIndex(18); // Owner UUID
}
@Override
public void onMappingDataLoaded() {
mapTypes();
final EntityData.MetaCreator displayMetaCreator = storage -> {
storage.add(new Metadata(0, Types1_19_3.META_TYPES.byteType, (byte) 0x20)); // Invisible
storage.add(new Metadata(5, Types1_19_3.META_TYPES.booleanType, true)); // No gravity
storage.add(new Metadata(15, Types1_19_3.META_TYPES.byteType, (byte) (0x01 | 0x10))); // Small marker
};
mapEntityTypeWithData(EntityTypes1_19_4.TEXT_DISPLAY, EntityTypes1_19_4.ARMOR_STAND).spawnMetadata(displayMetaCreator);
mapEntityTypeWithData(EntityTypes1_19_4.ITEM_DISPLAY, EntityTypes1_19_4.ARMOR_STAND).spawnMetadata(displayMetaCreator);
mapEntityTypeWithData(EntityTypes1_19_4.BLOCK_DISPLAY, EntityTypes1_19_4.ARMOR_STAND).spawnMetadata(displayMetaCreator);
mapEntityTypeWithData(EntityTypes1_19_4.INTERACTION, EntityTypes1_19_4.ARMOR_STAND).spawnMetadata(displayMetaCreator); // Not much we can do about this one
mapEntityTypeWithData(EntityTypes1_19_4.SNIFFER, EntityTypes1_19_4.RAVAGER).jsonName();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_19_4.getTypeFromId(type);
}
}
@@ -1,232 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_4to1_20.packets;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_4to1_20.Protocol1_19_4To1_20;
import com.viaversion.viabackwards.protocol.protocol1_19_4to1_20.storage.BackSignEditStorage;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.rewriter.RecipeRewriter1_19_4;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.util.Key;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class BlockItemPackets1_20 extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_19_4, Protocol1_19_4To1_20> {
private static final Set<String> NEW_TRIM_PATTERNS = new HashSet<>(Arrays.asList("host", "raiser", "shaper", "silence", "wayfinder"));
public BlockItemPackets1_20(final Protocol1_19_4To1_20 protocol) {
super(protocol, Type.ITEM1_13_2, Type.ITEM1_13_2_ARRAY);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPackets1_19_4> blockRewriter = BlockRewriter.for1_14(protocol);
blockRewriter.registerBlockAction(ClientboundPackets1_19_4.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19_4.BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19_4.EFFECT, 1010, 2001);
blockRewriter.registerBlockEntityData(ClientboundPackets1_19_4.BLOCK_ENTITY_DATA, this::handleBlockEntity);
protocol.registerClientbound(ClientboundPackets1_19_4.CHUNK_DATA, new PacketHandlers() {
@Override
protected void register() {
handler(blockRewriter.chunkDataHandler1_19(ChunkType1_18::new, BlockItemPackets1_20.this::handleBlockEntity));
create(Type.BOOLEAN, true); // Trust edges
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.UPDATE_LIGHT, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // X
wrapper.passthrough(Type.VAR_INT); // Y
wrapper.write(Type.BOOLEAN, true); // Trust edges
});
protocol.registerClientbound(ClientboundPackets1_19_4.MULTI_BLOCK_CHANGE, new PacketHandlers() {
@Override
public void register() {
map(Type.LONG); // Chunk position
create(Type.BOOLEAN, false); // Suppress light updates
handler(wrapper -> {
for (final BlockChangeRecord record : wrapper.passthrough(Type.VAR_LONG_BLOCK_CHANGE_RECORD_ARRAY)) {
record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId()));
}
});
}
});
registerOpenWindow(ClientboundPackets1_19_4.OPEN_WINDOW);
registerSetCooldown(ClientboundPackets1_19_4.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19_4.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19_4.SET_SLOT);
registerEntityEquipmentArray(ClientboundPackets1_19_4.ENTITY_EQUIPMENT);
registerClickWindow1_17_1(ServerboundPackets1_19_4.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_19_4.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_19_4.CREATIVE_INVENTORY_ACTION);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19_4.WINDOW_PROPERTY);
registerSpawnParticle1_19(ClientboundPackets1_19_4.SPAWN_PARTICLE);
protocol.registerClientbound(ClientboundPackets1_19_4.ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN))
wrapper.passthrough(Type.STRING);
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT); // Title
wrapper.passthrough(Type.COMPONENT); // Description
handleItemToClient(wrapper.passthrough(Type.ITEM1_13_2)); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
wrapper.passthrough(Type.STRING_ARRAY); // Criteria
int arrayLength = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Type.STRING_ARRAY); // String array
}
wrapper.read(Type.BOOLEAN); // Sends telemetry
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.OPEN_SIGN_EDITOR, wrapper -> {
final Position position = wrapper.passthrough(Type.POSITION1_14);
final boolean frontSide = wrapper.read(Type.BOOLEAN);
if (frontSide) {
wrapper.user().remove(BackSignEditStorage.class);
} else {
wrapper.user().put(new BackSignEditStorage(position));
}
});
protocol.registerServerbound(ServerboundPackets1_19_4.UPDATE_SIGN, wrapper -> {
final Position position = wrapper.passthrough(Type.POSITION1_14);
final BackSignEditStorage backSignEditStorage = wrapper.user().remove(BackSignEditStorage.class);
final boolean frontSide = backSignEditStorage == null || !backSignEditStorage.position().equals(position);
wrapper.write(Type.BOOLEAN, frontSide);
});
new RecipeRewriter1_19_4<>(protocol).register(ClientboundPackets1_19_4.DECLARE_RECIPES);
}
@Override
public @Nullable Item handleItemToClient(@Nullable final Item item) {
if (item == null) {
return null;
}
super.handleItemToClient(item);
// Remove new trim tags
final CompoundTag trimTag;
final CompoundTag tag = item.tag();
if (tag != null && (trimTag = tag.getCompoundTag("Trim")) != null) {
final StringTag patternTag = trimTag.getStringTag("pattern");
if (patternTag != null) {
final String pattern = Key.stripMinecraftNamespace(patternTag.getValue());
if (NEW_TRIM_PATTERNS.contains(pattern)) {
tag.remove("Trim");
tag.put(nbtTagName + "|Trim", trimTag);
}
}
}
return item;
}
@Override
public @Nullable Item handleItemToServer(@Nullable final Item item) {
if (item == null) {
return null;
}
super.handleItemToServer(item);
// Add back original trim tag
final Tag trimTag;
final CompoundTag tag = item.tag();
if (tag != null && (trimTag = tag.remove(nbtTagName + "|Trim")) != null) {
tag.put("Trim", trimTag);
}
return item;
}
private void handleBlockEntity(final BlockEntity blockEntity) {
// Check for signs
if (blockEntity.typeId() != 7 && blockEntity.typeId() != 8) {
return;
}
final CompoundTag tag = blockEntity.tag();
final Tag frontText = tag.remove("front_text");
tag.remove("back_text");
if (frontText instanceof CompoundTag) {
final CompoundTag frontTextTag = (CompoundTag) frontText;
writeMessages(frontTextTag, tag, false);
writeMessages(frontTextTag, tag, true);
final Tag color = frontTextTag.remove("color");
if (color != null) {
tag.put("Color", color);
}
final Tag glowing = frontTextTag.remove("has_glowing_text");
if (glowing != null) {
tag.put("GlowingText", glowing);
}
}
}
private void writeMessages(final CompoundTag frontText, final CompoundTag tag, final boolean filtered) {
final ListTag messages = frontText.getListTag(filtered ? "filtered_messages" : "messages");
if (messages == null) {
return;
}
int i = 0;
for (final Tag message : messages) {
tag.put((filtered ? "FilteredText" : "Text") + ++i, message);
}
}
}
@@ -1,159 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_19_4to1_20.packets;
import com.google.common.collect.Sets;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_19_4to1_20.Protocol1_19_4To1_20;
import com.viaversion.viaversion.api.minecraft.Quaternion;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4;
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_19_4;
import com.viaversion.viaversion.api.type.types.version.Types1_20;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.util.Key;
import java.util.Set;
public final class EntityPackets1_20 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_19_4To1_20> {
private final Set<String> newTrimPatterns = Sets.newHashSet("host_armor_trim_smithing_template", "raiser_armor_trim_smithing_template",
"silence_armor_trim_smithing_template", "shaper_armor_trim_smithing_template", "wayfinder_armor_trim_smithing_template");
private static final Quaternion Y_FLIPPED_ROTATION = new Quaternion(0, 1, 0, 0);
public EntityPackets1_20(final Protocol1_19_4To1_20 protocol) {
super(protocol, Types1_19_4.META_TYPES.optionalComponentType, Types1_19_4.META_TYPES.booleanType);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_19_4.SPAWN_ENTITY, EntityTypes1_19_4.FALLING_BLOCK);
registerMetadataRewriter(ClientboundPackets1_19_4.ENTITY_METADATA, Types1_20.METADATA_LIST, Types1_19_4.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_19_4.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_19_4.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
map(Type.BOOLEAN); // Hardcore
map(Type.BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
map(Type.NAMED_COMPOUND_TAG); // Dimension registry
map(Type.STRING); // Dimension key
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.VAR_INT); // Max players
map(Type.VAR_INT); // Chunk radius
map(Type.VAR_INT); // Simulation distance
map(Type.BOOLEAN); // Reduced debug info
map(Type.BOOLEAN); // Show death screen
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
map(Type.OPTIONAL_GLOBAL_POSITION); // Last death location
read(Type.VAR_INT); // Portal cooldown
handler(dimensionDataHandler()); // Caches dimensions to access data like height later
handler(biomeSizeTracker()); // Tracks the amount of biomes sent for chunk data
handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking
handler(wrapper -> {
final CompoundTag registry = wrapper.get(Type.NAMED_COMPOUND_TAG, 0);
final ListTag values;
// A 1.20 server can't send this element, and the 1.20 client still works, if the element is missing
// on a 1.19.4 client there is an exception, so in case the 1.20 server doesn't send the element we put in an original 1.20 element
final CompoundTag trimPatternTag = registry.getCompoundTag("minecraft:trim_pattern");
if (trimPatternTag != null) {
values = trimPatternTag.getListTag("value");
} else {
final CompoundTag trimPatternRegistry = Protocol1_19_4To1_20.MAPPINGS.getTrimPatternRegistry().copy();
registry.put("minecraft:trim_pattern", trimPatternRegistry);
values = trimPatternRegistry.get("value");
}
for (final Tag entry : values) {
final CompoundTag element = ((CompoundTag) entry).get("element");
final StringTag templateItem = element.get("template_item");
if (newTrimPatterns.contains(Key.stripMinecraftNamespace(templateItem.getValue()))) {
templateItem.setValue("minecraft:spire_armor_trim_smithing_template");
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Dimension
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous gamemode
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
map(Type.BYTE); // Data to keep
map(Type.OPTIONAL_GLOBAL_POSITION); // Last death location
read(Type.VAR_INT); // Portal cooldown
handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking
}
});
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> meta.setMetaType(Types1_19_4.META_TYPES.byId(meta.metaType().typeId())));
registerMetaTypeHandler(Types1_19_4.META_TYPES.itemType, Types1_19_4.META_TYPES.blockStateType, Types1_19_4.META_TYPES.optionalBlockStateType,
Types1_19_4.META_TYPES.particleType, Types1_19_4.META_TYPES.componentType, Types1_19_4.META_TYPES.optionalComponentType);
filter().type(EntityTypes1_19_4.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int blockState = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
});
// Rotate item display by 180 degrees around the Y axis
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).handler((event, meta) -> {
if (event.trackedEntity().hasSentMetadata() || event.hasExtraMeta()) {
return;
}
if (event.metaAtIndex(12) == null) {
event.createExtraMeta(new Metadata(12, Types1_19_4.META_TYPES.quaternionType, Y_FLIPPED_ROTATION));
}
});
filter().type(EntityTypes1_19_4.ITEM_DISPLAY).index(12).handler((event, meta) -> {
final Quaternion quaternion = meta.value();
meta.setValue(rotateY180(quaternion));
});
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_19_4.getTypeFromId(type);
}
private Quaternion rotateY180(final Quaternion quaternion) {
return new Quaternion(-quaternion.z(), quaternion.w(), quaternion.x(), -quaternion.y());
}
}
@@ -1,415 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_20_2to1_20_3;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappings;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.rewriter.BlockItemPacketRewriter1_20_3;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.rewriter.EntityPacketRewriter1_20_3;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.storage.ResourcepackIDStorage;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.storage.SpawnPositionStorage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_3;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.fastutil.Pair;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.rewriter.CommandRewriter1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.Protocol1_20_3To1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundConfigurationPackets1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ServerboundPackets1_20_3;
import com.viaversion.viaversion.rewriter.ComponentRewriter.ReadType;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.ComponentUtil;
import java.util.BitSet;
import java.util.UUID;
public final class Protocol1_20_2To1_20_3 extends BackwardsProtocol<ClientboundPackets1_20_3, ClientboundPackets1_20_2, ServerboundPackets1_20_3, ServerboundPackets1_20_2> {
public static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.20.3", "1.20.2", Protocol1_20_3To1_20_2.class);
private final EntityPacketRewriter1_20_3 entityRewriter = new EntityPacketRewriter1_20_3(this);
private final BlockItemPacketRewriter1_20_3 itemRewriter = new BlockItemPacketRewriter1_20_3(this);
private final TranslatableRewriter<ClientboundPackets1_20_3> translatableRewriter = new TranslatableRewriter<>(this, ReadType.NBT);
public Protocol1_20_2To1_20_3() {
super(ClientboundPackets1_20_3.class, ClientboundPackets1_20_2.class, ServerboundPackets1_20_3.class, ServerboundPackets1_20_2.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
final TagRewriter<ClientboundPackets1_20_3> tagRewriter = new TagRewriter<>(this);
tagRewriter.registerGeneric(ClientboundPackets1_20_3.TAGS);
final SoundRewriter<ClientboundPackets1_20_3> soundRewriter = new SoundRewriter<>(this);
soundRewriter.register1_19_3Sound(ClientboundPackets1_20_3.SOUND);
soundRewriter.registerEntitySound(ClientboundPackets1_20_3.ENTITY_SOUND);
soundRewriter.registerStopSound(ClientboundPackets1_20_3.STOP_SOUND);
new StatisticsRewriter<>(this).register(ClientboundPackets1_20_3.STATISTICS);
new CommandRewriter1_19_4<ClientboundPackets1_20_3>(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception {
if (argumentType.equals("minecraft:style")) {
wrapper.write(Type.VAR_INT, 1); // Phrase
} else {
super.handleArgument(wrapper, argumentType);
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_20_3.DECLARE_COMMANDS);
registerClientbound(ClientboundPackets1_20_3.RESET_SCORE, ClientboundPackets1_20_2.UPDATE_SCORE, wrapper -> {
wrapper.passthrough(Type.STRING); // Owner
wrapper.write(Type.VAR_INT, 1); // Reset score
final String objectiveName = wrapper.read(Type.OPTIONAL_STRING);
wrapper.write(Type.STRING, objectiveName != null ? objectiveName : ""); // Objective name
});
registerClientbound(ClientboundPackets1_20_3.UPDATE_SCORE, wrapper -> {
wrapper.passthrough(Type.STRING); // Owner
wrapper.write(Type.VAR_INT, 0); // Change score
wrapper.passthrough(Type.STRING); // Objective name
wrapper.passthrough(Type.VAR_INT); // Score
// Remove display and number format
wrapper.clearInputBuffer();
});
registerClientbound(ClientboundPackets1_20_3.SCOREBOARD_OBJECTIVE, wrapper -> {
wrapper.passthrough(Type.STRING); // Objective Name
final byte action = wrapper.passthrough(Type.BYTE); // Method
if (action == 0 || action == 2) {
convertComponent(wrapper); // Display Name
wrapper.passthrough(Type.VAR_INT); // Render type
// Remove number format
wrapper.clearInputBuffer();
}
});
cancelClientbound(ClientboundPackets1_20_3.TICKING_STATE);
cancelClientbound(ClientboundPackets1_20_3.TICKING_STEP);
registerServerbound(ServerboundPackets1_20_2.UPDATE_JIGSAW_BLOCK, wrapper -> {
wrapper.passthrough(Type.POSITION1_14); // Position
wrapper.passthrough(Type.STRING); // Name
wrapper.passthrough(Type.STRING); // Target
wrapper.passthrough(Type.STRING); // Pool
wrapper.passthrough(Type.STRING); // Final state
wrapper.passthrough(Type.STRING); // Joint type
wrapper.write(Type.VAR_INT, 0); // Selection priority
wrapper.write(Type.VAR_INT, 0); // Placement priority
});
// Components are now (mostly) written as nbt instead of json strings
registerClientbound(ClientboundPackets1_20_3.ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.STRING);
}
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
convertComponent(wrapper); // Title
convertComponent(wrapper); // Description
itemRewriter.handleItemToClient(wrapper.passthrough(Type.ITEM1_20_2)); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Type.INT);
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
final int requirements = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < requirements; array++) {
wrapper.passthrough(Type.STRING_ARRAY);
}
wrapper.passthrough(Type.BOOLEAN); // Send telemetry
}
});
registerClientbound(ClientboundPackets1_20_3.TAB_COMPLETE, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Transaction id
wrapper.passthrough(Type.VAR_INT); // Start
wrapper.passthrough(Type.VAR_INT); // Length
final int suggestions = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < suggestions; i++) {
wrapper.passthrough(Type.STRING); // Suggestion
convertOptionalComponent(wrapper); // Tooltip
}
});
registerClientbound(ClientboundPackets1_20_3.MAP_DATA, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Map id
wrapper.passthrough(Type.BYTE); // Scale
wrapper.passthrough(Type.BOOLEAN); // Locked
if (wrapper.passthrough(Type.BOOLEAN)) {
final int icons = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < icons; i++) {
wrapper.passthrough(Type.VAR_INT); // Type
wrapper.passthrough(Type.BYTE); // X
wrapper.passthrough(Type.BYTE); // Y
wrapper.passthrough(Type.BYTE); // Rotation
convertOptionalComponent(wrapper); // Display name
}
}
});
registerClientbound(ClientboundPackets1_20_3.BOSSBAR, wrapper -> {
wrapper.passthrough(Type.UUID); // Id
final int action = wrapper.passthrough(Type.VAR_INT);
if (action == 0 || action == 3) {
convertComponent(wrapper);
}
});
registerClientbound(ClientboundPackets1_20_3.PLAYER_CHAT, wrapper -> {
wrapper.passthrough(Type.UUID); // Sender
wrapper.passthrough(Type.VAR_INT); // Index
wrapper.passthrough(Type.OPTIONAL_SIGNATURE_BYTES); // Signature
wrapper.passthrough(Type.STRING); // Plain content
wrapper.passthrough(Type.LONG); // Timestamp
wrapper.passthrough(Type.LONG); // Salt
final int lastSeen = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < lastSeen; i++) {
final int index = wrapper.passthrough(Type.VAR_INT);
if (index == 0) {
wrapper.passthrough(Type.SIGNATURE_BYTES);
}
}
convertOptionalComponent(wrapper); // Unsigned content
final int filterMaskType = wrapper.passthrough(Type.VAR_INT);
if (filterMaskType == 2) {
wrapper.passthrough(Type.LONG_ARRAY_PRIMITIVE); // Mask
}
wrapper.passthrough(Type.VAR_INT); // Chat type
convertComponent(wrapper); // Sender
convertOptionalComponent(wrapper); // Target
});
registerClientbound(ClientboundPackets1_20_3.TEAMS, wrapper -> {
wrapper.passthrough(Type.STRING); // Team Name
final byte action = wrapper.passthrough(Type.BYTE); // Mode
if (action == 0 || action == 2) {
convertComponent(wrapper); // Display Name
wrapper.passthrough(Type.BYTE); // Flags
wrapper.passthrough(Type.STRING); // Name Tag Visibility
wrapper.passthrough(Type.STRING); // Collision rule
wrapper.passthrough(Type.VAR_INT); // Color
convertComponent(wrapper); // Prefix
convertComponent(wrapper); // Suffix
}
});
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.DISCONNECT.getId(), ClientboundConfigurationPackets1_20_2.DISCONNECT.getId(), this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.DISCONNECT, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.RESOURCE_PACK_PUSH, ClientboundPackets1_20_2.RESOURCE_PACK, resourcePackHandler());
registerClientbound(ClientboundPackets1_20_3.SERVER_DATA, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.ACTIONBAR, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.TITLE_TEXT, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.TITLE_SUBTITLE, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.DISGUISED_CHAT, wrapper -> {
convertComponent(wrapper);
wrapper.passthrough(Type.VAR_INT); // Chat type
convertComponent(wrapper); // Name
convertOptionalComponent(wrapper); // Target name
});
registerClientbound(ClientboundPackets1_20_3.SYSTEM_CHAT, this::convertComponent);
registerClientbound(ClientboundPackets1_20_3.OPEN_WINDOW, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Container id
final int containerTypeId = wrapper.read(Type.VAR_INT);
final int mappedContainerTypeId = MAPPINGS.getMenuMappings().getNewId(containerTypeId);
if (mappedContainerTypeId == -1) {
wrapper.cancel();
return;
}
wrapper.write(Type.VAR_INT, mappedContainerTypeId);
convertComponent(wrapper);
});
registerClientbound(ClientboundPackets1_20_3.TAB_LIST, wrapper -> {
convertComponent(wrapper);
convertComponent(wrapper);
});
registerClientbound(ClientboundPackets1_20_3.COMBAT_KILL, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Duration
handler(wrapper -> convertComponent(wrapper));
}
});
registerClientbound(ClientboundPackets1_20_3.PLAYER_INFO_UPDATE, wrapper -> {
final BitSet actions = wrapper.passthrough(Type.PROFILE_ACTIONS_ENUM);
final int entries = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Type.UUID);
if (actions.get(0)) {
wrapper.passthrough(Type.STRING); // Player Name
final int properties = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Type.STRING); // Name
wrapper.passthrough(Type.STRING); // Value
wrapper.passthrough(Type.OPTIONAL_STRING); // Signature
}
}
if (actions.get(1) && wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.UUID); // Session UUID
wrapper.passthrough(Type.PROFILE_KEY);
}
if (actions.get(2)) {
wrapper.passthrough(Type.VAR_INT); // Gamemode
}
if (actions.get(3)) {
wrapper.passthrough(Type.BOOLEAN); // Listed
}
if (actions.get(4)) {
wrapper.passthrough(Type.VAR_INT); // Latency
}
if (actions.get(5)) {
convertOptionalComponent(wrapper); // Display name
}
}
});
registerClientbound(ClientboundPackets1_20_3.SPAWN_POSITION, wrapper -> {
final Position position = wrapper.passthrough(Type.POSITION1_14);
final float angle = wrapper.passthrough(Type.FLOAT);
wrapper.user().get(SpawnPositionStorage.class).setSpawnPosition(Pair.of(position, angle));
});
registerClientbound(ClientboundPackets1_20_3.GAME_EVENT, wrapper -> {
final short reason = wrapper.passthrough(Type.UNSIGNED_BYTE);
if (reason == 13) { // Level chunks load start
wrapper.cancel();
final Pair<Position, Float> spawnPositionAndAngle = wrapper.user().get(SpawnPositionStorage.class).getSpawnPosition();
// To emulate the old behavior, we send a fake spawn pos packet containing the actual spawn pos which forces
// the 1.20.2 client to close the downloading terrain screen like the new game state does
final PacketWrapper spawnPosition = wrapper.create(ClientboundPackets1_20_2.SPAWN_POSITION);
spawnPosition.write(Type.POSITION1_14, spawnPositionAndAngle.first()); // position
spawnPosition.write(Type.FLOAT, spawnPositionAndAngle.second()); // angle
spawnPosition.send(Protocol1_20_2To1_20_3.class, true);
}
});
cancelClientbound(ClientboundPackets1_20_3.RESOURCE_PACK_POP);
registerServerbound(ServerboundPackets1_20_2.RESOURCE_PACK_STATUS, resourcePackStatusHandler());
cancelClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_3.RESOURCE_PACK_POP.getId());
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.RESOURCE_PACK, resourcePackStatusHandler());
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_3.RESOURCE_PACK_PUSH.getId(), ClientboundConfigurationPackets1_20_2.RESOURCE_PACK.getId(), resourcePackHandler());
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_3.UPDATE_TAGS.getId(), ClientboundConfigurationPackets1_20_2.UPDATE_TAGS.getId(), tagRewriter.getGenericHandler());
// TODO Auto map via packet types provider
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_3.UPDATE_ENABLED_FEATURES.getId(), ClientboundConfigurationPackets1_20_2.UPDATE_ENABLED_FEATURES.getId());
}
private PacketHandler resourcePackStatusHandler() {
return wrapper -> {
final ResourcepackIDStorage storage = wrapper.user().get(ResourcepackIDStorage.class);
wrapper.write(Type.UUID, storage != null ? storage.uuid() : UUID.randomUUID());
};
}
private PacketHandler resourcePackHandler() {
return wrapper -> {
final UUID uuid = wrapper.read(Type.UUID);
wrapper.user().put(new ResourcepackIDStorage(uuid));
wrapper.passthrough(Type.STRING); // Url
wrapper.passthrough(Type.STRING); // Hash
wrapper.passthrough(Type.BOOLEAN); // Required
convertOptionalComponent(wrapper);
};
}
private void convertComponent(final PacketWrapper wrapper) throws Exception {
final Tag tag = wrapper.read(Type.TAG);
translatableRewriter.processTag(tag);
wrapper.write(Type.COMPONENT, ComponentUtil.tagToJson(tag));
}
private void convertOptionalComponent(final PacketWrapper wrapper) throws Exception {
final Tag tag = wrapper.read(Type.OPTIONAL_TAG);
translatableRewriter.processTag(tag);
wrapper.write(Type.OPTIONAL_COMPONENT, ComponentUtil.tagToJson(tag));
}
@Override
public void init(final UserConnection connection) {
connection.put(new SpawnPositionStorage());
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_3.PLAYER));
}
@Override
protected ServerboundPacketType serverboundFinishConfigurationPacket() {
return ServerboundConfigurationPackets1_20_2.FINISH_CONFIGURATION;
}
@Override
protected ClientboundPacketType clientboundFinishConfigurationPacket() {
return ClientboundConfigurationPackets1_20_3.FINISH_CONFIGURATION;
}
@Override
public BackwardsMappings getMappingData() {
return MAPPINGS;
}
@Override
public BlockItemPacketRewriter1_20_3 getItemRewriter() {
return itemRewriter;
}
@Override
public EntityPacketRewriter1_20_3 getEntityRewriter() {
return entityRewriter;
}
@Override
public TranslatableRewriter<ClientboundPackets1_20_3> getTranslatableRewriter() {
return translatableRewriter;
}
}
@@ -1,158 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_20_2to1_20_3.rewriter;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.RecipeRewriter1_20_3;
import com.viaversion.viaversion.rewriter.BlockRewriter;
public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter<ClientboundPackets1_20_3, ServerboundPackets1_20_2, Protocol1_20_2To1_20_3> {
public BlockItemPacketRewriter1_20_3(final Protocol1_20_2To1_20_3 protocol) {
super(protocol, Type.ITEM1_20_2, Type.ITEM1_20_2_ARRAY);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPackets1_20_3> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockAction(ClientboundPackets1_20_3.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_20_3.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange1_20(ClientboundPackets1_20_3.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_20_3.EFFECT, 1010, 2001);
blockRewriter.registerChunkData1_19(ClientboundPackets1_20_3.CHUNK_DATA, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_20_3.BLOCK_ENTITY_DATA);
registerSetCooldown(ClientboundPackets1_20_3.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_20_3.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_20_3.SET_SLOT);
registerEntityEquipmentArray(ClientboundPackets1_20_3.ENTITY_EQUIPMENT);
registerClickWindow1_17_1(ServerboundPackets1_20_2.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_20_3.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_20_2.CREATIVE_INVENTORY_ACTION);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_20_3.WINDOW_PROPERTY);
protocol.registerClientbound(ClientboundPackets1_20_3.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
handler(wrapper -> {
final int id = wrapper.get(Type.VAR_INT, 0);
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (id == particleMappings.id("vibration")) {
final int positionSourceType = wrapper.read(Type.VAR_INT);
if (positionSourceType == 0) {
wrapper.write(Type.STRING, "minecraft:block");
} else if (positionSourceType == 1) {
wrapper.write(Type.STRING, "minecraft:entity");
} else {
ViaBackwards.getPlatform().getLogger().warning("Unknown position source type: " + positionSourceType);
wrapper.cancel();
}
}
});
handler(getSpawnParticleHandler(Type.VAR_INT));
}
});
new RecipeRewriter1_20_3<ClientboundPackets1_20_3>(protocol) {
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) throws Exception {
// Move width and height up
final String group = wrapper.read(Type.STRING);
final int craftingBookCategory = wrapper.read(Type.VAR_INT);
final int width = wrapper.passthrough(Type.VAR_INT);
final int height = wrapper.passthrough(Type.VAR_INT);
wrapper.write(Type.STRING, group);
wrapper.write(Type.VAR_INT, craftingBookCategory);
final int ingredients = height * width;
for (int i = 0; i < ingredients; i++) {
handleIngredient(wrapper);
}
rewrite(wrapper.passthrough(itemType())); // Result
wrapper.passthrough(Type.BOOLEAN); // Show notification
}
}.register(ClientboundPackets1_20_3.DECLARE_RECIPES);
protocol.registerClientbound(ClientboundPackets1_20_3.EXPLOSION, wrapper -> {
wrapper.passthrough(Type.DOUBLE); // X
wrapper.passthrough(Type.DOUBLE); // Y
wrapper.passthrough(Type.DOUBLE); // Z
wrapper.passthrough(Type.FLOAT); // Power
final int blocks = wrapper.read(Type.VAR_INT);
final byte[][] toBlow = new byte[blocks][3];
for (int i = 0; i < blocks; i++) {
toBlow[i] = new byte[]{
wrapper.read(Type.BYTE), // Relative X
wrapper.read(Type.BYTE), // Relative Y
wrapper.read(Type.BYTE) // Relative Z
};
}
final float knockbackX = wrapper.read(Type.FLOAT); // Knockback X
final float knockbackY = wrapper.read(Type.FLOAT); // Knockback Y
final float knockbackZ = wrapper.read(Type.FLOAT); // Knockback Z
final int blockInteraction = wrapper.read(Type.VAR_INT); // Block interaction type
// 0 = keep, 1 = destroy, 2 = destroy_with_decay, 3 = trigger_block
if (blockInteraction == 1 || blockInteraction == 2) {
wrapper.write(Type.VAR_INT, blocks);
for (final byte[] relativeXYZ : toBlow) {
wrapper.write(Type.BYTE, relativeXYZ[0]);
wrapper.write(Type.BYTE, relativeXYZ[1]);
wrapper.write(Type.BYTE, relativeXYZ[2]);
}
} else {
// Explosion doesn't destroy blocks
wrapper.write(Type.VAR_INT, 0);
}
wrapper.write(Type.FLOAT, knockbackX);
wrapper.write(Type.FLOAT, knockbackY);
wrapper.write(Type.FLOAT, knockbackZ);
// TODO Probably needs handling
wrapper.read(Types1_20_3.PARTICLE); // Small explosion particle
wrapper.read(Types1_20_3.PARTICLE); // Large explosion particle
wrapper.read(Type.STRING); // Explosion sound
wrapper.read(Type.OPTIONAL_FLOAT); // Sound range
});
}
}
@@ -1,160 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_20_2to1_20_3.rewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viabackwards.protocol.protocol1_20_2to1_20_3.storage.SpawnPositionStorage;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_3;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3;
import com.viaversion.viaversion.util.ComponentUtil;
public final class EntityPacketRewriter1_20_3 extends EntityRewriter<ClientboundPackets1_20_3, Protocol1_20_2To1_20_3> {
public EntityPacketRewriter1_20_3(final Protocol1_20_2To1_20_3 protocol) {
super(protocol, Types1_20_2.META_TYPES.optionalComponentType, Types1_20_2.META_TYPES.booleanType);
}
@Override
public void registerPackets() {
registerSpawnTracker(ClientboundPackets1_20_3.SPAWN_ENTITY);
registerMetadataRewriter(ClientboundPackets1_20_3.ENTITY_METADATA, Types1_20_3.METADATA_LIST, Types1_20_2.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_20_3.REMOVE_ENTITIES);
protocol.registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.REGISTRY_DATA, new PacketHandlers() {
@Override
protected void register() {
map(Type.COMPOUND_TAG); // Registry data
handler(configurationDimensionDataHandler());
handler(configurationBiomeSizeTracker());
}
});
protocol.registerClientbound(ClientboundPackets1_20_3.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
map(Type.INT); // Entity id
map(Type.BOOLEAN); // Hardcore
map(Type.STRING_ARRAY); // World List
map(Type.VAR_INT); // Max players
map(Type.VAR_INT); // View distance
map(Type.VAR_INT); // Simulation distance
map(Type.BOOLEAN); // Reduced debug info
map(Type.BOOLEAN); // Show death screen
map(Type.BOOLEAN); // Limited crafting
map(Type.STRING); // Dimension key
map(Type.STRING); // World
handler(spawnPositionHandler());
handler(worldDataTrackerHandlerByKey());
}
});
protocol.registerClientbound(ClientboundPackets1_20_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Type.STRING); // Dimension
map(Type.STRING); // World
handler(spawnPositionHandler());
handler(worldDataTrackerHandlerByKey());
}
});
}
private PacketHandler spawnPositionHandler() {
return wrapper -> {
final String world = wrapper.get(Type.STRING, 1);
wrapper.user().get(SpawnPositionStorage.class).setDimension(world);
};
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
final MetaType type = meta.metaType();
if (type == Types1_20_3.META_TYPES.componentType) {
meta.setTypeAndValue(Types1_20_2.META_TYPES.componentType, ComponentUtil.tagToJson(meta.value()));
return;
} else if (type == Types1_20_3.META_TYPES.optionalComponentType) {
meta.setTypeAndValue(Types1_20_2.META_TYPES.optionalComponentType, ComponentUtil.tagToJson(meta.value()));
return;
} else if (type == Types1_20_3.META_TYPES.particleType) {
final Particle particle = (Particle) meta.getValue();
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
if (particle.getId() == particleMappings.id("vibration")) {
// Change the type of the position source type argument
final int positionSourceType = particle.<Integer>removeArgument(0).getValue();
if (positionSourceType == 0) {
particle.add(0, Type.STRING, "minecraft:block");
} else { // Entity
particle.add(0, Type.STRING, "minecraft:entity");
}
}
rewriteParticle(particle);
} else if (type == Types1_20_3.META_TYPES.poseType) {
final int pose = meta.value();
if (pose >= 15) {
event.cancel();
}
}
meta.setMetaType(Types1_20_2.META_TYPES.byId(type.typeId()));
});
registerMetaTypeHandler(
Types1_20_2.META_TYPES.itemType,
Types1_20_2.META_TYPES.blockStateType,
Types1_20_2.META_TYPES.optionalBlockStateType,
Types1_20_2.META_TYPES.particleType,
Types1_20_2.META_TYPES.componentType,
Types1_20_2.META_TYPES.optionalComponentType
);
filter().type(EntityTypes1_20_3.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int blockState = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
});
filter().type(EntityTypes1_20_3.TNT).removeIndex(9); // Block state
}
@Override
public void onMappingDataLoaded() {
mapTypes();
mapEntityTypeWithData(EntityTypes1_20_3.BREEZE, EntityTypes1_20_3.BLAZE).jsonName();
mapEntityTypeWithData(EntityTypes1_20_3.WIND_CHARGE, EntityTypes1_20_3.LLAMA_SPIT).jsonName();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_20_3.getTypeFromId(type);
}
}
@@ -1,415 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_20to1_20_2.rewriter;
import com.viaversion.viabackwards.api.rewriters.ItemRewriter;
import com.viaversion.viabackwards.protocol.protocol1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.metadata.ChunkPosition;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.rewriter.RecipeRewriter1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.util.PotionEffects;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.MathUtil;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<ClientboundPackets1_20_2, ServerboundPackets1_19_4, Protocol1_20To1_20_2> {
public BlockItemPacketRewriter1_20_2(final Protocol1_20To1_20_2 protocol) {
super(protocol, Type.ITEM1_20_2, Type.ITEM1_20_2_ARRAY);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPackets1_20_2> blockRewriter = BlockRewriter.for1_14(protocol);
blockRewriter.registerBlockAction(ClientboundPackets1_20_2.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_20_2.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange1_20(ClientboundPackets1_20_2.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_20_2.EFFECT, 1010, 2001);
protocol.cancelClientbound(ClientboundPackets1_20_2.CHUNK_BATCH_START);
protocol.registerClientbound(ClientboundPackets1_20_2.CHUNK_BATCH_FINISHED, null, wrapper -> {
wrapper.cancel();
final PacketWrapper receivedPacket = wrapper.create(ServerboundPackets1_20_2.CHUNK_BATCH_RECEIVED);
receivedPacket.write(Type.FLOAT, 500F); // Requested next batch size... arbitrary value here
receivedPacket.sendToServer(Protocol1_20To1_20_2.class);
});
protocol.registerClientbound(ClientboundPackets1_20_2.UNLOAD_CHUNK, wrapper -> {
final ChunkPosition chunkPosition = wrapper.read(Type.CHUNK_POSITION);
wrapper.write(Type.INT, chunkPosition.chunkX());
wrapper.write(Type.INT, chunkPosition.chunkZ());
});
protocol.registerClientbound(ClientboundPackets1_20_2.MAP_DATA, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Map id
wrapper.passthrough(Type.BYTE); // Scale
wrapper.passthrough(Type.BOOLEAN); // Locked
if (wrapper.passthrough(Type.BOOLEAN)) {
final int icons = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < icons; i++) {
// Map new marker types to red marker
final int markerType = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, markerType < 27 ? markerType : 2);
wrapper.passthrough(Type.BYTE); // X
wrapper.passthrough(Type.BYTE); // Y
wrapper.passthrough(Type.BYTE); // Rotation
wrapper.passthrough(Type.OPTIONAL_COMPONENT); // Display name
}
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.NBT_QUERY, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Transaction id
wrapper.write(Type.NAMED_COMPOUND_TAG, wrapper.read(Type.COMPOUND_TAG));
});
protocol.registerClientbound(ClientboundPackets1_20_2.BLOCK_ENTITY_DATA, wrapper -> {
wrapper.passthrough(Type.POSITION1_14); // Position
wrapper.passthrough(Type.VAR_INT); // Type
wrapper.write(Type.NAMED_COMPOUND_TAG, handleBlockEntity(wrapper.read(Type.COMPOUND_TAG)));
});
protocol.registerClientbound(ClientboundPackets1_20_2.CHUNK_DATA, wrapper -> {
final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user());
final Type<Chunk> chunkType = new ChunkType1_20_2(tracker.currentWorldSectionHeight(),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().size()),
MathUtil.ceilLog2(tracker.biomesSent()));
final Chunk chunk = wrapper.read(chunkType);
final Type<Chunk> newChunkType = new ChunkType1_18(tracker.currentWorldSectionHeight(),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().mappedSize()),
MathUtil.ceilLog2(tracker.biomesSent()));
wrapper.write(newChunkType, chunk);
for (final ChunkSection section : chunk.getSections()) {
final DataPalette blockPalette = section.palette(PaletteType.BLOCKS);
for (int i = 0; i < blockPalette.size(); i++) {
final int id = blockPalette.idByIndex(i);
blockPalette.setIdByIndex(i, protocol.getMappingData().getNewBlockStateId(id));
}
}
for (final BlockEntity blockEntity : chunk.blockEntities()) {
handleBlockEntity(blockEntity.tag());
}
});
protocol.registerServerbound(ServerboundPackets1_19_4.SET_BEACON_EFFECT, wrapper -> {
// Effects start at 1 before 1.20.2
if (wrapper.passthrough(Type.BOOLEAN)) { // Primary effect
wrapper.write(Type.VAR_INT, wrapper.read(Type.VAR_INT) - 1);
}
if (wrapper.passthrough(Type.BOOLEAN)) { // Secondary effect
wrapper.write(Type.VAR_INT, wrapper.read(Type.VAR_INT) - 1);
}
});
// Replace the NBT type everywhere
protocol.registerClientbound(ClientboundPackets1_20_2.WINDOW_ITEMS, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
handler(wrapper -> {
final Item[] items = wrapper.read(Type.ITEM1_20_2_ARRAY);
for (final Item item : items) {
handleItemToClient(item);
}
wrapper.write(Type.ITEM1_13_2_ARRAY, items);
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))); // Carried item
});
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
map(Type.SHORT); // Slot id
handler(wrapper -> wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))));
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
final int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.STRING);
}
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT); // Title
wrapper.passthrough(Type.COMPONENT); // Description
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
final int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
wrapper.write(Type.STRING_ARRAY, new String[0]); // Criteria
final int requirements = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < requirements; array++) {
wrapper.passthrough(Type.STRING_ARRAY);
}
wrapper.passthrough(Type.BOOLEAN); // Send telemetry
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.ENTITY_EQUIPMENT, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Entity ID
handler(wrapper -> {
byte slot;
do {
slot = wrapper.passthrough(Type.BYTE);
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2)));
} while ((slot & 0xFFFFFF80) != 0);
});
}
});
protocol.registerServerbound(ServerboundPackets1_19_4.CLICK_WINDOW, new PacketHandlers() {
@Override
public void register() {
map(Type.UNSIGNED_BYTE); // Window Id
map(Type.VAR_INT); // State id
map(Type.SHORT); // Slot
map(Type.BYTE); // Button
map(Type.VAR_INT); // Mode
handler(wrapper -> {
// Affected items
final int length = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Type.SHORT); // Slot
wrapper.write(Type.ITEM1_20_2, handleItemToServer(wrapper.read(Type.ITEM1_13_2)));
}
// Carried item
wrapper.write(Type.ITEM1_20_2, handleItemToServer(wrapper.read(Type.ITEM1_13_2)));
});
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.TRADE_LIST, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Container id
final int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))); // Input
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))); // Output
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2))); // Second Item
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
wrapper.passthrough(Type.INT); // XP
wrapper.passthrough(Type.INT); // Special price
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); // Demand
}
});
protocol.registerServerbound(ServerboundPackets1_19_4.CREATIVE_INVENTORY_ACTION, new PacketHandlers() {
@Override
public void register() {
map(Type.SHORT); // 0 - Slot
handler(wrapper -> wrapper.write(Type.ITEM1_20_2, handleItemToServer(wrapper.read(Type.ITEM1_13_2)))); // 1 - Clicked Item
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.SPAWN_PARTICLE, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
handler(wrapper -> {
final int id = wrapper.get(Type.VAR_INT, 0);
final ParticleMappings mappings = Protocol1_20To1_20_2.MAPPINGS.getParticleMappings();
if (mappings.isBlockParticle(id)) {
final int data = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, protocol.getMappingData().getNewBlockStateId(data));
} else if (mappings.isItemParticle(id)) {
wrapper.write(Type.ITEM1_13_2, handleItemToClient(wrapper.read(Type.ITEM1_20_2)));
}
});
}
});
new RecipeRewriter1_20_2<ClientboundPackets1_20_2>(protocol) {
@Override
public void handleCraftingShapeless(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
handleIngredients(wrapper);
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
}
@Override
public void handleSmelting(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
handleIngredient(wrapper);
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
wrapper.passthrough(Type.FLOAT); // EXP
wrapper.passthrough(Type.VAR_INT); // Cooking time
}
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) throws Exception {
final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
for (int i = 0; i < ingredients; i++) {
handleIngredient(wrapper);
}
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
wrapper.passthrough(Type.BOOLEAN); // Show notification
}
@Override
public void handleStonecutting(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.STRING); // Group
handleIngredient(wrapper);
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
}
@Override
public void handleSmithing(final PacketWrapper wrapper) throws Exception {
handleIngredient(wrapper); // Base
handleIngredient(wrapper); // Addition
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
}
@Override
public void handleSmithingTransform(final PacketWrapper wrapper) throws Exception {
handleIngredient(wrapper); // Template
handleIngredient(wrapper); // Base
handleIngredient(wrapper); // Additions
final Item result = wrapper.read(itemType());
rewrite(result);
wrapper.write(Type.ITEM1_13_2, result);
}
@Override
protected void handleIngredient(final PacketWrapper wrapper) throws Exception {
final Item[] items = wrapper.read(itemArrayType());
wrapper.write(Type.ITEM1_13_2_ARRAY, items);
for (final Item item : items) {
rewrite(item);
}
}
}.register(ClientboundPackets1_20_2.DECLARE_RECIPES);
}
@Override
public @Nullable Item handleItemToClient(@Nullable final Item item) {
if (item == null) {
return null;
}
if (item.tag() != null) {
com.viaversion.viaversion.protocols.protocol1_20_2to1_20.rewriter.BlockItemPacketRewriter1_20_2.to1_20_1Effects(item);
}
return super.handleItemToClient(item);
}
@Override
public @Nullable Item handleItemToServer(@Nullable final Item item) {
if (item == null) {
return null;
}
if (item.tag() != null) {
com.viaversion.viaversion.protocols.protocol1_20_2to1_20.rewriter.BlockItemPacketRewriter1_20_2.to1_20_2Effects(item);
}
return super.handleItemToServer(item);
}
private @Nullable CompoundTag handleBlockEntity(@Nullable final CompoundTag tag) {
if (tag == null) {
return null;
}
final Tag primaryEffect = tag.remove("primary_effect");
if (primaryEffect instanceof StringTag) {
final String effectKey = Key.stripMinecraftNamespace(((StringTag) primaryEffect).getValue());
tag.putInt("Primary", PotionEffects.keyToId(effectKey));
}
final Tag secondaryEffect = tag.remove("secondary_effect");
if (secondaryEffect instanceof StringTag) {
final String effectKey = Key.stripMinecraftNamespace(((StringTag) secondaryEffect).getValue());
tag.putInt("Secondary", PotionEffects.keyToId(effectKey));
}
return tag;
}
}
@@ -1,215 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* 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.viabackwards.protocol.protocol1_20to1_20_2.rewriter;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.protocol1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viabackwards.protocol.protocol1_20to1_20_2.storage.ConfigurationPacketStorage;
import com.viaversion.viaversion.api.minecraft.GlobalPosition;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_20;
import com.viaversion.viaversion.api.type.types.version.Types1_20_2;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2;
public final class EntityPacketRewriter1_20_2 extends EntityRewriter<ClientboundPackets1_20_2, Protocol1_20To1_20_2> {
public EntityPacketRewriter1_20_2(final Protocol1_20To1_20_2 protocol) {
super(protocol, Types1_20.META_TYPES.optionalComponentType, Types1_20.META_TYPES.booleanType);
}
@Override
public void registerPackets() {
registerMetadataRewriter(ClientboundPackets1_20_2.ENTITY_METADATA, Types1_20_2.METADATA_LIST, Types1_20.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_20_2.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_20_2.SPAWN_ENTITY, new PacketHandlers() {
@Override
protected void register() {
handler(wrapper -> {
final int entityId = wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.UUID); // UUID
final int entityType = wrapper.read(Type.VAR_INT);
tracker(wrapper.user()).addEntity(entityId, typeFromId(entityType));
if (entityType != EntityTypes1_19_4.PLAYER.getId()) {
wrapper.write(Type.VAR_INT, entityType);
if (entityType == EntityTypes1_19_4.FALLING_BLOCK.getId()) {
wrapper.passthrough(Type.DOUBLE); // X
wrapper.passthrough(Type.DOUBLE); // Y
wrapper.passthrough(Type.DOUBLE); // Z
wrapper.passthrough(Type.BYTE); // Pitch
wrapper.passthrough(Type.BYTE); // Yaw
wrapper.passthrough(Type.BYTE); // Head yaw
final int blockState = wrapper.read(Type.VAR_INT); // Data
wrapper.write(Type.VAR_INT, protocol.getMappingData().getNewBlockStateId(blockState));
}
return;
}
// Map to spawn player packet
wrapper.setPacketType(ClientboundPackets1_19_4.SPAWN_PLAYER);
wrapper.passthrough(Type.DOUBLE); // X
wrapper.passthrough(Type.DOUBLE); // Y
wrapper.passthrough(Type.DOUBLE); // Z
final byte pitch = wrapper.read(Type.BYTE);
wrapper.passthrough(Type.BYTE); // Yaw
wrapper.write(Type.BYTE, pitch);
wrapper.read(Type.BYTE); // Head yaw
wrapper.read(Type.VAR_INT); // Data
final short velocityX = wrapper.read(Type.SHORT);
final short velocityY = wrapper.read(Type.SHORT);
final short velocityZ = wrapper.read(Type.SHORT);
if (velocityX == 0 && velocityY == 0 && velocityZ == 0) {
return;
}
// Follow up with velocity packet
wrapper.send(Protocol1_20To1_20_2.class);
wrapper.cancel();
final PacketWrapper velocityPacket = wrapper.create(ClientboundPackets1_19_4.ENTITY_VELOCITY);
velocityPacket.write(Type.VAR_INT, entityId);
velocityPacket.write(Type.SHORT, velocityX);
velocityPacket.write(Type.SHORT, velocityY);
velocityPacket.write(Type.SHORT, velocityZ);
velocityPacket.send(Protocol1_20To1_20_2.class);
});
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.JOIN_GAME, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
final ConfigurationPacketStorage configurationPacketStorage = wrapper.user().remove(ConfigurationPacketStorage.class);
wrapper.passthrough(Type.INT); // Entity id
wrapper.passthrough(Type.BOOLEAN); // Hardcore
final String[] worlds = wrapper.read(Type.STRING_ARRAY);
final int maxPlayers = wrapper.read(Type.VAR_INT);
final int viewDistance = wrapper.read(Type.VAR_INT);
final int simulationDistance = wrapper.read(Type.VAR_INT);
final boolean reducedDebugInfo = wrapper.read(Type.BOOLEAN);
final boolean showRespawnScreen = wrapper.read(Type.BOOLEAN);
wrapper.read(Type.BOOLEAN); // Limited crafting
final String dimensionType = wrapper.read(Type.STRING);
final String world = wrapper.read(Type.STRING);
final long seed = wrapper.read(Type.LONG);
wrapper.passthrough(Type.BYTE); // Gamemode
wrapper.passthrough(Type.BYTE); // Previous gamemode
wrapper.write(Type.STRING_ARRAY, worlds);
wrapper.write(Type.NAMED_COMPOUND_TAG, configurationPacketStorage.registry());
wrapper.write(Type.STRING, dimensionType);
wrapper.write(Type.STRING, world);
wrapper.write(Type.LONG, seed);
wrapper.write(Type.VAR_INT, maxPlayers);
wrapper.write(Type.VAR_INT, viewDistance);
wrapper.write(Type.VAR_INT, simulationDistance);
wrapper.write(Type.BOOLEAN, reducedDebugInfo);
wrapper.write(Type.BOOLEAN, showRespawnScreen);
worldDataTrackerHandlerByKey().handle(wrapper);
wrapper.send(Protocol1_20To1_20_2.class);
wrapper.cancel();
if (configurationPacketStorage.enabledFeatures() != null) {
final PacketWrapper featuresPacket = wrapper.create(ClientboundPackets1_19_4.UPDATE_ENABLED_FEATURES);
featuresPacket.write(Type.STRING_ARRAY, configurationPacketStorage.enabledFeatures());
featuresPacket.send(Protocol1_20To1_20_2.class);
}
configurationPacketStorage.sendQueuedPackets(wrapper.user());
});
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.RESPAWN, new PacketHandlers() {
@Override
public void register() {
handler(wrapper -> {
wrapper.passthrough(Type.STRING); // Dimension type
wrapper.passthrough(Type.STRING); // World
wrapper.passthrough(Type.LONG); // Seed
wrapper.write(Type.UNSIGNED_BYTE, wrapper.read(Type.BYTE).shortValue()); // Gamemode
wrapper.passthrough(Type.BYTE); // Previous gamemode
wrapper.passthrough(Type.BOOLEAN); // Debug
wrapper.passthrough(Type.BOOLEAN); // Flat
final GlobalPosition lastDeathPosition = wrapper.read(Type.OPTIONAL_GLOBAL_POSITION);
final int portalCooldown = wrapper.read(Type.VAR_INT);
wrapper.passthrough(Type.BYTE); // Data to keep
wrapper.write(Type.OPTIONAL_GLOBAL_POSITION, lastDeathPosition);
wrapper.write(Type.VAR_INT, portalCooldown);
});
handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.ENTITY_EFFECT, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Entity id
wrapper.write(Type.VAR_INT, wrapper.read(Type.VAR_INT) + 1); // Effect id
wrapper.passthrough(Type.BYTE); // Amplifier
wrapper.passthrough(Type.VAR_INT); // Duration
wrapper.passthrough(Type.BYTE); // Flags
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.write(Type.NAMED_COMPOUND_TAG, wrapper.read(Type.COMPOUND_TAG)); // Factor data
}
});
protocol.registerClientbound(ClientboundPackets1_20_2.REMOVE_ENTITY_EFFECT, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Entity id
wrapper.write(Type.VAR_INT, wrapper.read(Type.VAR_INT) + 1); // Effect id
});
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> meta.setMetaType(Types1_20.META_TYPES.byId(meta.metaType().typeId())));
registerMetaTypeHandler(Types1_20.META_TYPES.itemType, Types1_20.META_TYPES.blockStateType, Types1_20.META_TYPES.optionalBlockStateType, Types1_20.META_TYPES.particleType, null, null);
filter().type(EntityTypes1_19_4.DISPLAY).removeIndex(10);
filter().type(EntityTypes1_19_4.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int blockState = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
});
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_19_4.getTypeFromId(type);
}
}
Loaded 100 of 325 files, more files were not shown because too many files have changed in this diff. Show more