Compare commits

..
112 Commits
Author SHA1 Message Date
Nassim Jahnke c45c700301 Fix 1.21 player chat read type 2026-04-02 16:13:39 +02:00
Nassim Jahnke c43de2b88d Move 26.1 container empty item handling into proper upgrade/downgrade methods 2026-04-02 15:10:19 +02:00
Drex 898b6c8774 Improve enchantment term conversion (#4879) 2026-04-02 14:32:48 +02:00
Florian Reuth 2e3c47d292 Track sneaking state for secondary action in 1.21.11->26.1 (#4890) 2026-04-02 13:23:16 +02:00
Florian Reuth 7974d1a570 [ci skip] Update missing year references (#4786) 2026-04-02 11:56:51 +02:00
Florian Reuth cf2c1c5b76 Update time command translations in 1.21.11->26.1 (#4891) 2026-04-02 11:47:55 +02:00
Florian Reuth d75c54cc70 Fix kick when opening "edit game rules" screen (#4882) 2026-04-02 11:44:50 +02:00
Florian Reuth ead13b2bb9 Deprecate packet register methods with override boolean (#4881)
Replaced by Protocol#registerClientbound & Protocol#registerServerbound
2026-04-01 17:24:33 +02:00
Nassim Jahnke 2e91b841b0 Automatically call mapTypes in entity rewriter 2026-04-01 17:21:53 +02:00
Nassim Jahnke 50486fa43a Don't apply shared registrations to differing version types 2026-04-01 17:05:07 +02:00
Nassim Jahnke 31d4cd453d Add 26.1.1 to version string 2026-04-01 13:02:29 +02:00
Nassim Jahnke c5482b99bf [ci skip] Update error message 2026-03-31 21:15:01 +02:00
Nassim Jahnke 98ef806887 Fix baby wolf assets 2026-03-31 15:21:48 +02:00
Florian Reuth a26745862f Handle show_dialog click events (#4878) 2026-03-31 14:36:09 +02:00
Florian ReuthandNassim Jahnke 6bd081cefd Handle in-depth components in dialogs (#4876)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2026-03-31 11:25:47 +02:00
Nassim Jahnke bb9aa8b31c Fix adventure mode predicate index check in 1.20.4->1.20.5 2026-03-31 11:07:01 +02:00
Nassim Jahnke 572f7a2677 Fix hashing of attribute_modifiers with override text 2026-03-30 23:29:20 +02:00
Nassim Jahnke 11a5c9e32c Fix block entity tag read type 2026-03-30 23:09:37 +02:00
Nassim Jahnke 02b65dcb36 Fix command rewriter check being too early 2026-03-30 22:32:08 +02:00
Nassim Jahnke 0121534e7e Deduplicate particle type fillers 2026-03-30 21:53:47 +02:00
Florian Reuth 941e6f6df4 Null check block entity tag in 1.20->1.20.2 (#4872) 2026-03-30 20:40:26 +02:00
Nassim Jahnke fe6e18845b Make tests fail if error occurs during platform 2026-03-30 20:40:26 +02:00
Nassim Jahnke 8f8f5e72c0 Default rewriter registrations across protocols
In total it doesn't (yet) reduce the lines of code (though there is also some other changes adding code here), but makes adding single rewriter calls to a range of protocols much easier than having to individually check an ever increasing number of classes. This also moved Protocol#registerPackets until after mappings have been loaded (which makes onMappingDataLoaded redundant for now, but will become relevant later again)
2026-03-30 20:40:25 +02:00
Nassim Jahnke a6c35c6519 5.8.1 Release 2026-03-30 20:28:09 +02:00
Nassim Jahnke 8b115c7fde Fix attack_range and provides_banner_pattern hashing 2026-03-30 20:22:40 +02:00
Florian Reuth e2d3874f6d Add debug command usage help (#4874) 2026-03-30 15:25:21 +02:00
Florian Reuth 26d8190b23 Send empty tags packet in 1.21.11->26.1 (#4871) 2026-03-29 21:37:32 +02:00
RK_01 d508b6cec1 Add missing fluid block states for kelp, seagrass, and bubble columns (#4870)
Fixes water physics in 26.1
2026-03-29 17:36:08 +02:00
Nassim Jahnke 916ef8c5ac Fix removal of recipe displays 2026-03-29 15:07:44 +02:00
Nassim Jahnke 6b74116ff1 Handle item changes in dialog packets 2026-03-28 17:09:25 +01:00
Nassim Jahnke 5ead6805b9 Distinguish items of different ids for hashing 2026-03-28 11:25:22 +01:00
Nassim Jahnke a6eedfdf0b Bump version to 5.8.1-SNAPSHOT 2026-03-28 11:18:20 +01:00
Nassim Jahnke 38ecd65ee8 5.8.0 Release 2026-03-27 16:12:18 +01:00
Nassim Jahnke 788c1d1b1f Set hashed item amount from click packet
Preserves the amount the player actually had/saw at the end
2026-03-26 20:44:52 +01:00
Nassim Jahnke 0519184da2 Replace 0 count in item hovers 2026-03-25 16:21:55 +01:00
Florian Reuth fd13912295 Fix EntityDataTypes1_21_11#villagerDataType typo 2026-03-25 16:21:23 +01:00
Nassim Jahnke 8d3c36de06 Send empty tags packet if not sent early enough when leaving config stage
Some tags are required before the client finalizes its registries, this lets Via fill them up early enough in later protocols
2026-03-25 16:21:09 +01:00
Nassim Jahnke 219d374d7c Fix item particle type 2026-03-25 16:21:09 +01:00
Nassim Jahnke 9b163e70c3 Remove snapshot bit 2026-03-25 16:21:09 +01:00
Nassim Jahnke 9ed00904f9 26.1-rc-3 2026-03-25 16:21:09 +01:00
Nassim Jahnke e56abf5cac Update identifier files 2026-03-25 16:21:09 +01:00
Florian Reuth 1bf7274dc8 Add empty damage type & banner pattern tags
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-03-25 16:21:09 +01:00
Nassim Jahnke d218451418 26.1-rc-2 2026-03-25 16:21:08 +01:00
Nassim Jahnke 7d8dcce307 Fix pausing daylight cycle 2026-03-25 16:21:08 +01:00
Nassim Jahnke 2f5d527a38 Fix blocks attacks conversion and banner pattern hashing 2026-03-25 16:21:08 +01:00
Nassim Jahnke a16c5a9fc5 26.1-rc-1 2026-03-25 16:21:08 +01:00
Nassim Jahnke 318608b9cd Auto remove new registries from tags too 2026-03-25 16:21:08 +01:00
Nassim Jahnke ae7496fbad 26.1-pre-3 2026-03-25 16:21:07 +01:00
Nassim Jahnke 32a1dfe74f 26.1-pre-2 2026-03-25 16:21:07 +01:00
Nassim Jahnke 815ec24af1 Remove removed registries from command arguments 2026-03-25 16:21:07 +01:00
Nassim Jahnke 8ee0b66eed Always send interact_at 2026-03-25 16:21:07 +01:00
Nassim Jahnke ab2385b975 26.1-pre1 2026-03-25 16:21:07 +01:00
Nassim Jahnke 5a9ccf7c17 Update villager entity data id 2026-03-25 16:21:07 +01:00
Nassim Jahnke 22877d06a7 Replace remaining either holders 2026-03-25 16:21:06 +01:00
Nassim Jahnke 35d85d08a7 Update sound variants 2026-03-25 16:21:06 +01:00
Nassim Jahnke f5bb1c42db 26.1-snapshot-11 2026-03-25 16:21:06 +01:00
Nassim Jahnke cfb8519ae2 26.1-snapshot-10 2026-03-25 16:21:06 +01:00
Nassim Jahnke 4d1fa925ff Add new ambient light colors 2026-03-25 16:21:06 +01:00
Nassim Jahnke fa410b704a Fix cat variant asset change 2026-03-25 16:21:06 +01:00
Nassim Jahnke 483628f1f2 26.1-snapshot-9 2026-03-25 16:21:05 +01:00
Nassim Jahnke 7930e66676 26.1-snapshot-8 (maybe) 2026-03-25 16:21:05 +01:00
Nassim Jahnke 5b547a303a 26.1-snapshot-7 2026-03-25 16:21:05 +01:00
Nassim Jahnke 497d8e17da 26.1-snapshot-6 2026-03-25 16:21:05 +01:00
Nassim Jahnke efbd5d23cd 26.1-snapshot-5 2026-03-25 16:21:05 +01:00
Nassim Jahnke 592b8c8d47 26.1-snapshot-4 2026-03-25 16:21:04 +01:00
Nassim Jahnke 5393edc35b Handle null template items, fix asset id change 2026-03-25 16:21:04 +01:00
Nassim Jahnke 97aff00ced Fill registries used by delayed item loading 2026-03-25 16:21:04 +01:00
Nassim Jahnke 69121c5722 26.1-snapshot-3 2026-03-25 16:21:04 +01:00
Nassim Jahnke ba57197552 26.1-snapshot-2 2026-03-25 16:21:04 +01:00
Nassim Jahnke 7ca372dca4 Update template protocol 2026-03-25 16:21:04 +01:00
Nassim Jahnke e9fb10b63c 26.1-snapshot-1 2026-03-25 16:21:03 +01:00
Florian Reuth ca7696ce12 Allow platforms to append data to connection details protocols (#4859) 2026-03-24 23:17:48 +01:00
Florian Reuth e63c806d64 Fix custom potion effects translation in 1.20.3->1.20.5 (#4858) 2026-03-22 08:34:30 +01:00
Florian Reuth e470ca0002 [ci skip] Update README (#4856) 2026-03-21 19:07:32 +01:00
Florian Reuth 80e90a4401 Fix flower pot block storage 1.12.2->1.13 memory leak (#4852) 2026-03-18 15:05:30 +01:00
Florian Reuth 1d35f2ec35 Produce inlined string in 1.8->1.9 sign update (#4851) 2026-03-16 19:17:21 +01:00
Nassim Jahnke e639eb763a Update ViaNBT 2026-03-13 20:51:32 +01:00
Nassim Jahnke d8343d278d Use var int type in holder set type 2026-03-12 15:12:09 +01:00
Nassim Jahnke 833f49fff3 Swap end and overworld background tracks 2026-03-02 17:33:52 +01:00
Nassim Jahnke cd45a6e7ce 5.7.2 Release 2026-03-01 16:28:28 +01:00
Nassim Jahnke 271362da78 Update dependencies 2026-03-01 16:28:16 +01:00
Nassim Jahnke 05562c27c1 Fix nether biome sky colors, add missing dimension ambient sounds 2026-02-22 13:47:24 +01:00
Nassim Jahnke 5b4ed02748 Handle number format in set_score packet 2026-02-21 16:03:13 +01:00
Nassim Jahnke fe4e407520 Add gradle to dependabot config 2026-02-20 22:17:25 +01:00
Nassim Jahnke f003b6b84a Only do compression handler reorder on old servers after compression is enabled 2026-02-20 21:58:25 +01:00
Nassim Jahnke 207e085120 Add breath_of_the_nautilus to mob effects enum type 2026-02-20 19:18:19 +01:00
Nassim Jahnke 0a155651a1 Handle 1.21.9->1.21.11 biome sounds and particles 2026-02-20 13:56:19 +01:00
Florian Reuth d061083a8a Handle nested lore components in item_hover handling again (#4830) 2026-02-12 21:31:33 +01:00
Nassim Jahnke ad4c8e42f2 Add system property to disable legacy compression reorder 2026-02-09 17:56:19 +01:00
Florian Reuth b8b13f5831 [ci skip] Update my donation URL (#4826) 2026-02-05 17:09:38 +01:00
FlorianMichael 4dc533506f Don't register a cooldown rewriter in 1.17->1.17.1 (#4824) 2026-02-02 16:16:20 +01:00
dependabot[bot] a166b70996 [ci skip] Bump actions/checkout from 6.0.1 to 6.0.2 (#4822)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 14:07:37 +01:00
dependabot[bot] 639e8c454d [ci skip] Bump actions/setup-java from 5.1.0 to 5.2.0 (#4823)
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.1.0 to 5.2.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/f2beeb24e141e01a676f977032f5a29d81c9e27e...be666c2fcd27ec809703dec50e508c2fdc7f6654)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 5.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 14:07:23 +01:00
FlorianMichael 61fc96ee11 Allow platforms to change compression names (#4821) 2026-01-31 21:08:01 +01:00
Nassim Jahnke 56259c8318 Update supported Velocity versions 2026-01-31 12:02:24 +01:00
FlorianMichael a8637d9a06 Fix play state compression when already set during login in 1.8->1.9 (#4820) 2026-01-30 22:02:40 +01:00
FlorianMichael ce607b5cc7 Use compression handler names instead for utility method (#4818) 2026-01-30 21:28:37 +01:00
FlorianMichael aa9a615c6b [ci skip] Small code cleanups (#4819) 2026-01-30 21:25:40 +01:00
FlorianMichael 8febef07c3 Add ViaChannelInitializer#reorderPipeline (#4817) 2026-01-29 17:09:42 +01:00
Nassim Jahnke 13fcce6059 Use right method for sub 1.21.5 item_name/custom_name item_hover handling 2026-01-28 17:12:34 +01:00
FlorianMichael cf6427325c Call component rewriter for component item components (#4812) 2026-01-28 12:10:47 +01:00
ValapheeandFlorianMichael 2c30a2748c Display out of bounds enchantments in item lore in 1.17->1.17.1 (#4743)
Co-authored-by: FlorianMichael <git@florianmichael.de>
2026-01-25 20:29:38 +01:00
Nassim Jahnke 1ca5b33304 Fix trusted tag limiting 2026-01-25 13:13:55 +01:00
Nassim Jahnke 265859bdae Re-use byte array in hash builder 2026-01-25 10:59:39 +01:00
FlorianMichael 93e29ac832 Use BlockRewriter1_21_5 in 1.21.7->1.21.9 & 1.21.9->1.21.11 (#4807) 2026-01-24 19:35:27 +01:00
FlorianMichael 4735795323 [ci skip] Remove Gradle wrapper update action (#4805) 2026-01-24 19:25:39 +01:00
FlorianMichael fe5732b616 Make Config#originalRootSection consistent (#4798) 2026-01-21 17:18:27 +01:00
RK_01 b0d9b747de Add ProtocolVersionRange#getMin and ProtocolVersionRange#getMax (#4797) 2026-01-19 21:08:30 +01:00
Nassim Jahnke 3f0f973fac Use synchronized map for config to preserve correct order on late saves 2026-01-19 19:33:00 +01:00
RK_01 1fa3f15d91 Handle 1.21->1.21.2 empty food component split fully (#4796) 2026-01-18 21:39:40 +01:00
FlorianMichael 2979b9d63d Also send version type; always send player details (#4795) 2026-01-18 21:00:52 +01:00
FlorianMichael a734a4a9d1 Make UserConnectionViaVersionPlatform a proxy platform by default (#4794) 2026-01-18 21:00:25 +01:00
273 changed files with 6035 additions and 2394 deletions

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
github: kennytv
patreon: kennytv
custom: ['https://florianmichael.de/donate']
custom: ['https://florianreuth.de/donate']
+6
View File
@@ -6,3 +6,9 @@ updates:
directory: "/"
schedule:
interval: "monthly"
- package-ecosystem: "gradle"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
+3 -3
View File
@@ -11,13 +11,13 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # 5.0.1
- name: Set up JDK 17
uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # 5.1.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # 5.2.0
with:
distribution: 'temurin'
java-version: 17
+3 -3
View File
@@ -16,13 +16,13 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # 5.0.1
- name: Set up JDK 17
uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # 5.1.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # 5.2.0
with:
distribution: 'temurin'
java-version: 17
@@ -1,22 +0,0 @@
name: Update Gradle Wrapper
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * 0"
permissions:
contents: write
pull-requests: write
jobs:
update-gradle-wrapper:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # 6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@512b1875f3b6270828abfe77b247d5895a2da1e5 # 2.1.0
+20 -9
View File
@@ -7,11 +7,15 @@
**Allows the connection of higher client versions to lower server versions -
it works on any platform you can think of.**
The base ViaVersion jar runs on Paper and Velocity. We also have projects integrating ViaVersion to run
on Fabric, Forge, Sponge, or as a standalone proxy to join from basically any client version on
any server version from the past decade. **See [HERE](https://viaversion.com) for an overview of the different Via\* projects.**
The base ViaVersion jar runs on [Paper](https://papermc.io/software/paper/)
and [Velocity](https://papermc.io/software/velocity/). We also have projects integrating ViaVersion to run
on [Fabric](https://github.com/ViaVersion/ViaFabric), [Forge](https://github.com/ViaVersion/ViaForge), [Bungee](https://github.com/ViaVersion/ViaBungee), [Sponge](https://github.com/ViaVersion/ViaSponge),
or as [a standalone proxy](https://github.com/ViaVersion/ViaProxy) to join from basically any client version on
any server version from the past decade. **See [HERE](https://viaversion.com) for an overview of the different Via\*
projects.**
Note that ViaVersion will be able to **run best on either Paper servers or through [ViaFabricPlus](https://github.com/ViaVersion/ViaFabricPlus?tab=readme-ov-file#viafabricplus)** due to having
Note that ViaVersion will be able to **run best on either Paper servers or
through [ViaFabricPlus](https://github.com/ViaVersion/ViaFabricPlus?tab=readme-ov-file#viafabricplus)** due to having
direct access to client/server state and more extensive API.
Supported Versions:
@@ -22,10 +26,16 @@ Supported Versions:
Snapshot support
--------
**ViaVersion will only be released a few days *after* a Minecraft update** unless the protocol changes of the update were trivial. If you want early-access, usually days or even weeks before the final release, you can subscribe to either:
- [GitHub Sponsors](https://github.com/sponsors/kennytv/sponsorships?sponsor=kennytv&tier_id=385613&preview=false) (preferred option. Use the `/verify` command on this Discord after), or alternatively
- [Patreon](https://www.patreon.com/kennytv/membership) (see the highest tier and make sure to link Patreon to your Discord account under Settings->Connections)
This also includes access to a private repository with the code, which will be pushed to the public repository after the given delay on a Minecraft update.
**ViaVersion will only be released a few days *after* a Minecraft update** unless the protocol changes of the update
were trivial. If you want early-access, usually days or even weeks before the final release, you can subscribe to
either:
- [GitHub Sponsors](https://github.com/sponsors/kennytv/sponsorships?sponsor=kennytv&tier_id=385613&preview=false) (
preferred option. Use the `/verify` command on this Discord after), or alternatively
- [Patreon](https://www.patreon.com/kennytv/membership) (see the highest tier and make sure to link Patreon to your
Discord account under Settings->Connections)
This also includes access to a private repository with the code, which will be pushed to the public repository after
the given delay on a Minecraft update.
Releases/Dev Builds
--------
@@ -89,7 +99,8 @@ You need JDK 17 or newer to build ViaVersion.
Mapping Files
--------------
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings). The generated mapping output is stored [here](./common/src/main/resources/assets/viaversion).
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings). The
generated mapping output is stored [here](./common/src/main/resources/assets/viaversion).
Resources
--------
@@ -1,6 +1,6 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -134,6 +134,15 @@ public interface ProtocolInfo {
void setUuid(UUID uuid);
/**
* Returns whether compression is enabled for this connection.
*
* @return whether compression is enabled
*/
boolean compressionEnabled();
void setCompressionEnabled(boolean compressionEnabled);
/**
* Returns the user's pipeline.
*
@@ -0,0 +1,123 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.data;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class FullIdentityMappings implements FullMappings {
private static final String[] EMPTY_ARRAY = new String[0];
private final Object2IntMap<String> stringToId;
private final String[] idToString;
private final Mappings mappings;
public FullIdentityMappings(final IdentifiersPair identifiersPair, final Mappings mappings) {
Preconditions.checkNotNull(mappings, "Mappings cannot be null");
this.mappings = mappings;
this.stringToId = FullMappingsBase.toInverseMap(identifiersPair.unmapped());
this.idToString = identifiersPair.unmapped().toArray(EMPTY_ARRAY);
}
private FullIdentityMappings(final Object2IntMap<String> stringToId, final String[] idToString, final Mappings mappings) {
this.stringToId = stringToId;
this.idToString = idToString;
this.mappings = mappings;
}
@Override
public int id(final String identifier) {
return stringToId.getInt(Key.stripMinecraftNamespace(identifier));
}
@Override
public int mappedId(final String mappedIdentifier) {
return id(mappedIdentifier);
}
@Override
public String identifier(final int id) {
if (id < 0 || id >= idToString.length) {
return null;
}
final String identifier = idToString[id];
return Key.namespaced(identifier);
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
}
@Override
public @Nullable String mappedIdentifier(final int mappedId) {
return identifier(mappedId);
}
@Override
public @Nullable String mappedIdentifier(final String identifier) {
return identifier(identifier);
}
@Override
public int getNewId(int id) {
return mappings.getNewId(id);
}
@Override
public void setNewId(int id, int mappedId) {
mappings.setNewId(id, mappedId);
}
@Override
public int size() {
return mappings.size();
}
@Override
public int mappedSize() {
return mappings.mappedSize();
}
@Override
public boolean isIdentity() {
return true;
}
@Override
public boolean isIntIdIdentity() {
return true;
}
@Override
public FullMappings inverse() {
return new FullIdentityMappings(stringToId, idToString, mappings.inverse());
}
}
@@ -77,6 +77,14 @@ public interface FullMappings extends BiMappings {
*/
@Nullable String mappedIdentifier(String identifier);
/**
* Returns whether the int id mappings are identity mappings.
*
* @return whether the int id mappings are identity mappings
* @see #isIdentity()
*/
boolean isIntIdIdentity();
@Override
FullMappings inverse();
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.data;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
@@ -37,13 +38,13 @@ public class FullMappingsBase implements FullMappings {
private final String[] mappedIdToString;
private final Mappings mappings;
public FullMappingsBase(final List<String> unmappedIdentifiers, final List<String> mappedIdentifiers, final Mappings mappings) {
public FullMappingsBase(final IdentifiersPair identifiersPair, final Mappings mappings) {
Preconditions.checkNotNull(mappings, "Mappings cannot be null");
this.mappings = mappings;
this.stringToId = toInverseMap(unmappedIdentifiers);
this.mappedStringToId = toInverseMap(mappedIdentifiers);
this.idToString = unmappedIdentifiers.toArray(EMPTY_ARRAY);
this.mappedIdToString = mappedIdentifiers.toArray(EMPTY_ARRAY);
this.stringToId = toInverseMap(identifiersPair.unmapped());
this.idToString = identifiersPair.unmapped().toArray(EMPTY_ARRAY);
this.mappedStringToId = toInverseMap(identifiersPair.mapped());
this.mappedIdToString = identifiersPair.mapped().toArray(EMPTY_ARRAY);
}
private FullMappingsBase(final Object2IntMap<String> stringToId, final Object2IntMap<String> mappedStringToId, final String[] idToString, final String[] mappedIdToString, final Mappings mappings) {
@@ -54,7 +55,11 @@ public class FullMappingsBase implements FullMappings {
this.mappings = mappings;
}
private static Object2IntMap<String> toInverseMap(final List<String> list) {
public static FullMappings of(final IdentifiersPair identifiersPair, final Mappings mappings) {
return mappings.isIdentity() && identifiersPair.identity() ? new FullIdentityMappings(identifiersPair, mappings) : new FullMappingsBase(identifiersPair, mappings);
}
static Object2IntMap<String> toInverseMap(final List<String> list) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(list.size());
map.defaultReturnValue(-1);
for (int i = 0; i < list.size(); i++) {
@@ -135,6 +140,11 @@ public class FullMappingsBase implements FullMappings {
return mappings.mappedSize();
}
@Override
public boolean isIntIdIdentity() {
return mappings.isIdentity();
}
@Override
public FullMappings inverse() {
return new FullMappingsBase(mappedStringToId, stringToId, mappedIdToString, idToString, mappings.inverse());
@@ -38,4 +38,9 @@ public record IdentityMappings(int size, int mappedSize) implements Mappings {
public Mappings inverse() {
return new IdentityMappings(mappedSize, size);
}
@Override
public boolean isIdentity() {
return true;
}
}
@@ -170,6 +170,8 @@ public interface MappingData {
@Nullable FullMappings getRecipeSerializerMappings();
@Nullable FullMappings getSlotDisplayMappings();
@Nullable FullMappings getDataComponentSerializerMappings();
default @Nullable FullMappings getFullMappings(final MappingType mappingType) {
@@ -26,6 +26,7 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.TagData;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
@@ -45,6 +46,7 @@ public class MappingDataBase implements MappingData {
protected FullMappings entityMappings;
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings slotDisplayMappings;
protected FullMappings attributeMappings;
protected FullMappings blockEntityMappings;
protected ParticleMappings particleMappings;
@@ -89,19 +91,19 @@ public class MappingDataBase implements MappingData {
entityMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "entities");
argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes");
slotDisplayMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "slot_displays");
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
blockEntityMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "blockentities");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
if (unmappedParticles != null && mappedParticles != null) {
final IdentifiersPair particleIdentifiers = identifiersFromGlobalIds(unmappedIdentifierData, mappedIdentifierData, "particles");
if (particleIdentifiers != null) {
Mappings particleMappings = loadMappings(data, "particles");
if (particleMappings == null) {
particleMappings = new IdentityMappings(unmappedParticles.size(), mappedParticles.size());
particleMappings = new IdentityMappings(particleIdentifiers.unmapped().size(), particleIdentifiers.mapped().size());
}
this.particleMappings = new ParticleMappings(unmappedParticles, mappedParticles, particleMappings);
this.particleMappings = new ParticleMappings(particleIdentifiers, particleMappings);
}
} else {
// Might not have identifiers in older versions
@@ -130,6 +132,10 @@ public class MappingDataBase implements MappingData {
return MappingDataLoader.INSTANCE.identifiersFromGlobalIds(mappingsTag, key);
}
protected @Nullable IdentifiersPair identifiersFromGlobalIds(final CompoundTag unmappedTag, final CompoundTag mappedTag, final String key) {
return MappingDataLoader.INSTANCE.identifiersFromGlobalIds(unmappedTag, mappedTag, key);
}
protected @Nullable CompoundTag readMappingsFile(final String name) {
return MappingDataLoader.INSTANCE.loadNBT(name);
}
@@ -156,14 +162,12 @@ public class MappingDataBase implements MappingData {
return null;
}
final List<String> unmappedIdentifiers = identifiersFromGlobalIds(unmappedIdentifiersTag, key);
final List<String> mappedIdentifiers = identifiersFromGlobalIds(mappedIdentifiersTag, key);
final IdentifiersPair identifiersPair = identifiersFromGlobalIds(unmappedIdentifiersTag, mappedIdentifiersTag, key);
Mappings mappings = loadBiMappings(data, key); // Load as bi-mappings to keep the inverse cached
if (mappings == null) {
mappings = new IdentityMappings(unmappedIdentifiers.size(), mappedIdentifiers.size());
mappings = new IdentityMappings(identifiersPair.unmapped().size(), identifiersPair.mapped().size());
}
return new FullMappingsBase(unmappedIdentifiers, mappedIdentifiers, mappings);
return FullMappingsBase.of(identifiersPair, mappings);
}
protected @Nullable BiMappings loadBiMappings(final CompoundTag data, final String key) {
@@ -335,6 +339,11 @@ public class MappingDataBase implements MappingData {
return recipeSerializerMappings;
}
@Override
public @Nullable FullMappings getSlotDisplayMappings() {
return slotDisplayMappings;
}
@Override
public @Nullable IntSet changedBlocks() {
return changedBlocks;
@@ -81,8 +81,9 @@ public class MappingDataLoader {
for (final Map.Entry<String, Tag> entry : globalIdentifiers.entrySet()) {
//noinspection unchecked
final ListTag<StringTag> value = (ListTag<StringTag>) entry.getValue();
final String[] array = new String[value.size()];
for (int i = 0, size = value.size(); i < size; i++) {
final int size = value.size();
final String[] array = new String[size];
for (int i = 0; i < size; i++) {
array[i] = value.get(i).getValue();
}
GLOBAL_IDENTIFIER_INDEXES.put(entry.getKey(), array);
@@ -272,13 +273,60 @@ public class MappingDataLoader {
public @Nullable List<String> identifiersFromGlobalIds(final CompoundTag mappingsTag, final String key) {
final Mappings mappings = loadMappings(mappingsTag, key);
if (mappings == null) {
return mappings != null ? identifiers(mappings, key) : null;
}
/**
* Returns a pair of identifier lists, also keeping track of whether the two lists are equal.
*
* @param unmappedTag unmapped mappings tag
* @param mappedTag mapped mappings tag
* @param key mappings key
* @return pair of identifier lists
*/
public @Nullable IdentifiersPair identifiersFromGlobalIds(final CompoundTag unmappedTag, final CompoundTag mappedTag, final String key) {
final Mappings unmapped = loadMappings(unmappedTag, key);
if (unmapped == null) {
return null;
}
final Mappings mapped = loadMappings(mappedTag, key);
if (mapped == null) {
return null;
}
final int size = unmapped.size();
if (size != mapped.size()) {
return new IdentifiersPair(identifiers(unmapped, key), identifiers(mapped, key), false);
}
// Small optimization to only load one array and reduce loading for full mappings
final List<String> unmappedIdentifiers = new ArrayList<>(size);
final List<String> mappedIdentifiers = new ArrayList<>(size);
boolean identity = true;
for (int i = 0; i < size; i++) {
final int unmappedGlobalId = unmapped.getNewId(i);
final int mappedGlobalId = mapped.getNewId(i);
final String unmappedIdentifier = identifierFromGlobalId(key, unmappedGlobalId);
if (unmappedGlobalId == mappedGlobalId) {
unmappedIdentifiers.add(unmappedIdentifier);
mappedIdentifiers.add(unmappedIdentifier);
continue;
}
identity = false;
unmappedIdentifiers.add(unmappedIdentifier);
mappedIdentifiers.add(identifierFromGlobalId(key, mappedGlobalId));
}
return identity ? new IdentifiersPair(unmappedIdentifiers) : new IdentifiersPair(unmappedIdentifiers, mappedIdentifiers);
}
private List<String> identifiers(final Mappings mappings, final String key) {
final List<String> identifiers = new ArrayList<>(mappings.size());
for (int i = 0; i < mappings.size(); i++) {
identifiers.add(identifierFromGlobalId(key, mappings.getNewId(i)));
final int globalId = mappings.getNewId(i);
identifiers.add(identifierFromGlobalId(key, globalId));
}
return identifiers;
}
@@ -342,4 +390,15 @@ public class MappingDataLoader {
T create(V mappings, int mappedSize);
}
public record IdentifiersPair(List<String> unmapped, List<String> mapped, boolean identity) {
public IdentifiersPair(final List<String> unmapped, final List<String> mapped) {
this(unmapped, mapped, false);
}
public IdentifiersPair(final List<String> identifiers) {
this(identifiers, identifiers, true);
}
}
}
@@ -22,6 +22,8 @@
*/
package com.viaversion.viaversion.api.data;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface Mappings {
/**
@@ -84,4 +86,40 @@ public interface Mappings {
* @return mappings with keys and values swapped
*/
Mappings inverse();
/**
* Returns whether the mappings are unchanged identity mappings.
*
* @return whether the mappings are unchanged identity mappings
*/
default boolean isIdentity() {
return false;
}
/**
* Returns whether the mappings null or identity mappings.
*
* @param mappings mappings
* @return whether the mappings are identity mappings
* @see #isFullIdentity(Mappings)
*/
static boolean isIntIdIdentity(@Nullable final Mappings mappings) {
if (mappings == null) {
return true;
}
return mappings instanceof FullMappings fullMappings ? fullMappings.isIntIdIdentity() : mappings.isIdentity();
}
/**
* Returns whether the mappings null or full identity mappings.
* Stronger than {@link #isIntIdIdentity(Mappings)}, but equal to that if not {@link FullMappings}.
*
* @param mappings mappings
* @return whether the mappings are full identity mappings
* @see #isIntIdIdentity(Mappings)
*/
static boolean isFullIdentity(@Nullable final Mappings mappings) {
return mappings == null || mappings.isIdentity();
}
}
@@ -22,16 +22,16 @@
*/
package com.viaversion.viaversion.api.data;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import java.util.List;
public class ParticleMappings extends FullMappingsBase {
private final IntList itemParticleIds = new IntArrayList(4);
private final IntList blockParticleIds = new IntArrayList(4);
public ParticleMappings(final List<String> unmappedIdentifiers, final List<String> mappedIdentifiers, final Mappings mappings) {
super(unmappedIdentifiers, mappedIdentifiers, mappings);
public ParticleMappings(final IdentifiersPair identifiersPair, final Mappings mappings) {
super(identifiersPair, mappings);
addBlockParticle("block");
addBlockParticle("falling_dust");
addBlockParticle("block_marker");
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
@@ -40,6 +41,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final String tagKey) {
Preconditions.checkNotNull(tagKey);
return new HolderSetImpl.Tag(tagKey);
}
@@ -50,6 +52,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final int[] ids) {
Preconditions.checkNotNull(ids);
return new HolderSetImpl.Ids(ids);
}
@@ -58,8 +58,8 @@ public record PaintingVariant(int width, int height, String assetId, @Nullable T
final int width = Types.VAR_INT.readPrimitive(buffer);
final int height = Types.VAR_INT.readPrimitive(buffer);
final String assetId = Types.STRING.read(buffer);
final Tag title = Types.OPTIONAL_TAG.read(buffer);
final Tag author = Types.OPTIONAL_TAG.read(buffer);
final Tag title = Types.TRUSTED_OPTIONAL_TAG.read(buffer);
final Tag author = Types.TRUSTED_OPTIONAL_TAG.read(buffer);
return new PaintingVariant(width, height, assetId, title, author);
}
@@ -68,8 +68,8 @@ public record PaintingVariant(int width, int height, String assetId, @Nullable T
Types.VAR_INT.writePrimitive(buffer, variant.width());
Types.VAR_INT.writePrimitive(buffer, variant.height());
Types.STRING.write(buffer, variant.assetId());
Types.OPTIONAL_TAG.write(buffer, variant.title());
Types.OPTIONAL_TAG.write(buffer, variant.author());
Types.TRUSTED_OPTIONAL_TAG.write(buffer, variant.title());
Types.TRUSTED_OPTIONAL_TAG.write(buffer, variant.author());
}
@Override
@@ -79,8 +79,8 @@ public record PaintingVariant(int width, int height, String assetId, @Nullable T
.write("width", Types.INT, value.width())
.write("height", Types.INT, value.height())
.write("asset_id", Types.IDENTIFIER, Key.of(value.assetId()))
.writeOptional("title", Types.TAG, value.title())
.writeOptional("author", Types.TAG, value.author()));
.writeOptional("title", Types.TRUSTED_TAG, value.title())
.writeOptional("author", Types.TRUSTED_TAG, value.author()));
}
@Override
@@ -34,7 +34,9 @@ public enum RegistryType implements RegistryKey {
FLUID("fluid"),
ENTITY("entity_type"),
GAME_EVENT("game_event"),
ENCHANTMENT("enchantment");
ENCHANTMENT("enchantment"),
DAMAGE_TYPE("damage_type"),
BANNER_PATTERN("banner_pattern");
private static final Map<String, RegistryType> MAP = new HashMap<>();
private static final RegistryType[] VALUES = values();
@@ -61,6 +61,17 @@ public interface ChunkSection {
void setNonAirBlocksCount(int nonAirBlocksCount);
/**
* Returns the number of fluid blocks in this section.
* <p>
* Available with versions 26.1+.
*
* @return fluid blocks in this section
*/
int getFluidCount();
void setFluidCount(int fluidCount);
/**
* Returns whether this section holds light data.
* Only true for &lt; 1.14 chunks.
@@ -30,6 +30,7 @@ public class ChunkSectionImpl implements ChunkSection {
private final EnumMap<PaletteType, DataPalette> palettes = new EnumMap<>(PaletteType.class);
private ChunkSectionLight light;
private int nonAirBlocksCount;
private int fluidCount;
public ChunkSectionImpl() {
}
@@ -58,6 +59,16 @@ public class ChunkSectionImpl implements ChunkSection {
this.nonAirBlocksCount = nonAirBlocksCount;
}
@Override
public int getFluidCount() {
return fluidCount;
}
@Override
public void setFluidCount(final int fluidCount) {
this.fluidCount = fluidCount;
}
@Override
public @Nullable ChunkSectionLight getLight() {
return light;
@@ -160,6 +160,10 @@ public final class StructuredDataContainer implements Copyable {
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, @Nullable V> valueMapper) {
replace(key, toKey, valueMapper, null);
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, @Nullable V> valueMapper, final Runnable emptyValueHandler) {
final StructuredData<?> data = this.data.remove(key);
if (data == null) {
return;
@@ -175,6 +179,9 @@ public final class StructuredDataContainer implements Copyable {
} else {
// Also replace the key for empty data
setEmpty(toKey);
if (emptyValueHandler != null) {
emptyValueHandler.run();
}
}
}
@@ -37,6 +37,7 @@ import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.AttackRange;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
@@ -47,7 +48,8 @@ import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.BlocksAttacks;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant26_1;
import com.viaversion.viaversion.api.minecraft.item.data.DamageType;
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DebugStickState;
@@ -65,12 +67,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.ItemModel;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable.JukeboxSong;
import com.viaversion.viaversion.api.minecraft.item.data.KineticWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.LockCode;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PiercingWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
import com.viaversion.viaversion.api.minecraft.item.data.ProvidesBannerPatterns;
import com.viaversion.viaversion.api.minecraft.item.data.ProvidesTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.Repairable;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
@@ -98,8 +102,8 @@ import com.viaversion.viaversion.util.Unit;
* Holds data component keys.
*
* @param identifier string identifier
* @param type data type
* @param <T> data type
* @param type data type
* @param <T> data type
* @see VersionedTypes
*/
public record StructuredDataKey<T>(String identifier, Type<T> type) {
@@ -113,7 +117,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unit> UNBREAKABLE1_21_5 = new StructuredDataKey<>("unbreakable", Types.EMPTY);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Float> MINIMUM_ATTACK_CHARGE = new StructuredDataKey<>("minimum_attack_charge", Types.FLOAT);
public static final StructuredDataKey<DamageType> DAMAGE_TYPE = new StructuredDataKey<>("damage_type", DamageType.TYPE);
public static final StructuredDataKey<DamageType> DAMAGE_TYPE1_21_11 = new StructuredDataKey<>("damage_type", DamageType.TYPE1_21_11);
public static final StructuredDataKey<Integer> DAMAGE_TYPE26_1 = new StructuredDataKey<>("damage_type", new SynchronizedRegistryValueType(RegistryKey.of("damage_type")));
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<ItemModel> ITEM_MODEL = new StructuredDataKey<>("item_model", ItemModel.TYPE);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TEXT_COMPONENT_TAG, 256));
@@ -142,7 +147,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE);
public static final StructuredDataKey<UseCooldown> USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE);
public static final StructuredDataKey<Unit> FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY);
public static final StructuredDataKey<DamageResistant> DAMAGE_RESISTANT = new StructuredDataKey<>("damage_resistant", DamageResistant.TYPE);
public static final StructuredDataKey<DamageResistant1_21_2> DAMAGE_RESISTANT1_21_2 = new StructuredDataKey<>("damage_resistant", DamageResistant1_21_2.TYPE);
public static final StructuredDataKey<DamageResistant26_1> DAMAGE_RESISTANT26_1 = new StructuredDataKey<>("damage_resistant", DamageResistant26_1.TYPE);
public static final StructuredDataKey<ToolProperties> TOOL1_20_5 = new StructuredDataKey<>("tool", ToolProperties.TYPE1_20_5);
public static final StructuredDataKey<ToolProperties> TOOL1_21_5 = new StructuredDataKey<>("tool", ToolProperties.TYPE1_21_5);
public static final StructuredDataKey<Weapon> WEAPON = new StructuredDataKey<>("weapon", Weapon.TYPE);
@@ -155,12 +161,15 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<Key> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.IDENTIFIER);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS1_21_5 = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE1_21_5);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS26_1 = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE26_1);
public static final StructuredDataKey<PiercingWeapon> PIERCING_WEAPON = new StructuredDataKey<>("piercing_weapon", PiercingWeapon.TYPE);
public static final StructuredDataKey<KineticWeapon> KINETIC_WEAPON = new StructuredDataKey<>("kinetic_weapon", KineticWeapon.TYPE);
public static final StructuredDataKey<SwingAnimation> SWING_ANIMATION = new StructuredDataKey<>("swing_animation", SwingAnimation.TYPE);
public static final StructuredDataKey<Integer> ADDITIONAL_TRADE_COST = new StructuredDataKey<>("additional_trade_cost", Types.VAR_INT);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS1_20_5 = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE1_20_5);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS1_21_5 = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE1_21_5);
public static final StructuredDataKey<Integer> DYE = new StructuredDataKey<>("dye", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<DyedColor> DYED_COLOR1_20_5 = new StructuredDataKey<>("dyed_color", DyedColor.TYPE1_20_5);
public static final StructuredDataKey<DyedColor> DYED_COLOR1_21_5 = new StructuredDataKey<>("dyed_color", DyedColor.TYPE1_21_5);
public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Types.INT);
@@ -186,11 +195,15 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Holder<Instrument1_20_5>> INSTRUMENT1_20_5 = new StructuredDataKey<>("instrument", Instrument1_20_5.TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<EitherHolder<Instrument1_21_2>> INSTRUMENT1_21_5 = new StructuredDataKey<>("instrument", Instrument1_21_2.EITHER_HOLDER_TYPE);
public static final StructuredDataKey<ProvidesTrimMaterial> PROVIDES_TRIM_MATERIAL = new StructuredDataKey<>("provides_trim_material", ProvidesTrimMaterial.TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT26_1 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<ProvidesTrimMaterial> PROVIDES_TRIM_MATERIAL1_21_5 = new StructuredDataKey<>("provides_trim_material", ProvidesTrimMaterial.TYPE);
public static final StructuredDataKey<Holder<ArmorTrimMaterial>> PROVIDES_TRIM_MATERIAL26_1 = new StructuredDataKey<>("provides_trim_material", ArmorTrimMaterial.TYPE1_21_5);
public static final StructuredDataKey<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE1_21 = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE1_21);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE1_21_5 = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE1_21_5);
public static final StructuredDataKey<Key> PROVIDES_BANNER_PATTERNS = new StructuredDataKey<>("provides_banner_patterns", Types.TAG_KEY);
public static final StructuredDataKey<Holder<JukeboxSong>> JUKEBOX_PLAYABLE26_1 = new StructuredDataKey<>("jukebox_playable", JukeboxSong.TYPE);
public static final StructuredDataKey<Key> PROVIDES_BANNER_PATTERNS1_21_5 = new StructuredDataKey<>("provides_banner_patterns", Types.TAG_KEY);
public static final StructuredDataKey<ProvidesBannerPatterns> PROVIDES_BANNER_PATTERNS26_1 = new StructuredDataKey<>("provides_banner_patterns", ProvidesBannerPatterns.TYPE);
public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Types.TAG);
public static final StructuredDataKey<LodestoneTracker> LODESTONE_TRACKER = new StructuredDataKey<>("lodestone_tracker", LodestoneTracker.TYPE);
public static final StructuredDataKey<FireworkExplosion> FIREWORK_EXPLOSION = new StructuredDataKey<>("firework_explosion", FireworkExplosion.TYPE);
@@ -223,8 +236,10 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> RABBIT_VARIANT = new StructuredDataKey<>("rabbit/variant", EnumTypes.RABBIT_VARIANT);
public static final StructuredDataKey<Integer> PIG_VARIANT = new StructuredDataKey<>("pig/variant", new SynchronizedRegistryValueType(RegistryKey.of("pig_variant")));
public static final StructuredDataKey<Integer> COW_VARIANT = new StructuredDataKey<>("cow/variant", new SynchronizedRegistryValueType(RegistryKey.of("cow_variant")));
public static final StructuredDataKey<Either<Integer, String>> CHICKEN_VARIANT = new StructuredDataKey<>("chicken/variant", new SynchronizedRegistryEitherType(RegistryKey.of("chicken_variant")));
public static final StructuredDataKey<Either<Integer, String>> ZOMBIE_NAUTILUS_VARIANT = new StructuredDataKey<>("zombie_nautilus/variant", new SynchronizedRegistryEitherType(RegistryKey.of("zombie_nautilus_variant"))); // ???
public static final StructuredDataKey<Either<Integer, String>> CHICKEN_VARIANT1_21_5 = new StructuredDataKey<>("chicken/variant", new SynchronizedRegistryEitherType(RegistryKey.of("chicken_variant")));
public static final StructuredDataKey<Integer> CHICKEN_VARIANT26_1 = new StructuredDataKey<>("chicken/variant", new SynchronizedRegistryValueType(RegistryKey.of("chicken_variant")));
public static final StructuredDataKey<Either<Integer, String>> ZOMBIE_NAUTILUS_VARIANT1_21_11 = new StructuredDataKey<>("zombie_nautilus/variant", new SynchronizedRegistryEitherType(RegistryKey.of("zombie_nautilus_variant"))); // ???
public static final StructuredDataKey<Integer> ZOMBIE_NAUTILUS_VARIANT26_1 = new StructuredDataKey<>("zombie_nautilus/variant", new SynchronizedRegistryValueType(RegistryKey.of("zombie_nautilus_variant")));
public static final StructuredDataKey<Integer> FROG_VARIANT = new StructuredDataKey<>("frog/variant", new SynchronizedRegistryValueType(RegistryKey.of("frog_variant")));
public static final StructuredDataKey<Integer> HORSE_VARIANT = new StructuredDataKey<>("horse/variant", EnumTypes.HORSE_VARIANT);
public static final StructuredDataKey<Holder<PaintingVariant>> PAINTING_VARIANT = new StructuredDataKey<>("painting/variant", PaintingVariant.TYPE1_21_2);
@@ -234,6 +249,10 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> CAT_COLLAR = new StructuredDataKey<>("cat/collar", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> SHEEP_COLOR = new StructuredDataKey<>("sheep/color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> SHULKER_COLOR = new StructuredDataKey<>("shulker/color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> PIG_SOUND_VARIANT = new StructuredDataKey<>("pig/sound_variant", new SynchronizedRegistryValueType(RegistryKey.of("pig_sound_variant")));
public static final StructuredDataKey<Integer> COW_SOUND_VARIANT = new StructuredDataKey<>("cow/sound_variant", new SynchronizedRegistryValueType(RegistryKey.of("cow_sound_variant")));
public static final StructuredDataKey<Integer> CHICKEN_SOUND_VARIANT = new StructuredDataKey<>("chicken/sound_variant", new SynchronizedRegistryValueType(RegistryKey.of("chicken_sound_variant")));
public static final StructuredDataKey<Integer> CAT_SOUND_VARIANT = new StructuredDataKey<>("cat/sound_variant", new SynchronizedRegistryValueType(RegistryKey.of("cat_sound_variant")));
// These are only safe to use after protocol loading
public static final StructuredDataKeys1_20_5 V1_20_5 = VersionedTypes.V1_20_5.structuredDataKeys();
@@ -35,9 +35,9 @@ public class StructuredDataKeys1_21_2 extends VersionedStructuredDataKeys {
public final StructuredDataKey<Item> useRemainder;
public StructuredDataKeys1_21_2(final VersionedTypesHolder types) {
this.container = add("container", new ContainerContentsType(types.item()));
this.chargedProjectiles = add("charged_projectiles", types.itemArray());
this.bundleContents = add("bundle_contents", types.itemArray());
this.useRemainder = add("use_remainder", types.item());
this.container = add("container", new ContainerContentsType(types.optionalItemTemplate()));
this.chargedProjectiles = add("charged_projectiles", types.itemTemplateArray());
this.bundleContents = add("bundle_contents", types.itemTemplateArray());
this.useRemainder = add("use_remainder", types.itemTemplate());
}
}
@@ -33,8 +33,8 @@ public final class EntityDataTypes1_20_3 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType = add(7, Types.ITEM1_20_2);
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -33,8 +33,8 @@ public final class EntityDataTypes1_20_5 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -35,8 +35,8 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -34,8 +34,8 @@ public final class EntityDataTypes1_21_11 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -47,7 +47,7 @@ public final class EntityDataTypes1_21_11 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
@@ -35,8 +35,8 @@ public final class EntityDataTypes1_21_2 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -34,8 +34,8 @@ public final class EntityDataTypes1_21_5 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -34,8 +34,8 @@ public final class EntityDataTypes1_21_9 extends AbstractEntityDataTypes {
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
@@ -0,0 +1,82 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entitydata.types;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public final class EntityDataTypes26_1 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
public final EntityDataType catSoundVariant = add(22, Types.VAR_INT);
public final EntityDataType cowVariantType = add(23, Types.VAR_INT);
public final EntityDataType cowSoundVariant = add(24, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(25, Types.VAR_INT);
public final EntityDataType wolfSoundVariantType = add(26, Types.VAR_INT);
public final EntityDataType frogVariantType = add(27, Types.VAR_INT);
public final EntityDataType pigVariantType = add(28, Types.VAR_INT);
public final EntityDataType pigSoundVariant = add(29, Types.VAR_INT);
public final EntityDataType chickenVariantType = add(30, Types.VAR_INT);
public final EntityDataType chickenSoundVariant = add(31, Types.VAR_INT);
public final EntityDataType zombieNautilusVariantType = add(32, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(33, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(34, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(35, Types.VAR_INT);
public final EntityDataType armadilloState = add(36, Types.VAR_INT);
public final EntityDataType copperGolemState = add(37, Types.VAR_INT);
public final EntityDataType weatheringCopperState = add(38, Types.VAR_INT);
public final EntityDataType vector3FType = add(39, Types.VECTOR3F);
public final EntityDataType quaternionType = add(40, Types.QUATERNION);
public final EntityDataType mannequinProfileType = add(41, Types.RESOLVABLE_PROFILE);
public final EntityDataType humanoidArmType = add(42, Types.VAR_INT);
public EntityDataTypes26_1(final VersionedTypesHolder types) {
super(43);
this.itemType = add(7, types.item());
this.particleType = add(16, types.particle());
this.particlesType = add(17, types.particles());
}
}
@@ -76,4 +76,23 @@ public interface Item extends ItemBase {
*/
@Override
Item copy();
/**
* Returns whether the item is a template item.
*
* @return whether the item is a template item
*/
default boolean isTemplate() {
return false;
}
/**
* Returns whether the item is null or empty.
*
* @param item item
* @return whether the item is null or empty
*/
static boolean isEmpty(@Nullable final Item item) {
return item == null || item.isEmpty();
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
public class StructuredItemTemplate extends StructuredItem {
public StructuredItemTemplate(final int identifier, final int amount) {
super(identifier, amount, new StructuredDataContainer());
}
public StructuredItemTemplate(final int identifier, final int amount, final StructuredDataContainer data) {
super(identifier, amount, data);
}
@Override
public void setIdentifier(final int identifier) {
Preconditions.checkArgument(identifier > 0, "Template item cannot be empty");
super.setIdentifier(identifier);
}
@Override
public void setAmount(final int amount) {
Preconditions.checkArgument(amount > 0, "Template item cannot be empty");
super.setAmount(amount);
}
@Override
public boolean isTemplate() {
return true;
}
@Override
public StructuredItemTemplate copy() {
return new StructuredItemTemplate(identifier(), amount(), dataContainer().copy());
}
}
@@ -56,8 +56,8 @@ public record AttackRange(float minRange, float maxRange,
@Override
public void write(final Ops ops, final AttackRange AttackRange) {
ops.writeMap(map -> map
.writeOptional("min_range", Types.FLOAT, AttackRange.minRange, 0F)
.writeOptional("max_range", Types.FLOAT, AttackRange.maxRange, 3F)
.writeOptional("min_reach", Types.FLOAT, AttackRange.minRange, 0F)
.writeOptional("max_reach", Types.FLOAT, AttackRange.maxRange, 3F)
.writeOptional("min_creative_reach", Types.FLOAT, AttackRange.minCreativeRange, 0F)
.writeOptional("max_creative_reach", Types.FLOAT, AttackRange.maxCreativeRange, 5F)
.writeOptional("hitbox_margin", Types.FLOAT, AttackRange.hitboxMargin, 0.3F)
@@ -37,6 +37,7 @@ import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) implements Copyable, Rewritable {
@@ -226,7 +227,7 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
}
public static class Display implements Copyable {
public static final String[] DISPLAY_TYPES = {"default", "hidden", "override_text"};
public static final String[] DISPLAY_TYPES = {"default", "hidden", "override"};
public static final Display DEFAULT = new Display(0);
private final int id;
@@ -246,6 +247,17 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
public Display copy() {
return this;
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof final Display display)) return false;
return id == display.id;
}
@Override
public int hashCode() {
return id;
}
}
public static final class OverrideText extends Display {
@@ -271,5 +283,19 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
public OverrideText copy() {
return new OverrideText(this.component.copy());
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof final OverrideText that)) return false;
if (!super.equals(o)) return false;
return Objects.equals(component, that.component);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + Objects.hashCode(component);
return result;
}
}
}
@@ -43,12 +43,12 @@ public record BlocksAttacks(
float disableCooldownScale,
DamageReduction[] damageReductions,
ItemDamageFunction itemDamage,
@Nullable String bypassedByTag,
@Nullable HolderSet bypassedBy, // always a tag before 26.1
@Nullable Holder<SoundEvent> blockSound,
@Nullable Holder<SoundEvent> disableSound
) implements Rewritable {
public static final Type<BlocksAttacks> TYPE = new Type<>(BlocksAttacks.class) {
public static final Type<BlocksAttacks> TYPE1_21_5 = new Type<>(BlocksAttacks.class) {
@Override
public BlocksAttacks read(final ByteBuf buffer) {
@@ -59,7 +59,7 @@ public record BlocksAttacks(
final String bypassedByTag = Types.OPTIONAL_STRING.read(buffer);
final Holder<SoundEvent> blockSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
final Holder<SoundEvent> disableSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
return new BlocksAttacks(blockDelaySeconds, disableCooldownScale, damageReductions, itemDamage, bypassedByTag, blockSound, disableSound);
return new BlocksAttacks(blockDelaySeconds, disableCooldownScale, damageReductions, itemDamage, bypassedByTag != null ? HolderSet.of(bypassedByTag) : null, blockSound, disableSound);
}
@Override
@@ -68,7 +68,7 @@ public record BlocksAttacks(
buffer.writeFloat(value.disableCooldownScale());
DamageReduction.ARRAY_TYPE.write(buffer, value.damageReductions());
ItemDamageFunction.TYPE.write(buffer, value.itemDamage());
Types.OPTIONAL_STRING.write(buffer, value.bypassedByTag());
Types.OPTIONAL_STRING.write(buffer, value.bypassedBy() != null ? value.bypassedBy().tagKey() : null);
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.blockSound());
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.disableSound());
}
@@ -82,7 +82,47 @@ public record BlocksAttacks(
.writeOptional("disable_cooldown_scale", Types.FLOAT, value.disableCooldownScale(), 1F)
.writeOptional("damage_reductions", DamageReduction.ARRAY_TYPE, value.damageReductions(), defaultDamageReductions)
.writeOptional("item_damage", ItemDamageFunction.TYPE, value.itemDamage(), defaultItemDamage)
.writeOptional("bypassed_by", Types.TAG_KEY, value.bypassedByTag() != null ? Key.of(value.bypassedByTag()) : null)
.writeOptional("bypassed_by", Types.TAG_KEY, value.bypassedBy() != null ? Key.of(value.bypassedBy().tagKey()) : null)
.writeOptional("block_sound", Types.SOUND_EVENT, value.blockSound())
.writeOptional("disabled_sound", Types.SOUND_EVENT, value.disableSound()));
}
};
public static final Type<BlocksAttacks> TYPE26_1 = new Type<>(BlocksAttacks.class) {
@Override
public BlocksAttacks read(final ByteBuf buffer) {
final float blockDelaySeconds = buffer.readFloat();
final float disableCooldownScale = buffer.readFloat();
final DamageReduction[] damageReductions = DamageReduction.ARRAY_TYPE.read(buffer);
final ItemDamageFunction itemDamage = ItemDamageFunction.TYPE.read(buffer);
final HolderSet bypassedByTag = Types.OPTIONAL_HOLDER_SET.read(buffer);
final Holder<SoundEvent> blockSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
final Holder<SoundEvent> disableSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
return new BlocksAttacks(blockDelaySeconds, disableCooldownScale, damageReductions, itemDamage, bypassedByTag, blockSound, disableSound);
}
@Override
public void write(final ByteBuf buffer, final BlocksAttacks value) {
buffer.writeFloat(value.blockDelaySeconds());
buffer.writeFloat(value.disableCooldownScale());
DamageReduction.ARRAY_TYPE.write(buffer, value.damageReductions());
ItemDamageFunction.TYPE.write(buffer, value.itemDamage());
Types.OPTIONAL_HOLDER_SET.write(buffer, value.bypassedBy());
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.blockSound());
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.disableSound());
}
@Override
public void write(final Ops ops, final BlocksAttacks value) {
final DamageReduction[] defaultDamageReductions = {new DamageReduction(90, null, 0, 1)};
final ItemDamageFunction defaultItemDamage = new ItemDamageFunction(1, 0, 1);
ops.writeMap(map -> map
.writeOptional("block_delay_seconds", Types.FLOAT, value.blockDelaySeconds(), 0F)
.writeOptional("disable_cooldown_scale", Types.FLOAT, value.disableCooldownScale(), 1F)
.writeOptional("damage_reductions", DamageReduction.ARRAY_TYPE, value.damageReductions(), defaultDamageReductions)
.writeOptional("item_damage", ItemDamageFunction.TYPE, value.itemDamage(), defaultItemDamage)
.writeOptional("bypassed_by", Types.HOLDER_SET, value.bypassedBy())
.writeOptional("block_sound", Types.SOUND_EVENT, value.blockSound())
.writeOptional("disabled_sound", Types.SOUND_EVENT, value.disableSound()));
}
@@ -92,7 +132,7 @@ public record BlocksAttacks(
public BlocksAttacks rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> blockSound = SoundEvent.rewriteHolder(this.blockSound, Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> disableSound = SoundEvent.rewriteHolder(this.disableSound, Rewritable.soundRewriteFunction(protocol, clientbound));
return new BlocksAttacks(this.blockDelaySeconds, this.disableCooldownScale, this.damageReductions, this.itemDamage, this.bypassedByTag, blockSound, disableSound);
return new BlocksAttacks(this.blockDelaySeconds, this.disableCooldownScale, this.damageReductions, this.itemDamage, this.bypassedBy, blockSound, disableSound);
}
public record DamageReduction(float horizontalBlockingAngle, @Nullable HolderSet type, float base, float factor) {
@@ -59,7 +59,7 @@ public record ChatType(ChatTypeDecoration chatDecoration, ChatTypeDecoration nar
public ChatTypeDecoration read(final ByteBuf buffer) {
final String translationKey = Types.STRING.read(buffer);
final int[] parameters = Types.INT_ARRAY_PRIMITIVE.read(buffer);
final Tag style = Types.TAG.read(buffer);
final Tag style = Types.TRUSTED_TAG.read(buffer);
return new ChatTypeDecoration(translationKey, parameters, style);
}
@@ -67,7 +67,7 @@ public record ChatType(ChatTypeDecoration chatDecoration, ChatTypeDecoration nar
public void write(final ByteBuf buffer, final ChatTypeDecoration value) {
Types.STRING.write(buffer, value.translationKey());
Types.INT_ARRAY_PRIMITIVE.write(buffer, value.parameters());
Types.TAG.write(buffer, value.style());
Types.TRUSTED_TAG.write(buffer, value.style());
}
};
@@ -44,7 +44,7 @@ public final class ContainterContents {
ops.writeList(list -> {
for (int i = 0; i < value.length; i++) {
final Item item = value[i];
if (item.isEmpty()) {
if (item == null || item.isEmpty()) {
continue;
}
@@ -28,12 +28,12 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
public record DamageResistant(Key typesTagKey) {
public record DamageResistant1_21_2(Key typesTagKey) {
public static final Type<DamageResistant> TYPE = new TransformingType<>(Types.IDENTIFIER, DamageResistant.class, DamageResistant::new, DamageResistant::typesTagKey) {
public static final Type<DamageResistant1_21_2> TYPE = new TransformingType<>(Types.IDENTIFIER, DamageResistant1_21_2.class, DamageResistant1_21_2::new, DamageResistant1_21_2::typesTagKey) {
@Override
public void write(final Ops ops, final DamageResistant value) {
public void write(final Ops ops, final DamageResistant1_21_2 value) {
ops.writeMap(map -> map.write("types", Types.TAG_KEY, value.typesTagKey));
}
};
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
public record DamageResistant26_1(HolderSet types) {
public static final Type<DamageResistant26_1> TYPE = new TransformingType<>(Types.HOLDER_SET, DamageResistant26_1.class, DamageResistant26_1::new, DamageResistant26_1::types) {
@Override
public void write(final Ops ops, final DamageResistant26_1 value) {
ops.writeMap(map -> map.write("types", Types.HOLDER_SET, value.types));
}
};
}
@@ -28,7 +28,12 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.EitherType;
import com.viaversion.viaversion.util.Either;
/**
* 1.21.11-only damage type.
*
* @param id registry int or string id
*/
public record DamageType(Either<Integer, String> id) {
public static final Type<DamageType> TYPE = TransformingType.of(new EitherType<>(Types.VAR_INT, Types.STRING), DamageType.class, DamageType::new, DamageType::id);
public static final Type<DamageType> TYPE1_21_11 = TransformingType.of(new EitherType<>(Types.VAR_INT, Types.STRING), DamageType.class, DamageType::new, DamageType::id);
}
@@ -53,6 +53,6 @@ public final class EnumTypes {
// Hardcoded registries
public static final RegistryValueType VILLAGER_TYPE = new RegistryValueType(Key.of("villager_type"), "desert", "jungle", "plains", "savanna", "snow", "swamp", "taiga");
public static final RegistryValueType POTION = new RegistryValueType(Key.of("potion"), "water", "mundane", "thick", "awkward", "night_vision", "long_night_vision", "invisibility", "long_invisibility", "leaping", "long_leaping", "strong_leaping", "fire_resistance", "long_fire_resistance", "swiftness", "long_swiftness", "strong_swiftness", "slowness", "long_slowness", "strong_slowness", "turtle_master", "long_turtle_master", "strong_turtle_master", "water_breathing", "long_water_breathing", "healing", "strong_healing", "harming", "strong_harming", "poison", "long_poison", "strong_poison", "regeneration", "long_regeneration", "strong_regeneration", "strength", "long_strength", "strong_strength", "weakness", "long_weakness", "luck", "slow_falling", "long_slow_falling", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType MOB_EFFECT = new RegistryValueType(Key.of("mob_effect"), "speed", "slowness", "haste", "mining_fatigue", "strength", "instant_health", "instant_damage", "jump_boost", "nausea", "regeneration", "resistance", "fire_resistance", "water_breathing", "invisibility", "blindness", "night_vision", "hunger", "weakness", "poison", "wither", "health_boost", "absorption", "saturation", "glowing", "levitation", "luck", "unluck", "slow_falling", "conduit_power", "dolphins_grace", "bad_omen", "hero_of_the_village", "darkness", "trial_omen", "raid_omen", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType MOB_EFFECT = new RegistryValueType(Key.of("mob_effect"), "speed", "slowness", "haste", "mining_fatigue", "strength", "instant_health", "instant_damage", "jump_boost", "nausea", "regeneration", "resistance", "fire_resistance", "water_breathing", "invisibility", "blindness", "night_vision", "hunger", "weakness", "poison", "wither", "health_boost", "absorption", "saturation", "glowing", "levitation", "luck", "unluck", "slow_falling", "conduit_power", "dolphins_grace", "bad_omen", "hero_of_the_village", "darkness", "trial_omen", "raid_omen", "wind_charged", "weaving", "oozing", "infested", "breath_of_the_nautilus");
public static final RegistryValueType CONSUME_EFFECT = new RegistryValueType(Key.of("consume_effect_type"), "apply_effects", "remove_effects", "clear_all_effects", "teleport_randomly", "play_sound");
}
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
public record ProvidesBannerPatterns(HolderSet patterns) {
public static final Type<ProvidesBannerPatterns> TYPE = TransformingType.of(new HolderSetType(RegistryKey.of("banner_pattern")), ProvidesBannerPatterns.class, ProvidesBannerPatterns::new, ProvidesBannerPatterns::patterns);
}
@@ -79,7 +79,7 @@ public interface ViaInjector {
}
/**
* Get the name of the encoder for then netty pipeline for this platform.
* Get the name of the encoder for the netty pipeline for this platform.
*
* @return The name
*/
@@ -88,7 +88,7 @@ public interface ViaInjector {
}
/**
* Get the name of the decoder for then netty pipeline for this platform.
* Get the name of the decoder for the netty pipeline for this platform.
*
* @return The name
*/
@@ -165,6 +165,30 @@ public interface ViaPlatform<T> {
return false;
}
/**
* Modify the player details payload before it is sent.
* This method allows adding, changing, or removing fields from the payload.
* It is only called if {@link ViaVersionConfig#sendPlayerDetails()} is true.
*
* @param connection The UserConnection
* @param payload The constructed payload to modify
*/
default void modifyPlayerDetails(UserConnection connection, JsonObject payload) {
// To be overridden if needed
}
/**
* Modify the server details payload before it is sent.
* This method allows adding, changing, or removing fields from the payload.
* It is only called if {@link ViaVersionConfig#sendServerDetails()} is true.
*
* @param connection The UserConnection
* @param payload The constructed payload to modify
*/
default void modifyServerDetails(UserConnection connection, JsonObject payload) {
// To be overridden if needed
}
/**
* Send a custom payload to from a player to the server.
*
@@ -68,10 +68,6 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
registerServerbound(state, packetType.getId(), packetType.getId(), handler, false);
}
default void registerServerbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler) {
registerServerbound(state, unmappedPacketId, mappedPacketId, handler, false);
}
/**
* Registers a serverbound packet, with id transformation and remapper.
*
@@ -79,19 +75,17 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
* @param unmappedPacketId unmapped packet id
* @param mappedPacketId mapped packet id
* @param handler packet handler
* @param override whether an existing mapper should be overridden
* @see #registerServerbound(ServerboundPacketType, ServerboundPacketType, PacketHandler, boolean)
*/
default void registerServerbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler) {
registerServerbound(state, unmappedPacketId, mappedPacketId, handler, false);
}
@Deprecated(forRemoval = true)
void registerServerbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler, boolean override);
void cancelServerbound(State state, int mappedPacketId);
default void registerClientbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler) {
registerClientbound(state, unmappedPacketId, mappedPacketId, handler, false);
}
void cancelClientbound(State state, int unmappedPacketId);
/**
* Registers a clientbound packet, with id transformation and remapper.
*
@@ -99,9 +93,15 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
* @param unmappedPacketId unmapped packet id
* @param mappedPacketId mapped packet id
* @param handler packet handler
* @param override whether an existing mapper should be overridden
* @see #registerClientbound(ClientboundPacketType, ClientboundPacketType, PacketHandler, boolean)
*/
default void registerClientbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler) {
registerClientbound(state, unmappedPacketId, mappedPacketId, handler, false);
}
void cancelClientbound(State state, int unmappedPacketId);
@Deprecated(forRemoval = true)
void registerClientbound(State state, int unmappedPacketId, int mappedPacketId, @Nullable PacketHandler handler, boolean override);
// ---------------------------------------------------------------------------------------
@@ -144,6 +144,7 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
* @param handler packet handler
* @param override whether an existing mapping should be overridden if present
*/
@Deprecated(forRemoval = true)
void registerClientbound(CU packetType, @Nullable CM mappedPacketType, @Nullable PacketHandler handler, boolean override);
/**
@@ -191,6 +192,7 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
* @param handler packet handler
* @param override whether an existing mapping should be overridden if present
*/
@Deprecated(forRemoval = true)
void registerServerbound(SU packetType, @Nullable SM mappedPacketType, @Nullable PacketHandler handler, boolean override);
/**
@@ -260,6 +262,22 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
*/
void appendServerbound(SU type, PacketHandler handler);
/**
* Replaces a clientbound packet type handler with another.
*
* @param type clientbound packet type
* @param handler packet handler
*/
void replaceClientbound(CU type, @Nullable PacketHandler handler);
/**
* Replaces a serverbound packet type handler with another.
*
* @param type serverbound packet type
* @param handler packet handler
*/
void replaceServerbound(SU type, @Nullable PacketHandler handler);
/**
* Transform a packet using this protocol
*
@@ -441,4 +459,13 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
default boolean isBaseProtocol() {
return false;
}
/**
* Marks this protocol as dependent on another. Before being initialized, it will wait for the dependency's completion.
*
* @return protocol class to depend on
*/
default @Nullable Class<? extends Protocol<?, ?, ?, ?>> dependsOn() {
return null;
}
}
@@ -249,7 +249,17 @@ public interface ProtocolManager {
*
* @return true if the executor has now been shut down
*/
boolean checkForMappingCompletion();
default boolean checkForMappingCompletion() {
return checkForMappingCompletion(false);
}
/**
* Shuts down the executor and uncaches mappings if all futures have been completed.
*
* @param propagateErrors whether to propagate errors from the futures to the caller
* @return true if the executor has now been shut down
*/
boolean checkForMappingCompletion(boolean propagateErrors);
/**
* Executes the given runnable asynchronously, adding a {@link CompletableFuture}
@@ -328,6 +328,13 @@ public interface PacketWrapper {
*/
void resetReader();
/**
* Rewind the reader by the given number of arguments, so they can be read again.
*
* @param values number of values to add to the reader dequeue again
*/
void rewindReader(int values);
/**
* Sends this packet to the server.
* <b>Unlike {@link #sendToServer(Class)}, this method does not handle the pipeline with packet id and data changes.</b>
@@ -382,12 +389,21 @@ public interface PacketWrapper {
*/
void scheduleSendToServer(Class<? extends Protocol> protocol, boolean skipCurrentPipeline) throws InformativeException;
/**
* Allows running through code that may both read and write data to/from this packet wrapper,
* but will no-op any write call.
*
* @param runnable runnable to do further method calls on this packet wrapper
*/
void consumeReadsOnly(Runnable runnable);
/**
* Returns the packet type, or null if not transformed or manually unset.
*
* @return packet type if set
*/
@Nullable PacketType getPacketType();
@Nullable
PacketType getPacketType();
/**
* Sets the packet type. If set to null, it will not be written to the buffer with {@link #writeToBuffer(ByteBuf)}.
@@ -50,6 +50,11 @@ final class PacketIdMapping implements PacketMapping {
}
}
@Override
public void setHandler(@Nullable final PacketHandler handler) {
this.handler = handler;
}
@Override
public @Nullable PacketHandler handler() {
return handler;
@@ -39,6 +39,13 @@ public interface PacketMapping {
*/
void applyType(PacketWrapper wrapper);
/**
* Replaces the current packet handler.
*
* @param handler packet transformer
*/
void setHandler(@Nullable PacketHandler handler);
/**
* Returns a packet transformer to transform a packet from one protocol version to another.
*
@@ -52,6 +52,11 @@ final class PacketTypeMapping implements PacketMapping {
}
}
@Override
public void setHandler(@Nullable final PacketHandler handler) {
this.handler = handler;
}
@Override
public @Nullable PacketHandler handler() {
return handler;
@@ -93,6 +93,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_7 = register(772, "1.21.7-1.21.8", new SubVersionRange("1.21", 7, 8));
public static final ProtocolVersion v1_21_9 = register(773, "1.21.9-1.21.10", new SubVersionRange("1.21", 9, 10));
public static final ProtocolVersion v1_21_11 = register(774, "1.21.11");
public static final ProtocolVersion v26_1 = register(775, "26.1-26.1.1", new SubVersionRange("26.1", 0, 1));
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -27,9 +27,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Wrapper class file for {@link com.google.common.collect.Range} to support multiple ranges. This class is used to
* Wrapper class file for {@link Range} to support multiple ranges. This class is used to
* compare {@link ProtocolVersion} objects.
*/
public class ProtocolVersionRange {
@@ -43,7 +44,7 @@ public class ProtocolVersionRange {
}
/**
* Returns a range that contains all versions.
* Returns a range that contains all versions. Adding new ranges to this range is not supported.
*
* @return the range
*/
@@ -159,6 +160,46 @@ public class ProtocolVersionRange {
return false;
}
/**
* Gets the minimum version in this range. If there are multiple ranges, the lowest minimum is returned.
*
* @return the minimum version, or null if there is no minimum
*/
public @Nullable ProtocolVersion getMin() {
ProtocolVersion min = null;
if (this.ranges != null) {
for (Range<ProtocolVersion> range : this.ranges) {
if (range.hasLowerBound()) {
ProtocolVersion rangeMin = range.lowerEndpoint();
if (min == null || rangeMin.compareTo(min) < 0) {
min = rangeMin;
}
}
}
}
return min;
}
/**
* Gets the maximum version in this range. If there are multiple ranges, the highest maximum is returned.
*
* @return the maximum version, or null if there is no maximum
*/
public @Nullable ProtocolVersion getMax() {
ProtocolVersion max = null;
if (this.ranges != null) {
for (Range<ProtocolVersion> range : this.ranges) {
if (range.hasUpperBound()) {
ProtocolVersion rangeMax = range.upperEndpoint();
if (max == null || rangeMax.compareTo(max) > 0) {
max = rangeMax;
}
}
}
}
return max;
}
@Override
public String toString() {
if (this.ranges != null) {
@@ -197,7 +238,7 @@ public class ProtocolVersionRange {
}
/**
* Parses a range from a string.
* Parses a range from a string generated by {@link #toString()}.
*
* @param str the string
* @return the range
@@ -26,6 +26,7 @@ import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ComponentRewriter {
@@ -37,4 +38,6 @@ public interface ComponentRewriter {
JsonElement processText(UserConnection connection, @Nullable String json);
void handleShowItem(UserConnection connection, CompoundTag itemTag);
void passthroughAndProcess(PacketWrapper wrapper);
}
@@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.protocol.Protocol;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T> {
@@ -39,6 +40,11 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
*/
EntityType typeFromId(int type);
default @Nullable EntityType typeFromId(final String type) {
final int id = protocol().getMappingData().getEntityMappings().id(type);
return id == -1 ? null : typeFromId(id);
}
/**
* Returns the entity type from the given id.
* From 1.14 and onwards, this is the same exact value as {@link #typeFromId(int)}.
@@ -102,6 +102,16 @@ public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T
return itemArrayType();
}
@Nullable
default Type<Item> itemTemplateType() {
return itemType();
}
@Nullable
default Type<Item> mappedItemTemplateType() {
return mappedItemType();
}
/**
* Returns the NBT tag name used for storing original item data.
*
@@ -22,10 +22,22 @@
*/
package com.viaversion.viaversion.api.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.util.KeyMappings;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface RegistryDataRewriter {
@Nullable KeyMappings getMappings(String registryKey);
void handle(PacketWrapper wrapper);
@Nullable
KeyMappings getMappings(String registryKey);
boolean shouldRemoveRegistry(String registryKey);
boolean hasRegistriesToRemove();
void updateDialog(UserConnection connection, CompoundTag tag);
}
@@ -103,10 +103,11 @@ import com.viaversion.viaversion.api.type.types.math.BlockPositionType1_8;
import com.viaversion.viaversion.api.type.types.math.ChunkPositionType;
import com.viaversion.viaversion.api.type.types.math.EulerAngleType;
import com.viaversion.viaversion.api.type.types.math.GlobalBlockPositionType;
import com.viaversion.viaversion.api.type.types.math.MovementVectorType;
import com.viaversion.viaversion.api.type.types.math.LowPrecisionVectorType;
import com.viaversion.viaversion.api.type.types.math.QuaternionType;
import com.viaversion.viaversion.api.type.types.math.Vector3fType;
import com.viaversion.viaversion.api.type.types.math.VectorType;
import com.viaversion.viaversion.api.type.types.misc.CompoundTagHolderType;
import com.viaversion.viaversion.api.type.types.misc.CompoundTagType;
import com.viaversion.viaversion.api.type.types.misc.GameProfileType;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
@@ -117,8 +118,8 @@ import com.viaversion.viaversion.api.type.types.misc.NamedCompoundTagType;
import com.viaversion.viaversion.api.type.types.misc.PlayerMessageSignatureType;
import com.viaversion.viaversion.api.type.types.misc.ProfileKeyType;
import com.viaversion.viaversion.api.type.types.misc.ProfilePropertyType;
import com.viaversion.viaversion.api.type.types.misc.SoundEventType;
import com.viaversion.viaversion.api.type.types.misc.ResolvableProfileType;
import com.viaversion.viaversion.api.type.types.misc.SoundEventType;
import com.viaversion.viaversion.api.type.types.misc.TagKeyType;
import com.viaversion.viaversion.api.type.types.misc.TagType;
import com.viaversion.viaversion.api.type.types.misc.TextComponentTagType;
@@ -198,19 +199,28 @@ public final class Types {
public static final Type<Vector> VECTOR = new VectorType();
public static final Type<Vector3f> VECTOR3F = new Vector3fType();
public static final Type<Quaternion> QUATERNION = new QuaternionType();
public static final Type<Vector3d> MOVEMENT_VECTOR = new MovementVectorType();
public static final Type<Vector3d> LOW_PRECISION_VECTOR = new LowPrecisionVectorType();
@Deprecated(forRemoval = true)
public static final Type<Vector3d> MOVEMENT_VECTOR = LOW_PRECISION_VECTOR;
public static final Type<CompoundTag> NAMED_COMPOUND_TAG = new NamedCompoundTagType();
public static final Type<CompoundTag> OPTIONAL_NAMED_COMPOUND_TAG = new NamedCompoundTagType.OptionalNamedCompoundTagType();
public static final Type<CompoundTag[]> NAMED_COMPOUND_TAG_ARRAY = new ArrayType<>(Types.NAMED_COMPOUND_TAG);
public static final Type<CompoundTag> COMPOUND_TAG = new CompoundTagType();
public static final Type<CompoundTag> OPTIONAL_COMPOUND_TAG = new CompoundTagType.OptionalCompoundTagType();
public static final Type<CompoundTag> OPTIONAL_COMPOUND_TAG = CompoundTagType.OptionalCompoundTagType.type();
public static final HolderType<CompoundTag> TRUSTED_COMPOUND_TAG_HOLDER = new CompoundTagHolderType();
public static final Type<Tag> TAG = new TagType();
public static final Type<Tag[]> TAG_ARRAY = new ArrayType<>(TAG);
public static final Type<Tag> OPTIONAL_TAG = new TagType.OptionalTagType();
public static final Type<Tag> OPTIONAL_TAG = TagType.OptionalTagType.type();
public static final Type<Tag> TEXT_COMPONENT_TAG = new TextComponentTagType(); // only strictly needed for hashing
public static final Type<Tag> CUSTOM_CLICK_ACTION_TAG = new LengthPrefixedTagType(65536);
public static final Type<Tag> TRUSTED_TAG = new TagType(false);
public static final Type<Tag> TRUSTED_OPTIONAL_TAG = TagType.OptionalTagType.trustedType();
public static final Type<CompoundTag> TRUSTED_COMPOUND_TAG = new CompoundTagType(false);
public static final Type<CompoundTag> TRUSTED_OPTIONAL_COMPOUND_TAG = CompoundTagType.OptionalCompoundTagType.trustedType();
public static final Type<GlobalBlockPosition> GLOBAL_POSITION = new GlobalBlockPositionType();
public static final Type<GlobalBlockPosition> OPTIONAL_GLOBAL_POSITION = new GlobalBlockPositionType.OptionalGlobalPositionType();
public static final Type<ChunkPosition> CHUNK_POSITION = new ChunkPositionType();
@@ -28,13 +28,21 @@ import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public class VarIntArrayType extends Type<int[]> {
public VarIntArrayType() {
private final int length;
public VarIntArrayType(final int length) {
super(int[].class);
this.length = length;
}
public VarIntArrayType() {
this(-1);
}
@Override
public int[] read(ByteBuf buffer) {
int length = Types.VAR_INT.readPrimitive(buffer);
int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length;
Preconditions.checkArgument(buffer.isReadable(length)); // Sanity check, at least 1 byte will be used for each varint
int[] array = new int[length];
for (int i = 0; i < array.length; i++) {
@@ -45,7 +53,11 @@ public class VarIntArrayType extends Type<int[]> {
@Override
public void write(ByteBuf buffer, int[] object) {
Types.VAR_INT.writePrimitive(buffer, object.length);
if (this.length != -1) {
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
} else {
Types.VAR_INT.writePrimitive(buffer, object.length);
}
for (int i : object) {
Types.VAR_INT.writePrimitive(buffer, i);
}
@@ -31,8 +31,8 @@ import io.netty.buffer.ByteBuf;
public class ChunkSectionType1_18 extends Type<ChunkSection> {
private final PaletteTypeBase blockPaletteType;
private final PaletteTypeBase biomePaletteType;
protected final PaletteTypeBase blockPaletteType;
protected final PaletteTypeBase biomePaletteType;
public ChunkSectionType1_18(final int globalPaletteBlockBits, final int globalPaletteBiomeBits) {
super(ChunkSection.class);
@@ -0,0 +1,68 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.chunk;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import io.netty.buffer.ByteBuf;
public class ChunkSectionType26_1 extends ChunkSectionType1_18 {
public ChunkSectionType26_1(final int globalPaletteBlockBits, final int globalPaletteBiomeBits) {
super(
new PaletteType1_21_5(PaletteType.BLOCKS, globalPaletteBlockBits),
new PaletteType1_21_5(PaletteType.BIOMES, globalPaletteBiomeBits)
);
}
@Override
public ChunkSection read(final ByteBuf buffer) {
final ChunkSection chunkSection = new ChunkSectionImpl();
chunkSection.setNonAirBlocksCount(buffer.readShort());
chunkSection.setFluidCount(buffer.readShort());
chunkSection.addPalette(PaletteType.BLOCKS, blockPaletteType.read(buffer));
chunkSection.addPalette(PaletteType.BIOMES, biomePaletteType.read(buffer));
return chunkSection;
}
@Override
public void write(final ByteBuf buffer, final ChunkSection section) {
buffer.writeShort(section.getNonAirBlocksCount());
buffer.writeShort(section.getFluidCount());
blockPaletteType.write(buffer, section.palette(PaletteType.BLOCKS));
biomePaletteType.write(buffer, section.palette(PaletteType.BIOMES));
}
@Override
public int serializedSize(final Chunk chunk) {
int length = 0;
for (final ChunkSection section : chunk.getSections()) {
length += Short.BYTES + Short.BYTES // non-air and fluid count
+ blockPaletteType.serializedSize(section.palette(PaletteType.BLOCKS))
+ biomePaletteType.serializedSize(section.palette(PaletteType.BIOMES));
}
return length;
}
}
@@ -34,14 +34,18 @@ import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
public final class ChunkType1_21_5 extends Type<Chunk> {
public class ChunkType1_21_5 extends Type<Chunk> {
private final ChunkSectionType1_18 sectionType;
private final int ySectionCount;
public ChunkType1_21_5(final int ySectionCount, final int globalPaletteBlockBits, final int globalPaletteBiomeBits) {
this(new ChunkSectionType1_21_5(globalPaletteBlockBits, globalPaletteBiomeBits), ySectionCount);
}
protected ChunkType1_21_5(final ChunkSectionType1_18 sectionType, final int ySectionCount) {
super(Chunk.class);
Preconditions.checkArgument(ySectionCount > 0);
this.sectionType = new ChunkSectionType1_21_5(globalPaletteBlockBits, globalPaletteBiomeBits);
this.sectionType = sectionType;
this.ySectionCount = ySectionCount;
}
@@ -20,17 +20,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.protocol;
package com.viaversion.viaversion.api.type.types.chunk;
/**
* A simple protocol which does not have any packet types.
* <p>
* {@link AbstractProtocol} should be preferred over this class in most cases.
*/
public abstract class AbstractSimpleProtocol extends AbstractProtocol<SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes,
SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes> implements SimpleProtocol {
public final class ChunkType26_1 extends ChunkType1_21_5 {
protected AbstractSimpleProtocol() {
super(null, null, null, null);
public ChunkType26_1(final int ySectionCount, final int globalPaletteBlockBits, final int globalPaletteBiomeBits) {
super(new ChunkSectionType26_1(globalPaletteBlockBits, globalPaletteBiomeBits), ySectionCount);
}
}
@@ -0,0 +1,64 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.item;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
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.StructuredItemTemplate;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.Map;
// Holds the same exact data as a regular item stack
public class ItemTemplateType26_1 extends ItemType1_20_5 {
public ItemTemplateType26_1(final StructuredDataTypeBase dataType) {
super(dataType);
}
@Override
public Item read(final ByteBuf buffer) {
final int id = Types.VAR_INT.readPrimitive(buffer);
final int amount = Types.VAR_INT.readPrimitive(buffer);
final Map<StructuredDataKey<?>, StructuredData<?>> data = readData(buffer);
return new StructuredItemTemplate(id, amount, new StructuredDataContainer(data));
}
@Override
public void write(final ByteBuf buffer, final Item object) {
Types.VAR_INT.writePrimitive(buffer, object.identifier());
Types.VAR_INT.writePrimitive(buffer, object.amount());
writeData(buffer, object);
}
public static final class OptionalItemTemplateType extends OptionalType<Item> {
public OptionalItemTemplateType(final Type<Item> type) {
super(type);
}
}
}
@@ -58,7 +58,7 @@ public class ItemType1_20_5 extends Type<Item> {
return new StructuredItem(id, amount, new StructuredDataContainer(data));
}
private Map<StructuredDataKey<?>, StructuredData<?>> readData(final ByteBuf buffer) {
protected Map<StructuredDataKey<?>, StructuredData<?>> readData(final ByteBuf buffer) {
final int valuesSize = Types.VAR_INT.readPrimitive(buffer);
final int markersSize = Types.VAR_INT.readPrimitive(buffer);
if (valuesSize == 0 && markersSize == 0) {
@@ -92,6 +92,10 @@ public class ItemType1_20_5 extends Type<Item> {
Types.VAR_INT.writePrimitive(buffer, object.amount());
Types.VAR_INT.writePrimitive(buffer, object.identifier());
writeData(buffer, object);
}
protected void writeData(final ByteBuf buffer, final Item object) {
final Map<StructuredDataKey<?>, StructuredData<?>> data = object.dataContainer().data();
int valuesSize = 0;
int markersSize = 0;
@@ -29,7 +29,7 @@ import com.viaversion.viaversion.api.type.types.UnsignedIntType;
import com.viaversion.viaversion.util.MathUtil;
import io.netty.buffer.ByteBuf;
public class MovementVectorType extends Type<Vector3d> {
public class LowPrecisionVectorType extends Type<Vector3d> {
// Using 15 bits, steal short constants for it
private static final double MAX_QUANTIZED_VALUE = Short.MAX_VALUE - 1;
private static final int SCALE_BITS = 2; // first 2 bits for the scale
@@ -38,7 +38,7 @@ public class MovementVectorType extends Type<Vector3d> {
private static final double ABS_MAX_VALUE = (1L << Integer.SIZE + SCALE_BITS) - 1; // Unsigned int + the first two scale bits
private static final double ABS_MIN_VALUE = 1 / MAX_QUANTIZED_VALUE;
public MovementVectorType() {
public LowPrecisionVectorType() {
super(Vector3d.class);
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public final class CompoundTagHolderType extends HolderType<CompoundTag> {
@Override
public CompoundTag readDirect(final ByteBuf buffer) {
return Types.TRUSTED_COMPOUND_TAG.read(buffer);
}
@Override
public void writeDirect(final ByteBuf buffer, final CompoundTag value) {
Types.TRUSTED_COMPOUND_TAG.write(buffer, value);
}
}
@@ -41,14 +41,21 @@ import java.util.Map;
*/
public class CompoundTagType extends Type<CompoundTag> {
private final int maxBytes;
public CompoundTagType() {
this(true);
}
public CompoundTagType(final boolean limitMaxBytes) {
super(CompoundTag.class);
this.maxBytes = limitMaxBytes ? NamedCompoundTagType.MAX_NBT_BYTES : Integer.MAX_VALUE;
}
@Override
public CompoundTag read(final ByteBuf buffer) {
try {
return NamedCompoundTagType.read(buffer, false);
return NamedCompoundTagType.read(buffer, this.maxBytes, false);
} catch (final IOException e) {
throw new RuntimeException(e);
}
@@ -74,8 +81,16 @@ public class CompoundTagType extends Type<CompoundTag> {
public static final class OptionalCompoundTagType extends OptionalType<CompoundTag> {
public OptionalCompoundTagType() {
super(Types.COMPOUND_TAG);
private OptionalCompoundTagType(final Type<CompoundTag> tagType) {
super(tagType);
}
public static OptionalCompoundTagType type() {
return new OptionalCompoundTagType(Types.COMPOUND_TAG);
}
public static OptionalCompoundTagType trustedType() {
return new OptionalCompoundTagType(Types.TRUSTED_COMPOUND_TAG);
}
}
}
@@ -29,6 +29,11 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
/**
* Mess for certain pre 26.1 things.
*
* @param <T> held type
*/
public final class EitherHolderType<T> extends Type<EitherHolder<T>> {
private final HolderType<T> holderType;
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntArrayType;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
@@ -58,12 +59,7 @@ public class HolderSetType extends Type<HolderSet> {
final String tag = Types.STRING.read(buffer);
return HolderSet.of(tag);
}
final int[] values = new int[size];
for (int i = 0; i < size; i++) {
values[i] = Types.VAR_INT.readPrimitive(buffer);
}
return HolderSet.of(values);
return HolderSet.of(new VarIntArrayType(size).read(buffer));
}
@Override
@@ -46,7 +46,7 @@ public class NamedCompoundTagType extends Type<CompoundTag> {
@Override
public CompoundTag read(final ByteBuf buffer) {
try {
return read(buffer, true);
return read(buffer, MAX_NBT_BYTES, true);
} catch (final IOException e) {
throw new RuntimeException(e);
}
@@ -61,7 +61,7 @@ public class NamedCompoundTagType extends Type<CompoundTag> {
}
}
public static CompoundTag read(final ByteBuf buffer, final boolean readName) throws IOException {
public static CompoundTag read(final ByteBuf buffer, final int maxBytes, final boolean readName) throws IOException {
final byte id = buffer.readByte();
if (id == 0) {
return null;
@@ -74,7 +74,7 @@ public class NamedCompoundTagType extends Type<CompoundTag> {
buffer.skipBytes(buffer.readUnsignedShort());
}
final TagLimiter tagLimiter = TagLimiter.create(MAX_NBT_BYTES, MAX_NESTING_LEVEL);
final TagLimiter tagLimiter = TagLimiter.create(maxBytes, MAX_NESTING_LEVEL);
return CompoundTag.read(new ByteBufInputStream(buffer), tagLimiter, 0);
}
@@ -59,17 +59,13 @@ public class ParticleType extends DynamicType<Particle> {
return protocol.getMappingData().getParticleMappings();
}
public static DataReader<Particle> itemHandler(final Type<Item> itemType) {
return (buf, particle) -> particle.add(itemType, itemType.read(buf));
}
public static final class Readers {
public static final DataReader<Particle> BLOCK = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Flat Block
};
public static final DataReader<Particle> ITEM1_13 = itemHandler(Types.ITEM1_13);
public static final DataReader<Particle> ITEM1_13_2 = itemHandler(Types.ITEM1_13_2);
public static final DataReader<Particle> ITEM1_13 = item(Types.ITEM1_13);
public static final DataReader<Particle> ITEM1_13_2 = item(Types.ITEM1_13_2);
public static final DataReader<Particle> DUST = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Red 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green 0-1
@@ -172,4 +168,103 @@ public class ParticleType extends DynamicType<Particle> {
return (buf, particle) -> particle.add(item, item.read(buf));
}
}
public static final class Fillers {
public static DynamicType<Particle>.DataFiller fill1_13_2(final Protocol<?, ?, ?, ?> protocol, final ParticleType type, final boolean useMappedNames) {
return type.filler(protocol, useMappedNames)
.reader("item", Readers.item(protocol.getItemRewriter().mappedItemType()))
.reader("block", Readers.BLOCK)
.reader("dust", Readers.DUST)
.reader("falling_dust", Readers.BLOCK);
}
public static DataFiller fill1_17(final Protocol<?, ?, ?, ?> protocol, final ParticleType type) {
return fill1_13_2(protocol, type, true)
.reader("dust_color_transition", Readers.DUST_TRANSITION)
.reader("vibration", Readers.VIBRATION);
}
public static void fill1_18(final Protocol<?, ?, ?, ?> protocol, final ParticleType type) {
fill1_17(protocol, type).reader("block_marker", Readers.BLOCK);
}
public static void fill1_19(final Protocol<?, ?, ?, ?> protocol, final ParticleType type) {
type.filler(protocol)
.reader("item", Readers.item(protocol.getItemRewriter().mappedItemType()))
.reader("block", Readers.BLOCK)
.reader("block_marker", Readers.BLOCK)
.reader("dust", Readers.DUST)
.reader("falling_dust", Readers.BLOCK)
.reader("dust_color_transition", Readers.DUST_TRANSITION)
.reader("vibration", Readers.VIBRATION1_19)
.reader("sculk_charge", Readers.SCULK_CHARGE)
.reader("shriek", Readers.SHRIEK);
}
public static DataFiller fill1_20_3(final Protocol<?, ?, ?, ?> protocol, final ParticleType type) {
return type.filler(protocol)
.reader("item", Readers.item(protocol.getItemRewriter().mappedItemType()))
.reader("block", Readers.BLOCK)
.reader("block_marker", Readers.BLOCK)
.reader("dust", Readers.DUST)
.reader("falling_dust", Readers.BLOCK)
.reader("dust_color_transition", Readers.DUST_TRANSITION)
.reader("vibration", Readers.VIBRATION1_20_3)
.reader("sculk_charge", Readers.SCULK_CHARGE)
.reader("shriek", Readers.SHRIEK);
}
public static void fill1_20_5(final Protocol<?, ?, ?, ?> protocol, final ParticleType type) {
fill1_20_3(protocol, type)
.reader("dust_pillar", Readers.BLOCK)
.reader("entity_effect", Readers.COLOR);
}
public static void fill1_21_2(final Protocol<?, ?, ?, ?> protocol) {
protocol.mappedTypes().particle().filler(protocol)
.reader("item", Readers.item(protocol.getItemRewriter().mappedItemType()))
.reader("block", Readers.BLOCK)
.reader("block_marker", Readers.BLOCK)
.reader("dust_pillar", Readers.BLOCK)
.reader("falling_dust", Readers.BLOCK)
.reader("block_crumble", Readers.BLOCK)
.reader("dust", Readers.DUST1_21_2)
.reader("dust_color_transition", Readers.DUST_TRANSITION1_21_2)
.reader("vibration", Readers.VIBRATION1_20_3)
.reader("sculk_charge", Readers.SCULK_CHARGE)
.reader("shriek", Readers.SHRIEK)
.reader("entity_effect", Readers.COLOR)
.reader("trail", Readers.TRAIL1_21_2);
}
public static DataFiller fill1_21_4(final Protocol<?, ?, ?, ?> protocol) {
return protocol.mappedTypes().particle().filler(protocol)
.reader("item", Readers.item(protocol.getItemRewriter().mappedItemTemplateType()))
.reader("block", Readers.BLOCK)
.reader("block_marker", Readers.BLOCK)
.reader("dust_pillar", Readers.BLOCK)
.reader("falling_dust", Readers.BLOCK)
.reader("block_crumble", Readers.BLOCK)
.reader("dust", Readers.DUST1_21_2)
.reader("dust_color_transition", Readers.DUST_TRANSITION1_21_2)
.reader("vibration", Readers.VIBRATION1_20_3)
.reader("sculk_charge", Readers.SCULK_CHARGE)
.reader("shriek", Readers.SHRIEK)
.reader("entity_effect", Readers.COLOR)
.reader("trail", Readers.TRAIL1_21_4);
}
public static DataFiller fill1_21_5(final Protocol<?, ?, ?, ?> protocol) {
return fill1_21_4(protocol).reader("tinted_leaves", Readers.COLOR);
}
public static void fill1_21_9(final Protocol<?, ?, ?, ?> protocol) {
fill1_21_5(protocol)
.reader("dragon_breath", Readers.POWER)
.reader("effect", Readers.SPELL)
.reader("instant_effect", Readers.SPELL)
.reader("flash", Readers.COLOR);
}
}
}
@@ -50,8 +50,15 @@ import java.util.Map;
public class TagType extends Type<Tag> {
private final int maxBytes;
public TagType() {
this(true);
}
public TagType(final boolean limitBytes) {
super(Tag.class);
this.maxBytes = limitBytes ? NamedCompoundTagType.MAX_NBT_BYTES : Integer.MAX_VALUE;
}
@Override
@@ -61,7 +68,7 @@ public class TagType extends Type<Tag> {
return null;
}
final TagLimiter tagLimiter = TagLimiter.create(NamedCompoundTagType.MAX_NBT_BYTES, NamedCompoundTagType.MAX_NESTING_LEVEL);
final TagLimiter tagLimiter = TagLimiter.create(this.maxBytes, NamedCompoundTagType.MAX_NESTING_LEVEL);
try {
return TagRegistry.read(id, new ByteBufInputStream(buffer), tagLimiter, 0);
} catch (final IOException e) {
@@ -127,8 +134,16 @@ public class TagType extends Type<Tag> {
public static final class OptionalTagType extends OptionalType<Tag> {
public OptionalTagType() {
super(Types.TAG);
private OptionalTagType(final Type<Tag> tagType) {
super(tagType);
}
public static OptionalTagType type() {
return new OptionalTagType(Types.TAG);
}
public static OptionalTagType trustedType() {
return new OptionalTagType(Types.TRUSTED_TAG);
}
}
}
@@ -50,7 +50,7 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
public final Type<Item[]> itemArray = new ArrayType<>(item);
public final Type<Item> itemCost = new ItemCostType1_20_5(structuredDataArray);
public final Type<Item> optionalItemCost = new ItemCostType1_20_5.OptionalItemCostType(itemCost);
public final K structuredDataKeys;
private K structuredDataKeys;
public final ParticleType particle = new ParticleType();
public final ArrayType<Particle> particles = new ArrayType<>(particle);
@@ -58,11 +58,17 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
public final Type<EntityData> entityData;
public final Type<List<EntityData>> entityDataList;
public Types1_20_5(final Function<Types1_20_5<?, ?>, K> keysSupplier, final Function<Types1_20_5<?, ?>, E> entityDataTypesSupplier) {
this.structuredDataKeys = keysSupplier.apply(this);
public Types1_20_5(final Function<VersionedTypesHolder, K> keysSupplier, final Function<VersionedTypesHolder, E> entityDataTypesSupplier) {
this.entityDataTypes = entityDataTypesSupplier.apply(this);
this.entityData = new EntityDataType(entityDataTypes);
this.entityDataList = new EntityDataListType(entityData);
if (keysSupplier != null) {
initKeys(keysSupplier);
}
}
protected void initKeys(final Function<VersionedTypesHolder, K> keysSupplier) {
this.structuredDataKeys = keysSupplier.apply(this);
}
@Override
@@ -75,6 +81,21 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
return itemArray;
}
@Override
public Type<Item> itemTemplate() {
return item;
}
@Override
public Type<Item> optionalItemTemplate() {
return item;
}
@Override
public Type<Item[]> itemTemplateArray() {
return itemArray;
}
@Override
public Type<Item> itemCost() {
return itemCost;
@@ -34,7 +34,7 @@ public final class Types1_21 extends Types1_20_5<StructuredDataKeys1_20_5, Entit
public final Type<Item> optionalItem; // Optional as in boolean prefixed, not via the amount
public Types1_21(final Function<Types1_20_5<?, ?>, StructuredDataKeys1_20_5> keysSupplier, final Function<Types1_20_5<?, ?>, EntityDataTypes1_21> entityDataTypesSupplier) {
public Types1_21(final Function<VersionedTypesHolder, StructuredDataKeys1_20_5> keysSupplier, final Function<VersionedTypesHolder, EntityDataTypes1_21> entityDataTypesSupplier) {
super(keysSupplier, entityDataTypesSupplier);
this.optionalItem = ((ItemType1_20_5) item).new OptionalItemType();
}
@@ -0,0 +1,58 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.data.version.VersionedStructuredDataKeys;
import com.viaversion.viaversion.api.minecraft.entitydata.types.AbstractEntityDataTypes;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.item.ItemTemplateType26_1;
import java.util.function.Function;
public class Types26_1<K extends VersionedStructuredDataKeys, E extends AbstractEntityDataTypes> extends Types1_20_5<K, E> {
public final Type<Item> itemTemplate = new ItemTemplateType26_1(structuredData);
public final Type<Item> optionalItemTemplate = new ItemTemplateType26_1.OptionalItemTemplateType(itemTemplate);
public final Type<Item[]> itemTemplateArray = new ArrayType<>(itemTemplate);
public Types26_1(final Function<VersionedTypesHolder, K> keysSupplier, final Function<VersionedTypesHolder, E> entityDataTypesSupplier) {
super(null, entityDataTypesSupplier);
initKeys(keysSupplier);
}
@Override
public Type<Item> itemTemplate() {
return itemTemplate;
}
@Override
public Type<Item> optionalItemTemplate() {
return optionalItemTemplate;
}
@Override
public Type<Item[]> itemTemplateArray() {
return itemTemplateArray;
}
}
@@ -32,6 +32,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_1;
/**
* Holds versioned accessors for highly volatile types, specifically around items and data components.
@@ -49,4 +50,5 @@ public final class VersionedTypes {
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_6 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> V1_21_9 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_9::new);
public static final Types1_20_5<StructuredDataKeys1_21_11, EntityDataTypes1_21_11> V1_21_11 = new Types1_20_5<>(StructuredDataKeys1_21_11::new, EntityDataTypes1_21_11::new);
public static final Types26_1<StructuredDataKeys1_21_11, EntityDataTypes26_1> V26_1 = new Types26_1<>(StructuredDataKeys1_21_11::new, EntityDataTypes26_1::new);
}
@@ -39,10 +39,31 @@ import java.util.List;
*/
public interface VersionedTypesHolder {
/**
* Returns the unmapped item stack type
*
* @return unmapped item stack type
*/
Type<Item> item();
Type<Item[]> itemArray();
/**
* Returns the unmapped item stack template type, used for certain recipes/templates in 26.1+.
*
* @return unmapped item stack template type
*/
Type<Item> itemTemplate();
Type<Item> optionalItemTemplate();
Type<Item[]> itemTemplateArray();
/**
* Returns the unmapped item cost type, used in merchant offers.
*
* @return unmapped item cost type
*/
Type<Item> itemCost();
Type<Item> optionalItemCost();
@@ -60,7 +60,7 @@ public class InformativeException extends RuntimeException {
@Override
public String getMessage() {
final StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n");
final StringBuilder builder = new StringBuilder("Please report the full error (!) from the console on the Via support Discord or open an issue on the relevant GitHub repository.\n");
boolean first = true;
for (final DataEntry entry : dataEntries) {
if (!first) {
+1 -1
View File
@@ -8,7 +8,7 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.3.1")
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.4.1")
// A nice no-conflict comment for patching in downgrading
}
@@ -49,6 +49,20 @@ public final class NMSUtil {
}
}
public static Class<?> nms(String className, String... fallbackFullClassNames) throws ClassNotFoundException {
try {
return Class.forName(NMS + "." + className);
} catch (ClassNotFoundException ignored) {
}
for (final String fallbackFullClassName : fallbackFullClassNames) {
try {
return Class.forName(fallbackFullClassName);
} catch (ClassNotFoundException ignored) {
}
}
throw new ClassNotFoundException(className);
}
public static Class<?> obc(String className) throws ClassNotFoundException {
return Class.forName(BASE + "." + className);
}
@@ -37,7 +37,7 @@ import java.util.List;
@ChannelHandler.Sharable
public final class BukkitEncodeHandler extends ViaEncodeHandler {
private boolean handledCompression = BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT != null;
private boolean handledCompression = BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT != null || Boolean.getBoolean("com.viaversion.disableLegacyCompressionReorder");
public BukkitEncodeHandler(final UserConnection connection) {
super(connection);
@@ -56,7 +56,7 @@ public final class BukkitEncodeHandler extends ViaEncodeHandler {
final ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf);
try {
final boolean needsCompression = !handledCompression && handleCompressionOrder(ctx, transformedBuf);
final boolean needsCompression = !handledCompression && connection.getProtocolInfo().compressionEnabled() && handleCompressionOrder(ctx, transformedBuf);
connection.transformClientbound(transformedBuf, CancelEncoderException::generate);
if (needsCompression) {
recompress(ctx, transformedBuf);
@@ -105,7 +105,8 @@ public class BukkitViaInjector extends LegacyViaInjector {
// Grab the ping class and find the field to access it
Class<?> pingClazz = NMSUtil.nms(
"ServerPing",
"net.minecraft.network.protocol.status.ServerPing"
"net.minecraft.network.protocol.status.ServerPing",
"net.minecraft.network.protocol.status.ServerStatus"
);
Object ping = null;
for (Field field : serverClazz.getDeclaredFields()) {
@@ -120,7 +121,8 @@ public class BukkitViaInjector extends LegacyViaInjector {
// Now get the ServerData inside ServerPing
Class<?> serverDataClass = NMSUtil.nms(
"ServerPing$ServerData",
"net.minecraft.network.protocol.status.ServerPing$ServerData"
"net.minecraft.network.protocol.status.ServerPing$ServerData",
"net.minecraft.network.protocol.status.ServerStatus$Version"
);
Object serverData = null;
for (Field field : pingClazz.getDeclaredFields()) {
@@ -155,7 +157,8 @@ public class BukkitViaInjector extends LegacyViaInjector {
);
Class<?> connectionClass = NMSUtil.nms(
"ServerConnection",
"net.minecraft.server.network.ServerConnection"
"net.minecraft.server.network.ServerConnection",
"net.minecraft.server.network.ServerConnectionListener"
);
Object server = ReflectionUtil.invokeStatic(serverClass, "getServer");
@@ -1,44 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.classgenerator.generated;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.handlers.BukkitDecodeHandler;
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
public interface HandlerSupplier {
MessageToMessageEncoder<ByteBuf> newEncodeHandler(UserConnection connection);
MessageToMessageDecoder<ByteBuf> newDecodeHandler(UserConnection connection);
final class DefaultHandlerSupplier implements HandlerSupplier {
@Override
public MessageToMessageEncoder<ByteBuf> newEncodeHandler(final UserConnection connection) {
return new BukkitEncodeHandler(connection);
}
@Override
public MessageToMessageDecoder<ByteBuf> newDecodeHandler(final UserConnection connection) {
return new BukkitDecodeHandler(connection);
}
}
}
@@ -2,23 +2,18 @@
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 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.
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.api.protocol;
@@ -39,10 +34,15 @@ import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypeMap;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.rewriter.MappingDataListener;
import com.viaversion.viaversion.api.rewriter.Rewriter;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.protocol.shared_registration.SharedRegistrations;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ProtocolLogger;
import com.viaversion.viaversion.util.ProtocolUtil;
import java.util.HashMap;
@@ -74,6 +74,8 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
private final Map<Class<?>, Object> storedObjects = new HashMap<>();
private boolean initialized;
private ProtocolLogger logger;
private ProtocolVersion serverVersion;
private ProtocolVersion clientVersion;
@Deprecated
protected AbstractProtocol() {
@@ -104,6 +106,11 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
if (logger == null) {
logger = createLogger();
}
// Apply shared registrations based on protocol version range
// Run before registerPackets, so implementations have to call append intentionally
applySharedRegistrations();
registerPackets();
registerConfigurationChangeHandlers();
@@ -128,6 +135,13 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
/**
* Applies shared registrations. Can be overridden to remove or add registrations.
*/
protected void applySharedRegistrations() {
SharedRegistrations.defaultRegistrations().applyMatching(this);
}
protected ProtocolLogger createLogger() {
return new ProtocolLogger(getClass());
}
@@ -177,6 +191,20 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
@Override
public void replaceClientbound(final CU type, @Nullable final PacketHandler handler) {
final PacketMapping mapping = clientboundMappings.mappedPacket(type.state(), type.getId());
Preconditions.checkNotNull(mapping, "Packet %s has no handler to replace", type);
mapping.setHandler(handler);
}
@Override
public void replaceServerbound(final SU type, @Nullable final PacketHandler handler) {
final PacketMapping mapping = serverboundMappings.mappedPacket(type.state(), type.getId());
Preconditions.checkNotNull(mapping, "Packet %s has no handler to replace", type);
mapping.setHandler(handler);
}
private <U extends PacketType, M extends PacketType> void registerPacketIdChanges(
Map<State, PacketTypeMap<U>> unmappedPacketTypes,
Map<State, PacketTypeMap<M>> mappedPacketTypes,
@@ -214,6 +242,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
@Override
public final void loadMappingData() {
getMappingData().load();
initialize();
onMappingDataLoaded();
}
@@ -289,6 +318,46 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
return packetTypesProvider.unmappedClientboundType(State.CONFIGURATION, "FINISH_CONFIGURATION");
}
/**
* Returns the server protocol version for this protocol,
* or null if not set (e.g. for base protocols).
*
* @return the server protocol version
*/
public @Nullable ProtocolVersion getServerVersion() {
return serverVersion;
}
/**
* Sets the server protocol version for this protocol.
* Called by the protocol manager before {@link #initialize()}.
*
* @param serverVersion the server protocol version
*/
public void setServerVersion(final ProtocolVersion serverVersion) {
this.serverVersion = serverVersion;
}
/**
* Returns the client protocol version for this protocol,
* or null if not set (e.g. for base protocols).
*
* @return the client protocol version for this protocol
*/
public @Nullable ProtocolVersion getClientVersion() {
return clientVersion;
}
/**
* Sets the client protocol version for this protocol.
* Called by the protocol manager before {@link #initialize()}.
*
* @param clientVersion the client protocol version for this protocol
*/
public void setClientVersion(final ProtocolVersion clientVersion) {
this.clientVersion = clientVersion;
}
// ---------------------------------------------------------------------------------
@Override
@@ -297,7 +366,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
PacketMapping packetMapping = PacketMapping.of(mappedPacketId, handler);
if (!override && serverboundMappings.hasMapping(state, unmappedPacketId)) {
Via.getPlatform().getLogger().log(Level.WARNING, unmappedPacketId + " already registered!" +
" If this override is intentional, set override to true. Stacktrace: ", new Exception());
" If this override is intentional, use replaceServerbound instead. Stacktrace: ", new Exception());
}
serverboundMappings.addMapping(state, unmappedPacketId, packetMapping);
}
@@ -313,7 +382,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
PacketMapping packetMapping = PacketMapping.of(mappedPacketId, handler);
if (!override && clientboundMappings.hasMapping(state, unmappedPacketId)) {
Via.getPlatform().getLogger().log(Level.WARNING, unmappedPacketId + " already registered!" +
" If override is intentional, set override to true. Stacktrace: ", new Exception());
" If override is intentional, use replaceClientbound instead. Stacktrace: ", new Exception());
}
clientboundMappings.addMapping(state, unmappedPacketId, packetMapping);
}
@@ -373,8 +442,8 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
PacketMapping packetMapping = PacketMapping.of(mappedPacketType, handler);
if (!override && packetMappings.hasMapping(packetType)) {
getLogger().log(Level.WARNING, packetType + " already registered!" +
" If override is intentional, set override to true. Stacktrace: ", new Exception());
throw new IllegalArgumentException("Packet type " + packetType + " already registered! If override is intentional, use "
+ (packetType.direction() == Direction.SERVERBOUND ? "replaceServerbound" : "replaceClientbound") + " instead.");
}
packetMappings.addMapping(packetType, packetMapping);
}
@@ -443,6 +512,39 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
return logger;
}
@Override
public @Nullable TagRewriter<CU> getTagRewriter() {
return null;
}
@Override
public @Nullable ComponentRewriterBase<CU> getComponentRewriter() {
return null;
}
@Override
public com.viaversion.viaversion.rewriter.@Nullable ParticleRewriter<CU> getParticleRewriter() {
return null;
}
@Override
public com.viaversion.viaversion.rewriter.@Nullable EntityRewriter<CU, ?> getEntityRewriter() {
return null;
}
@Override
public com.viaversion.viaversion.rewriter.@Nullable ItemRewriter<CU, SU, ?> getItemRewriter() {
return null;
}
public com.viaversion.viaversion.rewriter.@Nullable BlockRewriter<CU> getBlockRewriter() {
return null;
}
public @Nullable RecipeDisplayRewriter<CU> getRecipeRewriter() {
return null;
}
private void printRemapError(Direction direction, State state, int unmappedPacketId, int mappedPacketId, InformativeException e) {
// Don't print errors during handshake/login/status
if (state != State.PLAY && direction == Direction.SERVERBOUND && !Via.getManager().debugHandler().enabled()) {
@@ -30,7 +30,7 @@ public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, RegistryAccess
// Generally from hardcoded, but highly variable client data
private static final Set<StructuredDataKey<?>> NOT_IMPLEMENTED = new ReferenceOpenHashSet<>(List.of(
StructuredDataKey.DAMAGE_TYPE
StructuredDataKey.DAMAGE_TYPE1_21_11
));
public CodecRegistryContext(final Protocol<?, ?, ?, ?> protocol, final RegistryAccess registryAccess, final boolean mapped) {
@@ -22,9 +22,11 @@ import java.util.Arrays;
public final class HashBuilder {
private static final byte[] EMPTY_BYTES = new byte[0];
private static final int MAX_RETAINED_CAPACITY = 4096;
private final HashFunction hashFunction;
private byte[] bytes = EMPTY_BYTES;
private int index;
private boolean direct;
public HashBuilder(final HashFunction hashFunction) {
this.hashFunction = hashFunction;
@@ -43,11 +45,17 @@ public final class HashBuilder {
return this;
}
/**
* Writes the given bytes directly, avoiding a copy if currently empty.
*
* @param bytes the bytes to write directly
*/
public void writeBytesDirect(final byte[] bytes) {
if (this.bytes.length == 0) {
// Set bytes directly if still empty
this.bytes = bytes;
this.index = bytes.length;
this.direct = true;
} else {
writeBytes(bytes);
}
@@ -75,9 +83,11 @@ public final class HashBuilder {
public HashBuilder writeString(final CharSequence sequence) {
final int length = sequence.length();
this.ensureSize(length);
this.ensureSize(length * 2);
for (int i = 0; i < length; i++) {
this.writeChar(sequence.charAt(i));
final char c = sequence.charAt(i);
this.bytes[this.index++] = (byte) c;
this.bytes[this.index++] = (byte) (c >> 8);
}
return this;
}
@@ -130,9 +140,11 @@ public final class HashBuilder {
private void ensureSize(final int bytes) {
final int length = this.bytes.length;
if (this.index + bytes > length) {
final int newLength = Math.max(length * 2, this.index + bytes);
final int required = this.index + bytes;
if (required > length) {
final int newLength = Math.max(length * 2, required);
this.bytes = Arrays.copyOf(this.bytes, newLength);
this.direct = false;
}
}
@@ -142,7 +154,11 @@ public final class HashBuilder {
public void reset() {
this.index = 0;
this.bytes = EMPTY_BYTES;
// Discard the buffer if it was direct (externally owned) or exceeds max retained capacity
if (this.direct || this.bytes.length > MAX_RETAINED_CAPACITY) {
this.bytes = EMPTY_BYTES;
this.direct = false;
}
}
public HashFunction function() {
@@ -37,6 +37,11 @@ public class DebugSubCmd implements ViaSubCommand {
return "Toggle various debug modes.";
}
@Override
public String usage() {
return "debug [clear|pre|post], or debug <add|remove> <packet>";
}
@Override
public boolean execute(ViaCommandSender sender, String[] args) {
final DebugHandler debug = Via.getManager().debugHandler();
@@ -49,11 +54,11 @@ public class DebugSubCmd implements ViaSubCommand {
debug.clearPacketTypesToLog();
sendMessage(sender, "&6Cleared packet types to log");
return true;
} else if (args[0].equalsIgnoreCase("logpretransform")) {
} else if (args[0].equalsIgnoreCase("pre")) {
debug.setLogPrePacketTransform(!debug.logPrePacketTransform());
sendMessage(sender, "&6Pre transform packet logging is now %s", (debug.logPrePacketTransform() ? "&aenabled" : "&cdisabled"));
return true;
} else if (args[0].equalsIgnoreCase("logposttransform")) {
} else if (args[0].equalsIgnoreCase("post")) {
debug.setLogPostPacketTransform(!debug.logPostPacketTransform());
sendMessage(sender, "&6Post transform packet logging is now %s", (debug.logPostPacketTransform() ? "&aenabled" : "&cdisabled"));
return true;
@@ -75,7 +80,7 @@ public class DebugSubCmd implements ViaSubCommand {
@Override
public List<String> onTabComplete(final ViaCommandSender sender, final String[] args) {
if (args.length == 1) {
return Arrays.asList("clear", "logposttransform", "add", "remove");
return Arrays.asList("clear", "pre", "post", "add", "remove");
}
return Collections.emptyList();
}
@@ -37,7 +37,7 @@ public class DisplayLeaksSubCmd implements ViaSubCommand {
@Override
public String usage() {
return "displayleaks <level>";
return "displayleaks [level]";
}
@Override
@@ -64,24 +64,21 @@ public final class ConnectionDetails {
return;
}
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
final ProtocolVersion nativeVersion = protocolInfo.protocolVersion();
final ProtocolVersion serverVersion = protocolInfo.serverProtocolVersion();
if (serverVersion.equals(nativeVersion)) {
// No need to send details if the native version is the same as the server version
return;
}
final JsonObject payload = new JsonObject();
payload.addProperty("specVersion", VERSION);
final String platformName = Via.getPlatform().getPlatformName();
final String platformVersion = Via.getPlatform().getPlatformVersion();
final JsonObject payload = new JsonObject();
payload.addProperty("specVersion", VERSION);
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
final ProtocolVersion clientVersion = protocolInfo.protocolVersion();
payload.addProperty("platformName", platformName);
payload.addProperty("platformVersion", platformVersion);
payload.addProperty("version", nativeVersion.getOriginalVersion());
payload.addProperty("versionName", nativeVersion.getName());
payload.addProperty("version", clientVersion.getOriginalVersion());
payload.addProperty("versionName", clientVersion.getName());
payload.addProperty("versionType", clientVersion.getVersionType().name());
Via.getPlatform().modifyPlayerDetails(connection, payload);
Via.getPlatform().sendCustomPayload(connection, channel, payload.toString().getBytes(StandardCharsets.UTF_8));
}
@@ -98,13 +95,15 @@ public final class ConnectionDetails {
return;
}
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
final ProtocolVersion serverVersion = protocolInfo.serverProtocolVersion();
final JsonObject payload = new JsonObject();
payload.addProperty("specVersion", VERSION);
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
final ProtocolVersion serverVersion = protocolInfo.serverProtocolVersion();
payload.addProperty("version", serverVersion.getOriginalVersion());
payload.addProperty("versionName", serverVersion.getName());
payload.addProperty("versionType", serverVersion.getVersionType().name());
Via.getPlatform().modifyServerDetails(connection, payload);
Via.getPlatform().sendCustomPayloadToClient(connection, channel, payload.toString().getBytes(StandardCharsets.UTF_8));
}
@@ -32,6 +32,7 @@ public class ProtocolInfoImpl implements ProtocolInfo {
private String username;
private UUID uuid;
private ProtocolPipeline pipeline;
private boolean compressionEnabled;
@Override
public State getClientState() {
@@ -99,6 +100,16 @@ public class ProtocolInfoImpl implements ProtocolInfo {
this.uuid = uuid;
}
@Override
public boolean compressionEnabled() {
return compressionEnabled;
}
@Override
public void setCompressionEnabled(final boolean compressionEnabled) {
this.compressionEnabled = compressionEnabled;
}
@Override
public ProtocolPipeline getPipeline() {
return pipeline;
@@ -215,7 +215,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
@Override
public @Nullable DimensionData dimensionData(int dimensionId) {
return dimensions.values().stream().filter(data -> data.id() == dimensionId).findFirst().orElse(null); // TODO Store as array as well
return dimensions.values().stream().filter(data -> data.id() == dimensionId).findFirst().orElse(null);
}
@Override
@@ -116,6 +116,8 @@ public class ItemHasherBase implements ItemHasher {
entry.setValue(clientProvidedHash);
}
}
originalItem.setAmount(clientItem.amount());
return originalItem;
}
@@ -49,6 +49,11 @@ public abstract class UserConnectionViaVersionPlatform implements ViaPlatform<Us
@Override
public abstract Logger createLogger(String name);
@Override
public boolean isProxy() {
return true;
}
@Override
public Logger getLogger() {
return logger;
@@ -17,10 +17,13 @@
*/
package com.viaversion.viaversion.platform;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.platform.ViaInjector;
import com.viaversion.viaversion.connection.UserConnectionImpl;
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import java.lang.reflect.Method;
@@ -59,6 +62,30 @@ public abstract class ViaChannelInitializer extends ChannelInitializer<Channel>
return connection;
}
/**
* Reorders the ViaVersion handlers in the pipeline to be after the specified handlers. This is needed in platforms
* where enabling the compression breaks the order of Via handlers to be: encoder -> compressor -> via encoder.
*
* @param pipeline The channel pipeline
* @param compress The name of the compress handler where Via's encoder was initially placed after
* @param decompress The name of the decompress handler where Via's decoder was initially placed after
*/
public static void reorderPipeline(final ChannelPipeline pipeline, final String compress, final String decompress) {
final ViaInjector injector = Via.getManager().getInjector();
final int decompressIndex = pipeline.names().indexOf(decompress);
if (decompressIndex == -1) {
return;
}
if (decompressIndex > pipeline.names().indexOf(injector.getDecoderName())) {
final ChannelHandler encoderHandler = pipeline.remove(injector.getEncoderName());
final ChannelHandler decoderHandler = pipeline.remove(injector.getDecoderName());
pipeline.addAfter(compress, injector.getEncoderName(), encoderHandler);
pipeline.addAfter(decompress, injector.getDecoderName(), decoderHandler);
}
}
protected abstract void injectPipeline(ChannelPipeline pipeline, UserConnection connection);
@Override
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocol;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.SimpleProtocol;
/**
* A simple protocol which does not have any packet types.
* <p>
* {@link AbstractProtocol} should be preferred over this class in most cases.
*/
public abstract class AbstractSimpleProtocol extends AbstractProtocol<SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes,
SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes> implements SimpleProtocol {
protected AbstractSimpleProtocol() {
super(null, null, null, null);
}
}
@@ -23,6 +23,7 @@ import com.google.common.collect.Range;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.ProtocolManager;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
@@ -38,6 +39,7 @@ import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl;
import com.viaversion.viaversion.protocol.shared_registration.def.DefaultRegistrations;
import com.viaversion.viaversion.protocols.base.InitialBaseProtocol;
import com.viaversion.viaversion.protocols.base.v1_16.ClientboundBaseProtocol1_16;
import com.viaversion.viaversion.protocols.base.v1_7.ClientboundBaseProtocol1_7;
@@ -76,6 +78,7 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.Protocol1_21_11To26_1;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.Protocol1_21_5To1_21_6;
@@ -94,6 +97,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -112,9 +116,7 @@ import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.logging.Level;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolManagerImpl implements ProtocolManager {
@@ -145,6 +147,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
worker.setName("Via-Mappingloader-" + threadIndex.incrementAndGet());
return worker;
}, ForkJoinWorkerThread.getDefaultUncaughtExceptionHandler(), true);
DefaultRegistrations.apply();
}
public void registerProtocols() {
@@ -213,6 +217,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_21_6To1_21_7(), ProtocolVersion.v1_21_7, ProtocolVersion.v1_21_6);
registerProtocol(new Protocol1_21_7To1_21_9(), ProtocolVersion.v1_21_9, ProtocolVersion.v1_21_7);
registerProtocol(new Protocol1_21_9To1_21_11(), ProtocolVersion.v1_21_11, ProtocolVersion.v1_21_9);
registerProtocol(new Protocol1_21_11To26_1(), ProtocolVersion.v26_1, ProtocolVersion.v1_21_11);
}
@Override
@@ -222,8 +228,11 @@ public class ProtocolManagerImpl implements ProtocolManager {
@Override
public void registerProtocol(Protocol protocol, List<ProtocolVersion> supportedClientVersion, ProtocolVersion serverVersion) {
// Register the protocol's handlers
protocol.initialize();
// Set the server version on AbstractProtocol instances before initialization
if (protocol instanceof AbstractProtocol<?, ?, ?, ?> abstractProtocol) {
abstractProtocol.setServerVersion(serverVersion);
abstractProtocol.setClientVersion(supportedClientVersion.stream().max(ProtocolVersion::compareTo).orElseThrow());
}
// Clear cache as this may make new routes.
if (!pathCache.isEmpty()) {
@@ -245,14 +254,22 @@ public class ProtocolManagerImpl implements ProtocolManager {
refreshVersions();
}
if (protocol.hasMappingDataToLoad()) {
if (mappingLoaderExecutor != null) {
// Submit mapping data loading
addMappingLoaderFuture(protocol.getClass(), protocol::loadMappingData);
// Load mapping data and register the protocol's handlers
if (!protocol.hasMappingDataToLoad()) {
protocol.initialize();
return;
}
// Submit mapping data loading
if (mappingLoaderExecutor != null) {
if (protocol.dependsOn() != null) {
addMappingLoaderFuture(protocol.getClass(), protocol.dependsOn(), protocol::loadMappingData);
} else {
// Late protocol adding - just do it on the current thread
protocol.loadMappingData();
addMappingLoaderFuture(protocol.getClass(), protocol::loadMappingData);
}
} else {
// Late protocol adding - just do it on the current thread
protocol.loadMappingData();
}
}
@@ -481,7 +498,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public boolean checkForMappingCompletion() {
public boolean checkForMappingCompletion(final boolean propagateErrors) {
mappingLoaderLock.readLock().lock();
try {
if (mappingsLoaded) {
@@ -493,6 +510,9 @@ public class ProtocolManagerImpl implements ProtocolManager {
if (!future.isDone()) {
return false;
}
if (propagateErrors) {
future.join();
}
}
shutdownLoaderExecutor();
@@ -504,7 +524,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
@Override
public void addMappingLoaderFuture(Class<? extends Protocol> protocolClass, Runnable runnable) {
CompletableFuture<Void> future = CompletableFuture.runAsync(runnable, mappingLoaderExecutor).exceptionally(mappingLoaderThrowable(protocolClass));
CompletableFuture<Void> future = CompletableFuture.runAsync(runnable, mappingLoaderExecutor)
.whenComplete(($, t) -> logIfErrored(protocolClass, t));
mappingLoaderLock.writeLock().lock();
try {
@@ -516,8 +537,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
@Override
public void addMappingLoaderFuture(Class<? extends Protocol> protocolClass, Class<? extends Protocol> dependsOn, Runnable runnable) {
CompletableFuture<Void> future = getMappingLoaderFuture(dependsOn)
.whenCompleteAsync((v, throwable) -> runnable.run(), mappingLoaderExecutor).exceptionally(mappingLoaderThrowable(protocolClass));
CompletableFuture<Void> future = getMappingLoaderFuture(dependsOn).thenRunAsync(runnable, mappingLoaderExecutor)
.whenComplete(($, t) -> logIfErrored(protocolClass, t));
mappingLoaderLock.writeLock().lock();
try {
@@ -568,10 +589,9 @@ public class ProtocolManagerImpl implements ProtocolManager {
MappingDataLoader.INSTANCE.clearCache();
}
private Function<Throwable, Void> mappingLoaderThrowable(Class<? extends Protocol> protocolClass) {
return throwable -> {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error during mapping loading of " + protocolClass.getSimpleName(), throwable);
return null;
};
private void logIfErrored(final Class<? extends Protocol> protocolClass, @Nullable final Throwable throwable) {
if (throwable != null) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error during loading of " + protocolClass.getSimpleName(), throwable);
}
}
}
@@ -478,6 +478,19 @@ public class PacketWrapperImpl implements PacketWrapper {
this.packetValues.clear();
}
@Override
public void rewindReader(final int values) {
if (allActionsRead) {
return;
}
final int size = packetValues.size();
Preconditions.checkArgument(values <= size, "Tried resetting more values than there are readable values");
for (int i = size - 1; i >= size - values; i--) {
this.readableObjects.addFirst(this.packetValues.remove(i));
}
}
@Override
public void sendToServerRaw() throws InformativeException {
sendToServerRaw(true);
@@ -584,6 +597,17 @@ public class PacketWrapperImpl implements PacketWrapper {
this.allActionsRead = allActionsRead;
}
@Override
public void consumeReadsOnly(final Runnable runnable) {
final boolean previous = this.allActionsRead;
this.allActionsRead = true;
try {
runnable.run();
} finally {
this.allActionsRead = previous;
}
}
@Override
public String toString() {
return "PacketWrapper{" +
Loaded 100 of 273 files, more files were not shown because too many files have changed in this diff. Show more